Drawing Commands

Drawing commands (commands with Draw in the name) provoke work in a graphics pipeline. Drawing commands are recorded into a command buffer and when executed by a queue, will produce work which executes according to the bound graphics pipeline, or if the shaderObject feature is enabled, any shader objects bound to graphics stages. A graphics pipeline or a combination of one or more graphics shader objects must be bound to a command buffer before any drawing commands are recorded in that command buffer.

VkPipelineInputAssemblyStateCreateInfoStructure specifying parameters of a newly created pipeline input assembly state
VkPipelineInputAssemblyStateCreateFlagsReserved for future use
vkCmdSetPrimitiveRestartEnableSet primitive assembly restart state dynamically for a command buffer

Primitive Topologies

Primitive topology determines how consecutive vertices are organized into primitives, and determines the type of primitive that is used at the beginning of the graphics pipeline. The effective topology for later stages of the pipeline is altered by tessellation or geometry shading (if either is in use) and depends on the execution modes of those shaders. In the case of mesh shading the only effective topology is defined by the execution mode of the mesh shader.

VkPrimitiveTopologySupported primitive topologies
vkCmdSetPrimitiveTopologySet primitive topology state dynamically for a command buffer

Topology Class

The primitive topologies are grouped into the following topology classes:

Point Lists

When the topology is VK_PRIMITIVE_TOPOLOGY_POINT_LIST, each consecutive vertex defines a single point primitive, according to the equation:

pi = {vi}

As there is only one vertex, that vertex is the provoking vertex. The number of primitives generated is equal to vertexCount.

Line Lists

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_LINE_LIST, each consecutive pair of vertices defines a single line primitive, according to the equation:

pi = {v2i, v2i+1}

The number of primitives generated is equal to ⌊vertexCount/2⌋.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT, the provoking vertex for pi is v2i.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT, the provoking vertex for pi is v2i+1.

Line Strips

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, one line primitive is defined by each vertex and the following vertex, according to the equation:

pi = {vi, vi+1}

The number of primitives generated is equal to max(0,vertexCount-1).

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT, the provoking vertex for pi is vi.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT, the provoking vertex for pi is vi+1.

Triangle Lists

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, each consecutive set of three vertices defines a single triangle primitive, according to the equation:

pi = {v3i, v3i+1, v3i+2}

The number of primitives generated is equal to ⌊vertexCount/3⌋.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT, the provoking vertex for pi is v3i.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT, the provoking vertex for pi is v3i+2.

Triangle Strips

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, one triangle primitive is defined by each vertex and the two vertices that follow it, according to the equation:

pi = {vi, vi+(1+i%2), vi+(2-i%2)}

The number of primitives generated is equal to max(0,vertexCount-2).

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT, the provoking vertex for pi is vi.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT, the provoking vertex for pi is vi+2.

The ordering of the vertices in each successive triangle is reversed, so that the winding order is consistent throughout the strip.

Triangle Fans

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, triangle primitives are defined around a shared common vertex, according to the equation:

pi = {vi+1, vi+2, v0}

The number of primitives generated is equal to max(0,vertexCount-2).

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT, the provoking vertex for pi is vi+1.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT, the provoking vertex for pi is vi+2.

If the VK_KHR_portability_subset extension is enabled, and VkPhysicalDevicePortabilitySubsetFeaturesKHR::triangleFans is VK_FALSE, then triangle fans are not supported by the implementation, and VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN must not be used.

Line Lists With Adjacency

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, each consecutive set of four vertices defines a single line primitive with adjacency, according to the equation:

pi = {v4i, v4i+1, v4i+2,v4i+3}

A line primitive is described by the second and third vertices of the total primitive, with the remaining two vertices only accessible in a geometry shader.

The number of primitives generated is equal to ⌊vertexCount/4⌋.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT, the provoking vertex for pi is v4i+1.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT, the provoking vertex for pi is v4i+2.

Line Strips With Adjacency

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, one line primitive with adjacency is defined by each vertex and the following vertex, according to the equation:

pi = {vi, vi+1, vi+2, vi+3}

A line primitive is described by the second and third vertices of the total primitive, with the remaining two vertices only accessible in a geometry shader.

The number of primitives generated is equal to max(0,vertexCount-3).

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT, the provoking vertex for pi is vi+1.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT, the provoking vertex for pi is vi+2.

Triangle Lists With Adjacency

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, each consecutive set of six vertices defines a single triangle primitive with adjacency, according to the equations:

