diff --git a/source/d3d8to9.hpp b/source/d3d8to9.hpp index c0971f3..7180e63 100644 --- a/source/d3d8to9.hpp +++ b/source/d3d8to9.hpp @@ -161,7 +161,7 @@ class Direct3DDevice8 : public IDirect3DDevice8 private: void ApplyClipPlanes(); - void ReleaseShaders(); + void ReleaseShadersAndStateBlocks(); Direct3D8 *const D3D; IDirect3DDevice9 *const ProxyInterface; @@ -175,8 +175,8 @@ class Direct3DDevice8 : public IDirect3DDevice8 float StoredClipPlanes[MAX_CLIP_PLANES][4] = {}; DWORD ClipPlaneRenderState = 0; - // Store Shader Handles so they can be destroyed later to mirror D3D8 behavior - std::unordered_set PixelShaderHandles, VertexShaderHandles; + // Store Shader Handles and State Block Tokens so they can be destroyed later to mirror D3D8 behavior + std::unordered_set PixelShaderHandles, VertexShaderHandles, StateBlockTokens; unsigned int VertexShaderAndDeclarationCount = 0; }; diff --git a/source/d3d8to9_device.cpp b/source/d3d8to9_device.cpp index e102564..9e9166c 100644 --- a/source/d3d8to9_device.cpp +++ b/source/d3d8to9_device.cpp @@ -56,10 +56,10 @@ ULONG STDMETHODCALLTYPE Direct3DDevice8::Release() // Shaders are destroyed alongside the device that created them in D3D8 but not in D3D9 // so we Release all the shaders when the device releases to mirror that behaviour - if (LastRefCount !=0 && LastRefCount == (VertexShaderAndDeclarationCount + PixelShaderHandles.size())) + if (LastRefCount != 0 && LastRefCount == (VertexShaderAndDeclarationCount + PixelShaderHandles.size() + StateBlockTokens.size())) { ProxyInterface->AddRef(); - ReleaseShaders(); + ReleaseShadersAndStateBlocks(); LastRefCount = ProxyInterface->Release(); assert(LastRefCount == 0); } @@ -783,7 +783,12 @@ HRESULT STDMETHODCALLTYPE Direct3DDevice8::EndStateBlock(DWORD *pToken) if (pToken == nullptr) return D3DERR_INVALIDCALL; - return ProxyInterface->EndStateBlock(reinterpret_cast(pToken)); + HRESULT hr = ProxyInterface->EndStateBlock(reinterpret_cast(pToken)); + + if (SUCCEEDED(hr)) + StateBlockTokens.insert(*pToken); + + return hr; } HRESULT STDMETHODCALLTYPE Direct3DDevice8::ApplyStateBlock(DWORD Token) { @@ -806,6 +811,8 @@ HRESULT STDMETHODCALLTYPE Direct3DDevice8::DeleteStateBlock(DWORD Token) reinterpret_cast(Token)->Release(); + StateBlockTokens.erase(Token); + return D3D_OK; } HRESULT STDMETHODCALLTYPE Direct3DDevice8::CreateStateBlock(D3DSTATEBLOCKTYPE Type, DWORD *pToken) @@ -817,7 +824,12 @@ HRESULT STDMETHODCALLTYPE Direct3DDevice8::CreateStateBlock(D3DSTATEBLOCKTYPE Ty if (pToken == nullptr) return D3DERR_INVALIDCALL; - return ProxyInterface->CreateStateBlock(Type, reinterpret_cast(pToken)); + HRESULT hr = ProxyInterface->CreateStateBlock(Type, reinterpret_cast(pToken)); + + if (SUCCEEDED(hr)) + StateBlockTokens.insert(*pToken); + + return hr; } HRESULT STDMETHODCALLTYPE Direct3DDevice8::SetClipStatus(const D3DCLIPSTATUS8 *pClipStatus) { @@ -2181,7 +2193,7 @@ void Direct3DDevice8::ApplyClipPlanes() } } -void Direct3DDevice8::ReleaseShaders() +void Direct3DDevice8::ReleaseShadersAndStateBlocks() { for (auto Handle : PixelShaderHandles) { @@ -2194,4 +2206,9 @@ void Direct3DDevice8::ReleaseShaders() } VertexShaderHandles.clear(); VertexShaderAndDeclarationCount = 0; + for (auto Token : StateBlockTokens) + { + DeleteStateBlock(Token); + } + StateBlockTokens.clear(); }