Extend D3D12_EXECUTE_INDIRECT test for partial update of root constants

Change colour of triangle based on root constant values set by direct API not by indirect API.
This allows verification that RenderDoc replay of indirect root constants does not alter values set by the direct API
This commit is contained in:
Jake Turner
2025-07-23 17:33:03 +01:00
parent c4ab650a63
commit a8ee82bfe8
2 changed files with 95 additions and 12 deletions
@@ -48,14 +48,23 @@ cbuffer test : register(b0)
float4 cbtest[5];
}
cbuffer rootConsts : register(b1)
{
float4 rootConsts;
}
StructuredBuffer<float4> srvtest : register(t0);
RWStructuredBuffer<float4> uavtest : register(u0);
RWStructuredBuffer<float> uavarray[2] : register(u1);
v2f main(vertin IN, uint vid : SV_VertexID)
{
v2f OUT = (v2f)0;
int ZERO = floor(vid/(vid+1.0e-6f));
if(vid < 3)
{
OUT.pos = float4(IN.pos.xyz, 1);
@@ -69,6 +78,20 @@ v2f main(vertin IN, uint vid : SV_VertexID)
if(uavtest[1].w != 1.234f)
OUT.col.r += 0.5f;
if (rootConsts.x == 0.0f)
OUT.col.b += 0.2f;
if (rootConsts.y == 0.0f)
OUT.col.b += 0.2f;
if (rootConsts.z == 0.0f)
OUT.col.b += 0.2f;
if (rootConsts.w == 0.0f)
OUT.col.b += 0.2f;
if (rootConsts.w != 0.0f)
uavarray[ZERO][10] = 10.0;
else
uavarray[ZERO+1][10] = 20.0;
}
else
{
@@ -230,7 +253,7 @@ void main(uint3 gid : SV_GroupID)
if(!Init())
return 3;
ID3DBlobPtr vsblob = Compile(vert, "main", "vs_5_0");
ID3DBlobPtr vsblob = Compile(vert, "main", "vs_5_1");
ID3DBlobPtr vs2blob = Compile(vert2, "main", "vs_5_0");
ID3DBlobPtr psblob = Compile(pixel, "main", "ps_4_0");
@@ -260,14 +283,15 @@ void main(uint3 gid : SV_GroupID)
ID3D12ResourcePtr srv = MakeBuffer().Data(checkdata);
ID3D12ResourcePtr uav = MakeBuffer().UAV().Data(checkdata);
ID3D12RootSignaturePtr patchsig = MakeSig({
cbvParam(D3D12_SHADER_VISIBILITY_VERTEX, 0, 0),
srvParam(D3D12_SHADER_VISIBILITY_VERTEX, 0, 0),
uavParam(D3D12_SHADER_VISIBILITY_VERTEX, 0, 0),
});
ID3D12RootSignaturePtr patchsig = MakeSig(
{cbvParam(D3D12_SHADER_VISIBILITY_VERTEX, 0, 0),
srvParam(D3D12_SHADER_VISIBILITY_VERTEX, 0, 0),
uavParam(D3D12_SHADER_VISIBILITY_VERTEX, 0, 0),
constParam(D3D12_SHADER_VISIBILITY_VERTEX, 0, 1, 4),
tableParam(D3D12_SHADER_VISIBILITY_ALL, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, 1, 2, 0)});
ID3D12CommandSignaturePtr patchArgSig =
MakeCommandSig(patchsig, {vbArg(0), cbvArg(0), srvArg(1), uavArg(2), drawArg()});
ID3D12CommandSignaturePtr patchArgSig = MakeCommandSig(
patchsig, {vbArg(0), cbvArg(0), srvArg(1), uavArg(2), constArg(3, 0, 1), drawArg()});
struct PatchArgs
{
@@ -275,6 +299,7 @@ void main(uint3 gid : SV_GroupID)
D3D12_GPU_VIRTUAL_ADDRESS cbv;
D3D12_GPU_VIRTUAL_ADDRESS srv;
D3D12_GPU_VIRTUAL_ADDRESS uav;
float constData;
D3D12_DRAW_ARGUMENTS draw;
} patchargs;
@@ -288,8 +313,29 @@ void main(uint3 gid : SV_GroupID)
patchargs.draw.InstanceCount = 1;
patchargs.draw.StartInstanceLocation = 0;
patchargs.draw.StartVertexLocation = 0;
patchargs.constData = 123.0f;
ID3D12ResourcePtr patchArgBuf = MakeBuffer().Upload().Size(sizeof(patchargs)).Data(&patchargs);
std::vector<char> patchArgsData;
patchArgsData.resize(sizeof(PatchArgs));
char *ptr = patchArgsData.data();
memcpy(ptr, &patchargs.vb, sizeof(D3D12_VERTEX_BUFFER_VIEW));
ptr += sizeof(D3D12_VERTEX_BUFFER_VIEW);
memcpy(ptr, &patchargs.cbv, sizeof(D3D12_GPU_VIRTUAL_ADDRESS));
ptr += sizeof(D3D12_GPU_VIRTUAL_ADDRESS);
memcpy(ptr, &patchargs.srv, sizeof(D3D12_GPU_VIRTUAL_ADDRESS));
ptr += sizeof(D3D12_GPU_VIRTUAL_ADDRESS);
memcpy(ptr, &patchargs.uav, sizeof(D3D12_GPU_VIRTUAL_ADDRESS));
ptr += sizeof(D3D12_GPU_VIRTUAL_ADDRESS);
memcpy(ptr, &patchargs.constData, sizeof(float));
ptr += sizeof(float);
memcpy(ptr, &patchargs.draw, sizeof(D3D12_DRAW_ARGUMENTS));
ptr += sizeof(D3D12_DRAW_ARGUMENTS);
size_t patchArgsDataSize = ptrdiff_t(ptr - patchArgsData.data());
ID3D12ResourcePtr patchArgBuf =
MakeBuffer().Upload().Size((UINT)patchArgsData.size()).Data(patchArgsData.data());
ID3D12PipelineStatePtr patchpso =
MakePSO().RootSig(patchsig).InputLayout(layout).VS(vsblob).PS(psblob);
@@ -312,6 +358,10 @@ void main(uint3 gid : SV_GroupID)
.NumElements(256000)
.CreateGPU(1);
MakeUAV(compuav).Format(DXGI_FORMAT_R32_FLOAT).FirstElement(0).NumElements(1024).CreateGPU(2);
MakeUAV(compuav).Format(DXGI_FORMAT_R32_FLOAT).FirstElement(1024).NumElements(1024).CreateGPU(3);
ID3D12RootSignaturePtr compsig = MakeSig({
tableParam(D3D12_SHADER_VISIBILITY_ALL, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, 0, 1, 0),
tableParam(D3D12_SHADER_VISIBILITY_ALL, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, 1, 1, 1),
@@ -326,12 +376,17 @@ void main(uint3 gid : SV_GroupID)
ID3D12ResourcePtr fullargsDrawBuf =
MakeBuffer().Size(countDrawsInFullBuffer * sizeof(D3D12_INDIRECT_ARGUMENT_DESC));
PatchArgs fullargsStateDraw[countDrawsInFullBuffer];
std::vector<char> fullargsData;
fullargsData.resize(countDrawsInFullBuffer * sizeof(PatchArgs));
char *fullargsPtr = fullargsData.data();
for(uint32_t i = 0; i < countDrawsInFullBuffer; ++i)
fullargsStateDraw[i] = patchargs;
{
memcpy(fullargsPtr, patchArgsData.data(), patchArgsDataSize);
fullargsPtr += patchArgsDataSize;
}
ID3D12ResourcePtr fullargsStateDrawBuf =
MakeBuffer().Upload().Size(countDrawsInFullBuffer * sizeof(patchargs)).Data(fullargsStateDraw);
MakeBuffer().Upload().Size((UINT)fullargsData.size()).Data(fullargsData.data());
ID3D12RootSignaturePtr plainsig = MakeSig({});
ID3D12PipelineStatePtr plainpso =
@@ -344,6 +399,8 @@ void main(uint3 gid : SV_GroupID)
customvbargs, D3D12_RESOURCE_STATE_COMMON,
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER | D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
float baseConstData[4] = {10.0f, 9.0f, 8.0f, 7.0f};
while(Running())
{
std::vector<ID3D12GraphicsCommandListPtr> cmds;
@@ -352,6 +409,8 @@ void main(uint3 gid : SV_GroupID)
Reset(cmd);
cmds.push_back(cmd);
cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr());
uint32_t zero[4] = {};
cmd->ClearUnorderedAccessViewUint(
MakeUAV(compuav).Format(DXGI_FORMAT_R32G32B32A32_UINT).CreateGPU(0),
@@ -372,12 +431,16 @@ void main(uint3 gid : SV_GroupID)
cmd->SetPipelineState(patchpso);
cmd->SetGraphicsRootSignature(patchsig);
cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr());
cmd->SetGraphicsRootDescriptorTable(4, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart());
RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f});
RSSetScissorRect(cmd, {0, 0, screenWidth, screenHeight});
OMSetRenderTargets(cmd, {rtv}, {});
cmd->SetGraphicsRoot32BitConstants(3, 4, baseConstData, 0);
cmd->ExecuteIndirect(patchArgSig, 1, patchArgBuf, 0, NULL, 0);
}
popMarker(cmd);
@@ -485,11 +548,14 @@ void main(uint3 gid : SV_GroupID)
cmd->SetPipelineState(patchpso);
cmd->SetGraphicsRootSignature(patchsig);
cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr());
cmd->SetGraphicsRootDescriptorTable(4, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart());
RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f});
RSSetScissorRect(cmd, {0, 0, screenWidth, screenHeight});
OMSetRenderTargets(cmd, {rtv}, {});
cmd->SetGraphicsRoot32BitConstants(3, 4, baseConstData, 0);
cmd->ExecuteIndirect(patchArgSig, countDrawsInFullBuffer, fullargsStateDrawBuf, 0, NULL, 0);
}
popMarker(cmd);
@@ -18,11 +18,28 @@ class D3D12_Execute_Indirect(rdtest.TestCase):
raise rdtest.TestFailureException("No pixel history found")
rdtest.log.success("Pixel History Worked")
def check_root_consts(self, expected: List[float]):
pipe: rd.PipeState = self.controller.GetPipelineState()
root_consts = pipe.GetConstantBlock(rd.ShaderStage.Vertex, 1, 0)
if root_consts is None:
raise rdtest.TestFailureException('rootConsts not found in pipeline state')
bytes = self.controller.GetBufferData(root_consts.descriptor.resource, 0, root_consts.descriptor.byteSize)
self.check(len(bytes) == 16) # 4 floats
data = struct.unpack("ffff", bytes)
for i in range(len(expected)):
if not rdtest.value_compare(expected[i], data[i]):
raise rdtest.TestFailureException(f'rootConsts[i] does not match expected:{expected[i]} got:{data[i]}')
rdtest.log.success("rootConsts is as expected")
def check_capture(self):
from_eid = self.find_action("Multiple draws").eventId
ei_eid = self.find_action("ExecuteIndirect", from_eid).eventId
self.controller.SetFrameEvent(ei_eid - 1, False)
self.check_root_consts([10.0, 9.0, 8.0, 7.0])
for i in range(8):
action = self.find_action("IndirectDraw", from_eid)
self.controller.SetFrameEvent(action.eventId, False)
self.check_root_consts([123.0, 9.0, 8.0, 7.0])
self.check_triangle(back=[0.0, 0.0, 0.0, 1.0])