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:
parent
b747448330
commit
7068d282ff
@ -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 = {};
|
||||
|
@ -16,6 +16,7 @@ namespace D3dDdi
|
||||
void installHooks(HMODULE origDDrawModule);
|
||||
void setFlipIntervalOverride(UINT flipInterval);
|
||||
void setDcFormatOverride(UINT format);
|
||||
void setDcPaletteOverride(bool enable);
|
||||
void waitForVerticalBlank();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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] = {};
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ namespace DDraw
|
||||
virtual void restore();
|
||||
|
||||
static CompatWeakPtr<IDirectDrawPalette> s_palette;
|
||||
static PALETTEENTRY s_paletteEntries[256];
|
||||
|
||||
private:
|
||||
virtual void createImpl() override;
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user