可以在没有信号量或栅栏的情况下同步获取和写入交换链图像吗?

Can acquire and write to swap chain image be synchronized without a semaphore or fence?

通常,使用交换链映像的 VkRenderPass 在执行 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT 之前等待来自 vkAcquireNextImageKHR 的信号量。同样VkRenderPass还定义了一个subpass依赖,在同一个pipeline阶段的开始处transition图像:

    VkSubpassDependency dependency = {
    .srcSubpass = VK_SUBPASS_EXTERNAL,
    .dstSubpass = 0,
    // .srcStageMask needs to be a part of pWaitDstStageMask in the WSI semaphore.
    .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    .srcAccessMask = 0,
    .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    .dependencyFlags = 0};

//source: https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples#combined-graphicspresent-queue

根据 Vulkan 标准:

7: Subpass dependencies describe execution and memory dependencies between subpasses.

那么,这个子通道依赖性是否单独强制 VkRenderPass 颜色输出发生在表示引擎 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT 之后?来自 vkAcquireNextImageKHR 的信号量在等待什么,而依赖性却没有?

我无法有效地测试信号量的缺失。在我的 Mesa Linux 上,即使没有两种同步方法,渲染也会成功。

Vulkan 7.1.

If srcSubpass is equal to VK_SUBPASS_EXTERNAL, the first synchronization scope includes commands that occur earlier in submission order than the vkCmdBeginRenderPass used to begin the render pass instance.

vkAcquireNextImageKHR不在subpass依赖的第一个同步范围内,因为它不是提交到队列的命令。

信号量同步阶段。由于图像转换发生在颜色输出阶段的开始,因此它发生在信号量发出信号之后。由于两者都等待 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,信号量之前此阶段的操作被链接到转换依赖项。只有通过这条链,subpass 依赖关系才能知道何时获取图像以执行转换。 output阶段的写实际上是依赖transition then,而不是直接依赖semaphore

执行依赖关系建立两个范围之间的依赖关系:源范围和目标范围。源外部子通道依赖项定义如下:

If srcSubpass is equal to VK_SUBPASS_EXTERNAL, the first synchronization scope includes commands that occur earlier in submission order than the vkCmdBeginRenderPass used to begin the render pass instance.

注意关键词“较早提交顺序”。 Submission order 是根据提交到队列的命令定义的。

您可能已经注意到,vkAcquireNextImageKHR 不将队列作为参数。它的名字也不以“Cmd”开头。这些是操作未提交到任何队列的线索;这是 设备 级别的操作。

由于获取图像不是任何队列“提交顺序”的一部分,因此它不能(除非采用其他同步)成为外部子通道依赖项的“第一同步范围”的一部分。因此,这样的依赖对acquire操作没有影响。

因此,如果您需要对已获取图像的使用执行依赖,则必须通过信号量或栅栏。