From c6a9be6df55d5a9ec9dfe8eee1bc6f386388b6ca Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 13 Oct 2016 11:53:06 +0200 Subject: [PATCH] Add proper refcounting to wrapped D3D9 device --- renderdoc/driver/d3d9/d3d9_common.cpp | 58 ++++++++++++++ renderdoc/driver/d3d9/d3d9_common.h | 79 +++++++++++++++++++ renderdoc/driver/d3d9/d3d9_debug.cpp | 4 +- renderdoc/driver/d3d9/d3d9_debug.h | 2 +- renderdoc/driver/d3d9/d3d9_device.cpp | 76 ++++++++++++------ renderdoc/driver/d3d9/d3d9_device.h | 30 +++++-- renderdoc/driver/d3d9/renderdoc_d3d9.vcxproj | 2 + .../d3d9/renderdoc_d3d9.vcxproj.filters | 6 ++ 8 files changed, 224 insertions(+), 33 deletions(-) create mode 100644 renderdoc/driver/d3d9/d3d9_common.cpp create mode 100644 renderdoc/driver/d3d9/d3d9_common.h diff --git a/renderdoc/driver/d3d9/d3d9_common.cpp b/renderdoc/driver/d3d9/d3d9_common.cpp new file mode 100644 index 000000000..1dabb0f16 --- /dev/null +++ b/renderdoc/driver/d3d9/d3d9_common.cpp @@ -0,0 +1,58 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "d3d9_common.h" +#include "d3d9_device.h" + +unsigned int RefCounter9::SoftRef(WrappedD3DDevice9 *device) +{ + unsigned int ret = AddRef(); + if(device) + device->SoftRef(); + else + RDCWARN("No device pointer, is a deleted resource being AddRef()d?"); + return ret; +} + +unsigned int RefCounter9::SoftRelease(WrappedD3DDevice9 *device) +{ + unsigned int ret = Release(); + if(device) + device->SoftRelease(); + else + RDCWARN("No device pointer, is a deleted resource being Release()d?"); + return ret; +} + +void RefCounter9::AddDeviceSoftref(WrappedD3DDevice9 *device) +{ + if(device) + device->SoftRef(); +} + +void RefCounter9::ReleaseDeviceSoftref(WrappedD3DDevice9 *device) +{ + if(device) + device->SoftRelease(); +} diff --git a/renderdoc/driver/d3d9/d3d9_common.h b/renderdoc/driver/d3d9/d3d9_common.h new file mode 100644 index 000000000..ba55311e3 --- /dev/null +++ b/renderdoc/driver/d3d9/d3d9_common.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include "api/replay/renderdoc_replay.h" +#include "core/core.h" +#include "driver/dx/official/d3d9.h" + +class WrappedD3DDevice9; + +class RefCounter9 +{ +private: + IUnknown *m_pReal; + unsigned int m_iRefcount; + bool m_SelfDeleting; + +protected: + void SetSelfDeleting(bool selfDelete) { m_SelfDeleting = selfDelete; } + // used for derived classes that need to soft ref but are handling their + // own self-deletion + static void AddDeviceSoftref(WrappedD3DDevice9 *device); + static void ReleaseDeviceSoftref(WrappedD3DDevice9 *device); + +public: + RefCounter9(IUnknown *real, bool selfDelete = true) + : m_pReal(real), m_iRefcount(1), m_SelfDeleting(selfDelete) + { + } + virtual ~RefCounter9() {} + unsigned int GetRefCount() { return m_iRefcount; } + ////////////////////////////// + // implement IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface( + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + __RPC__deref_out void **ppvObject) + { + return E_NOINTERFACE; + } + + ULONG STDMETHODCALLTYPE AddRef() + { + InterlockedIncrement(&m_iRefcount); + return m_iRefcount; + } + ULONG STDMETHODCALLTYPE Release() + { + unsigned int ret = InterlockedDecrement(&m_iRefcount); + if(ret == 0 && m_SelfDeleting) + delete this; + return ret; + } + + unsigned int SoftRef(WrappedD3DDevice9 *device); + unsigned int SoftRelease(WrappedD3DDevice9 *device); +}; diff --git a/renderdoc/driver/d3d9/d3d9_debug.cpp b/renderdoc/driver/d3d9/d3d9_debug.cpp index ffebec66f..370a43841 100644 --- a/renderdoc/driver/d3d9/d3d9_debug.cpp +++ b/renderdoc/driver/d3d9/d3d9_debug.cpp @@ -186,8 +186,8 @@ void D3D9DebugManager::RenderTextInternal(float x, float y, const char *text) res |= m_WrappedDevice->SetTransform(D3DTS_VIEW, &identity); // enable fixed function pipeline - res |= m_WrappedDevice->SetVertexShader(nullptr); - res |= m_WrappedDevice->SetPixelShader(nullptr); + res |= m_WrappedDevice->SetVertexShader(NULL); + res |= m_WrappedDevice->SetPixelShader(NULL); // default render states res |= m_WrappedDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); diff --git a/renderdoc/driver/d3d9/d3d9_debug.h b/renderdoc/driver/d3d9/d3d9_debug.h index 98fcdcd1e..3989931fb 100644 --- a/renderdoc/driver/d3d9/d3d9_debug.h +++ b/renderdoc/driver/d3d9/d3d9_debug.h @@ -27,9 +27,9 @@ #include #include #include -#include "common/common.h" #include "driver/dx/official/d3d9.h" #include "stb/stb_truetype.h" +#include "d3d9_common.h" #include "d3d9_device.h" class D3D9DebugManager diff --git a/renderdoc/driver/d3d9/d3d9_device.cpp b/renderdoc/driver/d3d9/d3d9_device.cpp index 8a9a10dcb..c58b5af43 100644 --- a/renderdoc/driver/d3d9/d3d9_device.cpp +++ b/renderdoc/driver/d3d9/d3d9_device.cpp @@ -24,18 +24,67 @@ #include "d3d9_device.h" #include "core/core.h" +#include "serialise/serialiser.h" #include "d3d9_debug.h" -#include "windows.h" // TODO investigate how else this can be solved WrappedD3DDevice9::WrappedD3DDevice9(IDirect3DDevice9 *device) - : m_device(device), m_DebugManager(nullptr) + : m_RefCounter(device, false), + m_SoftRefCounter(NULL, false), + m_device(device), + m_DebugManager(NULL) { m_FrameCounter = 0; + + // refcounters implicitly construct with one reference, but we don't start with any soft + // references. + m_SoftRefCounter.Release(); + m_InternalRefcount = 0; + m_Alive = true; +} + +void WrappedD3DDevice9::CheckForDeath() +{ + if(!m_Alive) + return; + + if(m_RefCounter.GetRefCount() == 0) + { + RDCASSERT(m_SoftRefCounter.GetRefCount() >= m_InternalRefcount); + + if(m_SoftRefCounter.GetRefCount() <= m_InternalRefcount) + { + m_Alive = false; + delete this; + } + } } WrappedD3DDevice9::~WrappedD3DDevice9() { SAFE_DELETE(m_DebugManager); + + SAFE_RELEASE(m_device); +} + +HRESULT WrappedD3DDevice9::QueryInterface(REFIID riid, void **ppvObject) +{ + // RenderDoc UUID {A7AA6116-9C8D-4BBA-9083-B4D816B71B78} + static const GUID IRenderDoc_uuid = { + 0xa7aa6116, 0x9c8d, 0x4bba, {0x90, 0x83, 0xb4, 0xd8, 0x16, 0xb7, 0x1b, 0x78}}; + + if(riid == IRenderDoc_uuid) + { + AddRef(); + *ppvObject = (IUnknown *)this; + return S_OK; + } + else + { + string guid = ToStr::Get(riid); + RDCWARN("Querying IDirect3DDevice9 for interface: %s", guid.c_str()); + } + + return m_device->QueryInterface(riid, ppvObject); } void WrappedD3DDevice9::LazyInit() @@ -43,29 +92,6 @@ void WrappedD3DDevice9::LazyInit() m_DebugManager = new D3D9DebugManager(this); } -HRESULT __stdcall WrappedD3DDevice9::QueryInterface(REFIID riid, void **ppvObj) -{ - return m_device->QueryInterface(riid, ppvObj); -} - -ULONG __stdcall WrappedD3DDevice9::AddRef() -{ - ULONG refCount; - refCount = m_device->AddRef(); - return refCount; -} - -ULONG __stdcall WrappedD3DDevice9::Release() -{ - ULONG refCount; - refCount = m_device->Release(); - if(refCount == 0) - { - delete this; - } - return refCount; -} - HRESULT __stdcall WrappedD3DDevice9::TestCooperativeLevel() { return m_device->TestCooperativeLevel(); diff --git a/renderdoc/driver/d3d9/d3d9_device.h b/renderdoc/driver/d3d9/d3d9_device.h index aa0435f11..5c6f8f2fa 100644 --- a/renderdoc/driver/d3d9/d3d9_device.h +++ b/renderdoc/driver/d3d9/d3d9_device.h @@ -23,9 +23,8 @@ ******************************************************************************/ #pragma once -#include "common/common.h" #include "common/timing.h" -#include "driver/dx/official/d3d9.h" +#include "d3d9_common.h" class D3D9DebugManager; @@ -37,11 +36,25 @@ public: void LazyInit(); + void InternalRef() { InterlockedIncrement(&m_InternalRefcount); } + void InternalRelease() { InterlockedDecrement(&m_InternalRefcount); } + void SoftRef() { m_SoftRefCounter.AddRef(); } + void SoftRelease() + { + m_SoftRefCounter.Release(); + CheckForDeath(); + } + D3D9DebugManager *GetDebugManager() { return m_DebugManager; } /*** IUnknown methods ***/ - virtual HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObj); - virtual ULONG __stdcall AddRef(); - virtual ULONG __stdcall Release(); + ULONG STDMETHODCALLTYPE AddRef() { return m_RefCounter.AddRef(); } + ULONG STDMETHODCALLTYPE Release() + { + unsigned int ret = m_RefCounter.Release(); + CheckForDeath(); + return ret; + } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); /*** IDirect3DDevice9 methods ***/ virtual HRESULT __stdcall TestCooperativeLevel(); @@ -229,9 +242,16 @@ public: virtual HRESULT __stdcall CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9 **ppQuery); private: + void CheckForDeath(); + IDirect3DDevice9 *m_device; D3D9DebugManager *m_DebugManager; + unsigned int m_InternalRefcount; + RefCounter9 m_RefCounter; + RefCounter9 m_SoftRefCounter; + bool m_Alive; + uint32_t m_FrameCounter; }; diff --git a/renderdoc/driver/d3d9/renderdoc_d3d9.vcxproj b/renderdoc/driver/d3d9/renderdoc_d3d9.vcxproj index bba11d021..e4e59fa4c 100644 --- a/renderdoc/driver/d3d9/renderdoc_d3d9.vcxproj +++ b/renderdoc/driver/d3d9/renderdoc_d3d9.vcxproj @@ -184,6 +184,7 @@ + @@ -194,6 +195,7 @@ + diff --git a/renderdoc/driver/d3d9/renderdoc_d3d9.vcxproj.filters b/renderdoc/driver/d3d9/renderdoc_d3d9.vcxproj.filters index 723ee69bc..5c72514b2 100644 --- a/renderdoc/driver/d3d9/renderdoc_d3d9.vcxproj.filters +++ b/renderdoc/driver/d3d9/renderdoc_d3d9.vcxproj.filters @@ -24,6 +24,9 @@ Common + + Common + @@ -47,5 +50,8 @@ Common + + Common + \ No newline at end of file