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

Create helper surfaces via DirectDraw runtime

This commit is contained in:
narzoul 2021-06-05 17:29:51 +02:00
parent 51a451f424
commit 62983b19fe
17 changed files with 378 additions and 280 deletions

View File

@ -0,0 +1,23 @@
#pragma once
#include <tuple>
#include <type_traits>
#include <Windows.h>
template <typename T>
std::enable_if_t<std::is_class_v<T> && std::is_trivial_v<T>, bool> operator==(const T& left, const T& right)
{
return toTuple(left) == toTuple(right);
}
template <typename T>
std::enable_if_t<std::is_class_v<T> && std::is_trivial_v<T>, bool> operator<(const T& left, const T& right)
{
return toTuple(left) < toTuple(right);
}
inline auto toTuple(const LUID& luid)
{
return std::make_tuple(luid.LowPart, luid.HighPart);
}

View File

@ -1,9 +1,11 @@
#include <Common/Comparison.h>
#include <Common/CompatVtable.h>
#include <D3dDdi/Adapter.h>
#include <D3dDdi/AdapterFuncs.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/DeviceCallbacks.h>
#include <D3dDdi/DeviceFuncs.h>
#include <D3dDdi/KernelModeThunks.h>
namespace
{
@ -30,7 +32,10 @@ namespace D3dDdi
, m_origVtable(CompatVtable<D3DDDI_ADAPTERFUNCS>::s_origVtable)
, m_runtimeVersion(data.Version)
, m_driverVersion(data.DriverVersion)
, m_luid(KernelModeThunks::getLastOpenAdapterInfo().luid)
, m_repository{}
, m_d3dExtendedCaps{}
, m_ddrawCaps{}
{
if (m_adapter)
{
@ -143,5 +148,16 @@ namespace D3dDdi
return result;
}
void Adapter::setRepository(LUID luid, const DDraw::DirectDraw::Repository& repository)
{
for (auto& adapter : s_adapters)
{
if (adapter.second.m_luid == luid)
{
adapter.second.m_repository = repository;
}
}
}
std::map<HANDLE, Adapter> Adapter::s_adapters;
}

View File

@ -6,6 +6,9 @@
#include <d3dnthal.h>
#include <d3dumddi.h>
#include <Common/CompatPtr.h>
#include <DDraw/DirectDraw.h>
namespace D3dDdi
{
class Adapter
@ -21,7 +24,10 @@ namespace D3dDdi
const D3DNTHAL_D3DEXTENDEDCAPS& getD3dExtendedCaps() const { return m_d3dExtendedCaps; }
const DDRAW_CAPS& getDDrawCaps() const { return m_ddrawCaps; }
LUID getLuid() const { return m_luid; }
const D3DDDI_ADAPTERFUNCS& getOrigVtable() const { return m_origVtable; }
CompatWeakPtr<IDirectDraw7> getRepository() const { return m_repository.repo; }
bool isSrcColorKeySupported() const { return m_repository.isSrcColorKeySupported; }
HRESULT pfnCloseAdapter();
HRESULT pfnCreateDevice(D3DDDIARG_CREATEDEVICE* pCreateData);
@ -29,6 +35,7 @@ namespace D3dDdi
static void add(const D3DDDIARG_OPENADAPTER& data) { s_adapters.emplace(data.hAdapter, data); }
static Adapter& get(HANDLE adapter) { return s_adapters.find(adapter)->second; }
static void setRepository(LUID luid, const DDraw::DirectDraw::Repository& repository);
private:
DWORD getSupportedZBufferBitDepths();
@ -37,6 +44,8 @@ namespace D3dDdi
D3DDDI_ADAPTERFUNCS m_origVtable;
UINT m_runtimeVersion;
UINT m_driverVersion;
LUID m_luid;
DDraw::DirectDraw::Repository m_repository;
D3DNTHAL_D3DEXTENDEDCAPS m_d3dExtendedCaps;
DDRAW_CAPS m_ddrawCaps;

View File

@ -17,19 +17,6 @@ namespace
{
HANDLE g_gdiResourceHandle = nullptr;
D3dDdi::Resource* g_gdiResource = nullptr;
void logSrcColorKeySupportFailure(const char* reason, UINT32 resultCode)
{
std::ostringstream oss;
oss << "Checking source color key support: failed (" << reason;
if (resultCode)
{
oss << ": " << Compat::hex(resultCode);
}
oss << ')';
LOG_ONCE(oss.str().c_str());
}
}
namespace D3dDdi
@ -38,7 +25,6 @@ namespace D3dDdi
: m_origVtable(CompatVtable<D3DDDI_DEVICEFUNCS>::s_origVtable)
, m_adapter(adapter)
, m_device(device)
, m_isSrcColorKeySupported(checkSrcColorKeySupport())
, m_renderTarget(nullptr)
, m_renderTargetSubResourceIndex(0)
, m_sharedPrimary(nullptr)
@ -53,140 +39,26 @@ namespace D3dDdi
s_devices.try_emplace(device, adapter, device);
}
bool Device::checkSrcColorKeySupport()
{
if (!(m_adapter.getDDrawCaps().CKeyCaps & DDRAW_CKEYCAPS_SRCBLT))
{
logSrcColorKeySupportFailure("driver indicates no support", 0);
return false;
}
D3DDDI_SURFACEINFO si = {};
si.Width = 2;
si.Height = 1;
D3DDDIARG_CREATERESOURCE2 cr = {};
cr.Format = D3DDDIFMT_R5G6B5;
cr.Pool = D3DDDIPOOL_VIDEOMEMORY;
cr.pSurfList = &si;
cr.SurfCount = 1;
cr.Rotation = D3DDDI_ROTATION_IDENTITY;
HRESULT result = createPrivateResource(cr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error creating source resource", result);
return false;
}
auto resourceDeleter = [&](HANDLE resource) { m_origVtable.pfnDestroyResource(m_device, resource); };
std::unique_ptr<void, std::function<void(HANDLE)>> srcRes(cr.hResource, resourceDeleter);
cr.hResource = nullptr;
cr.Flags.RenderTarget = 1;
result = createPrivateResource(cr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error creating destination resource", result);
return false;
}
std::unique_ptr<void, std::function<void(HANDLE)>> dstRes(cr.hResource, resourceDeleter);
D3DDDIARG_LOCK lock = {};
lock.hResource = srcRes.get();
result = m_origVtable.pfnLock(m_device, &lock);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error locking source resource", result);
return false;
}
const UINT16 colorKey = 0xFA9F;
*static_cast<UINT32*>(lock.pSurfData) = colorKey;
D3DDDIARG_UNLOCK unlock = {};
unlock.hResource = srcRes.get();
m_origVtable.pfnUnlock(m_device, &unlock);
lock = {};
lock.hResource = dstRes.get();
result = m_origVtable.pfnLock(m_device, &lock);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error locking destination resource", result);
return false;
}
*static_cast<UINT32*>(lock.pSurfData) = 0xFFFFFFFF;
unlock.hResource = dstRes.get();
m_origVtable.pfnUnlock(m_device, &unlock);
D3DDDIARG_BLT blt = {};
blt.hSrcResource = srcRes.get();
blt.SrcRect = { 0, 0, 2, 1 };
blt.hDstResource = dstRes.get();
blt.DstRect = { 0, 0, 2, 1 };
blt.ColorKey = colorKey;
blt.Flags.SrcColorKey = 1;
result = m_origVtable.pfnBlt(m_device, &blt);
if (FAILED(result))
{
logSrcColorKeySupportFailure("blt error", result);
return false;
}
lock = {};
lock.hResource = dstRes.get();
result = m_origVtable.pfnLock(m_device, &lock);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error locking destination resource after blt", result);
return false;
}
const UINT32 dstPixels = *static_cast<UINT32*>(lock.pSurfData);
unlock.hResource = dstRes.get();
m_origVtable.pfnUnlock(m_device, &unlock);
if (dstPixels != 0xFFFF)
{
logSrcColorKeySupportFailure("test result pattern is incorrect", dstPixels);
return false;
}
LOG_ONCE("Checking source color key support: passed");
return true;
}
HRESULT Device::createPrivateResource(D3DDDIARG_CREATERESOURCE2& data)
{
if (m_origVtable.pfnCreateResource2)
const bool isPalettizedOffScreen = D3DDDIFMT_P8 == data.Format && !data.Flags.Texture;
if (isPalettizedOffScreen)
{
return m_origVtable.pfnCreateResource2(m_device, &data);
data.Format = D3DDDIFMT_L8;
data.Flags.Texture = 1;
}
return m_origVtable.pfnCreateResource(m_device, reinterpret_cast<D3DDDIARG_CREATERESOURCE*>(&data));
}
template <typename Arg>
HRESULT Device::createResourceImpl(Arg& data)
{
try
HRESULT result = m_origVtable.pfnCreateResource2
? m_origVtable.pfnCreateResource2(m_device, &data)
: m_origVtable.pfnCreateResource(m_device, reinterpret_cast<D3DDDIARG_CREATERESOURCE*>(&data));
if (isPalettizedOffScreen)
{
Resource resource(*this, data);
m_resources.emplace(resource, std::move(resource));
if (data.Flags.VertexBuffer &&
D3DDDIPOOL_SYSTEMMEM == data.Pool &&
data.pSurfList[0].pSysMem)
{
m_drawPrimitive.addSysMemVertexBuffer(data.hResource,
static_cast<BYTE*>(const_cast<void*>(data.pSurfList[0].pSysMem)));
}
return S_OK;
}
catch (const HResultException& e)
{
return e.getResult();
data.Format = D3DDDIFMT_P8;
data.Flags.Texture = 0;
}
return result;
}
Resource* Device::findResource(HANDLE resource)
@ -297,12 +169,32 @@ namespace D3dDdi
HRESULT Device::pfnCreateResource(D3DDDIARG_CREATERESOURCE* data)
{
return createResourceImpl(*data);
D3DDDIARG_CREATERESOURCE2 data2 = {};
memcpy(&data2, data, sizeof(*data));
HRESULT result = pfnCreateResource2(&data2);
data->hResource = data2.hResource;
return result;
}
HRESULT Device::pfnCreateResource2(D3DDDIARG_CREATERESOURCE2* data)
{
return createResourceImpl(*data);
try
{
Resource resource(*this, *data);
m_resources.emplace(resource, std::move(resource));
if (data->Flags.VertexBuffer &&
D3DDDIPOOL_SYSTEMMEM == data->Pool &&
data->pSurfList[0].pSysMem)
{
m_drawPrimitive.addSysMemVertexBuffer(data->hResource,
static_cast<BYTE*>(const_cast<void*>(data->pSurfList[0].pSysMem)));
}
return S_OK;
}
catch (const HResultException& e)
{
return e.getResult();
}
}
HRESULT Device::pfnDestroyDevice()

