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 <cstring>
#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);
}
}
}

View File

@ -1,6 +1,8 @@
#include <cstring>
#include <vector>
#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<IDirectDrawSurface7>::s_origVtable.SetPalette(
surface, CompatPrimarySurface::palette);
CompatDirectDrawSurface<IDirectDrawSurface7>::s_origVtable.SetPalette(surface, g_palette);
}
return surface;
@ -168,6 +171,11 @@ namespace CompatGdiDcCache
bool init()
{
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;
}
@ -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();
}
}
}

View File

@ -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);
}

View File

@ -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<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);
}
origWndProc(hwnd, WM_PRINT, reinterpret_cast<WPARAM>(compatDc),
PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT);
ValidateRect(hwnd, nullptr);
CompatGdiDc::releaseDc(dc);
}

View File

@ -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<IDirectDraw7>::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<PALETTEENTRY*>(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<IDirectDrawSurface7>::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);
}
};

View File

@ -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);
}

View File

@ -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();