dx12 multidraw command signature creation at shader creation time

This commit is contained in:
Turánszki János
2026-02-25 08:09:21 +01:00
parent 7dcc39ad95
commit e3720792ec
4 changed files with 105 additions and 69 deletions
+8 -8
View File
@@ -100,15 +100,15 @@ struct IndirectDispatchArgs
#define CBSLOT_RENDERER_TRACED 2
#define CBSLOT_RENDERER_MISC 3
#define CBSLOT_OTHER_EMITTEDPARTICLE 4
#define CBSLOT_OTHER_HAIRPARTICLE 4
#define CBSLOT_OTHER_FFTGENERATOR 3
#define CBSLOT_OTHER_EMITTEDPARTICLE 2
#define CBSLOT_OTHER_HAIRPARTICLE 2
#define CBSLOT_OTHER_FFTGENERATOR 2
#define CBSLOT_OTHER_OCEAN 3
#define CBSLOT_OTHER_CLOUDGENERATOR 3
#define CBSLOT_OTHER_GPUSORTLIB 4
#define CBSLOT_MSAO 4
#define CBSLOT_FSR 4
#define CBSLOT_TRAILRENDERER 3
#define CBSLOT_OTHER_CLOUDGENERATOR 2
#define CBSLOT_OTHER_GPUSORTLIB 2
#define CBSLOT_MSAO 2
#define CBSLOT_FSR 2
#define CBSLOT_TRAILRENDERER 2
#define CBSLOT_GPUSORTLIB 2
#else
+87 -57
View File
@@ -1432,6 +1432,10 @@ namespace dx12_internal
wi::allocator::shared_ptr<void> rootsig_desc_lifetime_extender;
RootSignatureOptimizer rootsig_optimizer;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawInstancedIndirectCountCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawIndexedInstancedIndirectCountCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> dispatchMeshIndirectCountCommandSignature;
struct PSO_STREAM
{
struct PSO_STREAM1
@@ -2866,42 +2870,6 @@ std::mutex queue_locker;
wi::platform::Exit();
}
// Dummy rootsignature is created for validating multidraw command signatures (required):
ComPtr<ID3D12RootSignature> rootsig;
ComPtr<ID3DBlob> serializedRootSig = nullptr;
ComPtr<ID3DBlob> errorBlob = nullptr;
D3D12_ROOT_PARAMETER rootparam = {};
rootparam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
rootparam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
rootparam.Constants.Num32BitValues = PUSH_CONSTANT_COUNT;
rootparam.Constants.ShaderRegister = 999;
D3D12_ROOT_SIGNATURE_DESC rootsig_desc = {};
rootsig_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
rootsig_desc.NumParameters = 1;
rootsig_desc.pParameters = &rootparam;
dx12_check(D3D12SerializeRootSignature(&rootsig_desc, D3D_ROOT_SIGNATURE_VERSION_1, serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf()));
dx12_check(device->CreateRootSignature(0, serializedRootSig->GetBufferPointer(), serializedRootSig->GetBufferSize(), PPV_ARGS(rootsig)));
D3D12_INDIRECT_ARGUMENT_DESC drawInstancedCountArgs[2];
drawInstancedCountArgs[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
drawInstancedCountArgs[0].Constant.RootParameterIndex = 0;
drawInstancedCountArgs[0].Constant.Num32BitValuesToSet = 1;
drawInstancedCountArgs[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
cmd_desc.ByteStride = sizeof(uint32_t) + sizeof(D3D12_DRAW_ARGUMENTS);
cmd_desc.NumArgumentDescs = arraysize(drawInstancedCountArgs);
cmd_desc.pArgumentDescs = drawInstancedCountArgs;
dx12_check(device->CreateCommandSignature(&cmd_desc, rootsig.Get(), PPV_ARGS(drawInstancedIndirectCountCommandSignature)));
D3D12_INDIRECT_ARGUMENT_DESC drawIndexedInstancedCountArgs[2];
drawIndexedInstancedCountArgs[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
drawIndexedInstancedCountArgs[0].Constant.RootParameterIndex = 0;
drawIndexedInstancedCountArgs[0].Constant.Num32BitValuesToSet = 1;
drawIndexedInstancedCountArgs[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
cmd_desc.ByteStride = sizeof(uint32_t) + sizeof(D3D12_DRAW_INDEXED_ARGUMENTS);
cmd_desc.NumArgumentDescs = arraysize(drawIndexedInstancedCountArgs);
cmd_desc.pArgumentDescs = drawIndexedInstancedCountArgs;
dx12_check(device->CreateCommandSignature(&cmd_desc, rootsig.Get(), PPV_ARGS(drawIndexedInstancedIndirectCountCommandSignature)));
if (CheckCapability(GraphicsDeviceCapability::MESH_SHADER))
{
D3D12_INDIRECT_ARGUMENT_DESC dispatchMeshArgs[1];
@@ -2914,21 +2882,6 @@ std::mutex queue_locker;
cmd_desc.NumArgumentDescs = 1;
cmd_desc.pArgumentDescs = dispatchMeshArgs;
dx12_check(device->CreateCommandSignature(&cmd_desc, nullptr, PPV_ARGS(dispatchMeshIndirectCommandSignature)));
D3D12_INDIRECT_ARGUMENT_DESC dispatchMeshCountArgs[2];
dispatchMeshCountArgs[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
dispatchMeshCountArgs[0].Constant.RootParameterIndex = 0;
dispatchMeshCountArgs[0].Constant.Num32BitValuesToSet = 1;
#ifdef PLATFORM_XBOX
wi::graphics::xbox::FillDispatchMeshIndirectArgumentDesc(dispatchMeshCountArgs[1], cmd_desc);
#else
dispatchMeshCountArgs[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH;
cmd_desc.ByteStride = sizeof(D3D12_DISPATCH_MESH_ARGUMENTS);
#endif // PLATFORM_XBOX
cmd_desc.ByteStride += sizeof(uint32_t);
cmd_desc.NumArgumentDescs = arraysize(dispatchMeshCountArgs);
cmd_desc.pArgumentDescs = dispatchMeshCountArgs;
dx12_check(device->CreateCommandSignature(&cmd_desc, rootsig.Get(), PPV_ARGS(dispatchMeshIndirectCommandSignature)));
}
allocationhandler->descriptors_res.init(this, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 4096);
@@ -3963,6 +3916,76 @@ std::mutex queue_locker;
hr = dx12_check(device->CreatePipelineState(&streamDesc, PPV_ARGS(internal_state->resource)));
}
if (stage == ShaderStage::VS)
{
std::scoped_lock lck(multidraw_signature_locker);
MultiDrawSignature& cached = multidraw_signatures[internal_state->rootSignature.Get()];
if (cached.drawInstancedIndirectCountCommandSignature)
{
internal_state->drawInstancedIndirectCountCommandSignature = cached.drawInstancedIndirectCountCommandSignature;
}
else
{
D3D12_COMMAND_SIGNATURE_DESC cmd_desc = {};
D3D12_INDIRECT_ARGUMENT_DESC drawInstancedCountArgs[2] = {};
drawInstancedCountArgs[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
drawInstancedCountArgs[0].Constant.RootParameterIndex = internal_state->rootsig_optimizer.PUSH;
drawInstancedCountArgs[0].Constant.Num32BitValuesToSet = 1;
drawInstancedCountArgs[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
cmd_desc.ByteStride = sizeof(uint32_t) + sizeof(D3D12_DRAW_ARGUMENTS);
cmd_desc.NumArgumentDescs = arraysize(drawInstancedCountArgs);
cmd_desc.pArgumentDescs = drawInstancedCountArgs;
dx12_check(device->CreateCommandSignature(&cmd_desc, internal_state->rootSignature.Get(), PPV_ARGS(internal_state->drawInstancedIndirectCountCommandSignature)));
}
if (cached.drawIndexedInstancedIndirectCountCommandSignature)
{
internal_state->drawIndexedInstancedIndirectCountCommandSignature = cached.drawIndexedInstancedIndirectCountCommandSignature;
}
else
{
D3D12_COMMAND_SIGNATURE_DESC cmd_desc = {};
D3D12_INDIRECT_ARGUMENT_DESC drawIndexedInstancedCountArgs[2] = {};
drawIndexedInstancedCountArgs[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
drawIndexedInstancedCountArgs[0].Constant.RootParameterIndex = internal_state->rootsig_optimizer.PUSH;
drawIndexedInstancedCountArgs[0].Constant.Num32BitValuesToSet = 1;
drawIndexedInstancedCountArgs[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
cmd_desc.ByteStride = sizeof(uint32_t) + sizeof(D3D12_DRAW_INDEXED_ARGUMENTS);
cmd_desc.NumArgumentDescs = arraysize(drawIndexedInstancedCountArgs);
cmd_desc.pArgumentDescs = drawIndexedInstancedCountArgs;
dx12_check(device->CreateCommandSignature(&cmd_desc, internal_state->rootSignature.Get(), PPV_ARGS(internal_state->drawIndexedInstancedIndirectCountCommandSignature)));
}
}
else if (stage == ShaderStage::MS)
{
std::scoped_lock lck(multidraw_signature_locker);
MultiDrawSignature& cached = multidraw_signatures[internal_state->rootSignature.Get()];
if (cached.dispatchMeshIndirectCountCommandSignature)
{
internal_state->dispatchMeshIndirectCountCommandSignature = cached.dispatchMeshIndirectCountCommandSignature;
}
else
{
D3D12_COMMAND_SIGNATURE_DESC cmd_desc = {};
D3D12_INDIRECT_ARGUMENT_DESC dispatchMeshCountArgs[2] = {};
dispatchMeshCountArgs[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
dispatchMeshCountArgs[0].Constant.RootParameterIndex = internal_state->rootsig_optimizer.PUSH;
dispatchMeshCountArgs[0].Constant.Num32BitValuesToSet = 1;
#ifdef PLATFORM_XBOX
wi::graphics::xbox::FillDispatchMeshIndirectArgumentDesc(dispatchMeshCountArgs[1], cmd_desc);
#else
dispatchMeshCountArgs[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH;
cmd_desc.ByteStride = sizeof(D3D12_DISPATCH_MESH_ARGUMENTS);
#endif // PLATFORM_XBOX
cmd_desc.ByteStride += sizeof(uint32_t);
cmd_desc.NumArgumentDescs = arraysize(dispatchMeshCountArgs);
cmd_desc.pArgumentDescs = dispatchMeshCountArgs;
dx12_check(device->CreateCommandSignature(&cmd_desc, internal_state->rootSignature.Get(), PPV_ARGS(internal_state->dispatchMeshIndirectCountCommandSignature)));
}
}
return SUCCEEDED(hr);
}
bool GraphicsDevice_DX12::CreateSampler(const SamplerDesc* desc, Sampler* sampler) const
@@ -4059,6 +4082,8 @@ std::mutex queue_locker;
internal_state->rootSignature = shader_internal->rootSignature;
internal_state->rootsig_desc = shader_internal->rootsig_desc;
internal_state->rootsig_desc_lifetime_extender = pso->desc.vs->internal_state;
internal_state->drawInstancedIndirectCountCommandSignature = shader_internal->drawInstancedIndirectCountCommandSignature;
internal_state->drawIndexedInstancedIndirectCountCommandSignature = shader_internal->drawIndexedInstancedIndirectCountCommandSignature;
stream.stream1.ROOTSIG = internal_state->rootSignature.Get();
}
}
@@ -4120,6 +4145,7 @@ std::mutex queue_locker;
internal_state->rootSignature = shader_internal->rootSignature;
internal_state->rootsig_desc = shader_internal->rootsig_desc;
internal_state->rootsig_desc_lifetime_extender = pso->desc.ms->internal_state;
internal_state->dispatchMeshIndirectCountCommandSignature = shader_internal->dispatchMeshIndirectCountCommandSignature;
stream.stream1.ROOTSIG = internal_state->rootSignature.Get();
}
}
@@ -5758,6 +5784,7 @@ std::mutex queue_locker;
void GraphicsDevice_DX12::ClearPipelineStateCache()
{
multidraw_signatures.clear();
pipelines_global.clear();
for (auto& x : commandlists)
@@ -6808,18 +6835,20 @@ std::mutex queue_locker;
void GraphicsDevice_DX12::DrawInstancedIndirectCount(const GPUBuffer* args, uint64_t args_offset, const GPUBuffer* count, uint64_t count_offset, uint32_t max_count, CommandList cmd)
{
predraw(cmd);
CommandList_DX12& commandlist = GetCommandList(cmd);
auto pso_internal = to_internal(commandlist.active_pso);
auto args_internal = to_internal(args);
auto count_internal = to_internal(count);
CommandList_DX12& commandlist = GetCommandList(cmd);
commandlist.GetGraphicsCommandList()->ExecuteIndirect(drawInstancedIndirectCountCommandSignature.Get(), max_count, args_internal->resource.Get(), args_offset, count_internal->resource.Get(), count_offset);
commandlist.GetGraphicsCommandList()->ExecuteIndirect(pso_internal->drawInstancedIndirectCountCommandSignature.Get(), max_count, args_internal->resource.Get(), args_offset, count_internal->resource.Get(), count_offset);
}
void GraphicsDevice_DX12::DrawIndexedInstancedIndirectCount(const GPUBuffer* args, uint64_t args_offset, const GPUBuffer* count, uint64_t count_offset, uint32_t max_count, CommandList cmd)
{
predraw(cmd);
CommandList_DX12& commandlist = GetCommandList(cmd);
auto pso_internal = to_internal(commandlist.active_pso);
auto args_internal = to_internal(args);
auto count_internal = to_internal(count);
CommandList_DX12& commandlist = GetCommandList(cmd);
commandlist.GetGraphicsCommandList()->ExecuteIndirect(drawIndexedInstancedIndirectCountCommandSignature.Get(), max_count, args_internal->resource.Get(), args_offset, count_internal->resource.Get(), count_offset);
commandlist.GetGraphicsCommandList()->ExecuteIndirect(pso_internal->drawIndexedInstancedIndirectCountCommandSignature.Get(), max_count, args_internal->resource.Get(), args_offset, count_internal->resource.Get(), count_offset);
}
void GraphicsDevice_DX12::Dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ, CommandList cmd)
{
@@ -6850,10 +6879,11 @@ std::mutex queue_locker;
void GraphicsDevice_DX12::DispatchMeshIndirectCount(const GPUBuffer* args, uint64_t args_offset, const GPUBuffer* count, uint64_t count_offset, uint32_t max_count, CommandList cmd)
{
predraw(cmd);
CommandList_DX12& commandlist = GetCommandList(cmd);
auto pso_internal = to_internal(commandlist.active_pso);
auto args_internal = to_internal(args);
auto count_internal = to_internal(count);
CommandList_DX12& commandlist = GetCommandList(cmd);
commandlist.GetGraphicsCommandList()->ExecuteIndirect(dispatchMeshIndirectCountCommandSignature.Get(), max_count, args_internal->resource.Get(), args_offset, count_internal->resource.Get(), count_offset);
commandlist.GetGraphicsCommandList()->ExecuteIndirect(pso_internal->dispatchMeshIndirectCountCommandSignature.Get(), max_count, args_internal->resource.Get(), args_offset, count_internal->resource.Get(), count_offset);
}
void GraphicsDevice_DX12::CopyResource(const GPUResource* pDst, const GPUResource* pSrc, CommandList cmd)
{
+9 -3
View File
@@ -60,9 +60,15 @@ namespace wi::graphics
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawIndexedInstancedIndirectCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> dispatchMeshIndirectCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawInstancedIndirectCountCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawIndexedInstancedIndirectCountCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> dispatchMeshIndirectCountCommandSignature;
// Multi count draw command signatures (when drawID is used) need to be created with valid root signature, so they are delayed until shader creation:
struct MultiDrawSignature
{
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawInstancedIndirectCountCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> drawIndexedInstancedIndirectCountCommandSignature;
Microsoft::WRL::ComPtr<ID3D12CommandSignature> dispatchMeshIndirectCountCommandSignature;
};
mutable std::mutex multidraw_signature_locker;
mutable wi::unordered_map<ID3D12RootSignature*, MultiDrawSignature> multidraw_signatures;
wi::vector<GUID> video_decode_profile_list;
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 72;
// minor bug fixes, alterations, refactors, updates
const int revision = 47;
const int revision = 48;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);