1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Use only static colors when default palette is selected

Fixes changing window border/caption colors (issue ).
This commit is contained in:
narzoul 2021-01-27 09:37:47 +01:00
parent 922d17d283
commit 6e15cb7da7
8 changed files with 107 additions and 93 deletions

@ -26,6 +26,7 @@ namespace
HGDIOBJ savedBrush; HGDIOBJ savedBrush;
HGDIOBJ savedPen; HGDIOBJ savedPen;
HPALETTE savedPalette; HPALETTE savedPalette;
bool useDefaultPalette;
}; };
typedef std::unordered_map<HDC, CompatDc> CompatDcMap; typedef std::unordered_map<HDC, CompatDc> CompatDcMap;
@ -151,7 +152,7 @@ namespace Gdi
for (auto& origDcToCompatDc : g_origDcToCompatDc) for (auto& origDcToCompatDc : g_origDcToCompatDc)
{ {
restoreDc(origDcToCompatDc.second); restoreDc(origDcToCompatDc.second);
Gdi::DcCache::deleteDc(origDcToCompatDc.second.dc); Gdi::VirtualScreen::deleteDc(origDcToCompatDc.second.dc);
} }
g_origDcToCompatDc.clear(); g_origDcToCompatDc.clear();
} }
@ -166,7 +167,7 @@ namespace Gdi
if (threadId == it->second.threadId) if (threadId == it->second.threadId)
{ {
restoreDc(it->second); restoreDc(it->second);
Gdi::DcCache::deleteDc(it->second.dc); Gdi::VirtualScreen::deleteDc(it->second.dc);
it = g_origDcToCompatDc.erase(it); it = g_origDcToCompatDc.erase(it);
} }
else else
@ -195,7 +196,8 @@ namespace Gdi
} }
CompatDc compatDc; CompatDc compatDc;
compatDc.dc = Gdi::DcCache::getDc(); compatDc.useDefaultPalette = GetStockObject(DEFAULT_PALETTE) == GetCurrentObject(origDc, OBJ_PAL);
compatDc.dc = Gdi::DcCache::getDc(compatDc.useDefaultPalette);
if (!compatDc.dc) if (!compatDc.dc)
{ {
return nullptr; return nullptr;
@ -251,7 +253,7 @@ namespace Gdi
if (0 == compatDc.refCount) if (0 == compatDc.refCount)
{ {
restoreDc(compatDc); restoreDc(compatDc);
Gdi::DcCache::releaseDc(compatDc.dc); Gdi::DcCache::releaseDc(compatDc.dc, compatDc.useDefaultPalette);
g_origDcToCompatDc.erase(origDc); g_origDcToCompatDc.erase(origDc);
} }
} }

@ -1,87 +1,61 @@
#include <algorithm>
#include <map> #include <map>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "Common/ScopedCriticalSection.h" #include <Common/ScopedCriticalSection.h>
#include "Gdi/DcCache.h" #include <Gdi/DcCache.h>
#include "Gdi/VirtualScreen.h" #include <Gdi/VirtualScreen.h>
namespace namespace
{ {
struct Cache
{
std::vector<std::unique_ptr<HDC__, void(*)(HDC)>> cache;
std::vector<std::unique_ptr<HDC__, void(*)(HDC)>> defPalCache;
};
Compat::CriticalSection g_cs; Compat::CriticalSection g_cs;
std::map<DWORD, std::vector<HDC>> g_threadIdToDcCache; std::map<DWORD, Cache> g_threadIdToDcCache;
} }
namespace Gdi namespace Gdi
{ {
namespace DcCache namespace DcCache
{ {
void deleteDc(HDC cachedDc)
{
Compat::ScopedCriticalSection lock(g_cs);
for (auto& threadIdToDcCache : g_threadIdToDcCache)
{
auto& dcCache = threadIdToDcCache.second;
auto it = std::find(dcCache.begin(), dcCache.end(), cachedDc);
if (it != dcCache.end())
{
Gdi::VirtualScreen::deleteDc(*it);
dcCache.erase(it);
return;
}
}
}
void dllProcessDetach() void dllProcessDetach()
{ {
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
for (auto& threadIdToDcCache : g_threadIdToDcCache)
{
for (HDC dc : threadIdToDcCache.second)
{
Gdi::VirtualScreen::deleteDc(dc);
}
}
g_threadIdToDcCache.clear(); g_threadIdToDcCache.clear();
} }
void dllThreadDetach() void dllThreadDetach()
{ {
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
auto it = g_threadIdToDcCache.find(GetCurrentThreadId()); g_threadIdToDcCache.erase(GetCurrentThreadId());
if (it == g_threadIdToDcCache.end())
{
return;
} }
for (HDC dc : it->second) HDC getDc(bool useDefaultPalette)
{
Gdi::VirtualScreen::deleteDc(dc);
}
g_threadIdToDcCache.erase(it);
}
HDC getDc()
{ {
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
std::vector<HDC>& dcCache = g_threadIdToDcCache[GetCurrentThreadId()]; auto& cache = g_threadIdToDcCache[GetCurrentThreadId()];
auto& dcCache = useDefaultPalette ? cache.defPalCache : cache.cache;
if (dcCache.empty()) if (dcCache.empty())
{ {
return Gdi::VirtualScreen::createDc(); return Gdi::VirtualScreen::createDc(useDefaultPalette);
} }
HDC dc = dcCache.back(); HDC dc = dcCache.back().release();
dcCache.pop_back(); dcCache.pop_back();
return dc; return dc;
} }
void releaseDc(HDC cachedDc) void releaseDc(HDC cachedDc, bool useDefaultPalette)
{ {
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
g_threadIdToDcCache[GetCurrentThreadId()].push_back(cachedDc); auto& cache = g_threadIdToDcCache[GetCurrentThreadId()];
auto& dcCache = useDefaultPalette ? cache.defPalCache : cache.cache;
dcCache.emplace_back(cachedDc, Gdi::VirtualScreen::deleteDc);
} }
} }
} }

