mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-26 01:11:49 +00:00
Re-use ray dispatch patching on replay
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user