diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index 09270c4af..cbfca203d 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -87,6 +87,9 @@ public: // implement IUnknown HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) { + if(!m_pReal) + return E_NOINTERFACE; + return RefCountDXGIObject::WrapQueryInterface(m_pReal, riid, ppvObject); } diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index 9d7109a50..ebb80da19 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -172,6 +172,9 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara if(RenderDoc::Inst().GetCrashHandler()) RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(WrappedID3D12Device)); + m_pDevice1 = NULL; + m_pDevice->QueryInterface(__uuidof(ID3D12Device1), (void **)&m_pDevice1); + for(size_t i = 0; i < ARRAY_COUNT(m_DescriptorIncrements); i++) m_DescriptorIncrements[i] = realDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE(i)); @@ -362,6 +365,8 @@ WrappedID3D12Device::~WrappedID3D12Device() SAFE_DELETE(m_ResourceManager); + SAFE_RELEASE(m_pDevice1); + SAFE_RELEASE(m_pInfoQueue); SAFE_RELEASE(m_WrappedDebug.m_pDebug); SAFE_RELEASE(m_pDevice); @@ -468,6 +473,19 @@ HRESULT WrappedID3D12Device::QueryInterface(REFIID riid, void **ppvObject) return hr; } } + else if(riid == __uuidof(ID3D12Device1)) + { + if(m_pDevice1) + { + AddRef(); + *ppvObject = (ID3D12Device1 *)this; + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } else if(riid == __uuidof(ID3D12InfoQueue)) { RDCWARN( diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index 60138aa4c..f243577db 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -219,10 +219,11 @@ class WrappedID3D12CommandQueue; ret func(__VA_ARGS__); \ bool CONCAT(Serialise_, func(Serialiser *localSerialiser, __VA_ARGS__)); -class WrappedID3D12Device : public IFrameCapturer, public ID3DDevice, public ID3D12Device +class WrappedID3D12Device : public IFrameCapturer, public ID3DDevice, public ID3D12Device1 { private: ID3D12Device *m_pDevice; + ID3D12Device1 *m_pDevice1; // list of all queues being captured std::vector m_Queues; @@ -677,4 +678,22 @@ public: D3D12_SUBRESOURCE_TILING *pSubresourceTilingsForNonPackedMips); IMPLEMENT_FUNCTION_THREAD_SERIALISED(virtual LUID STDMETHODCALLTYPE, GetAdapterLuid); + + IMPLEMENT_FUNCTION_THREAD_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, CreatePipelineLibrary, + _In_reads_(BlobLength) const void *pLibraryBlob, + SIZE_T BlobLength, REFIID riid, + _COM_Outptr_ void **ppPipelineLibrary); + + IMPLEMENT_FUNCTION_THREAD_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, + SetEventOnMultipleFenceCompletion, + _In_reads_(NumFences) ID3D12Fence *const *ppFences, + _In_reads_(NumFences) const UINT64 *pFenceValues, + UINT NumFences, D3D12_MULTIPLE_FENCE_WAIT_FLAGS Flags, + HANDLE hEvent); + + IMPLEMENT_FUNCTION_THREAD_SERIALISED(virtual HRESULT STDMETHODCALLTYPE, SetResidencyPriority, + UINT NumObjects, + _In_reads_(NumObjects) ID3D12Pageable *const *ppObjects, + _In_reads_(NumObjects) + const D3D12_RESIDENCY_PRIORITY *pPriorities); }; diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp index 9618eee9f..60a0aa476 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp @@ -1871,3 +1871,54 @@ void WrappedID3D12Device::GetCopyableFootprints(const D3D12_RESOURCE_DESC *pReso BaseOffset, pLayouts, pNumRows, pRowSizeInBytes, pTotalBytes); } + +HRESULT WrappedID3D12Device::CreatePipelineLibrary(_In_reads_(BlobLength) const void *pLibraryBlob, + SIZE_T BlobLength, REFIID riid, + _COM_Outptr_ void **ppPipelineLibrary) +{ +// we don't want to ever use pipeline libraries since then we can't get the +// bytecode and pipeline config. So instead we always return that a blob is +// non-matching and return a dummy interface that does nothing when stored. +// This might cause the application to clear its previous cache but that's +// not the end of the world. +#ifndef D3D12_ERROR_DRIVER_VERSION_MISMATCH +#define D3D12_ERROR_DRIVER_VERSION_MISMATCH _HRESULT_TYPEDEF_(0x887E0002L) +#endif + + if(BlobLength > 0) + return D3D12_ERROR_DRIVER_VERSION_MISMATCH; + + RDCASSERT(riid == __uuidof(ID3D12PipelineLibrary)); + + *ppPipelineLibrary = (ID3D12PipelineLibrary *)(new WrappedID3D12PipelineLibrary(this)); + + return S_OK; +} + +HRESULT WrappedID3D12Device::SetEventOnMultipleFenceCompletion( + _In_reads_(NumFences) ID3D12Fence *const *ppFences, + _In_reads_(NumFences) const UINT64 *pFenceValues, UINT NumFences, + D3D12_MULTIPLE_FENCE_WAIT_FLAGS Flags, HANDLE hEvent) +{ + ID3D12Fence **unwrapped = GetTempArray(NumFences); + + for(UINT i = 0; i < NumFences; i++) + unwrapped[i] = Unwrap(ppFences[i]); + + return m_pDevice1->SetEventOnMultipleFenceCompletion(unwrapped, pFenceValues, NumFences, Flags, + hEvent); +} + +HRESULT WrappedID3D12Device::SetResidencyPriority(UINT NumObjects, + _In_reads_(NumObjects) + ID3D12Pageable *const *ppObjects, + _In_reads_(NumObjects) + const D3D12_RESIDENCY_PRIORITY *pPriorities) +{ + ID3D12Pageable **unwrapped = GetTempArray(NumObjects); + + for(UINT i = 0; i < NumObjects; i++) + unwrapped[i] = (ID3D12Pageable *)Unwrap((ID3D12DeviceChild *)ppObjects[i]); + + return m_pDevice1->SetResidencyPriority(NumObjects, unwrapped, pPriorities); +} diff --git a/renderdoc/driver/d3d12/d3d12_manager.h b/renderdoc/driver/d3d12/d3d12_manager.h index 20a166d85..918ca202d 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.h +++ b/renderdoc/driver/d3d12/d3d12_manager.h @@ -47,6 +47,7 @@ enum D3D12ResourceType Resource_Resource, Resource_GraphicsCommandList, Resource_RootSignature, + Resource_PipelineLibrary, }; class WrappedID3D12DescriptorHeap; diff --git a/renderdoc/driver/d3d12/d3d12_resources.h b/renderdoc/driver/d3d12/d3d12_resources.h index 55202323f..a4b987e9f 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.h +++ b/renderdoc/driver/d3d12/d3d12_resources.h @@ -110,7 +110,7 @@ public: AddRef(); return S_OK; } - if(riid == __uuidof(NestedType1)) + if(riid == __uuidof(NestedType1) && m_pReal) { // check that the real interface supports this NestedType1 *dummy = NULL; @@ -125,7 +125,7 @@ public: AddRef(); return S_OK; } - if(riid == __uuidof(NestedType2)) + if(riid == __uuidof(NestedType2) && m_pReal) { // check that the real interface supports this NestedType2 *dummy = NULL; @@ -160,6 +160,9 @@ public: riid == __uuidof(IDXGISurface) || riid == __uuidof(IDXGISurface1) || riid == __uuidof(IDXGIResource1) || riid == __uuidof(IDXGISurface2)) { + if(m_pReal == NULL) + return E_NOINTERFACE; + // ensure the real object has this interface void *outObj; HRESULT hr = m_pReal->QueryInterface(riid, &outObj); @@ -226,6 +229,13 @@ public: HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID guid, UINT *pDataSize, void *pData) { + if(!m_pReal) + { + if(pDataSize) + *pDataSize = 0; + return S_OK; + } + return m_pReal->GetPrivateData(guid, pDataSize, pData); } @@ -237,11 +247,17 @@ public: if(guid == WKPDID_D3DDebugObjectName) m_pDevice->SetResourceName(this, (const char *)pData); + if(!m_pReal) + return S_OK; + return m_pReal->SetPrivateData(guid, DataSize, pData); } HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID guid, const IUnknown *pData) { + if(!m_pReal) + return S_OK; + return m_pReal->SetPrivateDataInterface(guid, pData); } @@ -250,6 +266,9 @@ public: string utf8 = StringFormat::Wide2UTF8(Name); m_pDevice->SetResourceName(this, utf8.c_str()); + if(!m_pReal) + return S_OK; + return m_pReal->SetName(Name); } @@ -783,6 +802,62 @@ public: virtual ~WrappedID3D12RootSignature() { Shutdown(); } }; +class WrappedID3D12PipelineLibrary : public WrappedDeviceChild12 +{ +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12PipelineLibrary); + + enum + { + TypeEnum = Resource_PipelineLibrary, + }; + + WrappedID3D12PipelineLibrary(WrappedID3D12Device *device) : WrappedDeviceChild12(NULL, device) {} + virtual ~WrappedID3D12PipelineLibrary() { Shutdown(); } + virtual HRESULT STDMETHODCALLTYPE StorePipeline(_In_opt_ LPCWSTR pName, + _In_ ID3D12PipelineState *pPipeline) + { + // do nothing + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE + LoadGraphicsPipeline(_In_ LPCWSTR pName, _In_ const D3D12_GRAPHICS_PIPELINE_STATE_DESC *pDesc, + REFIID riid, _COM_Outptr_ void **ppPipelineState) + { + // pretend we don't have it - assume that the application won't store then + // load in the same run, or will handle that if it happens + return E_INVALIDARG; + } + + virtual HRESULT STDMETHODCALLTYPE + LoadComputePipeline(_In_ LPCWSTR pName, _In_ const D3D12_COMPUTE_PIPELINE_STATE_DESC *pDesc, + REFIID riid, _COM_Outptr_ void **ppPipelineState) + { + // pretend we don't have it - assume that the application won't store then + // load in the same run, or will handle that if it happens + return E_INVALIDARG; + } + + static const SIZE_T DummyBytes = 32; + + virtual SIZE_T STDMETHODCALLTYPE GetSerializedSize(void) + { + // simple dummy serialisation since applications might not expect 0 bytes + return DummyBytes; + } + + virtual HRESULT STDMETHODCALLTYPE Serialize(_Out_writes_(DataSizeInBytes) void *pData, + SIZE_T DataSizeInBytes) + { + if(DataSizeInBytes < DummyBytes) + return E_INVALIDARG; + + memset(pData, 0, DummyBytes); + return S_OK; + } +}; + #define ALL_D3D12_TYPES \ D3D12_TYPE_MACRO(ID3D12CommandAllocator); \ D3D12_TYPE_MACRO(ID3D12CommandSignature); \ @@ -792,7 +867,8 @@ public: D3D12_TYPE_MACRO(ID3D12PipelineState); \ D3D12_TYPE_MACRO(ID3D12QueryHeap); \ D3D12_TYPE_MACRO(ID3D12Resource); \ - D3D12_TYPE_MACRO(ID3D12RootSignature); + D3D12_TYPE_MACRO(ID3D12RootSignature); \ + D3D12_TYPE_MACRO(ID3D12PipelineLibrary); // template magic voodoo to unwrap types template