diff --git a/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp index c15705a97..0ef976d40 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp @@ -1237,25 +1237,61 @@ bool WrappedID3D12GraphicsCommandList::Serialise_DispatchRays(SerialiserType &se m_Cmd->m_LastCmdListID = GetResourceManager()->GetOriginalID(GetResID(pCommandList)); + const D3D12RenderState &state = m_Cmd->m_BakedCmdListInfo[m_Cmd->m_LastCmdListID].state; + if(IsActiveReplaying(m_State)) { if(m_Cmd->InRerecordRange(m_Cmd->m_LastCmdListID)) { ID3D12GraphicsCommandListX *list = m_Cmd->RerecordCmdList(m_Cmd->m_LastCmdListID); + // this call will copy the specified buffers containing shader records and patch them. We get + // a reference to the lookup buffer used as well as a reference to the scratch buffer + // containing the patched shader records. + PatchedRayDispatch patchedDispatch = + GetResourceManager()->GetRaytracingResourceAndUtilHandler()->PatchRayDispatch( + Unwrap4(list), state.heaps, Desc); + + // restore state that would have been mutated by the patching process + Unwrap4(list)->SetComputeRootSignature( + Unwrap(GetResourceManager()->GetCurrentAs(state.compute.rootsig))); + Unwrap4(list)->SetPipelineState1( + Unwrap(GetResourceManager()->GetCurrentAs(state.stateobj))); + state.ApplyComputeRootElementsUnwrapped(Unwrap4(list)); + + m_Cmd->m_RayDispatches.push_back(patchedDispatch.resources); + uint32_t eventId = m_Cmd->HandlePreCallback(list, ActionFlags::DispatchRay); // this can't work yet as the shader records have not been patched - // Unwrap4(list)->DispatchRays(&Desc); + Unwrap4(list)->DispatchRays(&patchedDispatch.desc); if(eventId && m_Cmd->m_ActionCallback->PostDraw(eventId, list)) { - // Unwrap4(list)->DispatchRays(&Desc); + Unwrap4(list)->DispatchRays(&patchedDispatch.desc); m_Cmd->m_ActionCallback->PostRedraw(eventId, list); } } } else { - Unwrap4(pCommandList)->DispatchRays(&Desc); + // this call will copy the specified buffers containing shader records and patch them. We get + // a reference to the lookup buffer used as well as a reference to the scratch buffer + // containing the patched shader records. + PatchedRayDispatch patchedDispatch = + GetResourceManager()->GetRaytracingResourceAndUtilHandler()->PatchRayDispatch( + Unwrap4(pCommandList), state.heaps, Desc); + + // restore state that would have been mutated by the patching process + Unwrap4(pCommandList) + ->SetComputeRootSignature(Unwrap( + GetResourceManager()->GetCurrentAs(state.compute.rootsig))); + Unwrap4(pCommandList) + ->SetPipelineState1( + Unwrap(GetResourceManager()->GetCurrentAs(state.stateobj))); + state.ApplyComputeRootElementsUnwrapped(Unwrap4(pCommandList)); + + m_Cmd->m_RayDispatches.push_back(patchedDispatch.resources); + + Unwrap4(pCommandList)->DispatchRays(&patchedDispatch.desc); m_Cmd->AddEvent(); diff --git a/renderdoc/driver/d3d12/d3d12_commands.h b/renderdoc/driver/d3d12/d3d12_commands.h index f0cf9c7d5..4bc43171f 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.h +++ b/renderdoc/driver/d3d12/d3d12_commands.h @@ -363,6 +363,8 @@ struct D3D12CommandData double m_TimeFrequency = 1.0f; SDFile *m_StructuredFile; + rdcarray m_RayDispatches; + std::map> m_ResourceUses; D3D12ActionTreeNode m_ParentAction; diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index de2bd1f00..8cbf2559e 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -4939,6 +4939,16 @@ void WrappedID3D12Device::ReplayLog(uint32_t startEventID, uint32_t endEventID, ExecuteLists(); FlushLists(true); + // clear any previous ray dispatch references + D3D12CommandData &cmd = *m_Queue->GetCommandData(); + + for(PatchedRayDispatch::Resources &r : cmd.m_RayDispatches) + { + r.lookupBuffer->Release(); + r.patchScratchBuffer->Release(); + } + cmd.m_RayDispatches.clear(); + if(HasFatalError()) return; } diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp index 707e25f43..bcdd14109 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap5.cpp @@ -92,11 +92,9 @@ bool WrappedID3D12Device::Serialise_CreateStateObject(SerialiserType &ser, 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 + // 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; @@ -114,7 +112,6 @@ bool WrappedID3D12Device::Serialise_CreateStateObject(SerialiserType &ser, } 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); @@ -142,7 +139,31 @@ bool WrappedID3D12Device::Serialise_CreateStateObject(SerialiserType &ser, } else { - ret = new WrappedID3D12StateObject(ret, this); + for(UINT i = 0, r = 0, c = 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) + { + 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( + pStateObject, GetResourceManager()->GetRaytracingResourceAndUtilHandler(), + wrapped->GetProperties()); + + wrapped->exports->PopulateDatabase(Descriptor.NumSubobjects, subs); AddResource(pStateObject, ResourceType::PipelineState, "State Object"); for(ID3D12RootSignature *rootSig : rootSigs) @@ -158,7 +179,7 @@ bool WrappedID3D12Device::Serialise_CreateStateObject(SerialiserType &ser, .initialisationChunks.push_back((uint32_t)m_StructuredFile->chunks.size() - 2); m_GlobalEXTUAV = ~0U; } - GetResourceManager()->AddLiveResource(pStateObject, ret); + GetResourceManager()->AddLiveResource(pStateObject, wrapped); } } @@ -267,263 +288,11 @@ HRESULT WrappedID3D12Device::CreateStateObject(const D3D12_STATE_OBJECT_DESC *pD SCOPED_SERIALISE_CHUNK(D3D12Chunk::Device_CreateStateObject); Serialise_CreateStateObject(ser, pDesc, riid, (void **)&wrapped); - D3D12ShaderExportDatabase *exports = wrapped->exports; + wrapped->exports = new D3D12ShaderExportDatabase( + wrapped->GetResourceID(), GetResourceManager()->GetRaytracingResourceAndUtilHandler(), + wrapped->GetProperties()); - // store the default local root signature - if we only find one in the whole state object then it becomes default - ID3D12RootSignature *defaultRoot = NULL; - bool unassocDefaultValid = false; - bool explicitDefault = false; - bool unassocDXILDefaultValid = false; - uint32_t dxilDefaultRoot = ~0U; - - rdcarray> explicitRootSigAssocs; - rdcarray explicitDefaultDxilAssocs; - rdcarray> explicitDxilAssocs; - rdcflatmap dxilLocalRootSigs; - - rdcarray> inheritedRootSigAssocs; - rdcarray> inheritedDXILRootSigAssocs; - rdcflatmap inheritedDXILLocalRootSigs; - - // fill shader exports list as well as local root signature lookups. - // shader exports that can be queried come from two sources: - // - hit groups - // - exports from a DXIL library - // - exports from a collection - for(size_t i = 0; i < subobjects.size(); i++) - { - if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP) - { - D3D12_HIT_GROUP_DESC *desc = (D3D12_HIT_GROUP_DESC *)subobjects[i].pDesc; - exports->AddExport(StringFormat::Wide2UTF8(desc->HitGroupExport)); - - rdcarray shaders; - if(desc->IntersectionShaderImport) - shaders.push_back(StringFormat::Wide2UTF8(desc->IntersectionShaderImport)); - if(desc->AnyHitShaderImport) - shaders.push_back(StringFormat::Wide2UTF8(desc->AnyHitShaderImport)); - if(desc->ClosestHitShaderImport) - shaders.push_back(StringFormat::Wide2UTF8(desc->ClosestHitShaderImport)); - - // register the hit group so that if we get associations with the individual shaders we - // can apply that up to the hit group - exports->AddLastHitGroupShaders(std::move(shaders)); - } - else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY) - { - D3D12_DXIL_LIBRARY_DESC *dxil = (D3D12_DXIL_LIBRARY_DESC *)subobjects[i].pDesc; - - if(dxil->NumExports > 0) - { - for(UINT e = 0; e < dxil->NumExports; e++) - { - // Name is always the name used for exports - if renaming then the renamed-from name - // is only used to lookup in the dxil library and not for any associations-by-name - exports->AddExport(StringFormat::Wide2UTF8(dxil->pExports[e].Name)); - } - } - else - { - // hard part, we need to parse the DXIL to get the entry points - DXBC::DXBCContainer container( - bytebuf((byte *)dxil->DXILLibrary.pShaderBytecode, dxil->DXILLibrary.BytecodeLength), - rdcstr(), GraphicsAPI::D3D12, ~0U, ~0U); - - rdcarray entries = container.GetEntryPoints(); - - for(const ShaderEntryPoint &e : entries) - exports->AddExport(e.name); - } - - // TODO: register local root signature subobjects into dxilLocalRootSigs. Override - // anything in there, unlike the import from a collection below. - } - else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION) - { - D3D12_EXISTING_COLLECTION_DESC *coll = - (D3D12_EXISTING_COLLECTION_DESC *)subobjects[i].pDesc; - - WrappedID3D12StateObject *stateObj = (WrappedID3D12StateObject *)coll->pExistingCollection; - - if(coll->NumExports > 0) - { - for(UINT e = 0; e < coll->NumExports; e++) - exports->InheritCollectionExport( - stateObj->exports, StringFormat::Wide2UTF8(coll->pExports[e].Name), - StringFormat::Wide2UTF8(coll->pExports[e].ExportToRename - ? coll->pExports[e].ExportToRename - : coll->pExports[e].Name)); - } - else - { - exports->InheritAllCollectionExports(stateObj->exports); - } - - // inherit explicit associations from the collection as lowest priority - inheritedRootSigAssocs.append(stateObj->exports->danglingRootSigAssocs); - inheritedDXILRootSigAssocs.append(stateObj->exports->danglingDXILRootSigAssocs); - - for(auto it = stateObj->exports->danglingDXILLocalRootSigs.begin(); - it != stateObj->exports->danglingDXILLocalRootSigs.end(); ++it) - { - // don't override any local root signatures with the same name we already have. Not sure - // how this conflict should be resolved properly? - if(dxilLocalRootSigs.find(it->first) == dxilLocalRootSigs.end()) - dxilLocalRootSigs[it->first] = it->second; - } - } - else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) - { - // ignore these if an explicit default association has been made - if(!explicitDefault) - { - // if multiple root signatures are defined, then there can't be an unspecified default - unassocDefaultValid = defaultRoot != NULL; - defaultRoot = ((D3D12_LOCAL_ROOT_SIGNATURE *)subobjects[i].pDesc)->pLocalRootSignature; - } - } - 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; - - const D3D12_STATE_SUBOBJECT *other = assoc->pSubobjectToAssociate; - - // only care about associating local root signatures - if(other->Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) - { - ID3D12RootSignature *root = - ((D3D12_LOCAL_ROOT_SIGNATURE *)other->pDesc)->pLocalRootSignature; - - WrappedID3D12RootSignature *wrappedRoot = (WrappedID3D12RootSignature *)root; - - // if there are no exports this is an explicit default association. We assume this - // matches and doesn't conflict - if(assoc->NumExports == NULL) - { - explicitDefault = true; - defaultRoot = root; - } - else - { - // otherwise record the explicit associations - these may refer to exports that - // haven't been seen yet so we record them locally - for(UINT e = 0; e < assoc->NumExports; e++) - explicitRootSigAssocs.push_back( - {StringFormat::Wide2UTF8(assoc->pExports[e]), wrappedRoot->localRootSigIdx}); - } - } - } - else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION) - { - D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION *assoc = - (D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION *)subobjects[i].pDesc; - - rdcstr other = StringFormat::Wide2UTF8(assoc->SubobjectToAssociate); - - // we can't tell yet if this is a local root signature or not so we have to store it regardless - { - // if there are no exports this is an explicit default association, but we don't know if - // it's for a local root signature... - if(assoc->NumExports == NULL) - { - explicitDefaultDxilAssocs.push_back(other); - } - else - { - // otherwise record the explicit associations - these may refer to exports that - // haven't been seen yet so we record them locally - for(UINT e = 0; e < assoc->NumExports; e++) - explicitDxilAssocs.push_back({StringFormat::Wide2UTF8(assoc->pExports[e]), other}); - } - } - } - } - - // now that we have all exports registered, apply all associations we have in order of - // priority to get the right - - for(size_t i = 0; i < explicitRootSigAssocs.size(); i++) - { - exports->ApplyRoot(SubObjectPriority::CodeExplicitAssociation, - explicitRootSigAssocs[i].first, explicitRootSigAssocs[i].second); - } - - if(explicitDefault) - { - WrappedID3D12RootSignature *wrappedRoot = (WrappedID3D12RootSignature *)defaultRoot; - - exports->ApplyDefaultRoot(SubObjectPriority::CodeExplicitDefault, - wrappedRoot->localRootSigIdx); - } - // shouldn't be possible to have both explicit and implicit defaults? - else if(unassocDefaultValid) - { - WrappedID3D12RootSignature *wrappedRoot = (WrappedID3D12RootSignature *)defaultRoot; - - exports->ApplyDefaultRoot(SubObjectPriority::CodeImplicitDefault, - wrappedRoot->localRootSigIdx); - } - - for(size_t i = 0; i < explicitDxilAssocs.size(); i++) - { - auto it = dxilLocalRootSigs.find(explicitDxilAssocs[i].second); - - if(it == dxilLocalRootSigs.end()) - continue; - - uint32_t localRootSigIdx = it->second; - - exports->ApplyRoot(SubObjectPriority::DXILExplicitAssociation, explicitDxilAssocs[i].first, - localRootSigIdx); - } - - for(size_t i = 0; i < explicitDefaultDxilAssocs.size(); i++) - { - auto it = dxilLocalRootSigs.find(explicitDefaultDxilAssocs[i]); - - if(it == dxilLocalRootSigs.end()) - continue; - - uint32_t localRootSigIdx = it->second; - - exports->ApplyDefaultRoot(SubObjectPriority::DXILExplicitDefault, localRootSigIdx); - - // only expect one local root signature - the array is because we can't tell the type of the - // default subobject when we encounter it - break; - } - - if(unassocDXILDefaultValid) - { - exports->ApplyDefaultRoot(SubObjectPriority::DXILImplicitDefault, dxilDefaultRoot); - } - - // we assume it's not possible to inherit two different explicit associations for a single export - - for(size_t i = 0; i < inheritedRootSigAssocs.size(); i++) - { - exports->ApplyRoot(SubObjectPriority::CollectionExplicitAssociation, - inheritedRootSigAssocs[i].first, inheritedRootSigAssocs[i].second); - } - for(size_t i = 0; i < inheritedDXILRootSigAssocs.size(); i++) - { - auto it = dxilLocalRootSigs.find(inheritedDXILRootSigAssocs[i].second); - - if(it == dxilLocalRootSigs.end()) - continue; - - uint32_t localRootSigIdx = it->second; - - exports->ApplyRoot(SubObjectPriority::CollectionExplicitAssociation, - inheritedDXILRootSigAssocs[i].first, localRootSigIdx); - } - - exports->danglingRootSigAssocs.swap(inheritedRootSigAssocs); - exports->danglingDXILRootSigAssocs.swap(inheritedDXILRootSigAssocs); - exports->danglingDXILLocalRootSigs.swap(dxilLocalRootSigs); - - exports->UpdateHitGroupAssociations(); + wrapped->exports->PopulateDatabase(subobjects.size(), subobjects.data()); D3D12ResourceRecord *record = GetResourceManager()->AddResourceRecord(wrapped->GetResourceID()); record->type = Resource_PipelineState; diff --git a/renderdoc/driver/d3d12/d3d12_manager.cpp b/renderdoc/driver/d3d12/d3d12_manager.cpp index 3881cb3fe..5e8b2798c 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.cpp +++ b/renderdoc/driver/d3d12/d3d12_manager.cpp @@ -790,6 +790,8 @@ PatchedRayDispatch D3D12RaytracingResourceAndUtilHandler::PatchRayDispatch( ret.desc = desc; + D3D12MarkerRegion region(unwrappedCmd, "PatchRayDispatch"); + { SCOPED_LOCK(m_LookupBufferLock); if(m_LookupBufferDirty) @@ -968,7 +970,7 @@ PatchedRayDispatch D3D12RaytracingResourceAndUtilHandler::PatchRayDispatch( barrier.Transition.pResource = scratchBuffer->Resource(); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; unwrappedCmd->ResourceBarrier(1, &barrier); // put the resources into common. This should be implicitly promotable to @@ -1042,6 +1044,11 @@ PatchedRayDispatch D3D12RaytracingResourceAndUtilHandler::PatchRayDispatch( cbufferData.raydispatch_callcount, 1, 1); + barrier.Transition.pResource = scratchBuffer->Resource(); + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + unwrappedCmd->ResourceBarrier(1, &barrier); + // we have our own ref, the patch data has its ref too that will be held while the list is // submittable. Each submission will also get a ref to keep this referenced lookup buffer alive until then m_LookupBuffer->AddRef(); diff --git a/renderdoc/driver/d3d12/d3d12_resources.cpp b/renderdoc/driver/d3d12/d3d12_resources.cpp index 9ebb38b05..7b74c1f72 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.cpp +++ b/renderdoc/driver/d3d12/d3d12_resources.cpp @@ -810,6 +810,261 @@ D3D12ShaderExportDatabase::~D3D12ShaderExportDatabase() m_RayManager->UnregisterExportDatabase(this); } +void D3D12ShaderExportDatabase::PopulateDatabase(size_t NumSubobjects, + const D3D12_STATE_SUBOBJECT *subobjects) +{ + // store the default local root signature - if we only find one in the whole state object then it becomes default + ID3D12RootSignature *defaultRoot = NULL; + bool unassocDefaultValid = false; + bool explicitDefault = false; + bool unassocDXILDefaultValid = false; + uint32_t dxilDefaultRoot = ~0U; + + rdcarray> explicitRootSigAssocs; + rdcarray explicitDefaultDxilAssocs; + rdcarray> explicitDxilAssocs; + rdcflatmap dxilLocalRootSigs; + + rdcarray> inheritedRootSigAssocs; + rdcarray> inheritedDXILRootSigAssocs; + rdcflatmap inheritedDXILLocalRootSigs; + + // fill shader exports list as well as local root signature lookups. + // shader exports that can be queried come from two sources: + // - hit groups + // - exports from a DXIL library + // - exports from a collection + for(size_t i = 0; i < NumSubobjects; i++) + { + if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP) + { + D3D12_HIT_GROUP_DESC *desc = (D3D12_HIT_GROUP_DESC *)subobjects[i].pDesc; + AddExport(StringFormat::Wide2UTF8(desc->HitGroupExport)); + + rdcarray shaders; + if(desc->IntersectionShaderImport) + shaders.push_back(StringFormat::Wide2UTF8(desc->IntersectionShaderImport)); + if(desc->AnyHitShaderImport) + shaders.push_back(StringFormat::Wide2UTF8(desc->AnyHitShaderImport)); + if(desc->ClosestHitShaderImport) + shaders.push_back(StringFormat::Wide2UTF8(desc->ClosestHitShaderImport)); + + // register the hit group so that if we get associations with the individual shaders we + // can apply that up to the hit group + AddLastHitGroupShaders(std::move(shaders)); + } + else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY) + { + D3D12_DXIL_LIBRARY_DESC *dxil = (D3D12_DXIL_LIBRARY_DESC *)subobjects[i].pDesc; + + if(dxil->NumExports > 0) + { + for(UINT e = 0; e < dxil->NumExports; e++) + { + // Name is always the name used for exports - if renaming then the renamed-from name + // is only used to lookup in the dxil library and not for any associations-by-name + AddExport(StringFormat::Wide2UTF8(dxil->pExports[e].Name)); + } + } + else + { + // hard part, we need to parse the DXIL to get the entry points + DXBC::DXBCContainer container( + bytebuf((byte *)dxil->DXILLibrary.pShaderBytecode, dxil->DXILLibrary.BytecodeLength), + rdcstr(), GraphicsAPI::D3D12, ~0U, ~0U); + + rdcarray entries = container.GetEntryPoints(); + + for(const ShaderEntryPoint &e : entries) + AddExport(e.name); + } + + // TODO: register local root signature subobjects into dxilLocalRootSigs. Override + // anything in there, unlike the import from a collection below. + } + else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_EXISTING_COLLECTION) + { + D3D12_EXISTING_COLLECTION_DESC *coll = (D3D12_EXISTING_COLLECTION_DESC *)subobjects[i].pDesc; + + WrappedID3D12StateObject *stateObj = (WrappedID3D12StateObject *)coll->pExistingCollection; + + if(coll->NumExports > 0) + { + for(UINT e = 0; e < coll->NumExports; e++) + InheritCollectionExport(stateObj->exports, StringFormat::Wide2UTF8(coll->pExports[e].Name), + StringFormat::Wide2UTF8(coll->pExports[e].ExportToRename + ? coll->pExports[e].ExportToRename + : coll->pExports[e].Name)); + } + else + { + InheritAllCollectionExports(stateObj->exports); + } + + // inherit explicit associations from the collection as lowest priority + inheritedRootSigAssocs.append(stateObj->exports->danglingRootSigAssocs); + inheritedDXILRootSigAssocs.append(stateObj->exports->danglingDXILRootSigAssocs); + + for(auto it = stateObj->exports->danglingDXILLocalRootSigs.begin(); + it != stateObj->exports->danglingDXILLocalRootSigs.end(); ++it) + { + // don't override any local root signatures with the same name we already have. Not sure + // how this conflict should be resolved properly? + if(dxilLocalRootSigs.find(it->first) == dxilLocalRootSigs.end()) + dxilLocalRootSigs[it->first] = it->second; + } + } + else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) + { + // ignore these if an explicit default association has been made + if(!explicitDefault) + { + // if multiple root signatures are defined, then there can't be an unspecified default + unassocDefaultValid = defaultRoot != NULL; + defaultRoot = ((D3D12_LOCAL_ROOT_SIGNATURE *)subobjects[i].pDesc)->pLocalRootSignature; + } + } + 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; + + const D3D12_STATE_SUBOBJECT *other = assoc->pSubobjectToAssociate; + + // only care about associating local root signatures + if(other->Type == D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE) + { + ID3D12RootSignature *root = ((D3D12_LOCAL_ROOT_SIGNATURE *)other->pDesc)->pLocalRootSignature; + + WrappedID3D12RootSignature *wrappedRoot = (WrappedID3D12RootSignature *)root; + + // if there are no exports this is an explicit default association. We assume this + // matches and doesn't conflict + if(assoc->NumExports == NULL) + { + explicitDefault = true; + defaultRoot = root; + } + else + { + // otherwise record the explicit associations - these may refer to exports that + // haven't been seen yet so we record them locally + for(UINT e = 0; e < assoc->NumExports; e++) + explicitRootSigAssocs.push_back( + {StringFormat::Wide2UTF8(assoc->pExports[e]), wrappedRoot->localRootSigIdx}); + } + } + } + else if(subobjects[i].Type == D3D12_STATE_SUBOBJECT_TYPE_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION) + { + D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION *assoc = + (D3D12_DXIL_SUBOBJECT_TO_EXPORTS_ASSOCIATION *)subobjects[i].pDesc; + + rdcstr other = StringFormat::Wide2UTF8(assoc->SubobjectToAssociate); + + // we can't tell yet if this is a local root signature or not so we have to store it regardless + { + // if there are no exports this is an explicit default association, but we don't know if + // it's for a local root signature... + if(assoc->NumExports == NULL) + { + explicitDefaultDxilAssocs.push_back(other); + } + else + { + // otherwise record the explicit associations - these may refer to exports that + // haven't been seen yet so we record them locally + for(UINT e = 0; e < assoc->NumExports; e++) + explicitDxilAssocs.push_back({StringFormat::Wide2UTF8(assoc->pExports[e]), other}); + } + } + } + } + + // now that we have all exports registered, apply all associations we have in order of + // priority to get the right + + for(size_t i = 0; i < explicitRootSigAssocs.size(); i++) + { + ApplyRoot(SubObjectPriority::CodeExplicitAssociation, explicitRootSigAssocs[i].first, + explicitRootSigAssocs[i].second); + } + + if(explicitDefault) + { + WrappedID3D12RootSignature *wrappedRoot = (WrappedID3D12RootSignature *)defaultRoot; + + ApplyDefaultRoot(SubObjectPriority::CodeExplicitDefault, wrappedRoot->localRootSigIdx); + } + // shouldn't be possible to have both explicit and implicit defaults? + else if(unassocDefaultValid) + { + WrappedID3D12RootSignature *wrappedRoot = (WrappedID3D12RootSignature *)defaultRoot; + + ApplyDefaultRoot(SubObjectPriority::CodeImplicitDefault, wrappedRoot->localRootSigIdx); + } + + for(size_t i = 0; i < explicitDxilAssocs.size(); i++) + { + auto it = dxilLocalRootSigs.find(explicitDxilAssocs[i].second); + + if(it == dxilLocalRootSigs.end()) + continue; + + uint32_t localRootSigIdx = it->second; + + ApplyRoot(SubObjectPriority::DXILExplicitAssociation, explicitDxilAssocs[i].first, + localRootSigIdx); + } + + for(size_t i = 0; i < explicitDefaultDxilAssocs.size(); i++) + { + auto it = dxilLocalRootSigs.find(explicitDefaultDxilAssocs[i]); + + if(it == dxilLocalRootSigs.end()) + continue; + + uint32_t localRootSigIdx = it->second; + + ApplyDefaultRoot(SubObjectPriority::DXILExplicitDefault, localRootSigIdx); + + // only expect one local root signature - the array is because we can't tell the type of the + // default subobject when we encounter it + break; + } + + if(unassocDXILDefaultValid) + { + ApplyDefaultRoot(SubObjectPriority::DXILImplicitDefault, dxilDefaultRoot); + } + + // we assume it's not possible to inherit two different explicit associations for a single export + + for(size_t i = 0; i < inheritedRootSigAssocs.size(); i++) + { + ApplyRoot(SubObjectPriority::CollectionExplicitAssociation, inheritedRootSigAssocs[i].first, + inheritedRootSigAssocs[i].second); + } + for(size_t i = 0; i < inheritedDXILRootSigAssocs.size(); i++) + { + auto it = dxilLocalRootSigs.find(inheritedDXILRootSigAssocs[i].second); + + if(it == dxilLocalRootSigs.end()) + continue; + + uint32_t localRootSigIdx = it->second; + + ApplyRoot(SubObjectPriority::CollectionExplicitAssociation, inheritedDXILRootSigAssocs[i].first, + localRootSigIdx); + } + + danglingRootSigAssocs.swap(inheritedRootSigAssocs); + danglingDXILRootSigAssocs.swap(inheritedDXILRootSigAssocs); + danglingDXILLocalRootSigs.swap(dxilLocalRootSigs); + + UpdateHitGroupAssociations(); +} + void D3D12ShaderExportDatabase::AddExport(const rdcstr &exportName) { void *identifier = NULL; diff --git a/renderdoc/driver/d3d12/d3d12_resources.h b/renderdoc/driver/d3d12/d3d12_resources.h index e48ff48d3..e77bcd9db 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.h +++ b/renderdoc/driver/d3d12/d3d12_resources.h @@ -947,22 +947,7 @@ public: ResourceId GetResourceId() { return objectOriginalId; } - // register our own newly created export - void AddExport(const rdcstr &exportName); - - // import some or all of a collection's exports - void InheritCollectionExport(D3D12ShaderExportDatabase *existing, const rdcstr &nameToExport, - const rdcstr &nameInExisting); - void InheritAllCollectionExports(D3D12ShaderExportDatabase *existing); - - // we only apply root signature associations to our own exports. Anything that was considered exported - // in a parent object was already final and either had a local root signature, or didn't need one at all. - void ApplyDefaultRoot(SubObjectPriority priority, uint32_t localRootSigIndex); - void ApplyRoot(SubObjectPriority priority, const rdcstr &exportName, uint32_t localRootSigIndex); - - // register a hit group for local root sig inheritance - void AddLastHitGroupShaders(rdcarray &&shaders); - void UpdateHitGroupAssociations(); + void PopulateDatabase(size_t NumSubobjects, const D3D12_STATE_SUBOBJECT *subobjects); void *GetShaderIdentifier(const rdcstr &exportName) { @@ -975,18 +960,6 @@ public: return NULL; } - // these are not technically part of the 'exports' interface but they are very helpful to keep - // around at the same time. These are explicit associations which might yet apply to future - // exports in child state objects - rdcarray> danglingRootSigAssocs; - rdcarray> danglingDXILRootSigAssocs; - rdcflatmap danglingDXILLocalRootSigs; - - // list of hitgroups, with the name of the hit group export and the names of each shader export - // we can't precalculate the indices in this list because they could be dangling references that - // get inherited, so we have to do string lookups every time - rdcarray>> hitGroups; - struct ExportedIdentifier { // the unwrapped identifier to patch the contents of ShaderIdentifier into @@ -1053,10 +1026,39 @@ private: // in-line with wrappedIdentifiers because we want that to be a tight array of actual identifiers rdcarray exportLookups; + // these are not technically part of the 'exports' interface but they are very helpful to keep + // around at the same time. These are explicit associations which might yet apply to future + // exports in child state objects + rdcarray> danglingRootSigAssocs; + rdcarray> danglingDXILRootSigAssocs; + rdcflatmap danglingDXILLocalRootSigs; + + // list of hitgroups, with the name of the hit group export and the names of each shader export + // we can't precalculate the indices in this list because they could be dangling references that + // get inherited, so we have to do string lookups every time + rdcarray>> hitGroups; + void InheritExport(const rdcstr &exportName, D3D12ShaderExportDatabase *existing, size_t i); void ApplyRoot(const ShaderIdentifier &identifier, SubObjectPriority priority, uint32_t localRootSigIndex); + + // register our own newly created export + void AddExport(const rdcstr &exportName); + + // import some or all of a collection's exports + void InheritCollectionExport(D3D12ShaderExportDatabase *existing, const rdcstr &nameToExport, + const rdcstr &nameInExisting); + void InheritAllCollectionExports(D3D12ShaderExportDatabase *existing); + + // we only apply root signature associations to our own exports. Anything that was considered exported + // in a parent object was already final and either had a local root signature, or didn't need one at all. + void ApplyDefaultRoot(SubObjectPriority priority, uint32_t localRootSigIndex); + void ApplyRoot(SubObjectPriority priority, const rdcstr &exportName, uint32_t localRootSigIndex); + + // register a hit group for local root sig inheritance + void AddLastHitGroupShaders(rdcarray &&shaders); + void UpdateHitGroupAssociations(); }; class WrappedID3D12StateObject : public WrappedDeviceChild12, @@ -1078,9 +1080,6 @@ public: : WrappedDeviceChild12(real, device) { real->QueryInterface(__uuidof(ID3D12StateObjectProperties), (void **)&properties); - exports = new D3D12ShaderExportDatabase( - GetResourceID(), m_pDevice->GetResourceManager()->GetRaytracingResourceAndUtilHandler(), - properties); } virtual ~WrappedID3D12StateObject() { @@ -1102,6 +1101,8 @@ public: return WrappedDeviceChild12::QueryInterface(riid, ppvObject); } + ID3D12StateObjectProperties *GetProperties() const { return properties; } + ////////////////////////////// // implement ID3D12StateObject diff --git a/renderdoc/replay/replay_controller.cpp b/renderdoc/replay/replay_controller.cpp index 51aff5300..2339cdff1 100644 --- a/renderdoc/replay/replay_controller.cpp +++ b/renderdoc/replay/replay_controller.cpp @@ -249,6 +249,10 @@ bool ReplayController::PassEquivalent(const ActionDescription &a, const ActionDe if((a.flags & ActionFlags::Dispatch) != (b.flags & ActionFlags::Dispatch)) return false; + // don't group anything with raytracing either + if((a.flags & ActionFlags::DispatchRay) != (b.flags & ActionFlags::DispatchRay)) + return false; + // don't group present with anything if((a.flags & ActionFlags::Present) != (b.flags & ActionFlags::Present)) return false; @@ -400,6 +404,8 @@ void ReplayController::AddFakeMarkers() mark.customName = StringFormat::Fmt("Copy/Clear Pass #%d", copypassID++); else if(actions[refaction].flags & ActionFlags::Dispatch) mark.customName = StringFormat::Fmt("Compute Pass #%d", computepassID++); + else if(actions[refaction].flags & ActionFlags::DispatchRay) + mark.customName = StringFormat::Fmt("Raytracing Pass #%d", computepassID++); else if(maxOutCount == 0) mark.customName = StringFormat::Fmt("Depth-only Pass #%d", depthpassID++); else if(minOutCount == maxOutCount)