From 86165b7fd1ef890bc597072ed7ff86cc02b3a260 Mon Sep 17 00:00:00 2001 From: WinterSnowfall Date: Sun, 26 Mar 2023 22:31:47 +0300 Subject: [PATCH] [d3d8] RefCount refactoring --- src/d3d8/d3d8_blit.cpp | 2 +- src/d3d8/d3d8_device.h | 101 ++++++++++++++++++++++++++-------- src/d3d8/d3d8_device_child.h | 4 ++ src/d3d8/d3d8_state_block.cpp | 7 ++- src/d3d8/d3d8_texture.h | 2 +- 5 files changed, 90 insertions(+), 26 deletions(-) diff --git a/src/d3d8/d3d8_blit.cpp b/src/d3d8/d3d8_blit.cpp index 8a19b89caff3..6601a17dfe18 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 81ce708278ca..756f22cb0732 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; @@ -368,30 +369,62 @@ 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; - m_renderTarget = ref(surf); + // keep a temporary ref on the prev RT, since this could be a swap + D3D8Surface* pRenderTargetSwap = m_renderTargetPrev.ref(); + m_renderTargetPrev = m_renderTarget; + m_renderTarget = surf; + SAFE_RELEASE(pRenderTargetSwap); + } } // 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; + + // keep a temporary ref on the prev DS, since this could be a swap + D3D8Surface* pDepthStencilSwap = m_depthStencilPrev.ref(); + m_depthStencilPrev = m_depthStencil; + m_depthStencil = zStencil; + SAFE_RELEASE(pDepthStencilSwap); + } + + 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 +435,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; @@ -567,9 +603,13 @@ namespace dxvk { D3D8Texture2D* tex = static_cast(pTexture); - m_textures[Stage] = ref(tex); + if(likely(m_textures[Stage].ptr() != tex)) { + m_textures[Stage] = tex; + + return GetD3D9()->SetTexture(Stage, D3D8Texture2D::GetD3D9Nullable(tex)); + } - return GetD3D9()->SetTexture(Stage, D3D8Texture2D::GetD3D9Nullable(tex)); + return D3D_OK; } HRESULT STDMETHODCALLTYPE GetTextureStageState( @@ -723,9 +763,15 @@ namespace dxvk { D3D8VertexBuffer* buffer = static_cast(pStreamData); - m_streams[StreamNumber] = D3D8VBO {buffer, Stride}; + const D3D8VBO& vbo = m_streams[StreamNumber]; + + if(likely(vbo.buffer.ptr() != buffer || vbo.stride != Stride)) { + m_streams[StreamNumber] = D3D8VBO {buffer, Stride}; + + return GetD3D9()->SetStreamSource(StreamNumber, D3D8VertexBuffer::GetD3D9Nullable(buffer), 0, Stride); + } - return GetD3D9()->SetStreamSource(StreamNumber, D3D8VertexBuffer::GetD3D9Nullable(buffer), 0, Stride); + return D3D_OK; } HRESULT STDMETHODCALLTYPE GetStreamSource( @@ -761,16 +807,23 @@ namespace dxvk { D3D8IndexBuffer* buffer = static_cast(pIndexData); - m_indices = buffer; + if(likely(m_indices.ptr() != buffer)) { + m_indices = buffer; + + return GetD3D9()->SetIndices(D3D8IndexBuffer::GetD3D9Nullable(buffer)); + } - return GetD3D9()->SetIndices(D3D8IndexBuffer::GetD3D9Nullable(buffer)); + return D3D_OK; } HRESULT STDMETHODCALLTYPE GetIndices( IDirect3DIndexBuffer8** ppIndexData, UINT* pBaseVertexIndex) { + InitReturnPtr(ppIndexData); + *ppIndexData = m_indices.ptr(); *pBaseVertexIndex = m_baseVertexIndex; + return D3D_OK; } @@ -831,7 +884,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); @@ -849,23 +904,25 @@ 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, 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_renderTarget; + Com m_renderTargetPrev; Com m_depthStencil; + Com m_depthStencilPrev; std::vector m_vertexShaders; std::vector m_pixelShaders; diff --git a/src/d3d8/d3d8_device_child.h b/src/d3d8/d3d8_device_child.h index 8ab23efe5ce5..361ab841b96d 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(); diff --git a/src/d3d8/d3d8_state_block.cpp b/src/d3d8/d3d8_state_block.cpp index be2bcd244e9d..b7e065b2ff98 100644 --- a/src/d3d8/d3d8_state_block.cpp +++ b/src/d3d8/d3d8_state_block.cpp @@ -9,8 +9,11 @@ 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 + SAFE_RELEASE(m_textures[stage]); + } if (m_capture.indices) m_device->GetIndices(&m_indices, &m_baseVertexIndex); @@ -32,7 +35,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); diff --git a/src/d3d8/d3d8_texture.h b/src/d3d8/d3d8_texture.h index 97570f322bd1..9c1532aac077 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; };