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

mjw*_*ach 3 synchronization memory-barriers vulkan

Vulkan 规范 (1.0.27) 表示(在第6.5 节“管道障碍”中):

pMemoryBarriers、pBufferMemoryBarriers 和 pImageMemoryBarriers 数组的每个元素指定内存依赖性的两半,如上面所定义。[...]

如果在渲染通道实例之外调用 vkCmdPipelineBarrier,则第一组命令是提交到队列并记录在命令缓冲区中的所有先前命令,第二组命令是记录在命令缓冲区中并提交到队列的所有后续命令。

(这个措辞很有趣;如果从字面上解释,它似乎是说屏障只在一个命令缓冲区内对命令进行排序,而“提交到队列”部分可能是多余的;但如果解释得更模糊一点,它似乎旨在说屏障在其命令缓冲区和队列中对命令进行排序。其他 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);
Run Code Online (Sandbox Code Playgroud)

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

| 屏障| 上半场| 下半场|
|--------------------------------|---------------------------------------- -|----------------------------|
| 缓冲区 A 中的屏障 | A0 | A1、B0、B1、C0、C1、D0、D1 |
| 缓冲区 B 中的屏障 | A0、A1、B0 | B1、C0、C1、D0、D1 |
| 缓冲区 C 中的屏障 | A0、A1、B0、B1、C0 | C1、D0、D1 |
| 缓冲区 D 中的屏障 | A0、A1、B0、B1、C0、C1、D0 | D1 |

其中,对于缓冲区X,X0是屏障之前X中记录的动作命令集合,X1是屏障之后记录的集合;因此,命令集的运行方式如下:

A0; 然后
A1和B0;然后
B1和C0;然后
C1和D0;然后
D1

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

是这样吗?或者这仅适用于在四个不同命令中提交命令缓冲区 AD 的情况vkQueueSubmit?(或者它根本不适用?)

Nic*_*las 5

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

命令缓冲区边界,无论是在相同或不同批次或提交的主命令缓冲区之间,还是在主命令缓冲区和辅助命令缓冲区之间,都不会引入任何隐式排序约束。换句话说,在任何信号量或栅栏操作之间提交命令缓冲区集(可以包括执行辅助命令缓冲区)会执行记录的命令,就像它们已全部记录到单个主命令缓冲区中一样,除了当前状态被重置之外在每个边界上。显式排序约束可以用事件和管道障碍来表达。

因此,CB 是主要/次要、相同/不同批次、相同/不同提交命令并不重要。它们都表现得好像它们是一个非常大的主命令缓冲区。

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

vkQueueSubmit告诉我们:

批次按照它们在 pSubmits 中出现的顺序开始执行,但可能会乱序完成。

VkSubmitInfo在一批中说:

批量提交的命令缓冲区按照它们出现的顺序开始执行,pCommandBuffers可能会乱序完成。

添加了强调。

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

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