当前位置: 华文问答 > 游戏

Vulkan 1.2 Spec Notes

2021-11-22游戏

6. Command Buffers

有两种level的command buffer:

  • Primary Command Buffer
  • 可以提交到queue进行运行的command buffer
  • Secondary Command Buffer可以提交到Primary Command Buffer运行
  • Secondary Command Buffer
  • 不可以提交到queue运行,只能提交到Primary Command Buffer运行
  • 对应的handle:

    // Provided by VK_VERSION_1_0 VK_DEFINE_HANDLE ( VkCommandBuffer )

    Command Buffer中可以记录的Command类型包括:

  • 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
  • other commands.
  • 简单来说,我们必须把command先record到command buffer才能进行后续的执行。另外各个Command Buffer的状态都是自包的,互相不会影响,即使是提交到Primary的Secondary Command Buffer也不会受到目标Primary Command Buffer的影响。

    另外,一个Command Buffer在开始构建时候状态是undefined;一个primary command buffer运行完一个secondary以后,状态是undefined,除非是render/subpass相关的状态信息。

    任何和状态无关的command(draw或者dispatch)消耗的state都应该是undefined(确保和状态无关)。

    如果没有明确的指明,所有提交到queue的指令的执行顺序可能是任意的(除非他们之间有依赖关系),另外command的读写对于其他command可能不是可以直接visible的(同样除非他们之间有显式依赖关系)。这些设定对于即使在同一个command buffer中的指令也适用,更加别说多个command buffer之间。

    6.1. Command Buffer Lifecycle

    可能的状态包括:

    Initial :command buffer刚开始allocate或者reset之后都会进入Initial状态

    Recording :vkBeginCommandBuffer函数会使得command buffer从Initial状态到可以接受command的recording状态,可以使用vkCmd*各种函数来往一个command buffer进行塞command

    Executable :vkEndCommandBuffer函数可以是的Recording状态的command buffer进入可以提交到queue的状态,也就是Executable状态。然后可以通过submmit到queue中。

    Pending :Submit到queue的command buffer就处于Pending状态(或者说叫等待执行状态,注意没有executing状态)。进入Pending状态的command buffer必须不能进行修改。queue可能在随时某个点执行某个command buffer。执行完成后command buffer可能回到Executable状态,或者在设置一些flag后到Invalid状态。一个synchronization command应该被使用如果想要捕捉这个结束后的状态转换。最后Pending状态是唯一不用/不能用户进行操作的状态,全自动。

    Invalid :在某些用户的作死操作(比如删除运行中的command buffer的command或者resource)会使得Command Buffer进入state状态。其实可能是错误状态可能也有这个意思。处于这个状态的command buffer只能被reset或者free掉。

    具体转换图:

    转换成表格的话

    Initial Recording Executable Pending Invalid
    Initial Begin
    Recording Reset End Invalidate
    Executable Reset Submission Invalidate
    Pending Completion Completion
    Invalid Reset

    还是很稀疏的。

    6.1.1. Primary & Secondary Command Buffer

    Secondary通过vkCmdExecuteCommands提交到Primary,随后:

  • 当Primary执行时候也会同时执行Secondary
  • Primary结束时候Secondary也表明执行完成了
  • Primary和Secondary结束后会各自进入目标的最终状态(Executable or Invalid)
  • 如果Secondary最后是Invalid,那么Primary也会是Invalid
  • Reset或者Free一个Primary会删除相关Secondary的Link关系,但是不涉及清楚Secondary的内容
  • 6.2. Command Pools

    Commnand Pools是线程不安全的,对应的handle:

    // Provided by VK_VERSION_1_0 VK_DEFINE_NON_DISPATCHABLE_HANDLE ( VkCommandPool )

    和构建函数:

    // Provided by VK_VERSION_1_0 VkResult vkCreateCommandPool ( VkDevice device , const VkCommandPoolCreateInfo * pCreateInfo , const VkAllocationCallbacks * pAllocator , VkCommandPool * pCommandPool );

    熟悉的base + create-info + allocator + hold-handle的节奏。poo还有些其他操作:

  • 通过vkTrimCommandPool进行缩小
  • vkResetCommandPool
  • vkDestroyCommandPool
  • 6.3. Comamnd Buffer Allocation and Management

    对应的函数:

    // Provided by VK_VERSION_1_0 VkResult vkAllocateCommandBuffers ( VkDevice device , const VkCommandBufferAllocateInfo * pAllocateInfo , VkCommandBuffer * pCommandBuffers );

    这里的AllocationInfo中需要6.2中描述的pool:

    // Provided by VK_VERSION_1_0 typedef struct VkCommandBufferAllocateInfo { VkStructureType sType ; const void * pNext ; VkCommandPool commandPool ; VkCommandBufferLevel level ; uint32_t commandBufferCount ; } VkCommandBufferAllocateInfo ;

    这里的level就两个:primary或者secondary。对应的也有Command Buffer的一些操作:

  • vkResetCommandBuffer
  • vkFreeCommandBuffers
  • 6.4. Command Buffer Recording

    这里可以开始记录command了:

    // Provided by VK_VERSION_1_0 VkResult vkBeginCommandBuffer ( VkCommandBuffer commandBuffer , const VkCommandBufferBeginInfo * pBeginInfo );

    这里的info中包含了对于command buffer类型的定义:

    // Provided by VK_VERSION_1_0 typedef struct VkCommandBufferBeginInfo { VkStructureType sType ; const void * pNext ; VkCommandBufferUsageFlags flags ; const VkCommandBufferInheritanceInfo * pInheritanceInfo ; } VkCommandBufferBeginInfo ;

    flags可以用的值包括(注意是个bitmask ):

  • VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT : 提交一次之后buffer就被reset
  • VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT:secondary buffer在render pass
  • VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT:可以反复提交
  • VkCommandBufferInheritanceInfo用在secondary command buffer上面,设置secondary和primary之间的继承关系。

    Complete recording操作可以调用vkEndCommandBuffer:

    // Provided by VK_VERSION_1_0 VkResult vkEndCommandBuffer ( VkCommandBuffer commandBuffer );

    6.5 Command Buffer Submission

    可以通过vkQueueSubmit提交一个或者多个Command Buffer到一个queue:

    // Provided by VK_VERSION_1_0 VkResult vkQueueSubmit ( VkQueue queue , uint32_t submitCount , const VkSubmitInfo * pSubmits , VkFence fence );

    但注意,多个VkSubmitInfo之间的提交是不一定按照数组顺序的,可能是out-of-order的。提交完成后,所有在executable状态的command buffer会变成pending状态,等待执行。对应单个submit信息:

    // Provided by VK_VERSION_1_0 typedef struct VkSubmitInfo { VkStructureType sType ; const void * pNext ; uint32_t waitSemaphoreCount ; const VkSemaphore * pWaitSemaphores ; const VkPipelineStageFlags * pWaitDstStageMask ; uint32_t commandBufferCount ; const VkCommandBuffer * pCommandBuffers ; uint32_t signalSemaphoreCount ; const VkSemaphore * pSignalSemaphores ; } VkSubmitInfo ;

    配合不同的pNext,这里也可以进一步制定physcial device等信息。

    6.6. Queue Forward Progress

    command buffer运行的追踪?

    6.7. Secondary Command Buffer Execution

    因为secondary command buffer不能直接提交到queue运行,因此必须讲其提交到primary,通过primary的提交来进而运行secondary:

    // Provided by VK_VERSION_1_0 void vkCmdExecuteCommands ( VkCommandBuffer commandBuffer , uint32_t commandBufferCount , const VkCommandBuffer * pCommandBuffers );

    6.8. Command Buffer Device Mask

    device mask记录了某个command buffer中的command到底能在哪些physical device上运行的各种信息,可以设置的点包括:

  • 开始begin command buffer填充时候pNext可以设置VkDeviceGroupCommandBufferBeginInfo
  • 调用独立的vkCmdSetDeviceMask
  • 6.x Reference

  • 进击的 Vulkan 移动开发之 Command Buffer