6. Command Buffers
有两种level的command buffer:
对应的handle:
// Provided by VK_VERSION_1_0
VK_DEFINE_HANDLE
(
VkCommandBuffer
)
Command Buffer中可以记录的Command类型包括:
简单来说,我们必须把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,随后:
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还有些其他操作:
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的一些操作:
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 ):
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上运行的各种信息,可以设置的点包括:
6.x Reference