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