diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index 549fa29..c0aa293 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -10,10 +10,15 @@ #include "Common/Hook.h" #include "Common/ScopedCriticalSection.h" #include "Common/Time.h" +#include "D3dDdi/Device.h" #include "D3dDdi/Hooks.h" #include "D3dDdi/KernelModeThunks.h" #include "D3dDdi/Log/KernelModeThunksLog.h" +#include "D3dDdi/Resource.h" +#include "D3dDdi/ScopedCriticalSection.h" +#include "DDraw/ScopedThreadLock.h" #include "DDraw/Surfaces/PrimarySurface.h" +#include "Gdi/Palette.h" #include "Win32/DisplayMode.h" namespace @@ -34,6 +39,7 @@ namespace std::map g_contexts; D3DDDIFORMAT g_dcFormatOverride = D3DDDIFMT_UNKNOWN; + bool g_dcPaletteOverride = false; AdapterInfo g_gdiAdapterInfo = {}; AdapterInfo g_lastOpenAdapterInfo = {}; std::string g_lastDDrawCreateDcDevice; @@ -88,20 +94,50 @@ namespace pData->Format = g_dcFormatOverride; } - NTSTATUS result = 0; - if (D3DDDIFMT_P8 == pData->Format && !pData->pColorTable && - DDraw::PrimarySurface::s_palette) + std::vector palette; + auto origColorTable = pData->pColorTable; + + if (D3DDDIFMT_P8 == pData->Format) { - pData->pColorTable = DDraw::PrimarySurface::s_paletteEntries; - result = CALL_ORIG_FUNC(D3DKMTCreateDCFromMemory)(pData); - pData->pColorTable = nullptr; - } - else - { - result = CALL_ORIG_FUNC(D3DKMTCreateDCFromMemory)(pData); + if (g_dcPaletteOverride) + { + palette = Gdi::Palette::getHardwarePalette(); + pData->pColorTable = palette.data(); + } + else + { + DDraw::ScopedThreadLock ddLock; + D3dDdi::ScopedCriticalSection driverLock; + auto primaryResource = D3dDdi::Device::getResource(DDraw::PrimarySurface::getFrontResource()); + if (primaryResource && pData->pMemory == primaryResource->getLockPtr(0) && + (DDraw::PrimarySurface::getOrigCaps() & DDSCAPS_COMPLEX)) + { + pData->pColorTable = Gdi::Palette::getDefaultPalette(); + } + else if (pData->pColorTable) + { + palette.assign(pData->pColorTable, pData->pColorTable + 256); + auto sysPal = Gdi::Palette::getSystemPalette(); + for (UINT i = 0; i < 256; ++i) + { + if (palette[i].peFlags & PC_EXPLICIT) + { + palette[i] = sysPal[palette[i].peRed]; + } + } + pData->pColorTable = palette.data(); + } + else + { + palette = Gdi::Palette::getHardwarePalette(); + pData->pColorTable = palette.data(); + } + } } + auto result = CALL_ORIG_FUNC(D3DKMTCreateDCFromMemory)(pData); pData->Format = origFormat; + pData->pColorTable = origColorTable; return LOG_RESULT(result); } @@ -391,6 +427,11 @@ namespace D3dDdi g_dcFormatOverride = static_cast(format); } + void setDcPaletteOverride(bool enable) + { + g_dcPaletteOverride = enable; + } + void waitForVerticalBlank() { D3DKMT_WAITFORVERTICALBLANKEVENT data = {}; diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.h b/DDrawCompat/D3dDdi/KernelModeThunks.h index 5dd5673..9687150 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.h +++ b/DDrawCompat/D3dDdi/KernelModeThunks.h @@ -16,6 +16,7 @@ namespace D3dDdi void installHooks(HMODULE origDDrawModule); void setFlipIntervalOverride(UINT flipInterval); void setDcFormatOverride(UINT format); + void setDcPaletteOverride(bool enable); void waitForVerticalBlank(); } } diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index a486432..342f741 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -371,6 +371,19 @@ namespace D3dDdi } } + void* Resource::getLockPtr(UINT subResourceIndex) + { + if (subResourceIndex < m_lockData.size()) + { + return m_lockData[subResourceIndex].data; + } + else if (subResourceIndex < m_fixedData.SurfCount) + { + return const_cast(m_fixedData.pSurfList[subResourceIndex].pSysMem); + } + return nullptr; + } + bool Resource::isOversized() const { return m_fixedData.SurfCount != m_origData.SurfCount; diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 129dca3..18e2975 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -28,6 +28,7 @@ namespace D3dDdi HRESULT blt(D3DDDIARG_BLT data); HRESULT colorFill(const D3DDDIARG_COLORFILL& data); void destroy(); + void* getLockPtr(UINT subResourceIndex); HRESULT lock(D3DDDIARG_LOCK& data); void prepareForRendering(UINT subResourceIndex, bool isReadOnly); void resync(); diff --git a/DDrawCompat/DDraw/DirectDrawPalette.cpp b/DDrawCompat/DDraw/DirectDrawPalette.cpp index 077d3a5..f9ff453 100644 --- a/DDrawCompat/DDraw/DirectDrawPalette.cpp +++ b/DDrawCompat/DDraw/DirectDrawPalette.cpp @@ -24,16 +24,10 @@ namespace DDraw if (This == PrimarySurface::s_palette) { waitForNextUpdate(); - if (lpEntries && dwStartingEntry + dwCount <= 256 && - 0 == std::memcmp(&PrimarySurface::s_paletteEntries[dwStartingEntry], - lpEntries, dwCount * sizeof(PALETTEENTRY))) - { - return DD_OK; - } } HRESULT result = s_origVtable.SetEntries(This, dwFlags, dwStartingEntry, dwCount, lpEntries); - if (This == PrimarySurface::s_palette && SUCCEEDED(result)) + if (SUCCEEDED(result) && This == PrimarySurface::s_palette) { PrimarySurface::updatePalette(); } diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 54ba4ff..5a1ae9e 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -375,7 +375,9 @@ namespace g_paletteConverter->GetDC(g_paletteConverter, &paletteConverterDc); HDC srcDc = nullptr; D3dDdi::Device::setReadOnlyGdiLock(true); + D3dDdi::KernelModeThunks::setDcPaletteOverride(true); src->GetDC(src, &srcDc); + D3dDdi::KernelModeThunks::setDcPaletteOverride(false); D3dDdi::Device::setReadOnlyGdiLock(false); if (paletteConverterDc && srcDc) diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp index 3bef74d..0d10534 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.cpp @@ -8,6 +8,7 @@ #include "DDraw/RealPrimarySurface.h" #include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Surfaces/PrimarySurfaceImpl.h" +#include "Gdi/Palette.h" #include "Gdi/VirtualScreen.h" namespace @@ -30,7 +31,6 @@ namespace DDraw g_primarySurface = nullptr; g_origCaps = 0; s_palette = nullptr; - ZeroMemory(&s_paletteEntries, sizeof(s_paletteEntries)); for (auto& lockBuffer : g_lockBackBuffers) { @@ -233,13 +233,28 @@ namespace DDraw void PrimarySurface::updatePalette() { + PALETTEENTRY entries[256] = {}; if (s_palette) { - PrimarySurface::s_palette->GetEntries(s_palette, 0, 0, 256, s_paletteEntries); - RealPrimarySurface::update(); + PrimarySurface::s_palette->GetEntries(s_palette, 0, 0, 256, entries); } + + if (RealPrimarySurface::isFullScreen()) + { + if (!s_palette) + { + auto sysPalEntries(Gdi::Palette::getSystemPalette()); + std::memcpy(entries, sysPalEntries.data(), sizeof(entries)); + } + Gdi::Palette::setHardwarePalette(entries); + } + else if (s_palette) + { + Gdi::Palette::setSystemPalette(entries, 256, false); + } + + RealPrimarySurface::update(); } CompatWeakPtr PrimarySurface::s_palette; - PALETTEENTRY PrimarySurface::s_paletteEntries[256] = {}; } diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h index f33a948..2c4d8f0 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurface.h +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurface.h @@ -33,7 +33,6 @@ namespace DDraw virtual void restore(); static CompatWeakPtr s_palette; - static PALETTEENTRY s_paletteEntries[256]; private: virtual void createImpl() override; diff --git a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp index 597ec0c..44a3aa8 100644 --- a/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/PrimarySurfaceImpl.cpp @@ -222,10 +222,6 @@ namespace DDraw { DirectDrawPalette::waitForNextUpdate(); } - if (lpDDPalette == PrimarySurface::s_palette) - { - return DD_OK; - } HRESULT result = SurfaceImpl::SetPalette(This, lpDDPalette); if (SUCCEEDED(result)) diff --git a/DDrawCompat/Gdi/Palette.cpp b/DDrawCompat/Gdi/Palette.cpp index ec27fb1..b0d0cc4 100644 --- a/DDrawCompat/Gdi/Palette.cpp +++ b/DDrawCompat/Gdi/Palette.cpp @@ -1,9 +1,5 @@ -#define WIN32_LEAN_AND_MEAN - #include -#include - #include "Common/Hook.h" #include "Common/Log.h" #include "Common/ScopedCriticalSection.h" @@ -15,6 +11,8 @@ namespace { Compat::CriticalSection g_cs; + PALETTEENTRY g_defaultPalette[256] = {}; + PALETTEENTRY g_hardwarePalette[256] = {}; PALETTEENTRY g_systemPalette[256] = {}; UINT g_systemPaletteUse = SYSPAL_STATIC; UINT g_systemPaletteFirstUnusedIndex = 10; @@ -51,33 +49,18 @@ namespace return false; } - UINT fillSystemPalette(HDC dc) + void updateStaticSysPalEntries() { - HPALETTE palette = reinterpret_cast(GetCurrentObject(dc, OBJ_PAL)); - if (!palette || GetStockObject(DEFAULT_PALETTE) == palette) + const UINT count = g_systemPaletteFirstNonReservedIndex; + if (0 == count) { - 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; + return; } + memcpy(g_systemPalette, g_defaultPalette, count * sizeof(g_systemPalette[0])); + memcpy(&g_systemPalette[256 - count], &g_defaultPalette[256 - count], count * sizeof(g_systemPalette[0])); + Gdi::Palette::setHardwarePalette(g_systemPalette); Gdi::VirtualScreen::updatePalette(g_systemPalette); - return count; } UINT WINAPI getSystemPaletteEntries(HDC hdc, UINT iStartIndex, UINT nEntries, LPPALETTEENTRY lppe) @@ -117,7 +100,7 @@ namespace return LOG_RESULT(SYSPAL_ERROR); } Compat::ScopedCriticalSection lock(g_cs); - return g_systemPaletteUse; + return LOG_RESULT(g_systemPaletteUse); } UINT WINAPI realizePalette(HDC hdc) @@ -126,11 +109,18 @@ namespace if (Gdi::isDisplayDc(hdc)) { Compat::ScopedCriticalSection lock(g_cs); - if (g_foregroundPaletteDcs.find(hdc) != g_foregroundPaletteDcs.end()) + + HPALETTE palette = reinterpret_cast(GetCurrentObject(hdc, OBJ_PAL)); + if (!palette || GetStockObject(DEFAULT_PALETTE) == palette) { - g_systemPaletteFirstUnusedIndex = g_systemPaletteFirstNonReservedIndex; + return 0; } - return LOG_RESULT(fillSystemPalette(hdc)); + + PALETTEENTRY entries[256] = {}; + UINT count = GetPaletteEntries(palette, 0, 256, entries); + Gdi::Palette::setSystemPalette(entries, count, + g_foregroundPaletteDcs.find(hdc) == g_foregroundPaletteDcs.end()); + return LOG_RESULT(count); } return LOG_RESULT(CALL_ORIG_FUNC(RealizePalette)(hdc)); } @@ -175,6 +165,11 @@ namespace } Compat::ScopedCriticalSection lock(g_cs); + if (uUsage == g_systemPaletteUse) + { + return LOG_RESULT(g_systemPaletteUse); + } + const UINT prevUsage = g_systemPaletteUse; switch (uUsage) { @@ -198,6 +193,7 @@ namespace } g_systemPaletteUse = uUsage; + updateStaticSysPalEntries(); return LOG_RESULT(prevUsage); } } @@ -206,12 +202,30 @@ namespace Gdi { namespace Palette { + PALETTEENTRY* getDefaultPalette() + { + return g_defaultPalette; + } + + std::vector getHardwarePalette() + { + Compat::ScopedCriticalSection lock(g_cs); + return std::vector(g_hardwarePalette, g_hardwarePalette + 256); + } + + std::vector getSystemPalette() + { + Compat::ScopedCriticalSection lock(g_cs); + return std::vector(g_systemPalette, g_systemPalette + 256); + } + void installHooks() { HPALETTE defaultPalette = reinterpret_cast(GetStockObject(DEFAULT_PALETTE)); - GetPaletteEntries(defaultPalette, 0, 10, g_systemPalette); - GetPaletteEntries(defaultPalette, 10, 10, &g_systemPalette[246]); - Gdi::VirtualScreen::updatePalette(g_systemPalette); + GetPaletteEntries(defaultPalette, 0, 10, g_defaultPalette); + GetPaletteEntries(defaultPalette, 10, 10, &g_defaultPalette[246]); + + updateStaticSysPalEntries(); HOOK_FUNCTION(gdi32, GetSystemPaletteEntries, getSystemPaletteEntries); HOOK_FUNCTION(gdi32, GetSystemPaletteUse, getSystemPaletteUse); @@ -220,5 +234,36 @@ namespace Gdi HOOK_FUNCTION(gdi32, SelectPalette, selectPalette); HOOK_FUNCTION(gdi32, SetSystemPaletteUse, setSystemPaletteUse); } + + void setHardwarePalette(PALETTEENTRY* entries) + { + Compat::ScopedCriticalSection lock(g_cs); + std::memcpy(g_hardwarePalette, entries, sizeof(g_hardwarePalette)); + } + + void setSystemPalette(PALETTEENTRY* entries, DWORD count, bool forceBackground) + { + Compat::ScopedCriticalSection lock(g_cs); + if (!forceBackground) + { + g_systemPaletteFirstUnusedIndex = g_systemPaletteFirstNonReservedIndex; + } + + 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::Palette::setHardwarePalette(g_systemPalette); + Gdi::VirtualScreen::updatePalette(g_systemPalette); + } } } diff --git a/DDrawCompat/Gdi/Palette.h b/DDrawCompat/Gdi/Palette.h index 21948af..3e8b356 100644 --- a/DDrawCompat/Gdi/Palette.h +++ b/DDrawCompat/Gdi/Palette.h @@ -1,9 +1,20 @@ #pragma once +#define WIN32_LEAN_AND_MEAN + +#include + +#include + namespace Gdi { namespace Palette { + PALETTEENTRY* getDefaultPalette(); + std::vector getHardwarePalette(); + std::vector getSystemPalette(); void installHooks(); + void setHardwarePalette(PALETTEENTRY* entries); + void setSystemPalette(PALETTEENTRY* entries, DWORD count, bool forceBackground); } } diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index 97ad09f..a7fbb2a 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -5,6 +5,7 @@ #include "D3dDdi/Device.h" #include "D3dDdi/ScopedCriticalSection.h" #include "DDraw/DirectDraw.h" +#include "DDraw/RealPrimarySurface.h" #include "DDraw/ScopedThreadLock.h" #include "DDraw/Surfaces/PrimarySurface.h" #include "Gdi/Gdi.h" @@ -263,6 +264,8 @@ namespace Gdi SetDIBColorTable(dc, 0, 256, systemPalette); } } + + DDraw::RealPrimarySurface::gdiUpdate(); } } } diff --git a/DDrawCompat/Win32/DisplayMode.cpp b/DDrawCompat/Win32/DisplayMode.cpp index 8c248db..fee537f 100644 --- a/DDrawCompat/Win32/DisplayMode.cpp +++ b/DDrawCompat/Win32/DisplayMode.cpp @@ -203,9 +203,21 @@ namespace int WINAPI getDeviceCaps(HDC hdc, int nIndex) { LOG_FUNC("GetDeviceCaps", hdc, nIndex); - if (BITSPIXEL == nIndex && Gdi::isDisplayDc(hdc)) + switch (nIndex) { - return LOG_RESULT(g_currentBpp); + case BITSPIXEL: + if (Gdi::isDisplayDc(hdc)) + { + return LOG_RESULT(g_currentBpp); + } + break; + + case RASTERCAPS: + if (8 == g_currentBpp && Gdi::isDisplayDc(hdc)) + { + return LOG_RESULT(CALL_ORIG_FUNC(GetDeviceCaps)(hdc, nIndex) | RC_PALETTE); + } + break; } return LOG_RESULT(CALL_ORIG_FUNC(GetDeviceCaps)(hdc, nIndex)); }