diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp index 984cf9195..a40a9d5d0 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp @@ -363,6 +363,20 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader i++; } + for(size_t o = 0; o < outputIDs.size(); o++) + { + rdcstr varName = GetRawName(outputIDs[o]); + + for(size_t i = 0; i < globalSourceVars.size(); i++) + { + if(!globalSourceVars[i].variables.empty() && globalSourceVars[i].variables[0].name == varName) + { + ret->sourceVars.push_back(globalSourceVars[i]); + break; + } + } + } + ret->lineInfo.resize(instructionOffsets.size()); for(size_t i = 0; i < instructionOffsets.size(); i++) { diff --git a/util/test/demos/d3d11/d3d11_shader_debug_zoo.cpp b/util/test/demos/d3d11/d3d11_shader_debug_zoo.cpp index a7767b247..caf35921d 100644 --- a/util/test/demos/d3d11/d3d11_shader_debug_zoo.cpp +++ b/util/test/demos/d3d11/d3d11_shader_debug_zoo.cpp @@ -404,6 +404,8 @@ float4 main(v2f IN) : SV_Target0 return float4(read.b.xyz, read.c); } +)EOSHADER" + R"EOSHADER( if(IN.tri == 51) { // use this to ensure the compiler doesn't know we're using fixed locations diff --git a/util/test/demos/vk/vk_shader_debug_zoo.cpp b/util/test/demos/vk/vk_shader_debug_zoo.cpp index 220094146..aedc4597f 100644 --- a/util/test/demos/vk/vk_shader_debug_zoo.cpp +++ b/util/test/demos/vk/vk_shader_debug_zoo.cpp @@ -30,72 +30,101 @@ RD_TEST(VK_Shader_Debug_Zoo, VulkanGraphicsTest) struct ConstsA2V { - Vec3f pos; + Vec4f pos; float zero; float one; float negone; }; - const char *vertex = R"EOSHADER( -#version 430 core + std::string v2f = + R"EOSHADER( -layout(location = 0) in vec3 pos; -layout(location = 1) in float zero; -layout(location = 2) in float one; -layout(location = 3) in float negone; - -struct v2f +struct flatv2f { - vec2 zeroVal; - float tinyVal; - float oneVal; - float negoneVal; uint test; uint intval; }; -layout(location = 1) out flat v2f OUT; +struct v2f +{ + vec2 zeroVal; + vec2 inpos; + vec2 inposIncreased; + float tinyVal; + float oneVal; + float negoneVal; +}; + +layout(location = 1) inout_type flat flatv2f flatData; +layout(location = 3) inout_type v2f linearData; + +)EOSHADER"; + + std::string vertex = R"EOSHADER( +#version 430 core + +#define inout_type out + +)EOSHADER" + v2f + R"EOSHADER( + +layout(location = 0) in vec4 pos; +layout(location = 1) in float zero; +layout(location = 2) in float one; +layout(location = 3) in float negone; void main() { int test = gl_InstanceIndex; - gl_Position = vec4(pos.x + pos.z * float(test), pos.y, 0.0, 1.0); + gl_Position = vec4(pos.x + pos.z * float(test % 256), pos.y + pos.w * float(test / 256), 0.0, 1.0); - OUT.zeroVal = zero.xx; - OUT.oneVal = one; - OUT.negoneVal = negone; - OUT.test = test; - OUT.tinyVal = one * 1.0e-30; - OUT.intval = test + 7; + const vec4 verts[4] = vec4[4](vec4(-1.0, -1.0, 0.5, 1.0), vec4(1.0, -1.0, 0.5, 1.0), + vec4(-1.0, 1.0, 0.5, 1.0), vec4(1.0, 1.0, 0.5, 1.0)); + + const vec2 data[3] = vec2[3](vec2(10.0f, 10.0f), vec2(20.0f, 10.0f), vec2(10.0f, 20.0f)); + + linearData.zeroVal = zero.xx; + linearData.oneVal = one; + linearData.negoneVal = negone; + linearData.tinyVal = one * 1.0e-30; + linearData.inpos = data[gl_VertexIndex]; + linearData.inposIncreased = data[gl_VertexIndex] * 2.75f; + flatData.test = test; + flatData.intval = test + 7; } )EOSHADER"; - const char *pixel_glsl = R"EOSHADER( + std::string pixel_glsl = R"EOSHADER( #version 460 core -struct v2f -{ - vec2 zeroVal; - float tinyVal; - float oneVal; - float negoneVal; - uint test; - uint intval; -}; +#define inout_type in -layout(location = 1) in flat v2f IN; +)EOSHADER" + v2f + R"EOSHADER( layout(location = 0, index = 0) out vec4 Color; void main() { - if(IN.test == 0) + float posinf = linearData.oneVal/linearData.zeroVal.x; + float neginf = linearData.negoneVal/linearData.zeroVal.x; + float nan = linearData.zeroVal.x/linearData.zeroVal.y; + + float negone = linearData.negoneVal; + float posone = linearData.oneVal; + float zero = linearData.zeroVal.x; + float tiny = linearData.tinyVal; + + int intval = flatData.intval; + + uint test = flatData.test; + + Color = vec4(0,0,0,0); + if(test == 0) { Color = vec4(1.0f, 2.0f, 3.0f, 4.0f); } - else if(IN.test == 1) + else if(test == 1) { Color = gl_FragCoord; } @@ -103,14 +132,15 @@ void main() )EOSHADER"; - const char *pixel_asm = R"EOSHADER( + std::string pixel_asm = R"EOSHADER( OpCapability Shader %glsl450 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %main "main" %IN %Color %gl_FragCoord + OpEntryPoint Fragment %main "main" %flatData %linearData %Color %gl_FragCoord OpExecutionMode %main OriginUpperLeft - OpDecorate %IN Flat - OpDecorate %IN Location 1 + OpDecorate %flatData Flat + OpDecorate %flatData Location 1 + OpDecorate %linearData Location 3 OpDecorate %Color Index 0 OpDecorate %Color Location 0 OpDecorate %gl_FragCoord BuiltIn FragCoord @@ -127,18 +157,21 @@ void main() %mainfunc = OpTypeFunction %void - %v2f = OpTypeStruct %float2 %float %float %float %uint %uint + %v2f = OpTypeStruct %float2 %float2 %float2 %float %float %float + %flatv2f = OpTypeStruct %uint %uint %_ptr_Input_v2f = OpTypePointer Input %v2f +%_ptr_Input_flatv2f = OpTypePointer Input %flatv2f %_ptr_Input_uint = OpTypePointer Input %uint %_ptr_Input_float4 = OpTypePointer Input %float4 %_ptr_Output_float4 = OpTypePointer Output %float4 - %IN = OpVariable %_ptr_Input_v2f Input + %linearData = OpVariable %_ptr_Input_v2f Input + %flatData = OpVariable %_ptr_Input_flatv2f Input %gl_FragCoord = OpVariable %_ptr_Input_float4 Input %Color = OpVariable %_ptr_Output_float4 Output -%v2f_test_idx = OpConstant %int 4 +%flatv2f_test_idx = OpConstant %int 0 %uint_0 = OpConstant %uint 0 %uint_1 = OpConstant %uint 1 @@ -153,7 +186,7 @@ void main() %main = OpFunction %void None %mainfunc %main_begin = OpLabel - %test_ptr = OpAccessChain %_ptr_Input_uint %IN %v2f_test_idx + %test_ptr = OpAccessChain %_ptr_Input_uint %flatData %flatv2f_test_idx %test = OpLoad %uint %test_ptr OpSelectionMerge %break None @@ -174,7 +207,7 @@ void main() OpBranch %break %test_2 = OpLabel - %3 = OpVectorShuffle %float4 %float_0000 %float_1234 3 6 2 4 + %3 = OpVectorShuffle %float4 %float_0000 %float_1234 3 2 6 4 OpStore %Color %3 OpBranch %break @@ -193,23 +226,34 @@ void main() if(!Init()) return 3; - size_t lastTest = std::string(pixel_glsl).rfind("IN.test == "); - lastTest += sizeof("IN.test == ") - 1; + size_t lastTest = pixel_glsl.rfind("test == "); + lastTest += sizeof("test == ") - 1; - const uint32_t numGLSLTests = atoi(pixel_glsl + lastTest) + 1; + const uint32_t numGLSLTests = atoi(pixel_glsl.c_str() + lastTest) + 1; - const uint32_t numASMTests = 3; + lastTest = pixel_asm.rfind("%test_"); + lastTest += sizeof("%test_") - 1; - const uint32_t numTests = numGLSLTests + numASMTests; + const uint32_t numASMTests = atoi(pixel_asm.c_str() + lastTest) + 1; VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo()); - static const uint32_t texDim = AlignUp(numTests, 64U) * 4; + // calculate number of tests (align to 64) + uint32_t texWidth = AlignUp(std::max(numGLSLTests, numASMTests), 64U); - AllocatedImage img(this, vkh::ImageCreateInfo(texDim, 4, 0, VK_FORMAT_R32G32B32A32_SFLOAT, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT), - VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); + // wrap around after 256 + uint32_t texHeight = std::max(1U, texWidth / 256); + texWidth /= texHeight; + + // 4x4 for each test + texWidth *= 4; + texHeight *= 4; + + AllocatedImage img( + this, + vkh::ImageCreateInfo(texWidth, texHeight, 0, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView imgview = createImageView( vkh::ImageViewCreateInfo(img.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32G32B32A32_SFLOAT)); @@ -225,7 +269,7 @@ void main() VkRenderPass renderPass = createRenderPass(renderPassCreateInfo); VkFramebuffer framebuffer = - createFramebuffer(vkh::FramebufferCreateInfo(renderPass, {imgview}, {texDim, 4})); + createFramebuffer(vkh::FramebufferCreateInfo(renderPass, {imgview}, {texWidth, texHeight})); vkh::GraphicsPipelineCreateInfo pipeCreateInfo; @@ -250,12 +294,13 @@ void main() VkPipeline asmpipe = createGraphicsPipeline(pipeCreateInfo); - float triWidth = 8.0f / float(texDim); + float triWidth = 8.0f / float(texWidth); + float triHeight = 8.0f / float(texHeight); ConstsA2V triangle[] = { - {Vec3f(-1.0f, 1.0f, triWidth), 0.0f, 1.0f, -1.0f}, - {Vec3f(-1.0f, -1.0f, triWidth), 0.0f, 1.0f, -1.0f}, - {Vec3f(-1.0f + triWidth, -1.0f, triWidth), 0.0f, 1.0f, -1.0f}, + {Vec4f(-1.0f, -1.0f, triWidth, triHeight), 0.0f, 1.0f, -1.0f}, + {Vec4f(-1.0f + triWidth, -1.0f, triWidth, triHeight), 0.0f, 1.0f, -1.0f}, + {Vec4f(-1.0f, -1.0f + triHeight, triWidth, triHeight), 0.0f, 1.0f, -1.0f}, }; AllocatedBuffer vb(this, @@ -280,32 +325,56 @@ void main() VkViewport v = {}; v.maxDepth = 1.0f; - v.width = (float)texDim; - v.height = 4; + v.width = (float)texWidth; + v.height = (float)texHeight; VkRect2D s = {}; - s.extent.width = texDim; - s.extent.height = 4; - - vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, s, - {vkh::ClearValue(0.0f, 0.0f, 0.0f, 0.0f)}), - VK_SUBPASS_CONTENTS_INLINE); + s.extent.width = texWidth; + s.extent.height = texHeight; vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, glslpipe); vkCmdSetViewport(cmd, 0, 1, &v); vkCmdSetScissor(cmd, 0, 1, &s); vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0}); - setMarker(cmd, "GLSL tests"); - vkCmdDraw(cmd, 3, numGLSLTests, 0, 0); - v.x += numGLSLTests * 4; - v.width -= v.x; + vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, s, + {vkh::ClearValue(0.0f, 0.0f, 0.0f, 0.0f)}), + VK_SUBPASS_CONTENTS_INLINE); + + pushMarker(cmd, "GLSL tests"); + uint32_t numTests = numGLSLTests; + uint32_t offset = 0; + // loop drawing 256 tests at a time + while(numTests > 0) + { + uint32_t num = std::min(numTests, 256U); + vkCmdDraw(cmd, 3, num, 0, offset); + offset += num; + numTests -= num; + } + popMarker(cmd); + + vkCmdEndRenderPass(cmd); vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, asmpipe); vkCmdSetViewport(cmd, 0, 1, &v); - setMarker(cmd, "ASM tests"); - vkCmdDraw(cmd, 3, numASMTests, 0, 0); + vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, s, + {vkh::ClearValue(0.0f, 0.0f, 0.0f, 0.0f)}), + VK_SUBPASS_CONTENTS_INLINE); + + pushMarker(cmd, "ASM tests"); + numTests = numASMTests; + offset = 0; + // loop drawing 256 tests at a time + while(numTests > 0) + { + uint32_t num = std::min(numTests, 256U); + vkCmdDraw(cmd, 3, num, 0, offset); + offset += num; + numTests -= num; + } + popMarker(cmd); vkCmdEndRenderPass(cmd); diff --git a/util/test/tests/Vulkan/VK_Shader_Debug_Zoo.py b/util/test/tests/Vulkan/VK_Shader_Debug_Zoo.py new file mode 100644 index 000000000..2d24b615f --- /dev/null +++ b/util/test/tests/Vulkan/VK_Shader_Debug_Zoo.py @@ -0,0 +1,97 @@ +import renderdoc as rd +from typing import List +import rdtest + + +class VK_Shader_Debug_Zoo(rdtest.TestCase): + demos_test_name = 'VK_Shader_Debug_Zoo' + + def check_capture(self): + failed = False + + rdtest.log.begin_section("GLSL tests") + draw = self.find_draw("GLSL tests") + for child in range(len(draw.children)): + section = draw.children[child] + self.controller.SetFrameEvent(section.eventId, False) + pipe: rd.PipeState = self.controller.GetPipelineState() + + for test in range(section.numInstances): + x = 4 * test + 1 + y = 4 * child + 1 + + # Debug the shader + trace: rd.ShaderDebugTrace = self.controller.DebugPixel(x, y, rd.ReplayController.NoPreference, + rd.ReplayController.NoPreference) + + if trace.debugger is None: + failed = True + rdtest.log.error("Test {} in sub-section {} did not debug at all".format(test, child)) + self.controller.FreeTrace(trace) + continue + + cycles, variables = self.process_trace(trace) + + output = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0) + + debugged = self.evaluate_source_var(output, variables) + + try: + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, x, y, debugged.value.fv[0:4]) + except rdtest.TestFailureException as ex: + failed = True + rdtest.log.error("Test {} in sub-section {} did not match. {}".format(test, child, str(ex))) + continue + finally: + self.controller.FreeTrace(trace) + + rdtest.log.success("Test {} in sub-section {} matched as expected".format(test, child)) + rdtest.log.end_section("GLSL tests") + + self.controller.SetFrameEvent(draw.eventId, False) + + pipe: rd.PipeState = self.controller.GetPipelineState() + + rdtest.log.begin_section("ASM tests") + draw = self.find_draw("ASM tests") + for child in range(len(draw.children)): + section = draw.children[child] + self.controller.SetFrameEvent(section.eventId, False) + pipe: rd.PipeState = self.controller.GetPipelineState() + + for test in range(section.numInstances): + x = 4 * test + 1 + y = 4 * child + 1 + + # Debug the shader + trace: rd.ShaderDebugTrace = self.controller.DebugPixel(x, y, rd.ReplayController.NoPreference, + rd.ReplayController.NoPreference) + + if trace.debugger is None: + failed = True + rdtest.log.error("Test {} in sub-section {} did not debug at all".format(test, child)) + self.controller.FreeTrace(trace) + continue + + cycles, variables = self.process_trace(trace) + + output = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0) + + debugged = self.evaluate_source_var(output, variables) + + try: + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, x, y, debugged.value.fv[0:4]) + except rdtest.TestFailureException as ex: + failed = True + rdtest.log.error("Test {} in sub-section {} did not match. {}".format(test, child, str(ex))) + continue + finally: + self.controller.FreeTrace(trace) + + rdtest.log.success("Test {} in sub-section {} matched as expected".format(test, child)) + rdtest.log.end_section("ASM tests") + + if failed: + raise rdtest.TestFailureException("Some tests were not as expected") + + rdtest.log.success("All tests matched")