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

Support PC_RESERVED palette entry flag for GDI rendering

This commit is contained in:
narzoul 2016-04-17 01:01:14 +02:00
parent 111719eaf7
commit d4042f7e95
7 changed files with 58 additions and 155 deletions

View File

@ -1,5 +1,4 @@
#include <atomic> #include <atomic>
#include <cstring>
#include "CompatDirectDrawPalette.h" #include "CompatDirectDrawPalette.h"
#include "CompatDirectDrawSurface.h" #include "CompatDirectDrawSurface.h"
@ -25,8 +24,6 @@ namespace
HANDLE g_ddUnlockEndEvent = nullptr; HANDLE g_ddUnlockEndEvent = nullptr;
bool g_isDelayedUnlockPending = false; bool g_isDelayedUnlockPending = false;
PALETTEENTRY g_usedPaletteEntries[256] = {};
BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM lParam) BOOL CALLBACK invalidateWindow(HWND hwnd, LPARAM lParam)
{ {
if (!IsWindowVisible(hwnd)) if (!IsWindowVisible(hwnd))
@ -73,45 +70,6 @@ namespace
return true; 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() void unlockPrimarySurface()
{ {
GdiFlush(); GdiFlush();
@ -212,7 +170,6 @@ namespace CompatGdi
void installHooks() void installHooks()
{ {
InitializeCriticalSection(&g_gdiCriticalSection); InitializeCriticalSection(&g_gdiCriticalSection);
CompatPaletteConverter::init();
if (CompatGdiDcCache::init()) if (CompatGdiDcCache::init())
{ {
g_ddUnlockBeginEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); g_ddUnlockBeginEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
@ -246,18 +203,9 @@ namespace CompatGdi
void updatePalette(DWORD startingEntry, DWORD count) void updatePalette(DWORD startingEntry, DWORD count)
{ {
if (!isEmulationEnabled()) if (isEmulationEnabled() && CompatPrimarySurface::palette)
{ {
return; CompatGdiDcCache::updatePalette(startingEntry, count);
}
Compat::ScopedCriticalSection gdiLock(g_gdiCriticalSection);
CompatGdiDcCache::clear();
if (CompatPrimarySurface::palette)
{
replaceDuplicateWhitePaletteEntries(startingEntry, count);
invalidate(nullptr);
} }
} }
} }

View File

@ -1,6 +1,8 @@
#include <cstring>
#include <vector> #include <vector>
#include "CompatDirectDraw.h" #include "CompatDirectDraw.h"
#include "CompatDirectDrawPalette.h"
#include "CompatDirectDrawSurface.h" #include "CompatDirectDrawSurface.h"
#include "CompatGdiDcCache.h" #include "CompatGdiDcCache.h"
#include "CompatPrimarySurface.h" #include "CompatPrimarySurface.h"
@ -20,6 +22,8 @@ namespace
DWORD g_ddLockThreadId = 0; DWORD g_ddLockThreadId = 0;
IDirectDraw7* g_directDraw = nullptr; IDirectDraw7* g_directDraw = nullptr;
IDirectDrawPalette* g_palette = nullptr;
PALETTEENTRY g_paletteEntries[256] = {};
void* g_surfaceMemory = nullptr; void* g_surfaceMemory = nullptr;
LONG g_pitch = 0; LONG g_pitch = 0;
@ -74,10 +78,9 @@ namespace
return nullptr; return nullptr;
} }
if (CompatPrimarySurface::palette) if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
{ {
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette( CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(surface, g_palette);
surface, CompatPrimarySurface::palette);
} }
return surface; return surface;
@ -168,6 +171,11 @@ namespace CompatGdiDcCache
bool init() bool init()
{ {
g_directDraw = DDrawRepository::getDirectDraw(); g_directDraw = DDrawRepository::getDirectDraw();
if (g_directDraw)
{
CompatDirectDraw<IDirectDraw7>::s_origVtable.CreatePalette(
g_directDraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256, g_paletteEntries, &g_palette, nullptr);
}
return nullptr != g_directDraw; return nullptr != g_directDraw;
} }
@ -199,4 +207,31 @@ namespace CompatGdiDcCache
g_pitch = pitch; g_pitch = pitch;
clear(); 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();
}
}
} }

