From 49b2da36dd08b9b43aee1d6b78065474e438b33c Mon Sep 17 00:00:00 2001 From: WinterSnowfall Date: Sat, 15 Apr 2023 15:21:39 +0300 Subject: [PATCH 1/5] [d3d8] Ignore Release calls on objects with 0 refCount --- src/d3d8/d3d8_device_child.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/d3d8/d3d8_device_child.h b/src/d3d8/d3d8_device_child.h index 8ab23efe5ce..361ab841b96 100644 --- a/src/d3d8/d3d8_device_child.h +++ b/src/d3d8/d3d8_device_child.h @@ -32,6 +32,10 @@ namespace dxvk { } ULONG STDMETHODCALLTYPE Release() { + // ignore Release calls on objects with 0 refCount + if(unlikely(!this->m_refCount)) + return this->m_refCount; + uint32_t refCount = --this->m_refCount; if (unlikely(!refCount)) { auto* pDevice = GetDevice(); From 1705b7a7c56fdf68382cfde91e91a15accf15fb2 Mon Sep 17 00:00:00 2001 From: WinterSnowfall Date: Sat, 15 Apr 2023 15:23:07 +0300 Subject: [PATCH 2/5] [d3d8] Adjust state block texture refcounts --- src/d3d8/d3d8_state_block.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/d3d8/d3d8_state_block.cpp b/src/d3d8/d3d8_state_block.cpp index be2bcd244e9..a36eefe2e84 100644 --- a/src/d3d8/d3d8_state_block.cpp +++ b/src/d3d8/d3d8_state_block.cpp @@ -9,8 +9,12 @@ HRESULT dxvk::D3D8StateBlock::Capture() { if (m_capture.ps) m_device->GetPixelShader(&m_pixelShader); for (DWORD stage = 0; stage < m_textures.size(); stage++) - if (m_capture.textures.get(stage)) + if (m_capture.textures.get(stage)) { m_device->GetTexture(stage, &m_textures[stage]); + // we are adding a needless ref when calling GetTexture, so release it + if(m_textures[stage]) + m_textures[stage]->Release(); + } if (m_capture.indices) m_device->GetIndices(&m_indices, &m_baseVertexIndex); @@ -32,7 +36,7 @@ HRESULT dxvk::D3D8StateBlock::Apply() { for (DWORD stage = 0; stage < m_textures.size(); stage++) if (m_capture.textures.get(stage)) - m_device->SetTexture(stage, m_textures[stage] ); + m_device->SetTexture(stage, m_textures[stage]); if (m_capture.indices) m_device->SetIndices(m_indices, m_baseVertexIndex); From eeb22bc35fad3f02c536114e285974f78987c10e Mon Sep 17 00:00:00 2001 From: WinterSnowfall Date: Sat, 15 Apr 2023 15:28:35 +0300 Subject: [PATCH 3/5] [d3d8] Adjust texture and subresource refcounts --- src/d3d8/d3d8_device.h | 7 +++++-- src/d3d8/d3d8_texture.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/d3d8/d3d8_device.h b/src/d3d8/d3d8_device.h index 81ce708278c..99698304ab1 100644 --- a/src/d3d8/d3d8_device.h +++ b/src/d3d8/d3d8_device.h @@ -567,7 +567,10 @@ namespace dxvk { D3D8Texture2D* tex = static_cast(pTexture); - m_textures[Stage] = ref(tex); + if(unlikely(m_textures[Stage].ptr() == tex)) + return D3D_OK; + + m_textures[Stage] = tex; return GetD3D9()->SetTexture(Stage, D3D8Texture2D::GetD3D9Nullable(tex)); } @@ -854,7 +857,7 @@ namespace dxvk { }; // Remember to fill() these in the constructor! - std::array, d8caps::MAX_TEXTURE_STAGES> m_textures; + std::array, d8caps::MAX_TEXTURE_STAGES> m_textures; std::array m_streams; Com m_indices; diff --git a/src/d3d8/d3d8_texture.h b/src/d3d8/d3d8_texture.h index 97570f322bd..9c1532aac07 100644 --- a/src/d3d8/d3d8_texture.h +++ b/src/d3d8/d3d8_texture.h @@ -103,7 +103,7 @@ namespace dxvk { return ptr; } - std::vector> m_subresources; + std::vector> m_subresources; }; From e26d11c044d62198e3e7d33eff0f46ee1ea1f1c4 Mon Sep 17 00:00:00 2001 From: WinterSnowfall Date: Sat, 15 Apr 2023 15:31:29 +0300 Subject: [PATCH 4/5] [d3d8] Adjust DS and RT refcounts --- src/d3d8/d3d8_blit.cpp | 2 +- src/d3d8/d3d8_device.h | 73 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/d3d8/d3d8_blit.cpp b/src/d3d8/d3d8_blit.cpp index 8a19b89caff..6601a17dfe1 100644 --- a/src/d3d8/d3d8_blit.cpp +++ b/src/d3d8/d3d8_blit.cpp @@ -234,7 +234,7 @@ namespace dxvk { case D3DPOOL_SYSTEMMEM: { // RT (DEFAULT) -> SYSTEMMEM: Use GetRenderTargetData as fast path if possible - if ((srcDesc.Usage & D3DUSAGE_RENDERTARGET || m_renderTarget == src)) { + if ((srcDesc.Usage & D3DUSAGE_RENDERTARGET || m_renderTarget.ptr() == src.ptr())) { // GetRenderTargetData works if the formats and sizes match if (srcDesc.MultiSampleType == d3d9::D3DMULTISAMPLE_NONE diff --git a/src/d3d8/d3d8_device.h b/src/d3d8/d3d8_device.h index 99698304ab1..a5d9332d870 100644 --- a/src/d3d8/d3d8_device.h +++ b/src/d3d8/d3d8_device.h @@ -368,30 +368,76 @@ namespace dxvk { if (pRenderTarget != NULL) { D3D8Surface* surf = static_cast(pRenderTarget); - res = GetD3D9()->SetRenderTarget(0, surf->GetD3D9()); - if (FAILED(res)) return res; + D3DSURFACE_DESC rtDesc; + surf->GetDesc(&rtDesc); + + if (unlikely(!(rtDesc.Usage & D3DUSAGE_RENDERTARGET))) + return D3DERR_INVALIDCALL; + + if(likely(m_renderTarget.ptr() != surf)) { + res = GetD3D9()->SetRenderTarget(0, surf->GetD3D9()); + + if (FAILED(res)) return res; + + D3D8Surface* pRenderTargetSwap = nullptr; + bool isRTSwap = m_renderTargetPrev.ptr() == surf; + + if(unlikely(isRTSwap)) + // keep a temporary ref on the prev RT to prevent its release + pRenderTargetSwap = m_renderTargetPrev.ref(); - m_renderTarget = ref(surf); + m_renderTargetPrev = m_renderTarget; + m_renderTarget = surf; + + if(unlikely(isRTSwap && pRenderTargetSwap)) + pRenderTargetSwap->Release(); + } } // SetDepthStencilSurface is a separate call D3D8Surface* zStencil = static_cast(pNewZStencil); - res = GetD3D9()->SetDepthStencilSurface(D3D8Surface::GetD3D9Nullable(zStencil)); - if (FAILED(res)) return res; + if(pNewZStencil != NULL) { + D3DSURFACE_DESC zsDesc; + zStencil->GetDesc(&zsDesc); - m_depthStencil = ref(zStencil); - return res; + if (unlikely(!(zsDesc.Usage & D3DUSAGE_DEPTHSTENCIL))) + return D3DERR_INVALIDCALL; + } + + if(likely(m_depthStencil.ptr() != zStencil)) { + res = GetD3D9()->SetDepthStencilSurface(D3D8Surface::GetD3D9Nullable(zStencil)); + + if (FAILED(res)) return res; + + D3D8Surface* pDepthStencilSwap = nullptr; + bool isDSSwap = m_depthStencilPrev.ptr() == zStencil; + + if(unlikely(isDSSwap)) + // keep a temporary ref on the prev DS to prevent its release + pDepthStencilSwap = m_depthStencilPrev.ref(); + + m_depthStencilPrev = m_depthStencil; + m_depthStencil = zStencil; + + if(unlikely(isDSSwap && pDepthStencilSwap)) + pDepthStencilSwap->Release(); + } + + return D3D_OK; } HRESULT STDMETHODCALLTYPE GetRenderTarget(IDirect3DSurface8** ppRenderTarget) { + InitReturnPtr(ppRenderTarget); if (unlikely(m_renderTarget == nullptr)) { Com pRT9 = nullptr; HRESULT res = GetD3D9()->GetRenderTarget(0, &pRT9); // use RT index 0 - m_renderTarget = ref(new D3D8Surface(this, std::move(pRT9))); + if(FAILED(res)) return res; + + m_renderTarget = new D3D8Surface(this, std::move(pRT9)); *ppRenderTarget = m_renderTarget.ref(); return res; @@ -402,12 +448,15 @@ namespace dxvk { } HRESULT STDMETHODCALLTYPE GetDepthStencilSurface(IDirect3DSurface8** ppZStencilSurface) { + InitReturnPtr(ppZStencilSurface); if (unlikely(m_depthStencil == nullptr)) { Com pStencil9 = nullptr; HRESULT res = GetD3D9()->GetDepthStencilSurface(&pStencil9); - m_depthStencil = ref(new D3D8Surface(this, std::move(pStencil9))); + if(FAILED(res)) return res; + + m_depthStencil = new D3D8Surface(this, std::move(pStencil9)); *ppZStencilSurface = m_depthStencil.ref(); return res; @@ -834,7 +883,9 @@ namespace dxvk { } m_frontBuffer = nullptr; m_renderTarget = nullptr; + m_renderTargetPrev = nullptr; m_depthStencil = nullptr; + m_depthStencilPrev = nullptr; } friend d3d9::IDirect3DPixelShader9* getPixelShaderPtr(D3D8DeviceEx* device, DWORD Handle); @@ -867,8 +918,10 @@ namespace dxvk { std::vector> m_backBuffers; Com m_frontBuffer; - Com m_renderTarget; + Com m_renderTarget; + Com m_renderTargetPrev; Com m_depthStencil; + Com m_depthStencilPrev; std::vector m_vertexShaders; std::vector m_pixelShaders; From ad97fea9435288ad48d54e42129fe5a2ceb695f4 Mon Sep 17 00:00:00 2001 From: WinterSnowfall Date: Sat, 15 Apr 2023 15:36:46 +0300 Subject: [PATCH 5/5] [d3d8] Adjust VB, IB & backbuffer refcounts --- src/d3d8/d3d8_device.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/d3d8/d3d8_device.h b/src/d3d8/d3d8_device.h index a5d9332d870..c042d2ef185 100644 --- a/src/d3d8/d3d8_device.h +++ b/src/d3d8/d3d8_device.h @@ -151,6 +151,7 @@ namespace dxvk { UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface8** ppBackBuffer) { + InitReturnPtr(ppBackBuffer); if (iBackBuffer >= m_backBuffers.size() || m_backBuffers[iBackBuffer] == nullptr) { Com pSurface9; @@ -158,7 +159,7 @@ namespace dxvk { if (FAILED(res)) return res; - m_backBuffers[iBackBuffer] = ref(new D3D8Surface(this, std::move(pSurface9))); + m_backBuffers[iBackBuffer] = new D3D8Surface(this, std::move(pSurface9)); *ppBackBuffer = m_backBuffers[iBackBuffer].ref(); return res; @@ -821,8 +822,11 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE GetIndices( IDirect3DIndexBuffer8** ppIndexData, UINT* pBaseVertexIndex) { + InitReturnPtr(ppIndexData); + *ppIndexData = m_indices.ptr(); *pBaseVertexIndex = m_baseVertexIndex; + return D3D_OK; } @@ -881,7 +885,6 @@ namespace dxvk { for (UINT i = 0; i < m_presentParams.BackBufferCount; i++) { m_backBuffers.push_back(nullptr); } - m_frontBuffer = nullptr; m_renderTarget = nullptr; m_renderTargetPrev = nullptr; m_depthStencil = nullptr; @@ -903,20 +906,19 @@ namespace dxvk { D3D8StateBlock* m_recorder = nullptr; struct D3D8VBO { - Com buffer = nullptr; - UINT stride = 0; + Com buffer = nullptr; + UINT stride = 0; }; // Remember to fill() these in the constructor! std::array, d8caps::MAX_TEXTURE_STAGES> m_textures; std::array m_streams; - Com m_indices; - INT m_baseVertexIndex = 0; + Com m_indices; + INT m_baseVertexIndex = 0; // TODO: Which of these should be a private ref std::vector> m_backBuffers; - Com m_frontBuffer; Com m_renderTarget; Com m_renderTargetPrev;