From 727be63db1966ded74f425de6d12c827cdcaafc6 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 25 Nov 2018 16:15:53 +0100 Subject: [PATCH] Implement GDI system palette emulation --- DDrawCompat/D3dDdi/KernelModeThunks.cpp | 2 +- DDrawCompat/DDraw/DirectDraw.cpp | 17 +- DDrawCompat/DDraw/DirectDraw.h | 1 + DDrawCompat/DDraw/DirectDrawClipper.cpp | 2 +- DDrawCompat/DDraw/DirectDrawPalette.cpp | 5 +- DDrawCompat/DDraw/RealPrimarySurface.cpp | 24 +- DDrawCompat/DDraw/RealPrimarySurface.h | 2 - DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp | 9 + DDrawCompat/DDraw/Surfaces/PrimarySurface.h | 1 + .../DDraw/Surfaces/PrimarySurfaceImpl.cpp | 2 +- DDrawCompat/DDraw/Surfaces/Surface.cpp | 9 +- DDrawCompat/DDrawCompat.vcxproj | 2 + DDrawCompat/DDrawCompat.vcxproj.filters | 6 + DDrawCompat/Gdi/Caret.cpp | 2 +- DDrawCompat/Gdi/Dc.cpp | 4 + DDrawCompat/Gdi/DcFunctions.cpp | 55 +++-- DDrawCompat/Gdi/Gdi.cpp | 10 +- DDrawCompat/Gdi/Gdi.h | 1 + DDrawCompat/Gdi/PaintHandlers.cpp | 2 +- DDrawCompat/Gdi/Palette.cpp | 224 ++++++++++++++++++ DDrawCompat/Gdi/Palette.h | 9 + DDrawCompat/Gdi/VirtualScreen.cpp | 7 +- DDrawCompat/Gdi/WinProc.cpp | 8 +- DDrawCompat/Gdi/Window.cpp | 2 +- DDrawCompat/Win32/DisplayMode.cpp | 65 +---- DDrawCompat/Win32/DisplayMode.h | 5 - 26 files changed, 348 insertions(+), 128 deletions(-) create mode 100644 DDrawCompat/Gdi/Palette.cpp create mode 100644 DDrawCompat/Gdi/Palette.h diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index 5112e2a..f7958a6 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -225,7 +225,7 @@ namespace { g_gdiAdapterInfo = getAdapterInfo(data); } - ReleaseDC(nullptr, data.hDc); + CALL_ORIG_FUNC(ReleaseDC)(nullptr, data.hDc); lastDisplaySettingsUniqueness = currentDisplaySettingsUniqueness; } diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index c5b7783..85a6e45 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -20,7 +20,7 @@ namespace { Win32::DisplayMode::setDDrawBpp(bpp); HRESULT result = DDraw::DirectDraw::s_origVtable.SetDisplayMode( - This, width, height, bpp, refreshRate, flags); + This, width, height, 32, refreshRate, flags); Win32::DisplayMode::setDDrawBpp(0); return result; } @@ -59,7 +59,7 @@ namespace DDraw { DDSURFACEDESC2 dm = {}; dm.dwSize = sizeof(dm); - dd->GetDisplayMode(&dd, &dm); + dd.get().lpVtbl->GetDisplayMode(&dd, &dm); return dm; } @@ -114,6 +114,7 @@ namespace DDraw { vtable.CreateSurface = &CreateSurface; vtable.FlipToGDISurface = &FlipToGDISurface; + vtable.GetDisplayMode = &GetDisplayMode; vtable.GetGDISurface = &GetGDISurface; vtable.SetCooperativeLevel = &SetCooperativeLevel; vtable.SetDisplayMode = &SetDisplayMode; @@ -148,6 +149,18 @@ namespace DDraw return PrimarySurface::flipToGdiSurface(); } + template + HRESULT STDMETHODCALLTYPE DirectDraw::GetDisplayMode( + TDirectDraw* This, TSurfaceDesc* lpDDSurfaceDesc) + { + HRESULT result = s_origVtable.GetDisplayMode(This, lpDDSurfaceDesc); + if (SUCCEEDED(result) && lpDDSurfaceDesc) + { + lpDDSurfaceDesc->ddpfPixelFormat = getRgbPixelFormat(Win32::DisplayMode::getBpp()); + } + return result; + } + template HRESULT STDMETHODCALLTYPE DirectDraw::GetGDISurface( TDirectDraw* /*This*/, TSurface** lplpGDIDDSSurface) diff --git a/DDrawCompat/DDraw/DirectDraw.h b/DDrawCompat/DDraw/DirectDraw.h index 4c1ab09..b9562ce 100644 --- a/DDrawCompat/DDraw/DirectDraw.h +++ b/DDrawCompat/DDraw/DirectDraw.h @@ -35,6 +35,7 @@ namespace DDraw IUnknown* pUnkOuter); static HRESULT STDMETHODCALLTYPE FlipToGDISurface(TDirectDraw* This); + static HRESULT STDMETHODCALLTYPE GetDisplayMode(TDirectDraw* This, TSurfaceDesc* lpDDSurfaceDesc); static HRESULT STDMETHODCALLTYPE GetGDISurface(TDirectDraw* This, TSurface** lplpGDIDDSSurface); static HRESULT STDMETHODCALLTYPE Initialize(TDirectDraw* This, GUID* lpGUID); static HRESULT STDMETHODCALLTYPE SetCooperativeLevel(TDirectDraw* This, HWND hWnd, DWORD dwFlags); diff --git a/DDrawCompat/DDraw/DirectDrawClipper.cpp b/DDrawCompat/DDraw/DirectDrawClipper.cpp index bb0a3c6..4191b5e 100644 --- a/DDrawCompat/DDraw/DirectDrawClipper.cpp +++ b/DDrawCompat/DDraw/DirectDrawClipper.cpp @@ -42,7 +42,7 @@ namespace } DeleteObject(rgn); - ReleaseDC(data.hwnd, dc); + CALL_ORIG_FUNC(ReleaseDC)(data.hwnd, dc); } HRESULT STDMETHODCALLTYPE GetHWnd(IDirectDrawClipper* This, HWND* lphWnd) diff --git a/DDrawCompat/DDraw/DirectDrawPalette.cpp b/DDrawCompat/DDraw/DirectDrawPalette.cpp index 56e7c8f..077d3a5 100644 --- a/DDrawCompat/DDraw/DirectDrawPalette.cpp +++ b/DDrawCompat/DDraw/DirectDrawPalette.cpp @@ -4,7 +4,6 @@ #include "Common/Time.h" #include "Config/Config.h" #include "DDraw/DirectDrawPalette.h" -#include "DDraw/RealPrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h" #include "Gdi/AccessGuard.h" @@ -36,9 +35,7 @@ namespace DDraw HRESULT result = s_origVtable.SetEntries(This, dwFlags, dwStartingEntry, dwCount, lpEntries); if (This == PrimarySurface::s_palette && SUCCEEDED(result)) { - std::memcpy(&PrimarySurface::s_paletteEntries[dwStartingEntry], lpEntries, - dwCount * sizeof(PALETTEENTRY)); - RealPrimarySurface::updatePalette(); + PrimarySurface::updatePalette(); } return result; } diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index c185535..e02d7da 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -116,7 +116,7 @@ namespace RECT rect = windowPair.second->getWindowRect(); CALL_ORIG_FUNC(BitBlt)(dc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, virtualScreenDc.get(), rect.left, rect.top, SRCCOPY); - ReleaseDC(presentationWindow, dc); + CALL_ORIG_FUNC(ReleaseDC)(presentationWindow, dc); } } @@ -152,7 +152,7 @@ namespace SelectClipRgn(backBufferDc, nullptr); DeleteObject(rgn); - ReleaseDC(*it, windowDc); + CALL_ORIG_FUNC(ReleaseDC)(*it, windowDc); } backBuffer->ReleaseDC(backBuffer, backBufferDc); @@ -667,17 +667,6 @@ namespace DDraw return gammaControl->SetGammaRamp(gammaControl, 0, rampData); } - void RealPrimarySurface::setPalette() - { - DDraw::ScopedThreadLock lock; - if (g_surfaceDesc.ddpfPixelFormat.dwRGBBitCount <= 8) - { - g_frontBuffer->SetPalette(g_frontBuffer, PrimarySurface::s_palette); - } - - updatePalette(); - } - void RealPrimarySurface::update() { DDraw::ScopedThreadLock lock; @@ -689,15 +678,6 @@ namespace DDraw } } - void RealPrimarySurface::updatePalette() - { - DDraw::ScopedThreadLock lock; - if (PrimarySurface::s_palette) - { - update(); - } - } - bool RealPrimarySurface::waitForFlip(Surface* surface, bool wait) { auto primary(DDraw::PrimarySurface::getPrimary()); diff --git a/DDrawCompat/DDraw/RealPrimarySurface.h b/DDrawCompat/DDraw/RealPrimarySurface.h index 5126453..518afca 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.h +++ b/DDrawCompat/DDraw/RealPrimarySurface.h @@ -27,9 +27,7 @@ namespace DDraw static void removeUpdateThread(); static HRESULT restore(); static HRESULT setGammaRamp(DDGAMMARAMP* rampData); - static void setPalette(); static void update(); - static void updatePalette(); static bool waitForFlip(Surface* surface, bool wait = true); }; } diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index 78e67ef..2223416 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -231,6 +231,15 @@ namespace DDraw } while (surfacePtr && surfacePtr != g_primarySurface.get()); } + void PrimarySurface::updatePalette() + { + if (s_palette) + { + PrimarySurface::s_palette->GetEntries(s_palette, 0, 0, 256, s_paletteEntries); + RealPrimarySurface::update(); + } + } + CompatWeakPtr PrimarySurface::s_palette; PALETTEENTRY PrimarySurface::s_paletteEntries[256] = {}; std::vector> PrimarySurface::s_surfaceBuffers; diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h index 2f59f64..e0f5802 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h @@ -26,6 +26,7 @@ namespace DDraw static CompatWeakPtr getPrimary(); static DWORD getOrigCaps(); static void onRestore(); + static void updatePalette(); template static bool isGdiSurface(TSurface* surface); diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp index cb785b4..ec4d9d1 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp @@ -173,7 +173,7 @@ namespace DDraw if (SUCCEEDED(result)) { PrimarySurface::s_palette = lpDDPalette; - RealPrimarySurface::setPalette(); + PrimarySurface::updatePalette(); } return result; } diff --git a/DDrawCompat/DDraw/Surfaces/Surface.cpp b/DDrawCompat/DDraw/Surfaces/Surface.cpp index 01ab9a4..860775a 100644 --- a/DDrawCompat/DDraw/Surfaces/Surface.cpp +++ b/DDrawCompat/DDraw/Surfaces/Surface.cpp @@ -5,6 +5,7 @@ #include "DDraw/DirectDrawSurface.h" #include "DDraw/Surfaces/Surface.h" #include "DDraw/Surfaces/SurfaceImpl.h" +#include "Win32/DisplayMode.h" // {C62D8849-DFAC-4454-A1E8-DA67446426BA} DEFINE_GUID(IID_CompatSurfacePrivateData, @@ -15,8 +16,7 @@ namespace template HRESULT createSurface(CompatRef dd, TSurfaceDesc desc, TSurface*& surface) { - auto dd7(CompatPtr::from(&dd)); - fixSurfaceDesc(*dd7, desc.dwFlags, desc.ddsCaps.dwCaps, desc.ddpfPixelFormat); + fixSurfaceDesc(desc.dwFlags, desc.ddsCaps.dwCaps, desc.ddpfPixelFormat); if ((desc.ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN) && !(desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE))) @@ -35,7 +35,7 @@ namespace return dd->CreateSurface(&dd, &desc, &surface, nullptr); } - void fixSurfaceDesc(CompatRef dd, DWORD& flags, DWORD& caps, DDPIXELFORMAT& pf) + void fixSurfaceDesc(DWORD& flags, DWORD& caps, DDPIXELFORMAT& pf) { if ((flags & DDSD_WIDTH) && (flags & DDSD_HEIGHT) && @@ -43,9 +43,8 @@ namespace { if (!(flags & DDSD_PIXELFORMAT)) { - auto dm = DDraw::getDisplayMode(dd); flags |= DDSD_PIXELFORMAT; - pf = dm.ddpfPixelFormat; + pf = DDraw::getRgbPixelFormat(Win32::DisplayMode::getBpp()); } if ((pf.dwFlags & DDPF_RGB) && pf.dwRGBBitCount <= 8) diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 9160792..2f4a1fa 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -290,6 +290,7 @@ + @@ -350,6 +351,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index cd99b96..712998f 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -324,6 +324,9 @@ Header Files\Gdi + + Header Files\Gdi + @@ -500,6 +503,9 @@ Source Files\Gdi + + Source Files\Gdi + diff --git a/DDrawCompat/Gdi/Caret.cpp b/DDrawCompat/Gdi/Caret.cpp index e227292..a8ec942 100644 --- a/DDrawCompat/Gdi/Caret.cpp +++ b/DDrawCompat/Gdi/Caret.cpp @@ -43,7 +43,7 @@ namespace { HDC dc = GetDC(g_caret.hwnd); PatBlt(dc, g_caret.left, g_caret.top, g_caret.width, g_caret.height, PATINVERT); - ReleaseDC(g_caret.hwnd, dc); + CALL_ORIG_FUNC(ReleaseDC)(g_caret.hwnd, dc); } CaretData getCaretData(DWORD threadId) diff --git a/DDrawCompat/Gdi/Dc.cpp b/DDrawCompat/Gdi/Dc.cpp index 24d1c8b..2f634b1 100644 --- a/DDrawCompat/Gdi/Dc.cpp +++ b/DDrawCompat/Gdi/Dc.cpp @@ -24,6 +24,7 @@ namespace HGDIOBJ savedFont; HGDIOBJ savedBrush; HGDIOBJ savedPen; + HPALETTE savedPalette; }; typedef std::unordered_map CompatDcMap; @@ -37,6 +38,8 @@ namespace SelectObject(compatDc.dc, compatDc.savedFont = GetCurrentObject(origDc, OBJ_FONT)); SelectObject(compatDc.dc, compatDc.savedBrush = GetCurrentObject(origDc, OBJ_BRUSH)); SelectObject(compatDc.dc, compatDc.savedPen = GetCurrentObject(origDc, OBJ_PEN)); + CALL_ORIG_FUNC(SelectPalette)( + compatDc.dc, compatDc.savedPalette = static_cast(GetCurrentObject(origDc, OBJ_PAL)), FALSE); const int graphicsMode = GetGraphicsMode(origDc); SetGraphicsMode(compatDc.dc, graphicsMode); @@ -104,6 +107,7 @@ namespace SelectObject(compatDc.dc, compatDc.savedFont); SelectObject(compatDc.dc, compatDc.savedBrush); SelectObject(compatDc.dc, compatDc.savedPen); + CALL_ORIG_FUNC(SelectPalette)(compatDc.dc, compatDc.savedPalette, FALSE); } } diff --git a/DDrawCompat/Gdi/DcFunctions.cpp b/DDrawCompat/Gdi/DcFunctions.cpp index 66f915c..b0373b5 100644 --- a/DDrawCompat/Gdi/DcFunctions.cpp +++ b/DDrawCompat/Gdi/DcFunctions.cpp @@ -67,8 +67,7 @@ namespace bool hasDisplayDcArg(HDC dc) { - return dc && OBJ_DC == GetObjectType(dc) && DT_RASDISPLAY == GetDeviceCaps(dc, TECHNOLOGY) && - !(GetWindowLongPtr(CALL_ORIG_FUNC(WindowFromDC)(dc), GWL_EXSTYLE) & WS_EX_LAYERED); + return Gdi::isDisplayDc(dc); } template @@ -153,6 +152,42 @@ namespace return LOG_RESULT(TRUE); } + HBITMAP WINAPI createCompatibleBitmap(HDC hdc, int cx, int cy) + { + LOG_FUNC("CreateCompatibleBitmap", hdc, cx, cy); + if (Gdi::isDisplayDc(hdc)) + { + return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(cx, cy)); + } + return LOG_RESULT(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) + { + LOG_FUNC("CreateDIBitmap", hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage); + if (lpbmih && (!(fdwInit & CBM_INIT) || lpbInit && lpbmi)) + { + HBITMAP bitmap = Gdi::VirtualScreen::createOffScreenDib(lpbmih->biWidth, std::abs(lpbmih->biHeight)); + if (bitmap && (fdwInit & CBM_INIT)) + { + SetDIBits(hdc, bitmap, 0, std::abs(lpbmih->biHeight), lpbInit, lpbmi, fuUsage); + } + return LOG_RESULT(bitmap); + } + return LOG_RESULT(CALL_ORIG_FUNC(CreateDIBitmap)(hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage)); + } + + HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight) + { + LOG_FUNC("CreateDiscardableBitmap", hdc, nWidth, nHeight); + if (Gdi::isDisplayDc(hdc)) + { + return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(nWidth, nHeight)); + } + return LOG_RESULT(CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight)); + } + BOOL CALLBACK excludeRgnForOverlappingWindow(HWND hwnd, LPARAM lParam) { auto& args = *reinterpret_cast(lParam); @@ -262,13 +297,6 @@ namespace return 1; } - UINT WINAPI realizePalette(HDC hdc) - { - UINT result = CALL_ORIG_FUNC(RealizePalette)(hdc); - Gdi::VirtualScreen::updatePalette(); - return result; - } - HWND WINAPI windowFromDc(HDC dc) { return CALL_ORIG_FUNC(WindowFromDC)(Gdi::Dc::getOrigDc(dc)); @@ -299,9 +327,9 @@ namespace Gdi // Bitmap functions HOOK_GDI_DC_FUNCTION(msimg32, AlphaBlend); HOOK_GDI_DC_FUNCTION(gdi32, BitBlt); - HOOK_FUNCTION(gdi32, CreateCompatibleBitmap, Win32::DisplayMode::createCompatibleBitmap); - HOOK_FUNCTION(gdi32, CreateDIBitmap, Win32::DisplayMode::createDIBitmap); - HOOK_FUNCTION(gdi32, CreateDiscardableBitmap, Win32::DisplayMode::createDiscardableBitmap); + HOOK_FUNCTION(gdi32, CreateCompatibleBitmap, createCompatibleBitmap); + HOOK_FUNCTION(gdi32, CreateDIBitmap, createDIBitmap); + HOOK_FUNCTION(gdi32, CreateDiscardableBitmap, createDiscardableBitmap); HOOK_GDI_DC_FUNCTION(gdi32, ExtFloodFill); HOOK_GDI_DC_FUNCTION(gdi32, GdiAlphaBlend); HOOK_GDI_DC_FUNCTION(gdi32, GdiGradientFill); @@ -325,9 +353,6 @@ namespace Gdi // Clipping functions HOOK_FUNCTION(gdi32, GetRandomRgn, getRandomRgn); - // Color functions - HOOK_SHIM_FUNCTION(RealizePalette, realizePalette); - // Device context functions HOOK_GDI_DC_FUNCTION(gdi32, DrawEscape); HOOK_FUNCTION(user32, WindowFromDC, windowFromDc); diff --git a/DDrawCompat/Gdi/Gdi.cpp b/DDrawCompat/Gdi/Gdi.cpp index 586d4ab..13af1c8 100644 --- a/DDrawCompat/Gdi/Gdi.cpp +++ b/DDrawCompat/Gdi/Gdi.cpp @@ -5,6 +5,7 @@ #include "Gdi/DcFunctions.h" #include "Gdi/Gdi.h" #include "Gdi/PaintHandlers.h" +#include "Gdi/Palette.h" #include "Gdi/ScrollFunctions.h" #include "Gdi/Window.h" #include "Gdi/WinProc.h" @@ -50,12 +51,19 @@ namespace Gdi DcFunctions::installHooks(); PaintHandlers::installHooks(); + Palette::installHooks(); ScrollFunctions::installHooks(); Window::installHooks(); WinProc::installHooks(); Caret::installHooks(); } + bool isDisplayDc(HDC dc) + { + return dc && OBJ_DC == GetObjectType(dc) && DT_RASDISPLAY == GetDeviceCaps(dc, TECHNOLOGY) && + !(GetWindowLongPtr(CALL_ORIG_FUNC(WindowFromDC)(dc), GWL_EXSTYLE) & WS_EX_LAYERED); + } + void redraw(HRGN rgn) { EnumWindows(&redrawWindowCallback, reinterpret_cast(rgn)); @@ -97,7 +105,7 @@ namespace Gdi Window::uninstallHooks(); Dc::dllProcessDetach(); DcCache::dllProcessDetach(); - ReleaseDC(nullptr, g_screenDc); + CALL_ORIG_FUNC(ReleaseDC)(nullptr, g_screenDc); } void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc) diff --git a/DDrawCompat/Gdi/Gdi.h b/DDrawCompat/Gdi/Gdi.h index a3b95ab..ef4a3bf 100644 --- a/DDrawCompat/Gdi/Gdi.h +++ b/DDrawCompat/Gdi/Gdi.h @@ -14,6 +14,7 @@ namespace Gdi HDC getScreenDc(); HRGN getVisibleWindowRgn(HWND hwnd); void installHooks(); + bool isDisplayDc(HDC dc); void redraw(HRGN rgn); void redrawWindow(HWND hwnd, HRGN rgn); void unhookWndProc(LPCSTR className, WNDPROC oldWndProc); diff --git a/DDrawCompat/Gdi/PaintHandlers.cpp b/DDrawCompat/Gdi/PaintHandlers.cpp index b2ddfd8..4bc9836 100644 --- a/DDrawCompat/Gdi/PaintHandlers.cpp +++ b/DDrawCompat/Gdi/PaintHandlers.cpp @@ -299,7 +299,7 @@ namespace Gdi::Dc::releaseDc(windowDc); } - ReleaseDC(hwnd, windowDc); + CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc); return 0; } diff --git a/DDrawCompat/Gdi/Palette.cpp b/DDrawCompat/Gdi/Palette.cpp new file mode 100644 index 0000000..80180ea --- /dev/null +++ b/DDrawCompat/Gdi/Palette.cpp @@ -0,0 +1,224 @@ +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include "Common/Hook.h" +#include "Common/Log.h" +#include "DDraw/ScopedThreadLock.h" +#include "DDraw/Surfaces/PrimarySurface.h" +#include "Gdi/Gdi.h" +#include "Gdi/Palette.h" +#include "VirtualScreen.h" +#include "Win32/DisplayMode.h" + +namespace +{ + PALETTEENTRY g_systemPalette[256] = {}; + UINT g_systemPaletteUse = SYSPAL_STATIC; + UINT g_systemPaletteFirstUnusedIndex = 10; + UINT g_systemPaletteFirstNonReservedIndex = 10; + UINT g_systemPaletteLastNonReservedIndex = 245; + + std::set g_foregroundPaletteDcs; + + bool isSameColor(PALETTEENTRY entry1, PALETTEENTRY entry2) + { + return entry1.peRed == entry2.peRed && + entry1.peGreen == entry2.peGreen && + entry1.peBlue == entry2.peBlue; + } + + bool exactMatch(PALETTEENTRY entry) + { + for (UINT i = 0; i < g_systemPaletteFirstUnusedIndex; ++i) + { + if (isSameColor(entry, g_systemPalette[i])) + { + return true; + } + } + + for (UINT i = g_systemPaletteLastNonReservedIndex + 1; i < 256; ++i) + { + if (isSameColor(entry, g_systemPalette[i])) + { + return true; + } + } + + return false; + } + + UINT fillSystemPalette(HDC dc) + { + HPALETTE palette = reinterpret_cast(GetCurrentObject(dc, OBJ_PAL)); + if (!palette || GetStockObject(DEFAULT_PALETTE) == palette) + { + return 0; + } + + PALETTEENTRY entries[256] = {}; + UINT count = GetPaletteEntries(palette, 0, 256, entries); + for (UINT i = 0; + i < count && g_systemPaletteFirstUnusedIndex <= g_systemPaletteLastNonReservedIndex; + ++i) + { + if ((entries[i].peFlags & PC_EXPLICIT) || + 0 == (entries[i].peFlags & (PC_NOCOLLAPSE | PC_RESERVED)) && exactMatch(entries[i])) + { + continue; + } + + g_systemPalette[g_systemPaletteFirstUnusedIndex] = entries[i]; + g_systemPalette[g_systemPaletteFirstUnusedIndex].peFlags = 0; + ++g_systemPaletteFirstUnusedIndex; + } + + Gdi::VirtualScreen::updatePalette(); + return count; + } + + UINT WINAPI getSystemPaletteEntries(HDC hdc, UINT iStartIndex, UINT nEntries, LPPALETTEENTRY lppe) + { + LOG_FUNC("GetSystemPaletteEntries", hdc, iStartIndex, nEntries, lppe); + if (!Gdi::isDisplayDc(hdc)) + { + return LOG_RESULT(0); + } + + if (!lppe) + { + return LOG_RESULT(256); + } + + if (iStartIndex >= 256) + { + return LOG_RESULT(0); + } + + if (nEntries > 256 - iStartIndex) + { + nEntries = 256 - iStartIndex; + } + + DDraw::ScopedThreadLock lock; + std::memcpy(lppe, &DDraw::PrimarySurface::s_paletteEntries[iStartIndex], nEntries * sizeof(PALETTEENTRY)); + + return LOG_RESULT(nEntries); + } + + UINT WINAPI getSystemPaletteUse(HDC hdc) + { + LOG_FUNC("GetSystemPaletteUse", hdc); + if (!Gdi::isDisplayDc(hdc)) + { + return LOG_RESULT(SYSPAL_ERROR); + } + DDraw::ScopedThreadLock lock; + return g_systemPaletteUse; + } + + UINT WINAPI realizePalette(HDC hdc) + { + LOG_FUNC("RealizePalette", hdc); + if (Gdi::isDisplayDc(hdc)) + { + DDraw::ScopedThreadLock lock; + if (g_foregroundPaletteDcs.find(hdc) != g_foregroundPaletteDcs.end()) + { + g_systemPaletteFirstUnusedIndex = g_systemPaletteFirstNonReservedIndex; + } + return LOG_RESULT(fillSystemPalette(hdc)); + } + return LOG_RESULT(CALL_ORIG_FUNC(RealizePalette)(hdc)); + } + + int WINAPI releaseDc(HWND hWnd, HDC hDC) + { + LOG_FUNC("ReleaseDC", hWnd, hDC); + DDraw::ScopedThreadLock lock; + g_foregroundPaletteDcs.erase(hDC); + return LOG_RESULT(CALL_ORIG_FUNC(ReleaseDC)(hWnd, hDC)); + } + + HPALETTE WINAPI selectPalette(HDC hdc, HPALETTE hpal, BOOL bForceBackground) + { + LOG_FUNC("SelectPalette", hdc, hpal, bForceBackground); + HPALETTE result = CALL_ORIG_FUNC(SelectPalette)(hdc, hpal, bForceBackground); + if (result && Gdi::isDisplayDc(hdc)) + { + HWND wnd = CALL_ORIG_FUNC(WindowFromDC)(hdc); + if (wnd && GetDesktopWindow() != wnd) + { + DDraw::ScopedThreadLock lock; + if (bForceBackground || GetStockObject(DEFAULT_PALETTE) == hpal) + { + g_foregroundPaletteDcs.erase(hdc); + } + else + { + g_foregroundPaletteDcs.insert(hdc); + } + } + } + return LOG_RESULT(result); + } + + UINT WINAPI setSystemPaletteUse(HDC hdc, UINT uUsage) + { + LOG_FUNC("SetSystemPaletteUse", hdc, uUsage); + if (!Gdi::isDisplayDc(hdc)) + { + return LOG_RESULT(SYSPAL_ERROR); + } + + DDraw::ScopedThreadLock lock; + const UINT prevUsage = g_systemPaletteUse; + switch (uUsage) + { + case SYSPAL_STATIC: + g_systemPaletteFirstNonReservedIndex = 10; + g_systemPaletteLastNonReservedIndex = 245; + break; + + case SYSPAL_NOSTATIC: + g_systemPaletteFirstNonReservedIndex = 1; + g_systemPaletteLastNonReservedIndex = 254; + break; + + case SYSPAL_NOSTATIC256: + g_systemPaletteFirstNonReservedIndex = 0; + g_systemPaletteLastNonReservedIndex = 255; + break; + + default: + return LOG_RESULT(SYSPAL_ERROR); + } + + g_systemPaletteUse = uUsage; + return LOG_RESULT(prevUsage); + } +} + +namespace Gdi +{ + namespace Palette + { + void installHooks() + { + HPALETTE defaultPalette = reinterpret_cast(GetStockObject(DEFAULT_PALETTE)); + GetPaletteEntries(defaultPalette, 0, 10, g_systemPalette); + GetPaletteEntries(defaultPalette, 246, 10, &g_systemPalette[246]); + Gdi::VirtualScreen::updatePalette(); + + HOOK_FUNCTION(gdi32, GetSystemPaletteEntries, getSystemPaletteEntries); + HOOK_FUNCTION(gdi32, GetSystemPaletteUse, getSystemPaletteUse); + HOOK_FUNCTION(gdi32, RealizePalette, realizePalette); + HOOK_FUNCTION(user32, ReleaseDC, releaseDc); + HOOK_FUNCTION(gdi32, SelectPalette, selectPalette); + HOOK_FUNCTION(gdi32, SetSystemPaletteUse, setSystemPaletteUse); + } + } +} diff --git a/DDrawCompat/Gdi/Palette.h b/DDrawCompat/Gdi/Palette.h new file mode 100644 index 0000000..21948af --- /dev/null +++ b/DDrawCompat/Gdi/Palette.h @@ -0,0 +1,9 @@ +#pragma once + +namespace Gdi +{ + namespace Palette + { + void installHooks(); + } +} diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index 492f2ef..dfe55f4 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -168,7 +168,6 @@ namespace Gdi void init() { update(); - updatePalette(); } bool update() @@ -220,13 +219,9 @@ namespace Gdi void updatePalette() { DDraw::ScopedThreadLock lock; - if (8 != g_bpp) - { - return; - } PALETTEENTRY pal[256] = {}; - GetSystemPaletteEntries(nullptr, 0, 256, pal); + GetSystemPaletteEntries(Gdi::getScreenDc(), 0, 256, pal); RGBQUAD systemPalette[256] = {}; for (int i = 0; i < 256; ++i) diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index 676dd2e..922b901 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -6,10 +6,12 @@ #include #include +#include "Common/Hook.h" #include "Common/Log.h" #include "Common/ScopedCriticalSection.h" #include "Gdi/AccessGuard.h" #include "Gdi/Dc.h" +#include "Win32/DisplayMode.h" #include "Gdi/PaintHandlers.h" #include "Gdi/ScrollBar.h" #include "Gdi/ScrollFunctions.h" @@ -94,6 +96,10 @@ namespace if (GetCurrentProcessId() == windowPid) { onCreateWindow(hwnd); + if (8 == Win32::DisplayMode::getBpp()) + { + PostMessage(hwnd, WM_PALETTECHANGED, reinterpret_cast(GetDesktopWindow()), 0); + } } return TRUE; } @@ -148,7 +154,7 @@ namespace } Gdi::Dc::releaseDc(windowDc); } - ReleaseDC(hwnd, windowDc); + CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc); } } diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index d7ffbac..9750023 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -248,7 +248,7 @@ namespace Gdi { HDC windowDc = GetWindowDC(m_hwnd); GetRandomRgn(windowDc, newVisibleRegion, SYSRGN); - ReleaseDC(m_hwnd, windowDc); + CALL_ORIG_FUNC(ReleaseDC)(m_hwnd, windowDc); } if (m_presentationWindow && GetCurrentThreadId() == GetWindowThreadProcessId(m_hwnd, nullptr)) diff --git a/DDrawCompat/Win32/DisplayMode.cpp b/DDrawCompat/Win32/DisplayMode.cpp index 48dab07..7f35518 100644 --- a/DDrawCompat/Win32/DisplayMode.cpp +++ b/DDrawCompat/Win32/DisplayMode.cpp @@ -28,8 +28,6 @@ namespace } }; - CompatWeakPtr g_compatibleSurface = {}; - HDC g_compatibleDc = nullptr; DWORD g_origBpp = 0; DWORD g_currentBpp = 0; DWORD g_lastBpp = 0; @@ -39,7 +37,6 @@ namespace LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode, DWORD dwFlags); BOOL WINAPI enumDisplaySettingsExW( LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode, DWORD dwFlags); - void updateCompatibleDc(); template @@ -80,7 +77,6 @@ namespace { g_currentBpp = g_origBpp; } - updateCompatibleDc(); DevMode currDevMode = {}; currDevMode.dmSize = sizeof(currDevMode); @@ -290,65 +286,12 @@ namespace } return LOG_RESULT(CALL_ORIG_FUNC(GetDeviceCaps)(hdc, nIndex)); } - - void releaseCompatibleDc() - { - if (g_compatibleDc) - { - Dll::g_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 = DDraw::createCompatibleSurface(g_currentBpp).detach(); - if (g_compatibleSurface && - SUCCEEDED(g_compatibleSurface->GetDC(g_compatibleSurface, &g_compatibleDc))) - { - Dll::g_origProcs.ReleaseDDThreadLock(); - } - } } namespace Win32 { namespace DisplayMode { - HBITMAP WINAPI createCompatibleBitmap(HDC hdc, int cx, int cy) - { - LOG_FUNC("CreateCompatibleBitmap", hdc, cx, cy); - replaceDc(hdc); - return LOG_RESULT(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) - { - LOG_FUNC("CreateDIBitmap", hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage); - replaceDc(hdc); - return LOG_RESULT(CALL_ORIG_FUNC(CreateDIBitmap)(hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage)); - } - - HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight) - { - LOG_FUNC("CreateDiscardableBitmap", hdc, nWidth, nHeight); - replaceDc(hdc); - return LOG_RESULT(CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight)); - } - DWORD getBpp() { return g_currentBpp; @@ -380,6 +323,12 @@ namespace Win32 g_currentBpp = g_origBpp; g_lastBpp = g_origBpp; + if (32 != devMode.dmBitsPerPel) + { + devMode.dmBitsPerPel = 32; + ChangeDisplaySettings(&devMode, 0); + } + HOOK_FUNCTION(user32, ChangeDisplaySettingsExA, changeDisplaySettingsExA); HOOK_FUNCTION(user32, ChangeDisplaySettingsExW, changeDisplaySettingsExW); HOOK_FUNCTION(user32, EnumDisplaySettingsExA, enumDisplaySettingsExA); @@ -402,8 +351,6 @@ namespace Win32 &ddrawEnumDisplaySettingsExA); Compat::hookIatFunction(origDDrawModule, "user32.dll", "EnumDisplaySettingsExW", &ddrawEnumDisplaySettingsExW); - - updateCompatibleDc(); } } } diff --git a/DDrawCompat/Win32/DisplayMode.h b/DDrawCompat/Win32/DisplayMode.h index 33d3cdf..14bef03 100644 --- a/DDrawCompat/Win32/DisplayMode.h +++ b/DDrawCompat/Win32/DisplayMode.h @@ -8,11 +8,6 @@ namespace Win32 { namespace DisplayMode { - 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); - DWORD getBpp(); ULONG queryDisplaySettingsUniqueness(); void setDDrawBpp(DWORD bpp);