这是indexloc提供的服务,不要输入任何密码
Skip to content

Investigation: multi-draw-indirect #4349

@kainino0x

Description

@kainino0x

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions