Implemented support for separate unstripped shader debug info

It works this way:
The GameEngine stored the original shader blob on disk.
Than we add the path to that file to the D3D_BLOB_PRIVATE_DATA section of the shader blob.
After that we can strip the Debug information with D3DCOMPILER_STRIP_DEBUG_INFO.

Renderdoc will first check if the shader already has debug information.
If it cannot find the PDB in the shader blob it will try to look for a PrivateDataSection.
If there is a valid file path in the PrivateDataSection it will search for debug information in there.
If it finds valid debug information it will replace the entire shader blob with the one loaded from disk.
This commit is contained in:
unknown
2016-03-06 13:18:59 +01:00
committed by baldurk
parent bd7d38bbef
commit 8458b1d7a7
4 changed files with 119 additions and 0 deletions
@@ -62,6 +62,39 @@ map<ResourceId,WrappedID3D11Buffer::BufferEntry> WrappedID3D11Buffer::m_BufferLi
map<ResourceId,WrappedShader::ShaderEntry*> WrappedShader::m_ShaderList;
Threading::CriticalSection WrappedShader::m_ShaderListLock;
void WrappedShader::ShaderEntry::TryReplaceOriginalByteCode()
{
if(!DXBC::DXBCFile::CheckForDebugInfo((const void *)&m_Bytecode[0], m_Bytecode.size()))
{
string originalPath = DXBC::DXBCFile::GetDebugBinaryPath((const void *)&m_Bytecode[0], m_Bytecode.size());
if(!originalPath.empty())
{
FILE* originalShaderFile = FileIO::fopen(originalPath.c_str(), "rb");
if(originalShaderFile != nullptr)
{
FileIO::fseek64(originalShaderFile, 0L, SEEK_END);
uint64_t originalShaderSize = FileIO::ftell64(originalShaderFile);
FileIO::fseek64(originalShaderFile, 0, SEEK_SET);
if(originalShaderSize >= m_Bytecode.size())
{
vector<byte> originalBytecode;
originalBytecode.resize(originalShaderSize);
FileIO::fread(&originalBytecode[0], sizeof(byte), originalShaderSize, originalShaderFile);
if(DXBC::DXBCFile::CheckForDebugInfo((const void *)&originalBytecode[0], originalBytecode.size()))
{
m_Bytecode.swap(originalBytecode);
}
}
FileIO::fclose(originalShaderFile);
}
}
}
}
UINT GetMipForSubresource(ID3D11Resource *res, int Subresource)
{
D3D11_RESOURCE_DIMENSION dim;
+4
View File
@@ -1089,7 +1089,10 @@ public:
DXBC::DXBCFile *GetDXBC()
{
if(m_DXBCFile == NULL && !m_Bytecode.empty())
{
TryReplaceOriginalByteCode();
m_DXBCFile = new DXBC::DXBCFile((const void *)&m_Bytecode[0], m_Bytecode.size());
}
return m_DXBCFile;
}
ShaderReflection *GetDetails()
@@ -1100,6 +1103,7 @@ public:
}
private:
ShaderEntry(const ShaderEntry &e);
void TryReplaceOriginalByteCode();
ShaderEntry &operator =(const ShaderEntry &e);
vector<byte> m_Bytecode;
@@ -156,6 +156,14 @@ struct SIGNHeader
// for OSG5 you should use SIGNElement7
};
struct PRIVHeader
{
uint32_t fourcc; // "ISGN", "OSGN, "OSG5", "PCSG"
uint32_t chunkLength; // length of this chunk
void* data;
};
struct SIGNElement
{
uint32_t nameOffset; // relative to the same offset base position as others in similar chunks - after FourCC and chunk length.
@@ -192,6 +200,7 @@ static const uint32_t FOURCC_OSGN = MAKE_FOURCC('O', 'S', 'G', 'N');
static const uint32_t FOURCC_OSG5 = MAKE_FOURCC('O', 'S', 'G', '5');
static const uint32_t FOURCC_PCSG = MAKE_FOURCC('P', 'C', 'S', 'G');
static const uint32_t FOURCC_Aon9 = MAKE_FOURCC('A', 'o', 'n', '9');
static const uint32_t FOURCC_PRIV = MAKE_FOURCC('P', 'R', 'I', 'V');
int TypeByteSize(VariableType t)
{
@@ -455,6 +464,75 @@ CBufferVariableType DXBCFile::ParseRDEFType(RDEFHeader *h, char *chunkContents,
return ret;
}
bool DXBCFile::CheckForDebugInfo(const void *ByteCode, size_t ByteCodeLength)
{
FileHeader *header = (FileHeader *)ByteCode;
char *data = (char *)ByteCode; // just for convenience
if(header->fourcc != FOURCC_DXBC)
return false;
if(header->fileLength != (uint32_t)ByteCodeLength)
return false;
uint32_t *chunkOffsets = (uint32_t *)(header+1); // right after the header
for (uint32_t chunkIdx = 0; chunkIdx < header->numChunks; chunkIdx++)
{
uint32_t *fourcc = (uint32_t *)(data + chunkOffsets[chunkIdx]);
if(*fourcc == FOURCC_SDBG)
{
return true;
}
else if(*fourcc == FOURCC_SPDB)
{
return true;
}
}
return false;
}
string DXBCFile::GetDebugBinaryPath(const void *ByteCode, size_t ByteCodeLength)
{
string debugPath;
FileHeader *header = (FileHeader *)ByteCode;
char *data = (char *)ByteCode; // just for convenience
if(header->fourcc != FOURCC_DXBC)
return debugPath;
if(header->fileLength != (uint32_t)ByteCodeLength)
return debugPath;
uint32_t *chunkOffsets = (uint32_t *)(header+1); // right after the header
static char* dbgData = nullptr;
for(uint32_t chunkIdx = 0; chunkIdx < header->numChunks; chunkIdx++)
{
uint32_t *fourcc = (uint32_t *)(data + chunkOffsets[chunkIdx]);
dbgData = (char*)fourcc;
if(*fourcc == FOURCC_PRIV)
{
PRIVHeader *privHeader = (PRIVHeader *)fourcc;
const char* pathData = (char*)&privHeader->data;
size_t pathLength = strlen(pathData);
if(privHeader->chunkLength == (pathLength + 1))
{
debugPath.append(pathData, pathData + pathLength);
return debugPath;
}
}
}
return debugPath;
}
DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength)
{
m_DebugInfo = NULL;
@@ -372,6 +372,10 @@ class DXBCFile
const ASMOperation &GetInstruction(size_t i) { return m_Instructions[i]; }
size_t NumOperands(OpcodeType op);
static bool CheckForDebugInfo(const void *ByteCode, size_t ByteCodeLength);
static string GetDebugBinaryPath(const void *ByteCode, size_t ByteCodeLength);
private:
DXBCFile(const DXBCFile &o);
DXBCFile &operator =(const DXBCFile &o);