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

时间:2016-05-27 11:41:19

标签: c++ synchronization gpu vulkan

有几种方法可以处理Vulkan中的同步。这就是我理解的方式:

  • Fences是GPU到CPU的同步。
  • 信号量是GPU到GPU的同步,它们用于同步队列 提交(在相同或不同的队列上)。
  • 事件更通用,重置并在CPU和GPU上进行检查。
  • 障碍用于在命令缓冲区内进行同步。

在我的情况下,我有两个命令缓冲区。我希望第二个命令缓冲区在第一个命令缓冲区之后执行。

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)),与使用栅栏相同或者我应该使用事件或信号量吗?

如果我同时向队列发送多个命令缓冲区:

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

还有办法在第一个和第二个之间同步吗?

2 个答案:

答案 0 :(得分:15)

  

第一个命令缓冲区是渲染深度测试的渲染对象。第二个命令缓冲区在关闭深度测试的情况下渲染网格轮廓。因为它必须位于其他对象之上。

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

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

因为第2.2.1节API Ordering可以保护您。渲染传递实例中的深度测试和深度编写始终按API顺序进行。因此,无论是在相同的CB还是不同的命令中,都将按照深度测试/写入命令。

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

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

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

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

实际上,所有这些复杂性都是为什么你应该尝试将这些命令缓冲区放在同一个渲染过程实例中,如果可能的话。您无法这样做的唯一原因是您需要从着色器中的深度缓冲区读取。

答案 1 :(得分:6)

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

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