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

hid*_*yat 23 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);
Run Code Online (Sandbox Code Playgroud)

什么样的同步最适合这个?如果我使用的vkQueueWaitIdle(queue)),是与使用栅栏相同的东西,或者我应该使用事件或信号量?

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

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

还有一种方法可以在第一个和第二个之间同步吗?

Nic*_*las 17

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

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

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

因为第2.2.1节的API订购可以保护您.渲染传递实例中的深度测试和深度写入将始终按API顺序进行.因此,在深度测试/写入方面,将对后来的命令进行排序,无论是在相同的CB中还是在不同的CB中.

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

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

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

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

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


Sas*_*ems 6

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

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

  • 屏障不能工作吗?我一直在这里阅读障碍确实可以跨命令缓冲区边界工作:http://stackoverflow.com/a/36602598/1364776 这不能在这里适用吗?或者仅仅是事件比障碍更轻量级? (2认同)