View File

@ -59,8 +59,6 @@ namespace D3dDdi
void prepareForRendering();
void setRenderTarget(const D3DDDIARG_SETRENDERTARGET& data);
bool isSrcColorKeySupported() const { return m_isSrcColorKeySupported; }
static void add(Adapter& adapter, HANDLE device);
static Device& get(HANDLE device) { return s_devices.find(device)->second; }
@ -70,11 +68,6 @@ namespace D3dDdi
static void setGdiResourceHandle(HANDLE resource);
private:
bool checkSrcColorKeySupport();
template <typename Arg>
HRESULT createResourceImpl(Arg& data);
D3DDDI_DEVICEFUNCS m_origVtable;
Adapter& m_adapter;
HANDLE m_device;
@ -85,7 +78,6 @@ namespace D3dDdi
DrawPrimitive m_drawPrimitive;
DeviceState m_state;
ShaderBlitter m_shaderBlitter;
bool m_isSrcColorKeySupported;
static std::map<HANDLE, Device> s_devices;
static bool s_isFlushEnabled;

View File

@ -18,17 +18,10 @@
namespace
{
struct AdapterInfo
{
UINT adapter;
UINT vidPnSourceId;
RECT monitorRect;
};
D3DDDIFORMAT g_dcFormatOverride = D3DDDIFMT_UNKNOWN;
bool g_dcPaletteOverride = false;
AdapterInfo g_gdiAdapterInfo = {};
AdapterInfo g_lastOpenAdapterInfo = {};
D3dDdi::KernelModeThunks::AdapterInfo g_gdiAdapterInfo = {};
D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {};
Compat::SrwLock g_lastOpenAdapterInfoSrwLock;
std::string g_lastDDrawCreateDcDevice;
@ -109,7 +102,17 @@ namespace
HDC WINAPI ddrawCreateDcA(LPCSTR pwszDriver, LPCSTR pwszDevice, LPCSTR pszPort, const DEVMODEA* pdm)
{
LOG_FUNC("ddrawCreateDCA", pwszDriver, pwszDevice, pszPort, pdm);
g_lastDDrawCreateDcDevice = pwszDevice ? pwszDevice : std::string();
if (pwszDevice)
{
g_lastDDrawCreateDcDevice = pwszDevice;
}
else
{
MONITORINFOEXA mi = {};
mi.cbSize = sizeof(mi);
CALL_ORIG_FUNC(GetMonitorInfoA)(MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY), &mi);
g_lastDDrawCreateDcDevice = mi.szDevice;
}
return LOG_RESULT(CreateDCA(pwszDriver, pwszDevice, pszPort, pdm));
}
@ -126,11 +129,12 @@ namespace
return TRUE;
}
AdapterInfo getAdapterInfo(const D3DKMT_OPENADAPTERFROMHDC& data)
D3dDdi::KernelModeThunks::AdapterInfo getAdapterInfo(const D3DKMT_OPENADAPTERFROMHDC& data)
{
AdapterInfo adapterInfo = {};
D3dDdi::KernelModeThunks::AdapterInfo adapterInfo = {};
adapterInfo.adapter = data.hAdapter;
adapterInfo.vidPnSourceId = data.VidPnSourceId;
adapterInfo.luid = data.AdapterLuid;
EnumDisplayMonitors(nullptr, nullptr, findDDrawMonitorRect,
reinterpret_cast<LPARAM>(&adapterInfo.monitorRect));
@ -277,6 +281,20 @@ namespace D3dDdi
{
namespace KernelModeThunks
{
AdapterInfo getAdapterInfo(CompatRef<IDirectDraw7> dd)
{
DDraw::ScopedThreadLock lock;
DDDEVICEIDENTIFIER2 di = {};
dd.get().lpVtbl->GetDeviceIdentifier(&dd, &di, 0);
return getLastOpenAdapterInfo();
}
AdapterInfo getLastOpenAdapterInfo()
{
Compat::ScopedSrwLockShared srwLock(g_lastOpenAdapterInfoSrwLock);
return g_lastOpenAdapterInfo;
}
RECT getMonitorRect()
{
auto primary(DDraw::PrimarySurface::getPrimary());
@ -298,7 +316,7 @@ namespace D3dDdi
dd7.get()->lpVtbl->GetDeviceIdentifier(dd7, &di, 0);
}
return g_lastOpenAdapterInfo.monitorRect;
return getLastOpenAdapterInfo().monitorRect;
}
long long getQpcLastVsync()

View File

@ -1,11 +1,23 @@
#pragma once
#include <Windows.h>
#include <ddraw.h>
#include <Common/CompatRef.h>
namespace D3dDdi
{
namespace KernelModeThunks
{
struct AdapterInfo
{
UINT adapter;
UINT vidPnSourceId;
LUID luid;
RECT monitorRect;
};
AdapterInfo getAdapterInfo(CompatRef<IDirectDraw7> dd);
AdapterInfo getLastOpenAdapterInfo();
RECT getMonitorRect();
long long getQpcLastVsync();
UINT getVsyncCounter();

View File

@ -103,27 +103,10 @@ namespace
data.pSurfList = tiles.data();
data.Flags.Texture = 0;
}
D3DDDIARG_CREATERESOURCE2 upgradeResourceData(const D3DDDIARG_CREATERESOURCE& data)
{
D3DDDIARG_CREATERESOURCE2 data2 = {};
reinterpret_cast<D3DDDIARG_CREATERESOURCE&>(data2) = data;
return data2;
}
}
namespace D3dDdi
{
Resource::Data::Data()
: D3DDDIARG_CREATERESOURCE2{}
{
}
Resource::Data::Data(const D3DDDIARG_CREATERESOURCE& data)
: Data(upgradeResourceData(data))
{
}
Resource::Data::Data(const D3DDDIARG_CREATERESOURCE2& data)
: D3DDDIARG_CREATERESOURCE2(data)
{
@ -135,8 +118,7 @@ namespace D3dDdi
pSurfList = surfaceData.data();
}
template <typename Arg>
Resource::Resource(Device& device, Arg& data, HRESULT(APIENTRY* createResourceFunc)(HANDLE, Arg*))
Resource::Resource(Device& device, D3DDDIARG_CREATERESOURCE2& data)
: m_device(device)
, m_handle(nullptr)
, m_origData(data)
@ -154,26 +136,13 @@ namespace D3dDdi
fixResourceData(device, reinterpret_cast<D3DDDIARG_CREATERESOURCE&>(m_fixedData));
m_formatInfo = getFormatInfo(m_fixedData.Format);
const bool isPalettized = D3DDDIFMT_P8 == m_fixedData.Format;
if (isPalettized)
{
m_fixedData.Format = D3DDDIFMT_L8;
m_fixedData.Flags.Texture = 1;
}
HRESULT result = createResourceFunc(device, reinterpret_cast<Arg*>(&m_fixedData));
HRESULT result = m_device.createPrivateResource(m_fixedData);
if (FAILED(result))
{
throw HResultException(result);
}
m_handle = m_fixedData.hResource;
if (isPalettized)
{
m_fixedData.Format = D3DDDIFMT_P8;
m_fixedData.Flags.Texture = 0;
}
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool &&
0 != m_formatInfo.bytesPerPixel)
{
@ -190,16 +159,6 @@ namespace D3dDdi
data.hResource = m_fixedData.hResource;
}
Resource::Resource(Device& device, D3DDDIARG_CREATERESOURCE& data)
: Resource(device, data, device.getOrigVtable().pfnCreateResource)
{
}
Resource::Resource(Device& device, D3DDDIARG_CREATERESOURCE2& data)
: Resource(device, data, device.getOrigVtable().pfnCreateResource2)
{
}
HRESULT Resource::blt(D3DDDIARG_BLT data)
{
if (!isValidRect(data.DstSubResourceIndex, data.DstRect))
@ -445,7 +404,7 @@ namespace D3dDdi
{
LOG_FUNC("Resource::createSysMemResource", Compat::array(surfaceInfo.data(), surfaceInfo.size()));
D3DDDIARG_CREATERESOURCE2 data = {};
data.Format = (D3DDDIFMT_P8 == m_fixedData.Format) ? D3DDDIFMT_L8 : m_fixedData.Format;
data.Format = m_fixedData.Format;
data.Pool = D3DDDIPOOL_SYSTEMMEM;
data.pSurfList = surfaceInfo.data();
data.SurfCount = surfaceInfo.size();
@ -653,7 +612,7 @@ namespace D3dDdi
if (D3DDDIFMT_P8 != m_fixedData.Format)
{
if (data.Flags.MirrorLeftRight || data.Flags.MirrorUpDown ||
(data.Flags.SrcColorKey && !m_device.isSrcColorKeySupported()))
(data.Flags.SrcColorKey && !m_device.getAdapter().isSrcColorKeySupported()))
{
dstLockData.qpcLastForcedLock = now;
srcLockData.qpcLastForcedLock = now;

View File

@ -15,7 +15,6 @@ namespace D3dDdi
class Resource
{
public:
Resource(Device& device, D3DDDIARG_CREATERESOURCE& data);
Resource(Device& device, D3DDDIARG_CREATERESOURCE2& data);
Resource(const Resource&) = delete;
@ -41,8 +40,6 @@ namespace D3dDdi
class Data : public D3DDDIARG_CREATERESOURCE2
{
public:
Data();
Data(const D3DDDIARG_CREATERESOURCE& data);
Data(const D3DDDIARG_CREATERESOURCE2& data);
Data(const Data&) = delete;
@ -74,9 +71,6 @@ namespace D3dDdi
Device& m_device;
};
template <typename Arg>
Resource(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*));
HRESULT bltLock(D3DDDIARG_LOCK& data);
HRESULT bltUnlock(const D3DDDIARG_UNLOCK& data);
void clipRect(UINT subResourceIndex, RECT& rect);

View File

@ -1,44 +1,62 @@
#include <map>
#include <Common/Comparison.h>
#include <Common/Log.h>
#include <D3dDdi/Adapter.h>
#include <D3dDdi/Device.h>
#include <D3dDdi/Resource.h>
#include <D3dDdi/ShaderBlitter.h>
#include <DDraw/DirectDrawSurface.h>
#include <Shaders/PaletteLookup.h>
#define CONCAT_(a, b) a##b
#define CONCAT(a, b) CONCAT_(a, b)
#define SCOPED_STATE(state, ...) DeviceState::Scoped##state CONCAT(scopedState, __LINE__)(m_device.getState(), __VA_ARGS__)
namespace
{
std::map<LUID, CompatWeakPtr<IDirectDrawSurface7>> g_paletteTextures;
CompatWeakPtr<IDirectDrawSurface7> getPaletteTexture(CompatWeakPtr<IDirectDraw7> dd, LUID luid)
{
LOG_FUNC("ShaderBlitter::getPaletteTexture", dd.get(), luid);
if (!dd)
{
LOG_ONCE("Failed to create palette texture: no DirectDraw repository available")
return LOG_RESULT(nullptr);
}
auto it = g_paletteTextures.find(luid);
if (it == g_paletteTextures.end())
{
CompatPtr<IDirectDrawSurface7> paletteTexture;
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
desc.dwWidth = 256;
desc.dwHeight = 1;
desc.ddpfPixelFormat = DDraw::DirectDraw::getRgbPixelFormat(32);
desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
HRESULT result = dd->CreateSurface(dd, &desc, &paletteTexture.getRef(), nullptr);
if (FAILED(result))
{
LOG_ONCE("Failed to create palette texture: " << Compat::hex(result));
return nullptr;
}
it = g_paletteTextures.insert({ luid, paletteTexture.detach() }).first;
}
return LOG_RESULT(it->second.get());
}
}
namespace D3dDdi
{
ShaderBlitter::ShaderBlitter(Device& device)
: m_device(device)
, m_paletteTexture(nullptr)
, m_psPaletteLookup(createPixelShader(g_psPaletteLookup, sizeof(g_psPaletteLookup)))
, m_vertexShaderDecl(createVertexShaderDecl())
{
D3DDDI_SURFACEINFO si = {};
si.Width = 256;
si.Height = 1;
D3DDDIARG_CREATERESOURCE2 cr = {};
cr.Format = D3DDDIFMT_X8R8G8B8;
cr.Pool = D3DDDIPOOL_VIDEOMEMORY;
cr.pSurfList = &si;
cr.SurfCount = 1;
cr.Rotation = D3DDDI_ROTATION_IDENTITY;
cr.Flags.Texture = 1;
m_device.createPrivateResource(cr);
m_paletteTexture = cr.hResource;
}
ShaderBlitter::~ShaderBlitter()
{
if (m_paletteTexture)
{
m_device.getOrigVtable().pfnDestroyResource(m_device, m_paletteTexture);
m_paletteTexture = nullptr;
}
}
void ShaderBlitter::blt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect,
@ -146,32 +164,42 @@ namespace D3dDdi
void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
const Resource& srcResource, RGBQUAD palette[256])
{
LOG_FUNC("ShaderBlitter::palettizedBlt", static_cast<HANDLE>(dstResource), dstSubResourceIndex,
static_cast<HANDLE>(srcResource), Compat::array(reinterpret_cast<void**>(palette), 256));
if (m_paletteTexture && FAILED(m_paletteTexture->IsLost(m_paletteTexture)))
{
g_paletteTextures.erase(m_device.getAdapter().getLuid());
m_paletteTexture->Release(m_paletteTexture);
m_paletteTexture = nullptr;
}
if (!m_paletteTexture)
{
return;
m_paletteTexture = getPaletteTexture(m_device.getAdapter().getRepository(), m_device.getAdapter().getLuid());
if (!m_paletteTexture)
{
return;
}
}
D3DDDIARG_LOCK lock = {};
lock.hResource = m_paletteTexture;
lock.Flags.Discard = 1;
m_device.getOrigVtable().pfnLock(m_device, &lock);
if (!lock.pSurfData)
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
m_paletteTexture->Lock(m_paletteTexture, nullptr, &desc, DDLOCK_DISCARDCONTENTS | DDLOCK_WAIT, nullptr);
if (!desc.lpSurface)
{
return;
}
memcpy(lock.pSurfData, palette, 256 * sizeof(RGBQUAD));
D3DDDIARG_UNLOCK unlock = {};
unlock.hResource = m_paletteTexture;
m_device.getOrigVtable().pfnUnlock(m_device, &unlock);
memcpy(desc.lpSurface, palette, 256 * sizeof(RGBQUAD));
m_paletteTexture->Unlock(m_paletteTexture, nullptr);
const auto& dstSurface = dstResource.getFixedDesc().pSurfList[dstSubResourceIndex];
const auto& srcSurface = srcResource.getFixedDesc().pSurfList[0];
const RECT dstRect = { 0, 0, static_cast<LONG>(dstSurface.Width), static_cast<LONG>(dstSurface.Height) };
const RECT srcRect = { 0, 0, static_cast<LONG>(srcSurface.Width), static_cast<LONG>(srcSurface.Height) };
SCOPED_STATE(Texture, 1, m_paletteTexture, D3DTEXF_POINT);
SCOPED_STATE(Texture, 1, DDraw::DirectDrawSurface::getDriverResourceHandle(*m_paletteTexture), D3DTEXF_POINT);
blt(dstResource, dstSubResourceIndex, dstRect, srcResource, srcRect, m_psPaletteLookup, D3DTEXF_POINT);
}
}

View File

@ -1,6 +1,8 @@
#pragma once
#include <Windows.h>
#include <ddraw.h>
#include <Common/CompatWeakPtr.h>
namespace D3dDdi
{
@ -15,7 +17,6 @@ namespace D3dDdi
ShaderBlitter(ShaderBlitter&&) = delete;
ShaderBlitter& operator=(const ShaderBlitter&) = delete;
ShaderBlitter& operator=(ShaderBlitter&&) = delete;
~ShaderBlitter();
void palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex,
const Resource& srcResource, RGBQUAD palette[256]);
@ -28,7 +29,7 @@ namespace D3dDdi
HANDLE createVertexShaderDecl();
Device& m_device;
HANDLE m_paletteTexture;
CompatWeakPtr<IDirectDrawSurface7> m_paletteTexture;
HANDLE m_psPaletteLookup;
HANDLE m_vertexShaderDecl;
};

View File

@ -1,7 +1,10 @@
#include <type_traits>
#include <map>
#include <sstream>
#include <Common/Comparison.h>
#include <Common/CompatPtr.h>
#include <Common/CompatVtable.h>
#include <D3dDdi/Adapter.h>
#include <D3dDdi/KernelModeThunks.h>
#include <DDraw/DirectDraw.h>
#include <DDraw/RealPrimarySurface.h>
@ -11,9 +14,106 @@
namespace
{
void logComInstantiation()
void logSrcColorKeySupportFailure(const char* reason, UINT32 resultCode);
bool checkSrcColorKeySupport(CompatRef<IDirectDraw7> dd)
{
LOG_ONCE("COM instantiation of DirectDraw detected");
DDCAPS caps = {};
caps.dwSize = sizeof(caps);
dd->GetCaps(&dd, &caps, nullptr);
if (!(caps.dwCaps & DDCAPS_COLORKEY) || !(caps.dwCKeyCaps & DDCKEYCAPS_SRCBLT))
{
logSrcColorKeySupportFailure("driver indicates no support", 0);
return false;
}
DDSURFACEDESC2 desc = {};
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS;
desc.dwWidth = 2;
desc.dwHeight = 1;
desc.ddpfPixelFormat = DDraw::DirectDraw::getRgbPixelFormat(16);
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
CompatPtr<IDirectDrawSurface7> src;
HRESULT result = dd->CreateSurface(&dd, &desc, &src.getRef(), nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error creating source surface", result);
return false;
}
CompatPtr<IDirectDrawSurface7> dst;
result = dd->CreateSurface(&dd, &desc, &dst.getRef(), nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error creating destination surface", result);
return false;
}
result = src->Lock(src, nullptr, &desc, DDLOCK_WAIT, nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error locking source surface", result);
return false;
}
const UINT16 colorKey = 0xFA9F;
*static_cast<UINT32*>(desc.lpSurface) = colorKey;
src->Unlock(src, nullptr);
result = dst->Lock(dst, nullptr, &desc, DDLOCK_WAIT, nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error locking destination surface", result);
return false;
}
*static_cast<UINT32*>(desc.lpSurface) = 0xFFFFFFFF;
dst->Unlock(dst, nullptr);
DDBLTFX fx = {};
fx.dwSize = sizeof(fx);
fx.ddckSrcColorkey.dwColorSpaceLowValue = colorKey;
fx.ddckSrcColorkey.dwColorSpaceHighValue = colorKey;
result = dst->Blt(dst, nullptr, src, nullptr, DDBLT_KEYSRCOVERRIDE | DDBLT_WAIT, &fx);
if (FAILED(result))
{
logSrcColorKeySupportFailure("blt error", result);
return false;
}
result = dst->Lock(dst, nullptr, &desc, DDLOCK_WAIT, nullptr);
if (FAILED(result))
{
logSrcColorKeySupportFailure("error locking destination resource after blt", result);
return false;
}
const UINT32 dstPixels = *static_cast<UINT32*>(desc.lpSurface);
dst->Unlock(dst, nullptr);
if (dstPixels != 0xFFFF)
{
logSrcColorKeySupportFailure("test result pattern is incorrect", dstPixels);
return false;
}
Compat::Log() << "Source color key support: yes";
return true;
}
void logSrcColorKeySupportFailure(const char* reason, UINT32 resultCode)
{
std::ostringstream oss;
oss << "Source color key support: no (" << reason;
if (resultCode)
{
oss << ": " << Compat::hex(resultCode);
}
oss << ')';
Compat::Log() << oss.str();
}
template <typename TDirectDraw, typename TSurfaceDesc, typename TSurface>
@ -60,14 +160,6 @@ namespace
return DD_OK;
}
template <typename TDirectDraw>
HRESULT STDMETHODCALLTYPE Initialize(TDirectDraw* This, GUID* lpGUID)
{
logComInstantiation();
DDraw::DirectDraw::suppressEmulatedDirectDraw(lpGUID);
return getOrigVtable(This).Initialize(This, lpGUID);
}
template <typename TDirectDraw>
HRESULT STDMETHODCALLTYPE RestoreAllSurfaces(TDirectDraw* This)
{
@ -107,7 +199,6 @@ namespace
vtable.CreateSurface = &CreateSurface;
vtable.FlipToGDISurface = &FlipToGDISurface;
vtable.GetGDISurface = &GetGDISurface;
vtable.Initialize = &Initialize;
vtable.WaitForVerticalBlank = &WaitForVerticalBlank;
if constexpr (std::is_same_v<Vtable, IDirectDraw4Vtbl> || std::is_same_v<Vtable, IDirectDraw7Vtbl>)
@ -166,6 +257,26 @@ namespace DDraw
return pf;
}
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd)
{
static std::map<LUID, Repository> repositories;
auto adapterInfo = D3dDdi::KernelModeThunks::getAdapterInfo(dd);
auto it = repositories.find(adapterInfo.luid);
if (it == repositories.end())
{
CompatPtr<IDirectDraw7> repo;
CALL_ORIG_PROC(DirectDrawCreateEx)(guid, reinterpret_cast<void**>(&repo.getRef()), IID_IDirectDraw7, nullptr);
if (!repo)
{
return;
}
repo->SetCooperativeLevel(repo, nullptr, DDSCL_NORMAL);
it = repositories.insert({ adapterInfo.luid, { repo, checkSrcColorKeySupport(*repo) } }).first;
repo.detach();
}
D3dDdi::Adapter::setRepository(adapterInfo.luid, it->second);
}
void suppressEmulatedDirectDraw(GUID*& guid)
{
if (reinterpret_cast<GUID*>(DDCREATE_EMULATIONONLY) == guid)

View File

@ -2,14 +2,22 @@
#include <ddraw.h>
#include <Common/CompatPtr.h>
#include <Common/CompatRef.h>
namespace DDraw
{
namespace DirectDraw
{
struct Repository
{
CompatWeakPtr<IDirectDraw7> repo;
bool isSrcColorKeySupported;
};
DDSURFACEDESC2 getDisplayMode(CompatRef<IDirectDraw7> dd);
DDPIXELFORMAT getRgbPixelFormat(DWORD bpp);
void onCreate(GUID* guid, CompatRef<IDirectDraw7> dd);
void suppressEmulatedDirectDraw(GUID*& guid);
template <typename TDirectDraw>

View File

@ -12,6 +12,8 @@
namespace
{
decltype(IDirectDraw7Vtbl::Initialize) g_origInitialize = nullptr;
void hookDirectDraw(CompatPtr<IDirectDraw7> dd)
{
DDraw::DirectDraw::hookVtable(*CompatPtr<IDirectDraw>(dd).get()->lpVtbl);
@ -77,6 +79,19 @@ namespace
Compat::Log() << "ERROR: Failed to create a DirectDraw surface for hooking: " << result;
}
}
HRESULT STDMETHODCALLTYPE initialize(IUnknown* This, GUID* lpGUID)
{
LOG_FUNC("IDirectDrawVtbl::Initialize", This, lpGUID);
LOG_ONCE("COM instantiation of DirectDraw detected");
DDraw::DirectDraw::suppressEmulatedDirectDraw(lpGUID);
HRESULT result = g_origInitialize(reinterpret_cast<IDirectDraw7*>(This), lpGUID);
if (SUCCEEDED(result))
{
DDraw::DirectDraw::onCreate(lpGUID, *CompatPtr<IDirectDraw7>::from(This));
}
return result;
}
}
namespace DDraw
@ -90,6 +105,9 @@ namespace DDraw
Win32::Registry::unsetValue(
HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\Microsoft\\DirectDraw", "EmulationOnly");
g_origInitialize = dd7.get()->lpVtbl->Initialize;
Compat::hookFunction(reinterpret_cast<void*&>(g_origInitialize), initialize, "IDirectDrawVtbl::Initialize");
hookDirectDraw(dd7);
hookDirectDrawClipper(*dd7);
hookDirectDrawPalette(*dd7);

View File

@ -191,6 +191,7 @@
</FxCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Common\Comparison.h" />
<ClInclude Include="Common\CompatPtr.h" />
<ClInclude Include="Common\CompatQueryInterface.h" />
<ClInclude Include="Common\CompatRef.h" />

View File

@ -423,6 +423,9 @@
<ClInclude Include="D3dDdi\ShaderBlitter.h">
<Filter>Header Files\D3dDdi</Filter>
</ClInclude>
<ClInclude Include="Common\Comparison.h">
<Filter>Header Files\Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">

View File

@ -40,14 +40,27 @@ namespace
#undef DEFINE_FUNC_NAME
void installHooks();
void onDirectDrawCreate(GUID* lpGUID, LPDIRECTDRAW* lplpDD, IUnknown* pUnkOuter);
void onDirectDrawCreate(GUID* lpGUID, LPVOID* lplpDD, REFIID iid, IUnknown* pUnkOuter);
template <FARPROC(Dll::Procs::* origFunc), typename OrigFuncPtrType, typename FirstParam, typename... Params>
HRESULT WINAPI directDrawFunc(FirstParam firstParam, Params... params)
{
LOG_FUNC(getFuncName<origFunc>(), firstParam, params...);
LOG_FUNC(getFuncName<origFunc>(), params...);
installHooks();
suppressEmulatedDirectDraw(firstParam);
return LOG_RESULT(reinterpret_cast<OrigFuncPtrType>(Dll::g_origProcs.*origFunc)(firstParam, params...));
if constexpr (&Dll::Procs::DirectDrawCreate == origFunc || &Dll::Procs::DirectDrawCreateEx == origFunc)
{
DDraw::DirectDraw::suppressEmulatedDirectDraw(firstParam);
}
HRESULT result = reinterpret_cast<OrigFuncPtrType>(Dll::g_origProcs.*origFunc)(firstParam, params...);
if constexpr (&Dll::Procs::DirectDrawCreate == origFunc || &Dll::Procs::DirectDrawCreateEx == origFunc)
{
if (SUCCEEDED(result))
{
onDirectDrawCreate(firstParam, params...);
}
}
return LOG_RESULT(result);
}
void installHooks()
@ -109,6 +122,16 @@ namespace
(!Compat::isEqual(currentDllPath, dciman32DllPath) && GetModuleHandleW(dciman32DllPath.c_str()));
}
void onDirectDrawCreate(GUID* lpGUID, LPDIRECTDRAW* lplpDD, IUnknown* /*pUnkOuter*/)
{
return DDraw::DirectDraw::onCreate(lpGUID, *CompatPtr<IDirectDraw7>::from(*lplpDD));
}
void onDirectDrawCreate(GUID* lpGUID, LPVOID* lplpDD, REFIID /*iid*/, IUnknown* /*pUnkOuter*/)
{
return DDraw::DirectDraw::onCreate(lpGUID, *CompatPtr<IDirectDraw7>::from(static_cast<IDirectDraw7*>(*lplpDD)));
}
void printEnvironmentVariable(const char* var)
{
Compat::Log() << "Environment variable " << var << " = \"" << Dll::getEnvVar(var) << '"';
@ -128,16 +151,6 @@ namespace
}
SetProcessDPIAware();
}
template <typename Param>
void suppressEmulatedDirectDraw(Param)
{
}
void suppressEmulatedDirectDraw(GUID*& guid)
{
DDraw::DirectDraw::suppressEmulatedDirectDraw(guid);
}
}
#define LOAD_ORIG_PROC(proc) \