1
0
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:
narzoul 2016-04-17 14:22:55 +02:00
parent d4042f7e95
commit cc5a4c7cef
10 changed files with 109 additions and 38 deletions

View File

@ -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());
}

View File

@ -14,4 +14,6 @@ public:
DWORD dwStartingEntry, DWORD dwStartingEntry,
DWORD dwCount, DWORD dwCount,
LPPALETTEENTRY lpEntries); LPPALETTEENTRY lpEntries);
static void waitForNextUpdate();
}; };

View File

@ -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);

View File

@ -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;

View File

@ -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>

View File

@ -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">

View File

@ -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)
{ {

View File

@ -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
View 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
View 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;
}
}