Allow using shader processing tools for custom shaders

* This is primarily useful for HLSL on Vulkan, but could be used with any other
  combination. If multiple tools can perform the conversion, the highest
  priority one is used.
This commit is contained in:
baldurk
2019-05-22 17:54:10 +01:00
parent 694524c7bd
commit e4333291a1
27 changed files with 607 additions and 421 deletions
+321 -198
View File
@@ -193,6 +193,8 @@ void ShaderViewer::editShader(bool customShader, ShaderStage stage, const QStrin
m_Stage = stage;
m_Flags = flags;
m_CustomShader = customShader;
// set up compilation parameters
for(ShaderEncoding i : values<ShaderEncoding>())
if(IsTextRepresentation(i) || shaderEncoding == i)
@@ -2611,7 +2613,9 @@ void ShaderViewer::AddWatch(const rdcstr &variable)
int ShaderViewer::snippetPos()
{
if(IsD3D(m_Ctx.APIProps().pipelineType))
ShaderEncoding encoding = currentEncoding();
if(encoding != ShaderEncoding::GLSL)
return 0;
if(m_Scintillas.isEmpty())
@@ -2626,283 +2630,402 @@ int ShaderViewer::snippetPos()
return ver.second + 1;
}
void ShaderViewer::insertVulkanUBO()
void ShaderViewer::insertSnippet(const QString &text)
{
if(text.isEmpty())
return;
if(m_Scintillas.isEmpty())
return;
m_Scintillas[0]->insertText(snippetPos(),
"layout(binding = 0, std140) uniform RENDERDOC_Uniforms\n"
"{\n"
" uvec4 TexDim;\n"
" uint SelectedMip;\n"
" int TextureType;\n"
" uint SelectedSliceFace;\n"
" int SelectedSample;\n"
" uvec4 YUVDownsampleRate;\n"
" uvec4 YUVAChannels;\n"
"} RENDERDOC;\n\n");
m_Scintillas[0]->insertText(snippetPos(), text.toUtf8().data());
m_Scintillas[0]->setSelection(0, 0);
}
QString ShaderViewer::vulkanUBO()
{
ShaderEncoding encoding = currentEncoding();
if(encoding == ShaderEncoding::GLSL)
{
return lit(R"(
layout(binding = 0, std140) uniform RENDERDOC_Uniforms
{
uvec4 TexDim;
uint SelectedMip;
int TextureType;
uint SelectedSliceFace;
int SelectedSample;
uvec4 YUVDownsampleRate;
uvec4 YUVAChannels;
} RENDERDOC;
)");
}
else if(encoding == ShaderEncoding::HLSL)
{
return lit(R"(
cbuffer RENDERDOC_Constants : register(b0)
{
uint4 RENDERDOC_TexDim;
uint RENDERDOC_SelectedMip;
int RENDERDOC_TextureType;
uint RENDERDOC_SelectedSliceFace;
int RENDERDOC_SelectedSample;
uint4 RENDERDOC_YUVDownsampleRate;
uint4 RENDERDOC_YUVAChannels;
};
)");
}
else if(encoding == ShaderEncoding::SPIRVAsm)
{
return lit("; Can't insert snippets for SPIR-V ASM");
}
return QString();
}
void ShaderViewer::snippet_textureDimensions()
{
if(m_Scintillas.isEmpty())
return;
ShaderEncoding encoding = currentEncoding();
GraphicsAPI api = m_Ctx.APIProps().localRenderer;
GraphicsAPI api = m_Ctx.APIProps().pipelineType;
QString text;
if(IsD3D(api))
if(api == GraphicsAPI::Vulkan)
{
m_Scintillas[0]->insertText(snippetPos(),
"// xyz == width, height, depth. w == # mips\n"
"uint4 RENDERDOC_TexDim;\n"
"uint4 RENDERDOC_YUVDownsampleRate;\n"
"uint4 RENDERDOC_YUVAChannels; \n\n");
text = vulkanUBO();
}
else if(api == GraphicsAPI::OpenGL)
else if(encoding == ShaderEncoding::HLSL)
{
m_Scintillas[0]->insertText(snippetPos(),
"// xyz == width, height, depth. w == # mips\n"
"uniform uvec4 RENDERDOC_TexDim;\n\n");
text = lit(R"(
// xyz == width, height, depth. w == # mips
uint4 RENDERDOC_TexDim;
uint4 RENDERDOC_YUVDownsampleRate;
uint4 RENDERDOC_YUVAChannels;
)");
}
else if(api == GraphicsAPI::Vulkan)
else if(encoding == ShaderEncoding::GLSL)
{
insertVulkanUBO();
text = lit(R"(
// xyz == width, height, depth. w == # mips
uniform uvec4 RENDERDOC_TexDim;
)");
}
else if(encoding == ShaderEncoding::SPIRVAsm)
{
text = lit("; Can't insert snippets for SPIR-V ASM");
}
m_Scintillas[0]->setSelection(0, 0);
insertSnippet(text);
}
void ShaderViewer::snippet_selectedMip()
{
if(m_Scintillas.isEmpty())
return;
ShaderEncoding encoding = currentEncoding();
GraphicsAPI api = m_Ctx.APIProps().localRenderer;
GraphicsAPI api = m_Ctx.APIProps().pipelineType;
QString text;
if(IsD3D(api))
if(api == GraphicsAPI::Vulkan)
{
m_Scintillas[0]->insertText(snippetPos(),
"// selected mip in UI\n"
"uint RENDERDOC_SelectedMip;\n\n");
text = vulkanUBO();
}
else if(api == GraphicsAPI::OpenGL)
else if(encoding == ShaderEncoding::HLSL)
{
m_Scintillas[0]->insertText(snippetPos(),
"// selected mip in UI\n"
"uniform uint RENDERDOC_SelectedMip;\n\n");
text = lit(R"(
// selected mip in UI
uint RENDERDOC_SelectedMip;
)");
}
else if(api == GraphicsAPI::Vulkan)
else if(encoding == ShaderEncoding::GLSL)
{
insertVulkanUBO();
text = lit(R"(
// selected mip in UI
uniform uint RENDERDOC_SelectedMip;
)");
}
else if(encoding == ShaderEncoding::SPIRVAsm)
{
text = lit("; Can't insert snippets for SPIR-V ASM");
}
m_Scintillas[0]->setSelection(0, 0);
insertSnippet(text);
}
void ShaderViewer::snippet_selectedSlice()
{
if(m_Scintillas.isEmpty())
return;
ShaderEncoding encoding = currentEncoding();
GraphicsAPI api = m_Ctx.APIProps().localRenderer;
GraphicsAPI api = m_Ctx.APIProps().pipelineType;
QString text;
if(IsD3D(api))
if(api == GraphicsAPI::Vulkan)
{
m_Scintillas[0]->insertText(snippetPos(),
"// selected array slice or cubemap face in UI\n"
"uint RENDERDOC_SelectedSliceFace;\n\n");
text = vulkanUBO();
}
else if(api == GraphicsAPI::OpenGL)
else if(encoding == ShaderEncoding::HLSL)
{
m_Scintillas[0]->insertText(snippetPos(),
"// selected array slice or cubemap face in UI\n"
"uniform uint RENDERDOC_SelectedSliceFace;\n\n");
text = lit(R"(
// selected array slice or cubemap face in UI
uint RENDERDOC_SelectedSliceFace;
)");
}
else if(api == GraphicsAPI::Vulkan)
else if(encoding == ShaderEncoding::GLSL)
{
insertVulkanUBO();
text = lit(R"(
// selected array slice or cubemap face in UI
uniform uint RENDERDOC_SelectedSliceFace;
)");
}
else if(encoding == ShaderEncoding::SPIRVAsm)
{
text = lit("; Can't insert snippets for SPIR-V ASM");
}
m_Scintillas[0]->setSelection(0, 0);
insertSnippet(text);
}
void ShaderViewer::snippet_selectedSample()
{
if(m_Scintillas.isEmpty())
return;
ShaderEncoding encoding = currentEncoding();
GraphicsAPI api = m_Ctx.APIProps().localRenderer;
GraphicsAPI api = m_Ctx.APIProps().pipelineType;
QString text;
if(IsD3D(api))
if(api == GraphicsAPI::Vulkan)
{
m_Scintillas[0]->insertText(snippetPos(),
"// selected MSAA sample or -numSamples for resolve. See docs\n"
"int RENDERDOC_SelectedSample;\n\n");
text = vulkanUBO();
}
else if(api == GraphicsAPI::OpenGL)
else if(encoding == ShaderEncoding::HLSL)
{
m_Scintillas[0]->insertText(snippetPos(),
"// selected MSAA sample or -numSamples for resolve. See docs\n"
"uniform int RENDERDOC_SelectedSample;\n\n");
text = lit(R"(
// selected MSAA sample or -numSamples for resolve. See docs
int RENDERDOC_SelectedSample;
)");
}
else if(api == GraphicsAPI::Vulkan)
else if(encoding == ShaderEncoding::GLSL)
{
insertVulkanUBO();
text = lit(R"(
// selected MSAA sample or -numSamples for resolve. See docs
uniform int RENDERDOC_SelectedSample;
)");
}
else if(encoding == ShaderEncoding::SPIRVAsm)
{
text = lit("; Can't insert snippets for SPIR-V ASM");
}
m_Scintillas[0]->setSelection(0, 0);
insertSnippet(text);
}
void ShaderViewer::snippet_selectedType()
{
if(m_Scintillas.isEmpty())
return;
ShaderEncoding encoding = currentEncoding();
GraphicsAPI api = m_Ctx.APIProps().localRenderer;
GraphicsAPI api = m_Ctx.APIProps().pipelineType;
QString text;
if(IsD3D(api))
if(api == GraphicsAPI::Vulkan)
{
m_Scintillas[0]->insertText(snippetPos(),
"// 1 = 1D, 2 = 2D, 3 = 3D, 4 = Depth, 5 = Depth + Stencil\n"
"// 6 = Depth (MS), 7 = Depth + Stencil (MS)\n"
"uint RENDERDOC_TextureType;\n\n");
text = vulkanUBO();
}
else if(api == GraphicsAPI::OpenGL)
else if(encoding == ShaderEncoding::HLSL)
{
m_Scintillas[0]->insertText(snippetPos(),
"// 1 = 1D, 2 = 2D, 3 = 3D, 4 = Cube\n"
"// 5 = 1DArray, 6 = 2DArray, 7 = CubeArray\n"
"// 8 = Rect, 9 = Buffer, 10 = 2DMS\n"
"uniform uint RENDERDOC_TextureType;\n\n");
text = lit(R"(
// 1 = 1D, 2 = 2D, 3 = 3D, 4 = Depth, 5 = Depth + Stencil
// 6 = Depth (MS), 7 = Depth + Stencil (MS)
uint RENDERDOC_TextureType;
)");
}
else if(api == GraphicsAPI::Vulkan)
else if(encoding == ShaderEncoding::GLSL)
{
insertVulkanUBO();
text = lit(R"(
// 1 = 1D, 2 = 2D, 3 = 3D, 4 = Cube
// 5 = 1DArray, 6 = 2DArray, 7 = CubeArray
// 8 = Rect, 9 = Buffer, 10 = 2DMS
uniform uint RENDERDOC_TextureType;
)");
}
else if(encoding == ShaderEncoding::SPIRVAsm)
{
text = lit("; Can't insert snippets for SPIR-V ASM");
}
m_Scintillas[0]->setSelection(0, 0);
insertSnippet(text);
}
void ShaderViewer::snippet_samplers()
{
if(m_Scintillas.isEmpty())
return;
ShaderEncoding encoding = currentEncoding();
GraphicsAPI api = m_Ctx.APIProps().localRenderer;
GraphicsAPI api = m_Ctx.APIProps().pipelineType;
if(IsD3D(api))
if(encoding == ShaderEncoding::HLSL)
{
m_Scintillas[0]->insertText(snippetPos(),
"// Samplers\n"
"SamplerState pointSampler : register(s0);\n"
"SamplerState linearSampler : register(s1);\n"
"// End Samplers\n\n");
m_Scintillas[0]->setSelection(0, 0);
if(api == GraphicsAPI::Vulkan)
{
insertSnippet(lit(R"(
// Samplers
SamplerState pointSampler : register(s50);
SamplerState linearSampler : register(s51);
// End Samplers
)"));
}
else
{
insertSnippet(lit(R"(
// Samplers
SamplerState pointSampler : register(s0);
SamplerState linearSampler : register(s1);
// End Samplers
)"));
}
}
}
void ShaderViewer::snippet_resources()
{
if(m_Scintillas.isEmpty())
return;
ShaderEncoding encoding = currentEncoding();
GraphicsAPI api = m_Ctx.APIProps().localRenderer;
GraphicsAPI api = m_Ctx.APIProps().pipelineType;
if(encoding == ShaderEncoding::HLSL)
{
if(api == GraphicsAPI::Vulkan)
{
insertSnippet(lit(R"(
// Textures
// Floating point
Texture1DArray<float4> texDisplayTex1DArray : register(t6);
Texture2DArray<float4> texDisplayTex2DArray : register(t7);
Texture3D<float4> texDisplayTex3D : register(t8);
Texture2DMSArray<float4> texDisplayTex2DMSArray : register(t9);
Texture2DArray<float4> texDisplayYUVArray : register(t10);
if(IsD3D(api))
{
m_Scintillas[0]->insertText(
snippetPos(),
"// Textures\n"
"Texture1DArray<float4> texDisplayTex1DArray : register(t1);\n"
"Texture2DArray<float4> texDisplayTex2DArray : register(t2);\n"
"Texture3D<float4> texDisplayTex3D : register(t3);\n"
"Texture2DArray<float2> texDisplayTexDepthArray : register(t4);\n"
"Texture2DArray<uint2> texDisplayTexStencilArray : register(t5);\n"
"Texture2DMSArray<float2> texDisplayTexDepthMSArray : register(t6);\n"
"Texture2DMSArray<uint2> texDisplayTexStencilMSArray : register(t7);\n"
"Texture2DMSArray<float4> texDisplayTex2DMSArray : register(t9);\n"
"Texture2DArray<float4> texDisplayYUVArray : register(t10);\n"
"\n"
"Texture1DArray<uint4> texDisplayUIntTex1DArray : register(t11);\n"
"Texture2DArray<uint4> texDisplayUIntTex2DArray : register(t12);\n"
"Texture3D<uint4> texDisplayUIntTex3D : register(t13);\n"
"Texture2DMSArray<uint4> texDisplayUIntTex2DMSArray : register(t19);\n"
"\n"
"Texture1DArray<int4> texDisplayIntTex1DArray : register(t21);\n"
"Texture2DArray<int4> texDisplayIntTex2DArray : register(t22);\n"
"Texture3D<int4> texDisplayIntTex3D : register(t23);\n"
"Texture2DMSArray<int4> texDisplayIntTex2DMSArray : register(t29);\n"
"// End Textures\n\n\n");
}
else if(api == GraphicsAPI::OpenGL)
{
m_Scintillas[0]->insertText(snippetPos(),
"// Textures\n"
"// Unsigned int samplers\n"
"layout (binding = 1) uniform usampler1D texUInt1D;\n"
"layout (binding = 2) uniform usampler2D texUInt2D;\n"
"layout (binding = 3) uniform usampler3D texUInt3D;\n"
"// cube = 4\n"
"layout (binding = 5) uniform usampler1DArray texUInt1DArray;\n"
"layout (binding = 6) uniform usampler2DArray texUInt2DArray;\n"
"// cube array = 7\n"
"layout (binding = 8) uniform usampler2DRect texUInt2DRect;\n"
"layout (binding = 9) uniform usamplerBuffer texUIntBuffer;\n"
"layout (binding = 10) uniform usampler2DMS texUInt2DMS;\n"
"\n"
"// Int samplers\n"
"layout (binding = 1) uniform isampler1D texSInt1D;\n"
"layout (binding = 2) uniform isampler2D texSInt2D;\n"
"layout (binding = 3) uniform isampler3D texSInt3D;\n"
"// cube = 4\n"
"layout (binding = 5) uniform isampler1DArray texSInt1DArray;\n"
"layout (binding = 6) uniform isampler2DArray texSInt2DArray;\n"
"// cube array = 7\n"
"layout (binding = 8) uniform isampler2DRect texSInt2DRect;\n"
"layout (binding = 9) uniform isamplerBuffer texSIntBuffer;\n"
"layout (binding = 10) uniform isampler2DMS texSInt2DMS;\n"
"\n"
"// Floating point samplers\n"
"layout (binding = 1) uniform sampler1D tex1D;\n"
"layout (binding = 2) uniform sampler2D tex2D;\n"
"layout (binding = 3) uniform sampler3D tex3D;\n"
"layout (binding = 4) uniform samplerCube texCube;\n"
"layout (binding = 5) uniform sampler1DArray tex1DArray;\n"
"layout (binding = 6) uniform sampler2DArray tex2DArray;\n"
"layout (binding = 7) uniform samplerCubeArray texCubeArray;\n"
"layout (binding = 8) uniform sampler2DRect tex2DRect;\n"
"layout (binding = 9) uniform samplerBuffer texBuffer;\n"
"layout (binding = 10) uniform sampler2DMS tex2DMS;\n"
"// End Textures\n\n\n");
}
else if(api == GraphicsAPI::Vulkan)
{
m_Scintillas[0]->insertText(snippetPos(),
"// Textures\n"
"// Floating point samplers\n"
"layout(binding = 6) uniform sampler1DArray tex1DArray;\n"
"layout(binding = 7) uniform sampler2DArray tex2DArray;\n"
"layout(binding = 8) uniform sampler3D tex3D;\n"
"layout(binding = 9) uniform sampler2DMS tex2DMS;\n"
"layout(binding = 10) uniform sampler2DArray texYUVArray[2];\n"
"\n"
"// Unsigned int samplers\n"
"layout(binding = 11) uniform usampler1DArray texUInt1DArray;\n"
"layout(binding = 12) uniform usampler2DArray texUInt2DArray;\n"
"layout(binding = 13) uniform usampler3D texUInt3D;\n"
"layout(binding = 14) uniform usampler2DMS texUInt2DMS;\n"
"\n"
"// Int samplers\n"
"layout(binding = 16) uniform isampler1DArray texSInt1DArray;\n"
"layout(binding = 17) uniform isampler2DArray texSInt2DArray;\n"
"layout(binding = 18) uniform isampler3D texSInt3D;\n"
"layout(binding = 19) uniform isampler2DMS texSInt2DMS;\n"
"// End Textures\n\n\n");
}
// Unsigned int samplers
Texture1DArray<uint4> texDisplayUIntTex1DArray : register(t11);
Texture2DArray<uint4> texDisplayUIntTex2DArray : register(t12);
Texture3D<uint4> texDisplayUIntTex3D : register(t13);
Texture2DMSArray<uint4> texDisplayUIntTex2DMSArray : register(t14);
m_Scintillas[0]->setSelection(0, 0);
// Int samplers
Texture1DArray<int4> texDisplayIntTex1DArray : register(t16);
Texture2DArray<int4> texDisplayIntTex2DArray : register(t17);
Texture3D<int4> texDisplayIntTex3D : register(t18);
Texture2DMSArray<int4> texDisplayIntTex2DMSArray : register(t19);
// End Textures
)"));
}
else
{
insertSnippet(lit(R"(
// Textures
Texture1DArray<float4> texDisplayTex1DArray : register(t1);
Texture2DArray<float4> texDisplayTex2DArray : register(t2);
Texture3D<float4> texDisplayTex3D : register(t3);
Texture2DArray<float2> texDisplayTexDepthArray : register(t4);
Texture2DArray<uint2> texDisplayTexStencilArray : register(t5);
Texture2DMSArray<float2> texDisplayTexDepthMSArray : register(t6);
Texture2DMSArray<uint2> texDisplayTexStencilMSArray : register(t7);
Texture2DMSArray<float4> texDisplayTex2DMSArray : register(t9);
Texture2DArray<float4> texDisplayYUVArray : register(t10);
// Unsigned int samplers
Texture1DArray<uint4> texDisplayUIntTex1DArray : register(t11);
Texture2DArray<uint4> texDisplayUIntTex2DArray : register(t12);
Texture3D<uint4> texDisplayUIntTex3D : register(t13);
Texture2DMSArray<uint4> texDisplayUIntTex2DMSArray : register(t19);
// Int samplers
Texture1DArray<int4> texDisplayIntTex1DArray : register(t21);
Texture2DArray<int4> texDisplayIntTex2DArray : register(t22);
Texture3D<int4> texDisplayIntTex3D : register(t23);
Texture2DMSArray<int4> texDisplayIntTex2DMSArray : register(t29);
// End Textures
)"));
}
}
else if(encoding == ShaderEncoding::GLSL)
{
if(api == GraphicsAPI::Vulkan)
{
insertSnippet(lit(R"(
// Textures
// Floating point samplers
layout(binding = 6) uniform sampler1DArray tex1DArray;
layout(binding = 7) uniform sampler2DArray tex2DArray;
layout(binding = 8) uniform sampler3D tex3D;
layout(binding = 9) uniform sampler2DMS tex2DMS;
layout(binding = 10) uniform sampler2DArray texYUVArray[2];
// Unsigned int samplers
layout(binding = 11) uniform usampler1DArray texUInt1DArray;
layout(binding = 12) uniform usampler2DArray texUInt2DArray;
layout(binding = 13) uniform usampler3D texUInt3D;
layout(binding = 14) uniform usampler2DMS texUInt2DMS;
// Int samplers
layout(binding = 16) uniform isampler1DArray texSInt1DArray;
layout(binding = 17) uniform isampler2DArray texSInt2DArray;
layout(binding = 18) uniform isampler3D texSInt3D;
layout(binding = 19) uniform isampler2DMS texSInt2DMS;
// End Textures
)"));
}
else
{
insertSnippet(lit(R"(
// Textures
// Unsigned int samplers
layout (binding = 1) uniform usampler1D texUInt1D;
layout (binding = 2) uniform usampler2D texUInt2D;
layout (binding = 3) uniform usampler3D texUInt3D;
// cube = 4
layout (binding = 5) uniform usampler1DArray texUInt1DArray;
layout (binding = 6) uniform usampler2DArray texUInt2DArray;
// cube array = 7
layout (binding = 8) uniform usampler2DRect texUInt2DRect;
layout (binding = 9) uniform usamplerBuffer texUIntBuffer;
layout (binding = 10) uniform usampler2DMS texUInt2DMS;
// Int samplers
layout (binding = 1) uniform isampler1D texSInt1D;
layout (binding = 2) uniform isampler2D texSInt2D;
layout (binding = 3) uniform isampler3D texSInt3D;
// cube = 4
layout (binding = 5) uniform isampler1DArray texSInt1DArray;
layout (binding = 6) uniform isampler2DArray texSInt2DArray;
// cube array = 7
layout (binding = 8) uniform isampler2DRect texSInt2DRect;
layout (binding = 9) uniform isamplerBuffer texSIntBuffer;
layout (binding = 10) uniform isampler2DMS texSInt2DMS;
// Floating point samplers
layout (binding = 1) uniform sampler1D tex1D;
layout (binding = 2) uniform sampler2D tex2D;
layout (binding = 3) uniform sampler3D tex3D;
layout (binding = 4) uniform samplerCube texCube;
layout (binding = 5) uniform sampler1DArray tex1DArray;
layout (binding = 6) uniform sampler2DArray tex2DArray;
layout (binding = 7) uniform samplerCubeArray texCubeArray;
layout (binding = 8) uniform sampler2DRect tex2DRect;
layout (binding = 9) uniform samplerBuffer texBuffer;
layout (binding = 10) uniform sampler2DMS tex2DMS;
// End Textures
)"));
}
}
}
bool ShaderViewer::eventFilter(QObject *watched, QEvent *event)
@@ -3457,7 +3580,7 @@ void ShaderViewer::on_refresh_clicked()
// if we don't have any compile tools - even the 'builtin' one, this compilation is not going to
// succeed.
if(ui->compileTool->count() == 0)
if(ui->compileTool->count() == 0 && !m_CustomShader)
{
ShowErrors(tr("No compilation tool found that takes %1 as input and produces compatible output")
.arg(ToQStr(encoding)));
@@ -3488,8 +3611,8 @@ void ShaderViewer::on_refresh_clicked()
rdcarray<ShaderEncoding> accepted = m_Ctx.TargetShaderEncodings();
if(accepted.indexOf(encoding) >= 0 &&
ui->compileTool->currentIndex() == ui->compileTool->count() - 1)
if(m_CustomShader || (accepted.indexOf(encoding) >= 0 &&
ui->compileTool->currentIndex() == ui->compileTool->count() - 1))
{
// if using the builtin compiler, just pass through
}
+4 -1
View File
@@ -171,6 +171,8 @@ private:
void gotoSourceDebugging();
void gotoDisassemblyDebugging();
void insertSnippet(const QString &text);
void showVariableTooltip(VariableCategory varCat, int varIdx, int arrayIdx);
void showVariableTooltip(QString name);
void updateVariableTooltip();
@@ -190,6 +192,7 @@ private:
ICaptureContext &m_Ctx;
const ShaderBindpointMapping *m_Mapping = NULL;
const ShaderReflection *m_ShaderDetails = NULL;
bool m_CustomShader = false;
ShaderCompileFlags m_Flags;
QList<ShaderEncoding> m_Encodings;
ShaderStage m_Stage;
@@ -255,7 +258,7 @@ private:
ScintillaEdit *nextScintilla(ScintillaEdit *cur);
int snippetPos();
void insertVulkanUBO();
QString vulkanUBO();
int instructionForLine(sptr_t line);
+181 -34
View File
@@ -54,6 +54,13 @@ float aspect(const QSizeF &s)
return s.width() / s.height();
}
static QMap<QString, ShaderEncoding> encodingExtensions = {
{lit("hlsl"), ShaderEncoding::HLSL},
{lit("glsl"), ShaderEncoding::GLSL},
{lit("frag"), ShaderEncoding::GLSL},
{lit("spvasm"), ShaderEncoding::SPIRVAsm},
};
Q_DECLARE_METATYPE(Following);
const Following Following::Default = Following();
@@ -1470,6 +1477,13 @@ void TextureViewer::UI_UpdateChannels()
const bool yuvDecodeDisplay = ui->channels->currentIndex() == 2;
const bool customDisplay = ui->channels->currentIndex() == 3;
if(customDisplay && m_NeedCustomReload)
{
m_NeedCustomReload = false;
reloadCustomShaders(QString());
}
ui->channels->setItemText(0, yuv ? lit("YUVA") : lit("RGBA"));
ui->channelRed->setText(lit("R"));
ui->channelGreen->setText(lit("G"));
@@ -2671,7 +2685,8 @@ void TextureViewer::OnCaptureLoaded()
&TextureViewer::customShaderModified);
QObject::connect(m_Watcher, &QFileSystemWatcher::directoryChanged, this,
&TextureViewer::customShaderModified);
reloadCustomShaders(QString());
m_NeedCustomReload = true;
}
void TextureViewer::Reset()
@@ -3743,6 +3758,28 @@ void TextureViewer::on_textureList_clicked(const QModelIndex &index)
ViewTexture(id, false);
}
bool TextureViewer::canCompileCustomShader(ShaderEncoding encoding)
{
rdcarray<ShaderEncoding> supported = m_Ctx.CustomShaderEncodings();
// if it's directly supported, we can trivially compile it
if(supported.contains(encoding))
return true;
// otherwise see if we have a tool that can compile it for us
for(const ShaderProcessingTool &tool : m_Ctx.Config().ShaderProcessors)
{
// if this tool transforms from the encoding to one we support, we can compile a shader of this
// encoding
if(tool.input == encoding && supported.contains(tool.output))
return true;
}
// all options exhausted, we can't compile this
return false;
}
void TextureViewer::reloadCustomShaders(const QString &filter)
{
if(!m_Ctx.IsCaptureLoaded())
@@ -3766,7 +3803,7 @@ void TextureViewer::reloadCustomShaders(const QString &filter)
}
else
{
QString fn = QFileInfo(filter).baseName();
QString fn = QFileInfo(filter).fileName();
QString key = fn.toUpper();
if(m_CustomShaders.contains(key))
@@ -3794,10 +3831,18 @@ void TextureViewer::reloadCustomShaders(const QString &filter)
}
}
QStringList filters;
for(auto it = encodingExtensions.begin(); it != encodingExtensions.end(); ++it)
{
if(!canCompileCustomShader(it.value()))
continue;
filters.push_back(lit("*.") + it.key());
}
QStringList files =
QDir(configFilePath(QString()))
.entryList({QFormatStr("*.%1").arg(m_Ctx.CurPipelineState().GetShaderExtension())},
QDir::Files | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase);
.entryList(filters, QDir::Files | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase);
QStringList watchedFiles = m_Watcher->files();
if(!watchedFiles.isEmpty())
@@ -3805,8 +3850,13 @@ void TextureViewer::reloadCustomShaders(const QString &filter)
for(const QString &f : files)
{
QString fn = QFileInfo(f).baseName();
QFileInfo fileInfo(f);
QString fn = fileInfo.fileName();
QString key = fn.toUpper();
ShaderEncoding encoding = encodingExtensions[fileInfo.completeSuffix()];
if(!filter.isEmpty() && filter.toUpper() != key)
continue;
m_Watcher->addPath(configFilePath(f));
@@ -3818,36 +3868,87 @@ void TextureViewer::reloadCustomShaders(const QString &filter)
QTextStream stream(&fileHandle);
QString source = stream.readAll();
bytebuf shaderBytes(source.toUtf8());
rdcarray<ShaderEncoding> supported = m_Ctx.TargetShaderEncodings();
rdcstr errors;
// we don't accept this encoding directly, need to compile
if(!supported.contains(encoding))
{
for(const ShaderProcessingTool &tool : m_Ctx.Config().ShaderProcessors)
{
// pick the first tool that can convert to an accepted format
if(tool.input == encoding && supported.contains(tool.output))
{
ShaderToolOutput out =
tool.CompileShader(this, source, "main", ShaderStage::Pixel, "");
errors = out.log;
if(m_CustomShaderEditor.contains(key))
m_CustomShaderEditor[key]->ShowErrors(errors);
if(out.result.isEmpty())
break;
encoding = tool.output;
shaderBytes = out.result;
break;
}
}
}
// if the encoding still isn't supported, all tools failed. Bail out now
if(!supported.contains(encoding))
{
if(m_CustomShaderEditor.contains(key))
m_CustomShaderEditor[key]->ShowErrors(errors);
m_CustomShaders[key] = ResourceId();
QString prevtext = ui->customShader->currentText();
ui->customShader->addItem(fn);
ui->customShader->setCurrentText(prevtext);
continue;
}
ANALYTIC_SET(UIFeatures.CustomTextureVisualise, true);
fileHandle.close();
m_CustomShaders[key] = ResourceId();
m_CustomShadersBusy.push_back(key);
m_Ctx.Replay().AsyncInvoke([this, fn, key, source](IReplayController *r) {
rdcstr errors;
m_Ctx.Replay().AsyncInvoke(
[this, fn, key, shaderBytes, encoding, errors](IReplayController *r) {
rdcstr buildErrors;
ResourceId id;
rdctie(id, errors) = r->BuildCustomShader("main", source.toUtf8().data(),
ShaderCompileFlags(), ShaderStage::Pixel);
ResourceId id;
rdctie(id, buildErrors) = r->BuildCustomShader(
"main", encoding, shaderBytes, ShaderCompileFlags(), ShaderStage::Pixel);
if(m_CustomShaderEditor.contains(key))
{
IShaderViewer *editor = m_CustomShaderEditor[key];
GUIInvoke::call(editor->Widget(), [editor, errors]() { editor->ShowErrors(errors); });
}
if(!errors.empty())
buildErrors = errors + "\n\n" + buildErrors;
GUIInvoke::call(this, [this, fn, key, id]() {
QString prevtext = ui->customShader->currentText();
ui->customShader->addItem(fn);
ui->customShader->setCurrentText(prevtext);
if(m_CustomShaderEditor.contains(key))
{
IShaderViewer *editor = m_CustomShaderEditor[key];
GUIInvoke::call(editor->Widget(),
[editor, buildErrors]() { editor->ShowErrors(buildErrors); });
}
m_CustomShaders[key] = id;
m_CustomShadersBusy.removeOne(key);
GUIInvoke::call(this, [this, fn, key, id]() {
QString prevtext = ui->customShader->currentText();
ui->customShader->addItem(fn);
ui->customShader->setCurrentText(prevtext);
UI_UpdateChannels();
});
});
m_CustomShaders[key] = id;
m_CustomShadersBusy.removeOne(key);
UI_UpdateChannels();
});
});
}
}
}
@@ -3873,11 +3974,34 @@ void TextureViewer::on_customCreate_clicked()
return;
}
QString path = configFilePath(filename + lit(".") + m_Ctx.CurPipelineState().GetShaderExtension());
ShaderEncoding enc = encodingExtensions[QFileInfo(filename).completeSuffix()];
if(enc == ShaderEncoding::Unknown)
{
QString extString;
for(auto it = encodingExtensions.begin(); it != encodingExtensions.end(); ++it)
{
if(!canCompileCustomShader(it.value()))
continue;
if(!extString.isEmpty())
extString += lit(", ");
extString += it.key();
}
RDDialog::critical(this, tr("Error Creating Shader"),
tr("No file extension specified, unknown shading language.\n"
"Filename must contain one of: %1")
.arg(extString));
return;
}
QString path = configFilePath(filename);
QString src;
if(IsD3D(m_Ctx.APIProps().pipelineType))
if(enc == ShaderEncoding::HLSL)
{
src =
lit("float4 main(float4 pos : SV_Position, float4 uv : TEXCOORD0) : SV_Target0\n"
@@ -3885,7 +4009,7 @@ void TextureViewer::on_customCreate_clicked()
" return float4(0,0,0,1);\n"
"}\n");
}
else
else if(enc == ShaderEncoding::GLSL)
{
src =
lit("#version 420 core\n\n"
@@ -3896,6 +4020,14 @@ void TextureViewer::on_customCreate_clicked()
" color_out = vec4(0,0,0,1);\n"
"}\n");
}
else if(enc == ShaderEncoding::SPIRVAsm)
{
src = lit("; SPIR-V");
}
else
{
src = tr("Unknown format - no template available");
}
QFile fileHandle(path);
if(fileHandle.open(QFile::WriteOnly | QIODevice::Truncate | QIODevice::Text))
@@ -3928,7 +4060,7 @@ void TextureViewer::on_customEdit_clicked()
return;
}
QString path = configFilePath(filename + lit(".") + m_Ctx.CurPipelineState().GetShaderExtension());
QString path = configFilePath(filename);
QString src;
@@ -3954,13 +4086,15 @@ void TextureViewer::on_customEdit_clicked()
IShaderViewer *s = m_Ctx.EditShader(
true, ShaderStage::Fragment, lit("main"), files,
IsD3D(m_Ctx.APIProps().localRenderer) ? ShaderEncoding::HLSL : ShaderEncoding::GLSL,
ShaderCompileFlags(),
encodingExtensions[QFileInfo(filename).completeSuffix()], ShaderCompileFlags(),
// Save Callback
[thisPointer, key, filename, path](ICaptureContext *ctx, IShaderViewer *viewer,
ShaderEncoding encoding, ShaderCompileFlags flags,
rdcstr entryFunc, bytebuf bytes) {
ShaderEncoding, ShaderCompileFlags, rdcstr, bytebuf bytes) {
{
// don't trigger a full refresh
if(thisPointer)
thisPointer->m_CustomShaderWriteTime = thisPointer->m_CustomShaderTimer.elapsed();
QFile fileHandle(path);
if(fileHandle.open(QFile::WriteOnly | QIODevice::Truncate | QIODevice::Text))
{
@@ -4018,8 +4152,7 @@ void TextureViewer::on_customDelete_clicked()
if(res == QMessageBox::Yes)
{
QString path =
configFilePath(shaderName + lit(".") + m_Ctx.CurPipelineState().GetShaderExtension());
QString path = configFilePath(shaderName);
if(!QFileInfo::exists(path))
{
RDDialog::critical(
@@ -4043,8 +4176,22 @@ void TextureViewer::on_customDelete_clicked()
void TextureViewer::customShaderModified(const QString &path)
{
static bool recurse = false;
if(recurse)
return;
// if we just wrote a shader less than 100ms ago, don't refresh - this will have been handled
// internally at a finer granularity than 'all shaders'
if(m_CustomShaderWriteTime > m_CustomShaderTimer.elapsed() - 100)
return;
recurse = true;
// allow time for modifications to finish
QThread::msleep(15);
reloadCustomShaders(QString());
recurse = false;
}
+7
View File
@@ -27,6 +27,7 @@
#include <QFrame>
#include <QMenu>
#include <QMouseEvent>
#include <QTime>
#include "Code/Interface/QRDInterface.h"
namespace Ui
@@ -322,15 +323,21 @@ private:
TextureSave m_SaveConfig;
bool m_NeedCustomReload = false;
TextureDescription *m_CachedTexture;
Following m_Following = Following::Default;
QMap<ResourceId, TexSettings> m_TextureSettings;
QTime m_CustomShaderTimer;
int m_CustomShaderWriteTime = 0;
QFileSystemWatcher *m_Watcher = NULL;
QStringList m_CustomShadersBusy;
QMap<QString, ResourceId> m_CustomShaders;
QMap<QString, IShaderViewer *> m_CustomShaderEditor;
bool canCompileCustomShader(ShaderEncoding encoding);
void reloadCustomShaders(const QString &filter);
TextureDisplay m_TexDisplay;
+2 -2
View File
@@ -650,7 +650,7 @@
<rect>
<x>3</x>
<y>3</y>
<width>696</width>
<width>746</width>
<height>32</height>
</rect>
</property>
@@ -848,7 +848,7 @@
</property>
<property name="minimumSize">
<size>
<width>100</width>
<width>150</width>
<height>0</height>
</size>
</property>