From 2e2b9d2cf98b90dd118c1042d9eee85c04f755d6 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 9 May 2024 11:29:42 +0100 Subject: [PATCH] Add support for AddToStateObject --- renderdoc/driver/d3d12/d3d12_common.cpp | 61 ++++++ renderdoc/driver/d3d12/d3d12_common.h | 11 + renderdoc/driver/d3d12/d3d12_device_wrap5.cpp | 94 ++------- renderdoc/driver/d3d12/d3d12_device_wrap7.cpp | 197 +++++++++++++++++- renderdoc/driver/d3d12/d3d12_resources.h | 1 + renderdoc/driver/d3d12/d3d12_serialise.cpp | 2 +- 6 files changed, 291 insertions(+), 75 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index b0c7d13d9..0ab90ce46 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -1204,6 +1204,67 @@ D3D12_RASTERIZER_DESC2 Upconvert(const D3D12_RASTERIZER_DESC &desc) return RasterizerState; } +D3D12_UNWRAPPED_STATE_OBJECT_DESC::D3D12_UNWRAPPED_STATE_OBJECT_DESC( + const D3D12_STATE_OBJECT_DESC &wrappedDesc) +{ + Type = wrappedDesc.Type; + NumSubobjects = wrappedDesc.NumSubobjects; + + size_t numRoots = 0, numColls = 0, numAssocs = 0; + + subobjects.resize(NumSubobjects); + for(size_t i = 0; i < subobjects.size(); i++) + { + subobjects[i] = wrappedDesc.pSubobjects[i]; + if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE || + subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) + { + numRoots++; + } + else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION) + { + numColls++; + } + else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION) + { + numAssocs++; + } + } + + unwrappedRootsigObjs.resize(numRoots); + collObjs.resize(numColls); + rebasedAssocs.reserve(numAssocs); + + 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; + unwrappedRootsigObjs[r].pGlobalRootSignature = Unwrap(rootsig->pGlobalRootSignature); + subobjects[i].pDesc = &unwrappedRootsigObjs[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); + } + else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION) + { + D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION assoc = + *(D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION *)subobjects[i].pDesc; + + size_t idx = assoc.pSubobjectToAssociate - wrappedDesc.pSubobjects; + assoc.pSubobjectToAssociate = subobjects.data() + idx; + rebasedAssocs.push_back(assoc); + subobjects[i].pDesc = &rebasedAssocs.back(); + } + } + + pSubobjects = subobjects.data(); +} + D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC::D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC( const D3D12_GRAPHICS_PIPELINE_STATE_DESC &graphics) { diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index 9de46b217..28daa9cf5 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -639,6 +639,17 @@ inline bool operator==(const D3D12_CPU_DESCRIPTOR_HANDLE &l, const D3D12_CPU_DES return l.ptr == r.ptr; } +struct D3D12_UNWRAPPED_STATE_OBJECT_DESC : public D3D12_STATE_OBJECT_DESC +{ + D3D12_UNWRAPPED_STATE_OBJECT_DESC(const D3D12_STATE_OBJECT_DESC &wrappedDesc); + +private: + rdcarray subobjects; + rdcarray unwrappedRootsigObjs; + rdcarray rebasedAssocs; + rdcarray collObjs; +}; + // expanded version of D3D12_GRAPHICS_PIPELINE_STATE_DESC / D3D12_COMPUTE_PIPELINE_STATE_DESC with // all subobjects. No enums suitable to make this a stream though. struct D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp index 21a91ffe6..c02b076bb 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp @@ -127,14 +127,14 @@ bool WrappedID3D12Device::Serialise_CreateStateObject(SerialiserType &ser, else { SET_ERROR_RESULT(m_FailedReplayResult, ResultCode::APIHardwareUnsupported, - "Capture requires ID3D12Device2 which isn't available"); + "Capture requires ID3D12Device5 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()); + "Failed creating state object, HRESULT: %s", ToStr(hr).c_str()); return false; } else @@ -186,75 +186,14 @@ bool WrappedID3D12Device::Serialise_CreateStateObject(SerialiserType &ser, return true; } -HRESULT WrappedID3D12Device::CreateStateObject(const D3D12_STATE_OBJECT_DESC *pDesc, REFIID riid, - _COM_Outptr_ void **ppStateObject) +HRESULT +WrappedID3D12Device::CreateStateObject(const D3D12_STATE_OBJECT_DESC *pDesc, REFIID riid, + _COM_Outptr_ void **ppStateObject) { 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; - size_t numAssocs = 0; - 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); - } - else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION) - { - numAssocs++; - } - } - - rdcarray unwrappedRootsigObjs; - rdcarray rebasedAssocs; - rdcarray collObjs; - unwrappedRootsigObjs.resize(rootsigs.size()); - collObjs.resize(collections.size()); - rebasedAssocs.reserve(numAssocs); - - 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; - unwrappedRootsigObjs[r].pGlobalRootSignature = Unwrap(rootsig->pGlobalRootSignature); - subobjects[i].pDesc = &unwrappedRootsigObjs[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); - } - else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION) - { - D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION assoc = - *(D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION *)subobjects[i].pDesc; - - size_t idx = assoc.pSubobjectToAssociate - pDesc->pSubobjects; - assoc.pSubobjectToAssociate = subobjects.data() + idx; - rebasedAssocs.push_back(assoc); - subobjects[i].pDesc = &rebasedAssocs.back(); - } - } - - unwrappedDesc.pSubobjects = subobjects.data(); + D3D12_UNWRAPPED_STATE_OBJECT_DESC unwrappedDesc(*pDesc); if(ppStateObject == NULL) return m_pDevice5->CreateStateObject(&unwrappedDesc, riid, ppStateObject); @@ -299,10 +238,23 @@ HRESULT WrappedID3D12Device::CreateStateObject(const D3D12_STATE_OBJECT_DESC *pD record->Length = 0; wrapped->SetResourceRecord(record); - for(ID3D12RootSignature *sig : rootsigs) - record->AddParent(GetRecord(sig)); - for(ID3D12StateObject *coll : collections) - record->AddParent(GetRecord(coll)); + for(UINT i = 0; i < pDesc->NumSubobjects; i++) + { + if(pDesc->pSubobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE || + pDesc->pSubobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) + { + // both structs are the same + D3D12_GLOBAL_ROOT_SIGNATURE *rootsig = + (D3D12_GLOBAL_ROOT_SIGNATURE *)pDesc->pSubobjects[i].pDesc; + record->AddParent(GetRecord(rootsig->pGlobalRootSignature)); + } + else if(pDesc->pSubobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION) + { + D3D12_EXISTING_COLLECTION_DESC *coll = + (D3D12_EXISTING_COLLECTION_DESC *)pDesc->pSubobjects[i].pDesc; + record->AddParent(GetRecord(coll->pExistingCollection)); + } + } if(vendorChunk) record->AddChunk(vendorChunk); diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap7.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap7.cpp index ec1f5e4da..a2325c3d7 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap7.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap7.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include "d3d12_device.h" +#include "driver/dxgi/dxgi_common.h" #include "d3d12_resources.h" template @@ -32,15 +33,205 @@ bool WrappedID3D12Device::Serialise_AddToStateObject(SerialiserType &ser, REFIID riid, _COM_Outptr_ void **ppNewStateObject) { - return false; + SERIALISE_ELEMENT_LOCAL(Addition, *pAddition); + SERIALISE_ELEMENT(pStateObjectToGrowFrom).Important(); + SERIALISE_ELEMENT_LOCAL(guid, riid).Named("riid"_lit); + SERIALISE_ELEMENT_LOCAL(pNewStateObject, + ((WrappedID3D12StateObject *)*ppNewStateObject)->GetResourceID()) + .TypedAs("ID3D12StateObject *"_lit); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + ID3D12StateObject *ret = NULL; + HRESULT hr = E_NOINTERFACE; + + // unwrap the subobjects that need unwrapping in-place. We'll undo these after creating the + // object - this is probably better than unwrapping to a separate object since that requires + // rebasing all the associations etc + + rdcarray rootSigs; + rdcarray collections; + + const D3D12_STATE_SUBOBJECT *subs = Addition.pSubobjects; + for(UINT i = 0; i < Addition.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) + { + 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_pDevice7) + { + hr = m_pDevice7->CreateStateObject(&Addition, guid, (void **)&ret); + } + else + { + SET_ERROR_RESULT(m_FailedReplayResult, ResultCode::APIHardwareUnsupported, + "Capture requires ID3D12Device7 which isn't available"); + return false; + } + + if(FAILED(hr)) + { + SET_ERROR_RESULT(m_FailedReplayResult, ResultCode::APIReplayFailed, + "Failed creating state object, HRESULT: %s", ToStr(hr).c_str()); + return false; + } + else + { + for(UINT i = 0, r = 0, c = 0; i < Addition.NumSubobjects; i++) + { + if(subs[i].Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE || + subs[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) + { + D3D12_GLOBAL_ROOT_SIGNATURE *global = (D3D12_GLOBAL_ROOT_SIGNATURE *)subs[i].pDesc; + // the same order as above, we can consume the rootSigs in order + global->pGlobalRootSignature = rootSigs[r++]; + } + else if(subs[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION) + { + D3D12_EXISTING_COLLECTION_DESC *coll = (D3D12_EXISTING_COLLECTION_DESC *)subs[i].pDesc; + coll->pExistingCollection = collections[c++]; + } + } + + WrappedID3D12StateObject *wrapped = new WrappedID3D12StateObject(ret, this); + + // TODO: Apply m_GlobalEXTUAV, m_GlobalEXTUAVSpace for processing extensions in the DXBC files? + + wrapped->exports = new D3D12ShaderExportDatabase( + pNewStateObject, GetResourceManager()->GetRaytracingResourceAndUtilHandler(), + wrapped->GetProperties()); + + wrapped->exports->GrowFrom(((WrappedID3D12StateObject *)pStateObjectToGrowFrom)->exports); + wrapped->exports->PopulateDatabase(Addition.NumSubobjects, subs); + + AddResource(pNewStateObject, ResourceType::PipelineState, "State Object"); + for(ID3D12RootSignature *rootSig : rootSigs) + DerivedResource(rootSig, pNewStateObject); + for(ID3D12StateObject *coll : collections) + DerivedResource(coll, pNewStateObject); + + // 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(pNewStateObject) + .initialisationChunks.push_back((uint32_t)m_StructuredFile->chunks.size() - 2); + m_GlobalEXTUAV = ~0U; + } + GetResourceManager()->AddLiveResource(pNewStateObject, wrapped); + } + } + + return true; } HRESULT STDMETHODCALLTYPE WrappedID3D12Device::AddToStateObject( const D3D12_STATE_OBJECT_DESC *pAddition, ID3D12StateObject *pStateObjectToGrowFrom, REFIID riid, _COM_Outptr_ void **ppNewStateObject) { - D3D12NOTIMP("AddToStateObject"); - return E_INVALIDARG; + if(pAddition == NULL) + return m_pDevice7->AddToStateObject(pAddition, pStateObjectToGrowFrom, riid, ppNewStateObject); + + D3D12_UNWRAPPED_STATE_OBJECT_DESC unwrappedDesc(*pAddition); + + if(ppNewStateObject == NULL) + return m_pDevice7->AddToStateObject(&unwrappedDesc, pStateObjectToGrowFrom, riid, + ppNewStateObject); + + if(riid != __uuidof(ID3D12StateObject)) + return E_NOINTERFACE; + + ID3D12StateObject *real = NULL; + HRESULT ret; + SERIALISE_TIME_CALL(ret = m_pDevice7->AddToStateObject(&unwrappedDesc, pStateObjectToGrowFrom, + 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_AddToStateObject); + Serialise_AddToStateObject(ser, pAddition, pStateObjectToGrowFrom, riid, (void **)&wrapped); + + wrapped->exports = new D3D12ShaderExportDatabase( + wrapped->GetResourceID(), GetResourceManager()->GetRaytracingResourceAndUtilHandler(), + wrapped->GetProperties()); + + wrapped->exports->GrowFrom(((WrappedID3D12StateObject *)pStateObjectToGrowFrom)->exports); + wrapped->exports->PopulateDatabase(pAddition->NumSubobjects, pAddition->pSubobjects); + + D3D12ResourceRecord *record = GetResourceManager()->AddResourceRecord(wrapped->GetResourceID()); + record->type = Resource_PipelineState; + record->Length = 0; + wrapped->SetResourceRecord(record); + + for(UINT i = 0; i < pAddition->NumSubobjects; i++) + { + if(pAddition->pSubobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE || + pAddition->pSubobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) + { + // both structs are the same + D3D12_GLOBAL_ROOT_SIGNATURE *rootsig = + (D3D12_GLOBAL_ROOT_SIGNATURE *)pAddition->pSubobjects[i].pDesc; + record->AddParent(GetRecord(rootsig->pGlobalRootSignature)); + } + else if(pAddition->pSubobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION) + { + D3D12_EXISTING_COLLECTION_DESC *coll = + (D3D12_EXISTING_COLLECTION_DESC *)pAddition->pSubobjects[i].pDesc; + record->AddParent(GetRecord(coll->pExistingCollection)); + } + } + + if(vendorChunk) + record->AddChunk(vendorChunk); + record->AddChunk(scope.Get()); + } + else + { + GetResourceManager()->AddLiveResource(wrapped->GetResourceID(), wrapped); + } + + *ppNewStateObject = (ID3D12StateObject *)wrapped; + } + else + { + CheckHRESULT(ret); + } + + return ret; } HRESULT WrappedID3D12Device::CreateProtectedResourceSession1( diff --git a/renderdoc/driver/d3d12/d3d12_resources.h b/renderdoc/driver/d3d12/d3d12_resources.h index 25b5d3420..9d4560f77 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.h +++ b/renderdoc/driver/d3d12/d3d12_resources.h @@ -955,6 +955,7 @@ public: ResourceId GetResourceId() { return objectOriginalId; } + void GrowFrom(D3D12ShaderExportDatabase *existing) { InheritAllCollectionExports(existing); } void PopulateDatabase(size_t NumSubobjects, const D3D12_STATE_SUBOBJECT *subobjects); void *GetShaderIdentifier(const rdcstr &exportName) diff --git a/renderdoc/driver/d3d12/d3d12_serialise.cpp b/renderdoc/driver/d3d12/d3d12_serialise.cpp index 538e616df..9f14bcb31 100644 --- a/renderdoc/driver/d3d12/d3d12_serialise.cpp +++ b/renderdoc/driver/d3d12/d3d12_serialise.cpp @@ -1993,7 +1993,7 @@ template void DoSerialise(SerialiserType &ser, D3D12_STATE_OBJECT_DESC &el) { SERIALISE_MEMBER(Type); - SERIALISE_MEMBER(NumSubobjects); + SERIALISE_MEMBER(NumSubobjects).Important(); if(ser.IsReading()) {