From 07de716af9a4631bdedac8649b39d0891dc895b4 Mon Sep 17 00:00:00 2001 From: narzoul Date: Tue, 23 Apr 2019 12:44:13 +0200 Subject: [PATCH] Reworked oversized surface support --- DDrawCompat/Common/HResultException.h | 14 + DDrawCompat/D3dDdi/Adapter.h | 3 +- DDrawCompat/D3dDdi/Device.cpp | 139 ++------ DDrawCompat/D3dDdi/Device.h | 19 +- DDrawCompat/D3dDdi/KernelModeThunks.cpp | 17 +- DDrawCompat/D3dDdi/KernelModeThunks.h | 1 + DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp | 13 + DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h | 1 + .../D3dDdi/Log/KernelModeThunksLog.cpp | 1 + DDrawCompat/D3dDdi/OversizedResource.cpp | 91 ----- DDrawCompat/D3dDdi/OversizedResource.h | 28 -- DDrawCompat/D3dDdi/RenderTargetResource.cpp | 8 +- DDrawCompat/D3dDdi/Resource.cpp | 328 ++++++++++++++++++ DDrawCompat/D3dDdi/Resource.h | 56 +++ DDrawCompat/DDraw/RealPrimarySurface.cpp | 2 + DDrawCompat/DDrawCompat.vcxproj | 5 +- DDrawCompat/DDrawCompat.vcxproj.filters | 15 +- 17 files changed, 494 insertions(+), 247 deletions(-) create mode 100644 DDrawCompat/Common/HResultException.h delete mode 100644 DDrawCompat/D3dDdi/OversizedResource.cpp delete mode 100644 DDrawCompat/D3dDdi/OversizedResource.h create mode 100644 DDrawCompat/D3dDdi/Resource.cpp create mode 100644 DDrawCompat/D3dDdi/Resource.h diff --git a/DDrawCompat/Common/HResultException.h b/DDrawCompat/Common/HResultException.h new file mode 100644 index 0000000..9b51770 --- /dev/null +++ b/DDrawCompat/Common/HResultException.h @@ -0,0 +1,14 @@ +#pragma once + +typedef long HRESULT; + +class HResultException +{ +public: + HResultException(HRESULT result) : m_result(result) {} + + HRESULT getResult() const { return m_result; } + +private: + HRESULT m_result; +}; diff --git a/DDrawCompat/D3dDdi/Adapter.h b/DDrawCompat/D3dDdi/Adapter.h index bc6bd27..56f4f5b 100644 --- a/DDrawCompat/D3dDdi/Adapter.h +++ b/DDrawCompat/D3dDdi/Adapter.h @@ -13,8 +13,9 @@ namespace D3dDdi public: Adapter(HANDLE adapter, HMODULE module); + operator HANDLE() const { return m_adapter; } + const D3DNTHAL_D3DEXTENDEDCAPS& getD3dExtendedCaps() const { return m_d3dExtendedCaps; } - HANDLE getHandle() const { return m_adapter; } HMODULE getModule() const { return m_module; } static void add(HANDLE adapter, HMODULE module); diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp index 09519c1..99e3c95 100644 --- a/DDrawCompat/D3dDdi/Device.cpp +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -1,17 +1,16 @@ #include #include <../km/d3dkmthk.h> +#include "Common/HResultException.h" #include "D3dDdi/Adapter.h" #include "D3dDdi/Device.h" #include "D3dDdi/DeviceFuncs.h" #include "D3dDdi/KernelModeThunks.h" +#include "D3dDdi/Resource.h" #include "Gdi/AccessGuard.h" namespace { - D3DDDI_RESOURCEFLAGS getResourceTypeFlags(); - - const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; HANDLE g_gdiResourceHandle = nullptr; bool g_isReadOnlyGdiLockEnabled = false; @@ -35,37 +34,6 @@ namespace private: D3dDdi::Device & m_device; }; - - D3DDDI_RESOURCEFLAGS getResourceTypeFlags() - { - D3DDDI_RESOURCEFLAGS flags = {}; - flags.RenderTarget = 1; - flags.ZBuffer = 1; - flags.DMap = 1; - flags.Points = 1; - flags.RtPatches = 1; - flags.NPatches = 1; - flags.Video = 1; - flags.CaptureBuffer = 1; - flags.Primary = 1; - flags.Texture = 1; - flags.CubeMap = 1; - flags.VertexBuffer = 1; - flags.IndexBuffer = 1; - flags.DecodeRenderTarget = 1; - flags.DecodeCompressedBuffer = 1; - flags.VideoProcessRenderTarget = 1; - flags.Overlay = 1; - flags.TextApi = 1; - return flags; - } - - bool isVidMemPool(D3DDDI_POOL pool) - { - return D3DDDIPOOL_VIDEOMEMORY == pool || - D3DDDIPOOL_LOCALVIDMEM == pool || - D3DDDIPOOL_NONLOCALVIDMEM == pool; - } } namespace D3dDdi @@ -110,19 +78,11 @@ namespace D3dDdi { RenderGuard srcRenderGuard(*this, Gdi::ACCESS_READ, data.hSrcResource, data.SrcSubResourceIndex); RenderGuard dstRenderGuard(*this, Gdi::ACCESS_WRITE, data.hDstResource, data.DstSubResourceIndex); - - auto it = m_oversizedResources.find(data.hSrcResource); - if (it != m_oversizedResources.end()) + auto it = m_resources.find(data.hDstResource); + if (it != m_resources.end()) { - return it->second.bltFrom(data); + return it->second.blt(data); } - - it = m_oversizedResources.find(data.hDstResource); - if (it != m_oversizedResources.end()) - { - return it->second.bltTo(data); - } - return m_origVtable.pfnBlt(m_device, &data); } @@ -138,76 +98,29 @@ namespace D3dDdi return m_origVtable.pfnColorFill(m_device, &data); } - template - HRESULT Device::createOversizedResource( - CreateResourceArg& data, - CreateResourceFunc origCreateResource, - const D3DNTHAL_D3DEXTENDEDCAPS& caps) + template + HRESULT Device::createResourceImpl(Arg& data) { - D3DDDI_SURFACEINFO compatSurfaceInfo = data.pSurfList[0]; - if (0 != caps.dwMaxTextureWidth && compatSurfaceInfo.Width > caps.dwMaxTextureWidth) + try { - compatSurfaceInfo.Width = caps.dwMaxTextureWidth; + Resource resource(Resource::create(*this, data)); + m_resources.emplace(resource, resource); + return S_OK; } - if (0 != caps.dwMaxTextureHeight && compatSurfaceInfo.Height > caps.dwMaxTextureHeight) + catch (const HResultException& e) { - compatSurfaceInfo.Height = caps.dwMaxTextureHeight; + return e.getResult(); } - - const D3DDDI_SURFACEINFO* origSurfList = data.pSurfList; - data.pSurfList = &compatSurfaceInfo; - HRESULT result = origCreateResource(m_device, &data); - data.pSurfList = origSurfList; - - if (SUCCEEDED(result)) - { - m_oversizedResources.emplace(data.hResource, OversizedResource(*this, data.Format, origSurfList[0])); - } - - return result; - } - - template - HRESULT Device::createResourceImpl(CreateResourceArg& data, CreateResourceFunc origCreateResource) - { - const bool isOffScreenPlain = 0 == (data.Flags.Value & g_resourceTypeFlags); - if (D3DDDIPOOL_SYSTEMMEM == data.Pool && - (isOffScreenPlain || data.Flags.Texture) && - OversizedResource::isSupportedFormat(data.Format) && - 1 == data.SurfCount) - { - const auto& caps = m_adapter.getD3dExtendedCaps(); - const auto& surfaceInfo = data.pSurfList[0]; - if (0 != caps.dwMaxTextureWidth && surfaceInfo.Width > caps.dwMaxTextureWidth || - 0 != caps.dwMaxTextureHeight && surfaceInfo.Height > caps.dwMaxTextureHeight) - { - return createOversizedResource(data, origCreateResource, caps); - } - } - - if (data.Flags.Primary) - { - data.Format = D3DDDIFMT_X8R8G8B8; - } - - HRESULT result = origCreateResource(m_device, &data); - if (SUCCEEDED(result) && data.Flags.RenderTarget && !data.Flags.Primary && isVidMemPool(data.Pool)) - { - m_renderTargetResources.emplace(data.hResource, - RenderTargetResource(*this, data.hResource, data.Format, data.SurfCount)); - } - - return result; } HRESULT Device::createResource(D3DDDIARG_CREATERESOURCE& data) { - return createResourceImpl(data, m_origVtable.pfnCreateResource); + return createResourceImpl(data); } HRESULT Device::createResource2(D3DDDIARG_CREATERESOURCE2& data) { - return createResourceImpl(data, m_origVtable.pfnCreateResource2); + return createResourceImpl(data); } HRESULT Device::destroyResource(HANDLE resource) @@ -220,7 +133,7 @@ namespace D3dDdi HRESULT result = m_origVtable.pfnDestroyResource(m_device, resource); if (SUCCEEDED(result)) { - m_oversizedResources.erase(resource); + m_resources.erase(resource); m_renderTargetResources.erase(resource); m_lockedRenderTargetResources.erase(resource); @@ -292,6 +205,13 @@ namespace D3dDdi } return result; } + + auto resourceIter = m_resources.find(data.hResource); + if (resourceIter != m_resources.end()) + { + return resourceIter->second.lock(data); + } + return m_origVtable.pfnLock(m_device, &data); } @@ -351,6 +271,13 @@ namespace D3dDdi { return it->second.unlock(data); } + + auto resourceIter = m_resources.find(data.hResource); + if (resourceIter != m_resources.end()) + { + return resourceIter->second.unlock(data); + } + return m_origVtable.pfnUnlock(m_device, &data); } @@ -366,6 +293,12 @@ namespace D3dDdi return m_origVtable.pfnUpdateWInfo(m_device, &data); } + void Device::addRenderTargetResource(const D3DDDIARG_CREATERESOURCE& data) + { + m_renderTargetResources.emplace(data.hResource, + RenderTargetResource(*this, data.hResource, data.Format, data.SurfCount)); + } + void Device::prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex) { resource.prepareForRendering(subResourceIndex); diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h index 45e4786..8904e46 100644 --- a/DDrawCompat/D3dDdi/Device.h +++ b/DDrawCompat/D3dDdi/Device.h @@ -6,7 +6,6 @@ #include #include -#include "D3dDdi/OversizedResource.h" #include "D3dDdi/RenderTargetResource.h" namespace D3dDdi @@ -14,10 +13,13 @@ namespace D3dDdi UINT getBytesPerPixel(D3DDDIFORMAT format); class Adapter; + class Resource; class Device { public: + operator HANDLE() const { return m_device; } + HRESULT blt(const D3DDDIARG_BLT& data); HRESULT clear(const D3DDDIARG_CLEAR& data, UINT numRect, const RECT* rect); HRESULT colorFill(const D3DDDIARG_COLORFILL& data); @@ -43,9 +45,10 @@ namespace D3dDdi HRESULT updateWInfo(const D3DDDIARG_WINFO& data); Adapter& getAdapter() const { return m_adapter; } - HANDLE getHandle() const { return m_device; } const D3DDDI_DEVICEFUNCS& getOrigVtable() const { return m_origVtable; } + std::map& getResources() { return m_resources; } + void addRenderTargetResource(const D3DDDIARG_CREATERESOURCE& data); void prepareForRendering(HANDLE resource, UINT subResourceIndex = UINT_MAX); void prepareForRendering(); @@ -59,21 +62,15 @@ namespace D3dDdi private: Device(HANDLE adapter, HANDLE device); - template - HRESULT createOversizedResource( - CreateResourceArg& data, - CreateResourceFunc origCreateResource, - const D3DNTHAL_D3DEXTENDEDCAPS& caps); - - template - HRESULT createResourceImpl(CreateResourceArg& data, CreateResourceFunc origCreateResource); + template + HRESULT createResourceImpl(Arg& data); void prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex = UINT_MAX); const D3DDDI_DEVICEFUNCS& m_origVtable; Adapter& m_adapter; HANDLE m_device; - std::map m_oversizedResources; + std::map m_resources; std::map m_renderTargetResources; std::map m_lockedRenderTargetResources; HANDLE m_sharedPrimary; diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index 4b335e8..1b78a2b 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -33,6 +33,7 @@ namespace }; std::map g_contexts; + D3DDDIFORMAT g_dcFormatOverride = D3DDDIFMT_UNKNOWN; AdapterInfo g_gdiAdapterInfo = {}; AdapterInfo g_lastOpenAdapterInfo = {}; std::string g_lastDDrawCreateDcDevice; @@ -80,8 +81,15 @@ namespace NTSTATUS APIENTRY createDcFromMemory(D3DKMT_CREATEDCFROMMEMORY* pData) { LOG_FUNC("D3DKMTCreateDCFromMemory", pData); + + auto origFormat = pData->Format; + if (D3DDDIFMT_UNKNOWN != g_dcFormatOverride) + { + pData->Format = g_dcFormatOverride; + } + NTSTATUS result = 0; - if (pData && D3DDDIFMT_P8 == pData->Format && !pData->pColorTable && + if (D3DDDIFMT_P8 == pData->Format && !pData->pColorTable && DDraw::PrimarySurface::s_palette) { pData->pColorTable = DDraw::PrimarySurface::s_paletteEntries; @@ -92,6 +100,8 @@ namespace { result = CALL_ORIG_FUNC(D3DKMTCreateDCFromMemory)(pData); } + + pData->Format = origFormat; return LOG_RESULT(result); } @@ -350,6 +360,11 @@ namespace D3dDdi g_flipIntervalOverride = flipInterval; } + void setDcFormatOverride(UINT format) + { + g_dcFormatOverride = static_cast(format); + } + void waitForVerticalBlank() { D3DKMT_WAITFORVERTICALBLANKEVENT data = {}; diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.h b/DDrawCompat/D3dDdi/KernelModeThunks.h index dfd91eb..5dd5673 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.h +++ b/DDrawCompat/D3dDdi/KernelModeThunks.h @@ -15,6 +15,7 @@ namespace D3dDdi long long getQpcLastVerticalBlank(); void installHooks(HMODULE origDDrawModule); void setFlipIntervalOverride(UINT flipInterval); + void setDcFormatOverride(UINT format); void waitForVerticalBlank(); } } diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp index c45a69c..e659287 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp @@ -19,6 +19,19 @@ std::ostream& operator<<(std::ostream& os, const D3DDDI_SURFACEINFO& val) << val.SysMemSlicePitch; } +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_BLT& val) +{ + return Compat::LogStruct(os) + << val.hSrcResource + << val.SrcSubResourceIndex + << val.SrcRect + << val.hDstResource + << val.DstSubResourceIndex + << val.DstRect + << Compat::hex(val.ColorKey) + << Compat::hex(val.Flags.Value); +} + std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CLEAR& val) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h index e4fb17e..10835a9 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h @@ -7,6 +7,7 @@ std::ostream& operator<<(std::ostream& os, const D3DDDI_RATIONAL& val); std::ostream& operator<<(std::ostream& os, const D3DDDI_SURFACEINFO& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_BLT& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CLEAR& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_COLORFILL& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATERESOURCE& val); diff --git a/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp b/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp index 47a2eb9..4dddd6e 100644 --- a/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp +++ b/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp @@ -45,6 +45,7 @@ std::ostream& operator<<(std::ostream& os, const D3DKMT_CREATEDCFROMMEMORY& data { return Compat::LogStruct(os) << data.pMemory + << data.Format << data.Width << data.Height << data.Pitch diff --git a/DDrawCompat/D3dDdi/OversizedResource.cpp b/DDrawCompat/D3dDdi/OversizedResource.cpp deleted file mode 100644 index 058e9cb..0000000 --- a/DDrawCompat/D3dDdi/OversizedResource.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "D3dDdi/Adapter.h" -#include "D3dDdi/Device.h" -#include "D3dDdi/OversizedResource.h" - -namespace D3dDdi -{ - OversizedResource::OversizedResource(Device& device, D3DDDIFORMAT format, const D3DDDI_SURFACEINFO& surfaceInfo) - : m_device(device) - , m_format(format) - , m_surfaceInfo(surfaceInfo) - { - } - - HRESULT OversizedResource::blt(D3DDDIARG_BLT& data, HANDLE& resource, RECT& rect) - { - const auto& caps = m_device.getAdapter().getD3dExtendedCaps(); - if (rect.right <= static_cast(caps.dwMaxTextureWidth) && - rect.bottom <= static_cast(caps.dwMaxTextureHeight)) - { - return m_device.getOrigVtable().pfnBlt(m_device.getHandle(), &data); - } - - HANDLE origResource = resource; - RECT origRect = rect; - HANDLE bltResource = createBltResource(rect); - - if (bltResource) - { - resource = bltResource; - rect = RECT{ 0, 0, rect.right - rect.left, rect.bottom - rect.top }; - } - - HRESULT result = m_device.getOrigVtable().pfnBlt(m_device.getHandle(), &data); - - if (bltResource) - { - resource = origResource; - rect = origRect; - m_device.getOrigVtable().pfnDestroyResource(m_device.getHandle(), bltResource); - } - - return result; - } - - HRESULT OversizedResource::bltFrom(D3DDDIARG_BLT data) - { - return blt(data, data.hSrcResource, data.SrcRect); - } - - HRESULT OversizedResource::bltTo(D3DDDIARG_BLT data) - { - return blt(data, data.hDstResource, data.DstRect); - } - - HANDLE OversizedResource::createBltResource(RECT bltRect) - { - const RECT surfaceRect = { - 0, 0, static_cast(m_surfaceInfo.Width), static_cast(m_surfaceInfo.Height) }; - IntersectRect(&bltRect, &surfaceRect, &bltRect); - - D3DDDI_SURFACEINFO bltSurfaceInfo = {}; - bltSurfaceInfo.Width = bltRect.right - bltRect.left; - bltSurfaceInfo.Height = bltRect.bottom - bltRect.top; - bltSurfaceInfo.pSysMem = static_cast(m_surfaceInfo.pSysMem) + - bltRect.top * m_surfaceInfo.SysMemPitch + - bltRect.left * getBytesPerPixel(m_format); - bltSurfaceInfo.SysMemPitch = m_surfaceInfo.SysMemPitch; - - D3DDDIARG_CREATERESOURCE2 bltResourceData = {}; - bltResourceData.Format = m_format; - bltResourceData.Pool = D3DDDIPOOL_SYSTEMMEM; - bltResourceData.pSurfList = &bltSurfaceInfo; - bltResourceData.SurfCount = 1; - - if (m_device.getOrigVtable().pfnCreateResource2) - { - m_device.getOrigVtable().pfnCreateResource2(m_device.getHandle(), &bltResourceData); - } - else - { - m_device.getOrigVtable().pfnCreateResource(m_device.getHandle(), - reinterpret_cast(&bltResourceData)); - } - return bltResourceData.hResource; - } - - bool OversizedResource::isSupportedFormat(D3DDDIFORMAT format) - { - return 0 != getBytesPerPixel(format); - } -} diff --git a/DDrawCompat/D3dDdi/OversizedResource.h b/DDrawCompat/D3dDdi/OversizedResource.h deleted file mode 100644 index 6748a30..0000000 --- a/DDrawCompat/D3dDdi/OversizedResource.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include - -namespace D3dDdi -{ - class Device; - - class OversizedResource - { - public: - OversizedResource(Device& device, D3DDDIFORMAT format, const D3DDDI_SURFACEINFO& surfaceInfo); - - HRESULT bltFrom(D3DDDIARG_BLT data); - HRESULT bltTo(D3DDDIARG_BLT data); - - static bool isSupportedFormat(D3DDDIFORMAT format); - - private: - HRESULT blt(D3DDDIARG_BLT& data, HANDLE& resource, RECT& rect); - HANDLE createBltResource(RECT bltRect); - - Device& m_device; - D3DDDIFORMAT m_format; - D3DDDI_SURFACEINFO m_surfaceInfo; - }; -} diff --git a/DDrawCompat/D3dDdi/RenderTargetResource.cpp b/DDrawCompat/D3dDdi/RenderTargetResource.cpp index f458bae..91390d6 100644 --- a/DDrawCompat/D3dDdi/RenderTargetResource.cpp +++ b/DDrawCompat/D3dDdi/RenderTargetResource.cpp @@ -15,7 +15,7 @@ namespace D3dDdi { if (data.SubResourceIndex >= m_subResources.size()) { - return m_device.getOrigVtable().pfnLock(m_device.getHandle(), &data); + return m_device.getOrigVtable().pfnLock(m_device, &data); } auto& subResource = m_subResources[data.SubResourceIndex]; @@ -34,7 +34,7 @@ namespace D3dDdi const UINT origFlags = data.Flags.Value; data.Flags.Value = 0; - const HRESULT result = m_device.getOrigVtable().pfnLock(m_device.getHandle(), &data); + const HRESULT result = m_device.getOrigVtable().pfnLock(m_device, &data); data.Flags.Value = origFlags; if (SUCCEEDED(result)) @@ -52,7 +52,7 @@ namespace D3dDdi { if (data.SubResourceIndex >= m_subResources.size()) { - return m_device.getOrigVtable().pfnUnlock(m_device.getHandle(), &data); + return m_device.getOrigVtable().pfnUnlock(m_device, &data); } m_subResources[data.SubResourceIndex].isLocked = false; @@ -86,7 +86,7 @@ namespace D3dDdi D3DDDIARG_UNLOCK data = {}; data.hResource = m_resource; data.SubResourceIndex = subResourceIndex; - m_device.getOrigVtable().pfnUnlock(m_device.getHandle(), &data); + m_device.getOrigVtable().pfnUnlock(m_device, &data); subResource.surfacePtr = nullptr; subResource.pitch = 0; diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp new file mode 100644 index 0000000..69f2733 --- /dev/null +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -0,0 +1,328 @@ +#include + +#include "Common/HResultException.h" +#include "Common/Log.h" +#include "D3dDdi/Adapter.h" +#include "D3dDdi/Device.h" +#include "D3dDdi/Log/DeviceFuncsLog.h" +#include "D3dDdi/Resource.h" + +namespace +{ + D3DDDI_RESOURCEFLAGS getResourceTypeFlags(); + bool isVidMemPool(D3DDDI_POOL pool); + void splitToTiles(D3DDDIARG_CREATERESOURCE& data, const UINT tileWidth, const UINT tileHeight); + + const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; + + LONG divCeil(LONG n, LONG d) + { + return (n + d - 1) / d; + } + + void fixResourceData(D3dDdi::Device& device, D3DDDIARG_CREATERESOURCE& data) + { + if (data.Flags.Primary) + { + data.Format = D3DDDIFMT_X8R8G8B8; + } + + const bool isOffScreenPlain = 0 == (data.Flags.Value & g_resourceTypeFlags); + if (D3DDDIPOOL_SYSTEMMEM == data.Pool && + (isOffScreenPlain || data.Flags.Texture) && + 1 == data.SurfCount && + 0 == data.pSurfList[0].Depth && + 0 != D3dDdi::getBytesPerPixel(data.Format)) + { + const auto& caps = device.getAdapter().getD3dExtendedCaps(); + const auto& surfaceInfo = data.pSurfList[0]; + if (0 != caps.dwMaxTextureWidth && surfaceInfo.Width > caps.dwMaxTextureWidth || + 0 != caps.dwMaxTextureHeight && surfaceInfo.Height > caps.dwMaxTextureHeight) + { + splitToTiles(data, caps.dwMaxTextureWidth, caps.dwMaxTextureHeight); + } + } + } + + D3DDDI_RESOURCEFLAGS getResourceTypeFlags() + { + D3DDDI_RESOURCEFLAGS flags = {}; + flags.RenderTarget = 1; + flags.ZBuffer = 1; + flags.DMap = 1; + flags.Points = 1; + flags.RtPatches = 1; + flags.NPatches = 1; + flags.Video = 1; + flags.CaptureBuffer = 1; + flags.Primary = 1; + flags.Texture = 1; + flags.CubeMap = 1; + flags.VertexBuffer = 1; + flags.IndexBuffer = 1; + flags.DecodeRenderTarget = 1; + flags.DecodeCompressedBuffer = 1; + flags.VideoProcessRenderTarget = 1; + flags.Overlay = 1; + flags.TextApi = 1; + return flags; + } + + bool isVidMemPool(D3DDDI_POOL pool) + { + return D3DDDIPOOL_VIDEOMEMORY == pool || + D3DDDIPOOL_LOCALVIDMEM == pool || + D3DDDIPOOL_NONLOCALVIDMEM == pool; + } + + void splitToTiles(D3DDDIARG_CREATERESOURCE& data, const UINT tileWidth, const UINT tileHeight) + { + static std::vector tiles; + tiles.clear(); + + const UINT bytesPerPixel = D3dDdi::getBytesPerPixel(data.Format); + + for (UINT y = 0; y < data.pSurfList[0].Height; y += tileHeight) + { + for (UINT x = 0; x < data.pSurfList[0].Width; x += tileWidth) + { + D3DDDI_SURFACEINFO tile = {}; + tile.Width = min(data.pSurfList[0].Width - x, tileWidth); + tile.Height = min(data.pSurfList[0].Height - y, tileHeight); + tile.pSysMem = static_cast(data.pSurfList[0].pSysMem) + + y * data.pSurfList[0].SysMemPitch + x * bytesPerPixel; + tile.SysMemPitch = data.pSurfList[0].SysMemPitch; + tiles.push_back(tile); + } + } + + data.SurfCount = tiles.size(); + 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) + { + surfaceData.reserve(data.SurfCount); + for (UINT i = 0; i < data.SurfCount; ++i) + { + surfaceData.push_back(data.pSurfList[i]); + } + pSurfList = surfaceData.data(); + } + + Resource::Data::Data(const Data& other) + : D3DDDIARG_CREATERESOURCE2(other) + , surfaceData(other.surfaceData) + { + pSurfList = surfaceData.data(); + } + + Resource::Data& Resource::Data::operator=(const Data& other) + { + static_cast(*this) = other; + surfaceData = other.surfaceData; + pSurfList = surfaceData.data(); + return *this; + } + + Resource::Resource(Device& device, const D3DDDIARG_CREATERESOURCE& data) + : Resource(device, upgradeResourceData(data)) + { + } + + Resource::Resource(Device& device, const D3DDDIARG_CREATERESOURCE2& data) + : m_device(device) + , m_handle(nullptr) + , m_origData(data) + { + } + + HRESULT Resource::blt(D3DDDIARG_BLT data) + { + if (isOversized()) + { + return splitBlt(data, data.DstSubResourceIndex, data.DstRect, data.SrcRect); + } + else + { + auto& resources = m_device.getResources(); + auto it = resources.find(data.hSrcResource); + if (it != resources.end() && it->second.isOversized()) + { + return it->second.splitBlt(data, data.SrcSubResourceIndex, data.SrcRect, data.DstRect); + } + } + return m_device.getOrigVtable().pfnBlt(m_device, &data); + } + + template + Resource Resource::create(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*)) + { + Resource resource(device, data); + Arg origData = data; + auto& baseData = reinterpret_cast(data); + fixResourceData(device, baseData); + resource.m_fixedData = data; + + HRESULT result = createResourceFunc(device, &data); + if (FAILED(result)) + { + data = origData; + throw HResultException(result); + } + + if (data.Flags.RenderTarget && !data.Flags.Primary && isVidMemPool(data.Pool)) + { + device.addRenderTargetResource(baseData); + } + + resource.m_handle = data.hResource; + data = origData; + data.hResource = resource.m_handle; + return resource; + } + + Resource Resource::create(Device& device, D3DDDIARG_CREATERESOURCE& data) + { + return create(device, data, device.getOrigVtable().pfnCreateResource); + } + + Resource Resource::create(Device& device, D3DDDIARG_CREATERESOURCE2& data) + { + return create(device, data, device.getOrigVtable().pfnCreateResource2); + } + + bool Resource::isOversized() const + { + return m_fixedData.SurfCount != m_origData.SurfCount; + } + + HRESULT Resource::lock(D3DDDIARG_LOCK& data) + { + if (isOversized()) + { + if (0 != data.SubResourceIndex || + data.Flags.RangeValid || data.Flags.AreaValid || data.Flags.BoxValid) + { + LOG_ONCE("WARNING: Unsupported lock of oversized resource: " << data); + return m_device.getOrigVtable().pfnLock(m_device, &data); + } + return splitLock(data, m_device.getOrigVtable().pfnLock); + } + return m_device.getOrigVtable().pfnLock(m_device, &data); + } + + HRESULT Resource::splitBlt(D3DDDIARG_BLT& data, UINT& subResourceIndex, RECT& rect, RECT& otherRect) + { + LOG_FUNC("Resource::splitBlt", data, subResourceIndex, rect, otherRect); + + if (0 != subResourceIndex || + data.SrcRect.right - data.SrcRect.left != data.DstRect.right - data.DstRect.left || + data.SrcRect.bottom - data.SrcRect.top != data.DstRect.bottom - data.DstRect.top || + data.Flags.MirrorLeftRight || + data.Flags.MirrorUpDown || + data.Flags.Rotate) + { + LOG_ONCE("WARNING: Unsupported blt of oversized resource: " << data); + return LOG_RESULT(m_device.getOrigVtable().pfnBlt(m_device, &data)); + } + + const auto& caps = m_device.getAdapter().getD3dExtendedCaps(); + const auto tilesPerRow = divCeil(m_origData.pSurfList[0].Width, caps.dwMaxTextureWidth); + + const RECT origRect = rect; + const POINT otherRectOffset = { otherRect.left - rect.left, otherRect.top - rect.top }; + + POINT tilePos = {}; + tilePos.y = rect.top / static_cast(caps.dwMaxTextureHeight); + + RECT tileRect = {}; + tileRect.top = tilePos.y * caps.dwMaxTextureHeight; + tileRect.bottom = tileRect.top + caps.dwMaxTextureHeight; + + while (tileRect.top < origRect.bottom) + { + tilePos.x = origRect.left / static_cast(caps.dwMaxTextureWidth); + tileRect.left = tilePos.x * caps.dwMaxTextureWidth; + tileRect.right = tileRect.left + caps.dwMaxTextureWidth; + + while (tileRect.left < origRect.right) + { + IntersectRect(&rect, &tileRect, &origRect); + otherRect = rect; + OffsetRect(&otherRect, otherRectOffset.x, otherRectOffset.y); + OffsetRect(&rect, -tileRect.left, -tileRect.top); + subResourceIndex = tilePos.y * tilesPerRow + tilePos.x; + + HRESULT result = m_device.getOrigVtable().pfnBlt(m_device, &data); + if (FAILED(result)) + { + return LOG_RESULT(result); + } + + ++tilePos.x; + tileRect.left += caps.dwMaxTextureWidth; + tileRect.right += caps.dwMaxTextureWidth; + } + + ++tilePos.y; + tileRect.top += caps.dwMaxTextureHeight; + tileRect.bottom += caps.dwMaxTextureHeight; + } + + return LOG_RESULT(S_OK); + } + + template + HRESULT Resource::splitLock(Arg& data, HRESULT(APIENTRY *lockFunc)(HANDLE, Arg*)) + { + LOG_FUNC("Resource::splitLock", data, lockFunc); + std::remove_const::type tmpData = data; + HRESULT result = lockFunc(m_device, &data); + if (SUCCEEDED(result)) + { + for (UINT i = 1; i < m_fixedData.SurfCount; ++i) + { + tmpData.SubResourceIndex = i; + lockFunc(m_device, &tmpData); + } + } + return LOG_RESULT(result); + } + + HRESULT Resource::unlock(const D3DDDIARG_UNLOCK& data) + { + if (isOversized()) + { + if (0 != data.SubResourceIndex) + { + LOG_ONCE("WARNING: Unsupported unlock of oversized resource: " << data); + return m_device.getOrigVtable().pfnUnlock(m_device, &data); + } + return splitLock(data, m_device.getOrigVtable().pfnUnlock); + } + return m_device.getOrigVtable().pfnUnlock(m_device, &data); + } +} diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h new file mode 100644 index 0000000..586407d --- /dev/null +++ b/DDrawCompat/D3dDdi/Resource.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include +#include + +namespace D3dDdi +{ + class Device; + + class Resource + { + public: + static Resource create(Device& device, D3DDDIARG_CREATERESOURCE& data); + static Resource create(Device& device, D3DDDIARG_CREATERESOURCE2& data); + + operator HANDLE() const { return m_handle; } + + HRESULT blt(D3DDDIARG_BLT data); + HRESULT lock(D3DDDIARG_LOCK& data); + HRESULT unlock(const D3DDDIARG_UNLOCK& data); + + private: + class Data : public D3DDDIARG_CREATERESOURCE2 + { + public: + Data(); + Data(const D3DDDIARG_CREATERESOURCE& data); + Data(const D3DDDIARG_CREATERESOURCE2& data); + Data(const Data& other); + Data& operator=(const Data& other); + Data(Data&&) = default; + Data& operator=(Data&&) = default; + + std::vector surfaceData; + }; + + Resource(Device& device, const D3DDDIARG_CREATERESOURCE& data); + Resource(Device& device, const D3DDDIARG_CREATERESOURCE2& data); + + template + static Resource create(Device& device, Arg& data, HRESULT(APIENTRY *createResourceFunc)(HANDLE, Arg*)); + + bool isOversized() const; + HRESULT splitBlt(D3DDDIARG_BLT& data, UINT& subResourceIndex, RECT& rect, RECT& otherRect); + + template + HRESULT splitLock(Arg& data, HRESULT(APIENTRY *lockFunc)(HANDLE, Arg*)); + + Device& m_device; + HANDLE m_handle; + Data m_origData; + Data m_fixedData; + }; +} diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 179e7c7..318ad5d 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -123,7 +123,9 @@ namespace if (!backBufferDc) { + D3dDdi::KernelModeThunks::setDcFormatOverride(D3DDDIFMT_X8R8G8B8); backBuffer->GetDC(backBuffer, &backBufferDc); + D3dDdi::KernelModeThunks::setDcFormatOverride(D3DDDIFMT_UNKNOWN); if (!backBufferDc) { return; diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 7cae2ab..e5bc865 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -234,6 +234,7 @@ + @@ -256,8 +257,8 @@ - + @@ -333,8 +334,8 @@ - + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 4d6fe36..2e958a4 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -285,9 +285,6 @@ Header Files\D3dDdi\Log - - Header Files\D3dDdi - Header Files\DDraw\Visitors @@ -348,6 +345,12 @@ Header Files\D3dDdi + + Header Files\D3dDdi + + + Header Files\Common + @@ -491,9 +494,6 @@ Source Files\D3dDdi\Log - - Source Files\D3dDdi - Source Files\DDraw @@ -530,6 +530,9 @@ Source Files\D3dDdi + + Source Files\D3dDdi +