From f8b458176a237de44facd86c3a5f3d50e7ebf449 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 6 Jul 2017 16:34:48 +0100 Subject: [PATCH] Add stub HLSL generation for editing D3D shaders that have no source --- qrenderdoc/Code/QRDUtils.cpp | 34 +++- .../D3D11PipelineStateViewer.cpp | 5 +- .../D3D12PipelineStateViewer.cpp | 5 +- .../PipelineState/GLPipelineStateViewer.cpp | 1 + .../PipelineState/PipelineStateViewer.cpp | 148 ++++++++++++++++++ .../PipelineState/PipelineStateViewer.h | 4 + renderdoc/api/replay/replay_enums.h | 4 + 7 files changed, 192 insertions(+), 9 deletions(-) diff --git a/qrenderdoc/Code/QRDUtils.cpp b/qrenderdoc/Code/QRDUtils.cpp index 3f6d5d42a..ff17686c7 100644 --- a/qrenderdoc/Code/QRDUtils.cpp +++ b/qrenderdoc/Code/QRDUtils.cpp @@ -215,7 +215,39 @@ QString D3DSemanticString(const SigParameter &sig) if(sig.systemValue == ShaderBuiltin::Undefined) return ToQStr(sig.semanticIdxName); - QString ret = ToQStr(sig.systemValue); + QString sysValues[ENUM_ARRAY_SIZE(ShaderBuiltin)] = { + lit("SV_Undefined"), + lit("SV_Position"), + lit("Unsupported (PointSize)"), + lit("SV_ClipDistance"), + lit("SV_CullDistance"), + lit("SV_RenderTargetIndex"), + lit("SV_ViewportIndex"), + lit("SV_VertexID"), + lit("SV_PrimitiveID"), + lit("SV_InstanceID"), + lit("Unsupported (DispatchSize)"), + lit("SV_DispatchThreadID"), + lit("SV_GroupID"), + lit("SV_GroupIndex"), + lit("SV_GroupThreadID"), + lit("SV_GSInstanceID"), + lit("SV_OutputControlPointID"), + lit("SV_DomainLocation"), + lit("SV_IsFrontFace"), + lit("SV_Coverage"), + lit("Unsupported (SamplePosition)"), + lit("SV_SampleIndex"), + lit("Unsupported (PatchNumVertices)"), + lit("SV_TessFactor"), + lit("SV_InsideTessFactor"), + lit("SV_Target"), + lit("SV_Depth"), + lit("SV_DepthGreaterEqual"), + lit("SV_DepthLessEqual"), + }; + + QString ret = sysValues[size_t(sig.systemValue)]; // need to include the index if it's a system value semantic that's numbered if(sig.systemValue == ShaderBuiltin::ColorOutput || diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index 39da27e66..9f913c876 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -2259,11 +2259,8 @@ void D3D11PipelineStateViewer::shaderEdit_clicked() if(!hasOrigSource) { - QString hlsl = lit("// TODO - generate stub HLSL"); - mainfile = lit("generated.hlsl"); - - files[mainfile] = hlsl; + files[mainfile] = m_Common.GenerateHLSLStub(shaderDetails, entryFunc); } if(files.empty()) diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index e21f479d0..54e55503b 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -2144,11 +2144,8 @@ void D3D12PipelineStateViewer::shaderEdit_clicked() if(!hasOrigSource) { - QString hlsl = lit("// TODO - generate stub HLSL"); - mainfile = lit("generated.hlsl"); - - files[mainfile] = hlsl; + files[mainfile] = m_Common.GenerateHLSLStub(shaderDetails, entryFunc); } if(files.empty()) diff --git a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp index 5dde0a9aa..752080b41 100644 --- a/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/GLPipelineStateViewer.cpp @@ -2277,6 +2277,7 @@ void GLPipelineStateViewer::shaderEdit_clicked() if(!hasOrigSource) { + // this would only happen if the GL program is uploading SPIR-V instead of GLSL. QString glsl = lit("// TODO - disassemble SPIR-V"); mainfile = lit("generated.glsl"); diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp index 82f2824bb..fd87ac705 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.cpp @@ -558,6 +558,154 @@ bool PipelineStateViewer::PrepareShaderEditing(const ShaderReflection *shaderDet return false; } +void PipelineStateViewer::MakeShaderVariablesHLSL(bool cbufferContents, + const rdctype::array &vars, + QString &struct_contents, QString &struct_defs) +{ + for(const ShaderConstant &v : vars) + { + if(v.type.members.count > 0) + { + QString def = lit("struct %1 {\n").arg(ToQStr(v.type.descriptor.name)); + + if(!struct_defs.contains(def)) + { + QString contents; + MakeShaderVariablesHLSL(false, v.type.members, contents, struct_defs); + + struct_defs += def + contents + lit("};\n\n"); + } + } + + struct_contents += lit("\t%1 %2").arg(ToQStr(v.type.descriptor.name)).arg(ToQStr(v.name)); + + char comp = 'x'; + if(v.reg.comp == 1) + comp = 'y'; + if(v.reg.comp == 2) + comp = 'z'; + if(v.reg.comp == 3) + comp = 'w'; + + if(cbufferContents) + struct_contents += lit(" : packoffset(c%1.%2);").arg(v.reg.vec).arg(QLatin1Char(comp)); + else + struct_contents += lit(";"); + + struct_contents += lit("\n"); + } +} + +QString PipelineStateViewer::GenerateHLSLStub(const ShaderReflection *shaderDetails, + const QString &entryFunc) +{ + QString hlsl = lit("// No HLSL available - function stub generated\n\n"); + + const QString textureDim[ENUM_ARRAY_SIZE(TextureDim)] = { + lit("Unknown"), lit("Buffer"), lit("Texture1D"), lit("Texture1DArray"), + lit("Texture2D"), lit("TextureRect"), lit("Texture2DArray"), lit("Texture2DMS"), + lit("Texture2DMSArray"), lit("Texture3D"), lit("TextureCube"), lit("TextureCubeArray"), + }; + + for(int i = 0; i < 2; i++) + { + const rdctype::array &resources = + (i == 0 ? shaderDetails->ReadOnlyResources : shaderDetails->ReadWriteResources); + for(const ShaderResource &res : resources) + { + if(res.IsSampler) + { + hlsl += lit("//SamplerComparisonState %1 : register(s%2); // can't disambiguate\n" + "SamplerState %1 : register(s%2); // can't disambiguate\n") + .arg(ToQStr(res.name)) + .arg(res.bindPoint); + } + else + { + char regChar = 't'; + + if(i == 1) + { + hlsl += lit("RW"); + regChar = 'u'; + } + + if(res.IsTexture) + { + hlsl += lit("%1<%2> %3 : register(%4%5);\n") + .arg(textureDim[(size_t)res.resType]) + .arg(ToQStr(res.variableType.descriptor.name)) + .arg(ToQStr(res.name)) + .arg(QLatin1Char(regChar)) + .arg(res.bindPoint); + } + else + { + if(res.variableType.descriptor.rows > 1) + hlsl += lit("Structured"); + + hlsl += lit("Buffer<%1> %2 : register(%3%4);\n") + .arg(ToQStr(res.variableType.descriptor.name)) + .arg(ToQStr(res.name)) + .arg(QLatin1Char(regChar)) + .arg(res.bindPoint); + } + } + } + } + + hlsl += lit("\n\n"); + + QString cbuffers; + + int cbufIdx = 0; + for(const ConstantBlock &cbuf : shaderDetails->ConstantBlocks) + { + if(cbuf.name.count > 0 && cbuf.variables.count > 0) + { + QString cbufName = ToQStr(cbuf.name); + if(cbufName == lit("$Globals")) + cbufName = lit("_Globals"); + cbuffers += lit("cbuffer %1 : register(b%2) {\n").arg(cbufName).arg(cbuf.bindPoint); + MakeShaderVariablesHLSL(true, cbuf.variables, cbuffers, hlsl); + cbuffers += lit("};\n\n"); + } + cbufIdx++; + } + + hlsl += cbuffers; + + hlsl += lit("\n\n"); + + hlsl += lit("struct InputStruct {\n"); + for(const SigParameter &sig : shaderDetails->InputSig) + hlsl += lit("\t%1 %2 : %3;\n") + .arg(TypeString(sig)) + .arg(sig.varName.count > 0 ? ToQStr(sig.varName) : lit("param%1").arg(sig.regIndex)) + .arg(D3DSemanticString(sig)); + hlsl += lit("};\n\n"); + + hlsl += lit("struct OutputStruct {\n"); + for(const SigParameter &sig : shaderDetails->OutputSig) + hlsl += lit("\t%1 %2 : %3;\n") + .arg(TypeString(sig)) + .arg(sig.varName.count > 0 ? ToQStr(sig.varName) : lit("param%1").arg(sig.regIndex)) + .arg(D3DSemanticString(sig)); + hlsl += lit("};\n\n"); + + hlsl += lit("OutputStruct %1(in InputStruct IN)\n" + "{\n" + "\tOutputStruct OUT = (OutputStruct)0;\n" + "\n" + "\t// ...\n" + "\n" + "\treturn OUT;\n" + "}\n") + .arg(entryFunc); + + return hlsl; +} + void PipelineStateViewer::EditShader(ShaderStage shaderType, ResourceId id, const ShaderReflection *shaderDetails, const QString &entryFunc, const QStringMap &files, const QString &mainfile) diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h index 48d752246..416cb46cb 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h @@ -67,6 +67,7 @@ public: bool PrepareShaderEditing(const ShaderReflection *shaderDetails, QString &entryFunc, QStringMap &files, QString &mainfile); + QString GenerateHLSLStub(const ShaderReflection *shaderDetails, const QString &entryFunc); void EditShader(ShaderStage shaderType, ResourceId id, const ShaderReflection *shaderDetails, const QString &entryFunc, const QStringMap &files, const QString &mainfile); @@ -83,6 +84,9 @@ private: Ui::PipelineStateViewer *ui; ICaptureContext &m_Ctx; + void MakeShaderVariablesHLSL(bool cbufferContents, const rdctype::array &vars, + QString &struct_contents, QString &struct_defs); + QPixmap m_TopoPixmaps[(int)Topology::PatchList + 1]; void setToD3D11(); diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index a81db4576..f7c7d4da4 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -693,6 +693,7 @@ to apply to multiple related things - see :data:`ClipDistance`, :data:`CullDista enum class ShaderBuiltin : uint32_t { Undefined = 0, + First = Undefined, Position, PointSize, ClipDistance, @@ -721,8 +722,11 @@ enum class ShaderBuiltin : uint32_t DepthOutput, DepthOutputGreaterEqual, DepthOutputLessEqual, + Count, }; +ITERABLE_OPERATORS(ShaderBuiltin); + // replay_render.h DOCUMENT(R"(The type of :class:`ReplayOutput` to create