View File

@ -21,4 +21,5 @@ namespace CompatGdiDcCache
void releaseDc(const CachedDc& cachedDc); void releaseDc(const CachedDc& cachedDc);
void setDdLockThreadId(DWORD ddLockThreadId); void setDdLockThreadId(DWORD ddLockThreadId);
void setSurfaceMemory(void* surfaceMemory, LONG pitch); void setSurfaceMemory(void* surfaceMemory, LONG pitch);
void updatePalette(DWORD startingEntry, DWORD count);
} }

View File

@ -4,7 +4,6 @@
#include "CompatGdiScrollBar.h" #include "CompatGdiScrollBar.h"
#include "CompatGdiScrollFunctions.h" #include "CompatGdiScrollFunctions.h"
#include "CompatGdiTitleBar.h" #include "CompatGdiTitleBar.h"
#include "CompatPaletteConverter.h"
#include "CompatPrimarySurface.h" #include "CompatPrimarySurface.h"
#include "CompatRegistry.h" #include "CompatRegistry.h"
#include "DDrawLog.h" #include "DDrawLog.h"
@ -158,27 +157,8 @@ namespace
HDC compatDc = CompatGdiDc::getDc(dc, isMenuPaintDc); HDC compatDc = CompatGdiDc::getDc(dc, isMenuPaintDc);
if (compatDc) if (compatDc)
{ {
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8) origWndProc(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc),
{ PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
HDC converterDc = CompatPaletteConverter::lockDc();
CompatPaletteConverter::setHalftonePalette();
origWndProc(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(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<WPARAM>(compatDc),
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
}
ValidateRect(hwnd, nullptr); ValidateRect(hwnd, nullptr);
CompatGdiDc::releaseDc(dc); CompatGdiDc::releaseDc(dc);
} }

View File

@ -14,9 +14,7 @@
namespace namespace
{ {
CRITICAL_SECTION g_criticalSection = {};
HDC g_dc = nullptr; HDC g_dc = nullptr;
RGBQUAD g_halftonePalette[256] = {};
HGDIOBJ g_oldBitmap = nullptr; HGDIOBJ g_oldBitmap = nullptr;
IDirectDrawSurface7* g_surface = nullptr; IDirectDrawSurface7* g_surface = nullptr;
@ -73,18 +71,6 @@ namespace
CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(dd, &desc, &surface, nullptr); CompatDirectDraw<IDirectDraw7>::s_origVtable.CreateSurface(dd, &desc, &surface, nullptr);
return surface; return surface;
} }
void initHalftonePalette()
{
HDC dc = GetDC(nullptr);
HPALETTE palette = CreateHalftonePalette(dc);
GetPaletteEntries(palette, 0, 256, reinterpret_cast<PALETTEENTRY*>(g_halftonePalette));
convertPaletteEntriesToRgbQuad(g_halftonePalette, 256);
DeleteObject(palette);
ReleaseDC(nullptr, dc);
}
} }
namespace CompatPaletteConverter namespace CompatPaletteConverter
@ -122,35 +108,24 @@ namespace CompatPaletteConverter
return false; return false;
} }
Compat::ScopedCriticalSection lock(g_criticalSection);
g_oldBitmap = SelectObject(dc, dib); g_oldBitmap = SelectObject(dc, dib);
g_dc = dc; g_dc = dc;
g_surface = surface; g_surface = surface;
return true; return true;
} }
void init() HDC getDc()
{ {
InitializeCriticalSection(&g_criticalSection);
initHalftonePalette();
}
HDC lockDc()
{
EnterCriticalSection(&g_criticalSection);
return g_dc; return g_dc;
} }
IDirectDrawSurface7* lockSurface() IDirectDrawSurface7* getSurface()
{ {
EnterCriticalSection(&g_criticalSection);
return g_surface; return g_surface;
} }
void release() void release()
{ {
Compat::ScopedCriticalSection lock(g_criticalSection);
if (!g_surface) if (!g_surface)
{ {
return; return;
@ -166,7 +141,6 @@ namespace CompatPaletteConverter
void setClipper(IDirectDrawClipper* clipper) void setClipper(IDirectDrawClipper* clipper)
{ {
Compat::ScopedCriticalSection lock(g_criticalSection);
if (g_surface) if (g_surface)
{ {
HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper( HRESULT result = CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetClipper(
@ -178,40 +152,15 @@ namespace CompatPaletteConverter
} }
} }
void setHalftonePalette() void updatePalette(DWORD startingEntry, DWORD count)
{ {
EnterCriticalSection(&g_criticalSection); if (g_dc && CompatPrimarySurface::palette)
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 (CompatPrimarySurface::palette) RGBQUAD entries[256] = {};
{ std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry],
RGBQUAD entries[256] = {}; count * sizeof(PALETTEENTRY));
std::memcpy(entries, &CompatPrimarySurface::paletteEntries[startingEntry], convertPaletteEntriesToRgbQuad(entries, count);
count * sizeof(PALETTEENTRY)); SetDIBColorTable(g_dc, startingEntry, count, entries);
convertPaletteEntriesToRgbQuad(entries, count);
SetDIBColorTable(g_dc, startingEntry, count, entries);
}
else
{
SetDIBColorTable(g_dc, 0, 256, g_halftonePalette);
}
} }
} }
void unlockDc()
{
LeaveCriticalSection(&g_criticalSection);
}
void unlockSurface()
{
LeaveCriticalSection(&g_criticalSection);
}
}; };

