diff --git a/renderdoc/driver/shaders/dxbc/dxbc_container.cpp b/renderdoc/driver/shaders/dxbc/dxbc_container.cpp index a8e9e7bde..60caed524 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_container.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_container.cpp @@ -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); } diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.h b/renderdoc/driver/shaders/dxil/dxil_bytecode.h index 56771f9a8..1fb5ae1bd 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.h +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.h @@ -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 &callstack) const override; + + bool HasSourceMapping() const override; + void GetLocals(const DXBC::DXBCContainer *dxbc, size_t instruction, uintptr_t offset, + rdcarray &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 m_GlobalVars; rdcarray m_Functions; rdcarray m_Aliases; diff --git a/renderdoc/driver/shaders/dxil/dxil_reflect.cpp b/renderdoc/driver/shaders/dxil/dxil_reflect.cpp index d4dba8851..890a8c196 100644 --- a/renderdoc/driver/shaders/dxil/dxil_reflect.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_reflect.cpp @@ -223,9 +223,13 @@ struct DXMeta const Metadata *viewIdState = NULL; const Metadata *entryPoints = NULL; + // technically llvm.ident + const Metadata *ident = NULL; + DXMeta(const rdcarray &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 &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 &locals) const +{ + locals.clear(); +} + }; // namespace DXIL