Command Buffers
Recorded commands include commands to bind pipelines and descriptor sets to the command buffer, commands to modify dynamic state, commands to draw (for graphics rendering), commands to dispatch (for compute), commands to execute secondary command buffers (for primary command buffers only), commands to copy buffers and images, and other commands.
Each command buffer manages state independently of other command buffers. There is no inheritance of state across primary and secondary command buffers, or between secondary command buffers. When a command buffer begins recording, all state in that command buffer is undefined. When secondary command buffer(s) are recorded to execute on a primary command buffer, the secondary command buffer inherits no state from the primary command buffer, and all state of the primary command buffer is undefined after an execute secondary command buffer command is recorded, with the following exception(s):
- If the primary command buffer is inside a render pass instance, then the render pass and subpass state is not disturbed by executing secondary command buffers.
- If the primary command buffer has a descriptor heap bound, and the address of that descriptor heap is specified in VkCommandBufferInheritanceDescriptorHeapInfoEXT for every secondary command buffer, that heap binding is not disturbed by executing secondary command buffers.
For state dependent commands (such as draws and dispatches), any state consumed by those commands must not be undefined.
VkCommandBufferInheritanceViewportScissorInfoNV defines an exception allowing limited inheritance of dynamic viewport and scissor state.
Unless otherwise specified, and without explicit synchronization, the various commands submitted to a queue via command buffers may execute in arbitrary order relative to each other, and/or concurrently. Also, the memory side effects of those commands may not be directly visible to other commands without explicit memory dependencies. This is true within a command buffer, and across command buffers submitted to a given queue. See the synchronization chapter for information on implicit and explicit synchronization between commands.
Command Buffer Lifecycle
Each command buffer is always in one of the following states:
Initial
Command buffers in the initial state can only be transitioned to the
recording state, or freed.
When a command buffer is allocated, it is
in the initial state.
Command buffers in any state other than the pending state can be
transitioned to the initial state by calling vkResetCommandPool on
the pool they were allocated from.
Command buffers allocated from a command pool created with
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT and in any state
other than the pending state can also be transitioned to the initial
state by calling vkResetCommandBuffer.
Recording
Command buffers in the recording state can be used to record commands
via vkCmd* commands, be reset, or be freed.
Command buffers in the initial state can be transitioned to the
recording state by vkBeginCommandBuffer.
Command buffers allocated from a command pool created with
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT in the invalid,
recording, or executable state can also be transitioned to the
recording state by vkBeginCommandBuffer.
Executable
A command buffer in the executable state can be
submitted for execution, reset, freed, or
recorded to another command buffer.
Command buffers in the recording state are transitioned to the
executable state by vkEndCommandBuffer.
Command buffers in the pending state that were recorded without the
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT flag immediately
return to the executable state as the final command in the command
buffer completes all execution, which can be observed via
synchronization commands.
Pending
A command buffer in the pending state must not be modified by the
application, as it may be executing on the device.
Command buffers in the pending state that were recorded without the
VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT flag, or with the
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT flag, must not be
submitted to the device for execution.
Command buffers in the executable state can be transitioned to the
pending state by queue submission
commands.
Once commands in the command buffer have completed all execution, the
command buffer is immediately in either the executable state, or in the
invalid state if it was recorded with the
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT flag.
A synchronization command can be used to detect
when command execution is complete.
Invalid
A command buffer in the invalid state can be reset or freed.
Command buffers in any state other than the pending state will
transition to the invalid state if any memory or object, other than
VkCommandPool, that may be accessed when the command buffer is
accessed (e.g. an object bound to the command buffer) is destroyed or
freed.
Command buffers in any state other than the pending state will
transition to the invalid state if any command buffer executed within it
via vkCmdExecuteCommands transitions to any state other than the
pending or executable state.
Command buffers in the pending state that were recorded without the
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT flag are immediately
invalid as the final command in the command buffer completes all
execution, which can be observed via synchronization
commands.
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) with a
synchronization command is sufficient to ensure the
command buffer is in the expected state.Secondary command buffers can be recorded to a primary command buffer via vkCmdExecuteCommands. This partially ties the lifecycle of the two command buffers together - if the primary is submitted to a queue, both the primary and any secondaries recorded to it move to the pending state. Similarly, once execution of the primary completes, it completes for any command buffer recorded within it.
Command Pools
Command Buffer Allocation and Management
Command Buffer Recording
VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT bit enables command
buffers to be patched in-place if needed, rather than creating a copy of the
command buffer.If a command buffer is in the invalid, or
executable state, and the command buffer was allocated from a command pool
with the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT flag set,
then vkBeginCommandBuffer implicitly resets the command buffer,
behaving as if vkResetCommandBuffer had been called with
VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT not set.
After the implicit reset, commandBuffer is moved to the
recording state.
If the commandBufferInheritance
feature is enabled, all graphics and compute state including bound pipeline
state, bound shader objects, bound vertex and index buffers, bound
descriptor sets and push constants,
descriptor heaps and push data,
and all previously set dynamic state is inherited by the secondary command
buffer from the primary or secondary command buffer that executes it.
Furthermore, all of the state set by this secondary command buffer is
inherited back to the primary or secondard command buffer that executes it.
If the commandBufferInheritance
feature is not enabled there is a limited amount of inheritance of state
into the secondary command buffer as specified below.
Once recording starts, an application records a sequence of commands
(vkCmd*) to set state in the command buffer, draw, dispatch, and other
commands.
Several commands can also be recorded indirectly from VkBuffer
content, see Device-Generated Commands.
When a command buffer is in the executable state, it can be submitted to a queue for execution.
Command Buffer Submission
vkQueueSubmit
or vkQueueSubmit2
as possible.If the pNext chain of VkSubmitInfo includes a
VkPerformanceQuerySubmitInfoKHR structure, then the structure
indicates which counter pass is active for the batch in that submit.
Queue Forward Progress
When using binary semaphores, the application must ensure that command
buffer submissions will be able to complete without any subsequent
operations by the application on any queue.
After any call to vkQueueSubmit (or other queue operation), for every
queued wait on a semaphore
created with a VkSemaphoreType of VK_SEMAPHORE_TYPE_BINARY
there must be a prior signal of that semaphore that will not be consumed by
a different wait on the semaphore.
When using timeline semaphores, wait-before-signal behavior is well-defined
and applications can submit work via vkQueueSubmit defining a
timeline semaphore wait operation
before submitting a corresponding semaphore signal operation.
For each timeline semaphore wait
operation defined by a call to vkQueueSubmit, the application must
ensure that a corresponding semaphore signal operation is executed before forward progress can be
made.
If a command buffer submission waits for any events to be signaled, the application must ensure that command buffer submissions will be able to complete without any subsequent operations by the application. Events signaled by the host must be signaled before the command buffer waits on those events.
Secondary Command Buffer Execution
Nested Command Buffers
In addition to secondary command buffer execution from primary command
buffers, an implementation may support nested command
buffers, which enable secondary command buffers to be executed from other
secondary command buffers.
If the nestedCommandBuffer feature
is enabled, the implementation supports nested command
buffers.
Nested command buffer execution works the same as primary-to-secondary execution, except that it is subject to some additional implementation-defined limits.
Each secondary command buffer has a command buffer nesting
level, which is determined at vkEndCommandBuffer time and evaluated
at vkCmdExecuteCommands time.
A secondary command buffer that executes no other secondary command buffers
has a command buffer nesting level of zero.
Otherwise, the command buffer nesting level of a secondary
command buffer is equal to the maximum nesting level of all secondary
command buffers executed by that command buffer plus one.
Some implementations may have a limit on the maximum nesting level of
secondary command buffers that can be recorded.
This limit is advertised in maxCommandBufferNestingLevel.
If the nestedCommandBufferRendering feature is enabled, the implementation
supports calling vkCmdExecuteCommands inside secondary command buffers
recorded with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT.
If the nestedCommandBufferSimultaneousUse feature is enabled, the
implementation supports calling vkCmdExecuteCommands with secondary
command buffers recorded with
VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT.
Whenever vkCmdExecuteCommands is recorded inside a secondary command
buffer recorded with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT,
each member of pCommandBuffers must have been recorded with a
VkCommandBufferBeginInfo with VkCommandBufferInheritanceInfo
compatible with the VkCommandBufferInheritanceInfo of the command
buffer into which the vkCmdExecuteCommands call is being recorded.
The VkCommandBufferInheritanceRenderingInfo structures are compatible
when the VkCommandBufferInheritanceRenderingInfo::renderpass are
compatible, or if they are
VK_NULL_HANDLE then the VkCommandBufferInheritanceRenderingInfo
members match, and all other members of
VkCommandBufferInheritanceRenderingInfo match.
This requirement applies recursively, down to the most nested command buffer
and up to the command buffer where the render pass was originally begun.
Command Buffer Device Mask
Each command buffer has a piece of state storing the current device mask of the command buffer. This mask controls which physical devices within the logical device all subsequent commands will execute on, including state-setting commands, action commands, and synchronization commands.
Scissor, exclusive scissor, and viewport state (excluding the count of each) can be different values on each physical device (only when set as dynamic state), and each physical device will render using its local copy of the state. Other state is shared between physical devices, such that all physical devices use the most recently set values for the state. However, when recording an action command that uses a piece of state, the most recent command that set that state must have included all physical devices that execute the action command in its current device mask.
The command buffer’s device mask is orthogonal to the
pCommandBufferDeviceMasks member of VkDeviceGroupSubmitInfo.
Commands only execute on a physical device if the device index is set in
both device masks.