Indirect Drawing

Indirect drawing enables some scene-traversal and culling to be moved from the CPU to the GPU, which can improve performance. The command buffer can be generated by the CPU or GPU.

Command Signatures

The command signature object (ID3D12CommandSignature) enables apps to specify indirect drawing, in particular setting the following:

At startup, an app creates a small set of command signatures. At runtime, the application fills a buffer with commands (via whatever means the app developer chooses). The commands optionally containing state to set for vertex buffer views, index buffer views, root constants and root descriptors (raw or structured SRV/UAV/CBVs). These argument layouts are not hardware specific so apps can generate the buffers directly. The command signature inherits the remaining state from the command list. Then the app calls ExecuteIndirect to instruct the GPU to interpret the contents of the indirect argument buffer according to the format defined by a particular command signature.

If the command signature changes any root arguments, this is stored within the command signature as a subset of a root signature.

Note that no command signature state leaks back to the command list when the execution is complete.

For example, suppose an app developer wants a unique root constant to be specified per-draw call in the indirect argument buffer. The app would create a command signature that enables the indirect argument buffer to specify the following parameters per draw call:

  • The value of one root constant.
  • The draw arguments (vertex count, instance count, etc).

The indirect argument buffer generated by the application would contain an array of fixed-size records. Each structure corresponds to one draw call. Each structure contains the drawing arguments, and the value of the root constant. The number of draw calls is specified in a separate GPU-visible buffer.

An example command buffer generated by the app follows:

command buffer format

Indirect Argument Buffer Structures

The following structures define how particular arguments appear in an indirect argument buffer. These structures do not appear in any D3D12 API. Applications use these definitions when writing to an indirect argument buffer (with the CPU or GPU):

Command Signature Creation

To create a command signature, use the following API items:

The ordering of arguments within an indirect argument buffer is defined to exactly match the order of arguments specified in the pArguments parameter of D3D12_COMMAND_SIGNATURE_DESC. All of the arguments for one draw (graphics)/dispatch (compute) call within an indirect argument buffer are tightly packed. However, applications are allowed to specify an arbitrary byte stride between draw/dispatch commands in an indirect argument buffer.

The root signature must be specified if and only if the command signature changes one of the root arguments.

For root SRV/UAV/CBV, the application specified size is in bytes. The debug layer will validate the following restrictions on the address:

  • CBV – address must be a multiple of 256 bytes.
  • Raw SRV/UAV – address must be a multiple of 4 bytes.
  • Structured SRV/UAV – address must be a multiple of the structure byte stride (declared in the shader).

A given command signature is either a draw or a compute command signature. If a command signature contains a drawing operation, then it is a graphics command signature. Otherwise, the command signature must contain a dispatch operation, and it is a compute command signature.

The following sections show some example command signatures.

No Argument Changes

In this example, the indirect argument buffer generated by the application holds an array of 36-byte structures. Each structure only contains the five parameters passed to DrawIndexedInstanced (plus padding).

The code to create the command signature description follows:

D3D12_INDIRECT_ARGUMENT_DESC Args[1];
Args[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;

D3D12_COMMAND_SIGNATURE_DESC ProgramDesc;
ProgramDesc.ByteStride = 36;
ProgramDesc.ArgumentCount = 1;
ProgramDesc.pArguments = Args;

The layout of a single structure within an indirect argument buffer is:

Bytes Description
0:3 IndexCountPerInstance
4:7 InstanceCount
8:11 StartIndexLocation
12:15 BaseVertexLocation
16:19 StartInstanceLocation
20:35 Padding

 

Root Constants and Vertex Buffers

In this example, each structure in an indirect argument buffer changes two root constants, changes one vertex buffer binding, and performs one drawing non-indexed operation. There is no padding between structures.

The code to create the command signature description is:

D3D12_INDIRECT_ARGUMENT_DESC Args[4];
Args[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
Args[0].Constant.RootParameterIndex = 2;

Args[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT;
Args[1].Constant.RootParameterIndex = 6;

Args[2].Type = D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW;
Args[2].VertexBuffer.VBSlot = 3;

Args[3].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INSTANCED;

D3D12_COMMAND_SIGNATURE_DESC ProgramDesc;
ProgramDesc.ByteStride = 40;
ProgramDesc.ArgumentCount = 4;
ProgramDesc.pArguments = Args;

The layout of a single structure within the indirect argument buffer is the following:

Bytes Description
0:3 Data for root parameter index 2
4:7 Data for root parameter index 6
8:15 Virtual address of VB (64-bit)
16:19 VB size
20:23 VB stride
24:27 VertexCountPerInstance
28:31 InstanceCount
32:35 StartVertexLocation
36:39 StartInstanceLocation

 

DirectX advanced learning video tutorials : Execute Indirect and Async GPU culling

Indirect drawing and GPU culling : code walk-through

Rendering