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

Improved palette handling

Fixes windowed-mode palette issues in SimCopter (issue #46)
This commit is contained in:
narzoul 2019-08-02 22:16:44 +02:00
parent b747448330
commit 7068d282ff
13 changed files with 194 additions and 61 deletions

View File

@ -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<D3DKMT_HANDLE, ContextInfo> 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<PALETTEENTRY> 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<D3DDDIFORMAT>(format);
}
void setDcPaletteOverride(bool enable)
{
g_dcPaletteOverride = enable;
}
void waitForVerticalBlank()
{
D3DKMT_WAITFORVERTICALBLANKEVENT data = {};

View File

@ -16,6 +16,7 @@ namespace D3dDdi
void installHooks(HMODULE origDDrawModule);
void setFlipIntervalOverride(UINT flipInterval);
void setDcFormatOverride(UINT format);
void setDcPaletteOverride(bool enable);
void waitForVerticalBlank();
}
}

View File

@ -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<void*>(m_fixedData.pSurfList[subResourceIndex].pSysMem);
}
return nullptr;
}
bool Resource::isOversized() const
{
return m_fixedData.SurfCount != m_origData.SurfCount;

View File

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

View File

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

View File

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

View File

@ -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<IDirectDrawPalette> PrimarySurface::s_palette;
PALETTEENTRY PrimarySurface::s_paletteEntries[256] = {};
}

View File

@ -33,7 +33,6 @@ namespace DDraw
virtual void restore();
static CompatWeakPtr<IDirectDrawPalette> s_palette;
static PALETTEENTRY s_paletteEntries[256];
private:
virtual void createImpl() override;

View File

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

View File

@ -1,9 +1,5 @@
#define WIN32_LEAN_AND_MEAN
#include <set>
#include <Windows.h>
#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<HPALETTE>(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<HPALETTE>(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<PALETTEENTRY> getHardwarePalette()
{
Compat::ScopedCriticalSection lock(g_cs);
return std::vector<PALETTEENTRY>(g_hardwarePalette, g_hardwarePalette + 256);
}
std::vector<PALETTEENTRY> getSystemPalette()
{
Compat::ScopedCriticalSection lock(g_cs);
return std::vector<PALETTEENTRY>(g_systemPalette, g_systemPalette + 256);
}
void installHooks()
{
HPALETTE defaultPalette = reinterpret_cast<HPALETTE>(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);
}
}
}

View File

@ -1,9 +1,20 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <vector>
#include <Windows.h>
namespace Gdi
{
namespace Palette
{
PALETTEENTRY* getDefaultPalette();
std::vector<PALETTEENTRY> getHardwarePalette();
std::vector<PALETTEENTRY> getSystemPalette();
void installHooks();
void setHardwarePalette(PALETTEENTRY* entries);
void setSystemPalette(PALETTEENTRY* entries, DWORD count, bool forceBackground);
}
}

View File

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

View File

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