出于障碍的目的,在单个 vkQueueSubmit 调用中,命令缓冲区是如何排序的?

How are command buffers ordered, for barriers' purposes, within a single vkQueueSubmit call?

Vulkan 规范 (1.0.27) 说(在 6.5. 管道障碍 部分):

Each element of the pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers arrays specifies two halves of a memory dependency, as defined above. [...]

If vkCmdPipelineBarrier is called outside a render pass instance, then the first set of commands is all prior commands submitted to the queue and recorded in the command buffer and the second set of commands is all subsequent commands recorded in the command buffer and submitted to the queue.

(措辞很有趣;如果按字面解释,它似乎是说屏障只在一个命令缓冲区内命令命令,而“提交到队列”部分可能是多余的;但如果解释得更模糊一点,它似乎目的是说屏障在其命令缓冲区和队列中命令命令。其他 Stack Overflow 页面将我指向以下内容,这似乎证实了后一种解释:https://github.com/KhronosGroup/Vulkan-Docs/issues/300 )

那么我的问题。假设您有四个命令缓冲区,分两批提交,全部在一个 vkQueueSubmit 命令中:

VkSubmitInfo nextSubmitInfo;
nextSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
nextSubmitInfo.pNext = nullptr;
nextSubmitInfo.waitSemaphoreCount = 0;
nextSubmitInfo.pWaitDstStageMask = nullptr;
nextSubmitInfo.pWaitSemaphores = nullptr;
nextSubmitInfo.signalSemaphoreCount = 0;
nextSubmitInfo.pSignalSemaphores = nullptr;

std::vector<VkCommandBuffer> commandBuffersAB{commandBufferA, commandBufferB};
std::vector<VkCommandBuffer> commandBuffersCD{commandBufferC, commandBufferD};

std::vector<VkSubmitInfo> submitInfo;

nextSubmitInfo.commandBufferCount = commandBuffersAB.size();
nextSubmitInfo.pCommandBuffers = commandBuffersAB.data();
submitInfo.emplace_back(nextSubmitInfo);

nextSubmitInfo.commandBufferCount = commandBuffersCD.size();
nextSubmitInfo.pCommandBuffers = commandBuffersCD.data();
submitInfo.emplace_back(nextSubmitInfo);

df.vkQueueSubmit(queue, submitInfo.size(), submitInfo.data(), VK_NULL_HANDLE);

假设四个命令缓冲区中的每一个都包含一个屏障和一些动作命令(根据规范,这些命令是“执行动作的命令(例如draw/dispatch)”)。那么,我倾向于天真地期望障碍会认为命令缓冲区是按字母顺序提交的,因此它们的第一和第二“一半”将包括(可能除其他外)以下内容:

| barrier             | first half                 | second half                |
|---------------------|----------------------------|----------------------------|
| barrier in buffer A | A0                         | A1, B0, B1, C0, C1, D0, D1 |
| barrier in buffer B | A0, A1, B0                 | B1, C0, C1, D0, D1         |
| barrier in buffer C | A0, A1, B0, B1, C0         | C1, D0, D1                 |
| barrier in buffer D | A0, A1, B0, B1, C0, C1, D0 | D1                         |

其中对于缓冲区X,X0是屏障之前X中记录的动作命令集合,X1是屏障之后记录的集合;结果,命令集将 运行 显示如下:

A0; then
A1 and B0; then
B1 and C0; then
C1 and D0; then
D1

--table 的每一行中的所有命令都没有按特定顺序执行,除非它们自己的特殊功能可能需要它。

是这样吗?或者这是否仅适用于在四个不同的 vkQueueSubmit 命令中提交命令缓冲区 A-D 的情况? (或者它甚至不适用?)

根据 Vulkan 规范 1.0.35 版,命令缓冲区边界对操作之间的顺序没有任何影响:

Command buffer boundaries, both between primary command buffers of the same or different batches or submissions as well as between primary and secondary command buffers, do not introduce any implicit ordering constraints. In other words, submitting the set of command buffers (which can include executing secondary command buffers) between any semaphore or fence operations execute the recorded commands as if they had all been recorded into a single primary command buffer, except that the current state is reset on each boundary. Explicit ordering constraints can be expressed with events and pipeline barriers.

因此,CB 是 primary/secondary、same/different 批次还是 same/different 次提交命令都没有关系。它们都表现得好像是一个非常大的主命令缓冲区。

因此,同步在所有这些边界之间起作用。

vkQueueSubmit 告诉我们:

Batches begin execution in the order they appear in pSubmits, but may complete out of order.

并且 VkSubmitInfo 表示,在一个批次中:

The command buffers submitted in a batch begin execution in the order they appear in pCommandBuffers, but may complete out of order.

添加了重点。

鉴于所有这些,我们知道您如何提交这些批次并不重要。无论您是在 1 vkQueueSubmit 还是 4 中进行。无论您是在 1 批 4 个 CB 还是 4 批,每批 1 个 CB 中进行。唯一重要的是这些 CB 的显示顺序。

这就是为什么您应该使用尽可能少的 vkQueueSubmit 调用。因为它不会对您的程序的执行产生任何影响,但它可能会对 性能.

产生重大影响