diff --git a/docs/window/settings_window.rst b/docs/window/settings_window.rst index ca4a163a4..ca7a4f8ea 100644 --- a/docs/window/settings_window.rst +++ b/docs/window/settings_window.rst @@ -241,6 +241,8 @@ Other custom tools can be configured, but for those the command line arguments m * ``{entry_point}`` will be replaced by the entry point name, only when compiling a shader. * ``{glsl_stage4}`` will be replaced by the glsl stage short-hand, one of: vert, tesc, tese, geom, frag, or comp. * ``{hlsl_stage2}`` will be replaced by the hlsl stage short-hand, one of: vs, hs, ds, gs, ps, or cs. +* ``{spirv_ver}`` will be replaced by the SPIR-V version in use, e.g. spirv1.2 or spirv1.6. +* ``{vulkan_ver}`` will be replaced by the Vulkan-identified SPIR-V version in use, e.g. vulkan1.0 or vulkan1.3. This value may be lossy, and will pick the next *lowest* version that compiles with a given SPIR-V version. E.g. SPIR-V 1.2 was not used by a vulkan version, so will be rounded down to vulkan1.0. You must also select the input and output format of the tool, such as HLSL input and SPIR-V output. This will be used to match the tool against a given need at runtime with different types of shaders. diff --git a/qrenderdoc/Code/Interface/PersistantConfig.cpp b/qrenderdoc/Code/Interface/PersistantConfig.cpp index ce40122ae..093bd4895 100644 --- a/qrenderdoc/Code/Interface/PersistantConfig.cpp +++ b/qrenderdoc/Code/Interface/PersistantConfig.cpp @@ -699,15 +699,15 @@ rdcstr ShaderProcessingTool::DefaultArguments() const else if(tool == KnownShaderTool::spirv_dis || tool == KnownShaderTool::spirv_dis_OpenGL) return "--no-color"; else if(tool == KnownShaderTool::glslangValidatorGLSL) - return "-g -V -S {glsl_stage4}"; + return "-g -V -S {glsl_stage4} --target-env {spirv_ver}"; else if(tool == KnownShaderTool::glslangValidatorGLSL_OpenGL) - return "-g -G -S {glsl_stage4}"; + return "-g -G -S {glsl_stage4} --target-env {spirv_ver}"; else if(tool == KnownShaderTool::glslangValidatorHLSL) - return "-D -g -V -S {glsl_stage4} -e {entry_point}"; + return "-D -g -V -S {glsl_stage4} -e {entry_point} --target-env {spirv_ver}"; else if(tool == KnownShaderTool::spirv_as || tool == KnownShaderTool::spirv_as_OpenGL) return ""; else if(tool == KnownShaderTool::dxcSPIRV) - return "-T {hlsl_stage2}_6_0 -E {entry_point} -spirv"; + return "-T {hlsl_stage2}_6_0 -E {entry_point} -spirv -fspv-target-env={vulkan_ver}"; else if(tool == KnownShaderTool::dxcDXIL) return "-T {hlsl_stage2}_6_0 -E {entry_point}"; else if(tool == KnownShaderTool::fxc) diff --git a/qrenderdoc/Code/Interface/PersistantConfig.h b/qrenderdoc/Code/Interface/PersistantConfig.h index 5daf48218..12d77b5ad 100644 --- a/qrenderdoc/Code/Interface/PersistantConfig.h +++ b/qrenderdoc/Code/Interface/PersistantConfig.h @@ -113,6 +113,8 @@ struct ShaderProcessingTool :param str source: The source code, preprocessed into a single file. :param str entryPoint: The name of the entry point in the shader to compile. :param renderdoc.ShaderStage stage: The pipeline stage that this shader represents. +:param str spirvVer: The version of SPIR-V in use for this shader, or an empty string for defaults. + The current version can be obtained from reflection data via the ``@spirver`` compile flag. :param str args: arguments to pass to the tool. The default arguments can be obtained using :meth:`DefaultArguments` which can then be customised as desired. Passing an empty string uses the default arguments. @@ -120,7 +122,7 @@ struct ShaderProcessingTool :rtype: ShaderToolOutput )"); ShaderToolOutput CompileShader(QWidget *window, rdcstr source, rdcstr entryPoint, - ShaderStage stage, rdcstr args) const; + ShaderStage stage, rdcstr spirvVer, rdcstr args) const; private: DOCUMENT("Internal function"); diff --git a/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp b/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp index cc9a739f7..bec700ffd 100644 --- a/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp +++ b/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp @@ -41,6 +41,22 @@ static QString tmpPath(const QString &filename) return QDir(QDir::tempPath()).absoluteFilePath(filename); } +QString vulkanVerForSpirVer(QString spirvVer) +{ + if(spirvVer == lit("spirv1.0") || spirvVer == lit("spirv1.1") || spirvVer == lit("spirv1.2")) + return lit("vulkan1.0"); + if(spirvVer == lit("spirv1.3")) + return lit("vulkan1.1"); + if(spirvVer == lit("spirv1.4")) + return lit("vulkan1.1spirv1.4"); + if(spirvVer == lit("spirv1.5")) + return lit("vulkan1.2"); + if(spirvVer == lit("spirv1.6")) + return lit("vulkan1.3"); + else + return lit("vulkan1.3"); +} + static ShaderToolOutput RunTool(const ShaderProcessingTool &tool, QWidget *window, QString input_file, QString output_file, QStringList &argList) { @@ -243,6 +259,11 @@ ShaderToolOutput ShaderProcessingTool::DisassembleShader(QWidget *window, input_file = tmpPath(lit("shader_input")); + QString spirvVer = lit("spirv1.0"); + for(const ShaderCompileFlag &flag : shaderDetails->debugInfo.compileFlags.flags) + if(flag.name == "@spirver") + spirvVer = flag.value; + // replace arguments after expansion to avoid problems with quoting paths etc for(QString &arg : argList) { @@ -262,6 +283,10 @@ ShaderToolOutput ShaderProcessingTool::DisassembleShader(QWidget *window, arg.replace(0, 13, glsl_stage4[int(shaderDetails->stage)]); if(arg.left(13) == lit("{hlsl_stage2}")) arg.replace(0, 13, hlsl_stage2[int(shaderDetails->stage)]); + if(arg.left(11) == lit("{spirv_ver}")) + arg.replace(0, 11, spirvVer); + if(arg.left(12) == lit("{vulkan_ver}")) + arg.replace(0, 12, vulkanVerForSpirVer(spirvVer)); } QFile binHandle(input_file); @@ -287,7 +312,7 @@ ShaderToolOutput ShaderProcessingTool::DisassembleShader(QWidget *window, ShaderToolOutput ShaderProcessingTool::CompileShader(QWidget *window, rdcstr source, rdcstr entryPoint, ShaderStage stage, - rdcstr arguments) const + rdcstr spirvVer, 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 @@ -298,6 +323,9 @@ ShaderToolOutput ShaderProcessingTool::CompileShader(QWidget *window, rdcstr sou input_file = tmpPath(lit("shader_input")); + if(spirvVer.isEmpty()) + spirvVer = "spirv1.0"; + // replace arguments after expansion to avoid problems with quoting paths etc for(QString &arg : argList) { @@ -313,6 +341,10 @@ ShaderToolOutput ShaderProcessingTool::CompileShader(QWidget *window, rdcstr sou arg.replace(0, 13, glsl_stage4[int(stage)]); if(arg.left(13) == lit("{hlsl_stage2}")) arg.replace(0, 13, hlsl_stage2[int(stage)]); + if(arg.left(11) == lit("{spirv_ver}")) + arg.replace(0, 11, spirvVer); + if(arg.left(12) == lit("{vulkan_ver}")) + arg.replace(0, 12, vulkanVerForSpirVer(spirvVer)); } QFile binHandle(input_file); diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp index 5ffe26c21..802a38923 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp @@ -88,7 +88,7 @@ ShaderToolOutput ShaderProcessingTool::DisassembleShader(QWidget *window, ShaderToolOutput ShaderProcessingTool::CompileShader(QWidget *window, rdcstr source, rdcstr entryPoint, ShaderStage stage, - rdcstr arguments) const + rdcstr spirvVer, rdcstr arguments) const { return {}; } diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp index 8d65055f5..f561303e6 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp @@ -1043,7 +1043,13 @@ IShaderViewer *PipelineStateViewer::EditDecompiledSource(const ShaderProcessingT rdcstrpairs files; files.push_back(rdcpair("decompiled", source)); - IShaderViewer *sv = EditShader(id, shaderDetails->stage, shaderDetails->entryPoint, {}, + ShaderCompileFlags flags; + + for(const ShaderCompileFlag &flag : shaderDetails->debugInfo.compileFlags.flags) + if(flag.name == "@spirver") + flags.flags.push_back(flag); + + IShaderViewer *sv = EditShader(id, shaderDetails->stage, shaderDetails->entryPoint, flags, KnownShaderTool::Unknown, tool.output, files); sv->ShowErrors(out.log); diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index 685bce05f..038ee47fb 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -6029,6 +6029,11 @@ void ShaderViewer::on_refresh_clicked() rdcarray accepted = m_Ctx.TargetShaderEncodings(); + rdcstr spirvVer = "spirv1.0"; + for(const ShaderCompileFlag &flag : m_Flags.flags) + if(flag.name == "@spirver") + spirvVer = flag.value; + if(m_CustomShader || (accepted.indexOf(encoding) >= 0 && ui->compileTool->currentIndex() == ui->compileTool->count() - 1)) { @@ -6041,7 +6046,7 @@ void ShaderViewer::on_refresh_clicked() if(QString(tool.name) == ui->compileTool->currentText()) { ShaderToolOutput out = tool.CompileShader(this, source, ui->entryFunc->text(), m_Stage, - ui->toolCommandLine->toPlainText()); + spirvVer, ui->toolCommandLine->toPlainText()); ShowErrors(out.log); diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 9048f2c97..3721fe478 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -4415,7 +4415,7 @@ void TextureViewer::reloadCustomShaders(const QString &filter) } ShaderToolOutput out = - tool.CompileShader(this, source, "main", ShaderStage::Pixel, ""); + tool.CompileShader(this, source, "main", ShaderStage::Pixel, "", ""); errors = out.log; diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp index fd0c7bcc8..907bcd7ad 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp @@ -936,6 +936,9 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st if(!cmdline.empty()) reflection.debugInfo.compileFlags.flags = {{"@cmdline", cmdline}}; + reflection.debugInfo.compileFlags.flags.push_back( + {"@spirver", StringFormat::Fmt("spirv%d.%d", m_MajorVersion, m_MinorVersion)}); + { auto it = funcToDebugFunc.find(entry->id); if(it != funcToDebugFunc.end())