mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-25 17:01:35 +00:00
struct TestGrand
{
int3 i3;
int2 i2;
};
struct TestParent : TestGrand
{
int4 i4;
};
struct TestChild : TestParent
{
int i;
};
480 lines
14 KiB
C++
480 lines
14 KiB
C++
/******************************************************************************
|
|
* 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;
|
|
};
|
|
|
|
struct TestGrand
|
|
{
|
|
int3 i3;
|
|
int2 i2;
|
|
};
|
|
|
|
struct TestParent : TestGrand
|
|
{
|
|
int4 i4;
|
|
};
|
|
|
|
struct TestChild : TestParent
|
|
{
|
|
int i;
|
|
};
|
|
|
|
)EOSHADER";
|
|
|
|
std::string testsBody = R"EOSHADER(
|
|
|
|
TestStruct testStruct;
|
|
TestChild testChild;
|
|
|
|
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_SET(int, testChild.i, 1)
|
|
TEST_DEBUG_VAR_SET(int2, testChild.i2, 2)
|
|
TEST_DEBUG_VAR_SET(int3, testChild.i3, 3)
|
|
TEST_DEBUG_VAR_SET(int4, testChild.i4, 4)
|
|
// 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 if(testIndex == 4)
|
|
{
|
|
testResult.x = intVal * 7;
|
|
testResult.y = intVal * 5;
|
|
SET_DATA(testIndex, testResult);
|
|
EARLY_RETURN;
|
|
}
|
|
else if(testIndex == 5)
|
|
{
|
|
testResult.x = testChild.i;
|
|
testResult.y = testChild.i2.x;
|
|
testResult.z = testChild.i3.y;
|
|
testResult.w = testChild.i4.z;
|
|
}
|
|
else
|
|
{
|
|
testResult = 0.4f;
|
|
}
|
|
|
|
USE_DEBUG_VECTOR_TYPE(int);
|
|
USE_DEBUG_VECTOR_TYPE(float);
|
|
)EOSHADER";
|
|
|
|
std::string pixel = R"EOSHADER(
|
|
|
|
#define SET_DATA(INDEX, DATA)
|
|
#define EARLY_RETURN return testResult
|
|
#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(
|
|
|
|
RWStructuredBuffer<float4> bufOut : register(u0);
|
|
|
|
void SetOutput(uint index, float4 data)
|
|
{
|
|
bufOut[index] = data;
|
|
}
|
|
|
|
#define SET_DATA(INDEX, DATA) SetOutput(INDEX, DATA)
|
|
#define EARLY_RETURN return
|
|
#define TEST_INDEX inTestIndex
|
|
)EOSHADER" + testDefines +
|
|
R"EOSHADER(
|
|
|
|
[numthreads(1,1,1)]
|
|
void main(int inTestIndex: SV_GroupID)
|
|
{
|
|
int __ONE = floor(inTestIndex/(inTestIndex+1.0e-6f)) + 1;
|
|
)EOSHADER" + testsBody +
|
|
R"EOSHADER(
|
|
|
|
SetOutput(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();
|