Add d3d12_shader_debugdata_zoo test

Similar to d3d12_shader_debug_zoo but instead of verifying debugger simulation accuracy used to verify debug data is parsed and present

Supports SM6.0 and the DXIL debugger - verifies debug data in pixel and compute shaders
This commit is contained in:
Jake Turner
2025-03-01 17:07:45 +00:00
parent 5120723135
commit 9cac526d49
4 changed files with 646 additions and 0 deletions
@@ -0,0 +1,435 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2025 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "d3d12_test.h"
RD_TEST(D3D12_Shader_DebugData_Zoo, D3D12GraphicsTest)
{
static constexpr const char *Description = "Tests shader debug data from different sources";
struct ConstsA2V
{
Vec3f pos;
};
std::string pixelBlit = R"EOSHADER(
cbuffer rootconsts : register(b0)
{
float offset;
}
Texture2D<float4> intex : register(t0);
float4 main(float4 pos : SV_Position) : SV_Target0
{
return intex.Load(float3(pos.x, pos.y - offset, 0));
}
)EOSHADER";
std::string common = R"EOSHADER(
struct consts
{
float3 pos : POSITION;
};
struct v2f
{
float4 pos : SV_POSITION;
uint tri : TRIANGLE;
uint intval : INTVAL;
};
)EOSHADER";
std::string vertex = R"EOSHADER(
v2f main(consts IN, uint tri : SV_InstanceID)
{
v2f OUT = (v2f)0;
OUT.pos = float4(IN.pos.x + IN.pos.z * float(tri), IN.pos.y, 0.0f, 1);
OUT.tri = tri;
OUT.intval = tri + 11;
return OUT;
}
)EOSHADER";
std::string testDefines = R"EOSHADER(
#define TEST_RESULT 0
#define TEST_DEBUG_TYPE(TYPE) TYPE __test_ ## TYPE = 0;
#define TEST_DEBUG_VECTOR_TYPE(TYPE) \
TEST_DEBUG_TYPE(TYPE) \
TEST_DEBUG_TYPE(TYPE ## 1) \
TEST_DEBUG_TYPE(TYPE ## 2) \
TEST_DEBUG_TYPE(TYPE ## 3) \
TEST_DEBUG_TYPE(TYPE ## 4)
#define USE_DEBUG_VECTOR_TYPE(TYPE) \
testResult.x += __test_ ## TYPE .x; \
testResult.x += __test_ ## TYPE ## 1 .x; \
testResult.xy += __test_ ## TYPE ## 2 .xy; \
testResult.xyz += __test_ ## TYPE ## 3 .xyz; \
testResult.xyzw += __test_ ## TYPE ## 4 .xyzw;
#define TEST_DEBUG_VAR_SET(TYPE, VAR, VALUE) \
VAR = VALUE * __ONE; \
__test_ ## TYPE += VAR;
#define TEST_DEBUG_VAR_DECLARE(TYPE, VAR, VALUE) TYPE VAR; TEST_DEBUG_VAR_SET(TYPE, VAR, VALUE)
struct TestStruct
{
struct
{
int4 a;
int3 b;
} anon;
};
)EOSHADER";
std::string testsBody = R"EOSHADER(
TestStruct testStruct;
TEST_DEBUG_VECTOR_TYPE(int);
TEST_DEBUG_VECTOR_TYPE(float);
// 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_SET(int4, testStruct.anon.a, 1)
TEST_DEBUG_VAR_SET(int3, testStruct.anon.b, 2)
// TEST_DEBUG_VAR_END
if(testIndex == 0)
{
testResult = intVal;
}
else if(testIndex == 1)
{
testResult = intVal * 2;
}
else if(testIndex == 2)
{
testResult = intVal / 2;
}
else if(testIndex == 3)
{
testResult.x = testStruct.anon.a.x;
testResult.y = testStruct.anon.b.x;
}
else
{
testResult = 0.4f;
}
USE_DEBUG_VECTOR_TYPE(int);
USE_DEBUG_VECTOR_TYPE(float);
)EOSHADER";
std::string pixel = R"EOSHADER(
#define TEST_INDEX IN.tri
)EOSHADER" + testDefines +
R"EOSHADER(
float4 main(v2f IN) : SV_Target0
{
int __ONE = floor((IN.intval - 11)/(IN.tri+1.0e-6f)) + 1;
)EOSHADER" + testsBody +
R"EOSHADER(
return testResult;
}
)EOSHADER";
std::string compute = R"EOSHADER(
#define TEST_INDEX inTestIndex
)EOSHADER" + testDefines +
R"EOSHADER(
RWStructuredBuffer<float4> bufOut : register(u0);
[numthreads(1,1,1)]
void main(int inTestIndex: SV_GroupID)
{
int __ONE = floor(inTestIndex/(inTestIndex+1.0e-6f)) + 1;
)EOSHADER" + testsBody +
R"EOSHADER(
bufOut[testIndex] = testResult;
}
)EOSHADER";
void Prepare(int argc, char **argv)
{
D3D12GraphicsTest::Prepare(argc, argv);
if(!Avail.empty())
return;
bool supportSM60 = (m_HighestShaderModel >= D3D_SHADER_MODEL_6_0) && m_DXILSupport;
if(!supportSM60)
Avail = "Shader Model 6.0 and DXIL is not supported";
}
int main()
{
// initialise, create window, create device, etc
if(!Init())
return 3;
const char *testMatch = NULL;
size_t lastTest = 0;
testMatch = "testIndex == ";
lastTest = pixel.rfind(testMatch);
lastTest += strlen(testMatch);
const uint32_t numPSTests = atoi(pixel.c_str() + lastTest) + 1;
lastTest = compute.rfind(testMatch);
lastTest += strlen(testMatch);
const uint32_t numCSTests = atoi(compute.c_str() + lastTest) + 1;
TEST_ASSERT(numPSTests == numCSTests,
"Mismatched number of tests between pixel and compute shaders");
std::vector<D3D12_INPUT_ELEMENT_DESC> inputLayout;
inputLayout.reserve(4);
inputLayout.push_back({
"POSITION",
0,
DXGI_FORMAT_R32G32B32_FLOAT,
0,
0,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
0,
});
D3D12_STATIC_SAMPLER_DESC staticSamp = {};
staticSamp.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
staticSamp.AddressU = staticSamp.AddressV = staticSamp.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
staticSamp.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
ID3D12RootSignaturePtr sig =
MakeSig({}, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, 1, &staticSamp);
const int numShaderModels = 1; // 6.0
ID3D12PipelineStatePtr psos[numShaderModels] = {};
uint32_t compileOptions = CompileOptionFlags::None;
std::string shaderDefines = "";
{
ID3DBlobPtr vsblob = Compile(common + vertex, "main", "vs_6_0");
psos[0] = MakePSO()
.RootSig(sig)
.InputLayout(inputLayout)
.VS(vsblob)
.PS(Compile(common + "\n#define SM_6_0 1\n" + shaderDefines + pixel, "main",
"ps_6_0", compileOptions | CompileOptionFlags::SkipOptimise))
.RTVs({DXGI_FORMAT_R32G32B32A32_FLOAT});
psos[0]->SetName(L"ps_6_0");
}
static const uint32_t texDim = AlignUp(numPSTests, 64U) * 4;
ID3D12ResourcePtr fltTex = MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, texDim, 4)
.RTV()
.InitialState(D3D12_RESOURCE_STATE_RENDER_TARGET);
D3D12_CPU_DESCRIPTOR_HANDLE fltRTV = MakeRTV(fltTex).CreateCPU(0);
D3D12_GPU_DESCRIPTOR_HANDLE fltSRV = MakeSRV(fltTex).CreateGPU(8);
float triWidth = 8.0f / float(texDim);
ConstsA2V triangle[] = {
{Vec3f(-1.0f, -1.0f, triWidth)},
{Vec3f(-1.0f, 1.0f, triWidth)},
{Vec3f(-1.0f + triWidth, 1.0f, triWidth)},
};
ID3D12ResourcePtr vb = MakeBuffer().Data(triangle);
ResourceBarrier(vb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
ID3D12RootSignaturePtr blitSig = MakeSig({
constParam(D3D12_SHADER_VISIBILITY_PIXEL, 0, 0, 1),
tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 0, 1, 8),
});
ID3D12PipelineStatePtr blitpso = MakePSO()
.RootSig(blitSig)
.VS(Compile(D3DFullscreenQuadVertex, "main", "vs_4_0"))
.PS(Compile(pixelBlit, "main", "ps_5_0"));
const uint32_t renderDataSize = sizeof(float) * 22;
// Create resources for compute shader
const uint32_t computeDataStart = AlignUp(renderDataSize, 1024U);
ID3D12RootSignaturePtr sigCompute = MakeSig({
tableParam(D3D12_SHADER_VISIBILITY_ALL, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, 0, 2),
});
const uint32_t countComputeSMs = 1;
ID3D12PipelineStatePtr computePSOs[countComputeSMs] = {NULL};
std::string computeSMs[countComputeSMs] = {"cs_6_0"};
ID3DBlobPtr csblob =
Compile(compute, "main", "cs_6_0", compileOptions | CompileOptionFlags::SkipOptimise);
computePSOs[0] = MakePSO().RootSig(sigCompute).CS(csblob);
const uint32_t uavSize = AlignUp(numCSTests, 1024U);
ID3D12ResourcePtr bufOut = MakeBuffer().Size(uavSize).UAV();
bufOut->SetName(L"bufOut");
D3D12_GPU_DESCRIPTOR_HANDLE bufOutGPU =
MakeUAV(bufOut).Format(DXGI_FORMAT_R32G32B32A32_FLOAT).CreateGPU(computeDataStart + 0);
D3D12_CPU_DESCRIPTOR_HANDLE bufOutClearCPU =
MakeUAV(bufOut).Format(DXGI_FORMAT_R32G32B32A32_FLOAT).CreateClearCPU(computeDataStart + 0);
{
D3D12_CPU_DESCRIPTOR_HANDLE cpu = m_CBVUAVSRV->GetCPUDescriptorHandleForHeapStart();
cpu.ptr += dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) * 0;
D3D12_UNORDERED_ACCESS_VIEW_DESC uavdesc = {};
uavdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
uavdesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uavdesc.Buffer.NumElements = numCSTests;
dev->CreateUnorderedAccessView(bufOut, NULL, &uavdesc, cpu);
}
std::vector<float> bufOutInitData;
bufOutInitData.resize(uavSize);
for(uint32_t i = 0; i < uavSize; ++i)
{
bufOutInitData[i] = 222.0f + i / 4.0f;
}
D3D12_RECT uavClearRect = {};
uavClearRect.right = uavSize;
uavClearRect.bottom = 1;
while(Running())
{
ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer();
Reset(cmd);
ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);
D3D12_CPU_DESCRIPTOR_HANDLE rtv =
MakeRTV(bb).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(2);
ClearRenderTargetView(cmd, rtv, {0.2f, 0.2f, 0.2f, 1.0f});
float blitOffsets[] = {0.0f};
D3D12_RECT scissors[] = {
{0, 0, (int)texDim, 4},
};
const char *markers[] = {
"sm_6_0",
};
static_assert(ARRAY_COUNT(blitOffsets) == ARRAY_COUNT(psos), "mismatched array dimension");
static_assert(ARRAY_COUNT(scissors) == ARRAY_COUNT(psos), "mismatched array dimension");
static_assert(ARRAY_COUNT(markers) == ARRAY_COUNT(psos), "mismatched array dimension");
// Clear, draw, and blit to backbuffer
size_t countGraphicsPasses = 1;
TEST_ASSERT(countGraphicsPasses <= ARRAY_COUNT(psos), "More graphic passes than psos");
pushMarker(cmd, "Pixel");
for(size_t i = 0; i < countGraphicsPasses; ++i)
{
OMSetRenderTargets(cmd, {fltRTV}, {});
ClearRenderTargetView(cmd, fltRTV, {0.2f, 0.2f, 0.2f, 1.0f});
IASetVertexBuffer(cmd, vb, sizeof(ConstsA2V), 0);
cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cmd->SetGraphicsRootSignature(sig);
cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr());
cmd->SetPipelineState(psos[i]);
RSSetViewport(cmd, {0.0f, 0.0f, (float)texDim, 4.0f, 0.0f, 1.0f});
RSSetScissorRect(cmd, {0, 0, (int)texDim, 4});
// Add a marker so we can easily locate this draw
setMarker(cmd, markers[i]);
cmd->DrawInstanced(3, numPSTests, 0, 0);
ResourceBarrier(cmd, fltTex, D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
OMSetRenderTargets(cmd, {rtv}, {});
RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f});
RSSetScissorRect(cmd, scissors[i]);
cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
cmd->SetGraphicsRootSignature(blitSig);
cmd->SetPipelineState(blitpso);
cmd->SetGraphicsRoot32BitConstant(0, *(UINT *)&blitOffsets[i], 0);
cmd->SetGraphicsRootDescriptorTable(1, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart());
cmd->DrawInstanced(4, 1, 0, 0);
ResourceBarrier(cmd, fltTex, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET);
}
FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET);
popMarker(cmd);
pushMarker(cmd, "Compute");
size_t countComputePasses = 1;
TEST_ASSERT(countComputePasses <= ARRAY_COUNT(computePSOs), "More compute passes than psos");
for(size_t i = 0; i < countComputePasses; ++i)
{
cmd->ClearUnorderedAccessViewFloat(bufOutGPU, bufOutClearCPU, bufOut, bufOutInitData.data(),
1, &uavClearRect);
cmd->SetComputeRootSignature(sigCompute);
cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr());
cmd->SetComputeRootDescriptorTable(0, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart());
cmd->SetPipelineState(computePSOs[i]);
setMarker(cmd, computeSMs[i]);
cmd->Dispatch(numCSTests, 1, 1);
}
popMarker(cmd);
cmd->Close();
Submit({cmd});
Present();
}
return 0;
}
};
REGISTER_TEST();
+1
View File
@@ -214,6 +214,7 @@
<ClCompile Include="d3d12\d3d12_resource_lifetimes.cpp" />
<ClCompile Include="d3d12\d3d12_resource_mapping_zoo.cpp" />
<ClCompile Include="d3d12\d3d12_rtas_zoo.cpp" />
<ClCompile Include="d3d12\d3d12_shader_debugdata_zoo.cpp" />
<ClCompile Include="d3d12\d3d12_shader_debug_zoo.cpp" />
<ClCompile Include="d3d12\d3d12_shader_editing.cpp" />
<ClCompile Include="d3d12\d3d12_shader_isa.cpp" />
+3
View File
@@ -709,6 +709,9 @@
<ClCompile Include="d3d11\d3d11_groupshared.cpp">
<Filter>D3D11\demos</Filter>
</ClCompile>
<ClCompile Include="d3d12\d3d12_shader_debugdata_zoo.cpp">
<Filter>D3D12\demos</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="D3D11">
@@ -0,0 +1,207 @@
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, realTestResult, test):
'''
// 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_END
'''
varsToCheck = []
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)
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
var = (name, type, 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):
if not self.controller.GetAPIProperties().shaderDebugging:
rdtest.log.success("Shader debugging not enabled, skipping test")
return
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: rd.ActionDescription = 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.next
self.controller.SetFrameEvent(action.eventId, False)
pipe: rd.PipeState = self.controller.GetPipelineState()
if pipe.GetShaderReflection(rd.ShaderStage.Vertex).debugInfo.debuggable:
# Debug the vertex shader
instId = 1
trace: rd.ShaderDebugTrace = self.controller.DebugVertex(0, instId, 0, 0)
cycles, variables = self.process_trace(trace)
output = self.find_output_source_var(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")
else:
rdtest.log.print(f"Ignoring undebuggable Vertex shader at {action.eventId} for {shaderModels[sm]}.")
if not pipe.GetShaderReflection(rd.ShaderStage.Pixel).debugInfo.debuggable:
rdtest.log.print(f"Skipping undebuggable Pixel shader at {action.eventId} for {shaderModels[sm]}.")
rdtest.log.end_section(shaderModels[sm] + " tests")
continue
# Loop over every test
for test in range(action.numInstances):
# Debug the shader
trace: rd.ShaderDebugTrace = self.controller.DebugPixel(4 * test, 0, rd.DebugPixelInputs())
cycles, variables = self.process_trace(trace)
output = self.find_output_source_var(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.controller.PickPixel(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 = self.get_source_shader_var_value(trace.instInfo[-1].sourceVars, name, varType, variables)
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
finally:
self.controller.FreeTrace(trace)
rdtest.log.success("Test {} matched as expected".format(test))
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: rd.ActionDescription = 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.next
self.controller.SetFrameEvent(action.eventId, False)
pipe: rd.PipeState = self.controller.GetPipelineState()
if not pipe.GetShaderReflection(rd.ShaderStage.Compute).debugInfo.debuggable:
rdtest.log.print(f"Skipping undebuggable Compute shader at {action.eventId} for {csShaderModels[sm]}.")
rdtest.log.end_section(section)
continue
# Loop over every test
for test in range(action.dispatchDimension[0]):
# Debug the shader
groupid = (test,0,0)
threadid = (0,0,0)
trace: rd.ShaderDebugTrace = self.controller.DebugThread(groupid, threadid)
cycles, variables = self.process_trace(trace)
# Check for non-zero cycles
if cycles == 0:
rdtest.log.error("Shader debug cycle count was zero")
failed = True
continue
# 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 = self.get_source_shader_var_value(trace.instInfo[-1].sourceVars, name, varType, variables)
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
finally:
self.controller.FreeTrace(trace)
rdtest.log.success("Test {} matched as expected".format(test))
rdtest.log.end_section(section)
if failed:
raise rdtest.TestFailureException("Some tests were not as expected")
rdtest.log.success("All tests matched")