繁体   English   中英

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

[英]Synchronization between command buffers in Vulkan

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

  • 栅栏是 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.2.1 节的API 订购会保护您。 渲染过程实例中的深度测试和深度写入将始终按 API 顺序进行。 因此,以后的命令,无论是在同一个 CB 中还是在不同的 CB 中,都将根据深度测试/写入进行排序。

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM