VK_DEPENDENCY_BY_REGION_BIT

问题描述

输入附件可以通过 subpassLoad GLSL 函数访问,该函数在当前片段位置对输入附件进行采样,即接口不提供随机访问。其结果是无法在任意片段位置访问输入附件。

这实际上意味着 [1]:

如果渲染技术需要读取当前片段区域之外的值(这在平铺上意味着访问当前渲染平铺之外的渲染数据),则必须使用单独的渲染通道。

然后,关于 VK_DEPENDENCY_BY_REGION_BIT 规范说 [2]:

如果同步命令包含一个 dependencyFlags 参数,并指定了 VK_DEPENDENCY_BY_REGION_BIT 标志,那么它为所有帧缓冲区区域定义了该同步命令中帧缓冲区空间流水线阶段的帧缓冲区本地依赖关系。如果未包含dependencyFlags 参数,或未指定VK_DEPENDENCY_BY_REGION_BIT 标志,则为这些阶段指定帧缓冲区全局依赖项。

来自 ARM [3] 的 Hans-Kristian Arntzen 建议在平铺架构上,多子通道渲染通道应仅与 VK_DEPENDENCY_BY_REGION_BIT 结合使用:

接下来,我们尝试将相邻的渲染通道合并在一起。这对于基于 tile 的渲染器尤其重要。如果出现以下情况,我们会尝试将通行证合并在一起:

  • 它们都是图形通道
  • 他们共享一些颜色/深度/输入附件
  • 不超过一个独特的深度/模板附件
  • 它们的依赖关系可以通过 BY_REGION_BIT 实现,即没有“纹理”依赖关系,允许对任意位置进行采样。

现在的问题是:

  1. 如果无论如何都无法访问当前片段位置之外的片段,那么 VK_DEPENDENCY_BY_REGION_BIT 有什么意义?

  2. 在平铺架构上,不能使用 VK_DEPENDENCY_BY_REGION_BIT 声明子通道依赖项的多子通道渲染通道是否比功能等效的正确同步的一系列单独的单子通道渲染通道提供任何性能优势?

解决方法

好吧,规范给出了一个例子。如果要访问片段未涵盖的输入附件示例,则必须使用帧缓冲区全局依赖项(即 dependencyFlags = 0,或供应商扩展修复之一)。

尽管最明显的例子是非附件资源,它们自然是随机访问的(您可以访问任何像素)。使用 VK_DEPENDENCY_BY_REGION_BIT,只有为同一片段编写的部分才能确定可见。使用帧缓冲区全局依赖项 (dependencyFlags=0) 时,您可以访问由前一个子通道的任何片段着色器调用写入的存储缓冲区中的位置。

dependencyFlags=0 有点像渲染通道的软重启。所以一切都一样,我会这样评价表现:
单个子通道 ≥ 多个子通道,VK_DEPENDENCY_BY_REGION_BIT ≥ 多个子通道,无 VK_DEPENDENCY_BY_REGION_BIT ≥ 多个渲染通道。

如果没有对特定实现的测量,我不能说帧缓冲区全局子通道是否真的提供了任何性能优势(这可能是一个易腐烂的信息,随着新 GPU 甚至驱动程序版本的变化而变化)。虽然这种情况应该不会比单独的渲染通道更糟糕,但如果驱动程序无法对这些特殊的子通道执行任何操作,这可能是驱动程序本身所做的最糟糕的降级。