pi = {v6i, v6i+1, v6i+2, v6i+3, v6i+4, v6i+5}

A triangle primitive is described by the first, third, and fifth vertices of the total primitive, with the remaining three vertices only accessible in a geometry shader.

The number of primitives generated is equal to ⌊vertexCount/6⌋.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT, the provoking vertex for pi is v6i.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT, the provoking vertex for pi is v6i+4.

Triangle Strips With Adjacency

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, one triangle primitive with adjacency is defined by each vertex and the following 5 vertices.

The number of primitives generated, n, is equal to ⌊max(0, vertexCount - 4)/2⌋.

If n=1, the primitive is defined as:

p = {v0, v1, v2, v5, v4, v3}

If n>1, the total primitive consists of different vertices according to where it is in the strip:

pi = {v2i, v2i+1, v2i+2, v2i+6, v2i+4, v2i+3} when i=0

pi = {v2i, v2i+3, v2i+4, v2i+6, v2i+2, v2i-2} when i>0, i<n-1, and i%2=1

pi = {v2i, v2i-2, v2i+2, v2i+6, v2i+4, v2i+3} when i>0, i<n-1, and i%2=0

pi = {v2i, v2i+3, v2i+4, v2i+5, v2i+2, v2i-2} when i=n-1 and i%2=1

pi = {v2i, v2i-2, v2i+2, v2i+5, v2i+4, v2i+3} when i=n-1 and i%2=0

A triangle primitive is described by the first, third, and fifth vertices of the total primitive in all cases, with the remaining three vertices only accessible in a geometry shader.

The ordering of the vertices in each successive triangle is altered so that the winding order is consistent throughout the strip.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT, the provoking vertex for pi is always v2i.

When the provokingVertexMode is VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT, the provoking vertex for pi is always v2i+4.

Patch Lists

When the primitive topology is VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, each consecutive set of m vertices defines a single patch primitive, according to the equation:

pi = {vmi, vmi+1, …​, vmi+(m-2), vmi+(m-1)}

where m is equal to VkPipelineTessellationStateCreateInfo::patchControlPoints.

Patch lists are never passed to vertex post-processing, and as such no provoking vertex is defined for patch primitives. The number of primitives generated is equal to ⌊vertexCount/m⌋.

The vertices comprising a patch have no implied geometry, and are used as inputs to tessellation shaders and the fixed-function tessellator to generate new point, line, or triangle primitives.

Primitive Order

Primitives generated by drawing commands progress through the stages of the graphics pipeline in primitive order. Primitive order is initially determined in the following way:

  1. Submission order determines the initial ordering
  2. For indirect drawing commands, the order in which accessed instances of the VkDrawIndirectCommand are stored in buffer, from lower indirect buffer addresses to higher addresses.
  3. If a drawing command includes multiple instances, the order in which instances are executed, from lower numbered instances to higher.
  4. The order in which primitives are specified by a drawing command:
    • For non-indexed draws, from vertices with a lower numbered vertexIndex to a higher numbered vertexIndex.
    • For indexed draws, vertices sourced from a lower index buffer addresses to higher addresses.
    • For draws using mesh shaders, the order is provided by mesh shading.
    • For draws using cluster culling shaders, the order is provided by cluster culling shading.

Within this order implementations further sort primitives:

  1. If tessellation shading is active, by an implementation-dependent order of new primitives generated by tessellation.
  2. If geometry shading is active, by the order new primitives are generated by geometry shading.
  3. If the polygon mode is not VK_POLYGON_MODE_FILL, or VK_POLYGON_MODE_FILL_RECTANGLE_NV, by an implementation-dependent ordering of the new primitives generated within the original primitive.

Primitive order is later used to define rasterization order, which determines the order in which fragments output results to a framebuffer.

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 implementation-dependent 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:

vkCmdBindIndexBufferBind an index buffer to a command buffer
vkCmdBindIndexBuffer2KHRBind an index buffer to a command buffer
VkIndexTypeType of index buffer indices

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 robustBufferAccess feature.

