Add shader debug loading logging for shaders in DXBC containers

This commit is contained in:
Jake Turner
2026-02-06 10:39:11 +13:00
parent 5135ef6f75
commit 8d2fbbfadf
3 changed files with 117 additions and 7 deletions
@@ -122,12 +122,12 @@ struct DebugFile
bool empty() { return path.empty(); }
void ReadAndProcess(bool lz4, const rdcfixedarray<uint32_t, 4> &desiredHash)
void ReadAndProcess(bool lz4, const rdcfixedarray<uint32_t, 4> &desiredHash, rdcstr &log)
{
FileIO::ReadAll(path, contents);
Process(lz4, desiredHash);
Process(lz4, desiredHash, log);
}
void Process(bool lz4, const rdcfixedarray<uint32_t, 4> &desiredHash)
void Process(bool lz4, const rdcfixedarray<uint32_t, 4> &desiredHash, rdcstr &log)
{
if(lz4)
{
@@ -151,6 +151,7 @@ struct DebugFile
if(ret < 0)
{
RDCERR("Failed to decompress LZ4 data from %s", path.c_str());
log += StringFormat::Fmt("\nFailed to decompress LZ4 data from '%s'\n", path.c_str());
return;
}
}
@@ -183,6 +184,11 @@ struct DebugFile
if(debugDataHash != desiredHash)
{
RDCWARN("Debug info file at %s does not match hash from shader, ignoring", path.c_str());
log += StringFormat::Fmt(
"Ignoring debug info file '%s' hash 0x08%X08%X08%X08%X does not match shader hash "
"0x08%X08%X08%X08%X",
path.c_str(), debugDataHash[0], debugDataHash[1], debugDataHash[2], debugDataHash[3],
desiredHash[0], desiredHash[1], desiredHash[2], desiredHash[3]);
// invalidate ourselves
path.clear();
@@ -1482,6 +1488,7 @@ rdcstr DXBCContainer::GetDebugBinaryPath(const void *ByteCode, size_t ByteCodeLe
void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &debugInfoPath)
{
rdcstr loadingLog;
if(!CheckForDebugInfo((const void *)&byteCode[0], byteCode.size()))
{
rdcstr originalPath = debugInfoPath;
@@ -1499,6 +1506,8 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
for(uint32_t i = 0; i < desiredHash.byteSize(); i++)
originalPath += StringFormat::Fmt("%02x", h[i]);
originalPath += ".pdb";
loadingLog += StringFormat::Fmt("No shader PDB filename specified using default '%s'\n\n",
originalPath.c_str());
RDCDEBUG("No shader pdb filename specified - assuming default '%s'", originalPath.c_str());
}
@@ -1518,6 +1527,33 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
size_t numSearchPaths = searchPaths.size();
const rdcarray<rdcstr> nonRecursiveSearchPaths = Replay_Shader_LimitedSearchDirPaths();
loadingLog += StringFormat::Fmt("Shader filepath '%s'\n", originalPath.c_str());
if(searchPaths.size() > nonRecursiveSearchPaths.size())
{
loadingLog += rdcstr("\nRecursive Search Path(s):\n");
for(const rdcstr &path : searchPaths)
{
if(nonRecursiveSearchPaths.contains(path))
continue;
loadingLog += StringFormat::Fmt("'%s'\n", path.c_str());
}
}
else
{
loadingLog += rdcstr("\nNo Recursive Search Paths\n");
}
if(!nonRecursiveSearchPaths.empty())
{
loadingLog += rdcstr("\nNon-Recursive Search Path(s):\n");
for(const rdcstr &path : nonRecursiveSearchPaths)
loadingLog += StringFormat::Fmt("'%s'\n", path.c_str());
}
else
{
loadingLog += rdcstr("\nNo Non-Recursive Search Paths\n");
}
DebugFile found;
rdcstr nickname = originalPath;
@@ -1537,6 +1573,7 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
{
if(i == 0)
{
loadingLog += rdcstr("\n");
if(FileIO::exists(tempPath))
found.path = tempPath;
else if(!hasSuffix && FileIO::exists(tempPath + ".pdb"))
@@ -1548,7 +1585,16 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
tempPath.c_str(), originalPath.c_str());
// this may empty out found, if the hash doesn't match
found.ReadAndProcess(lz4, desiredHash);
found.ReadAndProcess(lz4, desiredHash, loadingLog);
loadingLog += StringFormat::Fmt("File found using filepath '%s'\n", found.path.c_str());
}
else
{
loadingLog +=
StringFormat::Fmt("File not found using filepath '%s'\n", tempPath.c_str());
if(!hasSuffix)
loadingLog +=
StringFormat::Fmt("File not found using filepath '%s.pdb'\n", tempPath.c_str());
}
}
else
@@ -1568,7 +1614,18 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
tempPath.c_str(), originalPath.c_str());
// this may empty out found, if the hash doesn't match
found.ReadAndProcess(lz4, desiredHash);
found.ReadAndProcess(lz4, desiredHash, loadingLog);
loadingLog += StringFormat::Fmt(
"File found in search directory using filepath '%s'\n", found.path.c_str());
}
else
{
loadingLog += StringFormat::Fmt(
"File not found in search directory using filepath '%s'\n", checkPath.c_str());
if(!hasSuffix)
loadingLog += StringFormat::Fmt(
"File not found in search directory using filepath '%s.pdb'\n",
checkPath.c_str());
}
}
}
@@ -1599,6 +1656,7 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
// on each replay.
if(found.empty() && !originalPath.contains('/') && !originalPath.contains('\\'))
{
loadingLog += rdcstr("\n");
CacheSearchDirDebugPaths();
auto it = cachedDebugFilesLookup.find(originalPath);
@@ -1609,8 +1667,27 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
found.path = it->second;
RDCDEBUG("Found %s recursively as %s", originalPath.c_str(), found.path.c_str());
found.ReadAndProcess(lz4, desiredHash);
found.ReadAndProcess(lz4, desiredHash, loadingLog);
loadingLog += StringFormat::Fmt(
"File found in recursive directory search using filepath '%s'\n", found.path.c_str());
}
else
{
loadingLog += StringFormat::Fmt(
"File not found in recursive directory search using filepath '%s'\n",
originalPath.c_str());
if(!hasSuffix)
loadingLog += StringFormat::Fmt(
"File not found in recursive directory search using filepath '%s.pdb'\n",
originalPath.c_str());
}
}
else if(found.empty())
{
loadingLog += StringFormat::Fmt(
"\nNot performing a recursive directory search because filepath contains directory "
"information '%s'\n",
originalPath.c_str());
}
// Try to retrieve debug file from the externally referenced files in the capture
@@ -1618,14 +1695,31 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
{
if(RenderDoc::Inst().GetTrackedFileData(nickname, found.contents))
{
loadingLog += StringFormat::Fmt(
"\nFound debug data from files embedded in the capture using nickname '%s'\n",
nickname.c_str());
found.path = nickname;
found.Process(lz4, desiredHash);
found.Process(lz4, desiredHash, loadingLog);
}
else
{
loadingLog += StringFormat::Fmt(
"\nFile not found in files embedded in the capture using nickname '%s'\n",
nickname.c_str());
}
}
if(found.empty())
{
RDCDEBUG("Couldn't find pdb for %s", originalPath.c_str());
m_DebugInfoLoadingLog =
StringFormat::Fmt("Did not find debug data for '%s'\n\n", originalPath.c_str());
if(!loadingLog.empty())
{
m_DebugInfoLoadingLog += StringFormat::Fmt("Details\n");
m_DebugInfoLoadingLog += StringFormat::Fmt("-------\n\n");
m_DebugInfoLoadingLog += loadingLog;
}
return;
}
@@ -1639,8 +1733,21 @@ void DXBCContainer::TryFetchSeparateDebugInfo(bytebuf &byteCode, const rdcstr &d
{
byteCode.swap(found.contents);
}
m_DebugInfoLoadingLog =
StringFormat::Fmt("Found debug data using filepath '%s'\n\n", found.path.c_str());
}
}
else
{
m_DebugInfoLoadingLog =
StringFormat::Fmt("Found debug data in the shader '%s'\n\n", debugInfoPath.c_str());
}
if(!loadingLog.empty())
{
m_DebugInfoLoadingLog += StringFormat::Fmt("Details\n");
m_DebugInfoLoadingLog += StringFormat::Fmt("-------\n\n");
m_DebugInfoLoadingLog += loadingLog;
}
}
DXBCContainer::DXBCContainer(const bytebuf &ByteCode, const rdcstr &debugInfoPath, GraphicsAPI api,
@@ -209,6 +209,7 @@ public:
void CacheOutputTopology();
D3D_PRIMITIVE_TOPOLOGY GetOutputTopology() const { return m_OutputTopology; }
ThreadScope GetThreadScope() const { return m_Threadscope; }
const rdcstr &GetDebugInfoLoadingLog() const { return m_DebugInfoLoadingLog; }
CBufferVariableType GetRayPayload(const ShaderEntryPoint &entry)
{
@@ -285,6 +286,7 @@ private:
bytebuf m_ShaderBlob;
rdcstr m_Disassembly;
rdcstr m_DebugInfoLoadingLog;
bool m_DXCStyle = false;
D3D_PRIMITIVE_TOPOLOGY m_OutputTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
@@ -320,6 +320,7 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, const ShaderEntryPoint &ent
}
refl->debugInfo.entrySourceName = refl->entryPoint = "main";
refl->debugInfo.debugInfoLoadingLog = dxbc->GetDebugInfoLoadingLog();
if(dxbc->GetDebugInfo())
{