mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-20 20:55:42 +00:00
Implement debug interface for DXIL, to get embedded shader source
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user