@ -6,10 +6,9 @@ namespace Gdi
{ {
namespace DcCache namespace DcCache
{ {
void deleteDc(HDC cachedDc);
void dllProcessDetach(); void dllProcessDetach();
void dllThreadDetach(); void dllThreadDetach();
HDC getDc(); HDC getDc(bool useDefaultPalette);
void releaseDc(HDC cachedDc); void releaseDc(HDC cachedDc, bool useDefaultPalette);
} }
} }

@ -214,7 +214,8 @@ namespace
LOG_FUNC("CreateCompatibleBitmap", hdc, cx, cy); LOG_FUNC("CreateCompatibleBitmap", hdc, cx, cy);
if (g_redirectToDib && Gdi::isDisplayDc(hdc)) if (g_redirectToDib && Gdi::isDisplayDc(hdc))
{ {
return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(cx, cy)); const bool useDefaultPalette = false;
return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(cx, cy, useDefaultPalette));
} }
return LOG_RESULT(CALL_ORIG_FUNC(CreateCompatibleBitmap)(hdc, cx, cy)); return LOG_RESULT(CALL_ORIG_FUNC(CreateCompatibleBitmap)(hdc, cx, cy));
} }
@ -226,7 +227,9 @@ namespace
const DWORD CBM_CREATDIB = 2; const DWORD CBM_CREATDIB = 2;
if (g_redirectToDib && !(fdwInit & CBM_CREATDIB) && lpbmih && Gdi::isDisplayDc(hdc)) if (g_redirectToDib && !(fdwInit & CBM_CREATDIB) && lpbmih && Gdi::isDisplayDc(hdc))
{ {
HBITMAP bitmap = Gdi::VirtualScreen::createOffScreenDib(lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight); const bool useDefaultPalette = false;
HBITMAP bitmap = Gdi::VirtualScreen::createOffScreenDib(
lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, useDefaultPalette);
if (bitmap && lpbInit && lpbmi) if (bitmap && lpbInit && lpbmi)
{ {
SetDIBits(hdc, bitmap, 0, std::abs(lpbmi->bmiHeader.biHeight), lpbInit, lpbmi, fuUsage); SetDIBits(hdc, bitmap, 0, std::abs(lpbmi->bmiHeader.biHeight), lpbInit, lpbmi, fuUsage);
@ -241,7 +244,8 @@ namespace
LOG_FUNC("CreateDiscardableBitmap", hdc, nWidth, nHeight); LOG_FUNC("CreateDiscardableBitmap", hdc, nWidth, nHeight);
if (g_redirectToDib && Gdi::isDisplayDc(hdc)) if (g_redirectToDib && Gdi::isDisplayDc(hdc))
{ {
return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(nWidth, nHeight)); const bool useDefaultPalette = false;
return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(nWidth, nHeight, useDefaultPalette));
} }
return LOG_RESULT(CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight)); return LOG_RESULT(CALL_ORIG_FUNC(createDiscardableBitmap)(hdc, nWidth, nHeight));
} }

@ -308,7 +308,8 @@ namespace
RECT r = {}; RECT r = {};
GetClientRect(hwnd, &r); GetClientRect(hwnd, &r);
HDC dc = CreateCompatibleDC(nullptr); HDC dc = CreateCompatibleDC(nullptr);
HBITMAP dib = Gdi::VirtualScreen::createOffScreenDib(r.right, r.bottom); const bool useDefaultPalette = true;
HBITMAP dib = Gdi::VirtualScreen::createOffScreenDib(r.right, r.bottom, useDefaultPalette);
HGDIOBJ origBitmap = SelectObject(dc, dib); HGDIOBJ origBitmap = SelectObject(dc, dib);
CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(dc), 0); CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(dc), 0);
LRESULT result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), lParam); LRESULT result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), lParam);

