From 033a4d1e5ab2efcccfca2895d22de711caac3e2e Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Wed, 7 May 2025 08:55:12 +0100 Subject: [PATCH] First version of python for *_Groupshared tests Verify outval shader debugger variable matches the real generated data in outBuf --- util/test/demos/d3d11/d3d11_groupshared.cpp | 2 + util/test/demos/d3d12/d3d12_groupshared.cpp | 2 + util/test/demos/vk/vk_groupshared.cpp | 2 + util/test/rdtest/__init__.py | 1 + util/test/rdtest/shared/Groupshared.py | 114 ++++++++++++++++++++ util/test/tests/D3D11/D3D11_Groupshared.py | 5 + util/test/tests/D3D12/D3D12_Groupshared.py | 5 + util/test/tests/Vulkan/VK_Groupshared.py | 5 + 8 files changed, 136 insertions(+) create mode 100644 util/test/rdtest/shared/Groupshared.py create mode 100644 util/test/tests/D3D11/D3D11_Groupshared.py create mode 100644 util/test/tests/D3D12/D3D12_Groupshared.py create mode 100644 util/test/tests/Vulkan/VK_Groupshared.py diff --git a/util/test/demos/d3d11/d3d11_groupshared.cpp b/util/test/demos/d3d11/d3d11_groupshared.cpp index e30f94b4c..54a06dae9 100644 --- a/util/test/demos/d3d11/d3d11_groupshared.cpp +++ b/util/test/demos/d3d11/d3d11_groupshared.cpp @@ -100,7 +100,9 @@ void main(uint3 tid : SV_GroupThreadID) ctx->CSSetUnorderedAccessViews(0, 1, &inUAV.GetInterfacePtr(), NULL); ctx->CSSetUnorderedAccessViews(1, 1, &outUAV.GetInterfacePtr(), NULL); + pushMarker("Compute Tests"); ctx->Dispatch(1, 1, 1); + popMarker(); Present(); } diff --git a/util/test/demos/d3d12/d3d12_groupshared.cpp b/util/test/demos/d3d12/d3d12_groupshared.cpp index 944084782..55c1c6e9c 100644 --- a/util/test/demos/d3d12/d3d12_groupshared.cpp +++ b/util/test/demos/d3d12/d3d12_groupshared.cpp @@ -129,6 +129,7 @@ void main(uint3 tid : SV_GroupThreadID) cmd->SetComputeRootUnorderedAccessView(0, inBuf->GetGPUVirtualAddress()); cmd->SetComputeRootUnorderedAccessView(1, outBuf->GetGPUVirtualAddress()); + pushMarker(cmd, "Compute Tests"); setMarker(cmd, "SM5"); cmd->SetPipelineState(pso50); cmd->Dispatch(1, 1, 1); @@ -141,6 +142,7 @@ void main(uint3 tid : SV_GroupThreadID) cmd->SetPipelineState(pso60); cmd->Dispatch(1, 1, 1); } + popMarker(cmd); FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); diff --git a/util/test/demos/vk/vk_groupshared.cpp b/util/test/demos/vk/vk_groupshared.cpp index 8a6ff29f8..f04cefdec 100644 --- a/util/test/demos/vk/vk_groupshared.cpp +++ b/util/test/demos/vk/vk_groupshared.cpp @@ -149,7 +149,9 @@ void main() vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, {descSet}, {}); vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + pushMarker(cmd, "Compute Tests"); vkCmdDispatch(cmd, 1, 1, 1); + popMarker(cmd); FinishUsingBackbuffer(cmd); diff --git a/util/test/rdtest/__init__.py b/util/test/rdtest/__init__.py index 54f816fb3..3233e5cf5 100644 --- a/util/test/rdtest/__init__.py +++ b/util/test/rdtest/__init__.py @@ -11,3 +11,4 @@ from .shared.Buffer_Truncation import * from .shared.Discard_Zoo import * from .shared.Subgroup_Zoo import * from .shared.Workgroup_Zoo import * +from .shared.Groupshared import * diff --git a/util/test/rdtest/shared/Groupshared.py b/util/test/rdtest/shared/Groupshared.py new file mode 100644 index 000000000..c461c36e7 --- /dev/null +++ b/util/test/rdtest/shared/Groupshared.py @@ -0,0 +1,114 @@ +import renderdoc as rd +import struct +import rdtest + +class Groupshared(rdtest.TestCase): + internal = True + demos_test_name = None + + def check_support(self, **kwargs): + # Only allow this if explicitly run + if kwargs['test_include'] == self.demos_test_name: + return True, '' + return False, 'Disabled test' + + def check_compute_thread_result(self, test, action, x, y, z, dim, bufdata): + try: + real = struct.unpack_from("4f", bufdata, 16*x) + + workgroup = (0, 0, 0) + trace = self.controller.DebugThread(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 'outval' at the highest instruction index + name = 'outval' + 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, action): + overallFailed = False + tests = [a for a in action.children if a.flags & rd.ActionFlags.Dispatch] + + for test, action in enumerate(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) != 2: + rdtest.log.error("Unexpected number of RW resources") + return False + + outBuf = rw[1].descriptor.resource + # each test writes up to one vec4 per thread * up to 64 threads + maxThreads = 64 + dataPerThread = 4 * 4 + dataPerTest = dataPerThread * maxThreads + bufdata = self.controller.GetBufferData(outBuf, test*dataPerTest, dataPerTest) + + for x in range(dim[0]): + y = 0 + z = 0 + 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"Tests at EID {action.eventId} successful") + else: + rdtest.log.error(f"Tests at EID {action.eventId} failed") + + return overallFailed + + def check_capture(self): + overallFailed = False + + action = self.find_action("Compute Tests") + sectionName = action.customName + rdtest.log.begin_section(sectionName) + overallFailed |= self.check_compute_tests(action) + rdtest.log.end_section(sectionName) + + if overallFailed: + raise rdtest.TestFailureException("Some tests were not as expected") + + self.check_renderdoc_log_asserts() + + rdtest.log.success("All tests matched") \ No newline at end of file diff --git a/util/test/tests/D3D11/D3D11_Groupshared.py b/util/test/tests/D3D11/D3D11_Groupshared.py new file mode 100644 index 000000000..ba41198bf --- /dev/null +++ b/util/test/tests/D3D11/D3D11_Groupshared.py @@ -0,0 +1,5 @@ +import rdtest + +class D3D11_Groupshared(rdtest.Groupshared): + internal = False + demos_test_name = 'D3D11_Groupshared' diff --git a/util/test/tests/D3D12/D3D12_Groupshared.py b/util/test/tests/D3D12/D3D12_Groupshared.py new file mode 100644 index 000000000..7e0be49f1 --- /dev/null +++ b/util/test/tests/D3D12/D3D12_Groupshared.py @@ -0,0 +1,5 @@ +import rdtest + +class D3D12_Groupshared(rdtest.Groupshared): + internal = False + demos_test_name = 'D3D12_Groupshared' diff --git a/util/test/tests/Vulkan/VK_Groupshared.py b/util/test/tests/Vulkan/VK_Groupshared.py new file mode 100644 index 000000000..5f7e5db7f --- /dev/null +++ b/util/test/tests/Vulkan/VK_Groupshared.py @@ -0,0 +1,5 @@ +import rdtest + +class VK_Groupshared(rdtest.Groupshared): + internal = False + demos_test_name = 'VK_Groupshared'