From 62983b19fe682af11d7997cfdaef9078e724a68f Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 5 Jun 2021 17:29:51 +0200 Subject: [PATCH] Create helper surfaces via DirectDraw runtime --- DDrawCompat/Common/Comparison.h | 23 +++ DDrawCompat/D3dDdi/Adapter.cpp | 16 +++ DDrawCompat/D3dDdi/Adapter.h | 9 ++ DDrawCompat/D3dDdi/Device.cpp | 178 +++++------------------- DDrawCompat/D3dDdi/Device.h | 8 -- DDrawCompat/D3dDdi/KernelModeThunks.cpp | 44 ++++-- DDrawCompat/D3dDdi/KernelModeThunks.h | 14 +- DDrawCompat/D3dDdi/Resource.cpp | 49 +------ DDrawCompat/D3dDdi/Resource.h | 6 - DDrawCompat/D3dDdi/ShaderBlitter.cpp | 100 ++++++++----- DDrawCompat/D3dDdi/ShaderBlitter.h | 7 +- DDrawCompat/DDraw/DirectDraw.cpp | 135 ++++++++++++++++-- DDrawCompat/DDraw/DirectDraw.h | 8 ++ DDrawCompat/DDraw/Hooks.cpp | 18 +++ DDrawCompat/DDrawCompat.vcxproj | 1 + DDrawCompat/DDrawCompat.vcxproj.filters | 3 + DDrawCompat/Dll/DllMain.cpp | 39 ++++-- 17 files changed, 378 insertions(+), 280 deletions(-) create mode 100644 DDrawCompat/Common/Comparison.h diff --git a/DDrawCompat/Common/Comparison.h b/DDrawCompat/Common/Comparison.h new file mode 100644 index 0000000..d5749cc --- /dev/null +++ b/DDrawCompat/Common/Comparison.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include + +template +std::enable_if_t && std::is_trivial_v, bool> operator==(const T& left, const T& right) +{ + return toTuple(left) == toTuple(right); +} + +template +std::enable_if_t && std::is_trivial_v, 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); +} diff --git a/DDrawCompat/D3dDdi/Adapter.cpp b/DDrawCompat/D3dDdi/Adapter.cpp index 41d8b87..53e04da 100644 --- a/DDrawCompat/D3dDdi/Adapter.cpp +++ b/DDrawCompat/D3dDdi/Adapter.cpp @@ -1,9 +1,11 @@ +#include #include #include #include #include #include #include +#include namespace { @@ -30,7 +32,10 @@ namespace D3dDdi , m_origVtable(CompatVtable::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 Adapter::s_adapters; } diff --git a/DDrawCompat/D3dDdi/Adapter.h b/DDrawCompat/D3dDdi/Adapter.h index f72b610..98aa63b 100644 --- a/DDrawCompat/D3dDdi/Adapter.h +++ b/DDrawCompat/D3dDdi/Adapter.h @@ -6,6 +6,9 @@ #include #include +#include +#include + 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 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; diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index 7ee67ec..de2e8d2 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -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::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> 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> 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(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(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(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(&data)); - } - template - HRESULT Device::createResourceImpl(Arg& data) - { - try + HRESULT result = m_origVtable.pfnCreateResource2 + ? m_origVtable.pfnCreateResource2(m_device, &data) + : m_origVtable.pfnCreateResource(m_device, reinterpret_cast(&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(const_cast(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(const_cast(data->pSurfList[0].pSysMem))); + } + return S_OK; + } + catch (const HResultException& e) + { + return e.getResult(); + } } HRESULT Device::pfnDestroyDevice() diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h index 709e010..e3f2ac4 100644 --- a/DDrawCompat/D3dDdi/Device.h +++ b/DDrawCompat/D3dDdi/Device.h @@ -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 - 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 s_devices; static bool s_isFlushEnabled; diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index fe5bd2c..c84c541 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -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(&adapterInfo.monitorRect)); @@ -277,6 +281,20 @@ namespace D3dDdi { namespace KernelModeThunks { + AdapterInfo getAdapterInfo(CompatRef 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() diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.h b/DDrawCompat/D3dDdi/KernelModeThunks.h index 02361b8..3e11721 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.h +++ b/DDrawCompat/D3dDdi/KernelModeThunks.h @@ -1,11 +1,23 @@ #pragma once -#include +#include + +#include namespace D3dDdi { namespace KernelModeThunks { + struct AdapterInfo + { + UINT adapter; + UINT vidPnSourceId; + LUID luid; + RECT monitorRect; + }; + + AdapterInfo getAdapterInfo(CompatRef dd); + AdapterInfo getLastOpenAdapterInfo(); RECT getMonitorRect(); long long getQpcLastVsync(); UINT getVsyncCounter(); diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index ed8e7a4..a846af8 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -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(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 - 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(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(&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; diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index 31190f5..ef7a453 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -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 - 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); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index 2f39cd5..7fb1780 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -1,44 +1,62 @@ +#include + +#include #include +#include #include #include #include +#include #include #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> g_paletteTextures; + + CompatWeakPtr getPaletteTexture(CompatWeakPtr 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 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(dstResource), dstSubResourceIndex, + static_cast(srcResource), Compat::array(reinterpret_cast(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(dstSurface.Width), static_cast(dstSurface.Height) }; const RECT srcRect = { 0, 0, static_cast(srcSurface.Width), static_cast(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); } } diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h index b5df97b..40ceef8 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.h +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -1,6 +1,8 @@ #pragma once -#include +#include + +#include 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 m_paletteTexture; HANDLE m_psPaletteLookup; HANDLE m_vertexShaderDecl; }; diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index 4394a83..385841a 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -1,7 +1,10 @@ -#include +#include +#include +#include #include #include +#include #include #include #include @@ -11,9 +14,106 @@ namespace { - void logComInstantiation() + void logSrcColorKeySupportFailure(const char* reason, UINT32 resultCode); + + bool checkSrcColorKeySupport(CompatRef 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 src; + HRESULT result = dd->CreateSurface(&dd, &desc, &src.getRef(), nullptr); + if (FAILED(result)) + { + logSrcColorKeySupportFailure("error creating source surface", result); + return false; + } + + CompatPtr 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(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(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(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 @@ -60,14 +160,6 @@ namespace return DD_OK; } - template - HRESULT STDMETHODCALLTYPE Initialize(TDirectDraw* This, GUID* lpGUID) - { - logComInstantiation(); - DDraw::DirectDraw::suppressEmulatedDirectDraw(lpGUID); - return getOrigVtable(This).Initialize(This, lpGUID); - } - template 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 || std::is_same_v) @@ -166,6 +257,26 @@ namespace DDraw return pf; } + void onCreate(GUID* guid, CompatRef dd) + { + static std::map repositories; + auto adapterInfo = D3dDdi::KernelModeThunks::getAdapterInfo(dd); + auto it = repositories.find(adapterInfo.luid); + if (it == repositories.end()) + { + CompatPtr repo; + CALL_ORIG_PROC(DirectDrawCreateEx)(guid, reinterpret_cast(&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(DDCREATE_EMULATIONONLY) == guid) diff --git a/DDrawCompat/DDraw/DirectDraw.h b/DDrawCompat/DDraw/DirectDraw.h index 83bef9d..bff928e 100644 --- a/DDrawCompat/DDraw/DirectDraw.h +++ b/DDrawCompat/DDraw/DirectDraw.h @@ -2,14 +2,22 @@ #include +#include #include namespace DDraw { namespace DirectDraw { + struct Repository + { + CompatWeakPtr repo; + bool isSrcColorKeySupported; + }; + DDSURFACEDESC2 getDisplayMode(CompatRef dd); DDPIXELFORMAT getRgbPixelFormat(DWORD bpp); + void onCreate(GUID* guid, CompatRef dd); void suppressEmulatedDirectDraw(GUID*& guid); template diff --git a/DDrawCompat/DDraw/Hooks.cpp b/DDrawCompat/DDraw/Hooks.cpp index e5e1a3e..e7ed633 100644 --- a/DDrawCompat/DDraw/Hooks.cpp +++ b/DDrawCompat/DDraw/Hooks.cpp @@ -12,6 +12,8 @@ namespace { + decltype(IDirectDraw7Vtbl::Initialize) g_origInitialize = nullptr; + void hookDirectDraw(CompatPtr dd) { DDraw::DirectDraw::hookVtable(*CompatPtr(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(This), lpGUID); + if (SUCCEEDED(result)) + { + DDraw::DirectDraw::onCreate(lpGUID, *CompatPtr::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(g_origInitialize), initialize, "IDirectDrawVtbl::Initialize"); + hookDirectDraw(dd7); hookDirectDrawClipper(*dd7); hookDirectDrawPalette(*dd7); diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 870d212..1ffa9c1 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -191,6 +191,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index b0c847e..46a9c65 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -423,6 +423,9 @@ Header Files\D3dDdi + + Header Files\Common + diff --git a/DDrawCompat/Dll/DllMain.cpp b/DDrawCompat/Dll/DllMain.cpp index bc23ad7..62d3088 100644 --- a/DDrawCompat/Dll/DllMain.cpp +++ b/DDrawCompat/Dll/DllMain.cpp @@ -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 HRESULT WINAPI directDrawFunc(FirstParam firstParam, Params... params) { - LOG_FUNC(getFuncName(), firstParam, params...); + LOG_FUNC(getFuncName(), params...); installHooks(); - suppressEmulatedDirectDraw(firstParam); - return LOG_RESULT(reinterpret_cast(Dll::g_origProcs.*origFunc)(firstParam, params...)); + if constexpr (&Dll::Procs::DirectDrawCreate == origFunc || &Dll::Procs::DirectDrawCreateEx == origFunc) + { + DDraw::DirectDraw::suppressEmulatedDirectDraw(firstParam); + } + HRESULT result = reinterpret_cast(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::from(*lplpDD)); + } + + void onDirectDrawCreate(GUID* lpGUID, LPVOID* lplpDD, REFIID /*iid*/, IUnknown* /*pUnkOuter*/) + { + return DDraw::DirectDraw::onCreate(lpGUID, *CompatPtr::from(static_cast(*lplpDD))); + } + void printEnvironmentVariable(const char* var) { Compat::Log() << "Environment variable " << var << " = \"" << Dll::getEnvVar(var) << '"'; @@ -128,16 +151,6 @@ namespace } SetProcessDPIAware(); } - - template - void suppressEmulatedDirectDraw(Param) - { - } - - void suppressEmulatedDirectDraw(GUID*& guid) - { - DDraw::DirectDraw::suppressEmulatedDirectDraw(guid); - } } #define LOAD_ORIG_PROC(proc) \