Article

About Argument Buffers

Improve your app's performance by grouping your resources into an argument buffer.

Overview

An argument buffer is an opaque data representation of a group of resources that can be collectively assigned as graphics or compute function arguments. An argument buffer can contain multiple resources of various sizes and types, such as buffers, textures, samplers, and inlined constant data.

Specifying Argument Buffers in Metal Shading Language Functions

Argument buffers may contain the following:

  • Basic scalar data types, such as half and float.

  • Basic vector and matrix data types, such as half4 and float4x4.

  • Arrays and structures of basic data types.

  • Buffer pointers.

  • Texture data types and arrays of textures.

  • Sampler data types and arrays of samplers.

The following example shows an argument buffer structure named My_AB that specifies resources for a kernel function named my_kernel:

struct My_AB {
    texture2d<float, access::write> a;
    depth2d<float> b;
    sampler c;
    texture2d<float> d;
    device float4* e;
    texture2d<float> f;
    int g;
};
kernel void my_kernel(constant My_AB & my_AB [[buffer(0)]])
{ ... }

Encoding Resources into Argument Buffers

The Metal driver may perform certain optimizations that modify the physical memory layout of an argument buffer. The layout is unknown; you must use a MTLArgumentEncoder object to encode argument buffer resources into a destination MTLBuffer object. You can encode the following resources into argument buffers:

You can then set an encoded argument buffer as a graphics or compute function argument using any of the following MTLRenderCommandEncoder or MTLComputeCommandEncoder methods:

Benefits of Using Argument Buffers

Argument buffers can assign a group of resources all at once to a single index in the function argument table. The main benefit of using argument buffers is to reduce the overhead incurred by assigning the same multiple resources to individual indices of the same function argument table. This is particularly beneficial for resources that do not change from frame to frame, because they can be assigned to an argument buffer once and reused many times.

Encoding resources into argument buffers eliminates the need for the Metal driver to capture state and track residency when individual resources are assigned to the indices of a function's argument table. Instead, argument buffers provide greater control over resource residency that you must explicitly declare before issuing draw or dispatch calls.

Using resource heaps is already a great way to reduce resource overhead. When you combine resource heaps with argument buffers, you can further reduce overhead by:

  • Encoding argument buffer resources before entering a draw or dispatch loop.

  • Allocating argument buffers from a resource heap, reducing the cost of tracking the residency of the argument buffer itself.

  • Managing argument buffer resources and resource heap residency outside of a draw or dispatch loop, further reducing the cost of tracking residency.

Finally, argument buffers allow resources to be indexed dynamically at function execution time by greatly increasing the limit on the number of resources that can be placed inside them.

Argument Buffer Tiers, Limits, and Capabilities

Argument buffer feature support is divided into two tiers: Tier 1 and Tier 2. You can query these tiers by accessing the argumentBuffersSupport property of a MTLDevice object.

Common Limits

For both tiers, the maximum number of argument buffer entries in each function argument table is 8.

For both tiers, the maximum number of unique samplers per app are 96 for iOS and tvOS, and at least 1024 for macOS; these limits are only applicable to samplers that have their supportArgumentBuffers property set to true. Query the maxArgumentBufferSamplerCount to determine the exact maximum number of unique samplers per app for a given device.

A MTLSamplerState object is considered unique if the configuration of its originating MTLSamplerDescriptor properties is unique. For example, two samplers with equal minFilter values but different magFilter values are considered unique.

Tier 1 Limits

The following resource limits are defined as the maximum combined number of resources set within an argument buffer and set individually, per graphics or compute function. For example, if a kernel function uses 4 individual textures and one argument buffer with 8 textures, the total number of textures for that kernel function is 12.

In iOS and tvOS, the maximum entries in each function argument table are:

  • 31 buffers

  • 31 textures*

  • 16 samplers

*Writable textures are not supported within an argument buffer.

In macOS, the maximum entries in each function argument table are:

  • 64 buffers

  • 128 textures

  • 16 samplers

Tier 2 Limits

Tier 2 argument buffers are supported only by macOS devices with a discrete GPU. In macOS, the maximum per-app resources available at any given time are:

  • 500,000 buffers or textures

  • 2048 unique samplers

Resource Access

Tier 1 argument buffers must be immutable; the GPU cannot modify the contents of an argument buffer. Tier 1 argument buffers must also be CPU-accessible (the buffer must specify either a MTLStorageMode.shared or MTLStorageMode.managed storage mode).

Tier 2 argument buffers can be mutable; the GPU and CPU can both modify the contents of an argument buffer at any time. However, the Metal driver may perform certain optimizations if you specify that neither the CPU nor the GPU will modify a buffer's contents between the time the buffer is set in a function's argument table and the time its associated command buffer completes execution. These types of argument buffers are considered immutable, and you can define them by setting the mutability property of an associated MTLPipelineBufferDescriptor object to MTLMutability.immutable.

Metal Shading Language Capabilities

Tier 1 argument buffers cannot be accessed through pointer indexing, nor can they include pointers to other argument buffers.

Tier 2 argument buffers can be accessed through pointer indexing, as shown in the following example:

kernel void my_kernel(constant My_AB_Resources *resourcesArray [[buffer(0)]]) {
    constant My_AB_Resources & resources = resourcesArray[3];
}

Tier 2 argument buffers can also access other argument buffers by including pointers to them, as shown in the following example:

struct My_AB_Textures {
    texture2d<float> diffuse;
    texture2d<float> specular;
};
struct My_AB_Material {
    device My_AB_Textures *textures;
};
fragment float4 my_fragment(device My_AB_Material & material)
{...}

Samplers cannot be copied from the thread address space to the device address space; therefore, argument buffer samplers can be copied only between argument buffers:

struct My_AB_Sampler {
    sampler sam0;
};
kernel void my_kernel(device My_AB_Sampler *source, device My_AB_Sampler *destination, sampler sam1) {
    constexpr sampler sam2;
    // device-to-device copy is allowed
    destination->sam0 = source->sam0;
    // thread-to-device copies are not allowed
    destination->sam0 = sam1;
    destination->sam0 = sam2;
}

See Also

Argument Buffers

Basic Argument Buffers

Demonstrates how to manage groups of resources with an argument buffer.

Argument Buffers with Arrays and Resource Heaps

Demonstrates how to define an argument buffer with arrays and reduce CPU overhead by combining argument buffers with resource heaps.

Argument Buffers with GPU Encoding

Demonstrates how to encode an argument buffer with a compute pass and then access its arguments in a subsequent render pass.

Dynamic Terrain with Argument Buffers

Demonstrates how to use argument buffers to render a dynamic terrain in real time with a GPU-driven pipeline.

Indexing Argument Buffers

Assign resource indices within an argument buffer.

Tracking the Resource Residency of Argument Buffers

Optimize resource performance within an argument buffer.

protocol MTLArgumentEncoder

An encoder that specifies resources for an argument buffer.

class MTLArgumentDescriptor

A representation of an argument within an argument buffer.