Files
renderdoc/util/test/tests/Vulkan/VK_Parameter_Zoo.py
T
baldurk 2a0989ba9a Use local helper function for setting current EID
* This lets the testcase track the current EID and print it when a failure
  happens
2026-09-11 19:19:27 +01:00

335 lines
13 KiB
Python

from typing import Dict
import renderdoc as rd
import rdtest
class VK_Parameter_Zoo(rdtest.TestCase):
demos_test_name = 'VK_Parameter_Zoo'
def check_capture(self):
assert self.controller is not None
if not self.validate_eventids(self.controller):
raise rdtest.TestFailureException("Event IDs are not valid")
action = self.find_action("Color Draw")
assert action is not None
action = action.nextAction
self.set_event(action.eventId, False)
pipe = self.controller.GetPipelineState()
self.check_pixel_value(pipe.GetOutputTargets()[0].resource, 0.5, 0.5, [0.0, 1.0, 0.0, 1.0])
# Readback reported extension support
descriptor_update_template = self.find_action("KHR_descriptor_update_template") is not None
push_descriptor = self.find_action("KHR_push_descriptor") is not None
# Find the action that contains resource references
action = self.find_action("References")
assert action is not None
action = action.nextAction
self.set_event(action.eventId, False)
vkpipe = self.controller.GetVulkanPipelineState()
res_names: Dict[rd.ResourceId, str] = {}
for res in self.controller.GetResources():
res_names[res.resourceId] = res.name
expected_binds = [
{
'sampname': 'refsamp'
},
{
'resname': 'refcombinedimg',
'sampname': 'refcombinedsamp'
},
{
'resname': 'refsampled'
},
{
'resname': 'refstorage'
},
{
'resname': 'refunitexel'
},
{
'resname': 'refstoretexel'
},
{
'resname': 'refunibuf'
},
{
'resname': 'refstorebuf'
},
{
'resname': 'refunibufdyn'
},
{
'resname': 'refstorebufdyn'
},
]
setidx = 0
for descset in vkpipe.graphics.descriptorSets:
if setidx == 2 and not descset.pushDescriptor:
raise rdtest.TestFailureException(f"Expected set {setidx} to be a push set")
if setidx != 2 and descset.pushDescriptor:
raise rdtest.TestFailureException(f"Expected set {setidx} to be a non-push set")
range = rd.DescriptorRange()
range.offset = 0
# push descriptors don't include dynamic descriptors so don't fetch those
range.count = len([
e for e in expected_binds
if ('sampname' in e or not descset.pushDescriptor or 'dyn' not in e['resname'])
])
range.descriptorSize = 1
descs = self.controller.GetDescriptors(descset.descriptorSetResourceId, [range])
samps = self.controller.GetSamplerDescriptors(descset.descriptorSetResourceId, [range])
for bindidx, (desc, samp) in enumerate(zip(descs, samps)):
sampname = res_names.get(samp.object, '!' + str(setidx))
resname = res_names.get(desc.resource, '!' + str(setidx))
expected_samp = expected_binds[bindidx].get('sampname', '!') + str(setidx)
expected_res = expected_binds[bindidx].get('resname', '!') + str(setidx)
if not sampname == expected_samp:
raise rdtest.TestFailureException(
f"Expected binding {bindidx} in set {setidx} to have sampler {expected_samp} but got {sampname}")
if not resname == expected_res:
raise rdtest.TestFailureException(
f"Expected binding {bindidx} in set {setidx} to have resource {expected_res} but got {resname}")
rdtest.log.success(f"Resources in set {setidx} were found as expected")
setidx = setidx + 1
# Since we can only have one push descriptor set we have a second action for push AND template updates
if descriptor_update_template and push_descriptor:
action = self.find_action("PushTemplReferences")
assert action is not None
action = action.nextAction
self.set_event(action.eventId, False)
vkpipe = self.controller.GetVulkanPipelineState()
descset = vkpipe.graphics.descriptorSets[2]
if not descset.pushDescriptor:
raise rdtest.TestFailureException("Expected set 2 to be a push set")
range = rd.DescriptorRange()
range.offset = 0
# push descriptors don't include dynamic descriptors so don't fetch those
range.count = len([
e for e in expected_binds
if ('sampname' in e or not descset.pushDescriptor or 'dyn' not in e['resname'])
])
range.descriptorSize = 1
descs = self.controller.GetDescriptors(descset.descriptorSetResourceId, [range])
samps = self.controller.GetSamplerDescriptors(descset.descriptorSetResourceId, [range])
for bindidx, (desc, samp) in enumerate(zip(descs, samps)):
sampname = res_names.get(samp.object, '!' + str(setidx))
resname = res_names.get(desc.resource, '!' + str(setidx))
expected_samp = expected_binds[bindidx].get('sampname', '!') + str(setidx)
expected_res = expected_binds[bindidx].get('resname', '!') + str(setidx)
if not sampname == expected_samp:
raise rdtest.TestFailureException(
f"Expected binding {bindidx} in set {setidx} to have sampler {expected_samp} but got {sampname}")
if not resname == expected_res:
raise rdtest.TestFailureException(
f"Expected binding {bindidx} in set {setidx} to have resource {expected_res} but got {resname}")
rdtest.log.success("Resources in push template set were found as expected")
rdtest.log.success("All resources were found as expected")
action = self.find_action("Tools available")
assert len(action.children) > 1
assert any([d.customName == 'RenderDoc' for d in action.children])
rdtest.log.success("RenderDoc tool was listed as available")
for variant in [1, 2]:
action = self.find_action(f"ASM Draw {variant}")
assert action is not None
action = action.nextAction
assert action is not None
self.set_event(action.eventId, False)
pipe = self.controller.GetPipelineState()
ro = pipe.GetReadOnlyResources(rd.ShaderStage.Vertex)
access = pipe.GetDescriptorAccess()
self.check_eq(len(ro), 1)
if not (rd.DescriptorType.Image, 0, 1) in [(a.type, a.index, a.arrayElement) for a in access]:
raise rdtest.TestFailureException(
f"Graphics bind 0[1] isn't the accessed descriptor {rd.DumpObject(access)!s}")
vkpipe = self.controller.GetVulkanPipelineState()
assert len(vkpipe.viewportScissor.viewportScissors) == 0
postvs_data = self.get_postvs(action, rd.MeshDataStage.VSOut, 0, action.numIndices)
postvs_ref: rdtest.MeshReference = {
0: {
'vtx': 0,
'idx': 0,
'_Position': [-1.0, 1.0, 0.0, 1.0],
},
1: {
'vtx': 1,
'idx': 1,
'_Position': [1.0, 1.0, 0.0, 1.0],
},
2: {
'vtx': 2,
'idx': 2,
'_Position': [-1.0, -1.0, 0.0, 1.0],
},
3: {
'vtx': 3,
'idx': 3,
'_Position': [1.0, -1.0, 0.0, 1.0],
},
}
self.check_mesh_data(postvs_ref, postvs_data)
rdtest.log.success(f"ASM Draw {variant} is as expected")
inline_ubo_actions = [
self.find_action("Inline UBO Draw"),
self.find_action("Inline UBO + Templ Draw"),
self.find_action("Inline UBO + Templ Dyn Draw"),
]
action = self.find_action("Inline UBO Draw")
for action in inline_ubo_actions:
if action is None:
continue
rdtest.log.print(f"Checking {action.customName}")
self.set_event(action.nextAction.eventId, False)
self.check_triangle(fore=[1.0, 0.0, 1.0, 1.0])
stage = rd.ShaderStage.Pixel
pipe = self.controller.GetPipelineState()
ubo1 = pipe.GetConstantBlock(stage, 0, 0).descriptor
ubo2 = pipe.GetConstantBlock(stage, 1, 0).descriptor
ubo1_vars = self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(),
pipe.GetShader(
stage), stage,
pipe.GetShaderEntryPoint(
stage), 0,
ubo1.resource, ubo1.byteOffset, ubo1.byteSize)
ubo2_vars = self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(),
pipe.GetShader(
stage), stage,
pipe.GetShaderEntryPoint(
stage), 1,
ubo2.resource, ubo2.byteOffset, ubo2.byteSize)
if len(ubo1_vars) != 1 or ubo1_vars[0].name != "col":
raise rdtest.TestFailureException("Didn't find ubo1 col variable")
if len(ubo2_vars) != 1 or ubo2_vars[0].name != "col":
raise rdtest.TestFailureException("Didn't find ubo2 col variable")
if ubo1_vars[0].value.f32v[0:4] != (1.0, 0.0, 0.0, 0.0):
raise rdtest.TestFailureException(f"ubo1 col value incorrect: {ubo1_vars[0].value.f32v[0:4]}")
if ubo2_vars[0].value.f32v[0:4] != (0.0, 0.0, 1.0, 1.0):
raise rdtest.TestFailureException(f"ubo2 col value incorrect: {ubo2_vars[0].value.f32v[0:4]}")
rdtest.log.success(f"{action.customName} is as expected")
action = self.find_action("Immutable Draw")
assert action is not None
action = action.nextAction
self.set_event(action.eventId, False)
pipe = self.controller.GetPipelineState()
ro = pipe.GetReadOnlyResources(rd.ShaderStage.Fragment)
if len(ro) != 1:
raise rdtest.TestFailureException("Expected only one resource to be used")
if ro[0].sampler.filter.minify != rd.FilterMode.Linear:
raise rdtest.TestFailureException("Expected linear sampler at binding slot 0 in immutable action")
if self.get_resource(ro[0].descriptor.secondary).name != "validSampler":
raise rdtest.TestFailureException("Expected validSampler to be at binding slot 0 in immutable action")
rdtest.log.success("Immutable Draw is as expected")
sdfile = self.controller.GetStructuredFile()
# Check for resource leaks
if len(sdfile.chunks) > 500:
raise rdtest.TestFailureException(f"Too many chunks found: {len(sdfile.chunks)}")
action = self.find_action("before_empty")
action = self.get_action(action.eventId + 1)
a = action.GetName(sdfile)
# vkQueueSubmit with two submits each with zero command buffers
assert "vkQueueSubmit(" in action.GetName(sdfile)
assert "No Command Buffers" in action.GetName(sdfile)
action = self.get_action(action.eventId + 1)
assert "vkQueueSubmit(" in action.GetName(sdfile)
assert "No Command Buffers" in action.GetName(sdfile)
# vkQueueSubmit with zero submits
action = self.get_action(action.eventId + 1)
assert "vkQueueSubmit()" in action.GetName(sdfile)
assert "No Submit" in action.GetName(sdfile)
action = self.get_action(action.eventId + 1)
if "after_empty" not in action.GetName(sdfile):
# vkQueueSubmit2 with one submit with zero command buffers
assert "vkQueueSubmit2(" in action.GetName(sdfile)
assert "No Command Buffers" in action.GetName(sdfile)
assert a != action.GetName(sdfile)
# vkQueueSubmit with zero submits
action = self.get_action(action.eventId + 1)
assert "vkQueueSubmit2()" in action.GetName(sdfile)
assert "No Submit" in action.GetName(sdfile)
rdtest.log.success("Empty queue submits are as expected")
action = self.find_action("Dynamic Array Draw")
action = action.nextAction
self.set_event(action.eventId, False)
self.check_triangle()
rdtest.log.success("Dynamic Array Draw is as expected")