-
Notifications
You must be signed in to change notification settings - Fork 345
Description
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:
multiDrawIndirectandmultiDrawIndexedIndirectmethods onGPURenderEncoderBase.- 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
firstInstancefordrawIndirect,drawIndexedIndirect,multiDrawIndirect, andmultiDrawIndexedIndirect.- 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_countVK_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:
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 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