mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-11-13 09:20:13 +00:00
288 lines
14 KiB
Python
288 lines
14 KiB
Python
from typing import List, Tuple
|
|
|
|
import renderdoc as rd
|
|
import rdtest
|
|
import struct
|
|
|
|
class D3D12_Shader_DebugData_Zoo(rdtest.TestCase):
|
|
demos_test_name = 'D3D12_Shader_DebugData_Zoo'
|
|
|
|
def parse_shader_source(self, shaderSrcRaw: str, realTestResult: rdtest.VectorValue, test: int):
|
|
'''
|
|
// TEST_DEBUG_VAR_START
|
|
TEST_DEBUG_VAR_DECLARE(int, testIndex, TEST_INDEX)
|
|
TEST_DEBUG_VAR_DECLARE(int1, intVal, TEST_INDEX)
|
|
TEST_DEBUG_VAR_DECLARE(float4, testResult, TEST_RESULT)
|
|
TEST_DEBUG_VAR_DECLARE(int2, jake, 5)
|
|
TEST_DEBUG_VAR_DECLARE(float1, bob, 3.0)
|
|
TEST_DEBUG_VAR_USE(int4, testStruct.anon.a, 1)
|
|
TEST_DEBUG_VAR_DECLARE_MATRIX23(float, fish, 7.2)
|
|
// TEST_DEBUG_VAR_END
|
|
'''
|
|
varsToCheck: List[Tuple[str, str, rdtest.ScalarOrVectorValue]] = []
|
|
foundStart = False
|
|
foundEnd = False
|
|
shaderSrc = shaderSrcRaw.splitlines()
|
|
for line in shaderSrc:
|
|
line = line.strip()
|
|
if line.endswith('TEST_DEBUG_VAR_START'):
|
|
foundStart = True
|
|
continue
|
|
if line.endswith('TEST_DEBUG_VAR_END'):
|
|
foundEnd = True
|
|
break
|
|
if not foundStart:
|
|
continue
|
|
if not line.startswith('TEST_DEBUG_VAR_'):
|
|
continue
|
|
toks = line.split(',')
|
|
type = toks[0].split('(')[1].strip()
|
|
name = toks[1].strip()
|
|
valString = toks[2].split(')')[0].strip()
|
|
scalarType, countElems = self.parse_shader_var_type(type)
|
|
isMatrix23 = line.startswith('TEST_DEBUG_VAR_DECLARE_MATRIX23')
|
|
rows = 0
|
|
if isMatrix23:
|
|
rows = 2
|
|
columns = 3
|
|
countElems = columns # each row is its own variable
|
|
|
|
if valString == 'TEST_INDEX':
|
|
value = test
|
|
elif valString == 'TEST_RESULT':
|
|
value = realTestResult
|
|
else:
|
|
if scalarType == 'float':
|
|
scalarVal = float(valString)
|
|
elif scalarType == 'int':
|
|
scalarVal = int(valString)
|
|
else:
|
|
raise rdtest.TestFailureException(f"Unhandled scalarType {scalarType} {type}")
|
|
value = [scalarVal] * countElems
|
|
|
|
if not isMatrix23:
|
|
var = (name, type, value)
|
|
varsToCheck.append(var)
|
|
else:
|
|
for row in range(rows):
|
|
var = (f"{name}.row{row}", f"{type}3", value)
|
|
varsToCheck.append(var)
|
|
|
|
if not foundStart or not foundEnd:
|
|
raise rdtest.TestFailureException("Couldn't find TEST_DEBUG_VAR_START and TEST_DEBUG_VAR_END")
|
|
|
|
return varsToCheck
|
|
|
|
def check_capture(self):
|
|
failed = False
|
|
|
|
shaderModels = [
|
|
"sm_6_0",
|
|
]
|
|
for sm in range(len(shaderModels)):
|
|
rdtest.log.begin_section(shaderModels[sm] + " tests")
|
|
|
|
# Jump to the action
|
|
test_marker = self.find_action(shaderModels[sm])
|
|
if (test_marker is None):
|
|
rdtest.log.print(f"Skipping Graphics tests for {shaderModels[sm]}")
|
|
rdtest.log.end_section(shaderModels[sm] + " tests")
|
|
continue
|
|
action = test_marker.nextAction
|
|
self.set_event(action.eventId, False)
|
|
|
|
pipe = self.controller.GetPipelineState()
|
|
|
|
# Debug the vertex shader
|
|
instId = 1
|
|
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)
|
|
|
|
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(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")
|
|
|
|
# Loop over every test
|
|
for test in range(action.numInstances):
|
|
# Debug the shader
|
|
with self.debug_pixel(4 * test, 0, rd.DebugPixelInputs()) as debug:
|
|
trace = debug.trace
|
|
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:
|
|
tex = pipe.GetOutputTargets()[0].resource
|
|
x = 4 * test
|
|
y = 0
|
|
self.check_pixel_value(tex, x, y, debugged.value.f32v[0:4])
|
|
picked = rd.PixelValue = self.pick_pixel(tex, x, y, rd.Subresource(0,0,0), rd.CompType.Typeless)
|
|
realTestResult = picked.floatValue
|
|
debugInfo = pipe.GetShaderReflection(rd.ShaderStage.Pixel).debugInfo
|
|
shaderSrcRaw = debugInfo.files[0].contents
|
|
varsToCheck = self.parse_shader_source(shaderSrcRaw, realTestResult, test)
|
|
for name, varType, expectedValue in varsToCheck:
|
|
debuggedValue = None
|
|
countInst = len(debug.trace.instInfo)
|
|
for inst in range(countInst):
|
|
sourceVars = debug.trace.instInfo[countInst-1-inst].sourceVars
|
|
try:
|
|
debuggedValue = self.get_source_shader_var_value(sourceVars, name, varType, variables)
|
|
except KeyError as ex:
|
|
continue
|
|
except rdtest.TestFailureException as ex:
|
|
continue
|
|
break
|
|
if debuggedValue is None:
|
|
raise rdtest.TestFailureException(f"Couldn't find source variable {name} type:{varType}")
|
|
if not rdtest.value_compare(expectedValue, debuggedValue):
|
|
raise rdtest.TestFailureException(f"'{name}' {varType} debugger {debuggedValue} doesn't match expected {expectedValue}")
|
|
|
|
rdtest.log.success(f"{len(varsToCheck)} source variables matched as expected")
|
|
|
|
# Look for _IN.MAT0 variable in the trace input variables
|
|
name = "_IN"
|
|
inVar = [v for v in debug.trace.inputs if v.name == name]
|
|
if len(inVar) != 1:
|
|
raise rdtest.TestFailureException(f"Couldn't find source input variable {name}")
|
|
name = "MAT0"
|
|
inVar = [v for v in inVar[0].members if v.name == name]
|
|
if len(inVar) != 1:
|
|
raise rdtest.TestFailureException(f"Couldn't find source input member {name}")
|
|
|
|
matched = True
|
|
varsToCheck = []
|
|
varsToCheck.append((f"[0]", "float4", [1.0, 2.0, 3.0, 4.0]))
|
|
varsToCheck.append((f"[1]", "float4", [5.0, 6.0, 7.0, 8.0]))
|
|
varsToCheck.append((f"[2]", "float4", [9.0, 10.0, 11.0, 12.0]))
|
|
for name, varType, expectedValue in varsToCheck:
|
|
assert isinstance(expectedValue, list)
|
|
debuggedValue = None
|
|
for v in inVar[0].members:
|
|
if v.name == name:
|
|
try:
|
|
debuggedValue = v.value.f32v[0:len(expectedValue)]
|
|
except rdtest.TestFailureException as ex:
|
|
matched = False
|
|
failed = True
|
|
break
|
|
|
|
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("PS MAT0 input source variable matched as expected")
|
|
|
|
except rdtest.TestFailureException as ex:
|
|
rdtest.log.error(f"Test {test} failed {ex}")
|
|
failed = True
|
|
continue
|
|
|
|
rdtest.log.success(f"Test {test} matched as expected")
|
|
|
|
rdtest.log.end_section(shaderModels[sm] + " tests")
|
|
|
|
csShaderModels = ["cs_6_0"]
|
|
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()
|
|
|
|
# Loop over every test
|
|
for test in range(action.dispatchDimension[0]):
|
|
# Debug the shader
|
|
groupid = (test,0,0)
|
|
threadid = (0,0,0)
|
|
with self.debug_thread(groupid, threadid) as debug:
|
|
cycles, variables = self.process_trace(debug.trace)
|
|
|
|
# Result is stored in RWStructuredBuffer<float4> bufOut : register(u0);
|
|
bufOut = pipe.GetReadWriteResources(rd.ShaderStage.Compute)[0].descriptor.resource
|
|
bufdata = self.controller.GetBufferData(bufOut, test*16, 16)
|
|
realTestResult = struct.unpack_from("4f", bufdata, 0)
|
|
debugInfo = pipe.GetShaderReflection(rd.ShaderStage.Compute).debugInfo
|
|
shaderSrcRaw = debugInfo.files[0].contents
|
|
varsToCheck = self.parse_shader_source(shaderSrcRaw, realTestResult, test)
|
|
try:
|
|
for name, varType, expectedValue in varsToCheck:
|
|
debuggedValue = None
|
|
countInst = len(debug.trace.instInfo)
|
|
for inst in range(countInst):
|
|
sourceVars = debug.trace.instInfo[countInst-1-inst].sourceVars
|
|
try:
|
|
debuggedValue = self.get_source_shader_var_value(sourceVars, name, varType, variables)
|
|
except KeyError as ex:
|
|
continue
|
|
except rdtest.TestFailureException as ex:
|
|
continue
|
|
break
|
|
if debuggedValue is None:
|
|
raise rdtest.TestFailureException(f"Couldn't find source variable {name} type:{varType}")
|
|
if not rdtest.value_compare(expectedValue, debuggedValue):
|
|
raise rdtest.TestFailureException(f"'{name}' {varType} debugger {debuggedValue} doesn't match expected {expectedValue}")
|
|
rdtest.log.success(f"{len(varsToCheck)} source variables matched as expected")
|
|
|
|
except rdtest.TestFailureException as ex:
|
|
rdtest.log.error(f"Test {test} failed {ex}")
|
|
failed = True
|
|
continue
|
|
|
|
rdtest.log.success(f"Test {test} matched as expected")
|
|
|
|
rdtest.log.end_section(section)
|
|
|
|
if failed:
|
|
raise rdtest.TestFailureException("Some tests were not as expected")
|
|
|
|
rdtest.log.success("All tests matched")
|