From e4333291a112f9fbf5491e367ae900ddc837ee20 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 22 May 2019 17:54:10 +0100 Subject: [PATCH] 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. --- docs/how/how_custom_visualisation.rst | 4 +- docs/how/how_edit_shader.rst | 2 +- qrenderdoc/Windows/ShaderViewer.cpp | 519 ++++++++++++------- qrenderdoc/Windows/ShaderViewer.h | 5 +- qrenderdoc/Windows/TextureViewer.cpp | 215 ++++++-- qrenderdoc/Windows/TextureViewer.h | 7 + qrenderdoc/Windows/TextureViewer.ui | 4 +- renderdoc/api/replay/pipestate.h | 9 - renderdoc/api/replay/pipestate.inl | 10 - renderdoc/api/replay/renderdoc_replay.h | 10 +- renderdoc/core/image_viewer.cpp | 6 +- renderdoc/core/replay_proxy.cpp | 10 +- renderdoc/core/replay_proxy.h | 6 +- renderdoc/driver/d3d11/d3d11_postvs.cpp | 3 + renderdoc/driver/d3d11/d3d11_replay.cpp | 19 +- renderdoc/driver/d3d11/d3d11_replay.h | 6 +- renderdoc/driver/d3d12/d3d12_replay.cpp | 19 +- renderdoc/driver/d3d12/d3d12_replay.h | 6 +- renderdoc/driver/gl/gl_replay.cpp | 67 +-- renderdoc/driver/gl/gl_replay.h | 4 +- renderdoc/driver/gl/wrappers/gl_emulated.cpp | 6 +- renderdoc/driver/vulkan/vk_debug.cpp | 4 + renderdoc/driver/vulkan/vk_replay.cpp | 53 +- renderdoc/driver/vulkan/vk_replay.h | 5 +- renderdoc/replay/replay_controller.cpp | 14 +- renderdoc/replay/replay_controller.h | 3 +- renderdoc/replay/replay_driver.h | 12 +- 27 files changed, 607 insertions(+), 421 deletions(-) diff --git a/docs/how/how_custom_visualisation.rst b/docs/how/how_custom_visualisation.rst index 9770d7a75..b5ea4e992 100644 --- a/docs/how/how_custom_visualisation.rst +++ b/docs/how/how_custom_visualisation.rst @@ -6,7 +6,9 @@ This page details how to set up a custom shader for visualisation. This can be u Introduction ------------ -The basic process of setting up the custom shader involves writing a ``.hlsl`` or ``.glsl`` file that will be compiled and used by RenderDoc. Note that the type used matches the API used, and RenderDoc will automatically list only the hlsl shaders you have if you load a log with D3D11 or D3D12, and glsl for OpenGL or Vulkan. +The basic process of setting up the custom shader involves writing a shader file that will be compiled and used by RenderDoc. Note that you can use any language that is either natively accepted by the graphics API used, or any language that can be compiled to an accepted shader. + +For example on D3D11 or D3D12, hlsl is the only language usable by default, but on Vulkan you can use hlsl or glsl as long as a compiler is available. There are several special global variables that can be specified and will be filled in with values by RenderDoc. diff --git a/docs/how/how_edit_shader.rst b/docs/how/how_edit_shader.rst index 4fb49789f..8c9b6829b 100644 --- a/docs/how/how_edit_shader.rst +++ b/docs/how/how_edit_shader.rst @@ -11,7 +11,7 @@ How to edit a custom shader :doc:`Custom visualisation shaders ` allow you to define your own transformation on any texture you're viewing before it is displayed. Mostly this is useful for decoding packed or custom-format data, or displaying some data in a more visually intuitive fashion. -These shaders live as ``.hlsl`` or ``.glsl`` files in the application storage directory ( ``%APPDATA%/qrenderdoc/`` on windows or ``~/.local/share/qrenderdoc`` elsewhere), and can be edited in your editor of choice, any changes saved will be reloaded. Note however that there is currently no way to see the compile warnings or errors produced when editing externally. +These shaders live as files in the application storage directory ( ``%APPDATA%/qrenderdoc/`` on windows or ``~/.local/share/qrenderdoc`` elsewhere), and can be edited in your editor of choice, any changes saved will be reloaded. Note however that there is currently no way to see the compile warnings or errors produced when editing externally. To edit a shader inside RenderDoc simply click the edit button |page_white_edit| when you have selected your custom shader for use. This will launch a new window with the custom shader and any changes you make to this shader will be saved to the file and compiled and reflected in the texture viewer as long as you have that custom shader selected. diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index 84dcbb905..91e765c86 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -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()) 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 texDisplayTex1DArray : register(t6); +Texture2DArray texDisplayTex2DArray : register(t7); +Texture3D texDisplayTex3D : register(t8); +Texture2DMSArray texDisplayTex2DMSArray : register(t9); +Texture2DArray texDisplayYUVArray : register(t10); - if(IsD3D(api)) - { - m_Scintillas[0]->insertText( - snippetPos(), - "// Textures\n" - "Texture1DArray texDisplayTex1DArray : register(t1);\n" - "Texture2DArray texDisplayTex2DArray : register(t2);\n" - "Texture3D texDisplayTex3D : register(t3);\n" - "Texture2DArray texDisplayTexDepthArray : register(t4);\n" - "Texture2DArray texDisplayTexStencilArray : register(t5);\n" - "Texture2DMSArray texDisplayTexDepthMSArray : register(t6);\n" - "Texture2DMSArray texDisplayTexStencilMSArray : register(t7);\n" - "Texture2DMSArray texDisplayTex2DMSArray : register(t9);\n" - "Texture2DArray texDisplayYUVArray : register(t10);\n" - "\n" - "Texture1DArray texDisplayUIntTex1DArray : register(t11);\n" - "Texture2DArray texDisplayUIntTex2DArray : register(t12);\n" - "Texture3D texDisplayUIntTex3D : register(t13);\n" - "Texture2DMSArray texDisplayUIntTex2DMSArray : register(t19);\n" - "\n" - "Texture1DArray texDisplayIntTex1DArray : register(t21);\n" - "Texture2DArray texDisplayIntTex2DArray : register(t22);\n" - "Texture3D texDisplayIntTex3D : register(t23);\n" - "Texture2DMSArray 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 texDisplayUIntTex1DArray : register(t11); +Texture2DArray texDisplayUIntTex2DArray : register(t12); +Texture3D texDisplayUIntTex3D : register(t13); +Texture2DMSArray texDisplayUIntTex2DMSArray : register(t14); - m_Scintillas[0]->setSelection(0, 0); +// Int samplers +Texture1DArray texDisplayIntTex1DArray : register(t16); +Texture2DArray texDisplayIntTex2DArray : register(t17); +Texture3D texDisplayIntTex3D : register(t18); +Texture2DMSArray texDisplayIntTex2DMSArray : register(t19); +// End Textures +)")); + } + else + { + insertSnippet(lit(R"( +// Textures +Texture1DArray texDisplayTex1DArray : register(t1); +Texture2DArray texDisplayTex2DArray : register(t2); +Texture3D texDisplayTex3D : register(t3); +Texture2DArray texDisplayTexDepthArray : register(t4); +Texture2DArray texDisplayTexStencilArray : register(t5); +Texture2DMSArray texDisplayTexDepthMSArray : register(t6); +Texture2DMSArray texDisplayTexStencilMSArray : register(t7); +Texture2DMSArray texDisplayTex2DMSArray : register(t9); +Texture2DArray texDisplayYUVArray : register(t10); + +// Unsigned int samplers +Texture1DArray texDisplayUIntTex1DArray : register(t11); +Texture2DArray texDisplayUIntTex2DArray : register(t12); +Texture3D texDisplayUIntTex3D : register(t13); +Texture2DMSArray texDisplayUIntTex2DMSArray : register(t19); + +// Int samplers +Texture1DArray texDisplayIntTex1DArray : register(t21); +Texture2DArray texDisplayIntTex2DArray : register(t22); +Texture3D texDisplayIntTex3D : register(t23); +Texture2DMSArray 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 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 } diff --git a/qrenderdoc/Windows/ShaderViewer.h b/qrenderdoc/Windows/ShaderViewer.h index e6f3c4901..7bf3873bb 100644 --- a/qrenderdoc/Windows/ShaderViewer.h +++ b/qrenderdoc/Windows/ShaderViewer.h @@ -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 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); diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 8165f81cb..c366589dd 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -54,6 +54,13 @@ float aspect(const QSizeF &s) return s.width() / s.height(); } +static QMap 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 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 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; } diff --git a/qrenderdoc/Windows/TextureViewer.h b/qrenderdoc/Windows/TextureViewer.h index ca9a7b568..fd68eeb23 100644 --- a/qrenderdoc/Windows/TextureViewer.h +++ b/qrenderdoc/Windows/TextureViewer.h @@ -27,6 +27,7 @@ #include #include #include +#include #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 m_TextureSettings; + QTime m_CustomShaderTimer; + int m_CustomShaderWriteTime = 0; + QFileSystemWatcher *m_Watcher = NULL; QStringList m_CustomShadersBusy; QMap m_CustomShaders; QMap m_CustomShaderEditor; + bool canCompileCustomShader(ShaderEncoding encoding); void reloadCustomShaders(const QString &filter); TextureDisplay m_TexDisplay; diff --git a/qrenderdoc/Windows/TextureViewer.ui b/qrenderdoc/Windows/TextureViewer.ui index b16eecbc1..467af40db 100644 --- a/qrenderdoc/Windows/TextureViewer.ui +++ b/qrenderdoc/Windows/TextureViewer.ui @@ -650,7 +650,7 @@ 3 3 - 696 + 746 32 @@ -848,7 +848,7 @@ - 100 + 150 0 diff --git a/renderdoc/api/replay/pipestate.h b/renderdoc/api/replay/pipestate.h index 4a3873fca..0b88250a6 100644 --- a/renderdoc/api/replay/pipestate.h +++ b/renderdoc/api/replay/pipestate.h @@ -184,15 +184,6 @@ requirements. )"); rdcstr OutputAbbrev() const; - DOCUMENT(R"(Retrieves the common file extension for high level shaders in the current API. - -Typically this is ``glsl`` or ``hlsl``. - -:return: The file extension with no ``.``. -:rtype: ``str`` -)"); - rdcstr GetShaderExtension() const; - DOCUMENT(R"(Retrieves the viewport for a given index. :param int index: The index to retrieve. diff --git a/renderdoc/api/replay/pipestate.inl b/renderdoc/api/replay/pipestate.inl index f4ea43964..6717bcc3f 100644 --- a/renderdoc/api/replay/pipestate.inl +++ b/renderdoc/api/replay/pipestate.inl @@ -166,16 +166,6 @@ const VKPipe::Shader &PipeState::GetVulkanStage(ShaderStage stage) const return m_Vulkan->computeShader; } -rdcstr PipeState::GetShaderExtension() const -{ - if(IsCaptureGL() || IsCaptureVK()) - { - return "glsl"; - } - - return "hlsl"; -} - Viewport PipeState::GetViewport(int index) const { Viewport ret = {}; diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index e640d7b3d..607a67ea5 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -982,19 +982,19 @@ or hardware-specific ISA formats. DOCUMENT(R"(Builds a shader suitable for running on the local replay instance as a custom shader. -The language used is native to the local renderer - HLSL for D3D based renderers, GLSL otherwise. - See :data:`TextureDisplay.customShaderId`. :param str entry: The entry point to use when compiling. -:param str source: The source file. +:param ShaderEncoding sourceEncoding: The encoding of the source data. +:param bytes source: The source data itself. :param int compileFlags: API-specific compilation flags. :param ShaderStage type: The stage that this shader will be executed at. :return: A ``tuple`` with the id of the new shader if compilation was successful, :meth:`ResourceId.Null` otherwise, and a ``str`` with any warnings/errors from compilation. :rtype: ``tuple`` of :class:`ResourceId` and ``str``. )"); - virtual rdcpair BuildCustomShader(const char *entry, const char *source, + virtual rdcpair BuildCustomShader(const char *entry, + ShaderEncoding sourceEncoding, bytebuf source, const ShaderCompileFlags &compileFlags, ShaderStage type) = 0; @@ -1008,8 +1008,6 @@ See :meth:`BuildCustomShader`. DOCUMENT(R"(Builds a shader suitable for running in the capture's API as a replacement shader. -The language used is native to the API's renderer - HLSL for D3D based renderers, GLSL otherwise. - :param str entry: The entry point to use when compiling. :param ShaderEncoding sourceEncoding: The encoding of the source data. :param bytes source: The source data itself. diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 3de28baec..ba56c3c8d 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -145,11 +145,11 @@ public: { return m_Proxy->GetCustomShaderEncodings(); } - void BuildCustomShader(std::string source, std::string entry, + void BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors) { - m_Proxy->BuildCustomShader(source, entry, compileFlags, type, id, errors); + m_Proxy->BuildCustomShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } void FreeCustomShader(ResourceId id) { m_Proxy->FreeTargetResource(id); } ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, @@ -269,7 +269,7 @@ public: RDCEraseEl(ret); return ret; } - void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, + void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors) { diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index c992fe3d4..8bf7247c8 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -1266,7 +1266,8 @@ rdcarray ReplayProxy::GetTargetShaderEncodings() template void ReplayProxy::Proxied_BuildTargetShader(ParamSerialiser ¶mser, ReturnSerialiser &retser, ShaderEncoding sourceEncoding, bytebuf source, - std::string entry, const ShaderCompileFlags &compileFlags, + const std::string &entry, + const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors) { const ReplayProxyPacket expectedPacket = eReplayProxy_BuildTargetShader; @@ -1309,7 +1310,7 @@ void ReplayProxy::Proxied_BuildTargetShader(ParamSerialiser ¶mser, ReturnSer } void ReplayProxy::BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, - std::string entry, const ShaderCompileFlags &compileFlags, + const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors) { PROXY_FUNCTION(BuildTargetShader, sourceEncoding, source, entry, compileFlags, type, id, errors); @@ -2614,9 +2615,12 @@ bool ReplayProxy::Tick(int type) } case eReplayProxy_GetPostVS: GetPostVSBuffers(0, 0, 0, MeshDataStage::Unknown); break; case eReplayProxy_BuildTargetShader: - BuildTargetShader(ShaderEncoding::Unknown, bytebuf(), "", ShaderCompileFlags(), + { + std::string entry; + BuildTargetShader(ShaderEncoding::Unknown, bytebuf(), entry, ShaderCompileFlags(), ShaderStage::Vertex, NULL, NULL); break; + } case eReplayProxy_ReplaceResource: ReplaceResource(ResourceId(), ResourceId()); break; case eReplayProxy_RemoveReplacement: RemoveReplacement(ResourceId()); break; case eReplayProxy_DebugVertex: DebugVertex(0, 0, 0, 0, 0, 0); break; diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 4ae095728..8fa68aa98 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -401,13 +401,13 @@ public: return ~0U; } - void BuildCustomShader(std::string source, std::string entry, + void BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors) { if(m_Proxy) { - m_Proxy->BuildCustomShader(source, entry, compileFlags, type, id, errors); + m_Proxy->BuildCustomShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } else { @@ -531,7 +531,7 @@ public: IMPLEMENT_FUNCTION_PROXIED(rdcarray, GetTargetShaderEncodings); IMPLEMENT_FUNCTION_PROXIED(void, BuildTargetShader, ShaderEncoding sourceEncoding, bytebuf source, - std::string entry, const ShaderCompileFlags &compileFlags, + const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); IMPLEMENT_FUNCTION_PROXIED(void, ReplaceResource, ResourceId from, ResourceId to); IMPLEMENT_FUNCTION_PROXIED(void, RemoveReplacement, ResourceId id); diff --git a/renderdoc/driver/d3d11/d3d11_postvs.cpp b/renderdoc/driver/d3d11/d3d11_postvs.cpp index 1fe298596..5463bac0a 100644 --- a/renderdoc/driver/d3d11/d3d11_postvs.cpp +++ b/renderdoc/driver/d3d11/d3d11_postvs.cpp @@ -833,6 +833,9 @@ void D3D11Replay::InitPostVSBuffers(uint32_t eventId) drawcall->instanceOffset); m_pImmediateContext->End(m_SOStatsQueries[inst - 1]); } + + if((inst % 2000) == 0) + SerializeImmediateContext(); } } diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 7353de563..85318555c 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -2292,9 +2292,9 @@ D3D11DebugManager *D3D11Replay::GetDebugManager() return m_pDevice->GetDebugManager(); } -void D3D11Replay::BuildShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, - const ShaderCompileFlags &compileFlags, ShaderStage type, - ResourceId *id, std::string *errors) +void D3D11Replay::BuildShader(ShaderEncoding sourceEncoding, bytebuf source, + const std::string &entry, const ShaderCompileFlags &compileFlags, + ShaderStage type, ResourceId *id, std::string *errors) { if(id == NULL || errors == NULL) { @@ -2449,7 +2449,7 @@ void D3D11Replay::BuildShader(ShaderEncoding sourceEncoding, bytebuf source, std } void D3D11Replay::BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, - std::string entry, const ShaderCompileFlags &compileFlags, + const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors) { ShaderCompileFlags debugCompileFlags = @@ -2458,14 +2458,11 @@ void D3D11Replay::BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf sourc BuildShader(sourceEncoding, source, entry, debugCompileFlags, type, id, errors); } -void D3D11Replay::BuildCustomShader(std::string source, std::string entry, - const ShaderCompileFlags &compileFlags, ShaderStage type, - ResourceId *id, std::string *errors) +void D3D11Replay::BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, + const std::string &entry, const ShaderCompileFlags &compileFlags, + ShaderStage type, ResourceId *id, std::string *errors) { - bytebuf buf; - buf.resize(source.size()); - memcpy(buf.data(), source.c_str(), buf.size()); - BuildShader(ShaderEncoding::HLSL, buf, entry, compileFlags, type, id, errors); + BuildTargetShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } bool D3D11Replay::RenderTexture(TextureDisplay cfg) diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 000859497..19394fea4 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -189,7 +189,7 @@ public: { return {ShaderEncoding::DXBC, ShaderEncoding::HLSL}; } - void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, + void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); void ReplaceResource(ResourceId from, ResourceId to); @@ -237,7 +237,7 @@ public: ResourceId RenderOverlay(ResourceId texid, CompType typeHint, DebugOverlay overlay, uint32_t eventId, const std::vector &passEvents); - void BuildCustomShader(std::string source, std::string entry, + void BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, @@ -252,7 +252,7 @@ private: D3D11DebugManager *GetDebugManager(); // shared by BuildCustomShader and BuildTargetShader - void BuildShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, + void BuildShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index d26f3d03a..48f42e335 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -2736,9 +2736,9 @@ std::vector D3D12Replay::GetDebugMessages() return m_pDevice->GetDebugMessages(); } -void D3D12Replay::BuildShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, - const ShaderCompileFlags &compileFlags, ShaderStage type, - ResourceId *id, std::string *errors) +void D3D12Replay::BuildShader(ShaderEncoding sourceEncoding, bytebuf source, + const std::string &entry, const ShaderCompileFlags &compileFlags, + ShaderStage type, ResourceId *id, std::string *errors) { if(id == NULL || errors == NULL) { @@ -2796,7 +2796,7 @@ void D3D12Replay::BuildShader(ShaderEncoding sourceEncoding, bytebuf source, std } void D3D12Replay::BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, - std::string entry, const ShaderCompileFlags &compileFlags, + const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors) { ShaderCompileFlags debugCompileFlags = @@ -3425,14 +3425,11 @@ void D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip SAFE_RELEASE(tmpTexture); } -void D3D12Replay::BuildCustomShader(std::string source, std::string entry, - const ShaderCompileFlags &compileFlags, ShaderStage type, - ResourceId *id, std::string *errors) +void D3D12Replay::BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, + const std::string &entry, const ShaderCompileFlags &compileFlags, + ShaderStage type, ResourceId *id, std::string *errors) { - bytebuf buf; - buf.resize(source.size()); - memcpy(buf.data(), source.c_str(), buf.size()); - BuildShader(ShaderEncoding::HLSL, buf, entry, compileFlags, type, id, errors); + BuildShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index c7cee7508..4f8882432 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -150,7 +150,7 @@ public: { return {ShaderEncoding::DXBC, ShaderEncoding::HLSL}; } - void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, + void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); void ReplaceResource(ResourceId from, ResourceId to); @@ -198,7 +198,7 @@ public: ResourceId RenderOverlay(ResourceId texid, CompType typeHint, DebugOverlay overlay, uint32_t eventId, const std::vector &passEvents); - void BuildCustomShader(std::string source, std::string entry, + void BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, @@ -219,7 +219,7 @@ private: void CreateSOBuffers(); - void BuildShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, + void BuildShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index b29c754d0..bb71cf9df 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -2727,64 +2727,11 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, drv.glDeleteTextures(1, &tempTex); } -void GLReplay::BuildCustomShader(std::string source, std::string entry, - const ShaderCompileFlags &compileFlags, ShaderStage type, - ResourceId *id, std::string *errors) +void GLReplay::BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, + const std::string &entry, const ShaderCompileFlags &compileFlags, + ShaderStage type, ResourceId *id, std::string *errors) { - if(id == NULL || errors == NULL) - { - if(id) - *id = ResourceId(); - return; - } - - WrappedOpenGL &drv = *m_pDriver; - - MakeCurrentReplayContext(m_DebugCtx); - - GLenum shtype = eGL_VERTEX_SHADER; - switch(type) - { - case ShaderStage::Vertex: shtype = eGL_VERTEX_SHADER; break; - case ShaderStage::Tess_Control: shtype = eGL_TESS_CONTROL_SHADER; break; - case ShaderStage::Tess_Eval: shtype = eGL_TESS_EVALUATION_SHADER; break; - case ShaderStage::Geometry: shtype = eGL_GEOMETRY_SHADER; break; - case ShaderStage::Fragment: shtype = eGL_FRAGMENT_SHADER; break; - case ShaderStage::Compute: shtype = eGL_COMPUTE_SHADER; break; - default: - { - RDCERR("Unknown shader type %u", type); - if(id) - *id = ResourceId(); - return; - } - } - - const char *src = source.c_str(); - GLuint shader = drv.glCreateShader(shtype); - - drv.glShaderSource(shader, 1, &src, NULL); - - drv.glCompileShader(shader); - - GLint status = 0; - drv.glGetShaderiv(shader, eGL_COMPILE_STATUS, &status); - - if(errors) - { - GLint len = 1024; - drv.glGetShaderiv(shader, eGL_INFO_LOG_LENGTH, &len); - char *buffer = new char[len + 1]; - drv.glGetShaderInfoLog(shader, len, NULL, buffer); - buffer[len] = 0; - *errors = buffer; - delete[] buffer; - } - - if(status == 0) - *id = ResourceId(); - else - *id = m_pDriver->GetResourceManager()->GetID(ShaderRes(m_pDriver->GetCtx(), shader)); + BuildTargetShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } ResourceId GLReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, @@ -2882,9 +2829,9 @@ void GLReplay::FreeCustomShader(ResourceId id) m_pDriver->glDeleteShader(m_pDriver->GetResourceManager()->GetCurrentResource(id).name); } -void GLReplay::BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, - const ShaderCompileFlags &compileFlags, ShaderStage type, - ResourceId *id, std::string *errors) +void GLReplay::BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, + const std::string &entry, const ShaderCompileFlags &compileFlags, + ShaderStage type, ResourceId *id, std::string *errors) { if(id == NULL || errors == NULL) { diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 15e6233bd..fa654e322 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -173,10 +173,10 @@ public: rdcarray GetCustomShaderEncodings() { return {ShaderEncoding::GLSL}; } rdcarray GetTargetShaderEncodings() { return {ShaderEncoding::GLSL}; } - void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, + void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); - void BuildCustomShader(std::string source, std::string entry, + void BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); void FreeCustomShader(ResourceId id); diff --git a/renderdoc/driver/gl/wrappers/gl_emulated.cpp b/renderdoc/driver/gl/wrappers/gl_emulated.cpp index a08e65df5..a1dfcef4b 100644 --- a/renderdoc/driver/gl/wrappers/gl_emulated.cpp +++ b/renderdoc/driver/gl/wrappers/gl_emulated.cpp @@ -3478,7 +3478,11 @@ void MakeOnlineShaderReflection(ShaderStage stage, const std::string &source, ResourceId id; std::string errors; - driver->BuildCustomShader(source, "main", ShaderCompileFlags(), stage, &id, &errors); + bytebuf buf; + buf.resize(source.size()); + memcpy(buf.data(), source.data(), source.size()); + driver->BuildCustomShader(ShaderEncoding::GLSL, buf, "main", ShaderCompileFlags(), stage, &id, + &errors); if(id == ResourceId()) { diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 3ea673974..ffe376928 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -1690,6 +1690,7 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo VulkanShaderCache *shaderCache = driver->GetShaderCache(); + CREATE_OBJECT(PointSampler, VK_FILTER_NEAREST); CREATE_OBJECT(LinearSampler, VK_FILTER_LINEAR); CREATE_OBJECT(DescSetLayout, @@ -1711,6 +1712,8 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo {18, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL}, {19, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL}, {20, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL}, + {50, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &PointSampler}, + {51, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &LinearSampler}, }); CREATE_OBJECT(PipeLayout, DescSetLayout, 0); @@ -2003,6 +2006,7 @@ void VulkanReplay::TextureRendering::Destroy(WrappedVulkan *driver) UBO.Destroy(); HeatmapUBO.Destroy(); + driver->vkDestroySampler(driver->GetDev(), PointSampler, NULL); driver->vkDestroySampler(driver->GetDev(), LinearSampler, NULL); for(size_t i = 0; i < ARRAY_COUNT(DummyImages); i++) diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index e4ff774a5..bf05519f4 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -3434,54 +3434,11 @@ void VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi } } -void VulkanReplay::BuildCustomShader(std::string source, std::string entry, - const ShaderCompileFlags &compileFlags, ShaderStage type, - ResourceId *id, std::string *errors) +void VulkanReplay::BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, + const std::string &entry, const ShaderCompileFlags &compileFlags, + ShaderStage type, ResourceId *id, std::string *errors) { - SPIRVShaderStage stage = SPIRVShaderStage::Invalid; - - switch(type) - { - case ShaderStage::Vertex: stage = SPIRVShaderStage::Vertex; break; - case ShaderStage::Hull: stage = SPIRVShaderStage::TessControl; break; - case ShaderStage::Domain: stage = SPIRVShaderStage::TessEvaluation; break; - case ShaderStage::Geometry: stage = SPIRVShaderStage::Geometry; break; - case ShaderStage::Pixel: stage = SPIRVShaderStage::Fragment; break; - case ShaderStage::Compute: stage = SPIRVShaderStage::Compute; break; - default: - RDCERR("Unexpected type in BuildShader!"); - *id = ResourceId(); - return; - } - - std::vector sources; - sources.push_back(source); - std::vector spirv; - - SPIRVCompilationSettings settings(SPIRVSourceLanguage::VulkanGLSL, stage); - - std::string output = CompileSPIRV(settings, sources, spirv); - - if(spirv.empty()) - { - *id = ResourceId(); - *errors = output; - return; - } - - VkShaderModuleCreateInfo modinfo = { - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - NULL, - 0, - spirv.size() * sizeof(uint32_t), - &spirv[0], - }; - - VkShaderModule module; - VkResult vkr = m_pDriver->vkCreateShaderModule(m_pDriver->GetDev(), &modinfo, NULL, &module); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - *id = GetResID(module); + BuildTargetShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } void VulkanReplay::FreeCustomShader(ResourceId id) @@ -3549,7 +3506,7 @@ ResourceId VulkanReplay::ApplyCustomShader(ResourceId shader, ResourceId texid, } void VulkanReplay::BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, - std::string entry, const ShaderCompileFlags &compileFlags, + const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors) { std::vector spirv; diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 1730aedcd..a0fbbac35 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -320,10 +320,10 @@ public: { return {ShaderEncoding::SPIRV, ShaderEncoding::GLSL}; } - void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, + void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); - void BuildCustomShader(std::string source, std::string entry, + void BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, const std::string &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId *id, std::string *errors); void FreeCustomShader(ResourceId id); @@ -523,6 +523,7 @@ private: VkDescriptorSet DescSet[16] = {VK_NULL_HANDLE}; uint32_t NextSet = 0; + VkSampler PointSampler = VK_NULL_HANDLE; VkSampler LinearSampler = VK_NULL_HANDLE; // descriptors must be valid even if they're skipped dynamically in the shader, so we create diff --git a/renderdoc/replay/replay_controller.cpp b/renderdoc/replay/replay_controller.cpp index ed5bcb63a..1d5eeb060 100644 --- a/renderdoc/replay/replay_controller.cpp +++ b/renderdoc/replay/replay_controller.cpp @@ -1958,7 +1958,8 @@ rdcpair ReplayController::BuildTargetShader( } rdcpair ReplayController::BuildCustomShader( - const char *entry, const char *source, const ShaderCompileFlags &compileFlags, ShaderStage type) + const char *entry, ShaderEncoding sourceEncoding, bytebuf source, + const ShaderCompileFlags &compileFlags, ShaderStage type) { CHECK_REPLAY_THREAD(); @@ -1976,10 +1977,19 @@ rdcpair ReplayController::BuildCustomShader( default: RDCERR("Unexpected type in BuildShader!"); return rdcpair(); } - m_pDevice->BuildCustomShader(source, entry, compileFlags, type, &id, &errs); + RDCLOG("Building custom shader"); + + m_pDevice->BuildCustomShader(sourceEncoding, source, entry, compileFlags, type, &id, &errs); if(id != ResourceId()) + { + RDCLOG("Successfully built custom shader"); m_CustomShaders.insert(id); + } + else + { + RDCLOG("Failed to build custom shader"); + } return rdcpair(id, errs); } diff --git a/renderdoc/replay/replay_controller.h b/renderdoc/replay/replay_controller.h index a2d4ec94a..9e0acdcf5 100644 --- a/renderdoc/replay/replay_controller.h +++ b/renderdoc/replay/replay_controller.h @@ -153,7 +153,8 @@ public: rdcarray GetDisassemblyTargets(); rdcstr DisassembleShader(ResourceId pipeline, const ShaderReflection *refl, const char *target); - rdcpair BuildCustomShader(const char *entry, const char *source, + rdcpair BuildCustomShader(const char *entry, ShaderEncoding sourceEncoding, + bytebuf source, const ShaderCompileFlags &compileFlags, ShaderStage type); void FreeCustomShader(ResourceId id); diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index e2868c9e9..d56a9393a 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -137,9 +137,9 @@ public: virtual void GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, const GetTextureDataParams ¶ms, bytebuf &data) = 0; - virtual void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, std::string entry, - const ShaderCompileFlags &compileFlags, ShaderStage type, - ResourceId *id, std::string *errors) = 0; + virtual void BuildTargetShader(ShaderEncoding sourceEncoding, bytebuf source, + const std::string &entry, const ShaderCompileFlags &compileFlags, + ShaderStage type, ResourceId *id, std::string *errors) = 0; virtual rdcarray GetTargetShaderEncodings() = 0; virtual void ReplaceResource(ResourceId from, ResourceId to) = 0; virtual void RemoveReplacement(ResourceId id) = 0; @@ -214,9 +214,9 @@ public: const MeshDisplay &cfg) = 0; virtual bool RenderTexture(TextureDisplay cfg) = 0; - virtual void BuildCustomShader(std::string source, std::string entry, - const ShaderCompileFlags &compileFlags, ShaderStage type, - ResourceId *id, std::string *errors) = 0; + virtual void BuildCustomShader(ShaderEncoding sourceEncoding, bytebuf source, + const std::string &entry, const ShaderCompileFlags &compileFlags, + ShaderStage type, ResourceId *id, std::string *errors) = 0; virtual rdcarray GetCustomShaderEncodings() = 0; virtual ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, uint32_t arrayIdx, uint32_t sampleIdx, CompType typeHint) = 0;