@ -1,20 +1,25 @@
#include <set> #include <map>
#include "Config/Config.h" #include <Config/Config.h>
#include "Common/ScopedCriticalSection.h" #include <Common/ScopedCriticalSection.h>
#include "D3dDdi/Device.h" #include <D3dDdi/Device.h>
#include "D3dDdi/ScopedCriticalSection.h" #include <D3dDdi/ScopedCriticalSection.h>
#include "DDraw/DirectDraw.h" #include <DDraw/DirectDraw.h>
#include "DDraw/RealPrimarySurface.h" #include <DDraw/RealPrimarySurface.h>
#include "DDraw/ScopedThreadLock.h" #include <DDraw/ScopedThreadLock.h>
#include "DDraw/Surfaces/PrimarySurface.h" #include <DDraw/Surfaces/PrimarySurface.h>
#include "Gdi/Gdi.h" #include <Gdi/Gdi.h>
#include "Gdi/Region.h" #include <Gdi/Region.h>
#include "Gdi/VirtualScreen.h" #include <Gdi/VirtualScreen.h>
#include "Win32/DisplayMode.h" #include <Win32/DisplayMode.h>
namespace namespace
{ {
struct VirtualScreenDc
{
bool useDefaultPalette;
};
Compat::CriticalSection g_cs; Compat::CriticalSection g_cs;
Gdi::Region g_region; Gdi::Region g_region;
RECT g_bounds = {}; RECT g_bounds = {};
@ -26,8 +31,9 @@ namespace
void* g_surfaceView = nullptr; void* g_surfaceView = nullptr;
HGDIOBJ g_stockBitmap = nullptr; HGDIOBJ g_stockBitmap = nullptr;
RGBQUAD g_defaultPalette[256] = {};
RGBQUAD g_systemPalette[256] = {}; RGBQUAD g_systemPalette[256] = {};
std::set<HDC> g_dcs; std::map<HDC, VirtualScreenDc> g_dcs;
BOOL CALLBACK addMonitorRectToRegion( BOOL CALLBACK addMonitorRectToRegion(
HMONITOR /*hMonitor*/, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM dwData) HMONITOR /*hMonitor*/, HDC /*hdcMonitor*/, LPRECT lprcMonitor, LPARAM dwData)
@ -38,7 +44,16 @@ namespace
return TRUE; return TRUE;
} }
HBITMAP createDibSection(LONG width, LONG height, HANDLE section) RGBQUAD convertToRgbQuad(PALETTEENTRY entry)
{
RGBQUAD quad = {};
quad.rgbRed = entry.peRed;
quad.rgbGreen = entry.peGreen;
quad.rgbBlue = entry.peBlue;
return quad;
}
HBITMAP createDibSection(LONG width, LONG height, HANDLE section, bool useDefaultPalette)
{ {
struct BITMAPINFO256 : public BITMAPINFO struct BITMAPINFO256 : public BITMAPINFO
{ {
@ -54,9 +69,16 @@ namespace
bmi.bmiHeader.biCompression = 8 == g_bpp ? BI_RGB : BI_BITFIELDS; bmi.bmiHeader.biCompression = 8 == g_bpp ? BI_RGB : BI_BITFIELDS;
if (8 == g_bpp) if (8 == g_bpp)
{
if (useDefaultPalette)
{
memcpy(bmi.bmiColors, g_defaultPalette, sizeof(g_defaultPalette));
}
else
{ {
memcpy(bmi.bmiColors, g_systemPalette, sizeof(g_systemPalette)); memcpy(bmi.bmiColors, g_systemPalette, sizeof(g_systemPalette));
} }
}
else else
{ {
const auto pf = DDraw::getRgbPixelFormat(g_bpp); const auto pf = DDraw::getRgbPixelFormat(g_bpp);
@ -74,10 +96,10 @@ namespace Gdi
{ {
namespace VirtualScreen namespace VirtualScreen
{ {
HDC createDc() HDC createDc(bool useDefaultPalette)
{ {
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
std::unique_ptr<void, decltype(&DeleteObject)> dib(createDib(), DeleteObject); std::unique_ptr<void, decltype(&DeleteObject)> dib(createDib(useDefaultPalette), DeleteObject);
if (!dib) if (!dib)
{ {
return nullptr; return nullptr;
@ -98,24 +120,24 @@ namespace Gdi
dib.release(); dib.release();
g_stockBitmap = stockBitmap; g_stockBitmap = stockBitmap;
g_dcs.insert(dc.get()); g_dcs[dc.get()] = { useDefaultPalette };
return dc.release(); return dc.release();
} }
HBITMAP createDib() HBITMAP createDib(bool useDefaultPalette)
{ {
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
if (!g_surfaceFileMapping) if (!g_surfaceFileMapping)
{ {
return nullptr; return nullptr;
} }
return createDibSection(g_width, -g_height, g_surfaceFileMapping); return createDibSection(g_width, -g_height, g_surfaceFileMapping, useDefaultPalette);
} }
HBITMAP createOffScreenDib(LONG width, LONG height) HBITMAP createOffScreenDib(LONG width, LONG height, bool useDefaultPalette)
{ {
Compat::ScopedCriticalSection lock(g_cs); Compat::ScopedCriticalSection lock(g_cs);
return createDibSection(width, height, nullptr); return createDibSection(width, height, nullptr, useDefaultPalette);
} }
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect) CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect)
@ -190,6 +212,16 @@ namespace Gdi
void init() void init()
{ {
PALETTEENTRY entries[20] = {};
HPALETTE defaultPalette = reinterpret_cast<HPALETTE>(GetStockObject(DEFAULT_PALETTE));
GetPaletteEntries(defaultPalette, 0, 20, entries);
for (int i = 0; i < 10; ++i)
{
g_defaultPalette[i] = convertToRgbQuad(entries[i]);
g_defaultPalette[246 + i] = convertToRgbQuad(entries[10 + i]);
}
update(); update();
} }
@ -223,9 +255,9 @@ namespace Gdi
if (g_surfaceFileMapping) if (g_surfaceFileMapping)
{ {
for (HDC dc : g_dcs) for (auto& dc : g_dcs)
{ {
DeleteObject(SelectObject(dc, g_stockBitmap)); DeleteObject(SelectObject(dc.first, g_stockBitmap));
} }
UnmapViewOfFile(g_surfaceView); UnmapViewOfFile(g_surfaceView);
CloseHandle(g_surfaceFileMapping); CloseHandle(g_surfaceFileMapping);
@ -235,9 +267,9 @@ namespace Gdi
g_pitch * g_height + 8, nullptr); g_pitch * g_height + 8, nullptr);
g_surfaceView = MapViewOfFile(g_surfaceFileMapping, FILE_MAP_WRITE, 0, 0, 0); g_surfaceView = MapViewOfFile(g_surfaceFileMapping, FILE_MAP_WRITE, 0, 0, 0);
for (HDC dc : g_dcs) for (auto& dc : g_dcs)
{ {
SelectObject(dc, createDib()); SelectObject(dc.first, createDib(dc.second.useDefaultPalette));
} }
} }
@ -252,17 +284,18 @@ namespace Gdi
RGBQUAD systemPalette[256] = {}; RGBQUAD systemPalette[256] = {};
for (int i = 0; i < 256; ++i) for (int i = 0; i < 256; ++i)
{ {
systemPalette[i].rgbRed = palette[i].peRed; systemPalette[i] = convertToRgbQuad(palette[i]);
systemPalette[i].rgbGreen = palette[i].peGreen;
systemPalette[i].rgbBlue = palette[i].peBlue;
} }
if (0 != memcmp(g_systemPalette, systemPalette, sizeof(systemPalette))) if (0 != memcmp(g_systemPalette, systemPalette, sizeof(systemPalette)))
{ {
memcpy(g_systemPalette, systemPalette, sizeof(systemPalette)); memcpy(g_systemPalette, systemPalette, sizeof(systemPalette));
for (HDC dc : g_dcs) for (auto& dc : g_dcs)
{ {
SetDIBColorTable(dc, 0, 256, systemPalette); if (!dc.second.useDefaultPalette)
{
SetDIBColorTable(dc.first, 0, 256, systemPalette);
}
} }
} }

@ -10,9 +10,9 @@ namespace Gdi
namespace VirtualScreen namespace VirtualScreen
{ {
HDC createDc(); HDC createDc(bool useDefaultPalette);
HBITMAP createDib(); HBITMAP createDib(bool useDefaultPalette);
HBITMAP createOffScreenDib(LONG width, LONG height); HBITMAP createOffScreenDib(LONG width, LONG height, bool useDefaultPalette);
CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect); CompatPtr<IDirectDrawSurface7> createSurface(const RECT& rect);
void deleteDc(HDC dc); void deleteDc(HDC dc);

@ -429,7 +429,8 @@ namespace Gdi
if (!virtualScreenDc) if (!virtualScreenDc)
{ {
virtualScreenDc.reset(Gdi::VirtualScreen::createDc()); const bool useDefaultPalette = false;
virtualScreenDc.reset(Gdi::VirtualScreen::createDc(useDefaultPalette));
if (!virtualScreenDc) if (!virtualScreenDc)
{ {
return; return;