From cc5a4c7cef6ef3e29c3417ad526375acb647ea9c Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 17 Apr 2016 14:22:55 +0200 Subject: [PATCH] Readded palette animation support --- DDrawCompat/CompatDirectDrawPalette.cpp | 35 +++++++++++++++++--- DDrawCompat/CompatDirectDrawPalette.h | 2 ++ DDrawCompat/CompatDirectDrawSurface.cpp | 12 +++++-- DDrawCompat/Config.h | 1 + DDrawCompat/DDrawCompat.vcxproj | 2 ++ DDrawCompat/DDrawCompat.vcxproj.filters | 6 ++++ DDrawCompat/DllMain.cpp | 2 ++ DDrawCompat/RealPrimarySurface.cpp | 43 +++++++------------------ DDrawCompat/Time.cpp | 15 +++++++++ DDrawCompat/Time.h | 29 +++++++++++++++++ 10 files changed, 109 insertions(+), 38 deletions(-) create mode 100644 DDrawCompat/Time.cpp create mode 100644 DDrawCompat/Time.h diff --git a/DDrawCompat/CompatDirectDrawPalette.cpp b/DDrawCompat/CompatDirectDrawPalette.cpp index 2fa6358..a0eccb9 100644 --- a/DDrawCompat/CompatDirectDrawPalette.cpp +++ b/DDrawCompat/CompatDirectDrawPalette.cpp @@ -1,8 +1,11 @@ #include +#include #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 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()); +} diff --git a/DDrawCompat/CompatDirectDrawPalette.h b/DDrawCompat/CompatDirectDrawPalette.h index e2e02ce..277b93a 100644 --- a/DDrawCompat/CompatDirectDrawPalette.h +++ b/DDrawCompat/CompatDirectDrawPalette.h @@ -14,4 +14,6 @@ public: DWORD dwStartingEntry, DWORD dwCount, LPPALETTEENTRY lpEntries); + + static void waitForNextUpdate(); }; diff --git a/DDrawCompat/CompatDirectDrawSurface.cpp b/DDrawCompat/CompatDirectDrawSurface.cpp index 8d2e163..a2469d3 100644 --- a/DDrawCompat/CompatDirectDrawSurface.cpp +++ b/DDrawCompat/CompatDirectDrawSurface.cpp @@ -3,6 +3,7 @@ #include #include "CompatDirectDraw.h" +#include "CompatDirectDrawPalette.h" #include "CompatDirectDrawSurface.h" #include "CompatGdi.h" #include "CompatPrimarySurface.h" @@ -640,9 +641,16 @@ HRESULT STDMETHODCALLTYPE CompatDirectDrawSurface::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); diff --git a/DDrawCompat/Config.h b/DDrawCompat/Config.h index 9882c47..ebfcaaa 100644 --- a/DDrawCompat/Config.h +++ b/DDrawCompat/Config.h @@ -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; diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index d236c99..2fdf64e 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -175,6 +175,7 @@ + @@ -201,6 +202,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index d07cb63..53158a7 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -108,6 +108,9 @@ Header Files + + Header Files + @@ -185,6 +188,9 @@ Source Files + + Source Files + diff --git a/DDrawCompat/DllMain.cpp b/DDrawCompat/DllMain.cpp index e0fb0cc..18118e4 100644 --- a/DDrawCompat/DllMain.cpp +++ b/DDrawCompat/DllMain.cpp @@ -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) { diff --git a/DDrawCompat/RealPrimarySurface.cpp b/DDrawCompat/RealPrimarySurface.cpp index 8e39557..cffad3e 100644 --- a/DDrawCompat/RealPrimarySurface.cpp +++ b/DDrawCompat/RealPrimarySurface.cpp @@ -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 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(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(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); } diff --git a/DDrawCompat/Time.cpp b/DDrawCompat/Time.cpp new file mode 100644 index 0000000..f1e0c09 --- /dev/null +++ b/DDrawCompat/Time.cpp @@ -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; + } +} diff --git a/DDrawCompat/Time.h b/DDrawCompat/Time.h new file mode 100644 index 0000000..d1eccc3 --- /dev/null +++ b/DDrawCompat/Time.h @@ -0,0 +1,29 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN + +#include + +namespace Time +{ + extern long long g_qpcFrequency; + + void init(); + + inline long long msToQpc(int ms) + { + return static_cast(ms) * g_qpcFrequency / 1000; + } + + inline int qpcToMs(long long qpc) + { + return static_cast(qpc * 1000 / g_qpcFrequency); + } + + inline long long queryPerformanceCounter() + { + LARGE_INTEGER qpc = {}; + QueryPerformanceCounter(&qpc); + return qpc.QuadPart; + } +}