Vulkan:Renderpass LoadOp 和 StoreOp 同步

Ala*_*mes 5 vulkan

语境

在规范中,它讨论了附件的 loadOp 和 storeOp 出现在哪个管道阶段(这里 - 项目符号后的第 2 和第 3 段),以及它们使用的访问类型(这里):

具有深度/模板格式的附件的加载操作在 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT 管道阶段执行。

带有颜色格式的附件的加载操作在 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT 管道阶段执行。

VK_ATTACHMENT_LOAD_OP_LOAD 指定将保留渲染区域内图像的先前内容。对于具有深度/模板格式的附件,这使用访问类型 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT。对于带有颜色格式的附件,这使用访问类型 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT。

其他 loadOps 和 storeOps 也是如此。

它还提到了 subpass 中发生的 loadOp、storeOp 和 resolve ops 如何包含在 subpass 依赖项的同步范围中(这里 - 项目符号后的第 2 段和第 3 段):

第一组命令包括作为 srcSubpass 标识的 subpass 实例的一部分提交的所有命令以及 srcSubpass 中使用的附件上的任何加载、存储或多样本解析操作

问题

规范的上述部分暗示在某些情况下需要此信息,以便您可以确保这些加载和存储操作与其他访问(在其他子通道中或在该渲染通道之外)正确同步,就像您需要确保解析操作与对同一附件的其他访问同步。

我的问题是在将子通道与其他子通道同步时是否需要考虑加载和存储操作,以及在渲染通道实例之外进行访问的子通道?在什么情况下需要同步?

我相信我一定是误解了某些东西,因为我在任何 vulkan 书籍或任何讨论它的人中都找不到对此的引用。

附加细节

我认识到,在大多数情况下,不需要考虑这一点,因为附件的 loadOp 或 storeOp 的管道阶段和访问类型与那些 loadOps 的 subpass 实例中记录的命令中使用的管道阶段和访问类型相同或 storeOps 会发生。但是,有些情况下它们是不一样的。

例如:

具有一个子通道 RP1 的渲染通道 RP。

该子通道使用图像视图 IV 作为输入附件,其中 loadOp = VK_ATTACHMENT_LOAD_OP_LOAD。

IV 具有颜色格式,并在 VK_IMAGE_LAYOUT_GENERAL 中。

在 RP1 开始时,loadOp 将在流水线阶段 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT 中运行,访问类型为 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT。(参见规范。参见上下文)。

但是当 IV 用作输入附件时,子通道将使用管道阶段 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT 和访问类型 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT 访问它。

假设一些写入是在 IV 上的 RP 之前执行的,具有像这样的外部子通道依赖性:

VkSubpassDependency subpassDependency;

subpassDependency.srcSubpass = VK_SUBPASS_EXTERNAL;
subpassDependency.dstSubpass = 0;

//source
subpassDependency.srcStageMask = /*Whatever the prior write was E.g. VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT*/;
subpassDependency.srcAccessMask = /*Whatever the prior write was E.g. VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT*/;

//destination
subpassDependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
subpassDependency.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
Run Code Online (Sandbox Code Playgroud)

即使看起来是正确的,这也可能允许 IV 的 loadOp 与先前对 IV 的写入同时运行,显然是无效的。

别名

最后,由于需要同步别名附件的 storeOps 和 loadOps,以及同步访问这些别名附件本身,这似乎也会导致复杂性。

先感谢您。

krO*_*oze 2

关于 Vulkan,我对“是否必须将 X 与 Y 同步”的回答是肯定的。大约有2-3个异常,并且过度同步不会立即造成损害。

您确实需要与渲染通道外部同步。如果您之前已经写入了资源,并且要加载它(读取,或者如果清除操作则写入),则必须存在障碍(通常是VK_SUBPASS_EXTERNAL依赖项)。同样,如果您存储了一个资源(写入)并且稍后会读取它。

规范说:

应用程序必须确保对给定渲染通道实例中用作附件的图像子资源的所有内存访问都发生在这些附件的加载操作之前,或者发生在这些附件的存储操作之后。

子通道可能会根据负载通过后续操作进行同步。例如,颜色附件也会被写入VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,您自然会为需要该输出的后续子通道提供依赖项。

至于您的示例中感知到的子通道自相关性,保证在第一次使用之前发生负载。类似地,存储会在上次使用后发生。规格报价:

附件中每个样本的加载操作发生在任何访问使用附件的第一个子通道中的样本的记录命令之前。

附件中每个样本的存储操作发生在任何访问使用附件的最后一个子通道中的样本的记录命令之后。

因此,在我的解释中,就好像您将一个虚构的vkCmdLoadResource命令添加到使用它的第一个子通道中,以及vkCmdPipelineBarrier该虚构的加载命令与该子通道中该资源的第一次使用之间的后续依赖关系。