Command Buffers

VkCommandBufferOpaque handle to a command buffer object

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.

commandbuffer lifecycle

The pending state is tied entirely to the status of execution of a command buffer’s commands; once all commands are finished executing, the command buffer is in the subsequent state (executable or invalid) with no further intervention.Detection of the final command in a command buffer completing all stages of execution (i.e. 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.

Resetting or freeing a primary command buffer removes the lifecycle linkage to all secondary command buffers that were recorded into it.

Command Pools

VkCommandPoolOpaque handle to a command pool object
vkCreateCommandPoolCreate a new command pool object
VkCommandPoolCreateInfoStructure specifying parameters of a newly created command pool
VkCommandPoolCreateFlagBitsBitmask specifying usage behavior for a command pool
VkCommandPoolCreateFlagsBitmask of VkCommandPoolCreateFlagBits
vkTrimCommandPoolTrim a command pool
VkCommandPoolTrimFlagsReserved for future use
vkResetCommandPoolReset a command pool
VkCommandPoolResetFlagBitsBitmask controlling behavior of a command pool reset
VkCommandPoolResetFlagsBitmask of VkCommandPoolResetFlagBits
vkDestroyCommandPoolDestroy a command pool object

Command Buffer Allocation and Management

vkAllocateCommandBuffersAllocate command buffers from an existing command pool
VkCommandBufferAllocateInfoStructure specifying the allocation parameters for command buffer object
VkCommandBufferLevelEnumerant specifying a command buffer level
vkResetCommandBufferReset a command buffer to the initial state
VkCommandBufferResetFlagBitsBitmask controlling behavior of a command buffer reset
VkCommandBufferResetFlagsBitmask of VkCommandBufferResetFlagBits
vkFreeCommandBuffersFree command buffers

Command Buffer Recording

vkBeginCommandBufferStart recording a command buffer
VkCommandBufferBeginInfoStructure specifying a command buffer begin operation
VkCommandBufferUsageFlagBitsBitmask specifying usage behavior for command buffer
VkCommandBufferUsageFlagsBitmask of VkCommandBufferUsageFlagBits
VkCommandBufferInheritanceInfoStructure specifying command buffer inheritance information
On some implementations, not using the 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.

VkCommandBufferInheritanceConditionalRenderingInfoEXTStructure specifying command buffer inheritance information
VkCommandBufferInheritanceRenderPassTransformInfoQCOMStructure describing transformed render pass parameters command buffer
VkCommandBufferInheritanceViewportScissorInfoNVStructure specifying command buffer inheritance information
VkCommandBufferInheritanceRenderingInfoStructure specifying command buffer inheritance info for dynamic render pass instances
VkAttachmentSampleCountInfoAMDStructure specifying command buffer inheritance info for dynamic render pass instances
VkCommandBufferInheritanceDescriptorHeapInfoEXTStructure specifying command buffer inheritance information

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.

vkEndCommandBufferFinish recording a command buffer

When a command buffer is in the executable state, it can be submitted to a queue for execution.

Command Buffer Submission

Submission can be a high overhead operation, and applications should attempt to batch work together into as few calls to vkQueueSubmit or vkQueueSubmit2 as possible.
vkQueueSubmit2Submits command buffers to a queue
VkSubmitInfo2Structure specifying a queue submit operation
VkSubmitFlagBitsBitmask specifying behavior of a submission
VkSubmitFlagsBitmask of VkSubmitFlagBits
VkSemaphoreSubmitInfoStructure specifying a semaphore signal or wait operation
VkCommandBufferSubmitInfoStructure specifying a command buffer submission
VkRenderPassStripeSubmitInfoARMStructure specifying striped rendering submit information
vkQueueSubmitSubmits a sequence of semaphores or command buffers to a queue
VkSubmitInfoStructure specifying a queue submit operation
VkTimelineSemaphoreSubmitInfoStructure specifying signal and wait values for timeline semaphores
VkD3D12FenceSubmitInfoKHRStructure specifying values for Direct3D 12 fence-backed semaphores
VkWin32KeyedMutexAcquireReleaseInfoKHRUse the Windows keyed mutex mechanism to synchronize work
VkWin32KeyedMutexAcquireReleaseInfoNVUse Windows keyex mutex mechanism to synchronize work
VkProtectedSubmitInfoStructure indicating whether the submission is protected
VkDeviceGroupSubmitInfoStructure indicating which physical devices execute semaphore operations and command buffers

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.

VkPerformanceQuerySubmitInfoKHRStructure indicating which counter pass index is active for performance queries

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.

The ability for commands to wait on the host to set an events was originally added to allow low-latency updates to resources between host and device. However, to ensure quality of service, implementations would necessarily detect extended stalls in execution and timeout after a short period. As this period is not defined in the Vulkan specification, it is impossible to correctly validate any application with any wait period. Since the original users of this functionality were highly limited and platform-specific, this functionality is now considered defunct and should not be used.

Secondary Command Buffer Execution

vkCmdExecuteCommandsExecute a secondary command buffer from a primary command buffer

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.

VkDeviceGroupCommandBufferBeginInfoSet the initial device mask for a command buffer
vkCmdSetDeviceMaskModify device mask of a command buffer