in Libraries/D3D12RaytracingFallback/src/StateObjectProcessing.cpp [1711:2085]
void CStateObjectInfo::AddCollection(const D3D12_EXISTING_COLLECTION_DESC* pCollection)
{
if(!pCollection || !pCollection->pExistingCollection)
{
LOG_ERROR(L"NULL specified for D3D12_EXISTING_COLLECTION_DESC or pExistingCollection.");
return;
}
CStateObjectInfo* pColInfo = m_pfnGetStateObjectInfoForExistingCollection(pCollection->pExistingCollection);
if (!pColInfo)
{
LOG_ERROR(L"Failed to extract collection information from D3D12_EXISTING_COLLECTION_DESC.pExistingCollection: "
<< pCollection->pExistingCollection);
return;
}
m_ExistingCollectionList.emplace_back();
auto& wrappedCollection = m_ExistingCollectionList.back();
wrappedCollection.Init(pCollection);
// Don't keep any references to pCollection, pColInfo or their contents -> app memory
// Exception is DXILLibraryReflection, which is a shared pointer (dependency taken below)
for(auto lib : pColInfo->m_DXILLibraryList) // copy shared pointer references
{
m_DXILLibraryList.push_back(lib);
}
// No manual export list, export everything
if (0 == pCollection->NumExports)
{
for (auto exportInfo : pColInfo->m_ExportInfoMap)
{
auto exportNameUnmangled = pColInfo->m_ExportNameMangledToUnmangled.find(exportInfo.first);
assert(exportNameUnmangled != pColInfo->m_ExportNameMangledToUnmangled.end());
AddExport(
exportInfo.first,
exportNameUnmangled->second,
exportInfo.second->m_pFunctionInfo,
exportInfo.second->m_pOwningStateObject,
pColInfo->AllowExternalDependenciesOnLocalDefinitions());
}
for(auto& hitGroup : pColInfo->m_HitGroupList)
{
AddHitGroup(&hitGroup,hitGroup.m_pOwningStateObject);
}
for(ASSOCIATEABLE_SUBOBJECT_NAME i = (ASSOCIATEABLE_SUBOBJECT_NAME)0; i < NUM_ASSOCIATEABLE_SUBOBJECT_TYPES; ((UINT&)i)++)
{
for(auto& association : pColInfo->m_SubobjectToExportsAssociations[i])
{
if(association.m_Exports.size() == 0)
{
continue; // skip default associations as they don't have affect outside their scope
}
CWrappedAssociation* pNewOrExistingAssociation = nullptr;
for(auto& existing : m_SubobjectToExportsAssociations[i])
{
if(association.m_pSubobject->Compare(existing.m_pSubobject))
{
// found a matching existing association
pNewOrExistingAssociation = &existing;
}
}
if(!pNewOrExistingAssociation)
{
m_SubobjectToExportsAssociations[i].emplace_back();
pNewOrExistingAssociation = &m_SubobjectToExportsAssociations[i].back();
pNewOrExistingAssociation->m_pSubobject = TrackAssociateableSubobject(
association.m_SubobjectType,association.m_pSubobject->m_LocalSubobjectDefinition.pDesc,nullptr);
pNewOrExistingAssociation->m_SubobjectType = association.m_SubobjectType;
}
for(auto ex : association.m_Exports)
{
pNewOrExistingAssociation->m_Exports.insert(LocalUniqueCopy(ex));
}
}
}
}
else
{
// Manual export list
// Multimap of internal export names to external export(s) the library desc manually listed (if any)
std::unordered_multimap<std::wstring, const D3D12_EXPORT_DESC*> ExportsToUse;
std::unordered_set<const D3D12_EXPORT_DESC*> ExportMissing;
for (UINT i = 0; i < pCollection->NumExports; i++)
{
LPCWSTR InternalName = pCollection->pExports[i].ExportToRename ? pCollection->pExports[i].ExportToRename : pCollection->pExports[i].Name;
ExportsToUse.insert({ InternalName,&pCollection->pExports[i] });
ExportMissing.insert(&pCollection->pExports[i]);
}
// Multimap of subobjects that were associated -> the exports associated to each one
// The subobjects (CWrappedAssociation*) are from the incoming collection, after the map is
// completely generated, need to make a local CWrappedAssociation for each one
std::unordered_multimap<const CWrappedAssociation*,LPCWSTR> ReferencedAssociations[NUM_ASSOCIATEABLE_SUBOBJECT_TYPES];
std::unordered_set<const CWrappedAssociation*> UniqueReferencedAssociations[NUM_ASSOCIATEABLE_SUBOBJECT_TYPES];
std::unordered_map<const CWrappedAssociation*,CWrappedAssociation*> OldToNewWrappedAssociations;
std::unordered_set<LPCWSTR> OldMangledNamesExported;
std::unordered_set<LPCWSTR> OldMangledNamesRenamed;
// Examine functions
{
auto AddExportWrapper = [&ReferencedAssociations,&UniqueReferencedAssociations,&OldMangledNamesExported,&pColInfo,this]
(LPCWSTR pExternalNameMangled, LPCWSTR pExternalNameUnmangled, LPCWSTR pOldMangledName, const CExportInfo* pColExportInfo)
{
for(ASSOCIATEABLE_SUBOBJECT_NAME i = (ASSOCIATEABLE_SUBOBJECT_NAME)0; i < NUM_ASSOCIATEABLE_SUBOBJECT_TYPES; ((UINT&)i)++)
{
for(auto a : pColExportInfo->m_Associations[i])
{
ReferencedAssociations[i].insert({a,LocalUniqueCopy(pExternalNameMangled)});
UniqueReferencedAssociations[i].insert(a);
}
}
OldMangledNamesExported.insert(pOldMangledName);
AddExport(
pExternalNameMangled,
pExternalNameUnmangled,
pColExportInfo->m_pFunctionInfo,
pColExportInfo->m_pOwningStateObject,
pColInfo->AllowExternalDependenciesOnLocalDefinitions());
};
for (UINT i = 0; i < pCollection->NumExports; i++)
{
LPCWSTR InternalName = pCollection->pExports[i].ExportToRename ? pCollection->pExports[i].ExportToRename : pCollection->pExports[i].Name;
auto matchesUnmangled = pColInfo->m_ExportNameUnmangledToMangled.equal_range(pColInfo->LocalUniqueCopy(InternalName));
// cases: (1) ExportToRename is an unmangled name, Name is unmangled
// (2) ExportToRename is a mangled name, Name is unmangled
// (3) ExportToRename is null, Name is unmangled
// (4) ExportToRename is null, Name is mangled
// AddExport will throw if the same external name is exported multiple times from the state object.
if (matchesUnmangled.first != pColInfo->m_ExportNameUnmangledToMangled.end())
{
for (auto matchUnmangledToMangled = matchesUnmangled.first; matchUnmangledToMangled != matchesUnmangled.second; matchUnmangledToMangled++)
{
auto matchMangledExportInfo = pColInfo->m_ExportInfoMap.find(matchUnmangledToMangled->second);
assert(matchMangledExportInfo != pColInfo->m_ExportInfoMap.end());
if (pCollection->pExports[i].ExportToRename)
{
// (1) - do a rename
AddExportWrapper(RenameMangledName(matchUnmangledToMangled->second, InternalName, pCollection->pExports[i].Name),
pCollection->pExports[i].Name, matchUnmangledToMangled->second, matchMangledExportInfo->second);
OldMangledNamesRenamed.insert(matchUnmangledToMangled->second);
}
else
{
// (3) - no rename
AddExportWrapper(matchUnmangledToMangled->second, InternalName, matchUnmangledToMangled->second, matchMangledExportInfo->second);
}
ExportMissing.erase(&pCollection->pExports[i]);
}
}
else
{
auto matchMangledExportInfo = pColInfo->m_ExportInfoMap.find(pColInfo->LocalUniqueCopy(InternalName));
if (matchMangledExportInfo != pColInfo->m_ExportInfoMap.end())
{
if (pCollection->pExports[i].ExportToRename)
{
// (2) - do a rename
auto mangledOriginalName = pColInfo->LocalUniqueCopy(pCollection->pExports[i].ExportToRename);
auto unmangledOriginalExportName = pColInfo->m_ExportNameMangledToUnmangled.find(mangledOriginalName);
assert(unmangledOriginalExportName != pColInfo->m_ExportNameMangledToUnmangled.end());
AddExportWrapper(RenameMangledName(pCollection->pExports[i].ExportToRename, unmangledOriginalExportName->second, pCollection->pExports[i].Name),
pCollection->pExports[i].Name, mangledOriginalName, matchMangledExportInfo->second);
OldMangledNamesRenamed.insert(mangledOriginalName);
}
else
{
// (4) - no rename
auto mangledOriginalName = pColInfo->LocalUniqueCopy(pCollection->pExports[i].Name);
auto unmangledOriginalExportName = pColInfo->m_ExportNameMangledToUnmangled.find(mangledOriginalName);
assert(unmangledOriginalExportName != pColInfo->m_ExportNameMangledToUnmangled.end());
AddExportWrapper(pCollection->pExports[i].Name, unmangledOriginalExportName->second, mangledOriginalName, matchMangledExportInfo->second);
}
ExportMissing.erase(&pCollection->pExports[i]);
}
}
}
}
// Try hit groups
{
std::unordered_set<const D3D12_EXPORT_DESC*> HitGroupFound;
for(auto& ex : ExportMissing)
{
LPCWSTR InternalName = ex->ExportToRename ? ex->ExportToRename : ex->Name;
auto match = pColInfo->m_HitGroups.find(pColInfo->LocalUniqueCopy(InternalName));
if(match != pColInfo->m_HitGroups.end())
{
D3D12_HIT_GROUP_DESC newHgDesc = *match->second;
newHgDesc.HitGroupExport = ex->Name;
// See if the constituent shaders were renamed
const CWrappedHitGroup& hgDesc = *match->second;
for (UINT s = 0; s < 3; s++)
{
LPCWSTR pDependency = nullptr;
LPCWSTR DependencyType = nullptr;
switch (s)
{
case 0:
pDependency = hgDesc.AnyHitShaderImport;
DependencyType = L"AnyHitShaderImport";
break;
case 1:
pDependency = hgDesc.ClosestHitShaderImport;
DependencyType = L"ClosestHitShaderImport";
break;
case 2:
pDependency = hgDesc.IntersectionShaderImport;
DependencyType = L"IntersectionShaderImport";
break;
default:
assert(false);
break;
}
if (!pDependency)
{
continue;
}
// Was this dependency renamed?
LPCWSTR pName = nullptr;
auto matches = ExportsToUse.equal_range(pDependency);
size_t count = ExportsToUse.count(pDependency);
switch (count)
{
case 0:
// Currently an unresolved export, ok.
pName = pDependency;
break;
case 1:
{
auto match = ExportsToUse.find(pDependency);
pName = match->second->Name;
break;
}
default:
LOG_ERROR(L"HitGroupExport \"" << hgDesc.HitGroupExport <<
L"\" imports " << DependencyType << L" named " << PrettyPrintPossiblyMangledName(pDependency) <<
L" which is being renamed as part of collection creation to multiple export names. "
L"so it is ambiguous which rename applies to " << PrettyPrintPossiblyMangledName(pDependency) << L".");
break;
}
if (pName)
{
switch (s)
{
case 0:
newHgDesc.AnyHitShaderImport = pName;
break;
case 1:
newHgDesc.ClosestHitShaderImport = pName;
break;
case 2:
newHgDesc.IntersectionShaderImport = pName;
break;
default:
assert(false);
break;
}
}
}
for(ASSOCIATEABLE_SUBOBJECT_NAME i = (ASSOCIATEABLE_SUBOBJECT_NAME)0; i < NUM_ASSOCIATEABLE_SUBOBJECT_TYPES; ((UINT&)i)++)
{
for(auto a : match->second->m_Associations[i])
{
ReferencedAssociations[i].insert({a,LocalUniqueCopy(newHgDesc.HitGroupExport)});
UniqueReferencedAssociations[i].insert(a);
}
}
OldMangledNamesExported.insert(match->first);
if(ex->ExportToRename)
{
OldMangledNamesRenamed.insert(match->first);
}
AddHitGroup(&newHgDesc,hgDesc.m_pOwningStateObject);
HitGroupFound.insert(ex);
} // else unresolved reference so far, ok
}
for(auto& found : HitGroupFound)
{
ExportMissing.erase(found);
}
}
// Add associations
for(ASSOCIATEABLE_SUBOBJECT_NAME i = (ASSOCIATEABLE_SUBOBJECT_NAME)0; i < NUM_ASSOCIATEABLE_SUBOBJECT_TYPES; ((UINT&)i)++)
{
for(auto& association : pColInfo->m_SubobjectToExportsAssociations[i])
{
if(association.m_Exports.size() == 0)
{
continue; // skip default associations as they don't have affect outside their scope
}
CWrappedAssociation* pNewOrExistingAssociation = nullptr;
for(auto& existing : m_SubobjectToExportsAssociations[i])
{
if(association.m_pSubobject->Compare(existing.m_pSubobject))
{
// found a matching existing association
pNewOrExistingAssociation = &existing;
}
}
if(!pNewOrExistingAssociation)
{
m_SubobjectToExportsAssociations[i].emplace_back();
pNewOrExistingAssociation = &m_SubobjectToExportsAssociations[i].back();
pNewOrExistingAssociation->m_pSubobject = TrackAssociateableSubobject(
association.m_SubobjectType,association.m_pSubobject->m_LocalSubobjectDefinition.pDesc,nullptr);
pNewOrExistingAssociation->m_SubobjectType = association.m_SubobjectType;
}
for(auto ex : association.m_Exports)
{
// Export only if it wasn't in the collection's incoming export list and renamed,
// and it isn't an export that was resolved in the old collection but not now.
// The destination of these renames handled by the UniqueReferencedAssociations
// processing further below.
bool bOldNameNoLongerExists =
((pColInfo->m_ExportInfoMap.find(ex) != pColInfo->m_ExportInfoMap.end()) &&
(OldMangledNamesExported.find(ex) == OldMangledNamesExported.end()));
bool bOldNameWasRenamed = (OldMangledNamesRenamed.find(ex) != OldMangledNamesRenamed.end());
if(!(bOldNameNoLongerExists || bOldNameWasRenamed))
{
pNewOrExistingAssociation->m_Exports.insert(LocalUniqueCopy(ex));
}
}
OldToNewWrappedAssociations.insert({&association,pNewOrExistingAssociation});
}
for(auto association : UniqueReferencedAssociations[i])
{
// Make a new wrapped association for each unique referenced wrapped association in collection
auto match = OldToNewWrappedAssociations.find(association);
CWrappedAssociation* pNewAssociation = nullptr;
if(match == OldToNewWrappedAssociations.end()) // didn't get added above because it was an empty export list, explicit default association
{
m_SubobjectToExportsAssociations[i].emplace_back();
pNewAssociation = &m_SubobjectToExportsAssociations[i].back();
pNewAssociation->m_pSubobject = TrackAssociateableSubobject(
association->m_SubobjectType,association->m_pSubobject->m_LocalSubobjectDefinition.pDesc,nullptr);
pNewAssociation->m_SubobjectType = association->m_SubobjectType;
}
else
{
pNewAssociation = match->second;
}
// For each export referencing this association, point it to the new local wrapper
auto refs = ReferencedAssociations[i].equal_range(association);
assert(refs.first != ReferencedAssociations[i].end());
for(auto ref = refs.first; ref != refs.second; ref++)
{
pNewAssociation->m_Exports.insert(ref->second);
}
}
}
#ifdef INCLUDE_MESSAGE_LOG
for(auto& ex : ExportMissing)
{
LPCWSTR InternalName = ex->ExportToRename ? ex->ExportToRename : ex->Name;
size_t i = (ex - &pCollection->pExports[0]);
LOG_ERROR(L"Manually listed export [" << i << L"], " << PrettyPrintPossiblyMangledName(InternalName) << L", doesn't exist in collection " << pCollection->pExistingCollection << L".");
}
#else
if(ExportMissing.size())
{
LOG_ERROR_NOMESSAGE;
}
#endif
}
}