Vulkan 中命令缓冲区之间的同步

Synchronization between command buffers in Vulkan

在 Vulkan 中有多种处理同步的方法。我是这样理解的:

在我的例子中,我有两个命令缓冲区。我希望第二个命令缓冲区在第一个命令缓冲区之后执行。

submitInfo.pCommandBuffers = &firstCommandBuffer;
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);

// wait for first command buffer to finish
submitInfo.pCommandBuffers = &secondCommandBuffer;
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);

哪种同步最适合这种情况? 如果我使用 vkQueueWaitIdle(queue)), 是否与使用栅栏一样,还是我应该为此使用事件或信号量?

如果我同时发送多个commandbuffer到队列:

std::vector<VkCommandBuffer> submitCmdBuffers = {
        firstCommandBuffer,
        secondCommandBuffer
    };
    submitInfo.commandBufferCount = submitCmdBuffers.size();
    submitInfo.pCommandBuffers = submitCmdBuffers.data();

还有办法让第一个和第二个同步吗?

对于您的场景,您应该使用事件。这些应该是按给定顺序同步执行两个命令缓冲区的最轻量级同步对象,即使您一次提交它们也是如此。但请注意,事件不能跨不同的队列工作。如果您只使用一个,请使用事件并尽量使 src 和 dst 管道阶段掩码尽可能窄。

信号量是同步命令缓冲区执行的另一种方式,但它们仅适用于队列提交,因此它们比事件更重量级。

The first command buffer is rendering object with the depth test turned on. The second command buffer is rendering outlines of meshes with the depth test turned off. Because it has to be on top of the other objects.

对于这种情况,您需要的取决于那些命令缓冲区。

如果这些是在同一个渲染通道实例中执行的辅助命令缓冲区,那么您不需要任何同步。除非您手动读取辅助命令缓冲区中的深度纹理,否则不会。为什么?

因为第 2.2.1 节的 API Ordering 保护您。渲染过程实例中的深度测试和深度写入将始终按API顺序进行。因此,以后的命令,无论是在同一个 CB 中还是在不同的 CB 中,都将根据深度 testing/writing.

进行排序

但是,如果您需要从着色器读取深度缓冲区,或者您的命令缓冲区位于不同的渲染过程实例中,那么您需要通过事件进行显式同步。

在这种情况下,vkCmdSetEvent命令的阶段掩码应该是写入深度值的阶段。这可能是 EARLY_FRAGMENT_TESTS_BITLATE_FRAGMENT_TESTS_BIT。为了安全起见,请同时使用两者。但是,由于您可能正在更新相同的颜色缓冲区,因此您还需要 COLOR_ATTACHMENT_OUTPUT_BIT 阶段。在第一个命令缓冲区的末尾插入此命令(或在所有深度写入完成后)。

对于 vkCmdWaitEvent,您想在需要它的管道阶段等待。在您的情况下,这又是片段测试和颜色附件。但是如果一个着色器阶段要读取深度,你也需要在等待命令中的那个阶段。

由于涉及内存,您的 vkCmdWaitEvent 还需要使用对深度和颜色缓冲区的内存依赖性。

尽管如此,所有这些复杂性都是您应该尽可能将这些命令缓冲区放在同一个渲染通道实例中的原因。您无法这样做的唯一原因是如果您需要从着色器中的深度缓冲区读取数据。