Skip to content

Commit f50c851

Browse files
committed
Unified Subgroup_Zoo VK and D3D12 python
Improved test failure reporting
1 parent fa9bc12 commit f50c851

File tree

4 files changed

+269
-473
lines changed

4 files changed

+269
-473
lines changed

util/test/rdtest/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
from .shared.Overlay_Test import *
1010
from .shared.Buffer_Truncation import *
1111
from .shared.Discard_Zoo import *
12+
from .shared.Subgroup_Zoo import *
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
import renderdoc as rd
2+
import struct
3+
import rdtest
4+
5+
# Not a real test, re-used by API-specific tests
6+
class Subgroup_Zoo(rdtest.TestCase):
7+
internal = True
8+
demos_test_name = None
9+
10+
def check_support(self, **kwargs):
11+
# Only allow this if explicitly run
12+
if kwargs['test_include'] == self.demos_test_name:
13+
return True, ''
14+
return False, 'Disabled test'
15+
16+
def check_capture(self):
17+
graphics_tests = [a for a in self.find_action(
18+
"Graphics Tests").children if a.flags & rd.ActionFlags.Drawcall]
19+
compute_dims = [a for a in self.find_action(
20+
"Compute Tests").children if 'x' in a.customName]
21+
22+
rdtest.log.begin_section("Graphics tests")
23+
24+
# instances to check in instanced draws
25+
inst_checks = [0, 1, 5, 10]
26+
# pixels to check
27+
pixel_checks = [
28+
# top quad
29+
(0, 0), (1, 0), (0, 1), (1, 1),
30+
# middle quad (away from triangle border)
31+
(64, 56), (65, 56), (64, 57), (65, 57),
32+
# middle quad (on triangle border)
33+
(64, 64), (65, 64), (64, 65), (65, 65),
34+
# middle quad on other triangle
35+
(56, 64), (57, 64), (56, 65), (57, 65),
36+
]
37+
# threads to check. largest dimension only (all small dim checked)
38+
thread_checks = [
39+
# first few
40+
0, 1, 2,
41+
# near end of 32-subgroup and boundary
42+
30, 31, 32,
43+
# near end of 64-subgroup and boundary
44+
62, 63, 64,
45+
# near end of 64-subgroup and boundary
46+
62, 63, 64,
47+
# large values spaced out with one near the end of our unaligned size
48+
100, 110, 120, 140, 149, 150, 160, 200, 250,
49+
]
50+
clear_col = (123456.0, 789.0, 101112.0, 0.0)
51+
52+
overallFailed = False
53+
for idx, action in enumerate(graphics_tests):
54+
failed = False
55+
self.controller.SetFrameEvent(action.eventId, False)
56+
57+
pipe = self.controller.GetPipelineState()
58+
59+
# check vertex output for every vertex
60+
for inst in [inst for inst in inst_checks if inst < action.numInstances]:
61+
for view in range(pipe.MultiviewBroadcastCount()):
62+
63+
postvs = self.get_postvs(
64+
action, rd.MeshDataStage.VSOut, first_index=0, num_indices=action.numIndices, instance=inst)
65+
66+
for vtx in range(action.numIndices):
67+
trace = self.controller.DebugVertex(
68+
vtx, inst, vtx, view)
69+
70+
if trace.debugger is None:
71+
self.controller.FreeTrace(trace)
72+
73+
rdtest.log.error(
74+
f"Test {idx} at {action.eventId} got no debug result at {vtx} inst {inst} view {view}")
75+
failed = True
76+
return
77+
78+
_, variables = self.process_trace(trace)
79+
80+
for var in trace.sourceVars:
81+
if var.name == 'vertdata':
82+
name = var.name
83+
84+
if var.name not in postvs[vtx].keys():
85+
rdtest.log.error(
86+
f"Don't have expected output for {var.name}")
87+
failed = True
88+
continue
89+
90+
real = postvs[vtx][name]
91+
debugged = self.evaluate_source_var(
92+
var, variables)
93+
94+
if debugged.columns != 4 or len(real) != 4:
95+
rdtest.log.error(
96+
f"Vertex output is not the right size ({len(real)} vs {debugged.columns})")
97+
failed = True
98+
continue
99+
100+
if not rdtest.value_compare(real, debugged.value.f32v[0:4], eps=5.0E-06):
101+
rdtest.log.error(
102+
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}")
103+
failed = True
104+
105+
self.controller.FreeTrace(trace)
106+
107+
# check some assorted pixel outputs
108+
target = pipe.GetOutputTargets()[0].resource
109+
110+
for pixel in pixel_checks:
111+
for view in range(pipe.MultiviewBroadcastCount()):
112+
x, y = pixel
113+
114+
picked = self.controller.PickPixel(
115+
target, x, y, rd.Subresource(0, 0, 0), rd.CompType.Float)
116+
117+
real = picked.floatValue
118+
119+
# silently skip pixels that weren't written to
120+
if real == clear_col:
121+
continue
122+
123+
inputs = rd.DebugPixelInputs()
124+
inputs.sample = 0
125+
inputs.primitive = rd.ReplayController.NoPreference
126+
inputs.view = view
127+
trace = self.controller.DebugPixel(x, y, inputs)
128+
129+
if trace.debugger is None:
130+
self.controller.FreeTrace(trace)
131+
rdtest.log.error(
132+
f"Test {idx} at {action.eventId} got no debug result at {x},{y}")
133+
failed = True
134+
continue
135+
136+
_, variables = self.process_trace(trace)
137+
138+
output_sourcevar = self.find_output_source_var(
139+
trace, rd.ShaderBuiltin.ColorOutput, 0)
140+
141+
if output_sourcevar is None:
142+
rdtest.log.error("No output variable found")
143+
failed = True
144+
continue
145+
146+
debugged = self.evaluate_source_var(
147+
output_sourcevar, variables)
148+
149+
self.controller.FreeTrace(trace)
150+
151+
debuggedValue = list(debugged.value.f32v[0:4])
152+
153+
if not rdtest.value_compare(real, debuggedValue, eps=5.0E-06):
154+
rdtest.log.error(
155+
f"Test {idx} at {action.eventId} debugged pixel value {debuggedValue} at {x},{y} in {view} does not match output {real}")
156+
failed = True
157+
158+
overallFailed |= failed
159+
if not failed:
160+
rdtest.log.success(f"Test {idx} successful")
161+
else:
162+
rdtest.log.error(f"Test {idx} failed")
163+
164+
rdtest.log.end_section("Graphics tests")
165+
166+
for comp_dim in compute_dims:
167+
rdtest.log.begin_section(
168+
f"Compute tests with {comp_dim.customName} workgroup")
169+
170+
compute_tests = [
171+
a for a in comp_dim.children if a.flags & rd.ActionFlags.Dispatch]
172+
173+
for test, action in enumerate(compute_tests):
174+
failed = False
175+
self.controller.SetFrameEvent(action.eventId, False)
176+
177+
pipe = self.controller.GetPipelineState()
178+
csrefl = pipe.GetShaderReflection(rd.ShaderStage.Compute)
179+
180+
dim = csrefl.dispatchThreadsDimension
181+
182+
rw = pipe.GetReadWriteResources(rd.ShaderStage.Compute)
183+
184+
if len(rw) != 1:
185+
rdtest.log.error("Unexpected number of RW resources")
186+
continue
187+
188+
# each test writes up to 16k data, one vec4 per thread * up to 1024 threads
189+
bufdata = self.controller.GetBufferData(
190+
rw[0].descriptor.resource, test*16*1024, 16*1024)
191+
192+
for t in thread_checks:
193+
xrange = 1
194+
yrange = dim[1]
195+
xbase = t
196+
ybase = 0
197+
198+
# vertical orientation
199+
if dim[1] > dim[0]:
200+
xrange = dim[0]
201+
yrange = 1
202+
xbase = 0
203+
ybase = t
204+
205+
for x in range(xbase, xbase+xrange):
206+
for y in range(ybase, ybase+yrange):
207+
z = 0
208+
209+
if x >= dim[0] or y >= dim[1]:
210+
continue
211+
212+
try:
213+
real = struct.unpack_from(
214+
"4f", bufdata, 16*y*dim[0] + 16*x)
215+
216+
trace = self.controller.DebugThread(
217+
(0, 0, 0), (x, y, z))
218+
219+
_, variables = self.process_trace(trace)
220+
221+
if trace.debugger is None:
222+
raise rdtest.TestFailureException(f"Test {test} at {action.eventId} got no debug result at {x},{y},{z}")
223+
224+
# Find the source variable 'data' at the highest instruction index
225+
debugged = None
226+
countInst = len(trace.instInfo)
227+
for inst in range(countInst):
228+
sourceVars = trace.instInfo[countInst-1-inst].sourceVars
229+
try:
230+
dataVars = [v for v in sourceVars if v.name == 'data']
231+
if len(dataVars) == 0:
232+
continue
233+
debugged = self.evaluate_source_var(dataVars[0], variables)
234+
except KeyError as ex:
235+
continue
236+
except rdtest.TestFailureException as ex:
237+
continue
238+
break
239+
if debugged is None:
240+
raise rdtest.TestFailureException(f"Couldn't find source variable {name}")
241+
242+
debuggedValue = list(debugged.value.f32v[0:4])
243+
244+
if not rdtest.value_compare(real, debuggedValue, eps=5.0E-06):
245+
raise rdtest.TestFailureException(f"EID:{action.eventId} TID:{x},{y},{z} debugged thread value {debuggedValue} does not match output {real}")
246+
247+
except rdtest.TestFailureException as ex:
248+
rdtest.log.error(f"Test {test} failed {ex}")
249+
failed = True
250+
continue
251+
finally:
252+
self.controller.FreeTrace(trace)
253+
254+
overallFailed |= failed
255+
if not failed:
256+
rdtest.log.success(f"Test {test} successful")
257+
else:
258+
rdtest.log.error(f"Test {test} failed")
259+
260+
rdtest.log.end_section(
261+
f"Compute tests with {comp_dim.customName} workgroup")
262+
263+
if overallFailed:
264+
raise rdtest.TestFailureException("Some tests were not as expected")

0 commit comments

Comments
 (0)