diff --git a/DDrawCompat/Common/Hook.cpp b/DDrawCompat/Common/Hook.cpp index 9945cba..77ed6b1 100644 --- a/DDrawCompat/Common/Hook.cpp +++ b/DDrawCompat/Common/Hook.cpp @@ -83,11 +83,11 @@ namespace { if (funcName) { - Compat::Log() << "Failed to hook a function: " << funcName; + Compat::LogDebug() << "Failed to hook a function: " << funcName; } else { - Compat::Log() << "Failed to hook a function: " << origFuncPtr; + Compat::LogDebug() << "Failed to hook a function: " << origFuncPtr; } return; } diff --git a/DDrawCompat/D3dDdi/DeviceFuncs.cpp b/DDrawCompat/D3dDdi/DeviceFuncs.cpp index 7297013..b405ca5 100644 --- a/DDrawCompat/D3dDdi/DeviceFuncs.cpp +++ b/DDrawCompat/D3dDdi/DeviceFuncs.cpp @@ -1,32 +1,92 @@ +#include +#include + #include "D3dDdi/DeviceFuncs.h" +#include "D3dDdi/LockResource.h" namespace { + struct Resource + { + HANDLE device; + HANDLE resource; + + Resource(HANDLE device, HANDLE resource) : device(device), resource(resource) {} + + bool operator<(const Resource& rhs) const + { + return device < rhs.device || (device == rhs.device && resource < rhs.resource); + } + }; + + 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(); - void modifyCreateResourceFlags(D3DDDI_RESOURCEFLAGS& flags); + bool isVidMemPool(D3DDDI_POOL pool); + D3dDdi::LockResource::SubResource* replaceWithActiveResource( + HANDLE device, HANDLE& resource, UINT subResourceIndex); + std::map g_lockResources; + std::map g_renderTargets; const UINT g_resourceTypeFlags = getResourceTypeFlags().Value; - HRESULT APIENTRY createResource(HANDLE hDevice, D3DDDIARG_CREATERESOURCE* pResource) + ResourceReplacer::ResourceReplacer(HANDLE device, const HANDLE& resource, UINT subResourceIndex) + : m_resource(const_cast(resource)) + , m_origResource(resource) { - modifyCreateResourceFlags(pResource->Flags); - return getOrigVtable(hDevice).pfnCreateResource(hDevice, pResource); + m_subResource = replaceWithActiveResource(device, m_resource, subResourceIndex); } - HRESULT APIENTRY createResource2(HANDLE hDevice, D3DDDIARG_CREATERESOURCE2* pResource2) + ResourceReplacer::~ResourceReplacer() { - modifyCreateResourceFlags(pResource2->Flags); - return getOrigVtable(hDevice).pfnCreateResource2(hDevice, pResource2); + m_resource = m_origResource; } - HRESULT APIENTRY destroyDevice(HANDLE hDevice) + template + HRESULT createResource(HANDLE device, CreateResourceArg* resourceData, + CreateResourceFunc origCreateResource) { - HRESULT result = getOrigVtable(hDevice).pfnDestroyDevice(hDevice); - if (SUCCEEDED(result)) + const bool isOffScreenPlain = 0 == (resourceData->Flags.Value & g_resourceTypeFlags); + if (isOffScreenPlain) { - D3dDdi::DeviceFuncs::s_origVtables.erase(hDevice); + resourceData->Flags.CpuOptimized = 1; } + + 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; } @@ -59,22 +119,224 @@ namespace return flags; } - void modifyCreateResourceFlags(D3DDDI_RESOURCEFLAGS& flags) + bool isVidMemPool(D3DDDI_POOL pool) { - const bool isOffScreenPlain = 0 == (flags.Value & g_resourceTypeFlags); - if (isOffScreenPlain) + 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()) { - flags.CpuOptimized = 1; + 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 = 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); + } + + HRESULT APIENTRY destroyDevice(HANDLE hDevice) + { + HRESULT result = getOrigVtable(hDevice).pfnDestroyDevice(hDevice); + if (SUCCEEDED(result)) + { + D3dDdi::DeviceFuncs::s_origVtables.erase(hDevice); + } + return result; + } + + HRESULT APIENTRY destroyResource(HANDLE hDevice, HANDLE hResource) + { + HRESULT result = getOrigVtable(hDevice).pfnDestroyResource(hDevice, hResource); + if (SUCCEEDED(result)) + { + auto it = g_lockResources.find(Resource(hDevice, hResource)); + if (it != g_lockResources.end()) + { + auto renderTarget = g_renderTargets.find(hDevice); + if (renderTarget != g_renderTargets.end() && + &renderTarget->second->getParent() == &it->second) + { + g_renderTargets.erase(hDevice); + } + + getOrigVtable(hDevice).pfnDestroyResource(hDevice, it->second.getHandle()); + g_lockResources.erase(it); + } + } + 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 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); } } +#define RENDER_FUNC(func) renderFunc + namespace D3dDdi { void DeviceFuncs::setCompatVtable(D3DDDI_DEVICEFUNCS& vtable) { + vtable.pfnBlt = &blt; + vtable.pfnClear = &RENDER_FUNC(pfnClear); + vtable.pfnColorFill = &colorFill; vtable.pfnCreateResource = &createResource; vtable.pfnCreateResource2 = &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.pfnPresent = &present; + vtable.pfnPresent1 = &present1; + vtable.pfnSetRenderTarget = &setRenderTarget; + vtable.pfnUnlock = &unlock; } } diff --git a/DDrawCompat/D3dDdi/LockResource.cpp b/DDrawCompat/D3dDdi/LockResource.cpp new file mode 100644 index 0000000..a1a11bf --- /dev/null +++ b/DDrawCompat/D3dDdi/LockResource.cpp @@ -0,0 +1,73 @@ +#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 new file mode 100644 index 0000000..2097e18 --- /dev/null +++ b/DDrawCompat/D3dDdi/LockResource.h @@ -0,0 +1,50 @@ +#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/Log/DeviceFuncsLog.cpp b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp index e299fea..0faf965 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp @@ -19,6 +19,25 @@ std::ostream& operator<<(std::ostream& os, const D3DDDI_SURFACEINFO& val) << val.SysMemSlicePitch; } +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CLEAR& val) +{ + return Compat::LogStruct(os) + << Compat::hex(val.Flags) + << Compat::hex(val.FillColor) + << val.FillDepth + << Compat::hex(val.FillStencil); +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_COLORFILL& val) +{ + return Compat::LogStruct(os) + << val.hResource + << val.SubResourceIndex + << val.DstRect + << Compat::hex(val.Color) + << Compat::hex(val.Flags.Value); +} + std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATERESOURCE& val) { return Compat::LogStruct(os) @@ -81,6 +100,38 @@ std::ostream& operator<<(std::ostream& os, const D3DDDIARG_OPENRESOURCE& val) << Compat::hex(val.Flags.Value); } +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENT& val) +{ + return Compat::LogStruct(os) + << val.hSrcResource + << val.SrcSubResourceIndex + << val.hDstResource + << val.DstSubResourceIndex + << Compat::hex(val.Flags.Value) + << val.FlipInterval; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENT1& val) +{ + return Compat::LogStruct(os) + << Compat::array(val.phSrcResources, val.SrcResources) + << val.SrcResources + << val.hDstResource + << val.DstSubResourceIndex + << Compat::hex(val.Flags.Value) + << val.FlipInterval + << val.Reserved + << Compat::array(val.pDirtyRects, val.DirtyRects) + << val.DirtyRects; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENTSURFACE& val) +{ + return Compat::LogStruct(os) + << val.hResource + << val.SubResourceIndex; +} + std::ostream& operator<<(std::ostream& os, const D3DDDIARG_UNLOCK& val) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h index 7b30631..80695d9 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h @@ -9,9 +9,14 @@ 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_CLEAR& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_COLORFILL& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATERESOURCE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATERESOURCE2& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_LOCK& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_OPENRESOURCE& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENT& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENT1& val); +std::ostream& operator<<(std::ostream& os, const D3DDDIARG_PRESENTSURFACE& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_UNLOCK& val); std::ostream& operator<<(std::ostream& os, const D3DDDIBOX& val); diff --git a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp index 8f51548..3ee33fe 100644 --- a/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp +++ b/DDrawCompat/DDraw/Surfaces/SurfaceImpl.cpp @@ -17,7 +17,7 @@ namespace void fixSurfacePtr(CompatRef surface, const DDSURFACEDESC2& desc) { - if ((desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) || 0 == desc.dwWidth || 0 == desc.dwHeight) + if ((desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) || !(desc.ddpfPixelFormat.dwFlags & DDPF_RGB)) { return; } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 869bb88..e368c76 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -169,6 +169,7 @@ + @@ -232,6 +233,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 9b7c034..ffec786 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -288,6 +288,9 @@ Header Files\D3dDdi\Log + + Header Files\D3dDdi + @@ -434,6 +437,9 @@ Source Files\D3dDdi\Log + + Source Files\D3dDdi +