20. 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.
A graphics pipeline must be bound to a command buffer before any drawing
commands are recorded in that command buffer.
Drawing can be achieved in two modes:
-
Programmable Mesh Shading, the mesh shader assembles primitives, or
-
Programmable Primitive Shading, the input primitives are assembled
as follows.
Each draw is made up of zero or more vertices and zero or more instances,
which are processed by the device and result in the assembly of primitives.
Primitives are assembled according to the pInputAssemblyState member
of the VkGraphicsPipelineCreateInfo structure, which is of type
VkPipelineInputAssemblyStateCreateInfo:
typedef struct VkPipelineInputAssemblyStateCreateInfo {
VkStructureType sType;
const void* pNext;
VkPipelineInputAssemblyStateCreateFlags flags;
VkPrimitiveTopology topology;
VkBool32 primitiveRestartEnable;
} VkPipelineInputAssemblyStateCreateInfo;
-
sTypeis the type of this structure. -
pNextisNULLor a pointer to an extension-specific structure. -
flagsis reserved for future use. -
topologyis a VkPrimitiveTopology defining the primitive topology, as described below. -
primitiveRestartEnablecontrols whether a special vertex index value is treated as restarting the assembly of primitives. This enable only applies to indexed draws (vkCmdDrawIndexed and vkCmdDrawIndexedIndirect), and the special index value is either 0xFFFFFFFF when theindexTypeparameter ofvkCmdBindIndexBufferis equal toVK_INDEX_TYPE_UINT32, or 0xFFFF whenindexTypeis equal toVK_INDEX_TYPE_UINT16. Primitive restart is not allowed for “list” topologies.
Restarting the assembly of primitives discards the most recent index values
if those elements formed an incomplete primitive, and restarts the primitive
assembly using the subsequent indices, but only assembling the immediately
following element through the end of the originally specified elements.
The primitive restart index value comparison is performed before adding the
vertexOffset value to the index value.
typedef VkFlags VkPipelineInputAssemblyStateCreateFlags;
VkPipelineInputAssemblyStateCreateFlags is a bitmask type for setting
a mask, but is currently reserved for future use.
20.1. 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.
The primitive topologies defined by VkPrimitiveTopology are:
typedef enum VkPrimitiveTopology {
VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0,
VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1,
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5,
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6,
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9,
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10,
VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF
} VkPrimitiveTopology;
-
VK_PRIMITIVE_TOPOLOGY_POINT_LISTspecifies a series of separate point primitives. -
VK_PRIMITIVE_TOPOLOGY_LINE_LISTspecifies a series of separate line primitives. -
VK_PRIMITIVE_TOPOLOGY_LINE_STRIPspecifies a series of connected line primitives with consecutive lines sharing a vertex. -
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LISTspecifies a series of separate triangle primitives. -
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIPspecifies a series of connected triangle primitives with consecutive triangles sharing an edge. -
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FANspecifies a series of connected triangle primitives with all triangles sharing a common vertex. -
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCYspecifies a series separate line primitives with adjacency. -
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCYspecifies a series connected line primitives with adjacency, with consecutive primitives sharing three vertices. -
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCYspecifies a series separate triangle primitives with adjacency. -
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCYspecifies connected triangle primitives with adjacency, with consecutive triangles sharing an edge. -
VK_PRIMITIVE_TOPOLOGY_PATCH_LISTspecifies separate patch primitives.
Each primitive topology, and its construction from a list of vertices, is described in detail below with a supporting diagram, according to the following key:
Vertex |
A point in 3-dimensional space. Positions chosen within the diagrams are arbitrary and for illustration only. |
|
Vertex Number |
Sequence position of a vertex within the provided vertex data. |
|
Provoking Vertex |
Provoking vertex within the main primitive. The arrow points along an edge of the relevant primitive, following winding order. Used in flat shading. |
|
Primitive Edge |
An edge connecting the points of a main primitive. |
|
Adjacency Edge |
Points connected by these lines do not contribute to a main primitive, and are only accessible in a geometry shader. |
|
Winding Order |
The relative order in which vertices are defined within a primitive, used in the facing determination. This ordering has no specific start or end point. |
The diagrams are supported with mathematical definitions where the vertices (v) and primitives (p) are numbered starting from 0; v0 is the first vertex in the provided data and p0 is the first primitive in the set of primitives defined by the vertices and topology.
20.1.1. 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.
20.1.2. Line Lists
When the 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 provoking vertex for pi is v2i.
The number of primitives generated is equal to
⌊vertexCount/2⌋.
20.1.3. Line Strips
When the 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 provoking vertex for pi is vi.
The number of primitives generated is equal to
max(0,vertexCount-1).
20.1.4. Triangle Lists
When the 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 provoking vertex for pi is v3i.
The number of primitives generated is equal to
⌊vertexCount/3⌋.
20.1.5. Triangle Strips
When the 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 provoking vertex for pi is vi.
The number of primitives generated is equal to
max(0,vertexCount-2).
|
Note
The ordering of the vertices in each successive triangle is reversed, so that the winding order is consistent throughout the strip. |
20.1.6. Triangle Fans
When the 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 provoking vertex for pi is vi+1.
The number of primitives generated is equal to
max(0,vertexCount-2).
20.1.7. Line Lists With Adjacency
When the 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 provoking vertex for pi is v4i+1.
The number of primitives generated is equal to
⌊vertexCount/4⌋.
20.1.8. Line Strips With Adjacency
When the 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 provoking vertex for pi is vi+1.
The number of primitives generated is equal to
max(0,vertexCount-3).
20.1.9. Triangle Lists With Adjacency
When the 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 provoking vertex for pi is v6i.
The number of primitives generated is equal to
⌊vertexCount/6⌋.
20.1.10. Triangle Strips With Adjacency
When the 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.
|
Note
The ordering of the vertices in each successive triangle is altered so that the winding order is consistent throughout the strip. |
The provoking vertex for pi is always v2i.
20.1.11. Patch Lists
When the 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.
20.2. 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:
-
Submission order determines the initial ordering
-
For indirect draw commands, the order in which accessed instances of the VkDrawIndirectCommand are stored in
buffer, from lower indirect buffer addresses to higher addresses. -
If a draw command includes multiple instances, the order in which instances are executed, from lower numbered instances to higher.
-
The order in which primitives are specified by a draw command:
-
For non-indexed draws, from vertices with a lower numbered
vertexIndexto a higher numberedvertexIndex. -
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.
-
Within this order implementations further sort primitives:
-
If tessellation shading is active, by an implementation-dependent order of new primitives generated by tessellation.
-
If geometry shading is active, by the order new primitives are generated by geometry shading.
-
If the polygon mode is not
VK_POLYGON_MODE_FILL, orVK_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.
20.3. 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:
-
Non-indexed drawing commands present a sequential
vertexIndexto the vertex shader. The sequential index is generated automatically by the device (see Fixed-Function Vertex Processing for details on both specifying the vertex attributes indexed byvertexIndex, as well as binding vertex buffers containing those attributes to a command buffer). These commands are: -
Indexed drawing commands read index values from an index buffer and use this to compute the
vertexIndexvalue for the vertex shader. These commands are:
To bind an index buffer to a command buffer, call:
void vkCmdBindIndexBuffer(
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkIndexType indexType);
-
commandBufferis the command buffer into which the command is recorded. -
bufferis the buffer being bound. -
offsetis the starting offset in bytes withinbufferused in index buffer address calculations. -
indexTypeis a VkIndexType value specifying whether indices are treated as 16 bits or 32 bits.
Possible values of vkCmdBindIndexBuffer::indexType, specifying
the size of indices, are:
typedef enum VkIndexType {
VK_INDEX_TYPE_UINT16 = 0,
VK_INDEX_TYPE_UINT32 = 1,
VK_INDEX_TYPE_NONE_NV = 1000165000,
VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF
} VkIndexType;
-
VK_INDEX_TYPE_UINT16specifies that indices are 16-bit unsigned integer values. -
VK_INDEX_TYPE_UINT32specifies that indices are 32-bit unsigned integer values. -
VK_INDEX_TYPE_NONE_NVspecifies that no indices are provided.
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.
To record a non-indexed draw, call:
void vkCmdDraw(
VkCommandBuffer commandBuffer,
uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance);
-
commandBufferis the command buffer into which the command is recorded. -
vertexCountis the number of vertices to draw. -
instanceCountis the number of instances to draw. -
firstVertexis the index of the first vertex to draw. -
firstInstanceis the instance ID of the first instance to draw.
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 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);
-
commandBufferis the command buffer into which the command is recorded. -
indexCountis the number of vertices to draw. -
instanceCountis the number of instances to draw. -
firstIndexis the base index within the index buffer. -
vertexOffsetis the value added to the vertex index before indexing into the vertex buffer. -
firstInstanceis the instance ID of the first instance to draw.
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 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 bound graphics pipeline.
To record a non-indexed indirect draw, call:
void vkCmdDrawIndirect(
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride);
-
commandBufferis the command buffer into which the command is recorded. -
bufferis the buffer containing draw parameters. -
offsetis the byte offset intobufferwhere parameters begin. -
drawCountis the number of draws to execute, and can be zero. -
strideis the byte stride between successive sets of draw parameters.
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;
-
vertexCountis the number of vertices to draw. -
instanceCountis the number of instances to draw. -
firstVertexis the index of the first vertex to draw. -
firstInstanceis the instance ID of the first instance to draw.
The members of VkDrawIndirectCommand have the same meaning as the
similarly named parameters of vkCmdDraw.
To record a non-indexed draw call with a draw call count sourced from a buffer, call:
void vkCmdDrawIndirectCountKHR(
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkBuffer countBuffer,
VkDeviceSize countBufferOffset,
uint32_t maxDrawCount,
uint32_t stride);
or the equivalent command
void vkCmdDrawIndirectCountAMD(
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkBuffer countBuffer,
VkDeviceSize countBufferOffset,
uint32_t maxDrawCount,
uint32_t stride);
-
commandBufferis the command buffer into which the command is recorded. -
bufferis the buffer containing draw parameters. -
offsetis the byte offset intobufferwhere parameters begin. -
countBufferis the buffer containing the draw count. -
countBufferOffsetis the byte offset intocountBufferwhere the draw count begins. -
maxDrawCountspecifies the maximum number of draws that will be executed. The actual number of executed draw calls is the minimum of the count specified incountBufferandmaxDrawCount. -
strideis the byte stride between successive sets of draw parameters.
vkCmdDrawIndirectCountKHR behaves similarly to vkCmdDrawIndirect
except that the draw count is read by the device from a buffer during
execution.
The command will read an unsigned 32-bit integer from countBuffer
located at countBufferOffset and use this as the draw count.
To record an indexed indirect draw, call:
void vkCmdDrawIndexedIndirect(
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride);
-
commandBufferis the command buffer into which the command is recorded. -
bufferis the buffer containing draw parameters. -
offsetis the byte offset intobufferwhere parameters begin. -
drawCountis the number of draws to execute, and can be zero. -
strideis the byte stride between successive sets of draw parameters.
vkCmdDrawIndexedIndirect behaves similarly to vkCmdDrawIndexed
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;
-
indexCountis the number of vertices to draw. -
instanceCountis the number of instances to draw. -
firstIndexis the base index within the index buffer. -
vertexOffsetis the value added to the vertex index before indexing into the vertex buffer. -
firstInstanceis the instance ID of the first instance to draw.
The members of VkDrawIndexedIndirectCommand have the same meaning as
the similarly named parameters of vkCmdDrawIndexed.
To record an indexed draw call with a draw call count sourced from a buffer, call:
void vkCmdDrawIndexedIndirectCountKHR(
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkBuffer countBuffer,
VkDeviceSize countBufferOffset,
uint32_t maxDrawCount,
uint32_t stride);
or the equivalent command
void vkCmdDrawIndexedIndirectCountAMD(
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkBuffer countBuffer,
VkDeviceSize countBufferOffset,
uint32_t maxDrawCount,
uint32_t stride);
-
commandBufferis the command buffer into which the command is recorded. -
bufferis the buffer containing draw parameters. -
offsetis the byte offset intobufferwhere parameters begin. -
countBufferis the buffer containing the draw count. -
countBufferOffsetis the byte offset intocountBufferwhere the draw count begins. -
maxDrawCountspecifies the maximum number of draws that will be executed. The actual number of executed draw calls is the minimum of the count specified incountBufferandmaxDrawCount. -
strideis the byte stride between successive sets of draw parameters.
vkCmdDrawIndexedIndirectCountKHR behaves similarly to
vkCmdDrawIndexedIndirect except that the draw count is read by the
device from a buffer during execution.
The command will read an unsigned 32-bit integer from countBuffer
located at countBufferOffset and use this as the draw count.
20.3.1. 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.
To record a non-indexed draw call, where the vertex count is based on a byte count read from a buffer and the passed in vertex stride parameter, call:
void vkCmdDrawIndirectByteCountEXT(
VkCommandBuffer commandBuffer,
uint32_t instanceCount,
uint32_t firstInstance,
VkBuffer counterBuffer,
VkDeviceSize counterBufferOffset,
uint32_t counterOffset,
uint32_t vertexStride);
-
commandBufferis the command buffer into which the command is recorded. -
instanceCountis the number of instances to draw. -
firstInstanceis the instance ID of the first instance to draw. -
counterBufferis the buffer handle from where the byte count is read. -
counterBufferOffsetis the offset into the buffer used to read the byte count, which is used to calculate the vertex count for this draw call. -
counterOffsetis subtracted from the byte count read from thecounterBufferat thecounterBufferOffset -
vertexStrideis the stride in bytes between each element of the vertex data that is used to calculate the vertex count from the counter value. This value is typically the same value that was used in the graphics pipeline state when the transform feedback was captured as theXfbStride.
When the command is executed, primitives are assembled in the same way as
done with vkCmdDraw except the vertexCount is calculated based
on the byte count read from counterBuffer at offset
counterBufferOffset.
The assembled primitives execute the bound graphics pipeline.
The effective vertexCount is calculated as follows:
const uint32_t * counterBufferPtr = (const uint8_t *)counterBuffer.address + counterBufferOffset;
vertexCount = floor(max(0, (*counterBufferPtr - counterOffset)) / vertexStride);
The effective firstVertex is zero.
20.4. 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 inherited conditional rendering 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).
To begin conditional rendering, call:
void vkCmdBeginConditionalRenderingEXT(
VkCommandBuffer commandBuffer,
const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin);
-
commandBufferis the command buffer into which this command will be recorded. -
pConditionalRenderingBeginis a pointer to an instance of the VkConditionalRenderingBeginInfoEXT structure specifying the parameters of conditional rendering.
The VkConditionalRenderingBeginInfoEXT structure is defined as:
typedef struct VkConditionalRenderingBeginInfoEXT {
VkStructureType sType;
const void* pNext;
VkBuffer buffer;
VkDeviceSize offset;
VkConditionalRenderingFlagsEXT flags;
} VkConditionalRenderingBeginInfoEXT;
-
sTypeis the type of this structure. -
pNextisNULLor a pointer to an extension-specific structure. -
bufferis a buffer containing the predicate for conditional rendering. -
offsetis the byte offset intobufferwhere the predicate is located. -
flagsis a bitmask of VkConditionalRenderingFlagsEXT specifying the behavior of conditional rendering.
If the 32-bit value at offset in buffer memory is zero, then the
rendering commands are discarded, otherwise they are executed as normal.
If the value of the predicate in buffer memory changes while conditional
rendering is active, the rendering commands may be discarded in an
implementation-dependent way.
Some implementations may latch the value of the predicate upon beginning
conditional rendering while others may read it before every rendering
command.
Bits which can be set in
vkCmdBeginConditionalRenderingEXT::flags specifying the behavior
of conditional rendering are:
typedef enum VkConditionalRenderingFlagBitsEXT {
VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 0x00000001,
VK_CONDITIONAL_RENDERING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
} VkConditionalRenderingFlagBitsEXT;
-
VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXTspecifies the condition used to determine whether to discard rendering commands or not. That is, if the 32-bit predicate read frombuffermemory atoffsetis zero, the rendering commands are not discarded, and if non zero, then they are discarded.
typedef VkFlags VkConditionalRenderingFlagsEXT;
VkConditionalRenderingFlagsEXT is a bitmask type for setting a mask of
zero or more VkConditionalRenderingFlagBitsEXT.
To end conditional rendering, call:
void vkCmdEndConditionalRenderingEXT(
VkCommandBuffer commandBuffer);
-
commandBufferis the command buffer into which this command will be recorded.
Once ended, conditional rendering becomes inactive.
20.5. 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.
To record a draw that uses the mesh pipeline, call:
void vkCmdDrawMeshTasksNV(
VkCommandBuffer commandBuffer,
uint32_t taskCount,
uint32_t firstTask);
-
commandBufferis the command buffer into which the command will be recorded. -
taskCountis the number of local workgroups to dispatch in the X dimension. Y and Z dimension are implicitly set to one. -
firstTaskis the X component of the first workgroup ID.
When the command is executed, a global workgroup consisting of
taskCount local workgroups is assembled.
To record an indirect mesh tasks draw, call:
void vkCmdDrawMeshTasksIndirectNV(
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride);
-
commandBufferis the command buffer into which the command is recorded. -
bufferis the buffer containing draw parameters. -
offsetis the byte offset intobufferwhere parameters begin. -
drawCountis the number of draws to execute, and can be zero. -
strideis the byte stride between successive sets of draw parameters.
vkCmdDrawMeshTasksIndirectNV behaves similarly to
vkCmdDrawMeshTasksNV 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
VkDrawMeshTasksIndirectCommandNV structures.
If drawCount is less than or equal to one, stride is ignored.
The VkDrawMeshTasksIndirectCommandNV structure is defined as:
typedef struct VkDrawMeshTasksIndirectCommandNV {
uint32_t taskCount;
uint32_t firstTask;
} VkDrawMeshTasksIndirectCommandNV;
-
taskCountis the number of local workgroups to dispatch in the X dimension. Y and Z dimension are implicitly set to one. -
firstTaskis the X component of the first workgroup ID.
The members of VkDrawMeshTasksIndirectCommandNV have the same meaning
as the similarly named parameters of vkCmdDrawMeshTasksNV.
To record an indirect mesh tasks draw with the draw count sourced from a buffer, call:
void vkCmdDrawMeshTasksIndirectCountNV(
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkBuffer countBuffer,
VkDeviceSize countBufferOffset,
uint32_t maxDrawCount,
uint32_t stride);
-
commandBufferis the command buffer into which the command is recorded. -
bufferis the buffer containing draw parameters. -
offsetis the byte offset intobufferwhere parameters begin. -
countBufferis the buffer containing the draw count. -
countBufferOffsetis the byte offset intocountBufferwhere the draw count begins. -
maxDrawCountspecifies the maximum number of draws that will be executed. The actual number of executed draw calls is the minimum of the count specified incountBufferandmaxDrawCount. -
strideis the byte stride between successive sets of draw parameters.
vkCmdDrawMeshTasksIndirectCountNV behaves similarly to
vkCmdDrawMeshTasksIndirectNV except that the draw count is read by the
device from a buffer during execution.
The command will read an unsigned 32-bit integer from countBuffer
located at countBufferOffset and use this as the draw count.