I'm copying this here so we have an open bug for the investigation and feature request.
Originally posted by @mrshannon in #1949
Indirect drawing with multiple indirect drawing commands is a common technique for drawing complex scenes that would otherwise be infeasible due to either an excessive number of CPU issued draw calls or scene complexity that cannot be built by the CPU alone. This is done by:
- Executing multiple draws with a single API call.
- Allowing the GPU to generate both geometry and the draws necessary to render it.
- Culling out unnecessary draw calls on the GPU in more complex scenes than CPU culling could achieve.
This PR addresses adding a multi-draw-indirect feature. In particular it addresses adding:
multiDrawIndirect and multiDrawIndexedIndirect methods on GPURenderEncoderBase.
- Allows submitting multiple draws with a single API call (multi-draw).
- Allows the GPU to determine the number of draw calls (draw count).
- Use cases:
- GPU derived scene data
- GPU based culling
- GPU based LOD
- Efficient execution of complex scenes with a large number of draws
- Non-zero
firstInstance for drawIndirect, drawIndexedIndirect, multiDrawIndirect, and multiDrawIndexedIndirect.
- This is the only available per draw input, without rebinds, that is readable in the shader.
- Use cases:
- Select instance stride vertex data
- Index into per object or per draw data in storage buffers
- Multi material, single API call, rendering
Compatibility
The required backend features to implement multi-draw-indirect are available on:
- Newer Apple devices (~2016+)
- All DX12 devices
- All Vulkan capable desktops (with up to date drivers)
- 30% of Android devices
See the sections below for details.
Vulkan
Multi-Draw
Requires the 0 or 1 restriction on the drawCount argument of vkCmdDrawIndirect and vkCmdDrawIndexIndirect to be relaxed to any non-negative integer. This requires the multiDrawIndirect feature which is supported on:
- 99% of desktop GPUs
- 63% of Android devices
NOTE: The stride argument will always be set for tight packing, in order to maintain compatibility with DX12.
Draw Count
Requires the vkCmdDrawIndirectCount and vkCmdDrawIndexedIndirectCount functions which are provided by either the drawIndirectCount feature of Vulkan 1.2 or one of the following extensions:
VK_AMD_draw_indirect_count
VK_KHR_draw_indirect_count
Because drawIndirectCount was introduced in driver updates the statistics at https://vulkan.gpuinfo.org cannot be relied upon. The following is based on the oldest card that supports drawIndirectCount from each manufacturer, if newer cards dropped support for drawIndirectCount that is not captured here.
- Intel integrated cards (that support Vulkan) support
drawIndirectCount.
- NVIDIA cards going back to Kepler support
drawIndirectCount.
- AMD cards going back to the HD 8000 series support
drawIndirectCount.
For Android:
drawIndirectCount is supported on 100% of devices that support Vulkan 1.2.
drawIndirectCount is supported, as an extension, on 28% of devices that do not support Vulkan 1.2.
Non-zero firstInstance
Requires the firstInstance property of the VkDrawIndirectCommand and VkDrawIndexedIndirectCommand to be non-zero. This requires the drawIndirectFirstInstance feature which is supported on:
- 99% of desktop GPUs
- 64% of Android devices
DX12
All required features are core to DX12.
Multi-Draw
Uses ExecuteIndirect where the MaxCommandCount argument is greater than 1 and the pArgumentBuffer argument points to a GPU buffer containing an array of D3D12_DRAW_ARGUMENTS or D3D12_DRAW_INDEXED_ARGUMENTS.
NOTE: The binary layout of these structs are compatible with Vulkan.
Draw Count
Uses ExecuteIndirect where the pCountBuffer argument is not NULL.
Non-zero firstInstance
This is the StartInstanceLocation of the D3D12_DRAW_ARGUMENTS or D3D12_DRAW_INDEXED_ARGUMENTS structures. Has native support for values greater than 0.
Metal
Multi-Draw
Can be emulated with Indirect Command Buffers (ICBs) and an extra compute shader invocation to translate from the Vulkan-like indirect draw buffer to an ICB.
Requires
- iOS 12.0+
- macOS 10.14+
- MTLGPUFamilyMac2
Non-zero firstInstance
Natively supported with the baseInstance argument.
Draw Count
Don't record commands past this count in the ICB and use optimizedIndirectCommandBuffer.
Requires
- iOS 12.0+
- macOS 10.14+
- MTLGPUFamilyMac2
I'm copying this here so we have an open bug for the investigation and feature request.
Originally posted by @mrshannon in #1949
Indirect drawing with multiple indirect drawing commands is a common technique for drawing complex scenes that would otherwise be infeasible due to either an excessive number of CPU issued draw calls or scene complexity that cannot be built by the CPU alone. This is done by:
This PR addresses adding a
multi-draw-indirectfeature. In particular it addresses adding:multiDrawIndirectandmultiDrawIndexedIndirectmethods onGPURenderEncoderBase.firstInstancefordrawIndirect,drawIndexedIndirect,multiDrawIndirect, andmultiDrawIndexedIndirect.Compatibility
The required backend features to implement
multi-draw-indirectare available on:See the sections below for details.
Vulkan
Multi-Draw
Requires the 0 or 1 restriction on the
drawCountargument ofvkCmdDrawIndirectandvkCmdDrawIndexIndirectto be relaxed to any non-negative integer. This requires themultiDrawIndirectfeature which is supported on:NOTE: The
strideargument will always be set for tight packing, in order to maintain compatibility with DX12.Draw Count
Requires the
vkCmdDrawIndirectCountandvkCmdDrawIndexedIndirectCountfunctions which are provided by either thedrawIndirectCountfeature of Vulkan 1.2 or one of the following extensions:VK_AMD_draw_indirect_countVK_KHR_draw_indirect_countBecause
drawIndirectCountwas introduced in driver updates the statistics at https://vulkan.gpuinfo.org cannot be relied upon. The following is based on the oldest card that supportsdrawIndirectCountfrom each manufacturer, if newer cards dropped support fordrawIndirectCountthat is not captured here.drawIndirectCount.drawIndirectCount.drawIndirectCount.For Android:
drawIndirectCountis supported on 100% of devices that support Vulkan 1.2.drawIndirectCountis supported, as an extension, on 28% of devices that do not support Vulkan 1.2.Non-zero
firstInstanceRequires the
firstInstanceproperty of theVkDrawIndirectCommandandVkDrawIndexedIndirectCommandto be non-zero. This requires thedrawIndirectFirstInstancefeature which is supported on:DX12
All required features are core to DX12.
Multi-Draw
Uses
ExecuteIndirectwhere theMaxCommandCountargument is greater than 1 and thepArgumentBufferargument points to a GPU buffer containing an array ofD3D12_DRAW_ARGUMENTSorD3D12_DRAW_INDEXED_ARGUMENTS.NOTE: The binary layout of these structs are compatible with Vulkan.
Draw Count
Uses
ExecuteIndirectwhere thepCountBufferargument is not NULL.Non-zero
firstInstanceThis is the
StartInstanceLocationof theD3D12_DRAW_ARGUMENTSorD3D12_DRAW_INDEXED_ARGUMENTSstructures. Has native support for values greater than 0.Metal
Multi-Draw
Can be emulated with Indirect Command Buffers (ICBs) and an extra compute shader invocation to translate from the Vulkan-like indirect draw buffer to an ICB.
Requires
Non-zero
firstInstanceNatively supported with the
baseInstanceargument.Draw Count
Don't record commands past this count in the ICB and use
optimizedIndirectCommandBuffer.Requires