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:
baldurk
2024-04-29 17:25:08 +01:00
parent 4c3de55d20
commit 34aba75128
6 changed files with 729 additions and 2 deletions
@@ -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;
+48
View File
@@ -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,
+16
View File
@@ -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
+245
View File
@@ -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();
+152 -2
View File
@@ -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
{