From cf08f101629eecaf0dcb7e00e1266daac96435c2 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 21 May 2016 15:21:43 +0200 Subject: [PATCH] Improved GetPixel performance via DDLOCK_READONLY Reduces Diablo II startup time. --- DDrawCompat/CompatGdi.cpp | 28 ++++++++++++++++++++++------ DDrawCompat/CompatGdi.h | 2 +- DDrawCompat/CompatGdiDcFunctions.cpp | 18 +++++++++++++++++- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/DDrawCompat/CompatGdi.cpp b/DDrawCompat/CompatGdi.cpp index 4361486..a3e78db 100644 --- a/DDrawCompat/CompatGdi.cpp +++ b/DDrawCompat/CompatGdi.cpp @@ -17,6 +17,7 @@ namespace { std::atomic g_disableEmulationCount = 0; DWORD g_renderingRefCount = 0; + DWORD g_ddLockFlags = 0; DWORD g_ddLockThreadRenderingRefCount = 0; DWORD g_ddLockThreadId = 0; HANDLE g_ddUnlockBeginEvent = nullptr; @@ -53,16 +54,22 @@ namespace return TRUE; } - bool lockPrimarySurface() + bool lockPrimarySurface(DWORD lockFlags) { DDSURFACEDESC2 desc = {}; desc.dwSize = sizeof(desc); auto primary(CompatPrimarySurface::getPrimary()); - if (FAILED(primary->Lock(primary, nullptr, &desc, DDLOCK_WAIT, nullptr))) + if (FAILED(primary->Lock(primary, nullptr, &desc, lockFlags | DDLOCK_WAIT, nullptr))) { return false; } + g_ddLockFlags = lockFlags; + if (0 != lockFlags) + { + EnterCriticalSection(&CompatGdi::g_gdiCriticalSection); + } + g_ddLockThreadId = GetCurrentThreadId(); CompatGdiDcCache::setDdLockThreadId(g_ddLockThreadId); CompatGdiDcCache::setSurfaceMemory(desc.lpSurface, desc.lPitch); @@ -74,8 +81,17 @@ namespace GdiFlush(); auto primary(CompatPrimarySurface::getPrimary()); primary->Unlock(primary, nullptr); - RealPrimarySurface::invalidate(nullptr); - RealPrimarySurface::update(); + if (DDLOCK_READONLY != g_ddLockFlags) + { + RealPrimarySurface::invalidate(nullptr); + RealPrimarySurface::update(); + } + + if (0 != g_ddLockFlags) + { + LeaveCriticalSection(&CompatGdi::g_gdiCriticalSection); + } + g_ddLockFlags = 0; Compat::origProcs.ReleaseDDThreadLock(); } @@ -85,7 +101,7 @@ namespace CompatGdi { CRITICAL_SECTION g_gdiCriticalSection; - bool beginGdiRendering() + bool beginGdiRendering(DWORD lockFlags) { if (!isEmulationEnabled()) { @@ -99,7 +115,7 @@ namespace CompatGdi LeaveCriticalSection(&g_gdiCriticalSection); Compat::origProcs.AcquireDDThreadLock(); EnterCriticalSection(&g_gdiCriticalSection); - if (!lockPrimarySurface()) + if (!lockPrimarySurface(lockFlags)) { Compat::origProcs.ReleaseDDThreadLock(); return false; diff --git a/DDrawCompat/CompatGdi.h b/DDrawCompat/CompatGdi.h index 80f8021..a2668e7 100644 --- a/DDrawCompat/CompatGdi.h +++ b/DDrawCompat/CompatGdi.h @@ -6,7 +6,7 @@ namespace CompatGdi { - bool beginGdiRendering(); + bool beginGdiRendering(DWORD lockFlags = 0); void endGdiRendering(); void disableEmulation(); diff --git a/DDrawCompat/CompatGdiDcFunctions.cpp b/DDrawCompat/CompatGdiDcFunctions.cpp index e363069..90a0b35 100644 --- a/DDrawCompat/CompatGdiDcFunctions.cpp +++ b/DDrawCompat/CompatGdiDcFunctions.cpp @@ -10,6 +10,9 @@ namespace { std::unordered_map g_funcNames; + template + DWORD getDdLockFlags(Params... params); + BOOL WINAPI GdiDrawStream(HDC, DWORD, DWORD) { return FALSE; } BOOL WINAPI PolyPatBlt(HDC, DWORD, DWORD, DWORD, DWORD) { return FALSE; } @@ -67,7 +70,8 @@ namespace Compat::LogEnter(g_funcNames[origFunc], params...); #endif - if (!hasDisplayDcArg(params...) || !CompatGdi::beginGdiRendering()) + if (!hasDisplayDcArg(params...) || + !CompatGdi::beginGdiRendering(getDdLockFlags(params...))) { Result result = Compat::getOrigFuncPtr()(params...); @@ -107,6 +111,18 @@ namespace return &compatGdiDcFunc; } + template + DWORD getDdLockFlags(Params...) + { + return 0; + } + + template <> + DWORD getDdLockFlags(HDC, int, int) + { + return DDLOCK_READONLY; + } + template void hookGdiDcFunction(const char* moduleName, const char* funcName) {