From 3ac4bd0ebd4b64fbef67553e11fe89e127fef79f Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 31 Jan 2022 19:14:08 +0000 Subject: [PATCH] Refactor custom shaders to abstract binding differences. Closes #2458 * Newly written shaders and any updated shaders can now use pre-defined macros to abstract away binding differences between APIs, so custom shaders will be more portable in particular shaders written in HLSL for D3D or GLSL on OpenGL won't break on vulkan because they refer to incorrect binds. --- docs/how/how_custom_visualisation.rst | 337 +++++----- qrenderdoc/Code/CaptureContext.cpp | 1 + qrenderdoc/Code/CaptureContext.h | 2 + qrenderdoc/Code/Interface/QRDInterface.h | 9 + qrenderdoc/Code/pyrenderdoc/renderdoc.i | 1 + qrenderdoc/Windows/PythonShell.cpp | 4 + qrenderdoc/Windows/ShaderViewer.cpp | 600 ++++++------------ qrenderdoc/Windows/ShaderViewer.h | 7 +- qrenderdoc/Windows/TextureViewer.cpp | 13 +- renderdoc/api/replay/renderdoc_replay.h | 22 + renderdoc/api/replay/shader_types.h | 29 + renderdoc/core/image_viewer.cpp | 4 + renderdoc/core/replay_proxy.h | 8 + renderdoc/data/glsl/glsl_ubos_cpp.h | 460 ++++++++++++++ renderdoc/data/glsl_shaders.cpp | 85 +++ renderdoc/data/glsl_shaders.h | 2 + renderdoc/data/hlsl/hlsl_cbuffers.h | 19 + renderdoc/data/hlsl/hlsl_custom_prefix.h | 153 +++++ .../driver/d3d11/d3d11_rendertexture.cpp | 46 +- renderdoc/driver/d3d11/d3d11_replay.cpp | 7 + renderdoc/driver/d3d11/d3d11_replay.h | 1 + .../driver/d3d12/d3d12_rendertexture.cpp | 46 +- renderdoc/driver/d3d12/d3d12_replay.cpp | 7 + renderdoc/driver/d3d12/d3d12_replay.h | 1 + renderdoc/driver/gl/gl_rendertexture.cpp | 25 + renderdoc/driver/gl/gl_replay.cpp | 12 + renderdoc/driver/gl/gl_replay.h | 8 + renderdoc/driver/vulkan/vk_rendertexture.cpp | 34 +- renderdoc/driver/vulkan/vk_replay.cpp | 28 +- renderdoc/driver/vulkan/vk_replay.h | 1 + renderdoc/renderdoc.vcxproj | 1 + renderdoc/renderdoc.vcxproj.filters | 3 + renderdoc/replay/dummy_driver.cpp | 8 +- renderdoc/replay/dummy_driver.h | 2 + renderdoc/replay/replay_controller.cpp | 7 + renderdoc/replay/replay_controller.h | 1 + renderdoc/replay/replay_driver.h | 1 + 37 files changed, 1382 insertions(+), 613 deletions(-) create mode 100644 renderdoc/data/hlsl/hlsl_custom_prefix.h diff --git a/docs/how/how_custom_visualisation.rst b/docs/how/how_custom_visualisation.rst index 1d327ea8a..45feed545 100644 --- a/docs/how/how_custom_visualisation.rst +++ b/docs/how/how_custom_visualisation.rst @@ -8,9 +8,9 @@ Introduction 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. +For example on D3D11 or D3D12, hlsl is the only language usable by default. On OpenGL only glsl can be used, but on Vulkan you can use glsl or use hlsl 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. +There are several special global helpers that can be declared and used, which will be implemented and return values by RenderDoc. In addition there are automatic macros that can be used to bind resources and still write shaders which work on different APIs with different bindings. Your pixel shader defines an operation that transforms the raw value from the input texture into a value that will then be displayed by the texture viewer. The usual texture viewer controls for range adaption and channels will still be available on the resulting texture. @@ -18,7 +18,11 @@ To set up your shader, it's recommended that you use the UI defined in the docum .. note:: - Since ``.glsl`` is used for both Vulkan and OpenGL shaders, you can differentiate by the pre-defined macro ``VULKAN`` if you are writing a shader to be used for both. + Since ``.glsl`` is used for both Vulkan and OpenGL shaders, you can differentiate by the pre-defined macro ``VULKAN`` if you are writing a shader to be used for both. + +.. warning:: + + Previously the custom shaders allowed more direct binding without helper functions or binding macros. These shaders will continue to work as backwards compatibility is maintained, however be aware that these bindings are API specific and so e.g. a shader written for OpenGL in glsl will not work on Vulkan unless care has been taken, or an HLSL shader between Vulkan and D3D. If portability is desired please update and use the new helpers and binding macros, or else be careful only to use custom shaders with the API they were written for. Predefined inputs ----------------- @@ -27,7 +31,7 @@ There are several pre-defined inputs that can either be taken as parameters to t .. warning:: - Type and capitalisation is important for these variables, so ensure you use the right declaration! + Type and capitalisation is important for these variables, so ensure you use the right declaration! The shader editor when using the UI can be used to insert these snippets for you, with the right type and spelling. For GLSL these snippets are inserted at the top of the file just after any ``#version`` statement. @@ -37,19 +41,19 @@ UV co-ordinates .. highlight:: c++ .. code:: c++ - /* HLSL */ - float4 main(float4 pos : SV_Position, float4 uv : TEXCOORD0) : SV_Target0 - { - return 1; - } + /* HLSL */ + float4 main(float4 pos : SV_Position, float4 uv : TEXCOORD0) : SV_Target0 + { + return 1; + } - /* GLSL */ - layout (location = 0) in vec2 uv; + /* GLSL */ + layout (location = 0) in vec2 uv; - void main() - { - // ... - } + void main() + { + // ... + } This input is defined in HLSL as a second parameter to the shader entry point. The first defines the usual ``SV_Position`` system semantic, and the first two components of the second ``TEXCOORD0`` parameter gives UV co-ordinates from 0 to 1 in each dimension over the size of the texture (or texture slice). @@ -59,31 +63,12 @@ You can also use the auto-generated system co-ordinates - ``SV_Position`` or ``g .. note:: - You must bind these parameters like this in this order to ensure the linkage with the vertex shader matches. + You must bind these parameters like this in this order to ensure the linkage with the vertex shader matches. Constant Parameters ~~~~~~~~~~~~~~~~~~~ -There are several constant parameters available, each detailed below with the values they contain. Where possible these are bound by name as globals for convenience, but in Vulkan all variables must be contained within a single uniform buffer. The parameters correspond with the GLSL documentation but are contained within a uniform buffer at binding 0, with a structure given as so: - - -.. highlight:: c++ -.. code:: c++ - - layout(binding = 0, std140) uniform RENDERDOC_Uniforms - { - uvec4 TexDim; - uint SelectedMip; - uint TextureType; - uint SelectedSliceFace; - int SelectedSample; - uvec4 YUVDownsampleRate; - uvec4 YUVAChannels; - float SelectedRangeMin; - float SelectedRangeMax; - } RENDERDOC; - -In this way you can access the properties as ``RENDERDOC.TexDim`` instead of ``RENDERDOC_TexDim``. +There are several constant parameters available, each available via a helper function. They are detailed below with the values they contain. Texture dimensions ~~~~~~~~~~~~~~~~~~ @@ -91,14 +76,16 @@ Texture dimensions .. highlight:: c++ .. code:: c++ - uint4 RENDERDOC_TexDim; // hlsl - uniform uvec4 RENDERDOC_TexDim; // glsl + uint4 RD_TexDim(); // hlsl + uvec4 RD_TexDim(); // glsl - uint4 RENDERDOC_YUVDownsampleRate; // hlsl / vulkan glsl only - uint4 RENDERDOC_YUVAChannels; // hlsl / vulkan glsl only + uint4 RD_YUVDownsampleRate(); // hlsl + uvec4 RD_YUVDownsampleRate(); // vulkan glsl only + uint4 RD_YUVAChannels(); // hlsl + uvec4 RD_YUVAChannels(); // vulkan glsl only -``RENDERDOC_TexDim`` will be filled out with the following values: +``RD_TexDim`` will return the following values: * ``.x`` Width * ``.y`` Height (if 2D or 3D) @@ -106,7 +93,7 @@ Texture dimensions * ``.w`` Number of mip levels -``RENDERDOC_YUVDownsampleRate`` will be filled out with the following values: +``RD_YUVDownsampleRate`` will return the following values: * ``.x`` Horizontal downsample rate. 1 for equal luma and chroma width, 2 for half rate. * ``.y`` Vertical downsample rate. 1 for equal luma and chroma height, 2 for half rate. @@ -114,7 +101,7 @@ Texture dimensions * ``.w`` Number of bits per component, e.g. 8, 10 or 16. -``RENDERDOC_YUVAChannels`` will be filled out an index indicating where each channel comes from in the source textures. The order is ``.x`` for ``Y``, ``.y`` for ``U``, ``.z`` for ``V`` and ``.w`` for ``A``. +``RD_YUVAChannels`` will return an index indicating where each channel comes from in the source textures. The order is ``.x`` for ``Y``, ``.y`` for ``U``, ``.z`` for ``V`` and ``.w`` for ``A``. The indices for channels in the first texture in the normal 2D slot are ``0, 1, 2, 3``. Indices from ``4`` to ``7`` indicate channels in the second texture, and so on. @@ -126,11 +113,10 @@ Selected Mip level .. highlight:: c++ .. code:: c++ - uint RENDERDOC_SelectedMip; // hlsl - uniform uint RENDERDOC_SelectedMip; // glsl + uint RD_SelectedMip(); // hlsl or glsl -This variable will be filled out with the selected mip level in the UI. +This will return the selected mip level in the UI. Selected Slice/Face ~~~~~~~~~~~~~~~~~~~ @@ -138,8 +124,7 @@ Selected Slice/Face .. highlight:: c++ .. code:: c++ - uint RENDERDOC_SelectedSliceFace; // hlsl - uniform uint RENDERDOC_SelectedSliceFace; // glsl + uint RD_SelectedSliceFace(); // hlsl or glsl This variable will be filled out with the selected texture array slice (or cubemap face) in the UI. @@ -150,8 +135,7 @@ Selected Multisample sample .. highlight:: c++ .. code:: c++ - int RENDERDOC_SelectedSample; // hlsl - uniform int RENDERDOC_SelectedSample; // glsl + int RD_SelectedSample(); // hlsl or glsl This variable will be filled out with the selected multisample sample index as chosen in the UI. If the UI has 'average value' selected, this variable will be negative and with an absolute value equal to the number of samples. @@ -165,14 +149,11 @@ Selected RangeMin, RangeMax .. highlight:: c++ .. code:: c++ - float RENDERDOC_SelectedRangeMin; // hlsl - float RENDERDOC_SelectedRangeMax; // hlsl - - uniform int RENDERDOC_SelectedRangeMin; // glsl - uniform int RENDERDOC_SelectedRangeMax; // glsl + float2 RD_SelectedRange(); // hlsl + vec2 RD_SelectedRange(); // glsl -These variables will be filled out with the current Minimum and Maximum values for the Range-selector in the Texture Viewer. +This function will return a pair, with the current Minimum and Maximum values for the Range-selector in the Texture Viewer. Current texture type @@ -181,166 +162,170 @@ Current texture type .. highlight:: c++ .. code:: c++ - uint RENDERDOC_TextureType; // hlsl - uniform uint RENDERDOC_TextureType; // glsl + uint RD_TextureType(); // hlsl or glsl This variable will be set to a given integer value, depending on the type of the current texture being displayed. This can be used to sample from the correct resource. .. note:: - The value varies depending on the API this shader will be used for, as each has different resource bindings. + The value varies depending on the API this shader will be used for, as each has different resource bindings. You should use the defines below to check, which will be portable across APIs -D3D11 or D3D12 / HLSL -^^^^^^^^^^^^^^^^^^^^^ +D3D11 or D3D12 +^^^^^^^^^^^^^^ -#. 1D texture -#. 2D texture -#. 3D texture -#. Depth -#. Depth + Stencil -#. Depth (Multisampled) -#. Depth + Stencil (Multisampled) -#. Legacy: used to be cubemap, removed as it's unused -#. 2D texture (Multisampled) +* ``RD_TextureType_1D`` - 1D texture +* ``RD_TextureType_2D`` - 2D texture +* ``RD_TextureType_3D`` - 3D texture +* ``RD_TextureType_Depth`` - Depth +* ``RD_TextureType_DepthStencil`` - Depth + Stencil +* ``RD_TextureType_DepthMS`` - Depth (Multisampled) +* ``RD_TextureType_DepthStencilMS`` - Depth + Stencil (Multisampled) +* ``RD_TextureType_2DMS`` - 2D texture (Multisampled) -OpenGL / GLSL -^^^^^^^^^^^^^ +In all cases on D3D the bindings can be used for arrays or not, interchangeably. -#. 1D texture -#. 2D texture -#. 3D texture -#. Cubemap -#. 1D array texture -#. 2D array texture -#. Cubemap array -#. Rectangle -#. Buffer texture -#. 2D texture (Multisampled) +OpenGL +^^^^^^ -Vulkan / GLSL -^^^^^^^^^^^^^ +* ``RD_TextureType_1D`` - 1D texture +* ``RD_TextureType_2D`` - 2D texture +* ``RD_TextureType_3D`` - 3D texture +* ``RD_TextureType_Cube`` - Cubemap +* ``RD_TextureType_1D_Array`` - 1D array texture +* ``RD_TextureType_2D_Array`` - 2D array texture +* ``RD_TextureType_Cube_Array`` - Cube array texture +* ``RD_TextureType_Rect`` - Rectangle texture +* ``RD_TextureType_Buffer`` - Buffer texture +* ``RD_TextureType_2DMS`` - 2D texture (Multisampled) +* ``RD_TextureType_2DMS_Array`` - 2D array texture (Multisampled) -#. 1D texture -#. 2D texture -#. 3D texture -#. 2D texture (Multisampled) +OpenGL has separate types and bindings for arrayed and non-arrayed textures. -Samplers (D3D11/D3D12 only) -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Vulkan +^^^^^^ + +* ``RD_TextureType_1D`` - 1D texture +* ``RD_TextureType_2D`` - 2D texture +* ``RD_TextureType_3D`` - 3D texture +* ``RD_TextureType_2DMS`` - 2D texture (Multisampled) + +In all cases on Vulkan the bindings can be used for arrays or not, interchangeably. + +Samplers +~~~~~~~~ .. highlight:: c++ .. code:: c++ - SamplerState pointSampler : register(s0); - SamplerState linearSampler : register(s1); -These samplers are provided to allow you to sample from the resource as opposed to doing straight loads. They are bound by slot and not by variable name - so this means you can name them as you wish but you must specify the register binding explicitly. + /* HLSL */ + SamplerState pointSampler : register(RD_POINT_SAMPLER_BINDING); + SamplerState linearSampler : register(RD_LINEAR_SAMPLER_BINDING); + + + /* GLSL */ + #ifdef VULKAN + + layout(binding = RD_POINT_SAMPLER_BINDING) uniform sampler pointSampler; + layout(binding = RD_LINEAR_SAMPLER_BINDING) uniform sampler linearSampler; + + #endif + +These samplers are provided to allow you to sample from the resource as opposed to doing straight loads. Samplers are not available on OpenGL, so it is recommended to protect the glsl definitions with ``#ifdef VULKAN`` as shown. Resources ~~~~~~~~~ -D3D11 or D3D12 / HLSL -^^^^^^^^^^^^^^^^^^^^^ +HLSL +^^^^ .. highlight:: c++ .. code:: c++ - 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); + // Float Textures + Texture1DArray texDisplayTex1DArray : register(RD_FLOAT_1D_ARRAY_BINDING); + Texture2DArray texDisplayTex2DArray : register(RD_FLOAT_2D_ARRAY_BINDING); + Texture3D texDisplayTex3D : register(RD_FLOAT_3D_BINDING); + Texture2DMSArray texDisplayTex2DMSArray : register(RD_FLOAT_2DMS_ARRAY_BINDING); + Texture2DArray texDisplayYUVArray : register(RD_FLOAT_YUV_ARRAY_BINDING); - Texture1DArray texDisplayUIntTex1DArray : register(t11); - Texture2DArray texDisplayUIntTex2DArray : register(t12); - Texture3D texDisplayUIntTex3D : register(t13); - Texture2DMSArray texDisplayUIntTex2DMSArray : register(t19); + // only used on D3D + Texture2DArray texDisplayTexDepthArray : register(RD_FLOAT_DEPTH_ARRAY_BINDING); + Texture2DArray texDisplayTexStencilArray : register(RD_FLOAT_STENCIL_ARRAY_BINDING); + Texture2DMSArray texDisplayTexDepthMSArray : register(RD_FLOAT_DEPTHMS_ARRAY_BINDING); + Texture2DMSArray texDisplayTexStencilMSArray : register(RD_FLOAT_STENCILMS_ARRAY_BINDING); - Texture1DArray texDisplayIntTex1DArray : register(t21); - Texture2DArray texDisplayIntTex2DArray : register(t22); - Texture3D texDisplayIntTex3D : register(t23); - Texture2DMSArray texDisplayIntTex2DMSArray : register(t29); + // Int Textures + Texture1DArray texDisplayIntTex1DArray : register(RD_INT_1D_ARRAY_BINDING); + Texture2DArray texDisplayIntTex2DArray : register(RD_INT_2D_ARRAY_BINDING); + Texture3D texDisplayIntTex3D : register(RD_INT_3D_BINDING); + Texture2DMSArray texDisplayIntTex2DMSArray : register(RD_INT_2DMS_ARRAY_BINDING); -OpenGL / GLSL -^^^^^^^^^^^^^ + // Unsigned int Textures + Texture1DArray texDisplayUIntTex1DArray : register(RD_UINT_1D_ARRAY_BINDING); + Texture2DArray texDisplayUIntTex2DArray : register(RD_UINT_2D_ARRAY_BINDING); + Texture3D texDisplayUIntTex3D : register(RD_UINT_3D_BINDING); + Texture2DMSArray texDisplayUIntTex2DMSArray : register(RD_UINT_2DMS_ARRAY_BINDING); + +GLSL +^^^^ .. highlight:: c++ .. code:: c++ - // Unsigned int samplers - layout (binding = 1) uniform usampler1D texUInt1D; - layout (binding = 2) uniform usampler2D texUInt2D; - layout (binding = 3) uniform usampler3D texUInt3D; - // skip cube = 4 - layout (binding = 5) uniform usampler1DArray texUInt1DArray; - layout (binding = 6) uniform usampler2DArray texUInt2DArray; - // skip cube array = 7 - layout (binding = 8) uniform usampler2DRect texUInt2DRect; - layout (binding = 9) uniform usamplerBuffer texUIntBuffer; - layout (binding = 10) uniform usampler2DMS texUInt2DMS; + // Float Textures + layout (binding = RD_FLOAT_1D_ARRAY_BINDING) uniform sampler1DArray tex1DArray; + layout (binding = RD_FLOAT_2D_ARRAY_BINDING) uniform sampler2DArray tex2DArray; + layout (binding = RD_FLOAT_3D_BINDING) uniform sampler3D tex3D; + layout (binding = RD_FLOAT_2DMS_ARRAY_BINDING) uniform sampler2DMSArray tex2DMSArray; - // Int samplers - layout (binding = 1) uniform isampler1D texSInt1D; - layout (binding = 2) uniform isampler2D texSInt2D; - layout (binding = 3) uniform isampler3D texSInt3D; - // skip cube = 4 - layout (binding = 5) uniform isampler1DArray texSInt1DArray; - layout (binding = 6) uniform isampler2DArray texSInt2DArray; - // skip cube array = 7 - layout (binding = 8) uniform isampler2DRect texSInt2DRect; - layout (binding = 9) uniform isamplerBuffer texSIntBuffer; - layout (binding = 10) uniform isampler2DMS texSInt2DMS; + // YUV textures only supported on vulkan + #ifdef VULKAN + layout(binding = RD_FLOAT_YUV_ARRAY_BINDING) uniform sampler2DArray texYUVArray[2]; + #endif - // 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; + // OpenGL has more texture types to match + #ifndef VULKAN + layout (binding = RD_FLOAT_1D_BINDING) uniform sampler1D tex1D; + layout (binding = RD_FLOAT_2D_BINDING) uniform sampler2D tex2D; + layout (binding = RD_FLOAT_CUBE_BINDING) uniform samplerCube texCube; + layout (binding = RD_FLOAT_CUBE_ARRAY_BINDING) uniform samplerCubeArray texCubeArray; + layout (binding = RD_FLOAT_RECT_BINDING) uniform sampler2DRect tex2DRect; + layout (binding = RD_FLOAT_BUFFER_BINDING) uniform samplerBuffer texBuffer; + layout (binding = RD_FLOAT_2DMS_BINDING) uniform sampler2DMS tex2DMS; + #endif -Vulkan / GLSL -^^^^^^^^^^^^^ + // Int Textures + layout (binding = RD_INT_1D_ARRAY_BINDING) uniform isampler1DArray texSInt1DArray; + layout (binding = RD_INT_2D_ARRAY_BINDING) uniform isampler2DArray texSInt2DArray; + layout (binding = RD_INT_3D_BINDING) uniform isampler3D texSInt3D; + layout (binding = RD_INT_2DMS_ARRAY_BINDING) uniform isampler2DMSArray texSInt2DMSArray; -.. highlight:: c++ -.. code:: c++ + #ifndef VULKAN + layout (binding = RD_INT_1D_BINDING) uniform isampler1D texSInt1D; + layout (binding = RD_INT_2D_BINDING) uniform isampler2D texSInt2D; + layout (binding = RD_INT_RECT_BINDING) uniform isampler2DRect texSInt2DRect; + layout (binding = RD_INT_BUFFER_BINDING) uniform isamplerBuffer texSIntBuffer; + layout (binding = RD_INT_2DMS_BINDING) uniform isampler2DMS texSInt2DMS; + #endif - // Floating point samplers + // Unsigned int Textures + layout (binding = RD_UINT_1D_ARRAY_BINDING) uniform usampler1DArray texSInt1DArray; + layout (binding = RD_UINT_2D_ARRAY_BINDING) uniform usampler2DArray texSInt2DArray; + layout (binding = RD_UINT_3D_BINDING) uniform usampler3D texSInt3D; + layout (binding = RD_UINT_2DMS_ARRAY_BINDING) uniform usampler2DMSArray texSInt2DMSArray; - // binding = 5 + RENDERDOC_TextureType - 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 texYUV; - - // Unsigned int samplers - - // binding = 10 + RENDERDOC_TextureType - 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 - - // binding = 15 + RENDERDOC_TextureType - layout(binding = 16) uniform isampler1DArray texSInt1DArray; - layout(binding = 17) uniform isampler2DArray texSInt2DArray; - layout(binding = 18) uniform isampler3D texSInt3D; - layout(binding = 19) uniform isampler2DMS texSInt2DMS; + #ifndef VULKAN + layout (binding = RD_UINT_1D_BINDING) uniform usampler1D texSInt1D; + layout (binding = RD_UINT_2D_BINDING) uniform usampler2D texSInt2D; + layout (binding = RD_UINT_RECT_BINDING) uniform usampler2DRect texSInt2DRect; + layout (binding = RD_UINT_BUFFER_BINDING) uniform usamplerBuffer texSIntBuffer; + layout (binding = RD_UINT_2DMS_BINDING) uniform usampler2DMS texSInt2DMS; + #endif -These resources are bound sparsely with the appropriate type for the current texture. With a couple of exceptions there will only be one texture bound at any one time. +These resources are bound sparsely with the appropriate type for the current texture. With a couple of exceptions there will only be one texture bound at any one time. Different APIs have different texture type matching requirements, so e.g. OpenGL has separate bindings for array and non-array texures, which will be reflected in the different ``RD_TextureType`` return values. When a cubemap texture is bound, it is bound both to the 2D Array as well as the Cube Array. If a depth-stencil texture has both components, the relevant depth and stencil resources will both be bound at once. @@ -351,7 +336,7 @@ Usually the float textures are used, but for unsigned and signed integer formats As with the samplers, these textures are bound by slot and not by name, so while you are free to name the variables as you wish, you must bind them explicitly to the slots listed here. .. note:: - YUV textures may have additional planes bound as separate textures - for D3D this is ``texDisplayYUVArray`` and for Vulkan it's ``texYUV`` above. Whether to use these planes or not is specified in the texture dimension variables. + YUV textures may have additional planes bound as separate textures - for D3D this is ``texDisplayYUVArray`` and for Vulkan it's ``texYUVArray`` above. Whether to use these planes or not is specified in the texture dimension variables. See Also -------- diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index fb5a99316..1958ccfee 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -981,6 +981,7 @@ void CaptureContext::LoadCaptureThreaded(const QString &captureFile, const Repla m_APIProps = r->GetAPIProperties(); m_CustomEncodings = r->GetCustomShaderEncodings(); + m_CustomPrefixes = r->GetCustomShaderSourcePrefixes(); m_TargetEncodings = r->GetTargetShaderEncodings(); m_PostloadProgress = 0.2f; diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index 349bf5017..d3831e028 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -155,6 +155,7 @@ public: const FrameDescription &FrameInfo() override { return m_FrameInfo; } const APIProperties &APIProps() override { return m_APIProps; } rdcarray CustomShaderEncodings() override { return m_CustomEncodings; } + rdcarray CustomShaderSourcePrefixes() override { return m_CustomPrefixes; } rdcarray TargetShaderEncodings() override { return m_TargetEncodings; } uint32_t CurSelectedEvent() override { return m_SelectedEventID; } uint32_t CurEvent() override { return m_EventID; } @@ -362,6 +363,7 @@ private: rdcarray m_EmptyActions; rdcarray m_CustomEncodings, m_TargetEncodings; + rdcarray m_CustomPrefixes; APIProperties m_APIProps; FrameDescription m_FrameInfo; const ActionDescription *m_FirstAction = NULL; diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index 6766feb90..11015c212 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -1945,6 +1945,15 @@ building custom shaders for the currently loaded capture. See )"); virtual rdcarray CustomShaderEncodings() = 0; + DOCUMENT(R"(Retrieve the list of prefixes for each :class:`~renderdoc.ShaderEncoding` that should +be added to custom compiled shaders. See +:meth:`~renderdoc.ReplayController.GetCustomShaderSourcePrefixes`. + +:return: A list of pairs, listing a prefix for each shader encoding referenced. +:rtype: List[Tuple[ShaderEncoding,str]] +)"); + virtual rdcarray CustomShaderSourcePrefixes() = 0; + DOCUMENT(R"(Retrieve the currently selected :data:`eventId `. In most cases, prefer using :meth:`CurEvent`. See :meth:`CaptureViewer.OnSelectedEventChanged` for more diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index 5d4077eb0..ac1a4c274 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -373,6 +373,7 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderMessage) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderResource) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderSampler) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderSourceFile) +TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderSourcePrefix) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderVariable) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderEncoding) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ShaderVariableChange) diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index 8c7b0eb51..89411e867 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -430,6 +430,10 @@ struct CaptureContextInvoker : ObjectForwarder { return m_Obj.CustomShaderEncodings(); } + virtual rdcarray CustomShaderSourcePrefixes() override + { + return m_Obj.CustomShaderSourcePrefixes(); + } virtual uint32_t CurSelectedEvent() override { return m_Obj.CurSelectedEvent(); } virtual uint32_t CurEvent() override { return m_Obj.CurEvent(); } virtual const ActionDescription *CurSelectedAction() override diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index 23e478208..1e71044a6 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -181,34 +181,17 @@ ShaderViewer::ShaderViewer(ICaptureContext &ctx, QWidget *parent) { QMenu *snippetsMenu = new QMenu(this); - QAction *dim = new QAction(tr("Texture Dimensions Global"), this); - QAction *mip = new QAction(tr("Selected Mip Global"), this); - QAction *slice = new QAction(tr("Selected Array Slice / Cubemap Face Global"), this); - QAction *sample = new QAction(tr("Selected Sample Global"), this); - QAction *range = new QAction(tr("Selected TextureViewer Range Global"), this); - QAction *type = new QAction(tr("Texture Type Global"), this); + QAction *constants = new QAction(tr("Per-texture constants"), this); QAction *samplers = new QAction(tr("Point && Linear Samplers"), this); QAction *resources = new QAction(tr("Texture Resources"), this); - snippetsMenu->addAction(dim); - snippetsMenu->addAction(mip); - snippetsMenu->addAction(slice); - snippetsMenu->addAction(sample); - snippetsMenu->addAction(range); - snippetsMenu->addAction(type); - snippetsMenu->addSeparator(); + snippetsMenu->addAction(constants); snippetsMenu->addAction(samplers); snippetsMenu->addAction(resources); - QObject::connect(dim, &QAction::triggered, this, &ShaderViewer::snippet_textureDimensions); - QObject::connect(mip, &QAction::triggered, this, &ShaderViewer::snippet_selectedMip); - QObject::connect(slice, &QAction::triggered, this, &ShaderViewer::snippet_selectedSlice); - QObject::connect(sample, &QAction::triggered, this, &ShaderViewer::snippet_selectedSample); - QObject::connect(range, &QAction::triggered, this, &ShaderViewer::snippet_selectedRange); - QObject::connect(type, &QAction::triggered, this, &ShaderViewer::snippet_selectedType); + QObject::connect(constants, &QAction::triggered, this, &ShaderViewer::snippet_constants); QObject::connect(samplers, &QAction::triggered, this, &ShaderViewer::snippet_samplers); QObject::connect(resources, &QAction::triggered, this, &ShaderViewer::snippet_resources); - QObject::connect(resources, &QAction::triggered, this, &ShaderViewer::snippet_resources); ui->snippets->setMenu(snippetsMenu); } @@ -282,7 +265,18 @@ void ShaderViewer::editShader(ResourceId id, ShaderStage stage, const QString &e ui->callstack->hide(); ui->sourceVars->hide(); - ui->snippets->setVisible(m_CustomShader); + if(m_CustomShader) + { + ui->snippets->show(); + ui->refresh->setText(tr("Refresh")); + ui->resetEdits->hide(); + ui->unrefresh->hide(); + ui->editStatusLabel->hide(); + } + else + { + ui->snippets->hide(); + } // hide debugging toolbar buttons ui->editSep->hide(); @@ -4351,270 +4345,105 @@ void ShaderViewer::insertSnippet(const QString &text) m_Scintillas[0]->setSelection(0, 0); } -QString ShaderViewer::vulkanUBO() +void ShaderViewer::snippet_constants() { ShaderEncoding encoding = currentEncoding(); + QString text; + if(encoding == ShaderEncoding::GLSL) { - return lit(R"( -layout(binding = 0, std140) uniform RENDERDOC_Uniforms -{ - uvec4 TexDim; - uint SelectedMip; - int TextureType; // 1 = 1D, 2 = 2D, 3 = 3D, 4 = 2DMS - uint SelectedSliceFace; - int SelectedSample; - uvec4 YUVDownsampleRate; - uvec4 YUVAChannels; - float SelectedRangeMin; - float SelectedRangeMax; -} RENDERDOC; + text = lit(R"( +// possible values (these are only return values from this function, NOT texture binding points): +// RD_TextureType_1D +// RD_TextureType_2D +// RD_TextureType_3D +// RD_TextureType_Cube (OpenGL only) +// RD_TextureType_1D_Array (OpenGL only) +// RD_TextureType_2D_Array (OpenGL only) +// RD_TextureType_Cube_Array (OpenGL only) +// RD_TextureType_Rect (OpenGL only) +// RD_TextureType_Buffer (OpenGL only) +// RD_TextureType_2DMS +// RD_TextureType_2DMS_Array (OpenGL only) +uint RD_TextureType(); -#define RENDERDOC_TexDim RENDERDOC.TexDim -#define RENDERDOC_SelectedMip RENDERDOC.SelectedMip -#define RENDERDOC_TextureType RENDERDOC.TextureType -#define RENDERDOC_SelectedSliceFace RENDERDOC.SelectedSliceFace -#define RENDERDOC_SelectedSample RENDERDOC.SelectedSample -#define RENDERDOC_YUVDownsampleRate RENDERDOC.YUVDownsampleRate -#define RENDERDOC_YUVAChannels RENDERDOC.YUVAChannels -#define RENDERDOC_SelectedRangeMin RENDERDOC.SelectedRangeMin -#define RENDERDOC_SelectedRangeMax RENDERDOC.SelectedRangeMax +// selected sample, or -numSamples for resolve +int RD_SelectedSample(); + +uint RD_SelectedSliceFace(); + +uint RD_SelectedMip(); + +// xyz = width, height, depth (or array size). w = # mips +uvec4 RD_TexDim(); + +// x = horizontal downsample rate (1 full rate, 2 half rate) +// y = vertical downsample rate +// z = number of planes in input texture +// w = number of bits per component (8, 10, 16) +uvec4 RD_YUVDownsampleRate(); + +// x = where Y channel comes from +// y = where U channel comes from +// z = where V channel comes from +// w = where A channel comes from +// each index will be [0,1,2,3] for xyzw in first plane, +// [4,5,6,7] for xyzw in second plane texture, etc. +// it will be 0xff = 255 if the channel does not exist. +uvec4 RD_YUVAChannels(); + +// a pair with minimum and maximum selected range values +vec2 RD_SelectedRange(); )"); } else if(encoding == ShaderEncoding::HLSL) - { - return lit(R"( -cbuffer RENDERDOC_Constants : register(b0) -{ - uint4 RENDERDOC_TexDim; - uint RENDERDOC_SelectedMip; - int RENDERDOC_TextureType; // 1 = 1D, 2 = 2D, 3 = 3D, 4 = 2DMS - uint RENDERDOC_SelectedSliceFace; - int RENDERDOC_SelectedSample; - uint4 RENDERDOC_YUVDownsampleRate; - uint4 RENDERDOC_YUVAChannels; - float RENDERDOC_SelectedRangeMin; - float RENDERDOC_SelectedRangeMax; -}; - -)"); - } - else if(encoding == ShaderEncoding::SPIRVAsm) - { - return lit("; Can't insert snippets for SPIR-V ASM"); - } - - return QString(); -} - -void ShaderViewer::snippet_textureDimensions() -{ - ShaderEncoding encoding = currentEncoding(); - GraphicsAPI api = m_Ctx.APIProps().localRenderer; - - QString text; - - if(api == GraphicsAPI::Vulkan) - { - text = vulkanUBO(); - } - else if(encoding == ShaderEncoding::HLSL) { text = lit(R"( -// xyz == width, height, depth. w == # mips -uint4 RENDERDOC_TexDim; -uint4 RENDERDOC_YUVDownsampleRate; -uint4 RENDERDOC_YUVAChannels; +///////////////////////////////////// +// Constants // +///////////////////////////////////// -)"); - } - else if(encoding == ShaderEncoding::GLSL) - { - text = lit(R"( -// xyz == width, height, depth. w == # mips -uniform uvec4 RENDERDOC_TexDim; +// possible values (these are only return values from this function, NOT texture binding points): +// RD_TextureType_1D +// RD_TextureType_2D +// RD_TextureType_3D +// RD_TextureType_Depth +// RD_TextureType_DepthStencil +// RD_TextureType_DepthMS +// RD_TextureType_DepthStencilMS +uint RD_TextureType(); -)"); - } - else if(encoding == ShaderEncoding::SPIRVAsm) - { - text = lit("; Can't insert snippets for SPIR-V ASM"); - } +// selected sample, or -numSamples for resolve +int RD_SelectedSample(); - insertSnippet(text); -} +uint RD_SelectedSliceFace(); -void ShaderViewer::snippet_selectedMip() -{ - ShaderEncoding encoding = currentEncoding(); - GraphicsAPI api = m_Ctx.APIProps().localRenderer; +uint RD_SelectedMip(); - QString text; +// xyz = width, height, depth. w = # mips +uint4 RD_TexDim(); - if(api == GraphicsAPI::Vulkan) - { - text = vulkanUBO(); - } - else if(encoding == ShaderEncoding::HLSL) - { - text = lit(R"( -// selected mip in UI -uint RENDERDOC_SelectedMip; +// x = horizontal downsample rate (1 full rate, 2 half rate) +// y = vertical downsample rate +// z = number of planes in input texture +// w = number of bits per component (8, 10, 16) +uint4 RD_YUVDownsampleRate(); -)"); - } - else if(encoding == ShaderEncoding::GLSL) - { - text = lit(R"( -// selected mip in UI -uniform uint RENDERDOC_SelectedMip; +// x = where Y channel comes from +// y = where U channel comes from +// z = where V channel comes from +// w = where A channel comes from +// each index will be [0,1,2,3] for xyzw in first plane, +// [4,5,6,7] for xyzw in second plane texture, etc. +// it will be 0xff = 255 if the channel does not exist. +uint4 RD_YUVAChannels(); -)"); - } - else if(encoding == ShaderEncoding::SPIRVAsm) - { - text = lit("; Can't insert snippets for SPIR-V ASM"); - } +// a pair with minimum and maximum selected range values +float2 RD_SelectedRange(); - insertSnippet(text); -} - -void ShaderViewer::snippet_selectedSlice() -{ - ShaderEncoding encoding = currentEncoding(); - GraphicsAPI api = m_Ctx.APIProps().localRenderer; - - QString text; - - if(api == GraphicsAPI::Vulkan) - { - text = vulkanUBO(); - } - else if(encoding == ShaderEncoding::HLSL) - { - text = lit(R"( -// selected array slice or cubemap face in UI -uint RENDERDOC_SelectedSliceFace; - -)"); - } - else if(encoding == ShaderEncoding::GLSL) - { - 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"); - } - - insertSnippet(text); -} - -void ShaderViewer::snippet_selectedSample() -{ - ShaderEncoding encoding = currentEncoding(); - GraphicsAPI api = m_Ctx.APIProps().localRenderer; - - QString text; - - if(api == GraphicsAPI::Vulkan) - { - text = vulkanUBO(); - } - else if(encoding == ShaderEncoding::HLSL) - { - text = lit(R"( -// selected MSAA sample or -numSamples for resolve. See docs -int RENDERDOC_SelectedSample; - -)"); - } - else if(encoding == ShaderEncoding::GLSL) - { - 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"); - } - - insertSnippet(text); -} - -void ShaderViewer::snippet_selectedRange() -{ - ShaderEncoding encoding = currentEncoding(); - GraphicsAPI api = m_Ctx.APIProps().localRenderer; - - QString text; - - if(api == GraphicsAPI::Vulkan) - { - text = vulkanUBO(); - } - else if(encoding == ShaderEncoding::HLSL) - { - text = lit(R"( -// selected range min/max in UI -float RENDERDOC_SelectedRangeMin; -float RENDERDOC_SelectedRangeMax; - -)"); - } - else if(encoding == ShaderEncoding::GLSL) - { - text = lit(R"( -// selected range minmax in UI -float RENDERDOC_SelectedRangeMin; -float RENDERDOC_SelectedRangeMax; - -)"); - } - else if(encoding == ShaderEncoding::SPIRVAsm) - { - text = lit("; Can't insert snippets for SPIR-V ASM"); - } - - insertSnippet(text); -} - -void ShaderViewer::snippet_selectedType() -{ - ShaderEncoding encoding = currentEncoding(); - GraphicsAPI api = m_Ctx.APIProps().localRenderer; - - QString text; - - if(api == GraphicsAPI::Vulkan) - { - text = vulkanUBO(); - } - else if(encoding == ShaderEncoding::HLSL) - { - text = lit(R"( -// 1 = 1D, 2 = 2D, 3 = 3D, 4 = Depth, 5 = Depth + Stencil -// 6 = Depth (MS), 7 = Depth + Stencil (MS), 9 = 2DMS -uint RENDERDOC_TextureType; - -)"); - } - else if(encoding == ShaderEncoding::GLSL) - { - text = lit(R"( -// 1 = 1D, 2 = 2D, 3 = 3D, 4 = Cube -// 5 = 1DArray, 6 = 2DArray, 7 = CubeArray -// 8 = Rect, 9 = Buffer, 10 = 2DMS, 11 = 2DMSArray -uniform uint RENDERDOC_TextureType; +///////////////////////////////////// )"); } @@ -4629,28 +4458,38 @@ uniform uint RENDERDOC_TextureType; void ShaderViewer::snippet_samplers() { ShaderEncoding encoding = currentEncoding(); - GraphicsAPI api = m_Ctx.APIProps().localRenderer; if(encoding == ShaderEncoding::HLSL) { - if(api == GraphicsAPI::Vulkan) - { - insertSnippet(lit(R"( -// Samplers -SamplerState pointSampler : register(s50); -SamplerState linearSampler : register(s51); -// End Samplers + insertSnippet(lit(R"( +///////////////////////////////////// +// Samplers // +///////////////////////////////////// + +SamplerState pointSampler : register(RD_POINT_SAMPLER_BINDING); +SamplerState linearSampler : register(RD_LINEAR_SAMPLER_BINDING); + +///////////////////////////////////// + )")); - } - else - { - insertSnippet(lit(R"( -// Samplers -SamplerState pointSampler : register(s0); -SamplerState linearSampler : register(s1); -// End Samplers + } + else + { + insertSnippet(lit(R"( + +///////////////////////////////////// +// Samplers // +///////////////////////////////////// + +#ifdef VULKAN + +layout(binding = RD_POINT_SAMPLER_BINDING) uniform sampler pointSampler; +layout(binding = RD_LINEAR_SAMPLER_BINDING) uniform sampler linearSampler; + +#endif + +///////////////////////////////////// )")); - } } } @@ -4661,132 +4500,97 @@ void ShaderViewer::snippet_resources() 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); + insertSnippet(lit(R"( +///////////////////////////////////// +// Resources // +///////////////////////////////////// -// Unsigned int -Texture1DArray texDisplayUIntTex1DArray : register(t11); -Texture2DArray texDisplayUIntTex2DArray : register(t12); -Texture3D texDisplayUIntTex3D : register(t13); -Texture2DMSArray texDisplayUIntTex2DMSArray : register(t14); +// Float Textures +Texture1DArray texDisplayTex1DArray : register(RD_FLOAT_1D_ARRAY_BINDING); +Texture2DArray texDisplayTex2DArray : register(RD_FLOAT_2D_ARRAY_BINDING); +Texture3D texDisplayTex3D : register(RD_FLOAT_3D_BINDING); +Texture2DMSArray texDisplayTex2DMSArray : register(RD_FLOAT_2DMS_ARRAY_BINDING); +Texture2DArray texDisplayYUVArray : register(RD_FLOAT_YUV_ARRAY_BINDING); + +// only used on D3D +Texture2DArray texDisplayTexDepthArray : register(RD_FLOAT_DEPTH_ARRAY_BINDING); +Texture2DArray texDisplayTexStencilArray : register(RD_FLOAT_STENCIL_ARRAY_BINDING); +Texture2DMSArray texDisplayTexDepthMSArray : register(RD_FLOAT_DEPTHMS_ARRAY_BINDING); +Texture2DMSArray texDisplayTexStencilMSArray : register(RD_FLOAT_STENCILMS_ARRAY_BINDING); + +// Int Textures +Texture1DArray texDisplayIntTex1DArray : register(RD_INT_1D_ARRAY_BINDING); +Texture2DArray texDisplayIntTex2DArray : register(RD_INT_2D_ARRAY_BINDING); +Texture3D texDisplayIntTex3D : register(RD_INT_3D_BINDING); +Texture2DMSArray texDisplayIntTex2DMSArray : register(RD_INT_2DMS_ARRAY_BINDING); + +// Unsigned int Textures +Texture1DArray texDisplayUIntTex1DArray : register(RD_UINT_1D_ARRAY_BINDING); +Texture2DArray texDisplayUIntTex2DArray : register(RD_UINT_2D_ARRAY_BINDING); +Texture3D texDisplayUIntTex3D : register(RD_UINT_3D_BINDING); +Texture2DMSArray texDisplayUIntTex2DMSArray : register(RD_UINT_2DMS_ARRAY_BINDING); + +///////////////////////////////////// -// Int -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 -Texture1DArray texDisplayUIntTex1DArray : register(t11); -Texture2DArray texDisplayUIntTex2DArray : register(t12); -Texture3D texDisplayUIntTex3D : register(t13); -Texture2DMSArray texDisplayUIntTex2DMSArray : register(t19); - -// Int -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]; + insertSnippet(lit(R"( +///////////////////////////////////// +// Resources // +///////////////////////////////////// -// 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; +// Float Textures +layout (binding = RD_FLOAT_1D_ARRAY_BINDING) uniform sampler1DArray tex1DArray; +layout (binding = RD_FLOAT_2D_ARRAY_BINDING) uniform sampler2DArray tex2DArray; +layout (binding = RD_FLOAT_3D_BINDING) uniform sampler3D tex3D; +layout (binding = RD_FLOAT_2DMS_ARRAY_BINDING) uniform sampler2DMSArray tex2DMSArray; -// 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 +// YUV textures only supported on vulkan +#ifdef VULKAN +layout(binding = RD_FLOAT_YUV_ARRAY_BINDING) uniform sampler2DArray texYUVArray[2]; +#endif + +// OpenGL has more texture types to match +#ifndef VULKAN +layout (binding = RD_FLOAT_1D_BINDING) uniform sampler1D tex1D; +layout (binding = RD_FLOAT_2D_BINDING) uniform sampler2D tex2D; +layout (binding = RD_FLOAT_CUBE_BINDING) uniform samplerCube texCube; +layout (binding = RD_FLOAT_CUBE_ARRAY_BINDING) uniform samplerCubeArray texCubeArray; +layout (binding = RD_FLOAT_RECT_BINDING) uniform sampler2DRect tex2DRect; +layout (binding = RD_FLOAT_BUFFER_BINDING) uniform samplerBuffer texBuffer; +layout (binding = RD_FLOAT_2DMS_BINDING) uniform sampler2DMS tex2DMS; +#endif + +// Int Textures +layout (binding = RD_INT_1D_ARRAY_BINDING) uniform isampler1DArray texSInt1DArray; +layout (binding = RD_INT_2D_ARRAY_BINDING) uniform isampler2DArray texSInt2DArray; +layout (binding = RD_INT_3D_BINDING) uniform isampler3D texSInt3D; +layout (binding = RD_INT_2DMS_ARRAY_BINDING) uniform isampler2DMSArray texSInt2DMSArray; + +#ifndef VULKAN +layout (binding = RD_INT_1D_BINDING) uniform isampler1D texSInt1D; +layout (binding = RD_INT_2D_BINDING) uniform isampler2D texSInt2D; +layout (binding = RD_INT_RECT_BINDING) uniform isampler2DRect texSInt2DRect; +layout (binding = RD_INT_BUFFER_BINDING) uniform isamplerBuffer texSIntBuffer; +layout (binding = RD_INT_2DMS_BINDING) uniform isampler2DMS texSInt2DMS; +#endif + +// Unsigned int Textures +layout (binding = RD_UINT_1D_ARRAY_BINDING) uniform usampler1DArray texSInt1DArray; +layout (binding = RD_UINT_2D_ARRAY_BINDING) uniform usampler2DArray texSInt2DArray; +layout (binding = RD_UINT_3D_BINDING) uniform usampler3D texSInt3D; +layout (binding = RD_UINT_2DMS_ARRAY_BINDING) uniform usampler2DMSArray texSInt2DMSArray; + +#ifndef VULKAN +layout (binding = RD_UINT_1D_BINDING) uniform usampler1D texSInt1D; +layout (binding = RD_UINT_2D_BINDING) uniform usampler2D texSInt2D; +layout (binding = RD_UINT_RECT_BINDING) uniform usampler2DRect texSInt2DRect; +layout (binding = RD_UINT_BUFFER_BINDING) uniform usamplerBuffer texSIntBuffer; +layout (binding = RD_UINT_2DMS_BINDING) uniform usampler2DMS texSInt2DMS; +#endif )")); - } - 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; -layout (binding = 11) uniform usampler2DMSArray texUInt2DMSArray; - -// 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; -layout (binding = 11) uniform isampler2DMSArray texSInt2DMSArray; - -// 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; -layout (binding = 11) uniform sampler2DMSArray tex2DMSArray; -// End Textures -)")); - } } } diff --git a/qrenderdoc/Windows/ShaderViewer.h b/qrenderdoc/Windows/ShaderViewer.h index ba74b738f..b8b8eea10 100644 --- a/qrenderdoc/Windows/ShaderViewer.h +++ b/qrenderdoc/Windows/ShaderViewer.h @@ -166,12 +166,7 @@ private slots: void performReplace(); void performReplaceAll(); - void snippet_textureDimensions(); - void snippet_selectedMip(); - void snippet_selectedSlice(); - void snippet_selectedSample(); - void snippet_selectedRange(); - void snippet_selectedType(); + void snippet_constants(); void snippet_samplers(); void snippet_resources(); diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 1871d3f51..93196c89b 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -4246,7 +4246,8 @@ void TextureViewer::reloadCustomShaders(const QString &filter) bytebuf shaderBytes(source.toUtf8()); - rdcarray supported = m_Ctx.TargetShaderEncodings(); + rdcarray supported = m_Ctx.CustomShaderEncodings(); + rdcarray prefixes = m_Ctx.CustomShaderSourcePrefixes(); rdcstr errors; @@ -4258,6 +4259,16 @@ void TextureViewer::reloadCustomShaders(const QString &filter) // pick the first tool that can convert to an accepted format if(tool.input == encoding && supported.contains(tool.output)) { + // apply any prefix needed + for(const ShaderSourcePrefix &prefix : prefixes) + { + if(prefix.encoding == encoding) + { + source = QString(prefix.prefix) + source; + break; + } + } + ShaderToolOutput out = tool.CompileShader(this, source, "main", ShaderStage::Pixel, ""); diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index 735197d70..17cd1c5e4 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -637,6 +637,28 @@ of the compile process or using alternate/updated tools. )"); virtual rdcarray GetCustomShaderEncodings() = 0; + DOCUMENT(R"(Retrieve a list of source prefixes that should be applied to custom shaders of each +:class:`ShaderEncoding` before custom compilation prior to calling :meth:`BuildCustomShader`. + +This list provides source code prefixes which should be applied to a given custom shader in a +:class:`ShaderEncoding` *if and only if* that shader is being compiled in a custom step to a +different encoding, prior to being passed to :meth:`BuildCustomShader`. This allows source +compatibility even when doing custom compilation. + +For example a shader written in :data:`ShaderEncoding.HLSL` may be custom compiled to +:data:`ShaderEncoding.SPIRV` before being passed to :meth:`BuildCustomShader`. In this case any +prefix for :data:`ShaderEncoding.HLSL` should be prepended to the source before custom compilation, +to allow for defines and other helpers to be made available, since otherwise the shader may not +compile. + +If a shader encoding is not in the list, no prefix is required. This may be possible even for a +high level language such as :data:`ShaderEncoding.GLSL`. + +:return: A list of pairs, listing a prefix for each shader encoding referenced. +:rtype: List[Tuple[ShaderEncoding,str]] +)"); + virtual rdcarray GetCustomShaderSourcePrefixes() = 0; + DOCUMENT(R"(Replace one resource with another for subsequent replay and analysis work. This is commonly used for modifying the capture by selectively replacing resources with newly diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 444256a09..08d373e48 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -1235,6 +1235,35 @@ struct ShaderCompileFlags DECLARE_REFLECTION_STRUCT(ShaderCompileFlags); +DOCUMENT("Contains the source prefix to add to a given type of shader source"); +struct ShaderSourcePrefix +{ + DOCUMENT(""); + ShaderSourcePrefix() = default; + ShaderSourcePrefix(const ShaderSourcePrefix &) = default; + ShaderSourcePrefix &operator=(const ShaderSourcePrefix &) = default; + + bool operator==(const ShaderSourcePrefix &o) const + { + return encoding == o.encoding && prefix == o.prefix; + } + bool operator<(const ShaderSourcePrefix &o) const + { + if(!(encoding == o.encoding)) + return encoding < o.encoding; + if(!(prefix == o.prefix)) + return prefix < o.prefix; + return false; + } + DOCUMENT("The encoding of the language this prefix applies to."); + ShaderEncoding encoding; + + DOCUMENT("The source prefix to add."); + rdcstr prefix; +}; + +DECLARE_REFLECTION_STRUCT(ShaderSourcePrefix); + DOCUMENT("Contains a source file available in a debug-compiled shader."); struct ShaderSourceFile { diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index e3cc77c8c..4589ba3c5 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -184,6 +184,10 @@ public: { return m_Proxy->GetCustomShaderEncodings(); } + rdcarray GetCustomShaderSourcePrefixes() + { + return m_Proxy->GetCustomShaderSourcePrefixes(); + } void SetCustomShaderIncludes(const rdcarray &directories) { m_Proxy->SetCustomShaderIncludes(directories); diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 8ac57976c..82a069d81 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -412,6 +412,14 @@ public: return {}; } + rdcarray GetCustomShaderSourcePrefixes() + { + if(m_Proxy) + return m_Proxy->GetCustomShaderSourcePrefixes(); + + return {}; + } + void FreeCustomShader(ResourceId id) { if(m_Proxy) diff --git a/renderdoc/data/glsl/glsl_ubos_cpp.h b/renderdoc/data/glsl/glsl_ubos_cpp.h index ac8333208..e70788ea5 100644 --- a/renderdoc/data/glsl/glsl_ubos_cpp.h +++ b/renderdoc/data/glsl/glsl_ubos_cpp.h @@ -51,3 +51,463 @@ #endif #include "glsl_ubos.h" + +struct RD_CustomShader_UBO_Type +{ + uvec4 TexDim; + uint SelectedMip; + uint TextureType; + uint SelectedSliceFace; + int SelectedSample; + uvec4 YUVDownsampleRate; + uvec4 YUVAChannels; + vec2 SelectedRange; +}; + +#if defined(VULKAN) + +#define HLSL_CUSTOM_PREFIX \ + R"EOPREFIX( + +#define RD_FLOAT_1D_ARRAY_BINDING t6 +#define RD_FLOAT_1D_BINDING t6 // all textures treated as arrays, add macro aliases + +#define RD_FLOAT_2D_ARRAY_BINDING t7 +#define RD_FLOAT_2D_BINDING t7 + +#define RD_FLOAT_3D_BINDING t8 + +#define RD_FLOAT_DEPTH_BINDING t7 +#define RD_FLOAT_DEPTH_ARRAY_BINDING t7 + +#define RD_FLOAT_STENCIL_BINDING t17 +#define RD_FLOAT_STENCIL_ARRAY_BINDING t17 + +#define RD_FLOAT_DEPTHMS_BINDING t9 +#define RD_FLOAT_DEPTHMS_ARRAY_BINDING t9 + +#define RD_FLOAT_STENCILMS_BINDING t19 +#define RD_FLOAT_STENCILMS_ARRAY_BINDING t19 + +#define RD_FLOAT_2DMS_ARRAY_BINDING t9 +#define RD_FLOAT_2DMS_BINDING t9 + +#define RD_FLOAT_YUV_ARRAY_BINDING t10 +#define RD_FLOAT_YUV_BINDING t10 + +#define RD_INT_1D_ARRAY_BINDING t11 +#define RD_INT_1D_BINDING t11 + +#define RD_INT_2D_ARRAY_BINDING t12 +#define RD_INT_2D_BINDING t12 + +#define RD_INT_3D_BINDING t13 + +#define RD_INT_2DMS_ARRAY_BINDING t14 +#define RD_INT_2DMS_BINDING t14 + +#define RD_UINT_1D_ARRAY_BINDING t16 +#define RD_UINT_1D_BINDING t16 + +#define RD_UINT_2D_ARRAY_BINDING t17 +#define RD_UINT_2D_BINDING t17 + +#define RD_UINT_3D_BINDING t18 + +#define RD_UINT_2DMS_ARRAY_BINDING t19 +#define RD_UINT_2DMS_BINDING t19 + +#define RD_POINT_SAMPLER_BINDING s50 +#define RD_LINEAR_SAMPLER_BINDING s51 + +#define RD_CONSTANT_BUFFER_BINDING b0 + +cbuffer RD_CBuffer_Type : register(RD_CONSTANT_BUFFER_BINDING) +{ + struct RD_CBuffer_Struct + { + uint4 TexDim; + uint SelectedMip; + uint TextureType; + uint SelectedSliceFace; + int SelectedSample; + uint4 YUVDownsampleRate; + uint4 YUVAChannels; + float2 SelectedRange; + } RD_CBuffer_Data; +}; + +#define RD_TextureType_1D 1 +#define RD_TextureType_2D 2 +#define RD_TextureType_3D 3 +#define RD_TextureType_Depth 999 +#define RD_TextureType_DepthStencil 999 +#define RD_TextureType_DepthMS 999 +#define RD_TextureType_DepthStencilMS 999 +#define RD_TextureType_2DMS 9 + +// for compatibility +#define RD_TextureType_1D_Array 1 +#define RD_TextureType_2D_Array 2 +#define RD_TextureType_Cube 999 +#define RD_TextureType_Cube_Array 999 + +// possible values (these are only return values from this function, NOT texture binding points): +// RD_TextureType_1D +// RD_TextureType_2D +// RD_TextureType_3D +// RD_TextureType_Depth (D3D only) +// RD_TextureType_DepthStencil (D3D only) +// RD_TextureType_DepthMS (D3D only) +// RD_TextureType_DepthStencilMS (D3D only) +// RD_TextureType_2DMS +uint RD_TextureType() +{ + return RD_CBuffer_Data.TextureType; +} + +// selected sample, or -numSamples for resolve +int RD_SelectedSample() +{ + return RD_CBuffer_Data.SelectedSample; +} + +uint RD_SelectedSliceFace() +{ + return RD_CBuffer_Data.SelectedSliceFace; +} + +uint RD_SelectedMip() +{ + return RD_CBuffer_Data.SelectedMip; +} + +// xyz = width, height, depth (or array size). w = # mips +uint4 RD_TexDim() +{ + return RD_CBuffer_Data.TexDim; +} + +// x = horizontal downsample rate (1 full rate, 2 half rate) +// y = vertical downsample rate +// z = number of planes in input texture +// w = number of bits per component (8, 10, 16) +uint4 RD_YUVDownsampleRate() +{ + return RD_CBuffer_Data.YUVDownsampleRate; +} + +// x = where Y channel comes from +// y = where U channel comes from +// z = where V channel comes from +// w = where A channel comes from +// each index will be [0,1,2,3] for xyzw in first plane, +// [4,5,6,7] for xyzw in second plane texture, etc. +// it will be 0xff = 255 if the channel does not exist. +uint4 RD_YUVAChannels() +{ + return RD_CBuffer_Data.YUVAChannels; +} + +// a pair with minimum and maximum selected range values +float2 RD_SelectedRange() +{ + return RD_CBuffer_Data.SelectedRange; +} + +)EOPREFIX" + +#define GLSL_CUSTOM_PREFIX \ + R"EOPREFIX( +#define RD_FLOAT_1D_ARRAY_BINDING 6 +#define RD_FLOAT_1D_BINDING 6 // all textures treated as arrays, add macro aliases + +#define RD_FLOAT_2D_ARRAY_BINDING 7 +#define RD_FLOAT_2D_BINDING 7 + +// cubemaps can read from the 2D binding +#define RD_FLOAT_CUBE_BINDING 7 +#define RD_FLOAT_CUBE_ARRAY_BINDING 7 + +// these have no equivalent. Define them to something valid so shaders still compile, +// but they will break if used +#define RD_FLOAT_BUFFER_BINDING 3 +#define RD_FLOAT_RECT_BINDING 4 + +#define RD_FLOAT_3D_BINDING 8 + +#define RD_FLOAT_2DMS_ARRAY_BINDING 9 +#define RD_FLOAT_2DMS_BINDING 9 + +#define RD_FLOAT_YUV_BINDING 10 +#define RD_FLOAT_YUV_ARRAY_SIZE 2 + +#define RD_INT_1D_ARRAY_BINDING 11 +#define RD_INT_1D_BINDING 11 + +#define RD_INT_2D_ARRAY_BINDING 12 +#define RD_INT_2D_BINDING 12 + +#define RD_INT_3D_BINDING 13 + +#define RD_INT_2DMS_ARRAY_BINDING 14 +#define RD_INT_2DMS_BINDING 14 + +#define RD_UINT_1D_ARRAY_BINDING 16 +#define RD_UINT_1D_BINDING 16 + +#define RD_UINT_2D_ARRAY_BINDING 17 +#define RD_UINT_2D_BINDING 17 + +#define RD_UINT_3D_BINDING 18 + +#define RD_UINT_2DMS_ARRAY_BINDING 19 +#define RD_UINT_2DMS_BINDING 19 + +#define RD_POINT_SAMPLER_BINDING 50 +#define RD_LINEAR_SAMPLER_BINDING 51 + +#define RD_CONSTANT_BUFFER_BINDING 0 + +layout(binding = RD_CONSTANT_BUFFER_BINDING) uniform RD_CBuffer_Type +{ + uvec4 TexDim; + uint SelectedMip; + uint TextureType; + uint SelectedSliceFace; + int SelectedSample; + uvec4 YUVDownsampleRate; + uvec4 YUVAChannels; + vec2 SelectedRange; +} RD_CBuffer_Data; + +#define RD_TextureType_1D 1 +#define RD_TextureType_2D 2 +#define RD_TextureType_3D 3 +#define RD_TextureType_2DMS 4 + +// for compatibility +#define RD_TextureType_1D_Array 1 +#define RD_TextureType_2D_Array 2 +#define RD_TextureType_2DMS_Array 4 +#define RD_TextureType_Cube 999 +#define RD_TextureType_Cube_Array 999 +#define RD_TextureType_Rect 999 +#define RD_TextureType_Buffer 999 +#define RD_TextureType_Depth 999 +#define RD_TextureType_DepthStencil 999 +#define RD_TextureType_DepthMS 999 +#define RD_TextureType_DepthStencilMS 999 + +// possible values (these are only return values from this function, NOT texture binding points): +// RD_TextureType_1D +// RD_TextureType_2D +// RD_TextureType_3D +// RD_TextureType_Cube (OpenGL only) +// RD_TextureType_1D_Array (OpenGL only) +// RD_TextureType_2D_Array (OpenGL only) +// RD_TextureType_Cube_Array (OpenGL only) +// RD_TextureType_Rect (OpenGL only) +// RD_TextureType_Buffer (OpenGL only) +// RD_TextureType_2DMS +// RD_TextureType_2DMS_Array (OpenGL only) +uint RD_TextureType() +{ + return RD_CBuffer_Data.TextureType; +} + +// selected sample, or -numSamples for resolve +int RD_SelectedSample() +{ + return RD_CBuffer_Data.SelectedSample; +} + +uint RD_SelectedSliceFace() +{ + return RD_CBuffer_Data.SelectedSliceFace; +} + +uint RD_SelectedMip() +{ + return RD_CBuffer_Data.SelectedMip; +} + +// xyz = width, height, depth (or array size). w = # mips +uvec4 RD_TexDim() +{ + return RD_CBuffer_Data.TexDim; +} + +// x = horizontal downsample rate (1 full rate, 2 half rate) +// y = vertical downsample rate +// z = number of planes in input texture +// w = number of bits per component (8, 10, 16) +uvec4 RD_YUVDownsampleRate() +{ + return RD_CBuffer_Data.YUVDownsampleRate; +} + +// x = where Y channel comes from +// y = where U channel comes from +// z = where V channel comes from +// w = where A channel comes from +// each index will be [0,1,2,3] for xyzw in first plane, +// [4,5,6,7] for xyzw in second plane texture, etc. +// it will be 0xff = 255 if the channel does not exist. +uvec4 RD_YUVAChannels() +{ + return RD_CBuffer_Data.YUVAChannels; +} + +// a pair with minimum and maximum selected range values +vec2 RD_SelectedRange() +{ + return RD_CBuffer_Data.SelectedRange; +} + +)EOPREFIX" + +#elif defined(OPENGL) + +#define GLSL_CUSTOM_PREFIX \ + R"EOPREFIX( +#define RD_FLOAT_1D_BINDING 1 +#define RD_FLOAT_2D_BINDING 2 +#define RD_FLOAT_3D_BINDING 3 +#define RD_FLOAT_CUBE_BINDING 4 +#define RD_FLOAT_1D_ARRAY_BINDING 5 +#define RD_FLOAT_2D_ARRAY_BINDING 6 +#define RD_FLOAT_CUBE_ARRAY_BINDING 7 +#define RD_FLOAT_RECT_BINDING 8 +#define RD_FLOAT_BUFFER_BINDING 9 +#define RD_FLOAT_2DMS_BINDING 10 +#define RD_FLOAT_2DMS_ARRAY_BINDING 11 + +#define RD_INT_1D_BINDING 1 +#define RD_INT_2D_BINDING 2 +#define RD_INT_3D_BINDING 3 +#define RD_INT_CUBE_BINDING 4 +#define RD_INT_1D_ARRAY_BINDING 5 +#define RD_INT_2D_ARRAY_BINDING 6 +#define RD_INT_CUBE_ARRAY_BINDING 7 +#define RD_INT_RECT_BINDING 8 +#define RD_INT_BUFFER_BINDING 9 +#define RD_INT_2DMS_BINDING 10 +#define RD_INT_2DMS_ARRAY_BINDING 11 + +#define RD_UINT_1D_BINDING 1 +#define RD_UINT_2D_BINDING 2 +#define RD_UINT_3D_BINDING 3 +#define RD_UINT_CUBE_BINDING 4 +#define RD_UINT_1D_ARRAY_BINDING 5 +#define RD_UINT_2D_ARRAY_BINDING 6 +#define RD_UINT_CUBE_ARRAY_BINDING 7 +#define RD_UINT_RECT_BINDING 8 +#define RD_UINT_BUFFER_BINDING 9 +#define RD_UINT_2DMS_BINDING 10 +#define RD_UINT_2DMS_ARRAY_BINDING 11 + +#define RD_CONSTANT_BUFFER_BINDING 0 + +layout(binding = RD_CONSTANT_BUFFER_BINDING) uniform RD_CBuffer_Type +{ + uvec4 TexDim; + uint SelectedMip; + uint TextureType; + uint SelectedSliceFace; + int SelectedSample; + uvec4 YUVDownsampleRate; + uvec4 YUVAChannels; + vec2 SelectedRange; +} RD_CBuffer_Data; + +#define RD_TextureType_1D 1 +#define RD_TextureType_2D 2 +#define RD_TextureType_3D 3 +#define RD_TextureType_Cube 4 +#define RD_TextureType_1D_Array 5 +#define RD_TextureType_2D_Array 6 +#define RD_TextureType_Cube_Array 7 +#define RD_TextureType_Rect 8 +#define RD_TextureType_Buffer 9 +#define RD_TextureType_2DMS 10 +#define RD_TextureType_2DMS_Array 11 + +// for compatibility +#define RD_TextureType_Depth 999 +#define RD_TextureType_DepthStencil 999 +#define RD_TextureType_DepthMS 999 +#define RD_TextureType_DepthStencilMS 999 + +// possible values (these are only return values from this function, NOT texture binding points): +// RD_TextureType_1D +// RD_TextureType_2D +// RD_TextureType_3D +// RD_TextureType_Cube (OpenGL only) +// RD_TextureType_1D_Array (OpenGL only) +// RD_TextureType_2D_Array (OpenGL only) +// RD_TextureType_Cube_Array (OpenGL only) +// RD_TextureType_Rect (OpenGL only) +// RD_TextureType_Buffer (OpenGL only) +// RD_TextureType_2DMS +// RD_TextureType_2DMS_Array (OpenGL only) +uint RD_TextureType() +{ + return RD_CBuffer_Data.TextureType; +} + +// selected sample, or -numSamples for resolve +int RD_SelectedSample() +{ + return RD_CBuffer_Data.SelectedSample; +} + +uint RD_SelectedSliceFace() +{ + return RD_CBuffer_Data.SelectedSliceFace; +} + +uint RD_SelectedMip() +{ + return RD_CBuffer_Data.SelectedMip; +} + +// xyz = width, height, depth (or array size). w = # mips +uvec4 RD_TexDim() +{ + return RD_CBuffer_Data.TexDim; +} + +// x = horizontal downsample rate (1 full rate, 2 half rate) +// y = vertical downsample rate +// z = number of planes in input texture +// w = number of bits per component (8, 10, 16) +uvec4 RD_YUVDownsampleRate() +{ + return RD_CBuffer_Data.YUVDownsampleRate; +} + +// x = where Y channel comes from +// y = where U channel comes from +// z = where V channel comes from +// w = where A channel comes from +// each index will be [0,1,2,3] for xyzw in first plane, +// [4,5,6,7] for xyzw in second plane texture, etc. +// it will be 0xff = 255 if the channel does not exist. +uvec4 RD_YUVAChannels() +{ + return RD_CBuffer_Data.YUVAChannels; +} + +// a pair with minimum and maximum selected range values +vec2 RD_SelectedRange() +{ + return RD_CBuffer_Data.SelectedRange; +} + +)EOPREFIX" + +#else + +#error "OPENGL and VULKAN both not defined" +#endif diff --git a/renderdoc/data/glsl_shaders.cpp b/renderdoc/data/glsl_shaders.cpp index d11cd0b88..8e87c3ce2 100644 --- a/renderdoc/data/glsl_shaders.cpp +++ b/renderdoc/data/glsl_shaders.cpp @@ -171,6 +171,91 @@ rdcstr GenerateGLSLShader(const rdcstr &shader, ShaderType type, int version, co return ret; } +static bool isspacetab(char c) +{ + return c == '\t' || c == ' '; +} + +static bool isnewline(char c) +{ + return c == '\r' || c == '\n'; +} + +rdcstr InsertSnippetAfterVersion(ShaderType type, const char *source, int len, const char *snippet) +{ + // we require these enums to be compatible elsewhere + glslang::TShader sh(EShLangFragment); + + glslang::EShClient client = + type == ShaderType::Vulkan ? glslang::EShClientVulkan : glslang::EShClientNone; + glslang::EShTargetClientVersion targetversion = + type == ShaderType::Vulkan ? glslang::EShTargetVulkan_1_0 : glslang::EShTargetOpenGL_450; + int inputVersion = client != glslang::EShClientNone ? 100 : 0; + + sh.setStringsWithLengths(&source, &len, 1); + sh.setEnvInput(glslang::EShSourceGlsl, EShLangFragment, client, inputVersion); + sh.setEnvClient(client, targetversion); + sh.setEnvTarget(glslang::EShTargetNone, glslang::EShTargetSpv_1_0); + + glslang::TShader::ForbidIncluder incl; + + bool success; + + EShMessages flags = EShMsgOnlyPreprocessor; + if(type == ShaderType::Vulkan) + flags = EShMessages(flags | EShMsgSpvRules | EShMsgVulkanRules); + else if(type == ShaderType::GLSPIRV) + flags = EShMessages(flags | EShMsgSpvRules); + + rdcstr src; + std::string outstr; + { + success = + sh.preprocess(GetDefaultResources(), 100, ENoProfile, false, false, flags, &outstr, incl); + src.assign(outstr.c_str(), outstr.size()); + } + + // find if this source contains a #version, accounting for whitespace. It must be the first thing + // (except for whitespace and comments, and comments have been removed) + int32_t it = src.find("#"); + len = src.count(); + + if(it >= 0) + { + // advance past the # + ++it; + + // skip whitespace + while(it < len && isspacetab(src[it])) + ++it; + + if(it + 7 < len && !strncmp(&src[it], "version", 7)) + { + it = src.find_first_of("\r\n", it); + while(it < len && isnewline(src[it])) + it++; + + // it points after the #version statement + } + else + { + it = -1; + } + } + + // no #version statement found - insert our own + if(it < 0) + { + rdcstr version = "#version 430 core\n\n"; + src.insert(0, version); + it = version.count(); + } + + src.insert(it, snippet); + + return src; +} + #if ENABLED(ENABLE_UNIT_TESTS) #include "catch/catch.hpp" diff --git a/renderdoc/data/glsl_shaders.h b/renderdoc/data/glsl_shaders.h index 637d2caf4..cd2d93435 100644 --- a/renderdoc/data/glsl_shaders.h +++ b/renderdoc/data/glsl_shaders.h @@ -36,6 +36,8 @@ enum class ShaderType rdcstr GenerateGLSLShader(const rdcstr &shader, ShaderType type, int version, const rdcstr &defines = ""); +rdcstr InsertSnippetAfterVersion(ShaderType type, const char *source, int len, const char *snippet); + // for unit tests struct ShaderReflection; struct ShaderBindpointMapping; diff --git a/renderdoc/data/hlsl/hlsl_cbuffers.h b/renderdoc/data/hlsl/hlsl_cbuffers.h index ef675cd47..c4d724245 100644 --- a/renderdoc/data/hlsl/hlsl_cbuffers.h +++ b/renderdoc/data/hlsl/hlsl_cbuffers.h @@ -247,3 +247,22 @@ cbuffer HistogramCBufferData REG(b0) #define SINT_TEX 0 #endif + +#if defined(__cplusplus) + +struct RD_CustomShader_CBuffer_Type +{ + uint4 TexDim; + uint SelectedMip; + uint TextureType; + uint SelectedSliceFace; + int SelectedSample; + uint4 YUVDownsampleRate; + uint4 YUVAChannels; + float2 SelectedRange; +}; + +// move to an #include since fxc barfs on it +#include "hlsl_custom_prefix.h" + +#endif diff --git a/renderdoc/data/hlsl/hlsl_custom_prefix.h b/renderdoc/data/hlsl/hlsl_custom_prefix.h new file mode 100644 index 000000000..967ce82cb --- /dev/null +++ b/renderdoc/data/hlsl/hlsl_custom_prefix.h @@ -0,0 +1,153 @@ + +#define HLSL_CUSTOM_PREFIX \ + R"EOPREFIX( +#define RD_FLOAT_1D_ARRAY_BINDING t1 +#define RD_FLOAT_1D_BINDING t1 // all textures treated as arrays, add macro aliases + +#define RD_FLOAT_2D_ARRAY_BINDING t2 +#define RD_FLOAT_2D_BINDING t2 + +#define RD_FLOAT_3D_BINDING t3 + +#define RD_FLOAT_DEPTH_BINDING t4 +#define RD_FLOAT_DEPTH_ARRAY_BINDING t4 + +#define RD_FLOAT_STENCIL_BINDING t5 +#define RD_FLOAT_STENCIL_ARRAY_BINDING t5 + +#define RD_FLOAT_DEPTHMS_BINDING t6 +#define RD_FLOAT_DEPTHMS_ARRAY_BINDING t6 + +#define RD_FLOAT_STENCILMS_BINDING t7 +#define RD_FLOAT_STENCILMS_ARRAY_BINDING t7 + +#define RD_FLOAT_2DMS_ARRAY_BINDING t9 +#define RD_FLOAT_2DMS_BINDING t9 + +#define RD_FLOAT_YUV_ARRAY_BINDING t10 +#define RD_FLOAT_YUV_BINDING t10 + +#define RD_INT_1D_ARRAY_BINDING t11 +#define RD_INT_1D_BINDING t11 + +#define RD_INT_2D_ARRAY_BINDING t12 +#define RD_INT_2D_BINDING t12 + +#define RD_INT_3D_BINDING t13 + +#define RD_INT_2DMS_ARRAY_BINDING t19 +#define RD_INT_2DMS_BINDING t19 + +#define RD_UINT_1D_ARRAY_BINDING t21 +#define RD_UINT_1D_BINDING t21 + +#define RD_UINT_2D_ARRAY_BINDING t22 +#define RD_UINT_2D_BINDING t22 + +#define RD_UINT_3D_BINDING t23 + +#define RD_UINT_2DMS_ARRAY_BINDING t29 +#define RD_UINT_2DMS_BINDING t29 + +#define RD_POINT_SAMPLER_BINDING s0 +#define RD_LINEAR_SAMPLER_BINDING s1 + +#define RD_CONSTANT_BUFFER_BINDING b0 + +cbuffer RD_CBuffer_Type : register(RD_CONSTANT_BUFFER_BINDING) +{ + struct RD_CBuffer_Struct + { + uint4 TexDim; + uint SelectedMip; + uint TextureType; + uint SelectedSliceFace; + int SelectedSample; + uint4 YUVDownsampleRate; + uint4 YUVAChannels; + float2 SelectedRange; + } RD_CBuffer_Data; +}; + +#define RD_TextureType_1D 1 +#define RD_TextureType_2D 2 +#define RD_TextureType_3D 3 +#define RD_TextureType_Depth 4 +#define RD_TextureType_DepthStencil 5 +#define RD_TextureType_DepthMS 6 +#define RD_TextureType_DepthStencilMS 7 +#define RD_TextureType_2DMS 9 + +// for compatibility +#define RD_TextureType_Cube 999 +#define RD_TextureType_Cube_Array 999 +#define RD_TextureType_1D_Array 999 +#define RD_TextureType_2D_Array 999 +#define RD_TextureType_Rect 999 +#define RD_TextureType_Buffer 999 +#define RD_TextureType_2DMS_Array 999 + +// possible values (these are only return values from this function, NOT texture binding points): +// RD_TextureType_1D +// RD_TextureType_2D +// RD_TextureType_3D +// RD_TextureType_Depth (D3D only) +// RD_TextureType_DepthStencil (D3D only) +// RD_TextureType_DepthMS (D3D only) +// RD_TextureType_DepthStencilMS (D3D only) +// RD_TextureType_2DMS +uint RD_TextureType() +{ + return RD_CBuffer_Data.TextureType; +} + +// selected sample, or -numSamples for resolve +int RD_SelectedSample() +{ + return RD_CBuffer_Data.SelectedSample; +} + +uint RD_SelectedSliceFace() +{ + return RD_CBuffer_Data.SelectedSliceFace; +} + +uint RD_SelectedMip() +{ + return RD_CBuffer_Data.SelectedMip; +} + +// xyz = width, height, depth (or array size). w = # mips +uint4 RD_TexDim() +{ + return RD_CBuffer_Data.TexDim; +} + +// x = horizontal downsample rate (1 full rate, 2 half rate) +// y = vertical downsample rate +// z = number of planes in input texture +// w = number of bits per component (8, 10, 16) +uint4 RD_YUVDownsampleRate() +{ + return RD_CBuffer_Data.YUVDownsampleRate; +} + +// x = where Y channel comes from +// y = where U channel comes from +// z = where V channel comes from +// w = where A channel comes from +// each index will be [0,1,2,3] for xyzw in first plane, +// [4,5,6,7] for xyzw in second plane texture, etc. +// it will be 0xff = 255 if the channel does not exist. +uint4 RD_YUVAChannels() +{ + return RD_CBuffer_Data.YUVAChannels; +} + +// a pair with minimum and maximum selected range values +float2 RD_SelectedRange() +{ + return RD_CBuffer_Data.SelectedRange; +} + +)EOPREFIX" diff --git a/renderdoc/driver/d3d11/d3d11_rendertexture.cpp b/renderdoc/driver/d3d11/d3d11_rendertexture.cpp index caa47847b..1ab9bae9b 100644 --- a/renderdoc/driver/d3d11/d3d11_rendertexture.cpp +++ b/renderdoc/driver/d3d11/d3d11_rendertexture.cpp @@ -579,7 +579,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag vertexData.VertexScale.y = (tex_y / m_OutputHeight) * cfg.scale * 2.0f; ID3D11PixelShader *customPS = NULL; - ID3D11Buffer *customBuff = NULL; + ID3D11Buffer *customBuffs[2] = {}; if(cfg.customShaderId != ResourceId()) { @@ -598,6 +598,24 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag (WrappedID3D11Shader *)m_pDevice->GetResourceManager()->GetLiveResource( cfg.customShaderId); + RD_CustomShader_CBuffer_Type customCBuffer = {}; + + customCBuffer.TexDim.x = details.texWidth; + customCBuffer.TexDim.y = details.texHeight; + customCBuffer.TexDim.z = + details.texType == eTexType_3D ? details.texDepth : details.texArraySize; + customCBuffer.TexDim.w = details.texMips; + customCBuffer.SelectedMip = cfg.subresource.mip; + customCBuffer.SelectedSliceFace = cfg.subresource.slice; + customCBuffer.SelectedSample = sampleIdx; + customCBuffer.TextureType = (uint32_t)details.texType; + customCBuffer.YUVDownsampleRate = details.YUVDownsampleRate; + customCBuffer.YUVAChannels = details.YUVAChannels; + customCBuffer.SelectedRange.x = cfg.rangeMin; + customCBuffer.SelectedRange.y = cfg.rangeMax; + + customBuffs[0] = GetDebugManager()->MakeCBuffer(&customCBuffer, sizeof(customCBuffer)); + customPS = wrapped; for(size_t i = 0; i < dxbc->GetReflection()->CBuffers.size(); i++) @@ -679,7 +697,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag { int32_t *d = (int32_t *)(byteData + var.offset); - d[0] = cfg.subresource.sample; + d[0] = sampleIdx; } else { @@ -718,7 +736,27 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag } } - customBuff = GetDebugManager()->MakeCBuffer(cbufData, cbuf.descriptor.byteSize); + if(cbuf.reg == 0) + { + // with the prefix added, binding 0 should be 'reserved' for the modern cbuffer. + // we can still make this work, but it's unexpected + RDCWARN( + "Unexpected globals cbuffer at binding 0, expected binding 1 after prefix " + "cbuffer"); + customBuffs[0] = GetDebugManager()->MakeCBuffer(cbufData, cbuf.descriptor.byteSize); + } + else if(cbuf.reg == 1) + { + customBuffs[1] = GetDebugManager()->MakeCBuffer(cbufData, cbuf.descriptor.byteSize); + } + else + { + RDCERR( + "Globals cbuffer at binding %d, unexpected and not handled - these constants " + "will be " + "undefined", + cbuf.reg); + } SAFE_DELETE_ARRAY(cbufData); } @@ -820,7 +858,7 @@ bool D3D11Replay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flag if(customPS) { m_pImmediateContext->PSSetShader(customPS, NULL, 0); - m_pImmediateContext->PSSetConstantBuffers(0, 1, &customBuff); + m_pImmediateContext->PSSetConstantBuffers(0, 2, customBuffs); } else { diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index b86ffc952..9ac8d69bd 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -2546,6 +2546,13 @@ void D3D11Replay::GetTextureData(ResourceId tex, const Subresource &sub, SAFE_RELEASE(dummyTex); } +rdcarray D3D11Replay::GetCustomShaderSourcePrefixes() +{ + return { + {ShaderEncoding::HLSL, HLSL_CUSTOM_PREFIX}, + }; +} + void D3D11Replay::ReplaceResource(ResourceId from, ResourceId to) { auto fromit = WrappedShader::m_ShaderList.find(from); diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 1e03abb6f..8e401cc8c 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -199,6 +199,7 @@ public: { return {ShaderEncoding::DXBC, ShaderEncoding::HLSL}; } + rdcarray GetCustomShaderSourcePrefixes(); rdcarray GetTargetShaderEncodings() { return {ShaderEncoding::DXBC, ShaderEncoding::HLSL}; diff --git a/renderdoc/driver/d3d12/d3d12_rendertexture.cpp b/renderdoc/driver/d3d12/d3d12_rendertexture.cpp index 4b50214e2..f5b563e19 100644 --- a/renderdoc/driver/d3d12/d3d12_rendertexture.cpp +++ b/renderdoc/driver/d3d12/d3d12_rendertexture.cpp @@ -512,6 +512,8 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture ID3D12PipelineState *customPSO = NULL; D3D12_GPU_VIRTUAL_ADDRESS psCBuf = 0; + D3D12_GPU_VIRTUAL_ADDRESS secondCBuf = + GetDebugManager()->UploadConstants(&heatmapData, sizeof(heatmapData)); if(cfg.customShaderId != ResourceId()) { @@ -521,6 +523,25 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture if(shader == NULL) return false; + RD_CustomShader_CBuffer_Type customCBuffer = {}; + + customCBuffer.TexDim.x = (uint32_t)resourceDesc.Width; + customCBuffer.TexDim.y = resourceDesc.Height; + customCBuffer.TexDim.z = resourceDesc.DepthOrArraySize; + customCBuffer.TexDim.w = resourceDesc.MipLevels; + customCBuffer.SelectedMip = cfg.subresource.mip; + customCBuffer.SelectedSliceFace = cfg.subresource.slice; + customCBuffer.SelectedSample = cfg.subresource.sample; + if(cfg.subresource.sample == ~0U) + customCBuffer.SelectedSample = -int(resourceDesc.SampleDesc.Count); + customCBuffer.TextureType = (uint32_t)resType; + customCBuffer.YUVDownsampleRate = YUVDownsampleRate; + customCBuffer.YUVAChannels = YUVAChannels; + customCBuffer.SelectedRange.x = cfg.rangeMin; + customCBuffer.SelectedRange.y = cfg.rangeMax; + + psCBuf = GetDebugManager()->UploadConstants(&customCBuffer, sizeof(customCBuffer)); + D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc = {}; pipeDesc.pRootSignature = m_TexRender.RootSig; pipeDesc.VS.BytecodeLength = m_TexRender.VS->GetBufferSize(); @@ -632,6 +653,8 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture int32_t *d = (int32_t *)(byteData + var.offset); d[0] = cfg.subresource.sample; + if(cfg.subresource.sample == ~0U) + d[0] = -int(resourceDesc.SampleDesc.Count); } else { @@ -670,7 +693,25 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture } } - psCBuf = GetDebugManager()->UploadConstants(cbufData, cbuf.descriptor.byteSize); + if(cbuf.reg == 0) + { + // with the prefix added, binding 0 should be 'reserved' for the modern cbuffer. + // we can still make this work, but it's unexpected + RDCWARN( + "Unexpected globals cbuffer at binding 0, expected binding 1 after prefix cbuffer"); + psCBuf = GetDebugManager()->UploadConstants(cbufData, cbuf.descriptor.byteSize); + } + else if(cbuf.reg == 1) + { + secondCBuf = GetDebugManager()->UploadConstants(cbufData, cbuf.descriptor.byteSize); + } + else + { + RDCERR( + "Globals cbuffer at binding %d, unexpected and not handled - these constants will be " + "undefined", + cbuf.reg); + } SAFE_DELETE_ARRAY(cbufData); } @@ -745,8 +786,7 @@ bool D3D12Replay::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, Texture list->SetGraphicsRootConstantBufferView( 0, GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData))); list->SetGraphicsRootConstantBufferView(1, psCBuf); - list->SetGraphicsRootConstantBufferView( - 2, GetDebugManager()->UploadConstants(&heatmapData, sizeof(heatmapData))); + list->SetGraphicsRootConstantBufferView(2, secondCBuf); list->SetGraphicsRootDescriptorTable(3, GetDebugManager()->GetGPUHandle(FIRST_TEXDISPLAY_SRV)); list->SetGraphicsRootDescriptorTable(4, GetDebugManager()->GetGPUHandle(FIRST_SAMP)); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 8ff537974..77e40e638 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -3953,6 +3953,13 @@ void D3D12Replay::GetTextureData(ResourceId tex, const Subresource &sub, SAFE_RELEASE(tmpTexture); } +rdcarray D3D12Replay::GetCustomShaderSourcePrefixes() +{ + return { + {ShaderEncoding::HLSL, HLSL_CUSTOM_PREFIX}, + }; +} + void D3D12Replay::SetCustomShaderIncludes(const rdcarray &directories) { m_CustomShaderIncludes = directories; diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index 47d401b8d..bd86f380a 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -175,6 +175,7 @@ public: { return {ShaderEncoding::DXBC, ShaderEncoding::HLSL}; } + rdcarray GetCustomShaderSourcePrefixes(); rdcarray GetTargetShaderEncodings() { return {ShaderEncoding::DXBC, ShaderEncoding::HLSL}; diff --git a/renderdoc/driver/gl/gl_rendertexture.cpp b/renderdoc/driver/gl/gl_rendertexture.cpp index 855fb3995..298fac461 100644 --- a/renderdoc/driver/gl/gl_rendertexture.cpp +++ b/renderdoc/driver/gl/gl_rendertexture.cpp @@ -491,6 +491,8 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flags) drv.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]); + RDCCOMPILE_ASSERT(sizeof(RD_CustomShader_UBO_Type) <= sizeof(TexDisplayUBOData), + "Custom shader UBO is bigger than tex display UBO, map is not valid"); TexDisplayUBOData *ubo = (TexDisplayUBOData *)drv.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(TexDisplayUBOData), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); @@ -626,6 +628,29 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, TexDisplayFlags flags) ubo->YUVDownsampleRate = {}; ubo->YUVAChannels = {}; + if(customProgram) + { + // overwrite with data for custom UBO + RD_CustomShader_UBO_Type customUBO = {}; + + customUBO.TexDim.x = texDetails.width; + customUBO.TexDim.y = texDetails.height; + customUBO.TexDim.z = texDetails.depth; + customUBO.TexDim.w = (uint32_t)numMips; + customUBO.SelectedMip = cfg.subresource.mip; + customUBO.TextureType = resType; + customUBO.SelectedSliceFace = cfg.subresource.slice; + if(cfg.subresource.sample == ~0U) + customUBO.SelectedSample = -texDetails.samples; + else + customUBO.SelectedSample = cfg.subresource.sample; + customUBO.YUVDownsampleRate = Vec4u(1, 1, 1, 8); + customUBO.YUVAChannels = Vec4u(0, 1, 2, 3); + customUBO.SelectedRange = Vec2f(cfg.rangeMin, cfg.rangeMax); + + memcpy(ubo, &customUBO, sizeof(RD_CustomShader_UBO_Type)); + } + drv.glUnmapBuffer(eGL_UNIFORM_BUFFER); TextureSamplerState prevSampState = SetSamplerParams(target, texname, mode); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 872a84fd8..f12a14229 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -25,6 +25,7 @@ #include "gl_replay.h" #include "core/settings.h" +#include "data/glsl_shaders.h" #include "driver/ihv/amd/amd_counters.h" #include "driver/ihv/arm/arm_counters.h" #include "driver/ihv/intel/intel_gl_counters.h" @@ -3021,6 +3022,17 @@ void GLReplay::BuildCustomShader(ShaderEncoding sourceEncoding, const bytebuf &s const rdcstr &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id, rdcstr &errors) { + if(sourceEncoding == ShaderEncoding::GLSL) + { + rdcstr sourceText = InsertSnippetAfterVersion(ShaderType::GLSL, (const char *)source.data(), + source.count(), GLSL_CUSTOM_PREFIX); + + bytebuf patchedSource; + patchedSource.assign((byte *)sourceText.begin(), sourceText.size()); + + return BuildTargetShader(sourceEncoding, patchedSource, entry, compileFlags, type, id, errors); + } + BuildTargetShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 7dcc2cd25..5322c5fb9 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -203,6 +203,14 @@ public: const MeshDisplay &cfg); rdcarray GetCustomShaderEncodings() { return {ShaderEncoding::GLSL}; } + rdcarray GetCustomShaderSourcePrefixes() + { + // this is a complete hack, since we *do* want to define a prefix for GLSL. However GLSL sucks + // and has the #version as the first thing, so we can't do a simple prepend of some defines. + // Instead we will return no prefix and insert our own in BuildCustomShader if we see GLSL + // coming in. + return {}; + } rdcarray GetTargetShaderEncodings() { return {ShaderEncoding::GLSL}; } void BuildTargetShader(ShaderEncoding sourceEncoding, const bytebuf &source, const rdcstr &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id, diff --git a/renderdoc/driver/vulkan/vk_rendertexture.cpp b/renderdoc/driver/vulkan/vk_rendertexture.cpp index 8ae894313..32acdfef8 100644 --- a/renderdoc/driver/vulkan/vk_rendertexture.cpp +++ b/renderdoc/driver/vulkan/vk_rendertexture.cpp @@ -368,33 +368,21 @@ bool VulkanReplay::RenderTextureInternal(TextureDisplay cfg, const ImageState &i { // must match struct declared in user shader (see documentation / Shader Viewer window helper // menus) - struct CustomTexDisplayUBOData - { - Vec4u texDim; - uint32_t selectedMip; - uint32_t texType; - uint32_t selectedSliceFace; - int32_t selectedSample; - Vec4u YUVDownsampleRate; - Vec4u YUVAChannels; - float selectedRangeMin; - float selectedRangeMax; - }; - CustomTexDisplayUBOData *customData = (CustomTexDisplayUBOData *)data; + RD_CustomShader_UBO_Type *customData = (RD_CustomShader_UBO_Type *)data; - customData->texDim.x = iminfo.extent.width; - customData->texDim.y = iminfo.extent.height; - customData->texDim.z = iminfo.extent.depth; - customData->texDim.w = iminfo.mipLevels; - customData->selectedMip = cfg.subresource.mip; - customData->selectedSliceFace = cfg.subresource.slice; - customData->selectedSample = sampleIdx; - customData->texType = (uint32_t)textype; + customData->TexDim.x = iminfo.extent.width; + customData->TexDim.y = iminfo.extent.height; + customData->TexDim.z = iminfo.type == VK_IMAGE_TYPE_3D ? iminfo.extent.depth : iminfo.arrayLayers; + customData->TexDim.w = iminfo.mipLevels; + customData->SelectedMip = cfg.subresource.mip; + customData->SelectedSliceFace = cfg.subresource.slice; + customData->SelectedSample = sampleIdx; + customData->TextureType = (uint32_t)textype; customData->YUVDownsampleRate = YUVDownsampleRate; customData->YUVAChannels = YUVAChannels; - customData->selectedRangeMin = cfg.rangeMin; - customData->selectedRangeMax = cfg.rangeMax; + customData->SelectedRange.x = cfg.rangeMin; + customData->SelectedRange.y = cfg.rangeMax; } m_TexRender.UBO.Unmap(); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 0cc63b86c..1dcef224c 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -28,8 +28,9 @@ #include #include #include "core/settings.h" +#include "data/glsl_shaders.h" #include "driver/ihv/amd/amd_rgp.h" -#include "driver/shaders/spirv/spirv_compile.h" +#include "driver/shaders/spirv/glslang_compile.h" #include "maths/formatpacking.h" #include "maths/matrix.h" #include "replay/dummy_driver.h" @@ -4062,6 +4063,17 @@ void VulkanReplay::BuildCustomShader(ShaderEncoding sourceEncoding, const bytebu const rdcstr &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id, rdcstr &errors) { + if(sourceEncoding == ShaderEncoding::GLSL) + { + rdcstr sourceText = InsertSnippetAfterVersion(ShaderType::Vulkan, (const char *)source.data(), + source.count(), GLSL_CUSTOM_PREFIX); + + bytebuf patchedSource; + patchedSource.assign((byte *)sourceText.begin(), sourceText.size()); + + return BuildTargetShader(sourceEncoding, patchedSource, entry, compileFlags, type, id, errors); + } + BuildTargetShader(sourceEncoding, source, entry, compileFlags, type, id, errors); } @@ -4137,6 +4149,20 @@ ResourceId VulkanReplay::ApplyCustomShader(TextureDisplay &display) return GetResID(GetDebugManager()->GetCustomTexture()); } +rdcarray VulkanReplay::GetCustomShaderSourcePrefixes() +{ + // this is a complete hack, since we *do* want to define a prefix for GLSL. However GLSL sucks + // and has the #version as the first thing, so we can't do a simple prepend of some defines. + // Instead we will return no prefix and insert our own in BuildCustomShader if we see GLSL + // coming in. + // For SPIR-V no prefix is needed (or possible) + // For HLSL however we define our HLSL prefix so that custom-compiled HLSL to SPIR-V gets the + // right binding and helper definitions + return { + {ShaderEncoding::HLSL, HLSL_CUSTOM_PREFIX}, + }; +} + void VulkanReplay::BuildTargetShader(ShaderEncoding sourceEncoding, const bytebuf &source, const rdcstr &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id, rdcstr &errors) diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index fff618c68..dfb618dd5 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -370,6 +370,7 @@ public: { return {ShaderEncoding::SPIRV, ShaderEncoding::GLSL}; } + rdcarray GetCustomShaderSourcePrefixes(); rdcarray GetTargetShaderEncodings() { return {ShaderEncoding::SPIRV, ShaderEncoding::GLSL}; diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index dae3df582..2d19506cb 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -225,6 +225,7 @@ + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index d80d8a8a2..a2f6c4ac3 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -573,6 +573,9 @@ Replay + + Resources\hlsl + diff --git a/renderdoc/replay/dummy_driver.cpp b/renderdoc/replay/dummy_driver.cpp index 92895c184..4aad08b1c 100644 --- a/renderdoc/replay/dummy_driver.cpp +++ b/renderdoc/replay/dummy_driver.cpp @@ -42,6 +42,7 @@ DummyDriver::DummyDriver(IReplayDriver *original, const rdcarrayGetAvailableGPUs(); m_WindowSystems = original->GetSupportedWindowSystems(); m_CustomEncodings = original->GetCustomShaderEncodings(); + m_CustomPrefixes = original->GetCustomShaderSourcePrefixes(); } DummyDriver::~DummyDriver() @@ -478,7 +479,12 @@ void DummyDriver::BuildCustomShader(ShaderEncoding sourceEncoding, const bytebuf rdcarray DummyDriver::GetCustomShaderEncodings() { - return {ShaderEncoding::HLSL, ShaderEncoding::GLSL}; + return m_CustomEncodings; +} + +rdcarray DummyDriver::GetCustomShaderSourcePrefixes() +{ + return m_CustomPrefixes; } ResourceId DummyDriver::ApplyCustomShader(TextureDisplay &display) diff --git a/renderdoc/replay/dummy_driver.h b/renderdoc/replay/dummy_driver.h index a85fc2614..fef94352d 100644 --- a/renderdoc/replay/dummy_driver.h +++ b/renderdoc/replay/dummy_driver.h @@ -167,6 +167,7 @@ public: const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id, rdcstr &errors); rdcarray GetCustomShaderEncodings(); + rdcarray GetCustomShaderSourcePrefixes(); ResourceId ApplyCustomShader(TextureDisplay &display); void FreeCustomShader(ResourceId id); @@ -195,4 +196,5 @@ private: rdcarray m_GPUs; rdcarray m_WindowSystems; rdcarray m_CustomEncodings; + rdcarray m_CustomPrefixes; }; diff --git a/renderdoc/replay/replay_controller.cpp b/renderdoc/replay/replay_controller.cpp index 126f83b1f..c58542ee7 100644 --- a/renderdoc/replay/replay_controller.cpp +++ b/renderdoc/replay/replay_controller.cpp @@ -1955,6 +1955,13 @@ rdcarray ReplayController::GetCustomShaderEncodings() return m_pDevice->GetCustomShaderEncodings(); } +rdcarray ReplayController::GetCustomShaderSourcePrefixes() +{ + CHECK_REPLAY_THREAD(); + + return m_pDevice->GetCustomShaderSourcePrefixes(); +} + rdcarray ReplayController::GetTargetShaderEncodings() { CHECK_REPLAY_THREAD(); diff --git a/renderdoc/replay/replay_controller.h b/renderdoc/replay/replay_controller.h index bf6882ec8..e49dc707c 100644 --- a/renderdoc/replay/replay_controller.h +++ b/renderdoc/replay/replay_controller.h @@ -153,6 +153,7 @@ public: void FreeCustomShader(ResourceId id); rdcarray GetCustomShaderEncodings(); + rdcarray GetCustomShaderSourcePrefixes(); rdcarray GetTargetShaderEncodings(); rdcpair BuildTargetShader(const rdcstr &entry, ShaderEncoding sourceEncoding, bytebuf source, diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index 2a321c1e0..8a04cf68e 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -269,6 +269,7 @@ public: const rdcstr &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id, rdcstr &errors) = 0; virtual rdcarray GetCustomShaderEncodings() = 0; + virtual rdcarray GetCustomShaderSourcePrefixes() = 0; virtual ResourceId ApplyCustomShader(TextureDisplay &display) = 0; virtual void FreeCustomShader(ResourceId id) = 0;