View File

@ -7,13 +7,9 @@
namespace CompatPaletteConverter namespace CompatPaletteConverter
{ {
bool create(); bool create();
void init(); HDC getDc();
HDC lockDc(); IDirectDrawSurface7* getSurface();
IDirectDrawSurface7* lockSurface();
void release(); void release();
void setClipper(IDirectDrawClipper* clipper); void setClipper(IDirectDrawClipper* clipper);
void setHalftonePalette(); void updatePalette(DWORD startingEntry, DWORD count);
void setPrimaryPalette(DWORD startingEntry, DWORD count);
void unlockDc();
void unlockSurface();
} }

View File

@ -53,22 +53,16 @@ namespace
if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8) if (CompatPrimarySurface::pixelFormat.dwRGBBitCount <= 8)
{ {
IDirectDrawSurface7* converterSurface = CompatPaletteConverter::lockSurface(); origVtable.Blt(CompatPaletteConverter::getSurface(), &g_updateRect,
HDC converterDc = CompatPaletteConverter::lockDc();
origVtable.Blt(converterSurface, &g_updateRect,
CompatPrimarySurface::surface, &g_updateRect, DDBLT_WAIT, nullptr); CompatPrimarySurface::surface, &g_updateRect, DDBLT_WAIT, nullptr);
HDC destDc = nullptr; HDC destDc = nullptr;
origVtable.GetDC(dest, &destDc); origVtable.GetDC(dest, &destDc);
result = TRUE == CALL_ORIG_FUNC(BitBlt)(destDc, g_updateRect.left, g_updateRect.top, 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, 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); origVtable.ReleaseDC(dest, destDc);
CompatPaletteConverter::unlockDc();
CompatPaletteConverter::unlockSurface();
if (dest == g_frontBuffer) if (dest == g_frontBuffer)
{ {
// Force the screen to be updated. It won't refresh from BitBlt alone. // 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) void RealPrimarySurface::updatePalette(DWORD startingEntry, DWORD count)
{ {
CompatPaletteConverter::setPrimaryPalette(startingEntry, count); CompatPaletteConverter::updatePalette(startingEntry, count);
CompatGdi::updatePalette(startingEntry, count); CompatGdi::updatePalette(startingEntry, count);
invalidate(nullptr); invalidate(nullptr);
update(); update();