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 <cstring>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
#include "CompatDirectDrawPalette.h"
|
#include "CompatDirectDrawPalette.h"
|
||||||
#include "CompatPrimarySurface.h"
|
#include "CompatPrimarySurface.h"
|
||||||
|
#include "Config.h"
|
||||||
#include "RealPrimarySurface.h"
|
#include "RealPrimarySurface.h"
|
||||||
|
#include "Time.h"
|
||||||
|
|
||||||
void CompatDirectDrawPalette::setCompatVtable(IDirectDrawPaletteVtbl& vtable)
|
void CompatDirectDrawPalette::setCompatVtable(IDirectDrawPaletteVtbl& vtable)
|
||||||
{
|
{
|
||||||
@ -16,11 +19,15 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawPalette::SetEntries(
|
|||||||
DWORD dwCount,
|
DWORD dwCount,
|
||||||
LPPALETTEENTRY lpEntries)
|
LPPALETTEENTRY lpEntries)
|
||||||
{
|
{
|
||||||
if (This == CompatPrimarySurface::palette && lpEntries && dwStartingEntry + dwCount <= 256 &&
|
if (This == CompatPrimarySurface::palette)
|
||||||
0 == std::memcmp(&CompatPrimarySurface::paletteEntries[dwStartingEntry],
|
|
||||||
lpEntries, dwCount * sizeof(PALETTEENTRY)))
|
|
||||||
{
|
{
|
||||||
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);
|
HRESULT result = s_origVtable.SetEntries(This, dwFlags, dwStartingEntry, dwCount, lpEntries);
|
||||||
@ -32,3 +39,23 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawPalette::SetEntries(
|
|||||||
}
|
}
|
||||||
return result;
|
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 dwStartingEntry,
|
||||||
DWORD dwCount,
|
DWORD dwCount,
|
||||||
LPPALETTEENTRY lpEntries);
|
LPPALETTEENTRY lpEntries);
|
||||||
|
|
||||||
|
static void waitForNextUpdate();
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "CompatDirectDraw.h"
|
#include "CompatDirectDraw.h"
|
||||||
|
#include "CompatDirectDrawPalette.h"
|
||||||
#include "CompatDirectDrawSurface.h"
|
#include "CompatDirectDrawSurface.h"
|
||||||
#include "CompatGdi.h"
|
#include "CompatGdi.h"
|
||||||
#include "CompatPrimarySurface.h"
|
#include "CompatPrimarySurface.h"
|
||||||
@ -640,9 +641,16 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface<TSurface>::SetPalette(
|
|||||||
TSurface* This,
|
TSurface* This,
|
||||||
LPDIRECTDRAWPALETTE lpDDPalette)
|
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);
|
HRESULT result = s_origVtable.SetPalette(This, lpDDPalette);
|
||||||
|
@ -4,6 +4,7 @@ typedef unsigned long DWORD;
|
|||||||
|
|
||||||
namespace Config
|
namespace Config
|
||||||
{
|
{
|
||||||
|
const int maxPaletteUpdatesPerMs = 10;
|
||||||
const int maxPrimaryUpdateRate = 60;
|
const int maxPrimaryUpdateRate = 60;
|
||||||
const int primaryUpdateDelayAfterFlip = 100;
|
const int primaryUpdateDelayAfterFlip = 100;
|
||||||
const DWORD preallocatedGdiDcCount = 4;
|
const DWORD preallocatedGdiDcCount = 4;
|
||||||
|
@ -175,6 +175,7 @@
|
|||||||
<ClInclude Include="IReleaseNotifier.h" />
|
<ClInclude Include="IReleaseNotifier.h" />
|
||||||
<ClInclude Include="RealPrimarySurface.h" />
|
<ClInclude Include="RealPrimarySurface.h" />
|
||||||
<ClInclude Include="ScopedCriticalSection.h" />
|
<ClInclude Include="ScopedCriticalSection.h" />
|
||||||
|
<ClInclude Include="Time.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="CompatDirectDraw.cpp" />
|
<ClCompile Include="CompatDirectDraw.cpp" />
|
||||||
@ -201,6 +202,7 @@
|
|||||||
<ClCompile Include="RealPrimarySurface.cpp" />
|
<ClCompile Include="RealPrimarySurface.cpp" />
|
||||||
<ClCompile Include="CompatGdiDc.cpp" />
|
<ClCompile Include="CompatGdiDc.cpp" />
|
||||||
<ClCompile Include="DDrawRepository.cpp" />
|
<ClCompile Include="DDrawRepository.cpp" />
|
||||||
|
<ClCompile Include="Time.cpp" />
|
||||||
<ClCompile Include="UnmodifiedDDrawProcs.cpp" />
|
<ClCompile Include="UnmodifiedDDrawProcs.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -108,6 +108,9 @@
|
|||||||
<ClInclude Include="ScopedCriticalSection.h">
|
<ClInclude Include="ScopedCriticalSection.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Time.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="DllMain.cpp">
|
<ClCompile Include="DllMain.cpp">
|
||||||
@ -185,6 +188,9 @@
|
|||||||
<ClCompile Include="CompatPaletteConverter.cpp">
|
<ClCompile Include="CompatPaletteConverter.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Time.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="DDrawCompat.def">
|
<None Include="DDrawCompat.def">
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "CompatVtable.h"
|
#include "CompatVtable.h"
|
||||||
#include "DDrawProcs.h"
|
#include "DDrawProcs.h"
|
||||||
#include "DDrawRepository.h"
|
#include "DDrawRepository.h"
|
||||||
|
#include "Time.h"
|
||||||
|
|
||||||
struct IDirectInput;
|
struct IDirectInput;
|
||||||
|
|
||||||
@ -166,6 +167,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/)
|
|||||||
|
|
||||||
SetProcessAffinityMask(GetCurrentProcess(), 1);
|
SetProcessAffinityMask(GetCurrentProcess(), 1);
|
||||||
SetThemeAppProperties(0);
|
SetThemeAppProperties(0);
|
||||||
|
Time::init();
|
||||||
|
|
||||||
if (Compat::origProcs.SetAppCompatData)
|
if (Compat::origProcs.SetAppCompatData)
|
||||||
{
|
{
|
||||||
|
@ -13,12 +13,11 @@
|
|||||||
#include "Hook.h"
|
#include "Hook.h"
|
||||||
#include "IReleaseNotifier.h"
|
#include "IReleaseNotifier.h"
|
||||||
#include "RealPrimarySurface.h"
|
#include "RealPrimarySurface.h"
|
||||||
|
#include "Time.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
long long msToQpc(int ms);
|
|
||||||
void onRelease();
|
void onRelease();
|
||||||
int qpcToMs(long long qpc);
|
|
||||||
void updateNow(long long qpcNow);
|
void updateNow(long long qpcNow);
|
||||||
|
|
||||||
IDirectDrawSurface7* g_frontBuffer = nullptr;
|
IDirectDrawSurface7* g_frontBuffer = nullptr;
|
||||||
@ -28,7 +27,6 @@ namespace
|
|||||||
HANDLE g_updateThread = nullptr;
|
HANDLE g_updateThread = nullptr;
|
||||||
HANDLE g_updateEvent = nullptr;
|
HANDLE g_updateEvent = nullptr;
|
||||||
RECT g_updateRect = {};
|
RECT g_updateRect = {};
|
||||||
long long g_qpcFrequency = 0;
|
|
||||||
long long g_qpcMinUpdateInterval = 0;
|
long long g_qpcMinUpdateInterval = 0;
|
||||||
std::atomic<long long> g_qpcNextUpdate = 0;
|
std::atomic<long long> g_qpcNextUpdate = 0;
|
||||||
|
|
||||||
@ -95,15 +93,10 @@ namespace
|
|||||||
|
|
||||||
bool isNextUpdateSignaledAndReady(long long qpcNow)
|
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);
|
WAIT_OBJECT_0 == WaitForSingleObject(g_updateEvent, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
long long msToQpc(int ms)
|
|
||||||
{
|
|
||||||
return static_cast<long long>(ms) * g_qpcFrequency / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onRelease()
|
void onRelease()
|
||||||
{
|
{
|
||||||
Compat::LogEnter("RealPrimarySurface::onRelease");
|
Compat::LogEnter("RealPrimarySurface::onRelease");
|
||||||
@ -120,18 +113,6 @@ namespace
|
|||||||
Compat::LogLeave("RealPrimarySurface::onRelease");
|
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)
|
void updateNow(long long qpcNow)
|
||||||
{
|
{
|
||||||
ResetEvent(g_updateEvent);
|
ResetEvent(g_updateEvent);
|
||||||
@ -139,7 +120,7 @@ namespace
|
|||||||
if (compatBlt(g_frontBuffer))
|
if (compatBlt(g_frontBuffer))
|
||||||
{
|
{
|
||||||
long long qpcNextUpdate = getNextUpdateQpc(qpcNow);
|
long long qpcNextUpdate = getNextUpdateQpc(qpcNow);
|
||||||
if (qpcToMs(qpcNow - qpcNextUpdate) >= 0)
|
if (Time::qpcToMs(qpcNow - qpcNextUpdate) >= 0)
|
||||||
{
|
{
|
||||||
qpcNextUpdate += g_qpcMinUpdateInterval;
|
qpcNextUpdate += g_qpcMinUpdateInterval;
|
||||||
}
|
}
|
||||||
@ -154,14 +135,15 @@ namespace
|
|||||||
WaitForSingleObject(g_updateEvent, INFINITE);
|
WaitForSingleObject(g_updateEvent, INFINITE);
|
||||||
|
|
||||||
const long long qpcTargetNextUpdate = g_qpcNextUpdate;
|
const long long qpcTargetNextUpdate = g_qpcNextUpdate;
|
||||||
const int msUntilNextUpdate = qpcToMs(qpcTargetNextUpdate - queryPerformanceCounter());
|
const int msUntilNextUpdate =
|
||||||
|
Time::qpcToMs(qpcTargetNextUpdate - Time::queryPerformanceCounter());
|
||||||
if (msUntilNextUpdate > 0)
|
if (msUntilNextUpdate > 0)
|
||||||
{
|
{
|
||||||
Sleep(msUntilNextUpdate);
|
Sleep(msUntilNextUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
Compat::DDrawScopedThreadLock lock;
|
Compat::DDrawScopedThreadLock lock;
|
||||||
const long long qpcNow = queryPerformanceCounter();
|
const long long qpcNow = Time::queryPerformanceCounter();
|
||||||
const bool isTargetUpdateStillNeeded = qpcTargetNextUpdate == g_qpcNextUpdate;
|
const bool isTargetUpdateStillNeeded = qpcTargetNextUpdate == g_qpcNextUpdate;
|
||||||
if (g_frontBuffer && (isTargetUpdateStillNeeded || isNextUpdateSignaledAndReady(qpcNow)))
|
if (g_frontBuffer && (isTargetUpdateStillNeeded || isNextUpdateSignaledAndReady(qpcNow)))
|
||||||
{
|
{
|
||||||
@ -224,11 +206,8 @@ HRESULT RealPrimarySurface::create(DirectDraw& dd)
|
|||||||
g_frontBuffer->lpVtbl->GetAttachedSurface(g_frontBuffer, &backBufferCaps, &g_backBuffer);
|
g_frontBuffer->lpVtbl->GetAttachedSurface(g_frontBuffer, &backBufferCaps, &g_backBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
LARGE_INTEGER qpc;
|
g_qpcMinUpdateInterval = Time::g_qpcFrequency / Config::maxPrimaryUpdateRate;
|
||||||
QueryPerformanceFrequency(&qpc);
|
g_qpcNextUpdate = Time::queryPerformanceCounter();
|
||||||
g_qpcFrequency = qpc.QuadPart;
|
|
||||||
g_qpcMinUpdateInterval = g_qpcFrequency / Config::maxPrimaryUpdateRate;
|
|
||||||
g_qpcNextUpdate = queryPerformanceCounter();
|
|
||||||
|
|
||||||
if (!g_updateEvent)
|
if (!g_updateEvent)
|
||||||
{
|
{
|
||||||
@ -275,7 +254,7 @@ HRESULT RealPrimarySurface::flip(DWORD flags)
|
|||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(result))
|
||||||
{
|
{
|
||||||
g_qpcNextUpdate = getNextUpdateQpc(
|
g_qpcNextUpdate = getNextUpdateQpc(
|
||||||
queryPerformanceCounter() + msToQpc(Config::primaryUpdateDelayAfterFlip));
|
Time::queryPerformanceCounter() + Time::msToQpc(Config::primaryUpdateDelayAfterFlip));
|
||||||
SetRectEmpty(&g_updateRect);
|
SetRectEmpty(&g_updateRect);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -354,8 +333,8 @@ void RealPrimarySurface::update()
|
|||||||
{
|
{
|
||||||
if (!IsRectEmpty(&g_updateRect))
|
if (!IsRectEmpty(&g_updateRect))
|
||||||
{
|
{
|
||||||
const long long qpcNow = queryPerformanceCounter();
|
const long long qpcNow = Time::queryPerformanceCounter();
|
||||||
if (qpcToMs(qpcNow - g_qpcNextUpdate) >= 0)
|
if (Time::qpcToMs(qpcNow - g_qpcNextUpdate) >= 0)
|
||||||
{
|
{
|
||||||
updateNow(qpcNow);
|
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