mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 10:00:40 +00:00
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:
@@ -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();
|
||||
@@ -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" />
|
||||
|
||||
@@ -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")
|
||||
Reference in New Issue
Block a user