Set up python script to run VK shader debug tests

* Since we expect many more tests it also runs the test texture in a 2D grid
  with N drawcalls
This commit is contained in:
baldurk
2020-04-07 17:14:50 +01:00
parent 1b6cc3a70e
commit 38abf04909
4 changed files with 254 additions and 72 deletions
@@ -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++)
{
@@ -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
+141 -72
View File
@@ -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);
@@ -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")