19.2. Programmable Primitive Shading

Once primitives are assembled, they proceed to the vertex shading stage of the pipeline. If the draw includes multiple instances, then the set of primitives is sent to the vertex shading stage multiple times, once for each instance.

It is undefined whether vertex shading occurs on vertices that are discarded as part of incomplete primitives, but if it does occur then it operates as if they were vertices in complete primitives and such invocations can have side effects.

Vertex shading receives two per-vertex inputs from the primitive assembly stage - the vertexIndex and the instanceIndex. How these values are generated is defined below, with each command.

Drawing commands fall roughly into two categories:

An index buffer is bound to a command buffer by calling:

 

void vkCmdBindIndexBuffer(
    VkCommandBuffer                             commandBuffer,
    VkBuffer                                    buffer,
    VkDeviceSize                                offset,
    VkIndexType                                 indexType);

 

typedef enum VkIndexType {
    VK_INDEX_TYPE_UINT16 = 0,
    VK_INDEX_TYPE_UINT32 = 1,
} VkIndexType;

The parameters for each drawing command are specified directly in the command or read from buffer memory, depending on the command. Drawing commands that source their parameters from buffer memory are known as indirect drawing commands.

All drawing commands interact with the Robust Buffer Access feature.

Primitives assembled by draw commands are considered to have an API order, which defines the order their fragments affect the framebuffer. When a draw command includes multiple instances, the lower numbered instances are earlier in API order. For non-indexed draws, primitives with lower numbered vertexIndex values are earlier in API order. For indexed draws, primitives assembled from lower index buffer addresses are earlier in API order.

To record a non-indexed draw, call:

 

void vkCmdDraw(
    VkCommandBuffer                             commandBuffer,
    uint32_t                                    vertexCount,
    uint32_t                                    instanceCount,
    uint32_t                                    firstVertex,
    uint32_t                                    firstInstance);

When the command is executed, primitives are assembled using the current primitive topology and vertexCount consecutive vertex indices with the first vertexIndex value equal to firstVertex. The primitives are drawn instanceCount times with instanceIndex starting with firstInstance and increasing sequentially for each instance. The assembled primitives execute the currently bound graphics pipeline.

To record an indexed draw, call:

 

void vkCmdDrawIndexed(
    VkCommandBuffer                             commandBuffer,
    uint32_t                                    indexCount,
    uint32_t                                    instanceCount,
    uint32_t                                    firstIndex,
    int32_t                                     vertexOffset,
    uint32_t                                    firstInstance);

When the command is executed, primitives are assembled using the current primitive topology and indexCount vertices whose indices are retrieved from the index buffer. The index buffer is treated as an array of tightly packed unsigned integers of size defined by the vkCmdBindIndexBuffer::indexType parameter with which the buffer was bound.

The first vertex index is at an offset of firstIndex * indexSize + offset within the currently bound index buffer, where offset is the offset specified by vkCmdBindIndexBuffer and indexSize is the byte size of the type specified by indexType. Subsequent index values are retrieved from consecutive locations in the index buffer. Indices are first compared to the primitive restart value, then zero extended to 32 bits (if the indexType is VK_INDEX_TYPE_UINT16) and have vertexOffset added to them, before being supplied as the vertexIndex value.

The primitives are drawn instanceCount times with instanceIndex starting with firstInstance and increasing sequentially for each instance. The assembled primitives execute the currently bound graphics pipeline.

A non-indexed indirect draw is recorded by calling:

 

void vkCmdDrawIndirect(
    VkCommandBuffer                             commandBuffer,
    VkBuffer                                    buffer,
    VkDeviceSize                                offset,
    uint32_t                                    drawCount,
    uint32_t                                    stride);

vkCmdDrawIndirect behaves similarly to vkCmdDraw except that the parameters are read by the device from a buffer during execution. drawCount draws are executed by the command, with parameters taken from buffer starting at offset and increasing by stride bytes for each successive draw. The parameters of each draw are encoded in an array of VkDrawIndirectCommand structures. If drawCount is less than or equal to one, stride is ignored.

The VkDrawIndirectCommand structure is defined as:

 

typedef struct VkDrawIndirectCommand {
    uint32_t    vertexCount;
    uint32_t    instanceCount;
    uint32_t    firstVertex;
    uint32_t    firstInstance;
} VkDrawIndirectCommand;

The members of VkDrawIndirectCommand have the same meaning as the similarly named parameters of vkCmdDraw.

An indexed indirect draw is recorded by calling:

 

void vkCmdDrawIndexedIndirect(
    VkCommandBuffer                             commandBuffer,
    VkBuffer                                    buffer,
    VkDeviceSize                                offset,
    uint32_t                                    drawCount,
    uint32_t                                    stride);

vkCmdDrawIndexedIndirect behaves similarly to vkCmdDrawIndirect except that the parameters are read by the device from a buffer during execution. drawCount draws are executed by the command, with parameters taken from buffer starting at offset and increasing by stride bytes for each successive draw. The parameters of each draw are encoded in an array of VkDrawIndexedIndirectCommand structures. If drawCount is less than or equal to one, stride is ignored.

The VkDrawIndexedIndirectCommand structure is defined as:

 

typedef struct VkDrawIndexedIndirectCommand {
    uint32_t    indexCount;
    uint32_t    instanceCount;
    uint32_t    firstIndex;
    int32_t     vertexOffset;
    uint32_t    firstInstance;
} VkDrawIndexedIndirectCommand;

The members of VkDrawIndexedIndirectCommand have the same meaning as the similarly named parameters of vkCmdDrawIndexed.