From 39d148e3ba1c4e46fbd890b95f3c2800afbaebf5 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 3 Feb 2018 17:02:32 +0100 Subject: [PATCH] Aggregate render target locks --- DDrawCompat/D3dDdi/Device.cpp | 347 +++++++++++++++ DDrawCompat/D3dDdi/Device.h | 71 +++ DDrawCompat/D3dDdi/DeviceFuncs.cpp | 454 ++------------------ DDrawCompat/D3dDdi/LockResource.cpp | 73 ---- DDrawCompat/D3dDdi/LockResource.h | 50 --- DDrawCompat/D3dDdi/OversizedResource.cpp | 35 +- DDrawCompat/D3dDdi/OversizedResource.h | 1 - DDrawCompat/D3dDdi/RenderTargetResource.cpp | 106 +++++ DDrawCompat/D3dDdi/RenderTargetResource.h | 44 ++ DDrawCompat/DDrawCompat.vcxproj | 6 +- DDrawCompat/DDrawCompat.vcxproj.filters | 18 +- 11 files changed, 620 insertions(+), 585 deletions(-) create mode 100644 DDrawCompat/D3dDdi/Device.cpp create mode 100644 DDrawCompat/D3dDdi/Device.h delete mode 100644 DDrawCompat/D3dDdi/LockResource.cpp delete mode 100644 DDrawCompat/D3dDdi/LockResource.h create mode 100644 DDrawCompat/D3dDdi/RenderTargetResource.cpp create mode 100644 DDrawCompat/D3dDdi/RenderTargetResource.h diff --git a/DDrawCompat/D3dDdi/Device.cpp b/DDrawCompat/D3dDdi/Device.cpp new file mode 100644 index 0000000..9ca3d3e --- /dev/null +++ b/DDrawCompat/D3dDdi/Device.cpp @@ -0,0 +1,347 @@ +#include "D3dDdi/AdapterFuncs.h" +#include "D3dDdi/Device.h" +#include "D3dDdi/DeviceFuncs.h" +#include "D3dDdi/KernelModeThunks.h" + +namespace +{ + D3DDDI_RESOURCEFLAGS getResourceTypeFlags(); + + const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; + + 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 +{ + UINT getBytesPerPixel(D3DDDIFORMAT format) + { + switch (format) + { + case D3DDDIFMT_A8: + case D3DDDIFMT_P8: + return 1; + + case D3DDDIFMT_R5G6B5: + case D3DDDIFMT_X1R5G5B5: + case D3DDDIFMT_A1R5G5B5: + case D3DDDIFMT_A8P8: + return 2; + + case D3DDDIFMT_R8G8B8: + return 3; + + case D3DDDIFMT_A8R8G8B8: + case D3DDDIFMT_X8R8G8B8: + case D3DDDIFMT_A8B8G8R8: + case D3DDDIFMT_X8B8G8R8: + return 4; + + default: + return 0; + } + } + + Device::Device(HANDLE adapter, HANDLE device) + : m_origVtable(&DeviceFuncs::s_origVtables.at(device)) + , m_adapter(adapter) + , m_device(device) + , m_sharedPrimary(nullptr) + { + } + + HRESULT Device::blt(const D3DDDIARG_BLT& data) + { + prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex); + prepareForRendering(data.hDstResource, data.DstSubResourceIndex); + + auto it = m_oversizedResources.find(data.hSrcResource); + if (it != m_oversizedResources.end()) + { + return it->second.bltFrom(data); + } + + it = m_oversizedResources.find(data.hDstResource); + if (it != m_oversizedResources.end()) + { + return it->second.bltTo(data); + } + + return m_origVtable->pfnBlt(m_device, &data); + } + + HRESULT Device::clear(const D3DDDIARG_CLEAR& data, UINT numRect, const RECT* rect) + { + prepareForRendering(); + return m_origVtable->pfnClear(m_device, &data, numRect, rect); + } + + HRESULT Device::colorFill(const D3DDDIARG_COLORFILL& data) + { + prepareForRendering(data.hResource, data.SubResourceIndex); + return m_origVtable->pfnColorFill(m_device, &data); + } + + template + HRESULT Device::createOversizedResource( + CreateResourceArg& data, + CreateResourceFunc origCreateResource, + const D3DNTHAL_D3DEXTENDEDCAPS& caps) + { + D3DDDI_SURFACEINFO compatSurfaceInfo = data.pSurfList[0]; + if (0 != caps.dwMaxTextureWidth && compatSurfaceInfo.Width > caps.dwMaxTextureWidth) + { + compatSurfaceInfo.Width = caps.dwMaxTextureWidth; + } + if (0 != caps.dwMaxTextureHeight && compatSurfaceInfo.Height > caps.dwMaxTextureHeight) + { + compatSurfaceInfo.Height = caps.dwMaxTextureHeight; + } + + 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(m_adapter, m_device, 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 && + m_adapter) + { + const auto& caps = AdapterFuncs::getD3dExtendedCaps(m_adapter); + 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); + } + } + + HRESULT result = origCreateResource(m_device, &data); + if (SUCCEEDED(result) && data.Flags.RenderTarget && !data.Flags.Primary && isVidMemPool(data.Pool)) + { + m_renderTargetResources.emplace(data.hResource, + RenderTargetResource(m_device, data.hResource, data.Format, data.SurfCount)); + } + + return result; + } + + HRESULT Device::createResource(D3DDDIARG_CREATERESOURCE& data) + { + return createResourceImpl(data, m_origVtable->pfnCreateResource); + } + + HRESULT Device::createResource2(D3DDDIARG_CREATERESOURCE2& data) + { + return createResourceImpl(data, m_origVtable->pfnCreateResource2); + } + + HRESULT Device::destroyResource(HANDLE resource) + { + if (resource == m_sharedPrimary) + { + KernelModeThunks::releaseVidPnSources(); + } + + HRESULT result = m_origVtable->pfnDestroyResource(m_device, resource); + if (SUCCEEDED(result)) + { + m_oversizedResources.erase(resource); + m_renderTargetResources.erase(resource); + m_lockedRenderTargetResources.erase(resource); + + if (resource == m_sharedPrimary) + { + m_sharedPrimary = nullptr; + } + } + + return result; + } + + HRESULT Device::drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data) + { + prepareForRendering(); + return m_origVtable->pfnDrawIndexedPrimitive(m_device, &data); + } + + HRESULT Device::drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data, + UINT indicesSize, const void* indexBuffer, const UINT* flagBuffer) + { + prepareForRendering(); + return m_origVtable->pfnDrawIndexedPrimitive2(m_device, &data, indicesSize, indexBuffer, flagBuffer); + } + + HRESULT Device::drawPrimitive(const D3DDDIARG_DRAWPRIMITIVE& data, const UINT* flagBuffer) + { + prepareForRendering(); + return m_origVtable->pfnDrawPrimitive(m_device, &data, flagBuffer); + } + + HRESULT Device::drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data) + { + prepareForRendering(); + return m_origVtable->pfnDrawPrimitive2(m_device, &data); + } + + HRESULT Device::drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info, + const FLOAT* patch) + { + prepareForRendering(); + return m_origVtable->pfnDrawRectPatch(m_device, &data, info, patch); + } + + HRESULT Device::drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info, + const FLOAT* patch) + { + prepareForRendering(); + return m_origVtable->pfnDrawTriPatch(m_device, &data, info, patch); + } + + HRESULT Device::lock(D3DDDIARG_LOCK& data) + { + auto it = m_renderTargetResources.find(data.hResource); + if (it != m_renderTargetResources.end()) + { + HRESULT result = it->second.lock(data); + if (SUCCEEDED(result)) + { + m_lockedRenderTargetResources.emplace(it->first, it->second); + } + return result; + } + return m_origVtable->pfnLock(m_device, &data); + } + + HRESULT Device::openResource(D3DDDIARG_OPENRESOURCE& data) + { + HRESULT result = m_origVtable->pfnOpenResource(m_device, &data); + if (SUCCEEDED(result) && data.Flags.Fullscreen) + { + m_sharedPrimary = data.hResource; + } + return result; + } + + HRESULT Device::present(const D3DDDIARG_PRESENT& data) + { + prepareForRendering(data.hSrcResource, data.SrcSubResourceIndex); + return m_origVtable->pfnPresent(m_device, &data); + } + + HRESULT Device::present1(D3DDDIARG_PRESENT1& data) + { + for (UINT i = 0; i < data.SrcResources; ++i) + { + prepareForRendering(data.phSrcResources[i].hResource, data.phSrcResources[i].SubResourceIndex); + } + return m_origVtable->pfnPresent1(m_device, &data); + } + + HRESULT Device::texBlt(const D3DDDIARG_TEXBLT& data) + { + prepareForRendering(data.hDstResource); + prepareForRendering(data.hSrcResource); + return m_origVtable->pfnTexBlt(m_device, &data); + } + + HRESULT Device::texBlt1(const D3DDDIARG_TEXBLT1& data) + { + prepareForRendering(data.hDstResource); + prepareForRendering(data.hSrcResource); + return m_origVtable->pfnTexBlt1(m_device, &data); + } + + HRESULT Device::unlock(const D3DDDIARG_UNLOCK& data) + { + auto it = m_renderTargetResources.find(data.hResource); + if (it != m_renderTargetResources.end()) + { + return it->second.unlock(data); + } + return m_origVtable->pfnUnlock(m_device, &data); + } + + HRESULT Device::updateWInfo(const D3DDDIARG_WINFO& data) + { + if (1.0f == data.WNear && 1.0f == data.WFar) + { + D3DDDIARG_WINFO wInfo = {}; + wInfo.WNear = 0.0f; + wInfo.WFar = 1.0f; + return m_origVtable->pfnUpdateWInfo(m_device, &wInfo); + } + return m_origVtable->pfnUpdateWInfo(m_device, &data); + } + + void Device::prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex) + { + resource.prepareForRendering(subResourceIndex); + if (!resource.hasLockedSubResources()) + { + m_lockedRenderTargetResources.erase(resource.getHandle()); + } + } + + void Device::prepareForRendering(HANDLE resource, UINT subResourceIndex) + { + auto it = m_lockedRenderTargetResources.find(resource); + if (it != m_lockedRenderTargetResources.end()) + { + prepareForRendering(it->second, subResourceIndex); + } + } + + void Device::prepareForRendering() + { + auto it = m_lockedRenderTargetResources.begin(); + while (it != m_lockedRenderTargetResources.end()) + { + prepareForRendering((it++)->second); + } + } +} diff --git a/DDrawCompat/D3dDdi/Device.h b/DDrawCompat/D3dDdi/Device.h new file mode 100644 index 0000000..50c19f8 --- /dev/null +++ b/DDrawCompat/D3dDdi/Device.h @@ -0,0 +1,71 @@ +#pragma once + +#define CINTERFACE + +#include +#include + +#include +#include +#include + +#include "D3dDdi/OversizedResource.h" +#include "D3dDdi/RenderTargetResource.h" + +namespace D3dDdi +{ + UINT getBytesPerPixel(D3DDDIFORMAT format); + + class Device + { + public: + Device(HANDLE adapter, HANDLE device); + + HRESULT blt(const D3DDDIARG_BLT& data); + HRESULT clear(const D3DDDIARG_CLEAR& data, UINT numRect, const RECT* rect); + HRESULT colorFill(const D3DDDIARG_COLORFILL& data); + HRESULT createResource(D3DDDIARG_CREATERESOURCE& data); + HRESULT createResource2(D3DDDIARG_CREATERESOURCE2& data); + HRESULT destroyResource(HANDLE resource); + HRESULT drawIndexedPrimitive(const D3DDDIARG_DRAWINDEXEDPRIMITIVE& data); + HRESULT drawIndexedPrimitive2(const D3DDDIARG_DRAWINDEXEDPRIMITIVE2& data, + UINT indicesSize, const void* indexBuffer, const UINT* flagBuffer); + HRESULT drawPrimitive(const D3DDDIARG_DRAWPRIMITIVE& data, const UINT* flagBuffer); + HRESULT drawPrimitive2(const D3DDDIARG_DRAWPRIMITIVE2& data); + HRESULT drawRectPatch(const D3DDDIARG_DRAWRECTPATCH& data, const D3DDDIRECTPATCH_INFO* info, + const FLOAT* patch); + HRESULT drawTriPatch(const D3DDDIARG_DRAWTRIPATCH& data, const D3DDDITRIPATCH_INFO* info, + const FLOAT* patch); + HRESULT lock(D3DDDIARG_LOCK& data); + HRESULT openResource(D3DDDIARG_OPENRESOURCE& data); + HRESULT present(const D3DDDIARG_PRESENT& data); + HRESULT present1(D3DDDIARG_PRESENT1& data); + HRESULT texBlt(const D3DDDIARG_TEXBLT& data); + HRESULT texBlt1(const D3DDDIARG_TEXBLT1& data); + HRESULT unlock(const D3DDDIARG_UNLOCK& data); + HRESULT updateWInfo(const D3DDDIARG_WINFO& data); + + void prepareForRendering(HANDLE resource, UINT subResourceIndex = UINT_MAX); + void prepareForRendering(); + + private: + template + HRESULT createOversizedResource( + CreateResourceArg& data, + CreateResourceFunc origCreateResource, + const D3DNTHAL_D3DEXTENDEDCAPS& caps); + + template + HRESULT createResourceImpl(CreateResourceArg& data, CreateResourceFunc origCreateResource); + + void prepareForRendering(RenderTargetResource& resource, UINT subResourceIndex = UINT_MAX); + + const D3DDDI_DEVICEFUNCS* m_origVtable; + HANDLE m_adapter; + HANDLE m_device; + std::map m_oversizedResources; + std::map m_renderTargetResources; + std::map m_lockedRenderTargetResources; + HANDLE m_sharedPrimary; + }; +} diff --git a/DDrawCompat/D3dDdi/DeviceFuncs.cpp b/DDrawCompat/D3dDdi/DeviceFuncs.cpp index f0d1a3f..d6a3a59 100644 --- a/DDrawCompat/D3dDdi/DeviceFuncs.cpp +++ b/DDrawCompat/D3dDdi/DeviceFuncs.cpp @@ -1,461 +1,77 @@ -#include #include -#include "D3dDdi/AdapterFuncs.h" +#include "D3dDdi/Device.h" #include "D3dDdi/DeviceFuncs.h" -#include "D3dDdi/LockResource.h" -#include "D3dDdi/KernelModeThunks.h" -#include "D3dDdi/OversizedResource.h" namespace { - struct Resource + std::map g_devices; + + D3dDdi::Device& getDevice(HANDLE device) { - HANDLE device; - HANDLE resource; - - Resource() : device(nullptr), resource(nullptr) {} - Resource(HANDLE device, HANDLE resource) : device(device), resource(resource) {} - - bool operator<(const Resource& rhs) const + auto it = g_devices.find(device); + if (it != g_devices.end()) { - return device < rhs.device || (device == rhs.device && resource < rhs.resource); + return it->second; } - }; - class ResourceReplacer - { - public: - ResourceReplacer(HANDLE device, const HANDLE& resource, UINT subResourceIndex); - ~ResourceReplacer(); - - D3dDdi::LockResource::SubResource* getSubResource() const { return m_subResource; } - - private: - HANDLE& m_resource; - HANDLE m_origResource; - D3dDdi::LockResource::SubResource* m_subResource; - }; - - D3DDDI_DEVICEFUNCS& getOrigVtable(HANDLE device); - D3DDDI_RESOURCEFLAGS getResourceTypeFlags(); - bool isVidMemPool(D3DDDI_POOL pool); - D3dDdi::LockResource::SubResource* replaceWithActiveResource( - HANDLE device, HANDLE& resource, UINT subResourceIndex); - - std::map g_deviceToAdapter; - std::map g_lockResources; - std::map g_oversizedResources; - std::map g_renderTargets; - Resource g_sharedPrimary; - const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; - - ResourceReplacer::ResourceReplacer(HANDLE device, const HANDLE& resource, UINT subResourceIndex) - : m_resource(const_cast(resource)) - , m_origResource(resource) - { - m_subResource = replaceWithActiveResource(device, m_resource, subResourceIndex); + return g_devices.emplace(device, D3dDdi::Device(nullptr, device)).first->second; } - ResourceReplacer::~ResourceReplacer() + template + HRESULT WINAPI deviceFunc(HANDLE device, Arg* data, Params... params) { - m_resource = m_origResource; - } - - template - HRESULT createOversizedResource(HANDLE device, CreateResourceArg& resourceData, - CreateResourceFunc origCreateResource, const D3DNTHAL_D3DEXTENDEDCAPS& caps) - { - D3DDDI_SURFACEINFO compatSurfaceInfo = resourceData.pSurfList[0]; - if (0 != caps.dwMaxTextureWidth && compatSurfaceInfo.Width > caps.dwMaxTextureWidth) - { - compatSurfaceInfo.Width = caps.dwMaxTextureWidth; - } - if (0 != caps.dwMaxTextureHeight && compatSurfaceInfo.Height > caps.dwMaxTextureHeight) - { - compatSurfaceInfo.Height = caps.dwMaxTextureHeight; - } - - const D3DDDI_SURFACEINFO* origSurfList = resourceData.pSurfList; - resourceData.pSurfList = &compatSurfaceInfo; - HRESULT result = origCreateResource(device, &resourceData); - resourceData.pSurfList = origSurfList; - - if (SUCCEEDED(result)) - { - auto it = g_deviceToAdapter.find(device); - if (it != g_deviceToAdapter.end()) - { - D3dDdi::OversizedResource oversizedResource( - it->second, device, resourceData.Format, origSurfList[0]); - g_oversizedResources[Resource(device, resourceData.hResource)] = oversizedResource; - } - } - - return result; - } - - template - HRESULT createResource(HANDLE device, CreateResourceArg* resourceData, - CreateResourceFunc origCreateResource) - { - const bool isOffScreenPlain = 0 == (resourceData->Flags.Value & g_resourceTypeFlags); - if (D3DDDIPOOL_SYSTEMMEM == resourceData->Pool && - (isOffScreenPlain || resourceData->Flags.Texture) && - D3dDdi::OversizedResource::isSupportedFormat(resourceData->Format) && - 1 == resourceData->SurfCount) - { - auto it = g_deviceToAdapter.find(device); - if (it != g_deviceToAdapter.end()) - { - const auto& caps = D3dDdi::AdapterFuncs::getD3dExtendedCaps(it->second); - const auto& surfaceInfo = resourceData->pSurfList[0]; - if (0 != caps.dwMaxTextureWidth && surfaceInfo.Width > caps.dwMaxTextureWidth || - 0 != caps.dwMaxTextureHeight && surfaceInfo.Height > caps.dwMaxTextureHeight) - { - return createOversizedResource(device, *resourceData, origCreateResource, caps); - } - } - } - - HANDLE origResourceHandle = resourceData->hResource; - HRESULT result = origCreateResource(device, resourceData); - if (SUCCEEDED(result) && resourceData->Flags.RenderTarget && !resourceData->Flags.Primary && - isVidMemPool(resourceData->Pool)) - { - CreateResourceArg lockResourceData = {}; - lockResourceData.Format = resourceData->Format; - lockResourceData.Pool = resourceData->Pool; - lockResourceData.pSurfList = resourceData->pSurfList; - lockResourceData.SurfCount = resourceData->SurfCount; - lockResourceData.hResource = origResourceHandle; - lockResourceData.Flags.CpuOptimized = 1; - - if (SUCCEEDED(origCreateResource(device, &lockResourceData))) - { - g_lockResources.emplace(std::piecewise_construct, - std::forward_as_tuple(device, resourceData->hResource), - std::forward_as_tuple(device, resourceData->hResource, lockResourceData.hResource, - lockResourceData.pSurfList, lockResourceData.SurfCount)); - } - } - - return result; - } - - D3DDDI_DEVICEFUNCS& getOrigVtable(HANDLE device) - { - return D3dDdi::DeviceFuncs::s_origVtables.at(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; - } - - HRESULT renderFunc(HANDLE device, std::function origFunc) - { - auto it = g_renderTargets.find(device); - if (it != g_renderTargets.end()) - { - it->second->updateOrig(); - } - - HRESULT result = origFunc(); - if (SUCCEEDED(result) && it != g_renderTargets.end()) - { - it->second->m_isLockUpToDate = false; - } - return result; - } - - D3dDdi::LockResource::SubResource* replaceWithActiveResource( - HANDLE device, HANDLE& resource, UINT subResourceIndex) - { - auto it = g_lockResources.find(Resource(device, resource)); - if (it == g_lockResources.end()) - { - return nullptr; - } - - auto& subResource = it->second.getSubResource(subResourceIndex); - if (subResource.m_isLockUpToDate) - { - resource = it->second.getHandle(); - } - return &subResource; - } - - HRESULT APIENTRY blt(HANDLE hDevice, const D3DDDIARG_BLT* pData) - { - ResourceReplacer srcReplacer(hDevice, pData->hSrcResource, pData->SrcSubResourceIndex); - ResourceReplacer dstReplacer(hDevice, pData->hDstResource, pData->DstSubResourceIndex); - auto dstSubResource = dstReplacer.getSubResource(); - - HRESULT result = S_OK; - auto it = g_oversizedResources.find(Resource(hDevice, pData->hSrcResource)); - if (it != g_oversizedResources.end()) - { - result = it->second.bltFrom(*pData); - } - else - { - it = g_oversizedResources.find(Resource(hDevice, pData->hDstResource)); - if (it != g_oversizedResources.end()) - { - result = it->second.bltTo(*pData); - } - else - { - result = getOrigVtable(hDevice).pfnBlt(hDevice, pData); - } - } - - if (SUCCEEDED(result) && dstSubResource && dstSubResource->m_isLockUpToDate) - { - dstSubResource->m_isOrigUpToDate = false; - } - return result; - } - - HRESULT APIENTRY colorFill(HANDLE hDevice, const D3DDDIARG_COLORFILL* pData) - { - ResourceReplacer replacer(hDevice, pData->hResource, pData->SubResourceIndex); - auto subResource = replacer.getSubResource(); - - HRESULT result = getOrigVtable(hDevice).pfnColorFill(hDevice, pData); - if (SUCCEEDED(result) && subResource && subResource->m_isLockUpToDate) - { - subResource->m_isOrigUpToDate = false; - } - return result; - } - - HRESULT APIENTRY createResource(HANDLE hDevice, D3DDDIARG_CREATERESOURCE* pResource) - { - return createResource(hDevice, pResource, getOrigVtable(hDevice).pfnCreateResource); - } - - HRESULT APIENTRY createResource2(HANDLE hDevice, D3DDDIARG_CREATERESOURCE2* pResource2) - { - return createResource(hDevice, pResource2, getOrigVtable(hDevice).pfnCreateResource2); + return (getDevice(device).*deviceMethod)(*data, params...); } HRESULT APIENTRY destroyDevice(HANDLE hDevice) { - HRESULT result = getOrigVtable(hDevice).pfnDestroyDevice(hDevice); + HRESULT result = D3dDdi::DeviceFuncs::s_origVtables.at(hDevice).pfnDestroyDevice(hDevice); if (SUCCEEDED(result)) { D3dDdi::DeviceFuncs::s_origVtables.erase(hDevice); - g_deviceToAdapter.erase(hDevice); + g_devices.erase(hDevice); } return result; } HRESULT APIENTRY destroyResource(HANDLE hDevice, HANDLE hResource) { - const bool isSharedPrimary = - hDevice == g_sharedPrimary.device && hResource == g_sharedPrimary.resource; - if (isSharedPrimary) - { - D3dDdi::KernelModeThunks::releaseVidPnSources(); - } - - HRESULT result = getOrigVtable(hDevice).pfnDestroyResource(hDevice, hResource); - if (SUCCEEDED(result)) - { - auto lockResourceIt = g_lockResources.find(Resource(hDevice, hResource)); - if (lockResourceIt != g_lockResources.end()) - { - auto renderTarget = g_renderTargets.find(hDevice); - if (renderTarget != g_renderTargets.end() && - &renderTarget->second->getParent() == &lockResourceIt->second) - { - g_renderTargets.erase(hDevice); - } - - getOrigVtable(hDevice).pfnDestroyResource(hDevice, lockResourceIt->second.getHandle()); - g_lockResources.erase(lockResourceIt); - } - - auto oversizedResourceIt = g_oversizedResources.find(Resource(hDevice, hResource)); - if (oversizedResourceIt != g_oversizedResources.end()) - { - g_oversizedResources.erase(oversizedResourceIt); - } - - if (isSharedPrimary) - { - g_sharedPrimary = {}; - } - } - return result; - } - - HRESULT APIENTRY lock(HANDLE hDevice, D3DDDIARG_LOCK* pData) - { - auto it = g_lockResources.find(Resource(hDevice, pData->hResource)); - if (it != g_lockResources.end()) - { - auto& subResource = it->second.getSubResource(pData->SubResourceIndex); - subResource.updateLock(); - - HANDLE origResourceHandle = pData->hResource; - pData->hResource = it->second.getHandle(); - HRESULT result = getOrigVtable(hDevice).pfnLock(hDevice, pData); - pData->hResource = origResourceHandle; - - if (SUCCEEDED(result) && !pData->Flags.ReadOnly) - { - subResource.m_isOrigUpToDate = false; - } - - return result; - } - return getOrigVtable(hDevice).pfnLock(hDevice, pData); - } - - HRESULT APIENTRY openResource(HANDLE hDevice, D3DDDIARG_OPENRESOURCE* pResource) - { - HRESULT result = getOrigVtable(hDevice).pfnOpenResource(hDevice, pResource); - if (SUCCEEDED(result) && pResource->Flags.Fullscreen) - { - g_sharedPrimary = Resource(hDevice, pResource->hResource); - } - return result; - } - - HRESULT APIENTRY present(HANDLE hDevice, const D3DDDIARG_PRESENT* pData) - { - auto it = g_lockResources.find(Resource(hDevice, pData->hSrcResource)); - if (it != g_lockResources.end()) - { - it->second.getSubResource(pData->SrcSubResourceIndex).updateOrig(); - } - return getOrigVtable(hDevice).pfnPresent(hDevice, pData); - } - - HRESULT APIENTRY present1(HANDLE hDevice, D3DDDIARG_PRESENT1* pPresentData) - { - for (UINT i = 0; i < pPresentData->SrcResources; ++i) - { - auto it = g_lockResources.find(Resource(hDevice, pPresentData->phSrcResources[i].hResource)); - if (it != g_lockResources.end()) - { - it->second.getSubResource(pPresentData->phSrcResources[i].SubResourceIndex).updateOrig(); - } - } - return getOrigVtable(hDevice).pfnPresent1(hDevice, pPresentData); - } - - template - HRESULT WINAPI renderFunc(HANDLE device, Params... params) - { - return renderFunc(device, - [=]() { return (getOrigVtable(device).*origFunc)(device, params...); }); - } - - HRESULT APIENTRY setRenderTarget(HANDLE hDevice, const D3DDDIARG_SETRENDERTARGET* pData) - { - HRESULT result = getOrigVtable(hDevice).pfnSetRenderTarget(hDevice, pData); - if (SUCCEEDED(result)) - { - auto it = g_lockResources.find(Resource(hDevice, pData->hRenderTarget)); - if (it != g_lockResources.end()) - { - g_renderTargets[hDevice] = &it->second.getSubResource(pData->SubResourceIndex); - } - else - { - g_renderTargets.erase(hDevice); - } - } - return result; - } - - HRESULT APIENTRY unlock(HANDLE hDevice, const D3DDDIARG_UNLOCK* pData) - { - auto it = g_lockResources.find(Resource(hDevice, pData->hResource)); - if (it != g_lockResources.end()) - { - HANDLE origResource = pData->hResource; - const_cast(pData->hResource) = it->second.getHandle(); - HRESULT result = getOrigVtable(hDevice).pfnUnlock(hDevice, pData); - const_cast(pData->hResource) = origResource; - return result; - } - return getOrigVtable(hDevice).pfnUnlock(hDevice, pData); - } - - HRESULT APIENTRY updateWInfo(HANDLE hDevice, const D3DDDIARG_WINFO* pData) - { - if (pData && 1.0f == pData->WNear && 1.0f == pData->WFar) - { - D3DDDIARG_WINFO wInfo = {}; - wInfo.WNear = 0.0f; - wInfo.WFar = 1.0f; - return getOrigVtable(hDevice).pfnUpdateWInfo(hDevice, &wInfo); - } - return getOrigVtable(hDevice).pfnUpdateWInfo(hDevice, pData); + return getDevice(hDevice).destroyResource(hResource); } } -#define RENDER_FUNC(func) renderFunc +#define DEVICE_FUNC(func) deviceFunc namespace D3dDdi { void DeviceFuncs::onCreateDevice(HANDLE adapter, HANDLE device) { - g_deviceToAdapter[device] = adapter; + g_devices.emplace(device, Device(adapter, device)); } void DeviceFuncs::setCompatVtable(D3DDDI_DEVICEFUNCS& vtable) { - vtable.pfnBlt = &blt; - vtable.pfnClear = &RENDER_FUNC(pfnClear); - vtable.pfnColorFill = &colorFill; - vtable.pfnCreateResource = &createResource; - vtable.pfnCreateResource2 = &createResource2; + vtable.pfnBlt = &DEVICE_FUNC(blt); + vtable.pfnClear = &DEVICE_FUNC(clear); + vtable.pfnColorFill = &DEVICE_FUNC(colorFill); + vtable.pfnCreateResource = &DEVICE_FUNC(createResource); + vtable.pfnCreateResource2 = &DEVICE_FUNC(createResource2); vtable.pfnDestroyDevice = &destroyDevice; vtable.pfnDestroyResource = &destroyResource; - vtable.pfnDrawIndexedPrimitive = &RENDER_FUNC(pfnDrawIndexedPrimitive); - vtable.pfnDrawIndexedPrimitive2 = &RENDER_FUNC(pfnDrawIndexedPrimitive2); - vtable.pfnDrawPrimitive = &RENDER_FUNC(pfnDrawPrimitive); - vtable.pfnDrawPrimitive2 = &RENDER_FUNC(pfnDrawPrimitive2); - vtable.pfnDrawRectPatch = &RENDER_FUNC(pfnDrawRectPatch); - vtable.pfnDrawTriPatch = &RENDER_FUNC(pfnDrawTriPatch); - vtable.pfnLock = &lock; - vtable.pfnOpenResource = &openResource; - vtable.pfnPresent = &present; - vtable.pfnPresent1 = &present1; - vtable.pfnSetRenderTarget = &setRenderTarget; - vtable.pfnUnlock = &unlock; - vtable.pfnUpdateWInfo = &updateWInfo; + vtable.pfnDrawIndexedPrimitive = &DEVICE_FUNC(drawIndexedPrimitive); + vtable.pfnDrawIndexedPrimitive2 = &DEVICE_FUNC(drawIndexedPrimitive2); + vtable.pfnDrawPrimitive = &DEVICE_FUNC(drawPrimitive); + vtable.pfnDrawPrimitive2 = &DEVICE_FUNC(drawPrimitive2); + vtable.pfnDrawRectPatch = &DEVICE_FUNC(drawRectPatch); + vtable.pfnDrawTriPatch = &DEVICE_FUNC(drawTriPatch); + vtable.pfnLock = &DEVICE_FUNC(lock); + vtable.pfnOpenResource = &DEVICE_FUNC(openResource); + vtable.pfnPresent = &DEVICE_FUNC(present); + vtable.pfnPresent1 = &DEVICE_FUNC(present1); + vtable.pfnTexBlt = &DEVICE_FUNC(texBlt); + vtable.pfnTexBlt1 = &DEVICE_FUNC(texBlt1); + vtable.pfnUnlock = &DEVICE_FUNC(unlock); + vtable.pfnUpdateWInfo = &DEVICE_FUNC(updateWInfo); } } diff --git a/DDrawCompat/D3dDdi/LockResource.cpp b/DDrawCompat/D3dDdi/LockResource.cpp deleted file mode 100644 index a1a11bf..0000000 --- a/DDrawCompat/D3dDdi/LockResource.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "D3dDdi/DeviceFuncs.h" -#include "D3dDdi/LockResource.h" - -namespace -{ - D3DDDI_DEVICEFUNCS& getOrigVtable(HANDLE device) - { - return D3dDdi::DeviceFuncs::s_origVtables.at(device); - } -} - -namespace D3dDdi -{ - LockResource::LockResource(HANDLE device, HANDLE origResource, HANDLE lockResource, - const D3DDDI_SURFACEINFO* surfaceInfo, UINT surfaceInfoCount) - : m_device(device) - , m_origResource(origResource) - , m_lockResource(lockResource) - { - for (UINT i = 0; i < surfaceInfoCount; ++i) - { - m_subResources.emplace_back(*this, i, surfaceInfo[i].Width, surfaceInfo[i].Height); - } - } - - LockResource::~LockResource() - { - } - - LockResource::SubResource::SubResource(LockResource& parent, UINT index, UINT width, UINT height) - : m_isOrigUpToDate(true) - , m_isLockUpToDate(true) - , m_parent(&parent) - , m_index(index) - , m_width(width) - , m_height(height) - { - } - - HRESULT LockResource::SubResource::blt(HANDLE dstResource, HANDLE srcResource) - { - RECT rect = { 0, 0, static_cast(m_width), static_cast(m_height) }; - - D3DDDIARG_BLT bltData = {}; - bltData.hSrcResource = srcResource; - bltData.SrcSubResourceIndex = m_index; - bltData.SrcRect = rect; - bltData.hDstResource = dstResource; - bltData.DstSubResourceIndex = m_index; - bltData.DstRect = rect; - bltData.Flags.Point = 1; - - return getOrigVtable(m_parent->m_device).pfnBlt(m_parent->m_device, &bltData); - } - - void LockResource::SubResource::updateLock() - { - if (!m_isLockUpToDate) - { - blt(m_parent->m_lockResource, m_parent->m_origResource); - m_isLockUpToDate = true; - } - } - - void LockResource::SubResource::updateOrig() - { - if (!m_isOrigUpToDate) - { - blt(m_parent->m_origResource, m_parent->m_lockResource); - m_isOrigUpToDate = true; - } - } -} diff --git a/DDrawCompat/D3dDdi/LockResource.h b/DDrawCompat/D3dDdi/LockResource.h deleted file mode 100644 index 2097e18..0000000 --- a/DDrawCompat/D3dDdi/LockResource.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#define CINTERFACE - -#include - -#include -#include - -namespace D3dDdi -{ - class LockResource - { - public: - struct SubResource - { - public: - SubResource(LockResource& parent, UINT index, UINT width, UINT height); - - LockResource& getParent() const { return *m_parent; } - void updateLock(); - void updateOrig(); - - bool m_isOrigUpToDate; - bool m_isLockUpToDate; - - private: - HRESULT blt(HANDLE dstResource, HANDLE srcResource); - - LockResource* m_parent; - UINT m_index; - UINT m_width; - UINT m_height; - }; - - LockResource(HANDLE device, HANDLE origResource, HANDLE lockResource, - const D3DDDI_SURFACEINFO* surfaceInfo, UINT surfaceInfoCount); - ~LockResource(); - LockResource(const LockResource&) = delete; - - HANDLE getHandle() const { return m_lockResource; } - SubResource& getSubResource(UINT index) { return m_subResources[index]; } - - private: - HANDLE m_device; - HANDLE m_origResource; - HANDLE m_lockResource; - std::vector m_subResources; - }; -} diff --git a/DDrawCompat/D3dDdi/OversizedResource.cpp b/DDrawCompat/D3dDdi/OversizedResource.cpp index b9f0bbf..6efa91f 100644 --- a/DDrawCompat/D3dDdi/OversizedResource.cpp +++ b/DDrawCompat/D3dDdi/OversizedResource.cpp @@ -1,43 +1,10 @@ #include "D3dDdi/AdapterFuncs.h" +#include "D3dDdi/Device.h" #include "D3dDdi/DeviceFuncs.h" #include "D3dDdi/OversizedResource.h" -namespace -{ - UINT getBytesPerPixel(D3DDDIFORMAT format) - { - switch (format) - { - case D3DDDIFMT_R5G6B5: - case D3DDDIFMT_X1R5G5B5: - case D3DDDIFMT_A1R5G5B5: - return 2; - - case D3DDDIFMT_R8G8B8: - return 3; - - case D3DDDIFMT_A8R8G8B8: - case D3DDDIFMT_X8R8G8B8: - case D3DDDIFMT_A8B8G8R8: - case D3DDDIFMT_X8B8G8R8: - return 4; - - default: - return 0; - } - } -} - namespace D3dDdi { - OversizedResource::OversizedResource() - : m_adapter(nullptr) - , m_device(nullptr) - , m_format(D3DDDIFMT_UNKNOWN) - , m_surfaceInfo() - { - } - OversizedResource::OversizedResource( HANDLE adapter, HANDLE device, D3DDDIFORMAT format, const D3DDDI_SURFACEINFO& surfaceInfo) : m_adapter(adapter) diff --git a/DDrawCompat/D3dDdi/OversizedResource.h b/DDrawCompat/D3dDdi/OversizedResource.h index 9e6f814..bf7afc2 100644 --- a/DDrawCompat/D3dDdi/OversizedResource.h +++ b/DDrawCompat/D3dDdi/OversizedResource.h @@ -10,7 +10,6 @@ namespace D3dDdi class OversizedResource { public: - OversizedResource(); OversizedResource(HANDLE adapter, HANDLE device, D3DDDIFORMAT format, const D3DDDI_SURFACEINFO& surfaceInfo); diff --git a/DDrawCompat/D3dDdi/RenderTargetResource.cpp b/DDrawCompat/D3dDdi/RenderTargetResource.cpp new file mode 100644 index 0000000..4ab7b90 --- /dev/null +++ b/DDrawCompat/D3dDdi/RenderTargetResource.cpp @@ -0,0 +1,106 @@ +#include "D3dDdi/Device.h" +#include "D3dDdi/DeviceFuncs.h" +#include "D3dDdi/RenderTargetResource.h" + +namespace D3dDdi +{ + RenderTargetResource::RenderTargetResource( + HANDLE device, HANDLE resource, D3DDDIFORMAT format, UINT surfaceCount) + : m_device(device) + , m_resource(resource) + , m_bytesPerPixel(getBytesPerPixel(format)) + , m_subResources(surfaceCount, SubResource(*this)) + { + } + + HRESULT RenderTargetResource::lock(D3DDDIARG_LOCK& data) + { + if (data.SubResourceIndex >= m_subResources.size()) + { + return D3dDdi::DeviceFuncs::s_origVtables.at(m_device).pfnLock(m_device, &data); + } + + auto& subResource = m_subResources[data.SubResourceIndex]; + if (subResource.surfacePtr) + { + auto surfacePtr = static_cast(subResource.surfacePtr); + if (data.Flags.AreaValid) + { + surfacePtr += data.Area.top * subResource.pitch + data.Area.left * m_bytesPerPixel; + } + data.pSurfData = surfacePtr; + data.Pitch = subResource.pitch; + subResource.isLocked = true; + return S_OK; + } + + const UINT origFlags = data.Flags.Value; + data.Flags.Value = 0; + const HRESULT result = D3dDdi::DeviceFuncs::s_origVtables.at(m_device).pfnLock(m_device, &data); + data.Flags.Value = origFlags; + + if (SUCCEEDED(result)) + { + subResource.surfacePtr = data.pSurfData; + subResource.pitch = data.Pitch; + subResource.isLocked = true; + m_lockedSubResources.insert(data.SubResourceIndex); + } + + return result; + } + + HRESULT RenderTargetResource::unlock(const D3DDDIARG_UNLOCK& data) + { + if (data.SubResourceIndex >= m_subResources.size()) + { + return D3dDdi::DeviceFuncs::s_origVtables.at(m_device).pfnUnlock(m_device, &data); + } + + m_subResources[data.SubResourceIndex].isLocked = false; + return S_OK; + } + + void RenderTargetResource::prepareForRendering(UINT subResourceIndex) + { + if (UINT_MAX == subResourceIndex) + { + auto it = m_lockedSubResources.begin(); + while (it != m_lockedSubResources.end()) + { + prepareSubResourceForRendering(*(it++)); + } + } + + if (subResourceIndex >= m_subResources.size()) + { + return; + } + + prepareSubResourceForRendering(subResourceIndex); + } + + void RenderTargetResource::prepareSubResourceForRendering(UINT subResourceIndex) + { + auto& subResource = m_subResources[subResourceIndex]; + if (subResource.surfacePtr && !subResource.isLocked) + { + D3DDDIARG_UNLOCK data = {}; + data.hResource = m_resource; + data.SubResourceIndex = subResourceIndex; + D3dDdi::DeviceFuncs::s_origVtables.at(m_device).pfnUnlock(m_device, &data); + + subResource.surfacePtr = nullptr; + subResource.pitch = 0; + m_lockedSubResources.erase(subResourceIndex); + } + } + + RenderTargetResource::SubResource::SubResource(RenderTargetResource& parent) + : parent(parent) + , surfacePtr(nullptr) + , pitch(0) + , isLocked(false) + { + } +} diff --git a/DDrawCompat/D3dDdi/RenderTargetResource.h b/DDrawCompat/D3dDdi/RenderTargetResource.h new file mode 100644 index 0000000..3be460b --- /dev/null +++ b/DDrawCompat/D3dDdi/RenderTargetResource.h @@ -0,0 +1,44 @@ +#pragma once + +#define CINTERFACE + +#include +#include + +#include +#include + +namespace D3dDdi +{ + class RenderTargetResource + { + public: + RenderTargetResource(HANDLE device, HANDLE resource, D3DDDIFORMAT format, UINT surfaceCount); + + HRESULT lock(D3DDDIARG_LOCK& data); + HRESULT unlock(const D3DDDIARG_UNLOCK& data); + + HANDLE getHandle() const { return m_resource; } + bool hasLockedSubResources() { return !m_lockedSubResources.empty(); } + void prepareForRendering(UINT subResourceIndex = UINT_MAX); + + private: + struct SubResource + { + RenderTargetResource& parent; + void* surfacePtr; + UINT pitch; + bool isLocked; + + SubResource(RenderTargetResource& parent); + }; + + void prepareSubResourceForRendering(UINT subResourceIndex); + + HANDLE m_device; + HANDLE m_resource; + UINT m_bytesPerPixel; + std::vector m_subResources; + std::set m_lockedSubResources; + }; +} diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 90c7e28..6a76fed 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -164,16 +164,17 @@ + - + @@ -235,16 +236,17 @@ + - + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 5ce1577..60f26de 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -282,9 +282,6 @@ Header Files\D3dDdi\Log - - Header Files\D3dDdi - Header Files\D3dDdi\Log @@ -312,6 +309,12 @@ Header Files\DDraw + + Header Files\D3dDdi + + + Header Files\D3dDdi + @@ -452,9 +455,6 @@ Source Files\D3dDdi\Log - - Source Files\D3dDdi - Source Files\D3dDdi\Log @@ -476,6 +476,12 @@ Source Files\DDraw + + Source Files\D3dDdi + + + Source Files\D3dDdi +