为什么 `VkPipelineStageFlagBits` 不仅仅定义流水线阶段?

Why `VkPipelineStageFlagBits` does not only define pipeline stages?

VkPipelineStageFlagBits 定义了与我们在图形管道中期望的阶段相对应的标志,例如 VK_PIPELINE_STAGE_VERTEX_SHADER_BITVK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT 等。我们还有计算管道阶段,例如 VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT.

但也有一些这里定义的标志似乎根本不对应任何图形或计算管道阶段,例如VK_PIPELINE_STAGE_TRANSFER_BITVK_PIPELINE_STAGE_HOST_BITVK_PIPELINE_STAGE_ALL_COMMANDS_BIT(来自VK_PIPELINE_STAGE_TOP_OF_PIPE_BITVK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT 已定义)。相反,这些是通过引用命令在规范中定义的。例如:

VK_PIPELINE_STAGE_TRANSFER_BIT specifies the following commands:

  • All copy commands, including vkCmdCopyQueryPoolResults
  • vkCmdBlitImage2 and vkCmdBlitImage
  • vkCmdResolveImage2 and vkCmdResolveImage
  • All clear commands, with the exception of vkCmdClearAttachments

那么,如果它不是流水线阶段,为什么它会列在 Vk**PipelineStage**FlagBits 中?为什么要这样命名呢?例如,如果我在 VkSubpassDependency 中将 VK_PIPELINE_STAGE_TRANSFER_BIT 用作 srcStageMaskdstStageMask 是什么意思?

传输几乎可以插入到管道的任何位置,以在缓冲区之间移动数据。这些是具有可以排队的依赖关系的普通命令,并且通常具有专用硬件,因此其他着色器可以 运行 并行。 “清除”命令使用一个常量值作为复制操作的源,但仍然使用DMA引擎,所以它们在同一组。

这些位在很大程度上对应于将要使用的资源。在 VkSubpassDependency 的情况下,它们定义了哪些资源需要同步以便管道传递正确的结果,因此如果您在第一个子通道中使用 Copy 或 Clear 操作,则需要在 [=11] 中指定 VK_PIPELINE_STAGE_TRANSFER_BIT =]表示第一个子通道将使用DMA引擎,因此切换到第二个子通道需要刷新DMA引擎的写缓存。省略该位将允许无效优化,因此允许使用复制或清除命令。

“所有命令”、“管道顶部”和“管道底部”只是在管道设置期间节省协商的简写。

VK_PIPELINE_STAGE_TRANSFER_BIT来自传输管道,它有一个阶段。

VK_PIPELINE_STAGE_HOST_BIT 伪阶段通信 主机和设备之间将有 内存域 传输。

VK_PIPELINE_STAGE_ALL_COMMANDS_BIT| 将所有适用于给定上下文的位组合在一起的快捷方式。

VK_PIPELINE_STAGE_TOP_OF_PIPE_BITVK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT 是管道终止符。它们不代表任何阶段,但它们在 API 级别上是必需的,以表示“第一阶段之前”和“最后阶段之后”。

What does it mean if I use VK_PIPELINE_STAGE_TRANSFER_BIT as srcStageMask or dstStageMask in VkSubpassDependency for instance?

are not allowed to,除非那个依赖是 VK_SUBPASS_EXTERNAL

在普通管道屏障或 VK_SUBPASS_EXTERNAL 依赖中,这意味着某些工作依赖于完成的副本,或者某些副本取决于首先进行的某些写入。


主机内存同步的工作原理是 Vulkan 将其分为 domains。有主机内存域,还有设备内存域。如果对内存的更改在读取之前没有从一个域转移到另一个域,则可能是写入在另一个域上不可见。

这就是 VK_PIPELINE_STAGE_HOST_BIT(加上相关的访问掩码)的用武之地。它指示驱动程序执行此潜在的昂贵且具有破坏性的域传输。

现在有一个罕见的隐式 Vulkan 行为。 host write ordering guarantee。如果你从主机写到内存,然后然后vkQueueSubmit一些东西,你不需要做任何事情。该提交中的操作自动看到主机写入,并且您不会使用 VK_PIPELINE_STAGE_HOST_BIT.

但是这并不适用于其他方式。如果你想在主机上读取写在设备上的东西,你总是需要使用 dstStage = VK_PIPELINE_STAGE_HOST_BIT (后跟一个栅栏或类似的东西),否则当你尝试读取它们时,写入可能在主机域上不可见.

第三种选择是先提交,然后然后在主机上写一些东西。以前这可能发生在事件中(但随后被禁止),现在它可能在使用扩展信号量时发生。在这种情况下,除了 host-device 信号量之外,您还需要使用 srcStage = VK_PIPELINE_STAGE_HOST_BIT,否则您的主机写入可能对该设备上的读取不可见。