- iOS 12.0+
- macOS 10.14+
- Xcode 11.0+
This sample app provides an introduction to indirect command buffers (ICB), which enable you to store repeated commands for later use. Because Metal discards a normal command buffer and its commands after Metal executes them, use ICBs to save expensive allocation, deallocation, and encoding time for your app’s common instructions. Additionally, you benefit when using ICBs with:
A reduction in rendering tasks because you execute an ICB with a single call.
By creating ICBs at initialization, it moves expensive command management out of your app’s critical path at rendering or compute-time.
An example of where ICBs are effective is with a game’s head-up display (HUD), because:
You render HUDs every frame.
The appearance of the HUD is usually static across frames.
ICBs are also useful to render static objects in typical 3D scenes. Because encoded commands typically result in lightweight data structures, ICBs are suitable for saving complex draws, too.
This sample demonstrates how to set up an ICB to repeatedly render a series of shapes. While it’s possible to gain even more instruction-parallelism by encoding the ICB on the GPU, this sample encodes an ICB on the CPU for simplicity. See Encoding Indirect Command Buffers on the GPU for the more advanced usage.
This sample contains macOS and iOS targets. Run the iOS scheme on a physical device because Metal isn’t supported in the simulator.
ICBs are supported by GPUs of family greater than or equal to:
Set _i OS _GPUFamily3 _v4
Set _mac OS _GPUFamily2 _v1
You check the GPU that you choose at runtime if it supports ICBs using
This sample calls ‘supportsFeatureSet:’ for this purpose within its view controller’s
Individual Commands Versus Indirect Command Buffers
Metal apps, particularly games, typically contain multiple render commands, each associated with a set of render states, buffers, and draw calls. To execute these commands for a render pass, apps first encode them into a render command encoder within a command buffer.
You encode individual commands into a render command encoder by calling
MTLRender methods such as
Recreating draws that were equivalent to ones you did in a previous queue can be tedious from a coding perspective and non-performant at runtime. Instead, move your repeated draws and their data buffers into an
MTLIndirect object using
MTLIndirect, thereby filling the ICB with commands. When you’re ready to use the ICB, encode individual executions of it by calling
Define Render Commands and Inherited Render State
For the indirect command buffer,
_indirect, the sample defines render commands that:
Set a vertex buffer using unique vertex data for each mesh
Set another vertex buffer using common transformation data for all meshes
Set another vertex buffer containing an array of parameters for each mesh
Draw the mesh’s triangles
The sample encodes these commands differently for the CPU or the GPU. However, these commands are still encoded into both versions of the indirect command buffer.
The sample also allows
_indirect to inherit the render pipeline state from its parent encoder,
_indirect implicitly inherits any render state that can’t be encoded into it, such as the cull mode and depth or stencil state for the render pass.
Create an Indirect Command Buffer
The sample creates
_indirect from a
MTLIndirect, which defines the features and limits of an indirect command buffer.
The sample specifies the types of commands,
command, and the maximum number of commands,
max, so that Metal reserves enough space in memory for the sample to encode
_indirect successfully (with the CPU or GPU).
Encode an Indirect Command Buffer with the CPU
From the CPU, the sample encodes commands into
_indirect with a
MTLIndirect object. For each shape to be rendered, the sample encodes two
set commands and one
The sample performs this encoding only once, before encoding any subsequent render commands.
_indirect contains a total of 16 draw calls, one for each shape to be rendered. Each draw call references the same transformation data,
_uniform, but different vertex data,
_vertex. Although the CPU encodes data only once, the sample issues 16 draw calls per frame.
Update the Data Used by an ICB
To update data that’s fed to the GPU, you typically cycle through a set of buffers such that the CPU updates one while the GPU reads another (see Synchronizing CPU and GPU Work). You can’t apply that pattern literally with ICBs, however, because you can’t update an ICB’s buffer set after you encode its commands, but you follow a two-step process to blit data updates from the CPU. First, update a single buffer in your dynamic buffer array on the CPU:
Then, blit the CPU-side buffer set to the location that’s accessible to the ICB (see _indirectFrameStateBuffer):
Execute an Indirect Command Buffer
The sample calls the
execute method to execute the commands in
Similar to the arguments in an argument buffer, the sample calls the
use method to indicate that the GPU can access the resources within an indirect command buffer.
The sample continues to execute
_indirect each frame.