mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Readded palette animation support
This commit is contained in:
parent
d4042f7e95
commit
cc5a4c7cef
@ -1,8 +1,11 @@
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
|
||||
#include "CompatDirectDrawPalette.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
#include "Config.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
#include "Time.h"
|
||||
|
||||
void CompatDirectDrawPalette::setCompatVtable(IDirectDrawPaletteVtbl& vtable)
|
||||
{
|
||||
@ -16,11 +19,15 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawPalette::SetEntries(
|
||||
DWORD dwCount,
|
||||
LPPALETTEENTRY lpEntries)
|
||||
{
|
||||
if (This == CompatPrimarySurface::palette && lpEntries && dwStartingEntry + dwCount <= 256 &&
|
||||
0 == std::memcmp(&CompatPrimarySurface::paletteEntries[dwStartingEntry],
|
||||
lpEntries, dwCount * sizeof(PALETTEENTRY)))
|
||||
if (This == CompatPrimarySurface::palette)
|
||||
{
|
||||
return DD_OK;
|
||||
waitForNextUpdate();
|
||||
if (lpEntries && dwStartingEntry + dwCount <= 256 &&
|
||||
0 == std::memcmp(&CompatPrimarySurface::paletteEntries[dwStartingEntry],
|
||||
lpEntries, dwCount * sizeof(PALETTEENTRY)))
|
||||
{
|
||||
return DD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT result = s_origVtable.SetEntries(This, dwFlags, dwStartingEntry, dwCount, lpEntries);
|
||||
@ -32,3 +39,23 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawPalette::SetEntries(
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CompatDirectDrawPalette::waitForNextUpdate()
|
||||
{
|
||||
static std::deque<long long> updatesInLastMs;
|
||||
|
||||
const long long qpcNow = Time::queryPerformanceCounter();
|
||||
const long long qpcLastMsBegin = qpcNow - Time::g_qpcFrequency / 1000;
|
||||
while (!updatesInLastMs.empty() && qpcLastMsBegin - updatesInLastMs.front() > 0)
|
||||
{
|
||||
updatesInLastMs.pop_front();
|
||||
}
|
||||
|
||||
if (updatesInLastMs.size() >= Config::maxPaletteUpdatesPerMs)
|
||||
{
|
||||
Sleep(1);
|
||||
updatesInLastMs.clear();
|
||||
}
|
||||
|
||||
updatesInLastMs.push_back(Time::queryPerformanceCounter());
|
||||
}
|
||||
|
@ -14,4 +14,6 @@ public:
|
||||
DWORD dwStartingEntry,
|
||||
DWORD dwCount,
|
||||
LPPALETTEENTRY lpEntries);
|
||||
|
||||
static void waitForNextUpdate();
|
||||
};
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "CompatDirectDraw.h"
|
||||
#include "CompatDirectDrawPalette.h"
|
||||
#include "CompatDirectDrawSurface.h"
|
||||
#include "CompatGdi.h"
|
||||
#include "CompatPrimarySurface.h"
|
||||
@ -640,9 +641,16 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::SetPalette(
|
||||
TSurface* This,
|
||||
LPDIRECTDRAWPALETTE lpDDPalette)
|
||||
{
|
||||
if (This == s_compatPrimarySurface && lpDDPalette == CompatPrimarySurface::palette)
|
||||
if (This == s_compatPrimarySurface)
|
||||
{
|
||||
return DD_OK;
|
||||
if (lpDDPalette)
|
||||
{
|
||||
CompatDirectDrawPalette::waitForNextUpdate();
|
||||
}
|
||||
if (lpDDPalette == CompatPrimarySurface::palette)
|
||||
{
|
||||
return DD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT result = s_origVtable.SetPalette(This, lpDDPalette);
|
||||
|
@ -4,6 +4,7 @@ typedef unsigned long DWORD;
|
||||
|
||||
namespace Config
|
||||
{
|
||||
const int maxPaletteUpdatesPerMs = 10;
|
||||
const int maxPrimaryUpdateRate = 60;
|
||||
const int primaryUpdateDelayAfterFlip = 100;
|
||||
const DWORD preallocatedGdiDcCount = 4;
|
||||
|
@ -175,6 +175,7 @@
|
||||
<ClInclude Include="IReleaseNotifier.h" />
|
||||
<ClInclude Include="RealPrimarySurface.h" />
|
||||
<ClInclude Include="ScopedCriticalSection.h" />
|
||||
<ClInclude Include="Time.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CompatDirectDraw.cpp" />
|
||||
@ -201,6 +202,7 @@
|
||||
<ClCompile Include="RealPrimarySurface.cpp" />
|
||||
<ClCompile Include="CompatGdiDc.cpp" />
|
||||
<ClCompile Include="DDrawRepository.cpp" />
|
||||
<ClCompile Include="Time.cpp" />
|
||||
<ClCompile Include="UnmodifiedDDrawProcs.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -108,6 +108,9 @@
|
||||
<ClInclude Include="ScopedCriticalSection.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Time.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="DllMain.cpp">
|
||||
@ -185,6 +188,9 @@
|
||||
<ClCompile Include="CompatPaletteConverter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Time.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="DDrawCompat.def">
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "CompatVtable.h"
|
||||
#include "DDrawProcs.h"
|
||||
#include "DDrawRepository.h"
|
||||
#include "Time.h"
|
||||
|
||||
struct IDirectInput;
|
||||
|
||||
@ -166,6 +167,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
|
||||
|
||||
SetProcessAffinityMask(GetCurrentProcess(), 1);
|
||||
SetThemeAppProperties(0);
|
||||
Time::init();
|
||||
|
||||
if (Compat::origProcs.SetAppCompatData)
|
||||
{
|
||||
|
@ -13,12 +13,11 @@
|
||||
#include "Hook.h"
|
||||
#include "IReleaseNotifier.h"
|
||||
#include "RealPrimarySurface.h"
|
||||
#include "Time.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
long long msToQpc(int ms);
|
||||
void onRelease();
|
||||
int qpcToMs(long long qpc);
|
||||
void updateNow(long long qpcNow);
|
||||
|
||||
IDirectDrawSurface7* g_frontBuffer = nullptr;
|
||||
@ -28,7 +27,6 @@ namespace
|
||||
HANDLE g_updateThread = nullptr;
|
||||
HANDLE g_updateEvent = nullptr;
|
||||
RECT g_updateRect = {};
|
||||
long long g_qpcFrequency = 0;
|
||||
long long g_qpcMinUpdateInterval = 0;
|
||||
std::atomic<long long> g_qpcNextUpdate = 0;
|
||||
|
||||
@ -95,15 +93,10 @@ namespace
|
||||
|
||||
bool isNextUpdateSignaledAndReady(long long qpcNow)
|
||||
{
|
||||
return qpcToMs(qpcNow - g_qpcNextUpdate) >= 0 &&
|
||||
return Time::qpcToMs(qpcNow - g_qpcNextUpdate) >= 0 &&
|
||||
WAIT_OBJECT_0 == WaitForSingleObject(g_updateEvent, 0);
|
||||
}
|
||||
|
||||
long long msToQpc(int ms)
|
||||
{
|
||||
return static_cast<long long>(ms) * g_qpcFrequency / 1000;
|
||||
}
|
||||
|
||||
void onRelease()
|
||||
{
|
||||
Compat::LogEnter("RealPrimarySurface::onRelease");
|
||||
@ -120,18 +113,6 @@ namespace
|
||||
Compat::LogLeave("RealPrimarySurface::onRelease");
|
||||
}
|
||||
|
||||
int qpcToMs(long long qpc)
|
||||
{
|
||||
return static_cast<int>(qpc * 1000 / g_qpcFrequency);
|
||||
}
|
||||
|
||||
long long queryPerformanceCounter()
|
||||
{
|
||||
LARGE_INTEGER qpc = {};
|
||||
QueryPerformanceCounter(&qpc);
|
||||
return qpc.QuadPart;
|
||||
}
|
||||
|
||||
void updateNow(long long qpcNow)
|
||||
{
|
||||
ResetEvent(g_updateEvent);
|
||||
@ -139,7 +120,7 @@ namespace
|
||||
if (compatBlt(g_frontBuffer))
|
||||
{
|
||||
long long qpcNextUpdate = getNextUpdateQpc(qpcNow);
|
||||
if (qpcToMs(qpcNow - qpcNextUpdate) >= 0)
|
||||
if (Time::qpcToMs(qpcNow - qpcNextUpdate) >= 0)
|
||||
{
|
||||
qpcNextUpdate += g_qpcMinUpdateInterval;
|
||||
}
|
||||
@ -154,14 +135,15 @@ namespace
|
||||
WaitForSingleObject(g_updateEvent, INFINITE);
|
||||
|
||||
const long long qpcTargetNextUpdate = g_qpcNextUpdate;
|
||||
const int msUntilNextUpdate = qpcToMs(qpcTargetNextUpdate - queryPerformanceCounter());
|
||||
const int msUntilNextUpdate =
|
||||
Time::qpcToMs(qpcTargetNextUpdate - Time::queryPerformanceCounter());
|
||||
if (msUntilNextUpdate > 0)
|
||||
{
|
||||
Sleep(msUntilNextUpdate);
|
||||
}
|
||||
|
||||
Compat::DDrawScopedThreadLock lock;
|
||||
const long long qpcNow = queryPerformanceCounter();
|
||||
const long long qpcNow = Time::queryPerformanceCounter();
|
||||
const bool isTargetUpdateStillNeeded = qpcTargetNextUpdate == g_qpcNextUpdate;
|
||||
if (g_frontBuffer && (isTargetUpdateStillNeeded || isNextUpdateSignaledAndReady(qpcNow)))
|
||||
{
|
||||
@ -224,11 +206,8 @@ HRESULT RealPrimarySurface::create(DirectDraw& dd)
|
||||
g_frontBuffer->lpVtbl->GetAttachedSurface(g_frontBuffer, &backBufferCaps, &g_backBuffer);
|
||||
}
|
||||
|
||||
LARGE_INTEGER qpc;
|
||||
QueryPerformanceFrequency(&qpc);
|
||||
g_qpcFrequency = qpc.QuadPart;
|
||||
g_qpcMinUpdateInterval = g_qpcFrequency / Config::maxPrimaryUpdateRate;
|
||||
g_qpcNextUpdate = queryPerformanceCounter();
|
||||
g_qpcMinUpdateInterval = Time::g_qpcFrequency / Config::maxPrimaryUpdateRate;
|
||||
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
||||
|
||||
if (!g_updateEvent)
|
||||
{
|
||||
@ -275,7 +254,7 @@ HRESULT RealPrimarySurface::flip(DWORD flags)
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
g_qpcNextUpdate = getNextUpdateQpc(
|
||||
queryPerformanceCounter() + msToQpc(Config::primaryUpdateDelayAfterFlip));
|
||||
Time::queryPerformanceCounter() + Time::msToQpc(Config::primaryUpdateDelayAfterFlip));
|
||||
SetRectEmpty(&g_updateRect);
|
||||
}
|
||||
return result;
|
||||
@ -354,8 +333,8 @@ void RealPrimarySurface::update()
|
||||
{
|
||||
if (!IsRectEmpty(&g_updateRect))
|
||||
{
|
||||
const long long qpcNow = queryPerformanceCounter();
|
||||
if (qpcToMs(qpcNow - g_qpcNextUpdate) >= 0)
|
||||
const long long qpcNow = Time::queryPerformanceCounter();
|
||||
if (Time::qpcToMs(qpcNow - g_qpcNextUpdate) >= 0)
|
||||
{
|
||||
updateNow(qpcNow);
|
||||
}
|
||||
|
15
DDrawCompat/Time.cpp
Normal file
15
DDrawCompat/Time.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Time.h"
|
||||
|
||||
namespace Time
|
||||
{
|
||||
long long g_qpcFrequency = 0;
|
||||
|
||||
void init()
|
||||
{
|
||||
LARGE_INTEGER qpc;
|
||||
QueryPerformanceFrequency(&qpc);
|
||||
g_qpcFrequency = qpc.QuadPart;
|
||||
}
|
||||
}
|
29
DDrawCompat/Time.h
Normal file
29
DDrawCompat/Time.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Time
|
||||
{
|
||||
extern long long g_qpcFrequency;
|
||||
|
||||
void init();
|
||||
|
||||
inline long long msToQpc(int ms)
|
||||
{
|
||||
return static_cast<long long>(ms) * g_qpcFrequency / 1000;
|
||||
}
|
||||
|
||||
inline int qpcToMs(long long qpc)
|
||||
{
|
||||
return static_cast<int>(qpc * 1000 / g_qpcFrequency);
|
||||
}
|
||||
|
||||
inline long long queryPerformanceCounter()
|
||||
{
|
||||
LARGE_INTEGER qpc = {};
|
||||
QueryPerformanceCounter(&qpc);
|
||||
return qpc.QuadPart;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user