From e3e191f8d630cedceab23e155e16f30d185a1068 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 23 Apr 2024 17:34:49 +0100 Subject: [PATCH] Wrap and serialise state objects as pass-through --- renderdoc/driver/d3d12/d3d12_common.h | 3 +- renderdoc/driver/d3d12/d3d12_device_wrap5.cpp | 195 +++++++++++++++++- renderdoc/driver/d3d12/d3d12_resources.h | 65 +++++- renderdoc/driver/d3d12/d3d12_serialise.cpp | 12 +- 4 files changed, 262 insertions(+), 13 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index 2b5842073..45d162b0b 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -522,7 +522,8 @@ struct D3D12CommandSignature SERIALISE_INTERFACE(ID3D12DescriptorHeap); \ SERIALISE_INTERFACE(ID3D12CommandSignature); \ SERIALISE_INTERFACE(ID3D12CommandQueue); \ - SERIALISE_INTERFACE(ID3D12CommandAllocator); + SERIALISE_INTERFACE(ID3D12CommandAllocator); \ + SERIALISE_INTERFACE(ID3D12StateObject); #define SERIALISE_INTERFACE(iface) DECLARE_REFLECTION_STRUCT(iface *) diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp index 967687d91..e2a0253df 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include "d3d12_device.h" +#include "driver/dxgi/dxgi_common.h" #include "d3d12_resources.h" HRESULT WrappedID3D12Device::CreateLifetimeTracker(_In_ ID3D12LifetimeOwner *pOwner, REFIID riid, @@ -79,23 +80,203 @@ bool WrappedID3D12Device::Serialise_CreateStateObject(SerialiserType &ser, const D3D12_STATE_OBJECT_DESC *pDesc, REFIID riid, _COM_Outptr_ void **ppStateObject) { - // AMD TODO - //Serialize Members + SERIALISE_ELEMENT_LOCAL(Descriptor, *pDesc).Named("pDesc"_lit).Important(); + SERIALISE_ELEMENT_LOCAL(guid, riid).Named("riid"_lit); + SERIALISE_ELEMENT_LOCAL(pStateObject, ((WrappedID3D12StateObject *)*ppStateObject)->GetResourceID()) + .TypedAs("ID3D12StateObject *"_lit); + + SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { - // AMD TODO - // Handle reading, and replaying + ID3D12StateObject *ret = NULL; + HRESULT hr = E_NOINTERFACE; + + // TODO: here we would need to process the state descriptor into any internal replay + // representation to know what's inside. We can also apply m_GlobalEXTUAV, m_GlobalEXTUAVSpace + // for processing extensions in the DXBC files + + // unwrap the subobjects that need unwrapping + + rdcarray rootSigs; + rdcarray collections; + + const D3D12_STATE_SUBOBJECT *subs = Descriptor.pSubobjects; + for(UINT i = 0; i < Descriptor.NumSubobjects; i++) + { + if(subs[i].Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE || + subs[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) + { + // both structs are the same + D3D12_GLOBAL_ROOT_SIGNATURE *global = (D3D12_GLOBAL_ROOT_SIGNATURE *)subs[i].pDesc; + rootSigs.push_back(global->pGlobalRootSignature); + global->pGlobalRootSignature = Unwrap(global->pGlobalRootSignature); + } + else if(subs[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION) + { + // both structs are the same + D3D12_EXISTING_COLLECTION_DESC *coll = (D3D12_EXISTING_COLLECTION_DESC *)subs[i].pDesc; + collections.push_back(coll->pExistingCollection); + coll->pExistingCollection = Unwrap(coll->pExistingCollection); + } + } + + m_UsedDXIL = true; + + if(m_pDevice5) + { + hr = m_pDevice5->CreateStateObject(&Descriptor, guid, (void **)&ret); + } + else + { + SET_ERROR_RESULT(m_FailedReplayResult, ResultCode::APIHardwareUnsupported, + "Capture requires ID3D12Device2 which isn't available"); + return false; + } + + if(FAILED(hr)) + { + SET_ERROR_RESULT(m_FailedReplayResult, ResultCode::APIReplayFailed, + "Failed creating pipeline state, HRESULT: %s", ToStr(hr).c_str()); + return false; + } + else + { + ret = new WrappedID3D12StateObject(ret, this); + + AddResource(pStateObject, ResourceType::PipelineState, "State Object"); + for(ID3D12RootSignature *rootSig : rootSigs) + DerivedResource(rootSig, pStateObject); + for(ID3D12StateObject *coll : collections) + DerivedResource(coll, pStateObject); + + // if this shader was initialised with nvidia's dynamic UAV, pull in that chunk as one of ours + // and unset it (there will be one for each create that actually used vendor extensions) + if(m_VendorEXT == GPUVendor::nVidia && m_GlobalEXTUAV != ~0U) + { + GetResourceDesc(pStateObject) + .initialisationChunks.push_back((uint32_t)m_StructuredFile->chunks.size() - 2); + m_GlobalEXTUAV = ~0U; + } + GetResourceManager()->AddLiveResource(pStateObject, ret); + } } - return false; + return true; } HRESULT WrappedID3D12Device::CreateStateObject(const D3D12_STATE_OBJECT_DESC *pDesc, REFIID riid, _COM_Outptr_ void **ppStateObject) { - // AMD TODO - RDCERR("CreateStateObject called but raytracing is not supported!"); - return E_INVALIDARG; + if(pDesc == NULL) + return m_pDevice5->CreateStateObject(pDesc, riid, ppStateObject); + + D3D12_STATE_OBJECT_DESC unwrappedDesc = *pDesc; + rdcarray subobjects; + subobjects.resize(unwrappedDesc.NumSubobjects); + + rdcarray rootsigs; + rdcarray collections; + for(size_t i = 0; i < subobjects.size(); i++) + { + subobjects[i] = pDesc->pSubobjects[i]; + if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE || + subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) + { + // both structs are the same + D3D12_GLOBAL_ROOT_SIGNATURE *rootsig = (D3D12_GLOBAL_ROOT_SIGNATURE *)subobjects[i].pDesc; + rootsigs.push_back(rootsig->pGlobalRootSignature); + } + else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION) + { + D3D12_EXISTING_COLLECTION_DESC *coll = (D3D12_EXISTING_COLLECTION_DESC *)subobjects[i].pDesc; + collections.push_back(coll->pExistingCollection); + } + } + + rdcarray rootsigObjs; + rdcarray collObjs; + rootsigObjs.resize(rootsigs.size()); + collObjs.resize(collections.size()); + + for(size_t i = 0, r = 0, c = 0; i < subobjects.size(); i++) + { + if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE || + subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) + { + D3D12_GLOBAL_ROOT_SIGNATURE *rootsig = (D3D12_GLOBAL_ROOT_SIGNATURE *)subobjects[i].pDesc; + rootsigObjs[r].pGlobalRootSignature = Unwrap(rootsig->pGlobalRootSignature); + subobjects[i].pDesc = &rootsigObjs[r++]; + } + else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION) + { + D3D12_EXISTING_COLLECTION_DESC *coll = (D3D12_EXISTING_COLLECTION_DESC *)subobjects[i].pDesc; + collObjs[c] = *coll; + collObjs[c].pExistingCollection = Unwrap(collObjs[c].pExistingCollection); + } + } + + unwrappedDesc.pSubobjects = subobjects.data(); + + if(ppStateObject == NULL) + return m_pDevice5->CreateStateObject(&unwrappedDesc, riid, ppStateObject); + + if(riid != __uuidof(ID3D12StateObject)) + return E_NOINTERFACE; + + ID3D12StateObject *real = NULL; + HRESULT ret; + SERIALISE_TIME_CALL(ret = m_pDevice5->CreateStateObject(&unwrappedDesc, riid, (void **)&real)); + + if(SUCCEEDED(ret)) + { + WrappedID3D12StateObject *wrapped = new WrappedID3D12StateObject(real, this); + + if(IsCaptureMode(m_State)) + { + CACHE_THREAD_SERIALISER(); + + Chunk *vendorChunk = NULL; + if(m_VendorEXT != GPUVendor::Unknown) + { + uint32_t reg = ~0U, space = ~0U; + GetShaderExtUAV(reg, space); + + // TODO: detect use of shader extensions and serialise vendor chunk here + } + + m_UsedDXIL = true; + + SCOPED_SERIALISE_CHUNK(D3D12Chunk::Device_CreateStateObject); + Serialise_CreateStateObject(ser, pDesc, riid, (void **)&wrapped); + + D3D12ResourceRecord *record = GetResourceManager()->AddResourceRecord(wrapped->GetResourceID()); + record->type = Resource_PipelineState; + record->Length = 0; + wrapped->SetResourceRecord(record); + + for(ID3D12RootSignature *sig : rootsigs) + record->AddParent(GetRecord(sig)); + for(ID3D12StateObject *coll : collections) + record->AddParent(GetRecord(coll)); + + if(vendorChunk) + record->AddChunk(vendorChunk); + record->AddChunk(scope.Get()); + } + else + { + GetResourceManager()->AddLiveResource(wrapped->GetResourceID(), wrapped); + } + + *ppStateObject = (ID3D12StateObject *)wrapped; + } + else + { + CheckHRESULT(ret); + } + + return ret; } void WrappedID3D12Device::GetRaytracingAccelerationStructurePrebuildInfo( diff --git a/renderdoc/driver/d3d12/d3d12_resources.h b/renderdoc/driver/d3d12/d3d12_resources.h index 76ab0e137..fd0fdcbcd 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.h +++ b/renderdoc/driver/d3d12/d3d12_resources.h @@ -913,6 +913,68 @@ public: typedef WrappedID3D12PipelineState::ShaderEntry WrappedID3D12Shader; +class WrappedID3D12StateObject : public WrappedDeviceChild12, + public ID3D12StateObjectProperties +{ + ID3D12StateObjectProperties *properties; + + +public: + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12StateObject); + + enum + { + TypeEnum = Resource_StateObject, + }; + + WrappedID3D12StateObject(ID3D12StateObject *real, WrappedID3D12Device *device) + : WrappedDeviceChild12(real, device) + { + real->QueryInterface(__uuidof(ID3D12StateObjectProperties), (void **)&properties); + } + virtual ~WrappedID3D12StateObject() + { + SAFE_RELEASE(properties); + Shutdown(); + } + + ULONG STDMETHODCALLTYPE AddRef() { return WrappedDeviceChild12::AddRef(); } + ULONG STDMETHODCALLTYPE Release() { return WrappedDeviceChild12::Release(); } + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + if(riid == __uuidof(ID3D12StateObjectProperties)) + { + *ppvObject = (ID3D12StateObjectProperties *)this; + AddRef(); + return S_OK; + } + return WrappedDeviceChild12::QueryInterface(riid, ppvObject); + } + + ////////////////////////////// + // implement ID3D12StateObject + + ////////////////////////////// + // implement ID3D12StateObjectProperties + + virtual void *STDMETHODCALLTYPE GetShaderIdentifier(LPCWSTR pExportName) + { + return properties->GetShaderIdentifier(pExportName); + } + virtual UINT64 STDMETHODCALLTYPE GetShaderStackSize(LPCWSTR pExportName) + { + return properties->GetShaderStackSize(pExportName); + } + virtual UINT64 STDMETHODCALLTYPE GetPipelineStackSize() + { + return properties->GetPipelineStackSize(); + } + virtual void STDMETHODCALLTYPE SetPipelineStackSize(UINT64 PipelineStackSizeInBytes) + { + properties->SetPipelineStackSize(PipelineStackSizeInBytes); + } +}; + class WrappedID3D12QueryHeap : public WrappedDeviceChild12 { public: @@ -1334,7 +1396,8 @@ private: D3D12_TYPE_MACRO(ID3D12RootSignature); \ D3D12_TYPE_MACRO(ID3D12PipelineLibrary); \ D3D12_TYPE_MACRO(ID3D12ProtectedResourceSession); \ - D3D12_TYPE_MACRO(ID3D12ShaderCacheSession); + D3D12_TYPE_MACRO(ID3D12ShaderCacheSession); \ + D3D12_TYPE_MACRO(ID3D12StateObject); // template magic voodoo to unwrap types template diff --git a/renderdoc/driver/d3d12/d3d12_serialise.cpp b/renderdoc/driver/d3d12/d3d12_serialise.cpp index 54eda4539..b35bac2cd 100644 --- a/renderdoc/driver/d3d12/d3d12_serialise.cpp +++ b/renderdoc/driver/d3d12/d3d12_serialise.cpp @@ -2197,15 +2197,19 @@ void Deserialise(const D3D12_DXIL_LIBRARY_DESC &el) template void DoSerialise(SerialiserType &ser, D3D12_EXISTING_COLLECTION_DESC &el) { - // AMD TODO - RDCERR("D3D12_EXISTING_COLLECTION_DESC serialization is not handled"); + SERIALISE_MEMBER(pExistingCollection); + SERIALISE_MEMBER(NumExports); + SERIALISE_MEMBER_ARRAY(pExports, NumExports); } template <> void Deserialise(const D3D12_EXISTING_COLLECTION_DESC &el) { - // AMD TODO - RDCERR("D3D12_EXISTING_COLLECTION_DESC de-serialization is not handled"); + for(size_t i = 0; i < el.NumExports; i++) + { + Deserialise(el.pExports[i]); + } + delete[] el.pExports; } template