Use context helpers for vertex debugging

This commit is contained in:
baldurk
2026-09-11 21:17:16 +01:00
parent d9c72e7651
commit 031212e916
2 changed files with 85 additions and 90 deletions
+47 -51
View File
@@ -646,74 +646,70 @@ class TestCase:
ignore_uninit=False,
name_retry: Callable[[str], str] | None = None
) -> Tuple[bool, str]:
trace = None
try:
trace = self.controller.DebugVertex(vtx, inst, idx, max(0, view))
with self.debug_vertex(vtx, inst, idx, max(0, view)) as debug:
ctx = f"vertex {vtx} (idx {idx}) instance {inst}"
if view >= 0:
ctx += f" view {view}"
ctx = f"vertex {vtx} (idx {idx}) instance {inst}"
if view >= 0:
ctx += f" view {view}"
if debug.trace.debugger is None:
raise TestFailureException(f"Couldn't debug {ctx}")
if trace.debugger is None:
raise TestFailureException(f"Couldn't debug {ctx}")
cycles, variables = self.process_trace(debug.trace)
cycles, variables = self.process_trace(trace)
postvs_vtx = vtx
if single_postvs:
postvs_vtx = 0
postvs_vtx = vtx
if single_postvs:
postvs_vtx = 0
for var in debug.trace.sourceVars:
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
name = var.name
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() 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}")
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 = 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)")
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])
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]
# 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")
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')
log.success(f'Successfully debugged vertex {ctx} in {cycles} cycles')
except TestFailureException as ex:
if not fatal:
return False, ex.message
raise ex
finally:
if trace is not None:
self.controller.FreeTrace(trace)
return True, ""
def run(self):
@@ -100,48 +100,47 @@ class D3D12_Shader_DebugData_Zoo(rdtest.TestCase):
if pipe.GetShaderReflection(rd.ShaderStage.Vertex).debugInfo.debuggable:
# Debug the vertex shader
instId = 1
trace = self.controller.DebugVertex(0, instId, 0, 0)
cycles, variables = self.process_trace(trace)
output = self.find_output_source_var(trace, rd.ShaderBuiltin.Undefined, 1)
assert output is not None
debugged = self.evaluate_source_var(output, variables)
actual = debugged.value.u32v[0]
expected = instId
if not rdtest.value_compare(actual, expected):
failed = True
rdtest.log.error(
f"Vertex shader TRIANGLE output did not match expectation {actual} != {expected}")
if not failed:
rdtest.log.success("Basic VS debugging was successful")
# Look for MAT0 variable in the trace initial source variables
matched = True
varsToCheck: List[Tuple[str, str, rdtest.ScalarOrVectorValue]] = []
varsToCheck.append((f"MAT0[0]", "float4", [1.0, 2.0, 3.0, 4.0]))
varsToCheck.append((f"MAT0[1]", "float4", [5.0, 6.0, 7.0, 8.0]))
varsToCheck.append((f"MAT0[2]", "float4", [9.0, 10.0, 11.0, 12.0]))
for name, varType, expectedValue in varsToCheck:
debuggedValue = None
try:
debuggedValue = self.get_source_shader_var_value(trace.sourceVars, name, varType, variables)
except KeyError as ex:
matched = False
failed = True
except rdtest.TestFailureException as ex:
matched = False
with self.debug_vertex(0, instId, 0, 0) as debug:
cycles, variables = self.process_trace(debug.trace)
output = self.find_output_source_var(debug.trace, rd.ShaderBuiltin.Undefined, 1)
assert output is not None
debugged = self.evaluate_source_var(output, variables)
actual = debugged.value.u32v[0]
expected = instId
if not rdtest.value_compare(actual, expected):
failed = True
rdtest.log.error(
f"Vertex shader TRIANGLE output did not match expectation {actual} != {expected}")
if debuggedValue is None:
raise rdtest.TestFailureException(f"Couldn't find source variable {name} type:{varType}")
if not rdtest.value_compare(expectedValue, debuggedValue):
matched = False
failed = True
rdtest.log.error(f"'{name}' {varType} debugger {debuggedValue} doesn't match expected {expectedValue}")
if not failed:
rdtest.log.success("Basic VS debugging was successful")
self.controller.FreeTrace(trace)
if matched:
rdtest.log.success("VS MAT0 output source variable matched as expected")
# Look for MAT0 variable in the trace initial source variables
matched = True
varsToCheck: List[Tuple[str, str, rdtest.ScalarOrVectorValue]] = []
varsToCheck.append((f"MAT0[0]", "float4", [1.0, 2.0, 3.0, 4.0]))
varsToCheck.append((f"MAT0[1]", "float4", [5.0, 6.0, 7.0, 8.0]))
varsToCheck.append((f"MAT0[2]", "float4", [9.0, 10.0, 11.0, 12.0]))
for name, varType, expectedValue in varsToCheck:
debuggedValue = None
try:
debuggedValue = self.get_source_shader_var_value(debug.trace.sourceVars, name, varType, variables)
except KeyError as ex:
matched = False
failed = True
except rdtest.TestFailureException as ex:
matched = False
failed = True
if debuggedValue is None:
raise rdtest.TestFailureException(f"Couldn't find source variable {name} type:{varType}")
if not rdtest.value_compare(expectedValue, debuggedValue):
matched = False
failed = True
rdtest.log.error(f"'{name}' {varType} debugger {debuggedValue} doesn't match expected {expectedValue}")
if matched:
rdtest.log.success("VS MAT0 output source variable matched as expected")
else:
rdtest.log.print(f"Ignoring undebuggable Vertex shader at {action.eventId} for {shaderModels[sm]}.")