Implement debug interface for DXIL, to get embedded shader source

This commit is contained in:
baldurk
2020-06-19 14:45:57 +01:00
parent 253a03f5be
commit 4d6e4857f6
3 changed files with 174 additions and 3 deletions
@@ -1390,6 +1390,9 @@ DXBCContainer::DXBCContainer(const void *ByteCode, size_t ByteCodeLength)
}
}
if(m_DXILByteCode)
m_DebugInfo = m_DXILByteCode;
// we do a mini-preprocess of the files from the debug info to handle #line directives.
// This means that any lines that our source file declares to be in another filename via a #line
// get put in the right place for what the debug information hopefully matches.
@@ -1398,7 +1401,8 @@ DXBCContainer::DXBCContainer(const void *ByteCode, size_t ByteCodeLength)
if(m_DebugInfo)
{
m_DXBCByteCode->SetDebugInfo(m_DebugInfo);
if(m_DXBCByteCode)
m_DXBCByteCode->SetDebugInfo(m_DebugInfo);
struct SplitFile
{
@@ -1626,9 +1630,15 @@ DXBCContainer::DXBCContainer(const void *ByteCode, size_t ByteCodeLength)
DXBCContainer::~DXBCContainer()
{
// DXIL bytecode doubles as debug info, don't delete it twice
if(m_DXILByteCode)
m_DebugInfo = NULL;
SAFE_DELETE(m_DebugInfo);
SAFE_DELETE(m_DXBCByteCode);
SAFE_DELETE(m_DXILByteCode);
SAFE_DELETE(m_Reflection);
}
+18 -2
View File
@@ -493,13 +493,13 @@ struct Function
AttachedMetadata attachedMeta;
};
class Program
class Program : public DXBC::IDebugInfo
{
public:
Program(const byte *bytes, size_t length);
Program(const Program &o) = default;
Program &operator=(const Program &o) = default;
virtual ~Program() {}
static bool Valid(const byte *bytes, size_t length);
void FetchComputeProperties(DXBC::Reflection *reflection);
@@ -516,6 +516,19 @@ public:
return m_Disassembly;
}
// IDebugInfo interface
rdcstr GetCompilerSig() const override { return m_CompilerSig; }
rdcstr GetEntryFunction() const override { return m_EntryPoint; }
rdcstr GetShaderProfile() const override { return m_Profile; }
ShaderCompileFlags GetShaderCompileFlags() const override { return m_CompileFlags; }
void GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const override;
void GetCallstack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &callstack) const override;
bool HasSourceMapping() const override;
void GetLocals(const DXBC::DXBCContainer *dxbc, size_t instruction, uintptr_t offset,
rdcarray<SourceVariableMapping> &locals) const override;
private:
void MakeDisassemblyString();
@@ -534,6 +547,9 @@ private:
DXBC::ShaderType m_Type;
uint32_t m_Major, m_Minor;
rdcstr m_CompilerSig, m_EntryPoint, m_Profile;
ShaderCompileFlags m_CompileFlags;
rdcarray<GlobalVar> m_GlobalVars;
rdcarray<Function> m_Functions;
rdcarray<Alias> m_Aliases;
@@ -223,9 +223,13 @@ struct DXMeta
const Metadata *viewIdState = NULL;
const Metadata *entryPoints = NULL;
// technically llvm.ident
const Metadata *ident = NULL;
DXMeta(const rdcarray<NamedMetadata> &namedMeta)
{
DXMeta &dx = *this;
DXMeta &llvm = *this;
for(size_t i = 0; i < namedMeta.size(); i++)
{
@@ -233,6 +237,7 @@ struct DXMeta
if(namedMeta[i].name == #metaname) \
metaname = &namedMeta[i];
GRAB_META(llvm.ident);
GRAB_META(dx.source.contents);
GRAB_META(dx.source.defines);
GRAB_META(dx.source.mainFileName);
@@ -746,6 +751,114 @@ DXBC::Reflection *Program::GetReflection()
TypeInfo typeInfo(dx.typeAnnotations);
if(dx.ident && dx.ident->children.size() == 1 && dx.ident->children[0]->children.size() == 1)
{
m_CompilerSig = "dxc - " + dx.ident->children[0]->children[0]->str;
}
else
{
m_CompilerSig = "dxc - unknown version";
}
if(dx.valver && dx.valver->children.size() == 1 && dx.valver->children[0]->children.size() == 2)
{
m_CompilerSig += StringFormat::Fmt(" (Validation version %s.%s)",
dx.valver->children[0]->children[0]->constant->toString(),
dx.valver->children[0]->children[1]->constant->toString());
}
if(dx.entryPoints && dx.entryPoints->children.size() > 0 &&
dx.entryPoints->children[0]->children.size() > 2)
{
m_EntryPoint = dx.entryPoints->children[0]->children[1]->str;
}
else
{
RDCERR("Didn't find dx.entryPoints");
m_EntryPoint = "main";
}
if(dx.shaderModel && dx.shaderModel->children.size() == 1 &&
dx.shaderModel->children[0]->children.size() == 3)
{
m_Profile = StringFormat::Fmt("%s_%s_%s", dx.shaderModel->children[0]->children[0]->str,
dx.shaderModel->children[0]->children[1]->constant->toString(),
dx.shaderModel->children[0]->children[2]->constant->toString());
}
else
{
switch(m_Type)
{
case DXBC::ShaderType::Pixel: m_Profile = "ps"; break;
case DXBC::ShaderType::Vertex: m_Profile = "vs"; break;
case DXBC::ShaderType::Geometry: m_Profile = "gs"; break;
case DXBC::ShaderType::Hull: m_Profile = "hs"; break;
case DXBC::ShaderType::Domain: m_Profile = "ds"; break;
case DXBC::ShaderType::Compute: m_Profile = "cs"; break;
default: m_Profile = "xx"; break;
}
m_Profile += StringFormat::Fmt("_%u_%u", m_Major, m_Minor);
}
if(dx.source.contents)
{
for(const Metadata *f : dx.source.contents->children)
{
if(f->children.size() != 2)
continue;
Files.push_back({f->children[0]->str, f->children[1]->str});
}
// push the main filename to the front
if(dx.source.mainFileName && !dx.source.mainFileName->children.empty())
{
rdcstr mainFile = dx.source.mainFileName->children[0]->str;
if(!mainFile.empty())
{
for(size_t i = 1; i < Files.size(); i++)
{
if(Files[i].first == mainFile)
{
std::swap(Files[0], Files[i]);
break;
}
}
}
}
}
if(dx.source.args && dx.source.args->children.size() == 1)
{
rdcstr cmdline;
for(const Metadata *f : dx.source.args->children[0]->children)
{
rdcstr param = f->str;
param.trim();
if(param.find_first_of(" \t\r\n") >= 0)
{
cmdline += " \"";
for(char c : param)
{
if(c == '"')
cmdline.push_back('\\');
cmdline.push_back(c);
}
cmdline += "\"";
}
else
{
cmdline += " " + param;
}
}
m_CompileFlags.flags.push_back({"@cmdline", cmdline});
}
else
{
m_CompileFlags.flags.push_back({"@cmdline", "-T " + m_Profile});
}
if(dx.resources)
{
RDCASSERTEQUAL(dx.resources->children.size(), 1);
@@ -864,4 +977,36 @@ DXBC::Reflection *Program::GetReflection()
return refl;
}
void Program::GetLineInfo(size_t instruction, uintptr_t offset, LineColumnInfo &lineInfo) const
{
lineInfo = LineColumnInfo();
for(const Function &f : m_Functions)
{
if(instruction < f.instructions.size())
{
lineInfo.disassemblyLine = f.instructions[instruction].disassemblyLine;
break;
}
instruction -= f.instructions.size();
}
}
void Program::GetCallstack(size_t instruction, uintptr_t offset, rdcarray<rdcstr> &callstack) const
{
callstack.clear();
}
bool Program::HasSourceMapping() const
{
// not yet implemented and only relevant for debugging
return false;
}
void Program::GetLocals(const DXBC::DXBCContainer *dxbc, size_t instruction, uintptr_t offset,
rdcarray<SourceVariableMapping> &locals) const
{
locals.clear();
}
}; // namespace DXIL