【问题标题】:Synchronization between command buffers in VulkanVulkan 中命令缓冲区之间的同步
【发布时间】:2016-09-25 17:49:20
【问题描述】:

在 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();

还有没有办法在第一个和第二个之间进行同步?

【问题讨论】:

  • "我希望第二个命令缓冲区在第一个命令缓冲区之后执行。" 您“希望”发生多少?也就是说,第二个命令缓冲区在做什么,以至于第一个命令缓冲区必须在第二个命令缓冲区开始之前完成执行?
  • 第一个命令缓冲区是打开深度测试的渲染对象。第二个命令缓冲区是在深度测试关闭的情况下渲染网格的轮廓。因为它必须在其他对象之上。
  • 如果您提交一份。然后在你的第一个命令缓冲区中使用 vkCmdSetEvent 并在你的第二个命令缓冲区中使用 vkCmdWaitEvents 并保持 src 和 dst 阶段掩码尽可能窄。

标签: c++ synchronization gpu vulkan


【解决方案1】:

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

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

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

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

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

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

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

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

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

【讨论】:

  • 您的知识令人印象深刻:),“如果它们是辅助命令缓冲区”,如果它们在同一个渲染通道中,它们是主命令缓冲区还是辅助命令缓冲区为什么重要?
  • @hidayat:因为在同一个渲染通道实例中不能有两个主命令缓冲区。 vkCmdEndCommandBuffer 不能在渲染通道实例处于活动状态时被调用。只有使用辅助命令缓冲区,它们才有可能在同一个渲染通道实例中发出命令。他们通过继承他们在其中执行的主命令缓冲区的 renderpass 实例来做到这一点。
【解决方案2】:

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

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

【讨论】:

  • 屏障不能工作吗?我一直在这里读到,障碍确实跨越命令缓冲区边界:stackoverflow.com/a/36602598/1364776 这难道不适用吗?还是仅仅是事件比障碍更轻量级?
  • @mjwach 我想知道同样的事情。据我了解是的,但如果有经验的人能提供答案,那就太好了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多