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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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