Add helper for checking vertex debugging matches postvs

* There are a few 'extras' here as the uses aren't quite uniform, but they are
  close enough it makes sense to have a common helper
This commit is contained in:
baldurk
2026-09-11 15:04:03 +01:00
parent 83c53890da
commit fd55020165
8 changed files with 90 additions and 321 deletions
+1 -36
View File
@@ -121,7 +121,7 @@ class Draw_Zoo(rdtest.TestCase):
idx = vsout_ref[vtx]['idx']
self.check_debug(vtx, idx, inst, postvs)
self.check_vertex_debug(vtx, idx, inst, postvs)
else:
rdtest.log.print('Not checking shader debugging, unsupported')
@@ -136,41 +136,6 @@ class Draw_Zoo(rdtest.TestCase):
rdtest.log.success("Checked action {}".format(action.eventId))
def check_debug(self, vtx, idx, inst, postvs):
trace: rd.ShaderDebugTrace = self.controller.DebugVertex(vtx, inst, idx, 0)
if trace.debugger is None:
self.controller.FreeTrace(trace)
raise rdtest.TestFailureException("Couldn't debug vertex {} in instance {}".format(vtx, inst))
cycles, variables = self.process_trace(trace)
for var in trace.sourceVars:
var: rd.SourceVariableMapping
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
name = var.name
if name not in postvs[vtx].keys():
raise rdtest.TestFailureException("Don't have expected output for {}".format(name))
expect = postvs[vtx][name]
value = self.evaluate_source_var(var, variables)
if len(expect) != value.columns:
raise rdtest.TestFailureException(
"Output {} at vert {} (idx {}) instance {} has different size ({} values) to expectation ({} values)"
.format(name, vtx, idx, inst, value.columns, len(expect)))
debugged = value.value.f32v[0:value.columns]
if not rdtest.value_compare(expect, debugged):
raise rdtest.TestFailureException(
"Debugged value {} at vert {} (idx {}) instance {}: {} doesn't exactly match postvs output {}".format(
name, vtx, idx, inst, debugged, expect))
rdtest.log.success('Successfully debugged vertex {} in instance {}'
.format(vtx, inst))
def check_capture(self):
test_marker: rd.ActionDescription = self.find_action("Test")
self.check_capture_action(test_marker)
+78
View File
@@ -536,6 +536,84 @@ class TestCase:
log.success("Simple triangle is as expected")
def check_vertex_debug(
self,
vtx: int,
idx: int,
inst: int,
postvs: analyse.MeshData,
*,
view=-1,
eps=util.FLT_EPSILON,
single_postvs=False,
ignore_uninit=False,
name_retry: Callable[[str], str] | None = None
):
trace = self.controller.DebugVertex(vtx, inst, idx, max(0, view))
ctx = f"vertex {vtx} (idx {idx}) instance {inst}"
if view >= 0:
ctx += f" view {view}"
if trace.debugger is None:
self.controller.FreeTrace(trace)
raise TestFailureException(f"Couldn't debug {ctx}")
try:
cycles, variables = self.process_trace(trace)
postvs_vtx = vtx
if single_postvs:
postvs_vtx = 0
for var in trace.sourceVars:
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
name = var.name
if name not in postvs[postvs_vtx].keys() and name_retry is not None:
name = name_retry(name)
if name not in postvs[postvs_vtx].keys():
raise TestFailureException(f"Don't have expected output for {name}")
expect = postvs[postvs_vtx][name]
assert expect is not None
value = self.evaluate_source_var(var, variables)
expect_cols = 1
if util.is_vector(expect):
expect_cols = len(expect)
if expect_cols != value.columns:
raise TestFailureException(
f"Output {name} at {ctx} has different size ({value.columns} values) to expectation ({expect_cols} values)")
compType = rd.VarTypeCompType(value.type)
debugged: util.VectorValue = []
if compType == rd.CompType.UInt:
debugged = list(value.value.u32v[0:value.columns])
elif compType == rd.CompType.SInt:
debugged = list(value.value.s32v[0:value.columns])
else:
debugged = list(value.value.f32v[0:value.columns])
# For now, ignore debugged values that are uninitialised. This is an application bug but it causes false
# reports of problems
if ignore_uninit and value.columns > 1:
assert util.is_vector(expect)
for comp in range(4):
if value.value.u32v[comp] == 0xcccccccc:
debugged[comp] = expect[comp]
is_eq, diff_amt = util.value_compare_diff(expect, debugged, eps=5.0E-06)
if not is_eq:
raise TestFailureException(
f"Debugged value {name} at {ctx}: {debugged} doesn't exactly match postvs output {expect}. {diff_amt} difference")
log.success(f'Successfully debugged vertex {ctx} in {cycles} cycles')
finally:
self.controller.FreeTrace(trace)
def run(self):
self.capture_filename = self.get_capture()
+5 -56
View File
@@ -97,65 +97,14 @@ class GL_Shader_Debug_Zoo(rdtest.TestCase):
postvs = self.get_postvs(action, rd.MeshDataStage.VSOut, first_index=vtx, num_indices=1, instance=inst)
trace: rd.ShaderDebugTrace = self.controller.DebugVertex(vtx, inst, idx, 0)
if trace.debugger is None:
try:
self.check_vertex_debug(vtx, idx, inst, postvs, single_postvs=True, name_retry = lambda x: x.replace(".", "Block."))
except rdtest.TestFailureException as err:
failed = True
rdtest.log.error("Test {} in sub-section {} did not debug vertex".format(test, child))
self.controller.FreeTrace(trace)
rdtest.log.error(f"Error debugging vertex at test {test} in sub-section {child}: {err.message}")
continue
_, variables = self.process_trace(trace)
outputs = 0
for var in trace.sourceVars:
var: rd.SourceVariableMapping
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
name = var.name
if name not in postvs[0].keys():
name = name.replace(".", "Block.")
if name not in postvs[0].keys():
failed = True
rdtest.log.error("Don't have expected output for {}".format(name))
continue
expect = postvs[0][name]
value = self.evaluate_source_var(var, variables)
if len(expect) != value.columns:
failed = True
rdtest.log.error(
"Output {} at EID {} has different size ({} values) to expectation ({} values)"
.format(name, action.eventId, value.columns, len(expect)))
continue
compType = rd.VarTypeCompType(value.type)
if compType == rd.CompType.UInt:
debugged = list(value.value.u32v[0:value.columns])
elif compType == rd.CompType.SInt:
debugged = list(value.value.s32v[0:value.columns])
else:
debugged = list(value.value.f32v[0:value.columns])
if not rdtest.value_compare(expect, debugged):
failed = True
rdtest.log.error("Test {} in sub-section {} did not match vertex.\nExpected {} but got {}".format(test, child, expect, debugged))
break
is_eq, diff_amt = rdtest.value_compare_diff(expect, debugged, eps=5.0E-06)
if not is_eq:
failed = True
rdtest.log.error(
"Debugged value {} at EID {} vert {} (idx {}) instance {}: {} difference. {} doesn't exactly match postvs output {}".format(
name, action.eventId, vtx, idx, inst, diff_amt, debugged, expect))
outputs = outputs + 1
self.controller.FreeTrace(trace)
rdtest.log.success("Test {} vertex in sub-section {} matched as expected".format(test, child))
rdtest.log.success(f"Test {test} vertex in sub-section {child} matched as expected")
rdtest.log.end_section(child)
+1 -59
View File
@@ -152,70 +152,12 @@ class Iter_Test(rdtest.TestCase):
postvs = self.get_postvs(action, rd.MeshDataStage.VSOut, first_index=vtx, num_indices=1, instance=inst)
trace: rd.ShaderDebugTrace = self.controller.DebugVertex(vtx, inst, idx, 0)
if trace.debugger is None:
self.controller.FreeTrace(trace)
rdtest.log.print("No debug result")
return
try:
cycles, variables = self.process_trace(trace)
self.check_vertex_debug(vtx, idx, inst, postvs, eps=5.0E-06, single_postvs=True, ignore_uninit=True)
except rdtest.TestFailureException as err:
rdtest.log.error(f"Error debugging: {err.message}")
return
outputs = 0
for var in trace.sourceVars:
var: rd.SourceVariableMapping
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
name = var.name
if name not in postvs[0].keys():
rdtest.log.error("Don't have expected output for {}".format(name))
continue
expect = postvs[0][name]
value = self.evaluate_source_var(var, variables)
if len(expect) != value.columns:
rdtest.log.error(
"Output {} at EID {} has different size ({} values) to expectation ({} values)"
.format(name, action.eventId, value.columns, len(expect)))
continue
compType = rd.VarTypeCompType(value.type)
if compType == rd.CompType.UInt:
debugged = list(value.value.u32v[0:value.columns])
elif compType == rd.CompType.SInt:
debugged = list(value.value.s32v[0:value.columns])
else:
debugged = list(value.value.f32v[0:value.columns])
# For now, ignore debugged values that are uninitialised. This is an application bug but it causes false
# reports of problems
for comp in range(4):
if value.value.u32v[comp] == 0xcccccccc:
debugged[comp] = expect[comp]
# Unfortunately we can't ever trust that we should get back a matching results, because some shaders
# rely on undefined/inaccurate maths that we don't emulate.
# So the best we can do is log an error for manual verification
is_eq, diff_amt = rdtest.value_compare_diff(expect, debugged, eps=5.0E-06)
if not is_eq:
rdtest.log.error(
"Debugged value {} at EID {} vert {} (idx {}) instance {}: {} difference. {} doesn't exactly match postvs output {}".format(
name, action.eventId, vtx, idx, inst, diff_amt, debugged, expect))
outputs = outputs + 1
rdtest.log.success('Successfully debugged vertex in {} cycles, {}/{} outputs match'
.format(cycles, outputs, len(refl.outputSignature)))
self.controller.FreeTrace(trace)
def pixel_debug(self, action: rd.ActionDescription):
pipe: rd.PipeState = self.controller.GetPipelineState()
+1 -45
View File
@@ -76,51 +76,7 @@ class VK_Graphics_Pipeline(rdtest.TestCase):
raise rdtest.TestFailureException(
f"Graphics bind 0[15] isn't the accessed descriptor {str(rd.DumpObject(access))}")
trace = self.controller.DebugVertex(0, 0, 0, 0)
if trace.debugger is None:
raise rdtest.TestFailureException("No vertex debug result")
cycles, variables = self.process_trace(trace)
outputs = 0
for var in trace.sourceVars:
var: rd.SourceVariableMapping
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
name = var.name
if name not in postvs_data[0].keys():
raise rdtest.TestFailureException("Don't have expected output for {}".format(name))
expect = postvs_data[0][name]
value = self.evaluate_source_var(var, variables)
if len(expect) != value.columns:
raise rdtest.TestFailureException(
"Vertex output {} has different size ({} values) to expectation ({} values)".format(
name, action.eventId, value.columns, len(expect)))
compType = rd.VarTypeCompType(value.type)
if compType == rd.CompType.UInt:
debugged = list(value.value.u32v[0:value.columns])
elif compType == rd.CompType.SInt:
debugged = list(value.value.s32v[0:value.columns])
else:
debugged = list(value.value.f32v[0:value.columns])
is_eq, diff_amt = rdtest.value_compare_diff(expect, debugged, eps=5.0E-06)
if not is_eq:
rdtest.log.error(
"Debugged vertex output value {}: {} difference. {} doesn't exactly match postvs output {}".
format(name, action.eventId, diff_amt, debugged, expect))
outputs = outputs + 1
rdtest.log.success('Successfully debugged vertex in {} cycles, {}/{} outputs match'.format(
cycles, outputs, len(vsrefl.outputSignature)))
self.controller.FreeTrace(trace)
self.check_vertex_debug(0, 0, 0, postvs_data)
history = self.controller.PixelHistory(pipe.GetOutputTargets()[0].resource, 200, 150, rd.Subresource(0, 0, 0),
rd.CompType.Typeless)
@@ -42,43 +42,6 @@ class VK_KHR_Buffer_Address(rdtest.TestCase):
postvs = self.get_postvs(action, rd.MeshDataStage.VSOut, instance=inst)
for vtx in range(action.numIndices):
idx = vtx
self.check_debug(vtx, idx, inst, postvs)
self.check_vertex_debug(vtx, idx, inst, postvs)
rdtest.log.success("All tests matched")
def check_debug(self, vtx, idx, inst, postvs):
trace: rd.ShaderDebugTrace = self.controller.DebugVertex(vtx, inst, idx, 0)
if trace.debugger is None:
self.controller.FreeTrace(trace)
raise rdtest.TestFailureException("Couldn't debug vertex {} in instance {}".format(vtx, inst))
cycles, variables = self.process_trace(trace)
for var in trace.sourceVars:
var: rd.SourceVariableMapping
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
name = var.name
if name not in postvs[vtx].keys():
raise rdtest.TestFailureException("Don't have expected output for {}".format(name))
expect = postvs[vtx][name]
value = self.evaluate_source_var(var, variables)
if len(expect) != value.columns:
raise rdtest.TestFailureException(
"Output {} at vert {} (idx {}) instance {} has different size ({} values) to expectation ({} values)"
.format(name, vtx, idx, inst, value.columns, len(expect)))
debugged = value.value.f32v[0:value.columns]
if not rdtest.value_compare(expect, debugged):
raise rdtest.TestFailureException(
"Debugged value {} at vert {} (idx {}) instance {}: {} doesn't exactly match postvs output {}".format(
name, vtx, idx, inst, debugged, expect))
rdtest.log.success('Successfully debugged vertex {} in instance {}'
.format(vtx, inst))
+1 -45
View File
@@ -36,51 +36,7 @@ class VK_Multi_Entry(rdtest.TestCase):
postvs = self.get_postvs(action, rd.MeshDataStage.VSOut, first_index=0, num_indices=1, instance=0)
trace: rd.ShaderDebugTrace = self.controller.DebugVertex(0, 0, 0, 0)
if trace.debugger is None:
raise rdtest.TestFailureException("No vertex debug result")
cycles, variables = self.process_trace(trace)
outputs = 0
for var in trace.sourceVars:
var: rd.SourceVariableMapping
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
name = var.name
if name not in postvs[0].keys():
raise rdtest.TestFailureException("Don't have expected output for {}".format(name))
expect = postvs[0][name]
value = self.evaluate_source_var(var, variables)
if len(expect) != value.columns:
raise rdtest.TestFailureException(
"Vertex output {} has different size ({} values) to expectation ({} values)".format(
name, action.eventId, value.columns, len(expect)))
compType = rd.VarTypeCompType(value.type)
if compType == rd.CompType.UInt:
debugged = list(value.value.u32v[0:value.columns])
elif compType == rd.CompType.SInt:
debugged = list(value.value.s32v[0:value.columns])
else:
debugged = list(value.value.f32v[0:value.columns])
is_eq, diff_amt = rdtest.value_compare_diff(expect, debugged, eps=5.0E-06)
if not is_eq:
rdtest.log.error(
"Debugged vertex output value {}: {} difference. {} doesn't exactly match postvs output {}".
format(name, action.eventId, diff_amt, debugged, expect))
outputs = outputs + 1
rdtest.log.success('Successfully debugged vertex in {} cycles, {}/{} outputs match'.format(
cycles, outputs, len(refl.outputSignature)))
self.controller.FreeTrace(trace)
self.check_vertex_debug(0, 0, 0, postvs, single_postvs=True)
history = self.controller.PixelHistory(pipe.GetOutputTargets()[0].resource, 200, 150, rd.Subresource(0, 0, 0),
rd.CompType.Typeless)
+2 -42
View File
@@ -45,7 +45,7 @@ class VK_Multi_View(rdtest.TestCase):
postvs = self.get_postvs(action, rd.MeshDataStage.VSOut, instance=inst, view=view)
for vtx in range(action.numIndices):
idx = vtx
self.check_debug(vtx, idx, inst, view, postvs)
self.check_vertex_debug(vtx, idx, inst, postvs, view=view)
rdtest.log.print(f"View {view} Slice {slice} passed")
for test_name in ["viewportIndex choice"]:
@@ -86,49 +86,9 @@ class VK_Multi_View(rdtest.TestCase):
postvs = self.get_postvs(action, rd.MeshDataStage.VSOut, instance=inst, view=view)
for vtx in range(action.numIndices):
idx = vtx
self.check_debug(vtx, idx, inst, view, postvs)
self.check_vertex_debug(vtx, idx, inst, postvs, view=view)
rdtest.log.print(f"View {view} Slice {slice} passed")
rdtest.log.success("All tests matched")
def check_debug(self, vtx, idx, inst, view, postvs):
trace: rd.ShaderDebugTrace = self.controller.DebugVertex(vtx, inst, idx, view)
if trace.debugger is None:
self.controller.FreeTrace(trace)
raise rdtest.TestFailureException("Couldn't debug vertex {} in instance {} for view {}".format(vtx, inst, view))
cycles, variables = self.process_trace(trace)
for var in trace.sourceVars:
var: rd.SourceVariableMapping
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
name = var.name
if name not in postvs[vtx].keys():
raise rdtest.TestFailureException("Don't have expected output for {}".format(name))
expect = postvs[vtx][name]
value = self.evaluate_source_var(var, variables)
if len(expect) != value.columns:
raise rdtest.TestFailureException(
"Output {} at vert {} (idx {}) instance {} view {} has different size ({} values) to expectation ({} values)"
.format(name, vtx, idx, inst, view, value.columns, len(expect)))
if value.type == rd.VarType.SInt:
debugged = value.value.s32v[0:value.columns]
elif value.type == rd.VarType.UInt:
debugged = value.value.u32v[0:value.columns]
else:
debugged = value.value.f32v[0:value.columns]
if not rdtest.value_compare(expect, debugged):
raise rdtest.TestFailureException(
"Debugged value {} at vert {} (idx {}) instance {} view {}: {} doesn't exactly match postvs output {}".format(
name, vtx, idx, inst, view, debugged, expect))
rdtest.log.success('Successfully debugged vertex {} in instance {} for view {}'
.format(vtx, inst, view))