From a8ee82bfe895240c582a66eba1d37663623562a6 Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Wed, 23 Jul 2025 17:33:03 +0100 Subject: [PATCH] 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 --- .../demos/d3d12/d3d12_execute_indirect.cpp | 90 ++++++++++++++++--- .../tests/D3D12/D3D12_Execute_Indirect.py | 17 ++++ 2 files changed, 95 insertions(+), 12 deletions(-) diff --git a/util/test/demos/d3d12/d3d12_execute_indirect.cpp b/util/test/demos/d3d12/d3d12_execute_indirect.cpp index 6085e7135..2a63c9fe2 100644 --- a/util/test/demos/d3d12/d3d12_execute_indirect.cpp +++ b/util/test/demos/d3d12/d3d12_execute_indirect.cpp @@ -48,14 +48,23 @@ cbuffer test : register(b0) float4 cbtest[5]; } +cbuffer rootConsts : register(b1) +{ + float4 rootConsts; +} + StructuredBuffer srvtest : register(t0); RWStructuredBuffer uavtest : register(u0); +RWStructuredBuffer 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 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 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 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); diff --git a/util/test/tests/D3D12/D3D12_Execute_Indirect.py b/util/test/tests/D3D12/D3D12_Execute_Indirect.py index 790ada0a7..c63246baf 100644 --- a/util/test/tests/D3D12/D3D12_Execute_Indirect.py +++ b/util/test/tests/D3D12/D3D12_Execute_Indirect.py @@ -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])