From c8ecb227a3186e43856fdc46b4521aa4fd51ec5e Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 22 May 2016 13:45:38 +0200 Subject: [PATCH] GDI performance enhancements --- DDrawCompat/CompatDisplayMode.cpp | 76 ++++++++++++++++++++++++++- DDrawCompat/CompatDisplayMode.h | 5 ++ DDrawCompat/CompatGdiDcFunctions.cpp | 77 ++++++++++++++++++++++++++-- 3 files changed, 152 insertions(+), 6 deletions(-) diff --git a/DDrawCompat/CompatDisplayMode.cpp b/DDrawCompat/CompatDisplayMode.cpp index 4535369..d8d7fc1 100644 --- a/DDrawCompat/CompatDisplayMode.cpp +++ b/DDrawCompat/CompatDisplayMode.cpp @@ -1,9 +1,31 @@ #include "CompatDisplayMode.h" +#include "CompatPtr.h" +#include "DDrawProcs.h" +#include "DDrawRepository.h" +#include "Hook.h" namespace { + CompatWeakPtr g_compatibleSurface = {}; + HDC g_compatibleDc = nullptr; CompatDisplayMode::DisplayMode g_emulatedDisplayMode = {}; + CompatPtr createCompatibleSurface() + { + DDSURFACEDESC2 desc = {}; + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + desc.dwWidth = 1; + desc.dwHeight = 1; + desc.ddpfPixelFormat = g_emulatedDisplayMode.pixelFormat; + desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + + auto dd = DDrawRepository::getDirectDraw(); + CompatPtr surface; + dd->CreateSurface(dd, &desc, &surface.getRef(), nullptr); + return surface; + } + template HRESULT PASCAL enumDisplayModesCallback( TSurfaceDesc* lpDDSurfaceDesc, @@ -49,13 +71,63 @@ namespace Compat::Log() << "Failed to find the requested display mode: " << width << "x" << height << "x" << bpp; } - + return pf; } + + void releaseCompatibleDc() + { + if (g_compatibleDc) + { + Compat::origProcs.AcquireDDThreadLock(); + g_compatibleSurface->ReleaseDC(g_compatibleSurface, g_compatibleDc); + g_compatibleDc = nullptr; + g_compatibleSurface.release(); + } + } + + void replaceDc(HDC& hdc) + { + if (g_compatibleDc && hdc && OBJ_DC == GetObjectType(hdc) && + DT_RASDISPLAY == GetDeviceCaps(hdc, TECHNOLOGY)) + { + hdc = g_compatibleDc; + } + } + + void updateCompatibleDc() + { + releaseCompatibleDc(); + g_compatibleSurface = createCompatibleSurface().detach(); + if (g_compatibleSurface && + SUCCEEDED(g_compatibleSurface->GetDC(g_compatibleSurface, &g_compatibleDc))) + { + Compat::origProcs.ReleaseDDThreadLock(); + } + } } namespace CompatDisplayMode { + HBITMAP WINAPI createCompatibleBitmap(HDC hdc, int cx, int cy) + { + replaceDc(hdc); + return CALL_ORIG_FUNC(CreateCompatibleBitmap)(hdc, cx, cy); + } + + HBITMAP WINAPI createDIBitmap(HDC hdc, const BITMAPINFOHEADER* lpbmih, DWORD fdwInit, + const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage) + { + replaceDc(hdc); + return CALL_ORIG_FUNC(CreateDIBitmap)(hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage); + } + + HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight) + { + replaceDc(hdc); + return CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight); + } + DisplayMode getDisplayMode(CompatRef dd) { if (0 == g_emulatedDisplayMode.width) @@ -85,6 +157,7 @@ namespace CompatDisplayMode if (SUCCEEDED(result)) { ZeroMemory(&g_emulatedDisplayMode, sizeof(g_emulatedDisplayMode)); + releaseCompatibleDc(); } return result; } @@ -111,6 +184,7 @@ namespace CompatDisplayMode g_emulatedDisplayMode.pixelFormat = pf; g_emulatedDisplayMode.refreshRate = refreshRate; g_emulatedDisplayMode.flags = flags; + updateCompatibleDc(); return DD_OK; } diff --git a/DDrawCompat/CompatDisplayMode.h b/DDrawCompat/CompatDisplayMode.h index 65e0d68..6cbb816 100644 --- a/DDrawCompat/CompatDisplayMode.h +++ b/DDrawCompat/CompatDisplayMode.h @@ -17,6 +17,11 @@ namespace CompatDisplayMode DWORD flags; }; + HBITMAP WINAPI createCompatibleBitmap(HDC hdc, int cx, int cy); + HBITMAP WINAPI createDIBitmap(HDC hdc, const BITMAPINFOHEADER* lpbmih, DWORD fdwInit, + const void* lpbInit, const BITMAPINFO* lpbmi, UINT fuUsage); + HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight); + DisplayMode getDisplayMode(CompatRef dd); DisplayMode getRealDisplayMode(CompatRef dd); HRESULT restoreDisplayMode(CompatRef dd); diff --git a/DDrawCompat/CompatGdiDcFunctions.cpp b/DDrawCompat/CompatGdiDcFunctions.cpp index 90a0b35..77c0ca8 100644 --- a/DDrawCompat/CompatGdiDcFunctions.cpp +++ b/DDrawCompat/CompatGdiDcFunctions.cpp @@ -1,5 +1,6 @@ #include +#include "CompatDisplayMode.h" #include "CompatGdi.h" #include "CompatGdiDc.h" #include "CompatGdiDcFunctions.h" @@ -111,18 +112,86 @@ namespace return &compatGdiDcFunc; } + DWORD getDdLockFlagsBlt(HDC hdcDest, HDC hdcSrc) + { + return hasDisplayDcArg(hdcSrc) && !hasDisplayDcArg(hdcDest) ? DDLOCK_READONLY : 0; + } + template DWORD getDdLockFlags(Params...) { return 0; } + template <> + DWORD getDdLockFlags( + HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, BLENDFUNCTION) + { + return getDdLockFlagsBlt(hdcDest, hdcSrc); + } + + template <> + DWORD getDdLockFlags( + HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, DWORD) + { + return getDdLockFlagsBlt(hdcDest, hdcSrc); + } + + template <> + DWORD getDdLockFlags( + HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, BLENDFUNCTION) + { + return getDdLockFlagsBlt(hdcDest, hdcSrc); + } + + template <> + DWORD getDdLockFlags( + HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, UINT) + { + return getDdLockFlagsBlt(hdcDest, hdcSrc); + } + + template <> + DWORD getDdLockFlags( + HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT) + { + return DDLOCK_READONLY; + } + template <> DWORD getDdLockFlags(HDC, int, int) { return DDLOCK_READONLY; } + template <> + DWORD getDdLockFlags( + HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, HBITMAP, int, int, DWORD) + { + return getDdLockFlagsBlt(hdcDest, hdcSrc); + } + + template <> + DWORD getDdLockFlags( + HDC hdcDest, const POINT*, HDC hdcSrc, int, int, int, int, HBITMAP, int, int) + { + return getDdLockFlagsBlt(hdcDest, hdcSrc); + } + + template <> + DWORD getDdLockFlags( + HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, DWORD) + { + return getDdLockFlagsBlt(hdcDest, hdcSrc); + } + + template <> + DWORD getDdLockFlags( + HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, UINT) + { + return getDdLockFlagsBlt(hdcDest, hdcSrc); + } + template void hookGdiDcFunction(const char* moduleName, const char* funcName) { @@ -154,10 +223,9 @@ namespace CompatGdiDcFunctions // Bitmap functions HOOK_GDI_DC_FUNCTION(msimg32, AlphaBlend); HOOK_GDI_DC_FUNCTION(gdi32, BitBlt); - HOOK_GDI_DC_FUNCTION(gdi32, CreateCompatibleBitmap); - HOOK_GDI_DC_FUNCTION(gdi32, CreateDIBitmap); - HOOK_GDI_DC_FUNCTION(gdi32, CreateDIBSection); - HOOK_GDI_DC_FUNCTION(gdi32, CreateDiscardableBitmap); + HOOK_FUNCTION(gdi32, CreateCompatibleBitmap, CompatDisplayMode::createCompatibleBitmap); + HOOK_FUNCTION(gdi32, CreateDIBitmap, CompatDisplayMode::createDIBitmap); + HOOK_FUNCTION(gdi32, CreateDiscardableBitmap, CompatDisplayMode::createDiscardableBitmap); HOOK_GDI_DC_FUNCTION(gdi32, ExtFloodFill); HOOK_GDI_DC_FUNCTION(gdi32, GdiAlphaBlend); HOOK_GDI_DC_FUNCTION(gdi32, GdiGradientFill); @@ -179,7 +247,6 @@ namespace CompatGdiDcFunctions HOOK_GDI_DC_FUNCTION(gdi32, PatBlt); // Device context functions - HOOK_GDI_DC_FUNCTION(gdi32, CreateCompatibleDC); HOOK_GDI_DC_FUNCTION(gdi32, DrawEscape); HOOK_FUNCTION(user32, WindowFromDC, windowFromDc);