mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-17 07:21:03 +00:00
Register local root signatures and databases of state object exports
* This information will be used for wrapping, unwrapping & replay-remapping of shader records
This commit is contained in:
@@ -1078,6 +1078,11 @@ bool WrappedID3D12Device::Serialise_CreateRootSignature(SerialiserType &ser, UIN
|
||||
|
||||
wrapped->sig = GetShaderCache()->GetRootSig(pBlobWithRootSignature, (size_t)blobLengthInBytes);
|
||||
|
||||
if(wrapped->sig.Flags & D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE)
|
||||
wrapped->localRootSigIdx =
|
||||
GetResourceManager()->GetRaytracingResourceAndUtilHandler()->RegisterLocalRootSig(
|
||||
wrapped->sig);
|
||||
|
||||
{
|
||||
StructuredSerialiser structuriser(ser.GetStructuredFile().chunks.back(), &GetChunkName);
|
||||
structuriser.SetUserData(GetResourceManager());
|
||||
@@ -1143,6 +1148,11 @@ HRESULT WrappedID3D12Device::CreateRootSignature(UINT nodeMask, const void *pBlo
|
||||
|
||||
wrapped->sig = GetShaderCache()->GetRootSig(pBlobWithRootSignature, blobLengthInBytes);
|
||||
|
||||
if(wrapped->sig.Flags & D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE)
|
||||
wrapped->localRootSigIdx =
|
||||
GetResourceManager()->GetRaytracingResourceAndUtilHandler()->RegisterLocalRootSig(
|
||||
wrapped->sig);
|
||||
|
||||
if(!m_BindlessResourceUseActive)
|
||||
{
|
||||
// force ref-all-resources if the heap is directly indexed because we can't track resource
|
||||
|
||||
@@ -250,6 +250,264 @@ 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;
|
||||
|
||||
// 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();
|
||||
|
||||
D3D12ResourceRecord *record = GetResourceManager()->AddResourceRecord(wrapped->GetResourceID());
|
||||
record->type = Resource_PipelineState;
|
||||
record->Length = 0;
|
||||
|
||||
@@ -861,6 +861,54 @@ void D3D12RaytracingResourceAndUtilHandler::InitReplayBlasPatchingResources()
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t D3D12RaytracingResourceAndUtilHandler::RegisterLocalRootSig(const D3D12RootSignature &sig)
|
||||
{
|
||||
rdcarray<uint32_t> tableOffsets;
|
||||
uint32_t offset = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES;
|
||||
for(uint32_t i = 0; i < sig.Parameters.size(); i++)
|
||||
{
|
||||
// constants are 4-byte aligned, everything else is 8-byte
|
||||
if(sig.Parameters[i].ParameterType != D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS)
|
||||
offset = AlignUp(offset, 8U);
|
||||
|
||||
if(sig.Parameters[i].ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
|
||||
tableOffsets.push_back(offset);
|
||||
|
||||
if(sig.Parameters[i].ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS)
|
||||
offset += sig.Parameters[i].Constants.Num32BitValues * sizeof(uint32_t);
|
||||
else
|
||||
offset += sizeof(uint64_t);
|
||||
}
|
||||
|
||||
// no patching needed if no tables
|
||||
if(tableOffsets.empty())
|
||||
return ~0U;
|
||||
|
||||
int idx = m_UniqueLocalRootSigs.indexOf(tableOffsets);
|
||||
if(idx < 0)
|
||||
{
|
||||
idx = m_UniqueLocalRootSigs.count();
|
||||
m_UniqueLocalRootSigs.push_back(tableOffsets);
|
||||
}
|
||||
|
||||
m_LookupBufferDirty = true;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
void D3D12RaytracingResourceAndUtilHandler::RegisterExportDatabase(D3D12ShaderExportDatabase *db)
|
||||
{
|
||||
m_ExportDatabases.push_back(db);
|
||||
m_LookupBufferDirty = true;
|
||||
}
|
||||
|
||||
void D3D12RaytracingResourceAndUtilHandler::UnregisterExportDatabase(D3D12ShaderExportDatabase *db)
|
||||
{
|
||||
m_ExportDatabases.push_back(db);
|
||||
// don't dirty the lookup buffer here, there's not much value in recreating it just to reduce
|
||||
// memory use - next time we need to add data we'll reclaim that.
|
||||
}
|
||||
|
||||
D3D12GpuBufferAllocator *D3D12GpuBufferAllocator::m_bufferAllocator = NULL;
|
||||
|
||||
bool D3D12GpuBufferAllocator::CopyBufferRegion(WrappedID3D12GraphicsCommandList *wrappedCmd,
|
||||
|
||||
@@ -1072,6 +1072,11 @@ public:
|
||||
|
||||
void InitInternalResources();
|
||||
|
||||
uint32_t RegisterLocalRootSig(const D3D12RootSignature &sig);
|
||||
|
||||
void RegisterExportDatabase(D3D12ShaderExportDatabase *db);
|
||||
void UnregisterExportDatabase(D3D12ShaderExportDatabase *db);
|
||||
|
||||
void ResizeSerialisationBuffer(UINT64 size);
|
||||
|
||||
// buffer in UAV state for emitting AS queries to, CPU accessible/mappable
|
||||
@@ -1091,6 +1096,17 @@ private:
|
||||
HANDLE m_gpuSyncHandle;
|
||||
UINT64 m_gpuSyncCounter;
|
||||
D3D12AccStructPatchInfo m_accStructPatchInfo;
|
||||
|
||||
// each unique set of descriptor table offsets are stored here, so any root signatures which only
|
||||
// vary in ways that don't affect which tables are contained within them (and so don't need
|
||||
// patching) will have a single entry in here
|
||||
rdcarray<rdcarray<uint32_t>> m_UniqueLocalRootSigs;
|
||||
|
||||
// export databases that are alive
|
||||
rdcarray<D3D12ShaderExportDatabase *> m_ExportDatabases;
|
||||
|
||||
// is the lookup buffer dirty and needs to be recreated with the latest data?
|
||||
bool m_LookupBufferDirty = true;
|
||||
};
|
||||
|
||||
struct D3D12ResourceManagerConfiguration
|
||||
|
||||
@@ -792,6 +792,251 @@ void WrappedID3D12PipelineState::ProcessDescriptorAccess()
|
||||
}
|
||||
}
|
||||
|
||||
D3D12ShaderExportDatabase::D3D12ShaderExportDatabase(ResourceId id,
|
||||
D3D12RaytracingResourceAndUtilHandler *rayManager,
|
||||
ID3D12StateObjectProperties *obj)
|
||||
: RefCounter12(NULL), objectOriginalId(id), m_RayManager(rayManager), m_StateObjectProps(obj)
|
||||
{
|
||||
m_RayManager->RegisterExportDatabase(this);
|
||||
}
|
||||
|
||||
D3D12ShaderExportDatabase::~D3D12ShaderExportDatabase()
|
||||
{
|
||||
for(D3D12ShaderExportDatabase *parent : parents)
|
||||
{
|
||||
SAFE_RELEASE(parent);
|
||||
}
|
||||
|
||||
m_RayManager->UnregisterExportDatabase(this);
|
||||
}
|
||||
|
||||
void D3D12ShaderExportDatabase::AddExport(const rdcstr &exportName)
|
||||
{
|
||||
void *identifier = NULL;
|
||||
if(m_StateObjectProps)
|
||||
identifier = m_StateObjectProps->GetShaderIdentifier(StringFormat::UTF82Wide(exportName).c_str());
|
||||
const bool complete = identifier != NULL;
|
||||
|
||||
{
|
||||
// store the wrapped identifier here in this database, ready to return to the application in
|
||||
// this object or any child objects.
|
||||
wrappedIdentifiers.push_back({objectOriginalId, (uint32_t)ownExports.size()});
|
||||
|
||||
// store the unwrapping information to go into the giant lookup table
|
||||
ownExports.push_back({});
|
||||
// if there's a real identifier then store it. But we track this regardless so that we can
|
||||
// know the root signature for hitgroup-component shaders. If this export is inherited then it
|
||||
// will be detected as incomplete and copied and patched in the child
|
||||
if(identifier)
|
||||
memcpy(ownExports.back().real, identifier, sizeof(ShaderIdentifier));
|
||||
// a local root signature may never get specified, so default to none
|
||||
ownExports.back().rootSigPrio = SubObjectPriority::NotYetDefined;
|
||||
ownExports.back().localRootSigIndex = 0xffff;
|
||||
}
|
||||
|
||||
if(exportName.size() > 2 && exportName[0] == '\x1' && exportName[1] == '?')
|
||||
{
|
||||
int idx = exportName.indexOf('@');
|
||||
if(idx > 2)
|
||||
{
|
||||
exportLookups.emplace_back(exportName, exportName.substr(2, idx - 2), complete);
|
||||
return;
|
||||
}
|
||||
}
|
||||
exportLookups.emplace_back(exportName, rdcstr(), complete);
|
||||
}
|
||||
|
||||
void D3D12ShaderExportDatabase::InheritCollectionExport(D3D12ShaderExportDatabase *existing,
|
||||
const rdcstr &nameToExport,
|
||||
const rdcstr &nameInExisting)
|
||||
{
|
||||
if(!parents.contains(existing))
|
||||
{
|
||||
parents.push_back(existing);
|
||||
existing->AddRef();
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < existing->exportLookups.size(); i++)
|
||||
{
|
||||
if(existing->exportLookups[i].name == nameInExisting ||
|
||||
existing->exportLookups[i].altName == nameInExisting)
|
||||
{
|
||||
InheritExport(nameInExisting, existing, i);
|
||||
|
||||
// if we renamed, now that we found the right export in the existing collection use the
|
||||
// desired name going forward. This may still find the existing identifier as that hasn't
|
||||
// necessarily changed
|
||||
if(nameToExport != nameInExisting)
|
||||
{
|
||||
exportLookups.back().name = nameToExport;
|
||||
exportLookups.back().altName.clear();
|
||||
|
||||
if(exportLookups.back().hitgroup)
|
||||
hitGroups.back().first = nameToExport;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ShaderExportDatabase::InheritExport(const rdcstr &exportName,
|
||||
D3D12ShaderExportDatabase *existing, size_t i)
|
||||
{
|
||||
void *identifier = NULL;
|
||||
if(m_StateObjectProps)
|
||||
identifier = m_StateObjectProps->GetShaderIdentifier(StringFormat::UTF82Wide(exportName).c_str());
|
||||
|
||||
wrappedIdentifiers.push_back(existing->wrappedIdentifiers[i]);
|
||||
exportLookups.push_back(existing->exportLookups[i]);
|
||||
|
||||
// if this export wasn't previously complete, consider it exported in this object
|
||||
// note that identifier may be NULL if this is a shader that can't be used on its own like any
|
||||
// hit, but we want to keep it in our export list so we can track its root signature to update
|
||||
// the hit group's root signature. Since there is only one level of collection => RT PSO this
|
||||
// won't cause too much wasted exports
|
||||
// we don't inherit non-complete identifiers when doing AddToStateObject so this doesn't apply
|
||||
if(!exportLookups.back().complete)
|
||||
{
|
||||
ownExports.push_back({});
|
||||
|
||||
// we expect this identifier to have come from the object we're inheriting
|
||||
RDCASSERTEQUAL(wrappedIdentifiers.back().id, existing->objectOriginalId);
|
||||
// which means we can copy any root signature it had associated even if it wasn't complete
|
||||
ownExports.back() = existing->ownExports[wrappedIdentifiers.back().index];
|
||||
|
||||
// now set the identifier, if we got one
|
||||
if(identifier)
|
||||
memcpy(ownExports.back().real, identifier, sizeof(ShaderIdentifier));
|
||||
|
||||
// and re-point this to point to ourselves when queried as we have the best data for it.
|
||||
wrappedIdentifiers.back() = {objectOriginalId, (uint32_t)ownExports.size()};
|
||||
|
||||
// if this is an incomplete hitgroup, also grab the hitgroup component data
|
||||
if(exportLookups.back().hitgroup)
|
||||
{
|
||||
for(size_t h = 0; h < existing->hitGroups.size(); h++)
|
||||
{
|
||||
if(existing->hitGroups[h].first == exportName)
|
||||
{
|
||||
hitGroups.push_back(existing->hitGroups[h]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ShaderExportDatabase::ApplyRoot(SubObjectPriority priority, const rdcstr &exportName,
|
||||
uint32_t localRootSigIndex)
|
||||
{
|
||||
for(size_t i = 0; i < exportLookups.size(); i++)
|
||||
{
|
||||
if(exportLookups[i].name == exportName || exportLookups[i].altName == exportName)
|
||||
{
|
||||
ApplyRoot(wrappedIdentifiers[i], priority, localRootSigIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ShaderExportDatabase::ApplyRoot(const ShaderIdentifier &identifier,
|
||||
SubObjectPriority priority, uint32_t localRootSigIndex)
|
||||
{
|
||||
if(identifier.id == objectOriginalId)
|
||||
{
|
||||
// set this anywhere we have a looser/lower priority association already (including the most
|
||||
// common case presumably where one isn't set at all)
|
||||
ExportedIdentifier &exported = ownExports[identifier.index];
|
||||
if(exported.rootSigPrio < priority)
|
||||
{
|
||||
exported.rootSigPrio = priority;
|
||||
exported.localRootSigIndex = (uint16_t)localRootSigIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ShaderExportDatabase::AddLastHitGroupShaders(rdcarray<rdcstr> &&shaders)
|
||||
{
|
||||
exportLookups.back().hitgroup = true;
|
||||
hitGroups.emplace_back(exportLookups.back().name, shaders);
|
||||
}
|
||||
|
||||
void D3D12ShaderExportDatabase::UpdateHitGroupAssociations()
|
||||
{
|
||||
// for each hit group
|
||||
for(size_t h = 0; h < hitGroups.size(); h++)
|
||||
{
|
||||
// find it in the exports, as it could have been dangling before
|
||||
for(size_t e = 0; e < exportLookups.size(); e++)
|
||||
{
|
||||
if(hitGroups[h].first == exportLookups[e].name)
|
||||
{
|
||||
// if the export is our own (ie. not complete and finished in a parent), we might need to
|
||||
// update its root sig
|
||||
if(wrappedIdentifiers[e].id == objectOriginalId)
|
||||
{
|
||||
// if the hit group got a code association already we assume it must match, but a DXIL
|
||||
// association or a default association could be overridden since it's unclear if a
|
||||
// hitgroup is a 'candidate' for default
|
||||
if(ownExports[wrappedIdentifiers[e].index].rootSigPrio !=
|
||||
SubObjectPriority::CodeExplicitAssociation)
|
||||
{
|
||||
// for each export, find it and try to update the root signature
|
||||
for(const rdcstr &shaderExport : hitGroups[h].second)
|
||||
{
|
||||
for(size_t e2 = 0; e2 < exportLookups.size(); e2++)
|
||||
{
|
||||
if(shaderExport == exportLookups[e2].name || shaderExport == exportLookups[e2].altName)
|
||||
{
|
||||
RDCASSERTEQUAL(wrappedIdentifiers[e2].id, objectOriginalId);
|
||||
uint32_t idx = wrappedIdentifiers[e2].index;
|
||||
ApplyRoot(wrappedIdentifiers[e], ownExports[idx].rootSigPrio,
|
||||
ownExports[idx].localRootSigIndex);
|
||||
|
||||
// don't keep looking at exports, we found this shader
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we've inherited an explicit code association from a component shader, that
|
||||
// also must match so we can stop looking. Otherwise we keep looking to try and find
|
||||
// a 'better' association that can't be overridden
|
||||
if(ownExports[wrappedIdentifiers[e].index].rootSigPrio ==
|
||||
SubObjectPriority::CodeExplicitAssociation)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// found this hit group, don't keep looking
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ShaderExportDatabase::InheritAllCollectionExports(D3D12ShaderExportDatabase *existing)
|
||||
{
|
||||
if(!parents.contains(existing))
|
||||
{
|
||||
parents.push_back(existing);
|
||||
existing->AddRef();
|
||||
}
|
||||
|
||||
wrappedIdentifiers.reserve(wrappedIdentifiers.size() + existing->wrappedIdentifiers.size());
|
||||
exportLookups.reserve(exportLookups.size() + existing->exportLookups.size());
|
||||
for(size_t i = 0; i < existing->exportLookups.size(); i++)
|
||||
{
|
||||
InheritExport(existing->exportLookups[i].name, existing, i);
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12ShaderExportDatabase::ApplyDefaultRoot(SubObjectPriority priority,
|
||||
uint32_t localRootSigIndex)
|
||||
{
|
||||
for(size_t i = 0; i < wrappedIdentifiers.size(); i++)
|
||||
ApplyRoot(wrappedIdentifiers[i], priority, localRootSigIndex);
|
||||
}
|
||||
|
||||
UINT GetPlaneForSubresource(ID3D12Resource *res, int Subresource)
|
||||
{
|
||||
D3D12_RESOURCE_DESC desc = res->GetDesc();
|
||||
|
||||
@@ -911,17 +911,162 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// the priorities of subobject associations. Default associations are not(?) inherited from
|
||||
// collections into PSOs, and are not inherited from DXIL libraries into state objects.
|
||||
// explicit associations are passed down from collection to state object but have the lowest priority of them all
|
||||
enum class SubObjectPriority : uint16_t
|
||||
{
|
||||
NotYetDefined,
|
||||
// an explicit association in a collection - either from DXIL or code matters not by the time we
|
||||
// get to a PSO including the collection
|
||||
CollectionExplicitAssociation,
|
||||
// subobject declared in DXIL in the same library but not associated at all
|
||||
DXILImplicitDefault,
|
||||
// subobject declared in DXIL and defaulted but just with an empty export string'
|
||||
DXILExplicitDefault,
|
||||
// subobject declared in DXIL and explicitly associated to an export
|
||||
DXILExplicitAssociation,
|
||||
// Object declared in code but not associated at all
|
||||
CodeImplicitDefault,
|
||||
// Object declared in code and defaulted with NULL export array
|
||||
CodeExplicitDefault,
|
||||
// Object declared in code and explicitly associated to an export
|
||||
CodeExplicitAssociation,
|
||||
};
|
||||
|
||||
typedef WrappedID3D12PipelineState::ShaderEntry WrappedID3D12Shader;
|
||||
|
||||
struct D3D12ShaderExportDatabase : public RefCounter12<IUnknown>
|
||||
{
|
||||
public:
|
||||
D3D12ShaderExportDatabase(ResourceId id, D3D12RaytracingResourceAndUtilHandler *rayManager,
|
||||
ID3D12StateObjectProperties *obj);
|
||||
~D3D12ShaderExportDatabase();
|
||||
|
||||
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 *GetShaderIdentifier(const rdcstr &exportName)
|
||||
{
|
||||
RDCCOMPILE_ASSERT(sizeof(D3D12ShaderExportDatabase::ShaderIdentifier) ==
|
||||
D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES,
|
||||
"Shader Identifier is wrongly sized");
|
||||
for(size_t i = 0; i < exportLookups.size(); i++)
|
||||
if(exportLookups[i].name == exportName || exportLookups[i].altName == exportName)
|
||||
return exportLookups[i].complete ? &wrappedIdentifiers[i] : NULL;
|
||||
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
|
||||
uint32_t real[8];
|
||||
// the index of the local root signature data to look up if local parameters need to be patched.
|
||||
uint16_t localRootSigIndex;
|
||||
// Subobjects have many different levels of priority they can come from, and the correct maximum
|
||||
// level may not be clear for a while and may be overridden late. This keeps track of where we
|
||||
// got the root signature from so that it can be overridden as necessary
|
||||
SubObjectPriority rootSigPrio;
|
||||
};
|
||||
|
||||
// unwrapped identifiers of NON-INHERITED NEWLY CREATED exports
|
||||
// inherited exports are stored in the ownExports array of the database created for those objects,
|
||||
// even if the objects themselves are not even around anymore - since the identifiers returned for
|
||||
// them need to stay valid.
|
||||
rdcarray<ExportedIdentifier> ownExports;
|
||||
|
||||
private:
|
||||
// the state object that originally created this export database. Some of our shader identifiers
|
||||
// may come from other databases, but when uploading the unwrap buffer we store information such
|
||||
// that if we want to unwrap an identifier that comes from this id we look up into unwrappedOwnExports
|
||||
// below. This is the original ID since this is used to look up identifiers that came from the application
|
||||
ResourceId objectOriginalId;
|
||||
|
||||
rdcarray<D3D12ShaderExportDatabase *> parents;
|
||||
|
||||
ID3D12StateObjectProperties *m_StateObjectProps = NULL;
|
||||
D3D12RaytracingResourceAndUtilHandler *m_RayManager = NULL;
|
||||
|
||||
struct ExportLookup
|
||||
{
|
||||
ExportLookup(rdcstr name, rdcstr altName, bool complete)
|
||||
: name(name), altName(altName), complete(complete)
|
||||
{
|
||||
}
|
||||
ExportLookup() = default;
|
||||
|
||||
// name of an export
|
||||
rdcstr name;
|
||||
// alternate names - for when name is mangled and unmangled names can be looked up
|
||||
rdcstr altName;
|
||||
// is this export complete - we rely on the runtime to resolve all the arcane rules and do any
|
||||
// DXIL linking to tell if this export is actually complete or not.
|
||||
// the first object where a shader identifier comes back is the one where we store the wrapped
|
||||
// identifier, since identifiers must be cross-compatible and persistent
|
||||
bool complete = false;
|
||||
// whether this export is a hitgroup - incomplete hitgroups get inherited explicitly
|
||||
bool hitgroup = false;
|
||||
};
|
||||
|
||||
struct ShaderIdentifier
|
||||
{
|
||||
ResourceId id; // the object which has the actual identifier in its ownExports array
|
||||
uint32_t index; // the index in the object's ownExports array
|
||||
uint32_t pad[5]; // padding up to D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES
|
||||
};
|
||||
|
||||
// wrapped identifiers for all exports in this database, ready to return to the application,
|
||||
// including any inherited from parent objects and not referring to our exports
|
||||
rdcarray<ShaderIdentifier> wrappedIdentifiers;
|
||||
|
||||
// parallel array to wrappedIdentifiers of export lookup information. This is parallel and not
|
||||
// in-line with wrappedIdentifiers because we want that to be a tight array of actual identifiers
|
||||
rdcarray<ExportLookup> exportLookups;
|
||||
|
||||
void InheritExport(const rdcstr &exportName, D3D12ShaderExportDatabase *existing, size_t i);
|
||||
|
||||
void ApplyRoot(const ShaderIdentifier &identifier, SubObjectPriority priority,
|
||||
uint32_t localRootSigIndex);
|
||||
};
|
||||
|
||||
class WrappedID3D12StateObject : public WrappedDeviceChild12<ID3D12StateObject>,
|
||||
public ID3D12StateObjectProperties
|
||||
{
|
||||
ID3D12StateObjectProperties *properties;
|
||||
|
||||
|
||||
public:
|
||||
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12StateObject);
|
||||
|
||||
D3D12ShaderExportDatabase *exports = NULL;
|
||||
|
||||
enum
|
||||
{
|
||||
TypeEnum = Resource_StateObject,
|
||||
@@ -931,10 +1076,14 @@ public:
|
||||
: WrappedDeviceChild12(real, device)
|
||||
{
|
||||
real->QueryInterface(__uuidof(ID3D12StateObjectProperties), (void **)&properties);
|
||||
exports = new D3D12ShaderExportDatabase(
|
||||
GetResourceID(), m_pDevice->GetResourceManager()->GetRaytracingResourceAndUtilHandler(),
|
||||
properties);
|
||||
}
|
||||
virtual ~WrappedID3D12StateObject()
|
||||
{
|
||||
SAFE_RELEASE(properties);
|
||||
SAFE_RELEASE(exports);
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
@@ -959,7 +1108,7 @@ public:
|
||||
|
||||
virtual void *STDMETHODCALLTYPE GetShaderIdentifier(LPCWSTR pExportName)
|
||||
{
|
||||
return properties->GetShaderIdentifier(pExportName);
|
||||
return exports->GetShaderIdentifier(StringFormat::Wide2UTF8(pExportName));
|
||||
}
|
||||
virtual UINT64 STDMETHODCALLTYPE GetShaderStackSize(LPCWSTR pExportName)
|
||||
{
|
||||
@@ -1236,6 +1385,7 @@ public:
|
||||
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12RootSignature);
|
||||
|
||||
D3D12RootSignature sig;
|
||||
uint32_t localRootSigIdx = ~0U;
|
||||
|
||||
enum
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user