diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index f0a692655..e9920b2be 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -256,22 +256,46 @@ void BarrierSet::Unapply(ID3D12GraphicsCommandListX *list) RDCASSERT(newToOldBarriers.empty()); } -bool EnableD3D12DebugLayer(PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface) +bool EnableD3D12DebugLayer(D3D12DevConfiguration *devConfig, + PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface) { - if(!getDebugInterface) - getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(GetModuleHandleA("d3d12.dll"), - "D3D12GetDebugInterface"); - - if(!getDebugInterface) + ID3D12Debug *debug = NULL; + if(devConfig) { - RDCERR("Couldn't find D3D12GetDebugInterface!"); - return false; + if(devConfig->debug) + { + debug = devConfig->debug; + debug->AddRef(); + } + } + else + { + if(!getDebugInterface) + getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress( + GetModuleHandleA("d3d12.dll"), "D3D12GetDebugInterface"); + + if(!getDebugInterface) + { + RDCERR("Couldn't find D3D12GetDebugInterface!"); + return false; + } + + HRESULT hr = getDebugInterface(__uuidof(ID3D12Debug), (void **)&debug); + + if(FAILED(hr)) + SAFE_RELEASE(debug); + + if(hr == DXGI_ERROR_SDK_COMPONENT_MISSING) + { + RDCWARN("Debug layer not available: DXGI_ERROR_SDK_COMPONENT_MISSING"); + } + else if(FAILED(hr)) + { + RDCERR("Couldn't enable debug layer: %x", hr); + } } - ID3D12Debug *debug = NULL; - HRESULT hr = getDebugInterface(__uuidof(ID3D12Debug), (void **)&debug); - - if(SUCCEEDED(hr) && debug) + if(debug) { debug->EnableDebugLayer(); @@ -298,14 +322,6 @@ bool EnableD3D12DebugLayer(PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface) return true; } - else if(hr == DXGI_ERROR_SDK_COMPONENT_MISSING) - { - RDCWARN("Debug layer not available: DXGI_ERROR_SDK_COMPONENT_MISSING"); - } - else - { - RDCERR("Couldn't enable debug layer: %x", hr); - } return false; } diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index 4c547bc74..9de46b217 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -56,11 +56,21 @@ struct D3D12MarkerRegion ID3D12CommandQueue *queue = NULL; }; -bool EnableD3D12DebugLayer(PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface = NULL); +struct D3D12DevConfiguration +{ + ID3D12SDKConfiguration1 *sdkconfig = NULL; + ID3D12DeviceFactory *devfactory = NULL; + ID3D12DeviceConfiguration *devconfig = NULL; + ID3D12Debug *debug = NULL; +}; + +bool EnableD3D12DebugLayer(D3D12DevConfiguration *devConfig, + PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface); HRESULT EnumAdapterByLuid(IDXGIFactory1 *factory, LUID luid, IDXGIAdapter **pAdapter); -void D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, bytebuf d3d12core, - bytebuf d3d12sdklayers, HMODULE d3d12lib); +D3D12DevConfiguration *D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, + bytebuf d3d12core, bytebuf d3d12sdklayers, + HMODULE d3d12lib); void D3D12_CleanupReplaySDK(); inline void SetObjName(ID3D12Object *obj, const rdcstr &utf8name) @@ -335,6 +345,87 @@ public: } }; +class WrappedID3D12DeviceConfiguration : public ID3D12DeviceConfiguration +{ +private: + ID3D12DeviceConfiguration *m_pReal = NULL; + IUnknown *wrappedParent = NULL; +public: + WrappedID3D12DeviceConfiguration(IUnknown *real, IUnknown *wrapped) + { + wrappedParent = wrapped; + + if(real) + { + HRESULT hr = real->QueryInterface(__uuidof(ID3D12DeviceConfiguration), (void **)&m_pReal); + if(FAILED(hr)) + SAFE_RELEASE(m_pReal); + } + } + + ~WrappedID3D12DeviceConfiguration() { SAFE_RELEASE(m_pReal); } + + bool IsValid() { return m_pReal != NULL; } + + ////////////////////////////// + // Implement IUnknown + ULONG STDMETHODCALLTYPE AddRef() { return wrappedParent->AddRef(); } + ULONG STDMETHODCALLTYPE Release() { return wrappedParent->Release(); } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(IUnknown)) + { + *ppvObject = (IUnknown *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(ID3D12DeviceConfiguration) && m_pReal) + { + *ppvObject = (ID3D12DeviceConfiguration *)this; + AddRef(); + return S_OK; + } + + return wrappedParent->QueryInterface(riid, ppvObject); + } + + ////////////////////////////// + // Implement ID3D12DeviceConfiguration +#if defined(_MSC_VER) || !defined(_WIN32) + virtual D3D12_DEVICE_CONFIGURATION_DESC STDMETHODCALLTYPE GetDesc(void) + { + return m_pReal->GetDesc(); + } +#else + virtual D3D12_DEVICE_CONFIGURATION_DESC *STDMETHODCALLTYPE + GetDesc(D3D12_DEVICE_CONFIGURATION_DESC *RetVal) + { + return m_pReal->GetDesc(RetVal); + } +#endif + + virtual HRESULT STDMETHODCALLTYPE GetEnabledExperimentalFeatures(_Out_writes_(NumGuids) + GUID *pGuids, + UINT NumGuids) + { + return m_pReal->GetEnabledExperimentalFeatures(pGuids, NumGuids); + } + + virtual HRESULT STDMETHODCALLTYPE SerializeVersionedRootSignature( + _In_ const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *pDesc, _COM_Outptr_ ID3DBlob **ppResult, + _Always_(_Outptr_opt_result_maybenull_) ID3DBlob **ppError) + { + return m_pReal->SerializeVersionedRootSignature(pDesc, ppResult, ppError); + } + + virtual HRESULT STDMETHODCALLTYPE + CreateVersionedRootSignatureDeserializer(_In_reads_bytes_(Size) const void *pBlob, SIZE_T Size, + REFIID riid, _COM_Outptr_ void **ppvDeserializer) + { + return m_pReal->CreateVersionedRootSignatureDeserializer(pBlob, Size, riid, ppvDeserializer); + } +}; + struct D3D12RootSignatureParameter : D3D12_ROOT_PARAMETER1 { D3D12RootSignatureParameter() diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index 8cbf2559e..9ee51ba7f 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -65,6 +65,13 @@ rdcstr WrappedID3D12Device::GetChunkName(uint32_t idx) return ToStr((D3D12Chunk)idx); } +D3D12ShaderCache *WrappedID3D12Device::GetShaderCache() +{ + if(m_ShaderCache == NULL) + m_ShaderCache = new D3D12ShaderCache(this); + return m_ShaderCache; +} + D3D12DebugManager *WrappedID3D12Device::GetDebugManager() { return m_Replay->GetDebugManager(); @@ -504,6 +511,7 @@ BOOL STDMETHODCALLTYPE WrappedAGS12::ExtensionsSupported() WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitParams params, bool enabledDebugLayer) : m_RefCounter(realDevice, false), + m_DevConfig(realDevice, this), m_SoftRefCounter(NULL, false), m_pDevice(realDevice), m_debugLayerEnabled(enabledDebugLayer), @@ -1222,6 +1230,17 @@ HRESULT WrappedID3D12Device::QueryInterface(REFIID riid, void **ppvObject) return E_NOINTERFACE; } } + else if(riid == __uuidof(ID3D12DeviceConfiguration)) + { + if(m_DevConfig.IsValid()) + { + *ppvObject = (ID3D12DeviceConfiguration *)&m_DevConfig; + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; + } else if(riid == __uuidof(ID3D12DeviceDownlevel)) { if(m_pDownlevel) @@ -4116,8 +4135,7 @@ void WrappedID3D12Device::CreateInternalResources() m_GPUSyncCounter = 0; - if(m_ShaderCache == NULL) - m_ShaderCache = new D3D12ShaderCache(this); + GetShaderCache()->SetDevConfiguration(m_Replay->GetDevConfiguration()); if(m_TextRenderer == NULL) m_TextRenderer = new D3D12TextRenderer(this); diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index ea250f7d4..97de14b41 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -606,6 +606,8 @@ private: ID3D12Device12 *m_pDevice12; ID3D12DeviceDownlevel *m_pDownlevel; + WrappedID3D12DeviceConfiguration m_DevConfig; + // list of all queues being captured rdcarray m_Queues; rdcarray m_QueueFences; @@ -886,7 +888,7 @@ public: ID3D12Device9 *GetReal9() const { return m_pDevice9; } static rdcstr GetChunkName(uint32_t idx); D3D12ResourceManager *GetResourceManager() { return m_ResourceManager; } - D3D12ShaderCache *GetShaderCache() { return m_ShaderCache; } + D3D12ShaderCache *GetShaderCache(); D3D12DebugManager *GetDebugManager(); ResourceId GetResourceID() { return m_ResourceID; } Threading::RWLock &GetCapTransitionLock() { return m_CapTransitionLock; } diff --git a/renderdoc/driver/d3d12/d3d12_hooks.cpp b/renderdoc/driver/d3d12/d3d12_hooks.cpp index 1b9877048..cc2d428f9 100644 --- a/renderdoc/driver/d3d12/d3d12_hooks.cpp +++ b/renderdoc/driver/d3d12/d3d12_hooks.cpp @@ -192,6 +192,297 @@ public: virtual void STDMETHODCALLTYPE SetForceLegacyBarrierValidation(BOOL Enable) {} }; +class WrappedID3D12Tools : public RefCounter12, public ID3D12Tools +{ + BOOL m_Instrumentation = FALSE; +public: + WrappedID3D12Tools() : RefCounter12(NULL) {} + virtual ~WrappedID3D12Tools() {} + ////////////////////////////// + // Implement IUnknown + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter12::AddRef(); } + ULONG STDMETHODCALLTYPE Release() { return RefCounter12::Release(); } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(IUnknown)) + { + *ppvObject = (IUnknown *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(ID3D12Tools)) + { + *ppvObject = (ID3D12Tools *)this; + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; + } + + ////////////////////////////// + // Implement ID3D12Tools + virtual void STDMETHODCALLTYPE EnableShaderInstrumentation(BOOL bEnable) + { + m_Instrumentation = bEnable; + } + + virtual BOOL STDMETHODCALLTYPE ShaderInstrumentationEnabled(void) { return m_Instrumentation; } +}; + +class WrappedID3D12DeviceRemovedExtendedData : public RefCounter12, + public ID3D12DeviceRemovedExtendedData1 +{ +public: + WrappedID3D12DeviceRemovedExtendedData() : RefCounter12(NULL) {} + virtual ~WrappedID3D12DeviceRemovedExtendedData() {} + ////////////////////////////// + // Implement IUnknown + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter12::AddRef(); } + ULONG STDMETHODCALLTYPE Release() { return RefCounter12::Release(); } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(IUnknown)) + { + *ppvObject = (IUnknown *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(ID3D12DeviceRemovedExtendedData)) + { + *ppvObject = (ID3D12DeviceRemovedExtendedData *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(ID3D12DeviceRemovedExtendedData1)) + { + *ppvObject = (ID3D12DeviceRemovedExtendedData1 *)this; + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; + } + + ////////////////////////////// + // Implement ID3D12DeviceRemovedExtendedData + virtual HRESULT STDMETHODCALLTYPE + GetAutoBreadcrumbsOutput(_Out_ D3D12_DRED_AUTO_BREADCRUMBS_OUTPUT *pOutput) + { + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + } + + virtual HRESULT STDMETHODCALLTYPE + GetPageFaultAllocationOutput(_Out_ D3D12_DRED_PAGE_FAULT_OUTPUT *pOutput) + { + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + } + + ////////////////////////////// + // Implement ID3D12DeviceRemovedExtendedData1 + virtual HRESULT STDMETHODCALLTYPE + GetAutoBreadcrumbsOutput1(_Out_ D3D12_DRED_AUTO_BREADCRUMBS_OUTPUT1 *pOutput) + { + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + } + + virtual HRESULT STDMETHODCALLTYPE + GetPageFaultAllocationOutput1(_Out_ D3D12_DRED_PAGE_FAULT_OUTPUT1 *pOutput) + { + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + } +}; + +class WrappedID3D12DeviceFactory : public RefCounter12, public ID3D12DeviceFactory +{ + WrappedID3D12DeviceConfiguration config; +public: + WrappedID3D12DeviceFactory(ID3D12DeviceFactory *real) : RefCounter12(real), config(real, this) {} + + virtual ~WrappedID3D12DeviceFactory() {} + ////////////////////////////// + // Implement IUnknown + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter12::AddRef(); } + ULONG STDMETHODCALLTYPE Release() { return RefCounter12::Release(); } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(IUnknown)) + { + *ppvObject = (IUnknown *)(ID3D12DeviceFactory *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(ID3D12DeviceFactory)) + { + *ppvObject = (ID3D12DeviceFactory *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(ID3D12DeviceConfiguration) && config.IsValid()) + { + *ppvObject = (ID3D12DeviceConfiguration *)&config; + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; + } + + ////////////////////////////// + // Implement ID3D12DeviceFactory + + virtual HRESULT STDMETHODCALLTYPE InitializeFromGlobalState(void) + { + return m_pReal->InitializeFromGlobalState(); + } + + virtual HRESULT STDMETHODCALLTYPE ApplyToGlobalState(void) + { + return m_pReal->ApplyToGlobalState(); + } + + virtual HRESULT STDMETHODCALLTYPE SetFlags(D3D12_DEVICE_FACTORY_FLAGS flags) + { + return m_pReal->SetFlags(flags); + } + + virtual D3D12_DEVICE_FACTORY_FLAGS STDMETHODCALLTYPE GetFlags(void) + { + return m_pReal->GetFlags(); + } + + virtual HRESULT STDMETHODCALLTYPE GetConfigurationInterface(REFCLSID clsid, REFIID iid, + _COM_Outptr_ void **ppv); + + virtual HRESULT STDMETHODCALLTYPE + EnableExperimentalFeatures(UINT NumFeatures, _In_reads_(NumFeatures) const IID *pIIDs, + _In_reads_opt_(NumFeatures) void *pConfigurationStructs, + _In_reads_opt_(NumFeatures) UINT *pConfigurationStructSizes) + { + rdcarray allowedIIDs; + + // allow enabling unsigned DXIL. + for(UINT i = 0; i < NumFeatures; i++) + { + if(pIIDs[i] == D3D12ExperimentalShaderModels) + allowedIIDs.push_back(D3D12ExperimentalShaderModels); + } + + // there's no "partially successful" error code, so we just lie to the application and pretend + // that any filtered IIDs also succeeded + if(!allowedIIDs.empty()) + return m_pReal->EnableExperimentalFeatures((UINT)allowedIIDs.size(), allowedIIDs.data(), NULL, + NULL); + + // header says "The call returns E_NOINTERFACE if an unrecognized feature is passed in or + // Windows Developer mode is not on." so this is the most appropriate error for if no IIDs are + // allowed. + return E_NOINTERFACE; + } + + virtual HRESULT STDMETHODCALLTYPE CreateDevice(_In_opt_ IUnknown *adapter, + D3D_FEATURE_LEVEL FeatureLevel, REFIID riid, + _COM_Outptr_opt_ void **ppvDevice) + { + if(RenderDoc::Inst().GetCaptureOptions().apiValidation) + { + D3D12DevConfiguration tmpConfig = {}; + HRESULT hr = m_pReal->GetConfigurationInterface(CLSID_D3D12Debug, __uuidof(ID3D12Debug), + (void **)&tmpConfig.debug); + if(SUCCEEDED(hr)) + { + EnableD3D12DebugLayer(&tmpConfig, NULL); + SAFE_RELEASE(tmpConfig.debug); + } + } + + return CreateD3D12_Internal( + [this](IUnknown *pAdapter, D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid, + void **ppDevice) { + return m_pReal->CreateDevice(pAdapter, MinimumFeatureLevel, riid, ppDevice); + }, + adapter, FeatureLevel, riid, ppvDevice); + } +}; + +class WrappedID3D12SDKConfiguration : public RefCounter12, + public ID3D12SDKConfiguration1 +{ + ID3D12SDKConfiguration1 *m_pReal1 = NULL; +public: + WrappedID3D12SDKConfiguration(ID3D12SDKConfiguration *real, ID3D12SDKConfiguration1 *real1) + : RefCounter12(real) + { + if(!real1) + real->QueryInterface(__uuidof(ID3D12SDKConfiguration1), (void **)&real1); + m_pReal1 = real1; + } + virtual ~WrappedID3D12SDKConfiguration() + { + SAFE_RELEASE(m_pReal); + SAFE_RELEASE(m_pReal1); + } + ////////////////////////////// + // Implement IUnknown + ULONG STDMETHODCALLTYPE AddRef() { return RefCounter12::AddRef(); } + ULONG STDMETHODCALLTYPE Release() { return RefCounter12::Release(); } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(IUnknown)) + { + *ppvObject = (IUnknown *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(ID3D12SDKConfiguration)) + { + *ppvObject = (ID3D12SDKConfiguration *)this; + AddRef(); + return S_OK; + } + if(riid == __uuidof(ID3D12SDKConfiguration1)) + { + *ppvObject = (ID3D12SDKConfiguration1 *)this; + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; + } + + ////////////////////////////// + // Implement ID3D12SDKConfiguration + virtual HRESULT STDMETHODCALLTYPE SetSDKVersion(UINT SDKVersion, _In_z_ LPCSTR SDKPath) + { + return m_pReal->SetSDKVersion(SDKVersion, SDKPath); + } + + ////////////////////////////// + // Implement ID3D12SDKConfiguration1 + virtual HRESULT STDMETHODCALLTYPE CreateDeviceFactory(UINT SDKVersion, _In_ LPCSTR SDKPath, + REFIID riid, _COM_Outptr_ void **ppvFactory) + { + if(riid != __uuidof(ID3D12DeviceFactory)) + { + RDCERR("Unexpected uuid to CreateDeviceFactory: %s", ToStr(riid).c_str()); + return E_NOINTERFACE; + } + + ID3D12DeviceFactory *realFactory = NULL; + HRESULT hr = m_pReal1->CreateDeviceFactory(SDKVersion, SDKPath, riid, (void **)&realFactory); + if(SUCCEEDED(hr)) + { + RDCASSERT(realFactory); + *ppvFactory = (ID3D12DeviceFactory *)(new WrappedID3D12DeviceFactory(realFactory)); + return hr; + } + SAFE_RELEASE(realFactory); + return hr; + } + + virtual void STDMETHODCALLTYPE FreeUnusedSDKs(void) { return m_pReal1->FreeUnusedSDKs(); } +}; + class D3D12Hook : LibraryHook { public: @@ -212,6 +503,7 @@ public: CreateDevice.Register("d3d12.dll", "D3D12CreateDevice", D3D12CreateDevice_hook); GetDebugInterface.Register("d3d12.dll", "D3D12GetDebugInterface", D3D12GetDebugInterface_hook); + GetInterface.Register("d3d12.dll", "D3D12GetInterface", D3D12GetInterface_hook); EnableExperimentalFeatures.Register("d3d12.dll", "D3D12EnableExperimentalFeatures", D3D12EnableExperimentalFeatures_hook); GetD3D11On12On7.Register("d3d11on12.dll", "GetD3D11On12On7Interface", @@ -221,10 +513,99 @@ public: Threading::SetTLSValue(m_RecurseSlot, NULL); } + static HRESULT GetWrappedInterface(IUnknown *realUnk, REFIID riid, void **ppvInterface) + { + if(riid == __uuidof(ID3D12Debug)) + { + *ppvInterface = (ID3D12Debug *)(new WrappedID3D12Debug()); + return S_OK; + } + else if(riid == __uuidof(ID3D12Debug1)) + { + *ppvInterface = (ID3D12Debug1 *)(new WrappedID3D12Debug()); + return S_OK; + } + else if(riid == __uuidof(ID3D12Debug2)) + { + *ppvInterface = (ID3D12Debug2 *)(new WrappedID3D12Debug()); + return S_OK; + } + else if(riid == __uuidof(ID3D12Debug3)) + { + *ppvInterface = (ID3D12Debug3 *)(new WrappedID3D12Debug()); + return S_OK; + } + else if(riid == __uuidof(ID3D12Debug4)) + { + *ppvInterface = (ID3D12Debug4 *)(new WrappedID3D12Debug()); + return S_OK; + } + else if(riid == __uuidof(ID3D12Debug5)) + { + *ppvInterface = (ID3D12Debug5 *)(new WrappedID3D12Debug()); + return S_OK; + } + else if(riid == __uuidof(ID3D12Debug6)) + { + *ppvInterface = (ID3D12Debug6 *)(new WrappedID3D12Debug()); + return S_OK; + } + else if(riid == __uuidof(ID3D12Tools)) + { + *ppvInterface = (ID3D12Tools *)(new WrappedID3D12Tools()); + return S_OK; + } + else if(riid == __uuidof(ID3D12DeviceRemovedExtendedData)) + { + *ppvInterface = + (ID3D12DeviceRemovedExtendedData *)(new WrappedID3D12DeviceRemovedExtendedData()); + return S_OK; + } + else if(riid == __uuidof(ID3D12DeviceRemovedExtendedData1)) + { + *ppvInterface = + (ID3D12DeviceRemovedExtendedData1 *)(new WrappedID3D12DeviceRemovedExtendedData()); + return S_OK; + } + else if(riid == __uuidof(ID3D12DeviceRemovedExtendedData2)) + { + *ppvInterface = + (ID3D12DeviceRemovedExtendedData2 *)(new WrappedID3D12DeviceRemovedExtendedData()); + return S_OK; + } + else if(riid == __uuidof(ID3D12SDKConfiguration)) + { + ID3D12SDKConfiguration *real = (ID3D12SDKConfiguration *)realUnk; + if(real) + { + // take a reference ourselves, realUnk is a transient pointer and will be released after this function returns + real->AddRef(); + *ppvInterface = (ID3D12SDKConfiguration *)(new WrappedID3D12SDKConfiguration(real, NULL)); + return S_OK; + } + } + else if(riid == __uuidof(ID3D12SDKConfiguration1)) + { + ID3D12SDKConfiguration1 *real1 = (ID3D12SDKConfiguration1 *)realUnk; + if(real1) + { + // take a reference ourselves, realUnk is a transient pointer and will be released after this function returns + real1->AddRef(); + ID3D12SDKConfiguration *real = NULL; + real1->QueryInterface(__uuidof(ID3D12SDKConfiguration), (void **)&real); + *ppvInterface = (ID3D12SDKConfiguration1 *)(new WrappedID3D12SDKConfiguration(real, real1)); + return S_OK; + } + } + + return E_NOINTERFACE; + } + private: static D3D12Hook d3d12hooks; HookedFunction GetDebugInterface; + HookedFunction GetInterface; HookedFunction CreateDevice; HookedFunction EnableExperimentalFeatures; HookedFunction GetD3D11On12On7; @@ -276,7 +657,7 @@ private: bool EnableDebugLayer = false; if(RenderDoc::Inst().GetCaptureOptions().apiValidation) - EnableDebugLayer = EnableD3D12DebugLayer(GetDebugInterface()); + EnableDebugLayer = EnableD3D12DebugLayer(NULL, GetDebugInterface()); RDCDEBUG("Calling real createdevice..."); @@ -460,54 +841,40 @@ private: static HRESULT WINAPI D3D12GetDebugInterface_hook(REFIID riid, void **ppvDebug) { - if(riid == __uuidof(ID3D12Debug)) - { - *ppvDebug = (ID3D12Debug *)(new WrappedID3D12Debug()); - return S_OK; - } - else if(riid == __uuidof(ID3D12Debug1)) - { - *ppvDebug = (ID3D12Debug1 *)(new WrappedID3D12Debug()); - return S_OK; - } - else if(riid == __uuidof(ID3D12Debug2)) - { - *ppvDebug = (ID3D12Debug2 *)(new WrappedID3D12Debug()); - return S_OK; - } - else if(riid == __uuidof(ID3D12Debug3)) - { - *ppvDebug = (ID3D12Debug3 *)(new WrappedID3D12Debug()); - return S_OK; - } - else if(riid == __uuidof(ID3D12Debug4)) - { - *ppvDebug = (ID3D12Debug4 *)(new WrappedID3D12Debug()); - return S_OK; - } - else if(riid == __uuidof(ID3D12Debug5)) - { - *ppvDebug = (ID3D12Debug5 *)(new WrappedID3D12Debug()); - return S_OK; - } - else if(riid == __uuidof(ID3D12Debug6)) - { - *ppvDebug = (ID3D12Debug6 *)(new WrappedID3D12Debug()); - return S_OK; - } - else - { - IUnknown *releaseme = NULL; - HRESULT real = d3d12hooks.GetDebugInterface()(riid, (void **)&releaseme); + IUnknown *realUnk = NULL; + HRESULT real = d3d12hooks.GetDebugInterface()(riid, (void **)&realUnk); - if(releaseme) - releaseme->Release(); + HRESULT hr = GetWrappedInterface(realUnk, riid, ppvDebug); - RDCWARN("Unknown UUID passed to D3D12GetDebugInterface: %s. Real call %s succeed (%x).", - ToStr(riid).c_str(), SUCCEEDED(real) ? "did" : "did not", real); + if(realUnk) + realUnk->Release(); - return E_NOINTERFACE; - } + if(SUCCEEDED(hr)) + return hr; + + RDCWARN("Unknown UUID passed to D3D12GetDebugInterface: %s. Real call %s succeed (%x).", + ToStr(riid).c_str(), SUCCEEDED(real) ? "did" : "did not", real); + + return E_NOINTERFACE; + } + + static HRESULT WINAPI D3D12GetInterface_hook(REFCLSID rclsid, REFIID riid, void **ppvDebug) + { + IUnknown *realUnk = NULL; + HRESULT real = d3d12hooks.GetInterface()(rclsid, riid, (void **)&realUnk); + + HRESULT hr = GetWrappedInterface(realUnk, riid, ppvDebug); + + if(realUnk) + realUnk->Release(); + + if(SUCCEEDED(hr)) + return hr; + + RDCWARN("Unknown UUID passed to D3D12GetInterface: %s (clsid %s). Real call %s succeed (%x).", + ToStr(riid).c_str(), ToStr(rclsid).c_str(), SUCCEEDED(real) ? "did" : "did not", real); + + return E_NOINTERFACE; } }; @@ -518,3 +885,23 @@ HRESULT CreateD3D12_Internal(RealD3D12CreateFunction real, IUnknown *pAdapter, { return D3D12Hook::d3d12hooks.Create_Internal(real, pAdapter, MinimumFeatureLevel, riid, ppDevice); } + +HRESULT STDMETHODCALLTYPE WrappedID3D12DeviceFactory::GetConfigurationInterface( + REFCLSID clsid, REFIID iid, _COM_Outptr_ void **ppv) +{ + IUnknown *realUnk = NULL; + HRESULT real = m_pReal->GetConfigurationInterface(clsid, iid, (void **)&realUnk); + + HRESULT hr = D3D12Hook::GetWrappedInterface(realUnk, iid, ppv); + + if(realUnk) + realUnk->Release(); + + if(SUCCEEDED(hr)) + return hr; + + RDCWARN("Unknown UUID passed to D3D12GetDebugInterface: %s. Real call %s succeed (%x).", + ToStr(iid).c_str(), SUCCEEDED(real) ? "did" : "did not", real); + + return E_NOINTERFACE; +} diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 644a29b36..76cf9484e 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -73,6 +73,18 @@ void D3D12Replay::Shutdown() SAFE_DELETE(m_RGP); + if(m_DevConfig) + { + SAFE_RELEASE(m_DevConfig->debug); + SAFE_RELEASE(m_DevConfig->devconfig); + SAFE_RELEASE(m_DevConfig->devfactory); + + m_DevConfig->sdkconfig->FreeUnusedSDKs(); + SAFE_DELETE(m_DevConfig->sdkconfig); + SAFE_DELETE(m_DevConfig); + } + + // this destroys the replay object m_pDevice->Release(); // the this pointer is free'd after this point @@ -90,9 +102,10 @@ void D3D12Replay::Shutdown() } } -void D3D12Replay::Initialise(IDXGIFactory1 *factory) +void D3D12Replay::Initialise(IDXGIFactory1 *factory, D3D12DevConfiguration *config) { m_pFactory = factory; + m_DevConfig = config; RDCEraseEl(m_DriverInfo); @@ -4557,8 +4570,8 @@ RDResult D3D12_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IRepl if(initParams.MinimumFeatureLevel < D3D_FEATURE_LEVEL_11_0) initParams.MinimumFeatureLevel = D3D_FEATURE_LEVEL_11_0; - D3D12_PrepareReplaySDKVersion(rdc && rdc->IsUntrusted(), initParams.SDKVersion, D3D12Core, - D3D12SDKLayers, D3D12Lib); + D3D12DevConfiguration *config = D3D12_PrepareReplaySDKVersion( + rdc && rdc->IsUntrusted(), initParams.SDKVersion, D3D12Core, D3D12SDKLayers, D3D12Lib); const bool isProxy = (rdc == NULL); @@ -4648,7 +4661,7 @@ RDResult D3D12_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IRepl if(shouldEnableDebugLayer) { - debugLayerEnabled = EnableD3D12DebugLayer(); + debugLayerEnabled = EnableD3D12DebugLayer(config, NULL); if(!debugLayerEnabled && !isProxy) { @@ -4659,7 +4672,11 @@ RDResult D3D12_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IRepl } ID3D12Device *dev = NULL; - hr = createDevice(adapter, initParams.MinimumFeatureLevel, __uuidof(ID3D12Device), (void **)&dev); + if(config) + hr = config->devfactory->CreateDevice(adapter, initParams.MinimumFeatureLevel, + __uuidof(ID3D12Device), (void **)&dev); + else + hr = createDevice(adapter, initParams.MinimumFeatureLevel, __uuidof(ID3D12Device), (void **)&dev); if((FAILED(hr) || !dev) && adapter) { @@ -4668,7 +4685,12 @@ RDResult D3D12_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IRepl RDCWARN("Couldn't replay on selected adapter, falling back to default adapter"); SAFE_RELEASE(adapter); - hr = createDevice(adapter, initParams.MinimumFeatureLevel, __uuidof(ID3D12Device), (void **)&dev); + if(config) + hr = config->devfactory->CreateDevice(adapter, initParams.MinimumFeatureLevel, + __uuidof(ID3D12Device), (void **)&dev); + else + hr = createDevice(adapter, initParams.MinimumFeatureLevel, __uuidof(ID3D12Device), + (void **)&dev); } SAFE_RELEASE(adapter); @@ -4723,7 +4745,7 @@ RDResult D3D12_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, IRepl replay->SetProxy(isProxy); replay->SetRGP(rgp); - replay->Initialise(factory); + replay->Initialise(factory, config); *driver = (IReplayDriver *)replay; return ResultCode::Succeeded; diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index b3c39c089..1650a044b 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -94,12 +94,14 @@ class D3D12Replay : public IReplayDriver public: D3D12Replay(WrappedID3D12Device *d); + D3D12DevConfiguration *GetDevConfiguration() { return m_DevConfig; } + D3D12DebugManager *GetDebugManager() { return m_DebugManager; } void SetRGP(AMDRGPControl *rgp) { m_RGP = rgp; } void Set12On7(bool d3d12on7) { m_D3D12On7 = d3d12on7; } void SetProxy(bool proxy) { m_Proxy = proxy; } bool IsRemoteProxy() { return m_Proxy; } - void Initialise(IDXGIFactory1 *factory); + void Initialise(IDXGIFactory1 *factory, D3D12DevConfiguration *config); void Shutdown(); RDResult FatalErrorCheck(); @@ -561,6 +563,8 @@ private: D3D12DebugManager *m_DebugManager = NULL; + D3D12DevConfiguration *m_DevConfig = NULL; + IDXGIFactory1 *m_pFactory = NULL; HMODULE m_D3D12Lib = NULL; diff --git a/renderdoc/driver/d3d12/d3d12_sdk_select.cpp b/renderdoc/driver/d3d12/d3d12_sdk_select.cpp index b43042e4b..7f9f3c329 100644 --- a/renderdoc/driver/d3d12/d3d12_sdk_select.cpp +++ b/renderdoc/driver/d3d12/d3d12_sdk_select.cpp @@ -314,11 +314,14 @@ bool IsSignedByMicrosoft(const rdcstr &filename, rdcstr &signer) return IsSignatureValid; } -void D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, bytebuf d3d12core_file, - bytebuf d3d12sdklayers_file, HMODULE d3d12lib) +D3D12DevConfiguration *D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, + bytebuf d3d12core_file, + bytebuf d3d12sdklayers_file, HMODULE d3d12lib) { - // D3D12Core shouldn't be loaded at this point, but it might be due to bugs. If it is, we can't do - // anything to change it anymore so we have to just handle what we have + // D3D12Core shouldn't be loaded at this point, but it might be due to bugs. If it is, we don't do + // anything to change it anymore so we have to just handle what we have. + // In theory it might be possible to load multiple d3d12cores using the new dll selection API, but + // that's probably not stable/reliable so we don't use it. HMODULE D3D12Core = GetModuleHandleA("D3D12Core.dll"); if(D3D12Core != NULL) { @@ -326,7 +329,7 @@ void D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, byteb // if the core that's loaded is sufficient, don't show any warnings if(ver_ptr && SDKVersion <= *ver_ptr) - return; + return NULL; RDCWARN( "D3D12Core.dll was already loaded before replay started. This may be caused by a D3D12 " @@ -339,7 +342,7 @@ void D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, byteb RDCWARN("The existing D3D12Core.dll had an unknown version, this capture requires version %u", SDKVersion); - return; + return NULL; } static bool core_fetched = false, hooks_applied = false; @@ -389,7 +392,7 @@ void D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, byteb // if the system doesn't have a core DLL we can't intercept and point to our own runtime, so just // abort here before doing anything potentially dangerous below. if(SystemCoreVersion == 0) - return; + return NULL; // similarly, if the system version is enough then the user didn't use a new runtime (or they used // what was at the time a new runtime but is now available in the system...), so also abort. @@ -397,31 +400,13 @@ void D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, byteb // The only exception is if the user has configured a force override, in which case we always use // it. if(SDKVersion <= SystemCoreVersion && D3D12_D3D12CoreDirPath().empty()) - return; - - // finally we're at a point where we will hook to force the library we want. - - if(!hooks_applied) - { - hooks_applied = true; - - Win32_RegisterManualModuleHooking(); - - D3D12GetInterface_Core_hook.Register("d3d12core.dll", "D3D12GetInterface", - Hooked_Core_D3D12GetInterface); - D3D12GetInterface_SDKLayers_hook.Register("d3d12sdklayers.dll", "D3D12GetInterface", - Hooked_SDKLayers_D3D12GetInterface); - - Win32_InterceptLibraryLoads(Hooked_D3D12LoadLibrary); - } - - // we do this always, even if the hooks are already applied, because this module has possibly been - // reloaded and needs to be re-hooked each time - Win32_ManualHookModule("d3d12.dll", d3d12lib); + return NULL; // *always* use the user's path if it exists D3D12Core_Override_Path = D3D12_D3D12CoreDirPath(); + DWORD OverrideDllVersion = 0; + if(D3D12Core_Override_Path.empty() || !FileIO::exists(D3D12Core_Override_Path.c_str())) { if(d3d12core_file.empty()) @@ -430,7 +415,7 @@ void D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, byteb "No D3D12Core.dll embedded in capture but we need a newer one (version %u) to properly " "replay this capture", SDKVersion); - return; + return NULL; } // find an appropriate spot to write this file. Other instances of RenderDoc might be running so @@ -557,6 +542,118 @@ void D3D12_PrepareReplaySDKVersion(bool untrustedCapture, UINT SDKVersion, byteb FreeLibrary(ret); } } + + if(FileIO::exists(D3D12Core_Override_Path.c_str())) + { + UINT prevErrorMode = GetErrorMode(); + SetErrorMode(prevErrorMode | SEM_FAILCRITICALERRORS); + HMODULE ret = + LoadLibraryW(StringFormat::UTF82Wide(D3D12Core_Override_Path + "/d3d12core.dll").c_str()); + + SetErrorMode(prevErrorMode); + + DWORD *ver_ptr = (DWORD *)GetProcAddress(ret, "D3D12SDKVersion"); + + if(ver_ptr) + OverrideDllVersion = *ver_ptr; + + FreeLibrary(ret); + } + + RDCLOG("Loading D3D12 runtime from %s which is version %u", D3D12Core_Override_Path.c_str(), + OverrideDllVersion); + + // see if we can use the new proper D3D12 dll selection API + { + HMODULE d3d12Lib = GetModuleHandleA("d3d12.dll"); + PFN_D3D12_GET_INTERFACE getD3D12Interface = NULL; + + if(d3d12Lib) + getD3D12Interface = (PFN_D3D12_GET_INTERFACE)GetProcAddress(d3d12Lib, "D3D12GetInterface"); + + if(getD3D12Interface) + { + ID3D12SDKConfiguration *config = NULL; + HRESULT hr = getD3D12Interface(CLSID_D3D12SDKConfiguration, __uuidof(ID3D12SDKConfiguration), + (void **)&config); + + if(SUCCEEDED(hr) && config) + { + ID3D12SDKConfiguration1 *config1 = NULL; + ID3D12DeviceFactory *devfactory = NULL; + hr = config->QueryInterface(__uuidof(ID3D12SDKConfiguration1), (void **)&config1); + if(SUCCEEDED(hr) && config1) + { + config1->CreateDeviceFactory(OverrideDllVersion, D3D12Core_Override_Path.c_str(), + __uuidof(ID3D12DeviceFactory), (void **)&devfactory); + } + SAFE_RELEASE(config); + + if(devfactory) + { + ID3D12Debug *debug = NULL; + hr = devfactory->GetConfigurationInterface(CLSID_D3D12Debug, __uuidof(ID3D12Debug), + (void **)&debug); + if(FAILED(hr)) + SAFE_RELEASE(debug); + ID3D12DeviceConfiguration *devConfig = NULL; + hr = devfactory->QueryInterface(__uuidof(ID3D12DeviceConfiguration), (void **)&devConfig); + if(FAILED(hr)) + SAFE_RELEASE(devConfig); + + // we got what we need, return the interfaces to use + D3D12DevConfiguration *ret = new D3D12DevConfiguration; + ret->devfactory = devfactory; + ret->sdkconfig = config1; + ret->debug = debug; + ret->devconfig = devConfig; + + RDCLOG("Accessing D3D12 dll via SDK configuration API"); + + return ret; + } + else + { + RDCLOG("Couldn't get device factory"); + } + + SAFE_RELEASE(config1); + } + else + { + RDCLOG("Couldn't get SDK configuration interface"); + } + SAFE_RELEASE(config); + } + else + { + RDCLOG("Couldn't get D3D12 interface query"); + } + } + + RDCLOG("Accessing D3D12 dll via hooks"); + + // finally we're at a point where we will hook to force the library we want. + + if(!hooks_applied) + { + hooks_applied = true; + + Win32_RegisterManualModuleHooking(); + + D3D12GetInterface_Core_hook.Register("d3d12core.dll", "D3D12GetInterface", + Hooked_Core_D3D12GetInterface); + D3D12GetInterface_SDKLayers_hook.Register("d3d12sdklayers.dll", "D3D12GetInterface", + Hooked_SDKLayers_D3D12GetInterface); + + Win32_InterceptLibraryLoads(Hooked_D3D12LoadLibrary); + } + + // we do this always, even if the hooks are already applied, because this module has possibly been + // reloaded and needs to be re-hooked each time + Win32_ManualHookModule("d3d12.dll", d3d12lib); + + return NULL; } void D3D12_CleanupReplaySDK() diff --git a/renderdoc/driver/d3d12/d3d12_shader_cache.cpp b/renderdoc/driver/d3d12/d3d12_shader_cache.cpp index 72d686fbd..2a48a0509 100644 --- a/renderdoc/driver/d3d12/d3d12_shader_cache.cpp +++ b/renderdoc/driver/d3d12/d3d12_shader_cache.cpp @@ -767,8 +767,14 @@ D3D12RootSignature D3D12ShaderCache::GetRootSig(const void *data, size_t dataSiz } ID3D12VersionedRootSignatureDeserializer *deser = NULL; - HRESULT hr = deserializeRootSig( - data, dataSize, __uuidof(ID3D12VersionedRootSignatureDeserializer), (void **)&deser); + HRESULT hr; + + if(m_DevConfig) + hr = m_DevConfig->devconfig->CreateVersionedRootSignatureDeserializer( + data, dataSize, __uuidof(ID3D12VersionedRootSignatureDeserializer), (void **)&deser); + else + hr = deserializeRootSig(data, dataSize, __uuidof(ID3D12VersionedRootSignatureDeserializer), + (void **)&deser); if(FAILED(hr)) { @@ -966,7 +972,12 @@ ID3DBlob *D3D12ShaderCache::MakeRootSig(const rdcarray &p ID3DBlob *ret = NULL; ID3DBlob *errBlob = NULL; - HRESULT hr = serializeRootSig(&verdesc, &ret, &errBlob); + HRESULT hr; + + if(m_DevConfig && m_DevConfig->devconfig) + hr = m_DevConfig->devconfig->SerializeVersionedRootSignature(&verdesc, &ret, &errBlob); + else + hr = serializeRootSig(&verdesc, &ret, &errBlob); SAFE_RELEASE(errBlob); if(SUCCEEDED(hr)) @@ -981,7 +992,10 @@ ID3DBlob *D3D12ShaderCache::MakeRootSig(const rdcarray &p oldSamplers[i] = Downconvert(StaticSamplers[i]); desc11.pStaticSamplers = oldSamplers.data(); - hr = serializeRootSig(&verdesc, &ret, &errBlob); + if(m_DevConfig && m_DevConfig->devconfig) + hr = m_DevConfig->devconfig->SerializeVersionedRootSignature(&verdesc, &ret, &errBlob); + else + hr = serializeRootSig(&verdesc, &ret, &errBlob); if(FAILED(hr)) { diff --git a/renderdoc/driver/d3d12/d3d12_shader_cache.h b/renderdoc/driver/d3d12/d3d12_shader_cache.h index 960320dd8..d6f859040 100644 --- a/renderdoc/driver/d3d12/d3d12_shader_cache.h +++ b/renderdoc/driver/d3d12/d3d12_shader_cache.h @@ -61,6 +61,7 @@ public: void LoadDXC(); + void SetDevConfiguration(D3D12DevConfiguration *config) { m_DevConfig = config; } void SetCaching(bool enabled) { m_CacheShaders = enabled; } private: static const uint32_t m_ShaderCacheMagic = 0xf000baba; @@ -71,6 +72,8 @@ private: bool m_ShaderCacheDirty = false, m_CacheShaders = false; std::map m_ShaderCache; + D3D12DevConfiguration *m_DevConfig = NULL; + D3D12_STATIC_SAMPLER_DESC1 Upconvert(const D3D12_STATIC_SAMPLER_DESC &StaticSampler); D3D12_STATIC_SAMPLER_DESC Downconvert(const D3D12_STATIC_SAMPLER_DESC1 &StaticSampler); };