From e061ea3b2e165f2f2bb0a92d79a70b485e414d53 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 10 Aug 2022 14:30:54 +0100 Subject: [PATCH] Improve handling of compilers & command line for edited shaders * We store the compiler used (when known) in shader debug info and use that to select the compiler for editing as even higher priority than the default for a given language/encoding combination. * We also ensure that for known tools we add the input and output parameters last, after any custom parameters, so that they are always present regardless of what the user puts in. --- qrenderdoc/Code/CaptureContext.cpp | 13 +- qrenderdoc/Code/CaptureContext.h | 5 +- .../Code/Interface/PersistantConfig.cpp | 50 +++++-- qrenderdoc/Code/Interface/PersistantConfig.h | 124 +--------------- qrenderdoc/Code/Interface/QRDInterface.h | 5 +- .../Code/Interface/ShaderProcessingTool.cpp | 22 +-- .../Code/pyrenderdoc/qrenderdoc_stub.cpp | 5 + .../PipelineState/PipelineStateViewer.cpp | 20 +-- .../PipelineState/PipelineStateViewer.h | 4 +- qrenderdoc/Windows/PythonShell.cpp | 6 +- qrenderdoc/Windows/ShaderViewer.cpp | 34 ++++- qrenderdoc/Windows/ShaderViewer.h | 9 +- qrenderdoc/Windows/TextureViewer.cpp | 2 +- renderdoc/api/replay/renderdoc_tostr.inl | 18 +++ renderdoc/api/replay/replay_enums.h | 134 ++++++++++++++++++ renderdoc/api/replay/shader_types.h | 11 +- renderdoc/driver/gl/gl_shader_refl.cpp | 1 + .../driver/shaders/dxbc/dxbc_reflect.cpp | 4 + .../shaders/spirv/spirv_disassemble.cpp | 25 ++++ .../driver/shaders/spirv/spirv_reflect.cpp | 37 +++-- .../driver/shaders/spirv/spirv_reflect.h | 6 +- renderdoc/replay/renderdoc_serialise.inl | 1 + 22 files changed, 333 insertions(+), 203 deletions(-) diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index e2b68b50b..6abfc0c94 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -2450,8 +2450,8 @@ void CaptureContext::ShowResourceInspector() m_MainWindow->showResourceInspector(); } -IShaderViewer *CaptureContext::EditShader(ResourceId id, ShaderStage stage, - const rdcstr &entryPoint, const rdcstrpairs &files, +IShaderViewer *CaptureContext::EditShader(ResourceId id, ShaderStage stage, const rdcstr &entryPoint, + const rdcstrpairs &files, KnownShaderTool knownTool, ShaderEncoding shaderEncoding, ShaderCompileFlags flags, IShaderViewer::SaveCallback saveCallback, IShaderViewer::RevertCallback revertCallback) @@ -2479,8 +2479,8 @@ IShaderViewer *CaptureContext::EditShader(ResourceId id, ShaderStage stage, revertCallback(ctx, view, id); }; - viewer = ShaderViewer::EditShader(*this, id, stage, entryPoint, files, shaderEncoding, flags, - replaceSaveCallback, replaceRevertCallback, + viewer = ShaderViewer::EditShader(*this, id, stage, entryPoint, files, knownTool, shaderEncoding, + flags, replaceSaveCallback, replaceRevertCallback, [this](ShaderViewer *view, bool closed) { SetModification(CaptureModifications::EditedShaders); if(closed) @@ -2493,8 +2493,9 @@ IShaderViewer *CaptureContext::EditShader(ResourceId id, ShaderStage stage, } else { - viewer = ShaderViewer::EditShader(*this, id, stage, entryPoint, files, shaderEncoding, flags, - saveCallback, revertCallback, NULL, m_MainWindow->Widget()); + viewer = + ShaderViewer::EditShader(*this, id, stage, entryPoint, files, knownTool, shaderEncoding, + flags, saveCallback, revertCallback, NULL, m_MainWindow->Widget()); } return viewer; diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index 4c4f73db4..f37ae3a44 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -245,8 +245,9 @@ public: void ShowResourceInspector() override; IShaderViewer *EditShader(ResourceId id, ShaderStage stage, const rdcstr &entryPoint, - const rdcstrpairs &files, ShaderEncoding shaderEncoding, - ShaderCompileFlags flags, IShaderViewer::SaveCallback saveCallback, + const rdcstrpairs &files, KnownShaderTool knownTool, + ShaderEncoding shaderEncoding, ShaderCompileFlags flags, + IShaderViewer::SaveCallback saveCallback, IShaderViewer::RevertCallback revertCallback) override; void ApplyShaderEdit(IShaderViewer *viewer, ResourceId id, ShaderStage stage, diff --git a/qrenderdoc/Code/Interface/PersistantConfig.cpp b/qrenderdoc/Code/Interface/PersistantConfig.cpp index ed029bf52..d15284e3a 100644 --- a/qrenderdoc/Code/Interface/PersistantConfig.cpp +++ b/qrenderdoc/Code/Interface/PersistantConfig.cpp @@ -511,12 +511,6 @@ bool PersistantConfig::Load(const rdcstr &filename) // if it's declared if(dis.tool != KnownShaderTool::Unknown) tools[(size_t)dis.tool] = true; - - for(KnownShaderTool tool : values()) - { - if(QString(dis.executable).contains(ToolExecutable(tool))) - tools[(size_t)tool] = true; - } } for(KnownShaderTool tool : values()) @@ -524,7 +518,7 @@ bool PersistantConfig::Load(const rdcstr &filename) if(tool == KnownShaderTool::Unknown || tools[(size_t)tool]) continue; - QString exe = ToolExecutable(tool); + rdcstr exe = ToolExecutable(tool); if(exe.isEmpty()) continue; @@ -588,6 +582,7 @@ bool PersistantConfig::Load(const rdcstr &filename) { if(dis.tool != KnownShaderTool::Unknown) { + dis.name = ToQStr(dis.tool); dis.input = ToolInput(dis.tool); dis.output = ToolOutput(dis.tool); } @@ -698,22 +693,47 @@ ShaderProcessingTool::ShaderProcessingTool(const QVariant &var) rdcstr ShaderProcessingTool::DefaultArguments() const { if(tool == KnownShaderTool::SPIRV_Cross) - return "--output {output_file} {input_file} --vulkan-semantics --entry {entry_point} --stage " - "{glsl_stage4}"; + return "--vulkan-semantics --entry {entry_point} --stage {glsl_stage4}"; else if(tool == KnownShaderTool::spirv_dis) - return "--no-color -o {output_file} {input_file}"; + return "--no-color"; else if(tool == KnownShaderTool::glslangValidatorGLSL) - return "-g -V -o {output_file} {input_file} -S {glsl_stage4}"; + return "-g -V -S {glsl_stage4}"; else if(tool == KnownShaderTool::glslangValidatorHLSL) - return "-D -g -V -o {output_file} {input_file} -S {glsl_stage4} -e {entry_point}"; + return "-D -g -V -S {glsl_stage4} -e {entry_point}"; else if(tool == KnownShaderTool::spirv_as) - return "-o {output_file} {input_file}"; - else if(tool == KnownShaderTool::dxc) - return "-T {hlsl_stage2}_6_0 -E {entry_point} -Fo {output_file} {input_file} -spirv"; + return ""; + else if(tool == KnownShaderTool::dxcSPIRV) + return "-T {hlsl_stage2}_6_0 -E {entry_point} -spirv"; + else if(tool == KnownShaderTool::dxcDXIL) + return "-T {hlsl_stage2}_6_0 -E {entry_point}"; + else if(tool == KnownShaderTool::fxc) + return "/T {hlsl_stage2}_5_0 /E {entry_point}"; return args; } +rdcstr ShaderProcessingTool::IOArguments() const +{ + if(tool == KnownShaderTool::SPIRV_Cross) + return "--output {output_file} {input_file}"; + else if(tool == KnownShaderTool::spirv_dis) + return "-o {output_file} {input_file}"; + else if(tool == KnownShaderTool::glslangValidatorGLSL) + return "-o {output_file} {input_file}"; + else if(tool == KnownShaderTool::glslangValidatorHLSL) + return "-o {output_file} {input_file}"; + else if(tool == KnownShaderTool::spirv_as) + return "-o {output_file} {input_file}"; + else if(tool == KnownShaderTool::dxcSPIRV) + return "-Fo {output_file} {input_file}"; + else if(tool == KnownShaderTool::dxcDXIL) + return "-Fo {output_file} {input_file}"; + else if(tool == KnownShaderTool::fxc) + return "/Fo {output_file} {input_file}"; + + return rdcstr(); +} + ShaderProcessingTool::operator QVariant() const { QVariantMap map; diff --git a/qrenderdoc/Code/Interface/PersistantConfig.h b/qrenderdoc/Code/Interface/PersistantConfig.h index ec36f581e..3905b0f51 100644 --- a/qrenderdoc/Code/Interface/PersistantConfig.h +++ b/qrenderdoc/Code/Interface/PersistantConfig.h @@ -30,126 +30,6 @@ class QMutex; -DOCUMENT(R"(Identifies a particular known tool used for shader processing. - -.. data:: Unknown - - Corresponds to no known tool. - -.. data:: SPIRV_Cross - - `SPIRV-Cross `_. - -.. data:: spirv_dis - - `spirv-dis from SPIRV-Tools `_. - -.. data:: glslangValidatorGLSL - - `glslang compiler (GLSL) `_. - -.. data:: glslangValidatorHLSL - - `glslang compiler (HLSL) `_. - -.. data:: spirv_as - - `spirv-as from SPIRV-Tools `_. - -.. data:: dxc - - `DirectX Shader Compiler `_. - -)"); -enum class KnownShaderTool : uint32_t -{ - Unknown, - First = Unknown, - SPIRV_Cross, - spirv_dis, - glslangValidatorGLSL, - glslangValidatorHLSL, - spirv_as, - dxc, - Count, -}; - -ITERABLE_OPERATORS(KnownShaderTool); - -DOCUMENT(R"(Returns the default executable name with no suffix for a given :class:`KnownShaderTool`. - -.. note:: - The executable name is returned with no suffix, e.g. ``foobar`` which may need a platform specific - suffix like ``.exe`` appended. - -:param KnownShaderTool tool: The tool to get the executable name for. -:return: The default executable name for this tool, or an empty string if the tool is unrecognised. -:rtype: str -)"); -inline rdcstr ToolExecutable(KnownShaderTool tool) -{ - if(tool == KnownShaderTool::SPIRV_Cross) - return "spirv-cross"; - else if(tool == KnownShaderTool::spirv_dis) - return "spirv-dis"; - else if(tool == KnownShaderTool::glslangValidatorGLSL) - return "glslangValidator"; - else if(tool == KnownShaderTool::glslangValidatorHLSL) - return "glslangValidator"; - else if(tool == KnownShaderTool::spirv_as) - return "spirv-as"; - else if(tool == KnownShaderTool::dxc) - return "dxc"; - - return ""; -} - -DOCUMENT(R"(Returns the expected default input :class:`~renderdoc.ShaderEncoding` that a -:class:`KnownShaderTool` expects. This may not be accurate and may be configurable depending on the -tool. - -:param KnownShaderTool tool: The tool to get the input encoding for. -:return: The encoding that this tool expects as an input by default. -:rtype: renderdoc.ShaderEncoding -)"); -inline ShaderEncoding ToolInput(KnownShaderTool tool) -{ - if(tool == KnownShaderTool::SPIRV_Cross || tool == KnownShaderTool::spirv_dis) - return ShaderEncoding::SPIRV; - else if(tool == KnownShaderTool::glslangValidatorGLSL) - return ShaderEncoding::GLSL; - else if(tool == KnownShaderTool::glslangValidatorHLSL) - return ShaderEncoding::HLSL; - else if(tool == KnownShaderTool::spirv_as) - return ShaderEncoding::SPIRVAsm; - else if(tool == KnownShaderTool::dxc) - return ShaderEncoding::HLSL; - - return ShaderEncoding::Unknown; -} - -DOCUMENT(R"(Returns the expected default output :class:`~renderdoc.ShaderEncoding` that a -:class:`KnownShaderTool` produces. This may not be accurate and may be configurable depending on the -tool. - -:param KnownShaderTool tool: The tool to get the output encoding for. -:return: The encoding that this tool produces as an output by default. -:rtype: renderdoc.ShaderEncoding -)"); -inline ShaderEncoding ToolOutput(KnownShaderTool tool) -{ - if(tool == KnownShaderTool::SPIRV_Cross) - return ShaderEncoding::GLSL; - else if(tool == KnownShaderTool::spirv_dis) - return ShaderEncoding::SPIRVAsm; - else if(tool == KnownShaderTool::glslangValidatorGLSL || - tool == KnownShaderTool::glslangValidatorHLSL || tool == KnownShaderTool::spirv_as || - tool == KnownShaderTool::dxc) - return ShaderEncoding::SPIRV; - - return ShaderEncoding::Unknown; -} - DOCUMENT(R"(Contains the output from invoking a :class:`ShaderProcessingTool`, including both the actual output data desired as well as any stdout/stderr messages. )"); @@ -241,6 +121,10 @@ struct ShaderProcessingTool )"); ShaderToolOutput CompileShader(QWidget *window, rdcstr source, rdcstr entryPoint, ShaderStage stage, rdcstr args) const; + +private: + DOCUMENT("Internal function"); + rdcstr IOArguments() const; }; DECLARE_REFLECTION_STRUCT(ShaderProcessingTool); diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index 730169689..60ad8b199 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -2515,6 +2515,7 @@ place if needed. :param str entryPoint: The entry point to be used when compiling the edited shader. :param List[Tuple[str,str]] files: The source files, with each tuple being a pair of the filename and the file contents. +:param renderdoc.KnownShaderTool knownTool: The preferred tool to use to compile, if known. :param renderdoc.ShaderEncoding shaderEncoding: The encoding of the input files. :param renderdoc.ShaderCompileFlags flags: The flags originally used to compile the shader. :param ShaderViewer.SaveCallback saveCallback: The callback function to call when a save/update is @@ -2525,8 +2526,8 @@ place if needed. :rtype: ShaderViewer )"); virtual IShaderViewer *EditShader(ResourceId id, ShaderStage stage, const rdcstr &entryPoint, - const rdcstrpairs &files, ShaderEncoding shaderEncoding, - ShaderCompileFlags flags, + const rdcstrpairs &files, KnownShaderTool knownTool, + ShaderEncoding shaderEncoding, ShaderCompileFlags flags, IShaderViewer::SaveCallback saveCallback, IShaderViewer::RevertCallback revertCallback) = 0; diff --git a/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp b/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp index 0634e2be8..eab561715 100644 --- a/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp +++ b/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp @@ -36,22 +36,6 @@ static const QString hlsl_stage2[arraydim()] = { lit("vs"), lit("hs"), lit("ds"), lit("gs"), lit("ps"), lit("cs"), }; -template <> -rdcstr DoStringise(const KnownShaderTool &el) -{ - BEGIN_ENUM_STRINGISE(KnownShaderTool); - { - STRINGISE_ENUM_CLASS_NAMED(Unknown, "Custom Tool"); - STRINGISE_ENUM_CLASS_NAMED(SPIRV_Cross, "SPIRV-Cross"); - STRINGISE_ENUM_CLASS_NAMED(spirv_dis, "spirv-dis"); - STRINGISE_ENUM_CLASS_NAMED(glslangValidatorGLSL, "glslang (GLSL)"); - STRINGISE_ENUM_CLASS_NAMED(glslangValidatorHLSL, "glslang (HLSL)"); - STRINGISE_ENUM_CLASS_NAMED(spirv_as, "spirv-as"); - STRINGISE_ENUM_CLASS_NAMED(dxc, "dxc"); - } - END_ENUM_STRINGISE(); -} - static QString tmpPath(const QString &filename) { return QDir(QDir::tempPath()).absoluteFilePath(filename); @@ -201,6 +185,9 @@ ShaderToolOutput ShaderProcessingTool::DisassembleShader(QWidget *window, rdcstr arguments) const { QStringList argList = ParseArgsList(arguments.isEmpty() ? DefaultArguments() : arguments); + // always append IO arguments for known tools, so we read/write to our own files and override any + // dangling output specified file in the embedded command line + argList.append(ParseArgsList(IOArguments())); QString input_file, output_file; @@ -253,6 +240,9 @@ ShaderToolOutput ShaderProcessingTool::CompileShader(QWidget *window, rdcstr sou rdcstr arguments) const { QStringList argList = ParseArgsList(arguments.isEmpty() ? DefaultArguments() : arguments); + // always append IO arguments for known tools, so we read/write to our own files and override any + // dangling output specified file in the embedded command line + argList.append(ParseArgsList(IOArguments())); QString input_file, output_file; diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp index fa9a52cb1..6870008d9 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp @@ -74,6 +74,11 @@ rdcstr ShaderProcessingTool::DefaultArguments() const return ""; } +rdcstr ShaderProcessingTool::IOArguments() const +{ + return ""; +} + ShaderToolOutput ShaderProcessingTool::DisassembleShader(QWidget *window, const ShaderReflection *shaderDetails, rdcstr arguments) const diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp index 4e395f5f4..65f46ec06 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp @@ -978,10 +978,12 @@ void PipelineStateViewer::shaderEdit_clicked() IShaderViewer *PipelineStateViewer::EditShader(ResourceId id, ShaderStage shaderType, const rdcstr &entry, ShaderCompileFlags compileFlags, - ShaderEncoding encoding, const rdcstrpairs &files) + KnownShaderTool knownTool, + ShaderEncoding shaderEncoding, + const rdcstrpairs &files) { - IShaderViewer *sv = - m_Ctx.EditShader(id, shaderType, entry, files, encoding, compileFlags, NULL, NULL); + IShaderViewer *sv = m_Ctx.EditShader(id, shaderType, entry, files, knownTool, shaderEncoding, + compileFlags, NULL, NULL); m_Ctx.AddDockWindow(sv->Widget(), DockReference::AddTo, this); @@ -1025,7 +1027,8 @@ IShaderViewer *PipelineStateViewer::EditOriginalShaderSource(ResourceId id, } return EditShader(id, shaderDetails->stage, shaderDetails->entryPoint, - shaderDetails->debugInfo.compileFlags, shaderDetails->debugInfo.encoding, files); + shaderDetails->debugInfo.compileFlags, shaderDetails->debugInfo.compiler, + shaderDetails->debugInfo.encoding, files); } IShaderViewer *PipelineStateViewer::EditDecompiledSource(const ShaderProcessingTool &tool, @@ -1040,8 +1043,8 @@ IShaderViewer *PipelineStateViewer::EditDecompiledSource(const ShaderProcessingT rdcstrpairs files; files.push_back(rdcpair("decompiled", source)); - IShaderViewer *sv = - EditShader(id, shaderDetails->stage, shaderDetails->entryPoint, {}, tool.output, files); + IShaderViewer *sv = EditShader(id, shaderDetails->stage, shaderDetails->entryPoint, {}, + KnownShaderTool::Unknown, tool.output, files); sv->ShowErrors(out.log); @@ -1133,7 +1136,8 @@ void PipelineStateViewer::SetupShaderEditButton(QToolButton *button, ResourceId files.push_back(rdcpair("pseudocode", editeddisasm)); EditShader(shaderId, shaderDetails->stage, shaderDetails->entryPoint, - shaderDetails->debugInfo.compileFlags, ShaderEncoding::Unknown, files); + shaderDetails->debugInfo.compileFlags, KnownShaderTool::Unknown, + ShaderEncoding::Unknown, files); }); }); } @@ -1147,7 +1151,7 @@ void PipelineStateViewer::SetupShaderEditButton(QToolButton *button, ResourceId "decompiled_stub.hlsl", GenerateHLSLStub(bindpointMapping, shaderDetails, entry))); EditShader(shaderId, shaderDetails->stage, entry, shaderDetails->debugInfo.compileFlags, - ShaderEncoding::HLSL, files); + KnownShaderTool::Unknown, ShaderEncoding::HLSL, files); } }); diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h index a4c5f8643..0e1fc82a5 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h @@ -146,8 +146,8 @@ private: QString GenerateHLSLStub(const ShaderBindpointMapping &bindpointMapping, const ShaderReflection *shaderDetails, const QString &entryFunc); IShaderViewer *EditShader(ResourceId id, ShaderStage shaderType, const rdcstr &entry, - ShaderCompileFlags compileFlags, ShaderEncoding encoding, - const rdcstrpairs &files); + ShaderCompileFlags compileFlags, KnownShaderTool knownTool, + ShaderEncoding shaderEncoding, const rdcstrpairs &files); IShaderViewer *EditOriginalShaderSource(ResourceId id, const ShaderReflection *shaderDetails); IShaderViewer *EditDecompiledSource(const ShaderProcessingTool &tool, ResourceId id, const ShaderReflection *shaderDetails); diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index 7b9cb2f21..8ddb43aca 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -754,13 +754,13 @@ struct CaptureContextInvoker : ObjectForwarder InvokeVoidFunction(&ICaptureContext::ShowResourceInspector); } virtual IShaderViewer *EditShader(ResourceId id, ShaderStage stage, const rdcstr &entryPoint, - const rdcstrpairs &files, ShaderEncoding shaderEncoding, - ShaderCompileFlags flags, + const rdcstrpairs &files, KnownShaderTool knownTool, + ShaderEncoding shaderEncoding, ShaderCompileFlags flags, IShaderViewer::SaveCallback saveCallback, IShaderViewer::RevertCallback revertCallback) override { return InvokeRetFunction(&ICaptureContext::EditShader, id, stage, entryPoint, - files, shaderEncoding, flags, saveCallback, + files, knownTool, shaderEncoding, flags, saveCallback, revertCallback); } diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index ab3dcdf48..c26a6fc60 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -191,8 +191,8 @@ ShaderViewer::ShaderViewer(ICaptureContext &ctx, QWidget *parent) } void ShaderViewer::editShader(ResourceId id, ShaderStage stage, const QString &entryPoint, - const rdcstrpairs &files, ShaderEncoding shaderEncoding, - ShaderCompileFlags flags) + const rdcstrpairs &files, KnownShaderTool knownTool, + ShaderEncoding shaderEncoding, ShaderCompileFlags flags) { m_Scintillas.removeOne(m_DisassemblyView); ui->docking->removeToolWindow(m_DisassemblyFrame); @@ -236,6 +236,28 @@ void ShaderViewer::editShader(ResourceId id, ShaderStage stage, const QString &e MarkModification(); }); + // if we know the shader was originally compiled with a specific tool, pick the first matching + // tool we have configured. + if(knownTool != KnownShaderTool::Unknown) + { + for(const ShaderProcessingTool &tool : m_Ctx.Config().ShaderProcessors) + { + // skip tools that can't accept our inputs, or doesn't produce a supported output + if(tool.tool == knownTool) + { + for(int i = 0; i < ui->compileTool->count(); i++) + { + if(ui->compileTool->itemText(i) == tool.name) + { + ui->compileTool->setCurrentIndex(i); + break; + } + } + break; + } + } + } + // if it's a custom shader, hide the group entirely (don't allow customisation of compile // parameters). We can still use it to store the parameters passed in. When visible we collapse it // by default. @@ -1248,8 +1270,9 @@ ShaderViewer *ShaderViewer::LoadEditor(ICaptureContext &ctx, QVariantMap data, encoding = ShaderEncoding::HLSL; } - ShaderViewer *view = EditShader(ctx, id, stage, entryPoint, files, encoding, flags, saveCallback, - revertCallback, modifyCallback, parent); + ShaderViewer *view = + EditShader(ctx, id, stage, entryPoint, files, KnownShaderTool::Unknown, encoding, flags, + saveCallback, revertCallback, modifyCallback, parent); int toolIndex = -1; @@ -5775,7 +5798,8 @@ void ShaderViewer::PopulateCompileToolParameters() ShaderCompileFlag &flag = m_Flags.flags[i]; if(flag.name == "@cmdline") { - // append command line from saved flags + // append command line from saved flags, so any specified options override the defaults if + // they're specified twice ui->toolCommandLine->setPlainText(ui->toolCommandLine->toPlainText() + lit(" %1").arg(flag.value)); break; diff --git a/qrenderdoc/Windows/ShaderViewer.h b/qrenderdoc/Windows/ShaderViewer.h index 7869fa9a2..8461fa511 100644 --- a/qrenderdoc/Windows/ShaderViewer.h +++ b/qrenderdoc/Windows/ShaderViewer.h @@ -116,8 +116,8 @@ public: static ShaderViewer *EditShader(ICaptureContext &ctx, ResourceId id, ShaderStage stage, const QString &entryPoint, const rdcstrpairs &files, - ShaderEncoding shaderEncoding, ShaderCompileFlags flags, - IShaderViewer::SaveCallback saveCallback, + KnownShaderTool knownTool, ShaderEncoding shaderEncoding, + ShaderCompileFlags flags, IShaderViewer::SaveCallback saveCallback, IShaderViewer::RevertCallback revertCallback, ModifyCallback modifyCallback, QWidget *parent) { @@ -125,7 +125,7 @@ public: ret->m_SaveCallback = saveCallback; ret->m_RevertCallback = revertCallback; ret->m_ModifyCallback = modifyCallback; - ret->editShader(id, stage, entryPoint, files, shaderEncoding, flags); + ret->editShader(id, stage, entryPoint, files, knownTool, shaderEncoding, flags); return ret; } @@ -208,7 +208,8 @@ private slots: private: explicit ShaderViewer(ICaptureContext &ctx, QWidget *parent = 0); void editShader(ResourceId id, ShaderStage stage, const QString &entryPoint, - const rdcstrpairs &files, ShaderEncoding shaderEncoding, ShaderCompileFlags flags); + const rdcstrpairs &files, KnownShaderTool knownTool, + ShaderEncoding shaderEncoding, ShaderCompileFlags flags); void debugShader(const ShaderBindpointMapping *bind, const ShaderReflection *shader, ResourceId pipeline, ShaderDebugTrace *trace, const QString &debugContext); diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index be63611da..32edb5554 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -4574,7 +4574,7 @@ void TextureViewer::on_customEdit_clicked() QPointer thisPointer(this); IShaderViewer *s = m_Ctx.EditShader( - ResourceId(), ShaderStage::Fragment, lit("main"), files, + ResourceId(), ShaderStage::Fragment, lit("main"), files, KnownShaderTool::Unknown, encodingExtensions[QFileInfo(filename).completeSuffix()], ShaderCompileFlags(), // Save Callback [thisPointer, key, filename, path](ICaptureContext *ctx, IShaderViewer *viewer, ResourceId, diff --git a/renderdoc/api/replay/renderdoc_tostr.inl b/renderdoc/api/replay/renderdoc_tostr.inl index cbcfd9f6c..cf38683ca 100644 --- a/renderdoc/api/replay/renderdoc_tostr.inl +++ b/renderdoc/api/replay/renderdoc_tostr.inl @@ -1034,6 +1034,24 @@ rdcstr DoStringise(const ShaderEncoding &el) END_ENUM_STRINGISE(); } +template <> +rdcstr DoStringise(const KnownShaderTool &el) +{ + BEGIN_ENUM_STRINGISE(KnownShaderTool); + { + STRINGISE_ENUM_CLASS_NAMED(Unknown, "Custom Tool"); + STRINGISE_ENUM_CLASS_NAMED(SPIRV_Cross, "SPIRV-Cross"); + STRINGISE_ENUM_CLASS_NAMED(spirv_dis, "spirv-dis"); + STRINGISE_ENUM_CLASS_NAMED(glslangValidatorGLSL, "glslang (GLSL)"); + STRINGISE_ENUM_CLASS_NAMED(glslangValidatorHLSL, "glslang (HLSL)"); + STRINGISE_ENUM_CLASS_NAMED(spirv_as, "spirv-as"); + STRINGISE_ENUM_CLASS_NAMED(dxcSPIRV, "dxc (SPIR-V)"); + STRINGISE_ENUM_CLASS_NAMED(dxcDXIL, "dxc (DXIL)"); + STRINGISE_ENUM_CLASS_NAMED(fxc, "fxc"); + } + END_ENUM_STRINGISE(); +} + template <> rdcstr DoStringise(const SectionType &el) { diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index 879cbb40f..62f7725f5 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -1830,6 +1830,140 @@ enum class ShaderEncoding : uint32_t ITERABLE_OPERATORS(ShaderEncoding); DECLARE_REFLECTION_ENUM(ShaderEncoding); +DOCUMENT(R"(Identifies a particular known tool used for shader processing. + +.. data:: Unknown + + Corresponds to no known tool. + +.. data:: SPIRV_Cross + + `SPIRV-Cross `_. + +.. data:: spirv_dis + + `spirv-dis from SPIRV-Tools `_. + +.. data:: glslangValidatorGLSL + + `glslang compiler (GLSL) `_. + +.. data:: glslangValidatorHLSL + + `glslang compiler (HLSL) `_. + +.. data:: spirv_as + + `spirv-as from SPIRV-Tools `_. + +.. data:: dxc_spirv + + `DirectX Shader Compiler `_ with SPIR-V output. + +.. data:: dxcDXIL + + `DirectX Shader Compiler `_ with DXIL output. + +.. data:: fxc + + fxc Shader Compiler with DXBC output. + +)"); +enum class KnownShaderTool : uint32_t +{ + Unknown, + First = Unknown, + SPIRV_Cross, + spirv_dis, + glslangValidatorGLSL, + glslangValidatorHLSL, + spirv_as, + dxcSPIRV, + dxcDXIL, + fxc, + Count, +}; + +ITERABLE_OPERATORS(KnownShaderTool); +DECLARE_REFLECTION_ENUM(KnownShaderTool); + +DOCUMENT(R"(Returns the default executable name with no suffix for a given :class:`KnownShaderTool`. + +.. note:: + The executable name is returned with no suffix, e.g. ``foobar`` which may need a platform specific + suffix like ``.exe`` appended. + +:param KnownShaderTool tool: The tool to get the executable name for. +:return: The default executable name for this tool, or an empty string if the tool is unrecognised. +:rtype: str +)"); +constexpr inline const char *const ToolExecutable(KnownShaderTool tool) +{ + // temporarily disable clang-format to make this more readable. + // Ideally we'd use a simple switch() but VS2015 doesn't support that :(. + // clang-format off + return tool == KnownShaderTool::SPIRV_Cross ? "spirv-cross" : + tool == KnownShaderTool::spirv_dis ? "spirv-dis" : + tool == KnownShaderTool::glslangValidatorGLSL ? "glslangValidator" : + tool == KnownShaderTool::glslangValidatorHLSL ? "glslangValidator" : + tool == KnownShaderTool::spirv_as ? "spirv-as" : + tool == KnownShaderTool::dxcSPIRV ? "dxc" : + tool == KnownShaderTool::dxcDXIL ? "dxc" : + tool == KnownShaderTool::fxc ? "fxc" : + ""; + // clang-format on +} + +DOCUMENT(R"(Returns the expected default input :class:`~renderdoc.ShaderEncoding` that a +:class:`KnownShaderTool` expects. This may not be accurate and may be configurable depending on the +tool. + +:param KnownShaderTool tool: The tool to get the input encoding for. +:return: The encoding that this tool expects as an input by default. +:rtype: renderdoc.ShaderEncoding +)"); +constexpr inline ShaderEncoding ToolInput(KnownShaderTool tool) +{ + // temporarily disable clang-format to make this more readable. + // Ideally we'd use a simple switch() but VS2015 doesn't support that :(. + // clang-format off + return tool == KnownShaderTool::SPIRV_Cross ? ShaderEncoding::SPIRV : + tool == KnownShaderTool::spirv_dis ? ShaderEncoding::SPIRV : + tool == KnownShaderTool::glslangValidatorGLSL ? ShaderEncoding::GLSL : + tool == KnownShaderTool::glslangValidatorHLSL ? ShaderEncoding::HLSL : + tool == KnownShaderTool::spirv_as ? ShaderEncoding::SPIRVAsm : + tool == KnownShaderTool::dxcSPIRV ? ShaderEncoding::HLSL : + tool == KnownShaderTool::dxcDXIL ? ShaderEncoding::HLSL : + tool == KnownShaderTool::fxc ? ShaderEncoding::HLSL : + ShaderEncoding::Unknown; + // clang-format on +} + +DOCUMENT(R"(Returns the expected default output :class:`~renderdoc.ShaderEncoding` that a +:class:`KnownShaderTool` produces. This may not be accurate and may be configurable depending on the +tool. + +:param KnownShaderTool tool: The tool to get the output encoding for. +:return: The encoding that this tool produces as an output by default. +:rtype: renderdoc.ShaderEncoding +)"); +constexpr inline ShaderEncoding ToolOutput(KnownShaderTool tool) +{ + // temporarily disable clang-format to make this more readable. + // Ideally we'd use a simple switch() but VS2015 doesn't support that :(. + // clang-format off + return tool == KnownShaderTool::SPIRV_Cross ? ShaderEncoding::GLSL : + tool == KnownShaderTool::spirv_dis ? ShaderEncoding::SPIRVAsm : + tool == KnownShaderTool::glslangValidatorGLSL ? ShaderEncoding::SPIRV : + tool == KnownShaderTool::glslangValidatorHLSL ? ShaderEncoding::SPIRV : + tool == KnownShaderTool::spirv_as ? ShaderEncoding::SPIRV : + tool == KnownShaderTool::dxcSPIRV ? ShaderEncoding::SPIRV : + tool == KnownShaderTool::dxcDXIL ? ShaderEncoding::DXIL : + tool == KnownShaderTool::fxc ? ShaderEncoding::DXBC : + ShaderEncoding::Unknown; + // clang-format on +} + DOCUMENT(R"(Check whether or not this is a human readable text representation. :param ShaderEncoding encoding: The encoding to check. diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 53e99b04e..0265e80db 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -1453,9 +1453,18 @@ in :data:`entryLocation`, and if no file is specified there then use the first f )"); int32_t editBaseFile = -1; - DOCUMENT("The :class:`ShaderEncoding` of the source. See :data:`files`."); + DOCUMENT(R"(The :class:`ShaderEncoding` of the source. See :data:`files`. + +:type: ShaderEncoding +)"); ShaderEncoding encoding = ShaderEncoding::Unknown; + DOCUMENT(R"(The :class:`KnownShaderTool` of the compiling tool. + +:type: KnownShaderTool +)"); + KnownShaderTool compiler = KnownShaderTool::Unknown; + DOCUMENT(R"(Indicates whether this particular shader can be debugged. In some cases even if the API can debug shaders in general, specific shaders cannot be debugged because they use unsupported functionality diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index 29755c549..dfd871f32 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -1233,6 +1233,7 @@ void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &ref refl.stage = MakeShaderStage(shadType); refl.entryPoint = "main"; refl.encoding = ShaderEncoding::GLSL; + refl.debugInfo.compiler = KnownShaderTool::Unknown; refl.debugInfo.encoding = ShaderEncoding::GLSL; if(shadType == eGL_COMPUTE_SHADER) diff --git a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp index 7e519c0c4..4ca4f8d8b 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp @@ -344,8 +344,12 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl, } refl->encoding = ShaderEncoding::DXBC; + refl->debugInfo.compiler = KnownShaderTool::fxc; if(dxbc->GetDXILByteCode()) + { refl->encoding = ShaderEncoding::DXIL; + refl->debugInfo.compiler = KnownShaderTool::dxcDXIL; + } refl->rawBytes = dxbc->GetShaderBlob(); refl->dispatchThreadsDimension[0] = dxbc->GetReflection()->DispatchThreadsDimension[0]; diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index 1b78b2f42..def2aff7b 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -1578,6 +1578,31 @@ rdcstr Reflector::Disassemble(const rdcstr &entryPoint, ret += ToStr(rdcspv::SourceLanguage(lang)); ret += ")"; } + else if(dbg.inst == ShaderDbg::EntryPoint) + { + ret += indent; + ret += "DebugEntryPoint("; + OpShaderDbg debugFunc(GetID(dbg.arg(0))); + ret += idName(debugFunc.arg(0)); + ret += ", "; + rdcstr gen = ToStr(m_Generator); + int i = gen.indexOf('-'); + if(i > 0) + gen.erase(i - 1, ~0u); + ret += gen; + ret += " "; + ret += idName(dbg.arg(2)); + rdcstr args = idName(dbg.arg(3)); + if(!args.empty()) + { + ret += ",\n"; + lineNum++; + ret += indent + " command line: "; + ret += args; + } + + ret += ")"; + } else if(dbg.inst == ShaderDbg::Value && Vulkan_Debug_ShowDebugValues()) { OpShaderDbg localVar(GetID(dbg.arg(0))); diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp index 59853c293..32cc84615 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp @@ -585,7 +585,7 @@ void Reflector::RegisterOp(Iter it) } else if(dbg.inst == ShaderDbg::FunctionDefinition) { - funcToLocation[dbg.arg(1)] = debugFuncToLocation[dbg.arg(0)]; + funcToDebugFunc[dbg.arg(1)] = dbg.arg(0); } else if(dbg.inst == ShaderDbg::CompilationUnit) { @@ -596,8 +596,8 @@ void Reflector::RegisterOp(Iter it) } else if(dbg.inst == ShaderDbg::EntryPoint) { - funcToBaseFile[dbg.arg(0)] = compUnitToFileIndex[dbg.arg(1)]; - funcToCmdLine[dbg.arg(0)] = strings[dbg.arg(3)]; + debugFuncToBaseFile[dbg.arg(0)] = compUnitToFileIndex[dbg.arg(1)]; + debugFuncToCmdLine[dbg.arg(0)] = strings[dbg.arg(3)]; } else if(dbg.inst == ShaderDbg::GlobalVariable) { @@ -852,25 +852,32 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st reflection.debugInfo.files.push_back({sources[i].name, sources[i].contents}); } + switch(m_Generator) { - auto it = funcToLocation.find(entry->id); - if(it != funcToLocation.end()) - reflection.debugInfo.entryLocation = it->second; - } - - { - auto it = funcToBaseFile.find(entry->id); - if(it != funcToBaseFile.end()) - reflection.debugInfo.editBaseFile = (int32_t)it->second; + case Generator::GlslangReferenceFrontEnd: + case Generator::ShadercoverGlslang: + reflection.debugInfo.compiler = reflection.debugInfo.encoding == ShaderEncoding::HLSL + ? KnownShaderTool::glslangValidatorHLSL + : KnownShaderTool::glslangValidatorGLSL; + break; + case Generator::SPIRVToolsAssembler: + reflection.debugInfo.compiler = KnownShaderTool::spirv_as; + break; + case Generator::spiregg: reflection.debugInfo.compiler = KnownShaderTool::dxcSPIRV; break; + default: reflection.debugInfo.compiler = KnownShaderTool::Unknown; break; } if(!cmdline.empty()) reflection.debugInfo.compileFlags.flags = {{"@cmdline", cmdline}}; { - auto it = funcToCmdLine.find(entry->id); - if(it != funcToCmdLine.end()) - reflection.debugInfo.compileFlags.flags = {{"@cmdline", it->second}}; + auto it = funcToDebugFunc.find(entry->id); + if(it != funcToDebugFunc.end()) + { + reflection.debugInfo.entryLocation = debugFuncToLocation[it->second]; + reflection.debugInfo.compileFlags.flags = {{"@cmdline", debugFuncToCmdLine[it->second]}}; + reflection.debugInfo.editBaseFile = (int32_t)debugFuncToBaseFile[it->second]; + } } PreprocessLineDirectives(reflection.debugInfo.files); diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.h b/renderdoc/driver/shaders/spirv/spirv_reflect.h index 9664277d8..43534557e 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.h +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.h @@ -130,10 +130,10 @@ private: rdcarray sources; SparseIdMap debugSources; SparseIdMap compUnitToFileIndex; - SparseIdMap funcToBaseFile; - SparseIdMap funcToCmdLine; + SparseIdMap debugFuncToBaseFile; + SparseIdMap debugFuncToCmdLine; SparseIdMap debugFuncToLocation; - SparseIdMap funcToLocation; + SparseIdMap funcToDebugFunc; Id curBlock; std::set loopBlocks; diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 90e51fa74..3512472df 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -268,6 +268,7 @@ void DoSerialise(SerialiserType &ser, ShaderDebugInfo &el) SERIALISE_MEMBER(entryLocation); SERIALISE_MEMBER(editBaseFile); SERIALISE_MEMBER(encoding); + SERIALISE_MEMBER(compiler); SERIALISE_MEMBER(debuggable); SERIALISE_MEMBER(debugStatus);