From 18713f644e0ba972c65e350c817cf4fb633744b6 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 23 Apr 2020 16:15:22 +0100 Subject: [PATCH] Implement OpImageQueryLod by faking derivatives on sample quad --- renderdoc/CMakeLists.txt | 1 + renderdoc/data/embedded_files.h | 1 + renderdoc/data/glsl/shaderdebug_sample.vert | 46 ++++++++++++ renderdoc/data/renderdoc.rc | 1 + renderdoc/data/resource.h | 1 + .../driver/shaders/spirv/spirv_debug.cpp | 22 +++--- renderdoc/driver/vulkan/vk_shader_cache.cpp | 2 + renderdoc/driver/vulkan/vk_shader_cache.h | 1 + renderdoc/driver/vulkan/vk_shaderdebug.cpp | 73 +++++++++++++++++-- renderdoc/renderdoc.vcxproj | 1 + renderdoc/renderdoc.vcxproj.filters | 3 + util/test/demos/vk/vk_shader_debug_zoo.cpp | 6 ++ 12 files changed, 141 insertions(+), 17 deletions(-) create mode 100644 renderdoc/data/glsl/shaderdebug_sample.vert diff --git a/renderdoc/CMakeLists.txt b/renderdoc/CMakeLists.txt index 12cf46be2..6a63c80d6 100644 --- a/renderdoc/CMakeLists.txt +++ b/renderdoc/CMakeLists.txt @@ -386,6 +386,7 @@ set(data data/glsl/quadresolve.frag data/glsl/quadwrite.frag data/glsl/pixelhistory_primid.frag + data/glsl/shaderdebug_sample.vert data/glsl/texdisplay.frag data/glsl/texremap.frag data/glsl/gl_texsample.h diff --git a/renderdoc/data/embedded_files.h b/renderdoc/data/embedded_files.h index b51ac6645..81b70dae7 100644 --- a/renderdoc/data/embedded_files.h +++ b/renderdoc/data/embedded_files.h @@ -64,6 +64,7 @@ DECLARE_EMBED(glsl_deptharr2ms_frag); DECLARE_EMBED(glsl_depthms2arr_frag); DECLARE_EMBED(glsl_gles_texsample_h); DECLARE_EMBED(glsl_pixelhistory_primid_frag); +DECLARE_EMBED(glsl_shaderdebug_sample_vert); DECLARE_EMBED(glsl_texremap_frag); #undef DECLARE_EMBED diff --git a/renderdoc/data/glsl/shaderdebug_sample.vert b/renderdoc/data/glsl/shaderdebug_sample.vert new file mode 100644 index 000000000..4a2bef5fc --- /dev/null +++ b/renderdoc/data/glsl/shaderdebug_sample.vert @@ -0,0 +1,46 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2020 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +layout(location = 0) out vec3 uvw; + +layout(push_constant) uniform PushData +{ + vec4 uvw; + vec4 ddx; + vec4 ddy; +} +push; + +void main(void) +{ + const vec4 verts[3] = vec4[3](vec4(-0.75, -0.75, 0.5, 1.0), vec4(1.25, -0.75, 0.5, 1.0), + vec4(-0.75, 1.25, 0.5, 1.0)); + + gl_Position = verts[gl_VertexIndex]; + uvw = push.uvw.xyz; + if(gl_VertexIndex == 1) + uvw += push.ddx.xyz; + else if(gl_VertexIndex == 2) + uvw += push.ddy.xyz; +} diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index 370713be8..68bb0da06 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -146,6 +146,7 @@ RESOURCE_glsl_gltext_vert TYPE_EMBED "glsl/gltext.vert" RESOURCE_glsl_gltext_frag TYPE_EMBED "glsl/gltext.frag" RESOURCE_glsl_glsl_globals_h TYPE_EMBED "glsl/glsl_globals.h" RESOURCE_glsl_texremap_frag TYPE_EMBED "glsl/texremap.frag" +RESOURCE_glsl_shaderdebug_sample_vert TYPE_EMBED "glsl/shaderdebug_sample.vert" #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index be46c0e72..523680371 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -49,6 +49,7 @@ #define RESOURCE_glsl_glsl_globals_h 440 #define RESOURCE_glsl_texremap_frag 441 #define RESOURCE_glsl_pixelhistory_primid_frag 442 +#define RESOURCE_glsl_shaderdebug_sample_vert 443 // Next default values for new objects // diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.cpp b/renderdoc/driver/shaders/spirv/spirv_debug.cpp index c61ab60d1..aa1e66e04 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug.cpp @@ -1986,6 +1986,7 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray case Op::ImageFetch: case Op::ImageGather: case Op::ImageDrefGather: + case Op::ImageQueryLod: case Op::ImageSampleExplicitLod: case Op::ImageSampleImplicitLod: case Op::ImageSampleDrefExplicitLod: @@ -2033,6 +2034,15 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray gather = GatherChannel::Red; compare = GetSrc(image.dref); } + else if(opdata.op == Op::ImageQueryLod) + { + OpImageQueryLod image(it); + + sampler = img = GetSrc(image.sampledImage); + uv = GetSrc(image.coordinate); + + derivId = image.coordinate; + } else if(opdata.op == Op::ImageSampleExplicitLod) { OpImageSampleExplicitLod image(it); @@ -2420,18 +2430,6 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray break; } - // TODO image lod query (from implicit lod) - case Op::ImageQueryLod: - { - RDCERR("Image lod query not yet implemented."); - - ShaderVariable var("", 0U, 0U, 0U, 0U); - var.columns = 1; - - SetDst(opdata.result, var); - break; - } - // TODO image load/store case Op::ImageRead: case Op::ImageWrite: diff --git a/renderdoc/driver/vulkan/vk_shader_cache.cpp b/renderdoc/driver/vulkan/vk_shader_cache.cpp index 85f36ddc6..bb9d95d85 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.cpp +++ b/renderdoc/driver/vulkan/vk_shader_cache.cpp @@ -93,6 +93,8 @@ static const BuiltinShaderConfig builtinShaders[] = { rdcspv::ShaderStage::Fragment, FeatureCheck::NoCheck, true}, {BuiltinShader::PixelHistoryPrimIDFS, EmbeddedResource(glsl_pixelhistory_primid_frag), rdcspv::ShaderStage::Fragment, FeatureCheck::NoCheck, true}, + {BuiltinShader::ShaderDebugSampleVS, EmbeddedResource(glsl_shaderdebug_sample_vert), + rdcspv::ShaderStage::Vertex, FeatureCheck::NoCheck, true}, }; RDCCOMPILE_ASSERT(ARRAY_COUNT(builtinShaders) == arraydim(), diff --git a/renderdoc/driver/vulkan/vk_shader_cache.h b/renderdoc/driver/vulkan/vk_shader_cache.h index 17c26f431..35ade9750 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.h +++ b/renderdoc/driver/vulkan/vk_shader_cache.h @@ -55,6 +55,7 @@ enum class BuiltinShader TexRemapUInt, TexRemapSInt, PixelHistoryPrimIDFS, + ShaderDebugSampleVS, Count, }; diff --git a/renderdoc/driver/vulkan/vk_shaderdebug.cpp b/renderdoc/driver/vulkan/vk_shaderdebug.cpp index e42f8dd7b..66f3a4c56 100644 --- a/renderdoc/driver/vulkan/vk_shaderdebug.cpp +++ b/renderdoc/driver/vulkan/vk_shaderdebug.cpp @@ -755,6 +755,7 @@ public: break; } + case rdcspv::Op::ImageQueryLod: case rdcspv::Op::ImageSampleExplicitLod: case rdcspv::Op::ImageSampleImplicitLod: case rdcspv::Op::ImageSampleProjExplicitLod: @@ -812,7 +813,7 @@ public: } if(opcode == rdcspv::Op::ImageSampleImplicitLod || - opcode == rdcspv::Op::ImageSampleProjImplicitLod) + opcode == rdcspv::Op::ImageSampleProjImplicitLod || opcode == rdcspv::Op::ImageQueryLod) { // use grad to sub in for the implicit lod constParams.useGradOrGatherOffsets = VK_TRUE; @@ -941,6 +942,14 @@ public: Unwrap(m_DebugData.PipeLayout), 0, 1, UnwrapPtr(m_DebugData.DescSet), 0, NULL); + // push uvw/ddx/ddy for the vertex shader + ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL, + sizeof(Vec4f) * 0, sizeof(Vec3f), &uniformParams.uvw); + ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL, + sizeof(Vec4f) * 1, sizeof(Vec3f), &uniformParams.ddx); + ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL, + sizeof(Vec4f) * 2, sizeof(Vec3f), &uniformParams.ddy); + ObjDisp(cmd)->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd)); @@ -1230,7 +1239,8 @@ private: const VkPipelineShaderStageCreateInfo shaderStages[2] = { {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_VERTEX_BIT, - m_pDriver->GetShaderCache()->GetBuiltinModule(BuiltinShader::BlitVS), "main", NULL}, + m_pDriver->GetShaderCache()->GetBuiltinModule(BuiltinShader::ShaderDebugSampleVS), "main", + NULL}, {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_FRAGMENT_BIT, m_DebugData.Module[shaderIndex], "main", &specInfo}, }; @@ -1545,6 +1555,7 @@ private: editor.CreateEmpty(1, 0); editor.AddCapability(rdcspv::Capability::Shader); + editor.AddCapability(rdcspv::Capability::ImageQuery); editor.AddCapability(rdcspv::Capability::Sampled1D); editor.AddCapability(rdcspv::Capability::SampledBuffer); @@ -1567,6 +1578,7 @@ private: rdcspv::Id v3i32 = editor.DeclareType(rdcspv::Vector(rdcspv::scalar(), 3)); rdcspv::Id v2f32 = editor.DeclareType(rdcspv::Vector(rdcspv::scalar(), 2)); rdcspv::Id v3f32 = editor.DeclareType(rdcspv::Vector(rdcspv::scalar(), 3)); + rdcspv::Id v4f32 = editor.DeclareType(rdcspv::Vector(rdcspv::scalar(), 4)); // int2[4] rdcspv::Id a4v2i32 = editor.AddType( @@ -1734,10 +1746,18 @@ private: editor.SetName(bindVars[(size_t)ShaderDebugBind::Sampler], "Sampler"); editor.SetName(bindVars[(size_t)ShaderDebugBind::Constants], "CBuffer"); + rdcspv::Id uvw_ptr = editor.DeclareType(rdcspv::Pointer(v3f32, rdcspv::StorageClass::Input)); + rdcspv::Id input_uvw_var = + editor.AddVariable(rdcspv::OpVariable(uvw_ptr, editor.MakeId(), rdcspv::StorageClass::Input)); + editor.AddDecoration(rdcspv::OpDecorate( + input_uvw_var, rdcspv::DecorationParam(0))); + + editor.SetName(input_uvw_var, "uvw"); + // register the entry point - editor.AddOperation( - editor.Begin(rdcspv::Section::EntryPoints), - rdcspv::OpEntryPoint(rdcspv::ExecutionModel::Fragment, entryId, "main", {outVar})); + editor.AddOperation(editor.Begin(rdcspv::Section::EntryPoints), + rdcspv::OpEntryPoint(rdcspv::ExecutionModel::Fragment, entryId, "main", + {input_uvw_var, outVar})); editor.AddOperation(editor.Begin(rdcspv::Section::ExecutionMode), rdcspv::OpExecutionMode(entryId, rdcspv::ExecutionMode::OriginUpperLeft)); @@ -1794,6 +1814,10 @@ private: editor.SetName(offset_xy, "offset_xy"); editor.SetName(offset_xyz, "offset_xyz"); + rdcspv::Id input_uvw = func.add(rdcspv::OpLoad(v3f32, editor.MakeId(), input_uvw_var)); + rdcspv::Id input_uv = + func.add(rdcspv::OpVectorShuffle(v2f32, editor.MakeId(), input_uvw, input_uvw, {0, 1})); + // first store NULL data in, so the output is always initialised rdcspv::Id breakLabel = editor.MakeId(); @@ -1820,6 +1844,16 @@ private: texel_u, // Buffer - u }; + // only used for QueryLod, so we can ignore MSAA/Buffer + rdcspv::Id input_coord[(uint32_t)ShaderDebugBind::Count] = { + rdcspv::Id(), + input_uv, // 1D - u and array + input_uvw, // 2D - u,v and array + input_uvw, // 3D - u,v,w + rdcspv::Id(), // 2DMS + rdcspv::Id(), // Buffer + }; + rdcspv::Id coord[(uint32_t)ShaderDebugBind::Count] = { rdcspv::Id(), uv, // 1D - u and array @@ -1892,6 +1926,35 @@ private: if(i == (uint32_t)ShaderDebugBind::Buffer || i == (uint32_t)ShaderDebugBind::Tex2DMS) continue; + { + rdcspv::Op op = rdcspv::Op::ImageQueryLod; + + rdcspv::Id label = editor.MakeId(); + targets.push_back({(uint32_t)op * 10 + i, label}); + + cases.add(rdcspv::OpLabel(label)); + rdcspv::Id loadedImage = + cases.add(rdcspv::OpLoad(texSampTypes[i], editor.MakeId(), bindVars[i])); + rdcspv::Id loadedSampler = + cases.add(rdcspv::OpLoad(texSampTypes[sampIdx], editor.MakeId(), bindVars[sampIdx])); + + rdcspv::Id combined = cases.add(rdcspv::OpSampledImage( + texSampCombinedTypes[i], editor.MakeId(), loadedImage, loadedSampler)); + + rdcspv::Id sampleResult = + cases.add(rdcspv::OpImageQueryLod(v2f32, editor.MakeId(), combined, input_coord[i])); + sampleResult = cases.add(rdcspv::OpVectorShuffle(v4f32, editor.MakeId(), sampleResult, + sampleResult, {0, 1, 0, 1})); + + // if we're sampling from an integer texture the output variable will be the same type. + // Just bitcast the float bits into it, which will come out the other side the right type. + if(uintTex || sintTex) + sampleResult = cases.add(rdcspv::OpBitcast(resultType, editor.MakeId(), sampleResult)); + + cases.add(rdcspv::OpStore(outVar, sampleResult)); + cases.add(rdcspv::OpBranch(breakLabel)); + } + for(rdcspv::Op op : {rdcspv::Op::ImageSampleExplicitLod, rdcspv::Op::ImageSampleImplicitLod}) { rdcspv::Id label = editor.MakeId(); diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index 91bfcfdf5..f45acf989 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -602,6 +602,7 @@ + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index 91b1f2aae..1a40ac145 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -1069,6 +1069,9 @@ Resources\hlsl + + Resources\glsl + diff --git a/util/test/demos/vk/vk_shader_debug_zoo.cpp b/util/test/demos/vk/vk_shader_debug_zoo.cpp index 29d7da1df..532ebd866 100644 --- a/util/test/demos/vk/vk_shader_debug_zoo.cpp +++ b/util/test/demos/vk/vk_shader_debug_zoo.cpp @@ -1074,6 +1074,12 @@ void main() Color = textureProj(linearSampledImage, vec3(inpos, 0.5f)); break; } + case 130: + { + Color.xy = textureQueryLod(linearSampledImage, inpos); + Color.zw = textureQueryLod(linearSampledImage, vec2(1.0f, 1.0f)/inpos); + break; + } default: break; } }