mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-17 19:25:39 +00:00
* These were available for python 3.6 too so was never any reason not to use them except not being aware they existed.
278 lines
11 KiB
Python
278 lines
11 KiB
Python
import renderdoc as rd
|
|
import struct
|
|
import rdtest
|
|
|
|
# Not a real test, re-used by API-specific tests
|
|
class Subgroup_Zoo(rdtest.TestCase):
|
|
internal = True
|
|
demos_test_name = None
|
|
workgroup = (0, 0, 0)
|
|
|
|
def check_compute_thread_result(self, test, action, x, y, z, dim, bufdata):
|
|
try:
|
|
real = struct.unpack_from(
|
|
"4f", bufdata, 16*y*dim[0] + 16*x)
|
|
except Exception as ex:
|
|
rdtest.log.error(f"Exception Test {test} failed {ex}")
|
|
return False
|
|
|
|
try:
|
|
trace = self.controller.DebugThread(self.workgroup, (x, y, z))
|
|
|
|
_, variables = self.process_trace(trace)
|
|
|
|
if trace.debugger is None:
|
|
raise rdtest.TestFailureException(f"Test {test} at {action.eventId} got no debug result at {x},{y},{z}")
|
|
|
|
# Find the source variable 'testResult' at the highest instruction index
|
|
name = 'testResult'
|
|
debugged = None
|
|
countInst = len(trace.instInfo)
|
|
for inst in range(countInst):
|
|
sourceVars = 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 {x},{y},{z}")
|
|
|
|
debuggedValue = list(debugged.value.f32v[0:4])
|
|
|
|
if not rdtest.value_compare(real, debuggedValue, eps=5.0E-06):
|
|
raise rdtest.TestFailureException(f"EID:{action.eventId} TID:{x},{y},{z} debugged thread value {debuggedValue} does not match output {real}")
|
|
|
|
except rdtest.TestFailureException as ex:
|
|
rdtest.log.error(f"Test {test} failed {ex}")
|
|
return False
|
|
finally:
|
|
self.controller.FreeTrace(trace)
|
|
|
|
return True
|
|
|
|
def check_compute_tests(self, compute_dims, thread_checks):
|
|
overallFailed = False
|
|
for comp_dim in compute_dims:
|
|
rdtest.log.begin_section(
|
|
f"Compute tests with {comp_dim.customName} workgroup")
|
|
|
|
compute_tests = [
|
|
a for a in comp_dim.children if a.flags & rd.ActionFlags.Dispatch]
|
|
|
|
for test, action in enumerate(compute_tests):
|
|
failed = False
|
|
self.controller.SetFrameEvent(action.eventId, False)
|
|
|
|
pipe = self.controller.GetPipelineState()
|
|
csrefl = pipe.GetShaderReflection(rd.ShaderStage.Compute)
|
|
|
|
dim = csrefl.dispatchThreadsDimension
|
|
|
|
rw = pipe.GetReadWriteResources(rd.ShaderStage.Compute)
|
|
|
|
if len(rw) != 1:
|
|
rdtest.log.error("Unexpected number of RW resources")
|
|
continue
|
|
|
|
# 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)
|
|
|
|
for t in thread_checks:
|
|
xrange = 1
|
|
yrange = dim[1]
|
|
xbase = t
|
|
ybase = 0
|
|
|
|
# vertical orientation
|
|
if dim[1] > dim[0]:
|
|
xrange = dim[0]
|
|
yrange = 1
|
|
xbase = 0
|
|
ybase = t
|
|
|
|
for x in range(xbase, xbase+xrange):
|
|
for y in range(ybase, ybase+yrange):
|
|
z = 0
|
|
|
|
if x >= dim[0] or y >= dim[1]:
|
|
continue
|
|
|
|
if not self.check_compute_thread_result(test, action, x, y, z, dim, bufdata):
|
|
failed = True
|
|
|
|
overallFailed |= failed
|
|
if not failed:
|
|
rdtest.log.success(f"Test {test} successful")
|
|
else:
|
|
rdtest.log.error(f"Test {test} failed")
|
|
|
|
rdtest.log.end_section(
|
|
f"Compute tests with {comp_dim.customName} workgroup")
|
|
|
|
return overallFailed
|
|
|
|
def check_capture(self):
|
|
graphics_tests = [a for a in self.find_action(
|
|
"Graphics Tests").children if a.flags & rd.ActionFlags.Drawcall]
|
|
|
|
rdtest.log.begin_section("Graphics tests")
|
|
|
|
# instances to check in instanced draws
|
|
inst_checks = [0, 1, 5, 10]
|
|
# pixels to check
|
|
pixel_checks = [
|
|
# top quad
|
|
(0, 0), (1, 0), (0, 1), (1, 1),
|
|
# middle quad (away from triangle border)
|
|
(64, 56), (65, 56), (64, 57), (65, 57),
|
|
# middle quad (on triangle border)
|
|
(64, 64), (65, 64), (64, 65), (65, 65),
|
|
# middle quad on other triangle
|
|
(56, 64), (57, 64), (56, 65), (57, 65),
|
|
]
|
|
clear_col = (123456.0, 789.0, 101112.0, 0.0)
|
|
|
|
overallFailed = False
|
|
for idx, action in enumerate(graphics_tests):
|
|
failed = False
|
|
self.controller.SetFrameEvent(action.eventId, False)
|
|
|
|
pipe = self.controller.GetPipelineState()
|
|
|
|
# check vertex output for every vertex
|
|
for inst in [inst for inst in inst_checks if inst < action.numInstances]:
|
|
for view in range(pipe.MultiviewBroadcastCount()):
|
|
|
|
postvs = self.get_postvs(
|
|
action, rd.MeshDataStage.VSOut, first_index=0, num_indices=action.numIndices, instance=inst)
|
|
|
|
for vtx in range(action.numIndices):
|
|
trace = self.controller.DebugVertex(
|
|
vtx, inst, vtx, view)
|
|
|
|
if trace.debugger is None:
|
|
self.controller.FreeTrace(trace)
|
|
|
|
rdtest.log.error(
|
|
f"Test {idx} at {action.eventId} got no debug result at {vtx} inst {inst} view {view}")
|
|
failed = True
|
|
continue
|
|
|
|
_, variables = self.process_trace(trace)
|
|
|
|
for var in trace.sourceVars:
|
|
if var.name == 'vertdata':
|
|
name = var.name
|
|
|
|
if var.name not in postvs[vtx].keys():
|
|
rdtest.log.error(
|
|
f"Don't have expected output for {var.name}")
|
|
failed = True
|
|
continue
|
|
|
|
real = postvs[vtx][name]
|
|
debugged = self.evaluate_source_var(
|
|
var, variables)
|
|
|
|
if debugged.columns != 4 or len(real) != 4:
|
|
rdtest.log.error(
|
|
f"Vertex output is not the right size ({len(real)} vs {debugged.columns})")
|
|
failed = True
|
|
continue
|
|
|
|
if not rdtest.value_compare(real, debugged.value.f32v[0:4], eps=5.0E-06):
|
|
rdtest.log.error(
|
|
f"Test {idx} at {action.eventId} debugged vertex value {debugged.value.f32v[0:4]} at {vtx} instance {inst} view {view} does not match output {real}")
|
|
failed = True
|
|
|
|
self.controller.FreeTrace(trace)
|
|
|
|
# check some assorted pixel outputs
|
|
target = pipe.GetOutputTargets()[0].resource
|
|
|
|
for pixel in pixel_checks:
|
|
for view in range(pipe.MultiviewBroadcastCount()):
|
|
x, y = pixel
|
|
|
|
picked = self.controller.PickPixel(
|
|
target, x, y, rd.Subresource(0, 0, 0), rd.CompType.Float)
|
|
|
|
real = picked.floatValue
|
|
|
|
# silently skip pixels that weren't written to
|
|
if real == clear_col:
|
|
continue
|
|
|
|
inputs = rd.DebugPixelInputs()
|
|
inputs.sample = 0
|
|
inputs.primitive = rd.ReplayController.NoPreference
|
|
inputs.view = view
|
|
trace = self.controller.DebugPixel(x, y, inputs)
|
|
|
|
if trace.debugger is None:
|
|
self.controller.FreeTrace(trace)
|
|
rdtest.log.error(
|
|
f"Test {idx} at {action.eventId} got no debug result at {x},{y}")
|
|
failed = True
|
|
continue
|
|
|
|
_, variables = self.process_trace(trace)
|
|
|
|
output_sourcevar = self.find_output_source_var(
|
|
trace, rd.ShaderBuiltin.ColorOutput, 0)
|
|
|
|
if output_sourcevar is None:
|
|
rdtest.log.error("No output variable found")
|
|
failed = True
|
|
continue
|
|
|
|
debugged = self.evaluate_source_var(
|
|
output_sourcevar, variables)
|
|
|
|
self.controller.FreeTrace(trace)
|
|
|
|
debuggedValue = list(debugged.value.f32v[0:4])
|
|
|
|
if not rdtest.value_compare(real, debuggedValue, eps=5.0E-06):
|
|
rdtest.log.error(
|
|
f"Test {idx} at {action.eventId} debugged pixel value {debuggedValue} at {x},{y} in {view} does not match output {real}")
|
|
failed = True
|
|
|
|
overallFailed |= failed
|
|
if not failed:
|
|
rdtest.log.success(f"Test {idx} successful")
|
|
else:
|
|
rdtest.log.error(f"Test {idx} failed")
|
|
|
|
rdtest.log.end_section("Graphics tests")
|
|
|
|
# threads to check. largest dimension only (all small dim checked)
|
|
thread_checks = [
|
|
# first few
|
|
0, 1, 2,
|
|
# near end of 32-subgroup and boundary
|
|
30, 31, 32, 33, 34,
|
|
# near end of 64-subgroup and boundary
|
|
62, 63, 64, 64, 65,
|
|
# large values spaced out with one near the end of our unaligned size
|
|
100, 110, 120, 140, 149, 150, 160, 200, 250,
|
|
]
|
|
compute_dims = [a for a in self.find_action(
|
|
"Compute Tests").children if 'x' in a.customName]
|
|
|
|
overallFailed |= self.check_compute_tests(compute_dims, thread_checks)
|
|
|
|
if overallFailed:
|
|
raise rdtest.TestFailureException("Some tests were not as expected")
|
|
|
|
self.check_renderdoc_log_asserts()
|
|
|
|
rdtest.log.success("All tests matched")
|