mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-11-13 17:30:12 +00:00
324 lines
15 KiB
Python
324 lines
15 KiB
Python
import renderdoc as rd
|
|
import rdtest
|
|
import struct
|
|
|
|
class D3D12_Shader_Debug_Zoo(rdtest.TestCase):
|
|
demos_test_name = 'D3D12_Shader_Debug_Zoo'
|
|
slow_test = True
|
|
|
|
def check_compute_derivative_tests(self):
|
|
failed = False
|
|
thread_checks = [
|
|
(0,0,0),
|
|
(1,1,0),
|
|
(2,2,0),
|
|
(3,3,0),
|
|
(4,2,0),
|
|
(5,1,0),
|
|
(6,0,0),
|
|
(7,1,0),
|
|
]
|
|
compute_dims = [a for a in self.find_action(
|
|
"Compute Derivative Tests").children if 'x' in a.customName]
|
|
for comp_dim in compute_dims:
|
|
section = f"Compute tests with {comp_dim.customName}"
|
|
rdtest.log.begin_section(section)
|
|
|
|
compute_tests = [
|
|
a for a in comp_dim.children if a.flags & rd.ActionFlags.Dispatch]
|
|
|
|
for test, action in enumerate(compute_tests):
|
|
self.set_event(action.eventId, False)
|
|
pipe = self.controller.GetPipelineState()
|
|
csrefl = pipe.GetShaderReflection(rd.ShaderStage.Compute)
|
|
|
|
rw = pipe.GetReadWriteResources(rd.ShaderStage.Compute)
|
|
if len(rw) != 1:
|
|
rdtest.log.error("Unexpected number of RW resources")
|
|
failed = True
|
|
continue
|
|
|
|
groupid = (1, 0, 0)
|
|
dim = csrefl.dispatchThreadsDimension
|
|
|
|
# Debug the shader
|
|
for threadid in thread_checks:
|
|
tid = ( min(threadid[0], dim[0]-1), min(threadid[1], dim[1]-1), min(threadid[2], dim[2]-1))
|
|
# each test writes up to 16k data, one vec4 per thread * up to 1024 threads
|
|
bufdata = self.controller.GetBufferData(
|
|
rw[0].descriptor.resource, test * 16 * 1024, 16 * 1024
|
|
)
|
|
try:
|
|
expectedValue = struct.unpack_from(
|
|
"4f", bufdata, 16*tid[1]*dim[0] + 16*tid[0])
|
|
except Exception as ex:
|
|
rdtest.log.error(f"Exception Test {test} failed {ex}")
|
|
failed = True
|
|
continue
|
|
|
|
# Debug the shader
|
|
with self.debug_thread(groupid, tid) as debug:
|
|
cycles, variables = self.process_trace(debug.trace)
|
|
|
|
# Find the source variable 'testResult' at the highest instruction index
|
|
name = 'testResult'
|
|
debugged = None
|
|
countInst = len(debug.trace.instInfo)
|
|
for inst in range(countInst):
|
|
sourceVars = debug.trace.instInfo[countInst-1-inst].sourceVars
|
|
try:
|
|
dataVars = [v for v in sourceVars if v.name == name]
|
|
if len(dataVars) == 0:
|
|
continue
|
|
debugged = self.evaluate_source_var(dataVars[0], variables)
|
|
except KeyError as ex:
|
|
continue
|
|
except rdtest.TestFailureException as ex:
|
|
continue
|
|
break
|
|
if debugged is None:
|
|
raise rdtest.TestFailureException(f"Couldn't find source variable {name} at {test}")
|
|
debuggedValue = list(debugged.value.f32v[0:4])
|
|
|
|
if not rdtest.value_compare(expectedValue, debuggedValue, eps=5.0E-06):
|
|
rdtest.log.error(f"Test {test} Group:{groupid} Thread:{tid} EID:{action.eventId} failed {name} debugger {debuggedValue} doesn't match expected {expectedValue}")
|
|
failed = True
|
|
continue
|
|
|
|
rdtest.log.success(f"Test {test} Group:{groupid} Thread:{tid} as expected")
|
|
|
|
rdtest.log.end_section(section)
|
|
return failed
|
|
|
|
def check_capture(self):
|
|
undefined_tests = [int(test) for test in self.find_action("Undefined tests: ").customName.split(" ")[2:]]
|
|
|
|
failed = False
|
|
|
|
shaderModels = [
|
|
"sm_5_0", "sm_5_1", "sm_6_0", "sm_6_2", "sm_6_6",
|
|
"sm_5_0_opt", "sm_5_1_opt", "sm_6_0_opt", "sm_6_2_opt", "sm_6_6_opt",
|
|
]
|
|
for j in range(2):
|
|
for sm in range(len(shaderModels)):
|
|
sectionName = shaderModels[sm] + " tests"
|
|
|
|
# Jump to the action
|
|
markerName = shaderModels[sm]
|
|
instId = 10
|
|
if j == 0:
|
|
markerName = "NoResources " + markerName
|
|
sectionName = "NoResources " + sectionName
|
|
instId = 2
|
|
|
|
with rdtest.log.auto_section(sectionName):
|
|
test_marker = self.find_action(markerName)
|
|
if (test_marker is None):
|
|
rdtest.log.print(f"Skipping Graphics tests for {sectionName}")
|
|
continue
|
|
action = test_marker.nextAction
|
|
assert action is not None
|
|
self.set_event(action.eventId, False)
|
|
|
|
pipe = self.controller.GetPipelineState()
|
|
|
|
postvs = self.get_postvs(action, rd.MeshDataStage.VSOut, instance=instId)
|
|
|
|
success, err = self.check_vertex_debug(0, 0, instId, postvs, fatal=False)
|
|
if not success:
|
|
failed = True
|
|
rdtest.log.error(f"Basic VS debugging didn't match: {err}")
|
|
continue
|
|
else:
|
|
rdtest.log.success("Basic VS debugging was successful")
|
|
|
|
# Loop over every test
|
|
for test in range(action.numInstances):
|
|
# Debug the shader
|
|
with self.debug_pixel(4 * test, 0, rd.DebugPixelInputs()) as debug:
|
|
cycles, variables = self.process_trace(debug.trace)
|
|
|
|
output = self.find_output_source_var(debug.trace, rd.ShaderBuiltin.ColorOutput, 0)
|
|
|
|
debugged = self.evaluate_source_var(output, variables)
|
|
|
|
try:
|
|
self.check_pixel_value(pipe.GetOutputTargets()[0].resource, 4 * test, 0, debugged.value.f32v[0:4])
|
|
except rdtest.TestFailureException as ex:
|
|
if test in undefined_tests:
|
|
rdtest.log.comment(f"Undefined test {test} did not match. {ex!s}")
|
|
else:
|
|
rdtest.log.error(f"Test {test} did not match. {ex!s}")
|
|
failed = True
|
|
continue
|
|
|
|
rdtest.log.success(f"Test {test} matched as expected")
|
|
|
|
rdtest.log.begin_section("MSAA tests")
|
|
|
|
# Enable MSAA tests when DXIL shader debugger supports MSAA instructions and SV_Barycentrics
|
|
msaaMarkers = [
|
|
"MSAA sm_5_0",
|
|
"MSAA sm_6_0",
|
|
"MSAA sm_6_1",
|
|
]
|
|
msaaMarkers = [
|
|
"MSAA sm_5_0",
|
|
]
|
|
for marker in msaaMarkers:
|
|
rdtest.log.begin_section(marker)
|
|
test_marker = self.find_action(marker)
|
|
action = test_marker.nextAction
|
|
self.set_event(action.eventId, False)
|
|
pipe = self.controller.GetPipelineState()
|
|
for (x,y) in [(4, 4), (4, 5), (3, 4), (3, 5)]:
|
|
for test in range(4):
|
|
# Debug the shader
|
|
inputs = rd.DebugPixelInputs()
|
|
inputs.sample = test
|
|
with self.debug_pixel(x, y, inputs) as debug:
|
|
# Validate that the correct sample index was debugged
|
|
sampRegister = self.find_input_source_var(debug.trace, rd.ShaderBuiltin.MSAASampleIndex)
|
|
sampInput = [var for var in debug.trace.inputs if var.name == sampRegister.variables[0].name][0]
|
|
if sampInput.value.u32v[0] != test:
|
|
rdtest.log.error(f"Test {test} did not pick the correct sample.")
|
|
|
|
cycles, variables = self.process_trace(debug.trace)
|
|
|
|
output = self.find_output_source_var(debug.trace, rd.ShaderBuiltin.ColorOutput, 0)
|
|
|
|
debugged = self.evaluate_source_var(output, variables)
|
|
|
|
# Validate the debug output result
|
|
try:
|
|
self.check_pixel_value(pipe.GetOutputTargets()[0].resource, x, y, debugged.value.f32v[0:4], sub=rd.Subresource(0, 0, test))
|
|
except rdtest.TestFailureException as ex:
|
|
failed = True
|
|
rdtest.log.error(f"Test {test} did not match. {ex!s}")
|
|
|
|
rdtest.log.end_section(marker)
|
|
|
|
rdtest.log.end_section("MSAA tests")
|
|
|
|
rdtest.log.begin_section("VertexSample tests")
|
|
shaderModels = ["sm_5_0", "sm_6_0", "sm_6_6"]
|
|
for sm in range(len(shaderModels)):
|
|
test_marker = self.find_action("VertexSample " + shaderModels[sm])
|
|
if test_marker is None:
|
|
rdtest.log.print(f"Skipping Vertex Sample tests for {shaderModels[sm]}")
|
|
continue
|
|
action = test_marker.nextAction
|
|
assert action is not None
|
|
self.set_event(action.eventId, False)
|
|
pipe = self.controller.GetPipelineState()
|
|
|
|
# Debug the vertex shader
|
|
success, err = self.check_vertex_debug(0, 0, 0, self.get_postvs(action, rd.MeshDataStage.VSOut), fatal=False)
|
|
if not success:
|
|
failed = True
|
|
rdtest.log.error(
|
|
f"{shaderModels[sm]} Vertex shader failed: {err}")
|
|
continue
|
|
else:
|
|
rdtest.log.success(shaderModels[sm] + " VertexSample VS was debugged correctly")
|
|
|
|
# Debug the pixel shader
|
|
inputs = rd.DebugPixelInputs()
|
|
inputs.sample = 0
|
|
with self.debug_pixel(51, 51, inputs) as debug:
|
|
cycles, variables = self.process_trace(debug.trace)
|
|
output = self.find_output_source_var(debug.trace, rd.ShaderBuiltin.ColorOutput, 0)
|
|
|
|
debugged = self.evaluate_source_var(output, variables)
|
|
|
|
# Validate the debug output result
|
|
try:
|
|
self.check_pixel_value(pipe.GetOutputTargets()[0].resource, 51, 51, debugged.value.f32v[0:4])
|
|
except rdtest.TestFailureException as ex:
|
|
failed = True
|
|
rdtest.log.error(f"Vertex sample pixel shader output did not match. {ex!s}")
|
|
|
|
rdtest.log.success("VertexSample PS was debugged correctly")
|
|
|
|
rdtest.log.end_section("VertexSample tests")
|
|
|
|
test_marker = self.find_action("Banned")
|
|
action = test_marker.nextAction
|
|
assert action is not None
|
|
self.set_event(action.eventId, False)
|
|
pipe = self.controller.GetPipelineState()
|
|
|
|
# Debug the banned vertex shader
|
|
self.check_vertex_debug(0, 0, 0, self.get_postvs(action, rd.MeshDataStage.VSOut), fatal=False)
|
|
|
|
# Debug the pixel shader
|
|
inputs = rd.DebugPixelInputs()
|
|
inputs.sample = 0
|
|
with self.debug_pixel(64, 64, inputs) as debug:
|
|
cycles, variables = self.process_trace(debug.trace)
|
|
|
|
output = self.find_output_source_var(debug.trace, rd.ShaderBuiltin.ColorOutput, 0)
|
|
|
|
debugged = self.evaluate_source_var(output, variables)
|
|
|
|
# Validate the debug output result
|
|
try:
|
|
self.check_pixel_value(pipe.GetOutputTargets()[0].resource, 64, 64, debugged.value.f32v[0:4])
|
|
except rdtest.TestFailureException as ex:
|
|
failed = True
|
|
rdtest.log.error(f"Vertex sample pixel shader output did not match. {ex!s}")
|
|
|
|
rdtest.log.success("Banned signature PS was debugged correctly")
|
|
|
|
csShaderModels = ["cs_5_0", "cs_6_0", "cs_6_6"]
|
|
for sm in range(len(csShaderModels)):
|
|
test = csShaderModels[sm]
|
|
section = test + " tests"
|
|
rdtest.log.begin_section(section)
|
|
|
|
# Jump to the action
|
|
test_marker = self.find_action(test)
|
|
if test_marker is None:
|
|
rdtest.log.print(f"Skipping Compute tests for {csShaderModels[sm]}")
|
|
rdtest.log.end_section(section)
|
|
continue
|
|
action = test_marker.nextAction
|
|
self.set_event(action.eventId, False)
|
|
pipe = self.controller.GetPipelineState()
|
|
|
|
# Debug the shader
|
|
for groupX in range(action.dispatchDimension[0]):
|
|
groupid = (groupX, 1, 0)
|
|
threadid = (0, 0, 0)
|
|
testIndex = groupX
|
|
with self.debug_thread(groupid, threadid) as debug:
|
|
cycles, variables = self.process_trace(debug.trace)
|
|
|
|
# Result is stored in RWStructuredBuffer<uint4> bufOut : register(u1);
|
|
bufOut = pipe.GetReadWriteResources(rd.ShaderStage.Compute)[1].descriptor.resource
|
|
bufdata = self.controller.GetBufferData(bufOut, testIndex*16, 16)
|
|
expectedValue = struct.unpack_from("4i", bufdata, 0)
|
|
# Test result is in variable called "int4 testResult"
|
|
name = 'testResult'
|
|
varType = 'int4'
|
|
try:
|
|
debuggedValue = self.get_source_shader_var_value(debug.trace.instInfo[-1].sourceVars, name, varType, variables)
|
|
if not rdtest.value_compare(expectedValue, debuggedValue):
|
|
raise rdtest.TestFailureException(f"'{name}' debugger {debuggedValue} doesn't match expected {expectedValue}")
|
|
|
|
except rdtest.TestFailureException as ex:
|
|
rdtest.log.error(f"Test {test} Group:{groupid} Thread:{threadid} Index:{testIndex} failed {ex}")
|
|
failed = True
|
|
continue
|
|
|
|
rdtest.log.success(f"Test {test} Group:{groupid} Thread:{threadid} as expected")
|
|
rdtest.log.end_section(section)
|
|
|
|
if self.check_compute_derivative_tests():
|
|
failed = True
|
|
|
|
if failed:
|
|
raise rdtest.TestFailureException("Some tests were not as expected")
|
|
|
|
rdtest.log.success("All tests matched")
|