From d4042f7e954137da304f12f8873ab2e3027b6b5b Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 17 Apr 2016 01:01:14 +0200 Subject: [PATCH] Support PC_RESERVED palette entry flag for GDI rendering --- DDrawCompat/CompatGdi.cpp | 56 +-------------------- DDrawCompat/CompatGdiDcCache.cpp | 41 +++++++++++++-- DDrawCompat/CompatGdiDcCache.h | 1 + DDrawCompat/CompatGdiPaintHandlers.cpp | 24 +-------- DDrawCompat/CompatPaletteConverter.cpp | 69 ++++---------------------- DDrawCompat/CompatPaletteConverter.h | 10 ++-- DDrawCompat/RealPrimarySurface.cpp | 12 ++--- 7 files changed, 58 insertions(+), 155 deletions(-) diff --git a/DDrawCompat/CompatGdi.cpp b/DDrawCompat/CompatGdi.cpp index 3e429c1..2ac413d 100644 --- a/DDrawCompat/CompatGdi.cpp +++ b/DDrawCompat/CompatGdi.cpp @@ -1,5 +1,4 @@ #include -#include #include "CompatDirectDrawPalette.h" #include "CompatDirectDrawSurface.h" @@ -25,8 +24,6 @@ namespace HANDLE g_ddUnlockEndEvent = nullptr; bool g_isDelayedUnlockPending = false; - PALETTEENTRY g_usedPaletteEntries[256] = {}; - BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM lParam) { if (!IsWindowVisible(hwnd)) @@ -73,45 +70,6 @@ namespace return true; } - /* - Workaround for correctly drawing icons with a transparent background using BitBlt and a monochrome - bitmap mask. Normally black (index 0) and white (index 255) are selected as foreground and background - colors on the target DC so that a BitBlt with the SRCAND ROP would preserve the background pixels and - set the foreground pixels to 0. (Logical AND with 0xFF preserves all bits.) - But if the physical palette contains another, earlier white entry, SRCAND will be performed with the - wrong index (less than 0xFF), erasing some of the bits from all background pixels. - This workaround replaces all unwanted white entries with a similar color. - */ - void replaceDuplicateWhitePaletteEntries(DWORD startingEntry, DWORD count) - { - if (startingEntry + count > 255) - { - count = 255 - startingEntry; - } - - PALETTEENTRY entries[256] = {}; - std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry], - count * sizeof(PALETTEENTRY)); - - bool isReplacementDone = false; - for (DWORD i = 0; i < count; ++i) - { - if (0xFF == entries[i].peRed && 0xFF == entries[i].peGreen && 0xFF == entries[i].peBlue) - { - entries[i].peRed = 0xFE; - entries[i].peGreen = 0xFE; - entries[i].peBlue = 0xFE; - isReplacementDone = true; - } - } - - if (isReplacementDone) - { - CompatDirectDrawPalette::s_origVtable.SetEntries( - CompatPrimarySurface::palette, 0, startingEntry, count, entries); - } - } - void unlockPrimarySurface() { GdiFlush(); @@ -212,7 +170,6 @@ namespace CompatGdi void installHooks() { InitializeCriticalSection(&g_gdiCriticalSection); - CompatPaletteConverter::init(); if (CompatGdiDcCache::init()) { g_ddUnlockBeginEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); @@ -246,18 +203,9 @@ namespace CompatGdi void updatePalette(DWORD startingEntry, DWORD count) { - if (!isEmulationEnabled()) + if (isEmulationEnabled() && CompatPrimarySurface::palette) { - return; - } - - Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection); - CompatGdiDcCache::clear(); - - if (CompatPrimarySurface::palette) - { - replaceDuplicateWhitePaletteEntries(startingEntry, count); - invalidate(nullptr); + CompatGdiDcCache::updatePalette(startingEntry, count); } } } diff --git a/DDrawCompat/CompatGdiDcCache.cpp b/DDrawCompat/CompatGdiDcCache.cpp index 8c5d17e..953eb6c 100644 --- a/DDrawCompat/CompatGdiDcCache.cpp +++ b/DDrawCompat/CompatGdiDcCache.cpp @@ -1,6 +1,8 @@ +#include #include #include "CompatDirectDraw.h" +#include "CompatDirectDrawPalette.h" #include "CompatDirectDrawSurface.h" #include "CompatGdiDcCache.h" #include "CompatPrimarySurface.h" @@ -20,6 +22,8 @@ namespace DWORD g_ddLockThreadId = 0; IDirectDraw7* g_directDraw = nullptr; + IDirectDrawPalette* g_palette = nullptr; + PALETTEENTRY g_paletteEntries[256] = {}; void* g_surfaceMemory = nullptr; LONG g_pitch = 0; @@ -74,10 +78,9 @@ namespace return nullptr; } - if (CompatPrimarySurface::palette) + if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8) { - CompatDirectDrawSurface::s_origVtable.SetPalette( - surface, CompatPrimarySurface::palette); + CompatDirectDrawSurface::s_origVtable.SetPalette(surface, g_palette); } return surface; @@ -168,6 +171,11 @@ namespace CompatGdiDcCache bool init() { g_directDraw = DDrawRepository::getDirectDraw(); + if (g_directDraw) + { + CompatDirectDraw::s_origVtable.CreatePalette( + g_directDraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256, g_paletteEntries, &g_palette, nullptr); + } return nullptr != g_directDraw; } @@ -199,4 +207,31 @@ namespace CompatGdiDcCache g_pitch = pitch; clear(); } + + void updatePalette(DWORD startingEntry, DWORD count) + { + PALETTEENTRY entries[256] = {}; + std::memcpy(&entries[startingEntry], + &CompatPrimarySurface::paletteEntries[startingEntry], + count * sizeof(PALETTEENTRY)); + + for (DWORD i = startingEntry; i < startingEntry + count; ++i) + { + if (entries[i].peFlags & PC_RESERVED) + { + entries[i] = CompatPrimarySurface::paletteEntries[0]; + entries[i].peFlags = CompatPrimarySurface::paletteEntries[i].peFlags; + } + } + + if (0 != std::memcmp(&g_paletteEntries[startingEntry], &entries[startingEntry], + count * sizeof(PALETTEENTRY))) + { + std::memcpy(&g_paletteEntries[startingEntry], &entries[startingEntry], + count * sizeof(PALETTEENTRY)); + CompatDirectDrawPalette::s_origVtable.SetEntries( + g_palette, 0, startingEntry, count, g_paletteEntries); + clear(); + } + } } diff --git a/DDrawCompat/CompatGdiDcCache.h b/DDrawCompat/CompatGdiDcCache.h index b0517a3..1450936 100644 --- a/DDrawCompat/CompatGdiDcCache.h +++ b/DDrawCompat/CompatGdiDcCache.h @@ -21,4 +21,5 @@ namespace CompatGdiDcCache void releaseDc(const CachedDc& cachedDc); void setDdLockThreadId(DWORD ddLockThreadId); void setSurfaceMemory(void* surfaceMemory, LONG pitch); + void updatePalette(DWORD startingEntry, DWORD count); } diff --git a/DDrawCompat/CompatGdiPaintHandlers.cpp b/DDrawCompat/CompatGdiPaintHandlers.cpp index e4a7865..6563261 100644 --- a/DDrawCompat/CompatGdiPaintHandlers.cpp +++ b/DDrawCompat/CompatGdiPaintHandlers.cpp @@ -4,7 +4,6 @@ #include "CompatGdiScrollBar.h" #include "CompatGdiScrollFunctions.h" #include "CompatGdiTitleBar.h" -#include "CompatPaletteConverter.h" #include "CompatPrimarySurface.h" #include "CompatRegistry.h" #include "DDrawLog.h" @@ -158,27 +157,8 @@ namespace HDC compatDc = CompatGdiDc::getDc(dc, isMenuPaintDc); if (compatDc) { - if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8) - { - HDC converterDc = CompatPaletteConverter::lockDc(); - CompatPaletteConverter::setHalftonePalette(); - - origWndProc(hwnd, WM_PRINT, reinterpret_cast(converterDc), - PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT); - - RECT rect = {}; - GetWindowRect(hwnd, &rect); - CALL_ORIG_FUNC(BitBlt)(compatDc, 0, 0, - rect.right - rect.left, rect.bottom - rect.top, converterDc, 0, 0, SRCCOPY); - - CompatPaletteConverter::setPrimaryPalette(0, 256); - CompatPaletteConverter::unlockDc(); - } - else - { - origWndProc(hwnd, WM_PRINT, reinterpret_cast(compatDc), - PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT); - } + origWndProc(hwnd, WM_PRINT, reinterpret_cast(compatDc), + PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT); ValidateRect(hwnd, nullptr); CompatGdiDc::releaseDc(dc); } diff --git a/DDrawCompat/CompatPaletteConverter.cpp b/DDrawCompat/CompatPaletteConverter.cpp index a5c834e..f5b739e 100644 --- a/DDrawCompat/CompatPaletteConverter.cpp +++ b/DDrawCompat/CompatPaletteConverter.cpp @@ -14,9 +14,7 @@ namespace { - CRITICAL_SECTION g_criticalSection = {}; HDC g_dc = nullptr; - RGBQUAD g_halftonePalette[256] = {}; HGDIOBJ g_oldBitmap = nullptr; IDirectDrawSurface7* g_surface = nullptr; @@ -73,18 +71,6 @@ namespace CompatDirectDraw::s_origVtable.CreateSurface(dd, &desc, &surface, nullptr); return surface; } - - void initHalftonePalette() - { - HDC dc = GetDC(nullptr); - HPALETTE palette = CreateHalftonePalette(dc); - - GetPaletteEntries(palette, 0, 256, reinterpret_cast(g_halftonePalette)); - convertPaletteEntriesToRgbQuad(g_halftonePalette, 256); - - DeleteObject(palette); - ReleaseDC(nullptr, dc); - } } namespace CompatPaletteConverter @@ -122,35 +108,24 @@ namespace CompatPaletteConverter return false; } - Compat::ScopedCriticalSection lock(g_criticalSection); g_oldBitmap = SelectObject(dc, dib); g_dc = dc; g_surface = surface; return true; } - void init() + HDC getDc() { - InitializeCriticalSection(&g_criticalSection); - initHalftonePalette(); - } - - HDC lockDc() - { - EnterCriticalSection(&g_criticalSection); return g_dc; } - IDirectDrawSurface7* lockSurface() + IDirectDrawSurface7* getSurface() { - EnterCriticalSection(&g_criticalSection); return g_surface; } void release() { - Compat::ScopedCriticalSection lock(g_criticalSection); - if (!g_surface) { return; @@ -166,7 +141,6 @@ namespace CompatPaletteConverter void setClipper(IDirectDrawClipper* clipper) { - Compat::ScopedCriticalSection lock(g_criticalSection); if (g_surface) { HRESULT result = CompatDirectDrawSurface::s_origVtable.SetClipper( @@ -178,40 +152,15 @@ namespace CompatPaletteConverter } } - void setHalftonePalette() + void updatePalette(DWORD startingEntry, DWORD count) { - EnterCriticalSection(&g_criticalSection); - SetDIBColorTable(g_dc, 0, 256, g_halftonePalette); - LeaveCriticalSection(&g_criticalSection); - } - - void setPrimaryPalette(DWORD startingEntry, DWORD count) - { - Compat::ScopedCriticalSection lock(g_criticalSection); - if (g_dc) + if (g_dc && CompatPrimarySurface::palette) { - if (CompatPrimarySurface::palette) - { - RGBQUAD entries[256] = {}; - std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry], - count * sizeof(PALETTEENTRY)); - convertPaletteEntriesToRgbQuad(entries, count); - SetDIBColorTable(g_dc, startingEntry, count, entries); - } - else - { - SetDIBColorTable(g_dc, 0, 256, g_halftonePalette); - } + RGBQUAD entries[256] = {}; + std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry], + count * sizeof(PALETTEENTRY)); + convertPaletteEntriesToRgbQuad(entries, count); + SetDIBColorTable(g_dc, startingEntry, count, entries); } } - - void unlockDc() - { - LeaveCriticalSection(&g_criticalSection); - } - - void unlockSurface() - { - LeaveCriticalSection(&g_criticalSection); - } }; diff --git a/DDrawCompat/CompatPaletteConverter.h b/DDrawCompat/CompatPaletteConverter.h index 5366ed4..d1236dd 100644 --- a/DDrawCompat/CompatPaletteConverter.h +++ b/DDrawCompat/CompatPaletteConverter.h @@ -7,13 +7,9 @@ namespace CompatPaletteConverter { bool create(); - void init(); - HDC lockDc(); - IDirectDrawSurface7* lockSurface(); + HDC getDc(); + IDirectDrawSurface7* getSurface(); void release(); void setClipper(IDirectDrawClipper* clipper); - void setHalftonePalette(); - void setPrimaryPalette(DWORD startingEntry, DWORD count); - void unlockDc(); - void unlockSurface(); + void updatePalette(DWORD startingEntry, DWORD count); } diff --git a/DDrawCompat/RealPrimarySurface.cpp b/DDrawCompat/RealPrimarySurface.cpp index a6b791a..8e39557 100644 --- a/DDrawCompat/RealPrimarySurface.cpp +++ b/DDrawCompat/RealPrimarySurface.cpp @@ -53,22 +53,16 @@ namespace if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8) { - IDirectDrawSurface7* converterSurface = CompatPaletteConverter::lockSurface(); - HDC converterDc = CompatPaletteConverter::lockDc(); - - origVtable.Blt(converterSurface, &g_updateRect, + origVtable.Blt(CompatPaletteConverter::getSurface(), &g_updateRect, CompatPrimarySurface::surface, &g_updateRect, DDBLT_WAIT, nullptr); HDC destDc = nullptr; origVtable.GetDC(dest, &destDc); result = TRUE == CALL_ORIG_FUNC(BitBlt)(destDc, g_updateRect.left, g_updateRect.top, g_updateRect.right - g_updateRect.left, g_updateRect.bottom - g_updateRect.top, - converterDc, g_updateRect.left, g_updateRect.top, SRCCOPY); + CompatPaletteConverter::getDc(), g_updateRect.left, g_updateRect.top, SRCCOPY); origVtable.ReleaseDC(dest, destDc); - CompatPaletteConverter::unlockDc(); - CompatPaletteConverter::unlockSurface(); - if (dest == g_frontBuffer) { // Force the screen to be updated. It won't refresh from BitBlt alone. @@ -374,7 +368,7 @@ void RealPrimarySurface::update() void RealPrimarySurface::updatePalette(DWORD startingEntry, DWORD count) { - CompatPaletteConverter::setPrimaryPalette(startingEntry, count); + CompatPaletteConverter::updatePalette(startingEntry, count); CompatGdi::updatePalette(startingEntry, count); invalidate(nullptr); update();