Re-use ray dispatch patching on replay

This commit is contained in:
baldurk
2024-04-30 18:28:33 +01:00
parent ffb9c6cb3b
commit 0dfb8474c1
8 changed files with 385 additions and 299 deletions
@@ -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<ID3D12RootSignature>(state.compute.rootsig)));
Unwrap4(list)->SetPipelineState1(
Unwrap(GetResourceManager()->GetCurrentAs<ID3D12StateObject>(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<ID3D12RootSignature>(state.compute.rootsig)));
Unwrap4(pCommandList)
->SetPipelineState1(
Unwrap(GetResourceManager()->GetCurrentAs<ID3D12StateObject>(state.stateobj)));
state.ApplyComputeRootElementsUnwrapped(Unwrap4(pCommandList));
m_Cmd->m_RayDispatches.push_back(patchedDispatch.resources);
Unwrap4(pCommandList)->DispatchRays(&patchedDispatch.desc);
m_Cmd->AddEvent();
+2
View File
@@ -363,6 +363,8 @@ struct D3D12CommandData
double m_TimeFrequency = 1.0f;
SDFile *m_StructuredFile;
rdcarray<PatchedRayDispatch::Resources> m_RayDispatches;
std::map<ResourceId, rdcarray<EventUsage>> m_ResourceUses;
D3D12ActionTreeNode m_ParentAction;
+10
View File
@@ -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;
}
+33 -264
View File
@@ -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<ID3D12RootSignature *> rootSigs;
rdcarray<ID3D12StateObject *> 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<rdcpair<rdcstr, uint32_t>> explicitRootSigAssocs;
rdcarray<rdcstr> explicitDefaultDxilAssocs;
rdcarray<rdcpair<rdcstr, rdcstr>> explicitDxilAssocs;
rdcflatmap<rdcstr, uint32_t> dxilLocalRootSigs;
rdcarray<rdcpair<rdcstr, uint32_t>> inheritedRootSigAssocs;
rdcarray<rdcpair<rdcstr, rdcstr>> inheritedDXILRootSigAssocs;
rdcflatmap<rdcstr, uint32_t> 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<rdcstr> 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<ShaderEntryPoint> 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;
+8 -1
View File
@@ -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();
+255
View File
@@ -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<rdcpair<rdcstr, uint32_t>> explicitRootSigAssocs;
rdcarray<rdcstr> explicitDefaultDxilAssocs;
rdcarray<rdcpair<rdcstr, rdcstr>> explicitDxilAssocs;
rdcflatmap<rdcstr, uint32_t> dxilLocalRootSigs;
rdcarray<rdcpair<rdcstr, uint32_t>> inheritedRootSigAssocs;
rdcarray<rdcpair<rdcstr, rdcstr>> inheritedDXILRootSigAssocs;
rdcflatmap<rdcstr, uint32_t> 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<rdcstr> 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<ShaderEntryPoint> 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;
+32 -31
View File
@@ -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<rdcstr> &&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<rdcpair<rdcstr, uint32_t>> danglingRootSigAssocs;
rdcarray<rdcpair<rdcstr, rdcstr>> danglingDXILRootSigAssocs;
rdcflatmap<rdcstr, uint32_t> 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<rdcpair<rdcstr, rdcarray<rdcstr>>> 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<ExportLookup> 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<rdcpair<rdcstr, uint32_t>> danglingRootSigAssocs;
rdcarray<rdcpair<rdcstr, rdcstr>> danglingDXILRootSigAssocs;
rdcflatmap<rdcstr, uint32_t> 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<rdcpair<rdcstr, rdcarray<rdcstr>>> 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<rdcstr> &&shaders);
void UpdateHitGroupAssociations();
};
class WrappedID3D12StateObject : public WrappedDeviceChild12<ID3D12StateObject>,
@@ -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
+6
View File
@@ -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)