vkCmdDrawDraw primitives
vkCmdDrawIndexedDraw primitives with indexed vertices
vkCmdDrawMultiEXTDraw primitives
vkCmdDrawMultiIndexedEXTDraw primitives
VkMultiDrawInfoEXTStructure specifying a multi-draw command
VkMultiDrawIndexedInfoEXTStructure specifying a multi-draw command
vkCmdDrawIndirectDraw primitives with indirect parameters
VkDrawIndirectCommandStructure specifying a indirect drawing command
vkCmdDrawIndirectCountDraw primitives with indirect parameters and draw count
vkCmdDrawIndexedIndirectDraw primitives with indirect parameters and indexed vertices
VkDrawIndexedIndirectCommandStructure specifying a indexed indirect drawing command
vkCmdDrawIndexedIndirectCountDraw parameters with indirect parameters, indexed vertices, and draw count

Drawing Transform Feedback

It is possible to draw vertex data that was previously captured during active transform feedback by binding one or more of the transform feedback buffers as vertex buffers. A pipeline barrier is required between using the buffers as transform feedback buffers and vertex buffers to ensure all writes to the transform feedback buffers are visible when the data is read as vertex attributes. The source access is VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT and the destination access is VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT for the pipeline stages VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT and VK_PIPELINE_STAGE_VERTEX_INPUT_BIT respectively. The value written to the counter buffer by vkCmdEndTransformFeedbackEXT can be used to determine the vertex count for the draw. A pipeline barrier is required between using the counter buffer for vkCmdEndTransformFeedbackEXT and vkCmdDrawIndirectByteCountEXT where the source access is VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT and the destination access is VK_ACCESS_INDIRECT_COMMAND_READ_BIT for the pipeline stages VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT and VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT respectively.

vkCmdDrawIndirectByteCountEXTDraw primitives with indirect parameters where the vertex count is derived from the counter byte value in the counter buffer

Conditional Rendering

Certain rendering commands can be executed conditionally based on a value in buffer memory. These rendering commands are limited to drawing commands, dispatching commands, and clearing attachments with vkCmdClearAttachments within a conditional rendering block which is defined by commands vkCmdBeginConditionalRenderingEXT and vkCmdEndConditionalRenderingEXT. Other rendering commands remain unaffected by conditional rendering.

After beginning conditional rendering, it is considered active within the command buffer it was called until it is ended with vkCmdEndConditionalRenderingEXT.

Conditional rendering must begin and end in the same command buffer. When conditional rendering is active, a primary command buffer can execute secondary command buffers if the inheritedConditionalRendering feature is enabled. For a secondary command buffer to be executed while conditional rendering is active in the primary command buffer, it must set the conditionalRenderingEnable flag of VkCommandBufferInheritanceConditionalRenderingInfoEXT, as described in the Command Buffer Recording section.

Conditional rendering must also either begin and end inside the same subpass of a render pass instance, or must both begin and end outside of a render pass instance (i.e. contain entire render pass instances).

vkCmdBeginConditionalRenderingEXTDefine the beginning of a conditional rendering block
VkConditionalRenderingBeginInfoEXTStructure specifying conditional rendering begin information
VkConditionalRenderingFlagBitsEXTSpecify the behavior of conditional rendering
VkConditionalRenderingFlagsEXTBitmask of VkConditionalRenderingFlagBitsEXT
vkCmdEndConditionalRenderingEXTDefine the end of a conditional rendering block

Programmable Mesh Shading

In this drawing approach, primitives are assembled by the mesh shader stage. Mesh shading operates similarly to dispatching compute as the shaders make use of workgroups.

vkCmdDrawMeshTasksNVDraw mesh task work items
vkCmdDrawMeshTasksIndirectNVIssue an indirect mesh tasks draw into a command buffer
VkDrawMeshTasksIndirectCommandNVStructure specifying a mesh tasks draw indirect command
vkCmdDrawMeshTasksIndirectCountNVPerform an indirect mesh tasks draw with the draw count sourced from a buffer
vkCmdDrawMeshTasksEXTDraw mesh task work items
vkCmdDrawMeshTasksIndirectEXTIssue an indirect mesh tasks draw into a command buffer
VkDrawMeshTasksIndirectCommandEXTStructure specifying a mesh tasks draw indirect command
vkCmdDrawMeshTasksIndirectCountEXTPerform an indirect mesh tasks draw with the draw count sourced from a buffer

Programmable Cluster Culling Shading

In this drawing approach, cluster are generated by the cluster culling shader stage. It operates similarly to dispatching compute as the shaders make use of workgroups.

vkCmdDrawClusterHUAWEIDraw cluster culling work items
vkCmdDrawClusterIndirectHUAWEIIssue an indirect cluster culling draw into a command buffer