【问题标题】:Why do we need multiple render passes and subpasses?为什么我们需要多个渲染通道和子通道?
【发布时间】:2018-01-17 11:28:30
【问题描述】:

我过去有过使用 DirectX12 的经验,但我不记得在 Vulkan 中有类似渲染通道的东西,所以我无法进行类比。如果我正确理解同一子通道内的命令缓冲区,则不需要同步。那么为什么要复杂化并制作多个呢?为什么我不能只取一个命令缓冲区并将所有与帧相关的信息放在那里?

【问题讨论】:

  • 我的回答说明了它们是什么,但我没有解决您问题的同步部分。渲染通道不会取代或避免同步。是什么让您认为他们会这样做?
  • 我不确定,也许我解释错了,但是,例如,here Nicol 告诉你不需要任何同步如果命令缓冲区在同一个渲染通道实例中执行.
  • @nikitablack:您不需要同步来简单地让一个 CB 在另一个之后执行,并使之前的 CB 的渲染产品对后面的 CB 中的任何混合或类似覆盖操作可见。这就是OP所要问的,所以这就是我解释的。如果你在一个 CB 中做图像存储,并且想在后面的一个 CB 中读取它们,你仍然需要同步。

标签: vulkan


【解决方案1】:

想象一下,GPU 无法直接渲染到图像。想象一下,它只能渲染到与常规图像内存完全分开的特殊帧缓冲区内存存储中。您不能直接与此帧缓冲区内存通信,也不能从中进行分配。但是,在渲染操作期间,您可以将图像中的数据复制到其中,将其中的数据读取到图像中,当然也可以渲染到这个内部存储器。

现在假设您的特殊帧缓冲区内存的大小是固定的,该大小小于您要渲染到的整体帧缓冲区的大小(可能小得多)。为了能够渲染大于帧缓冲内存的图像,您基本上必须多次执行这些目标的所有渲染命令。为了避免多次运行顶点处理,您需要一种方法来存储顶点处理阶段的输出。

此外,在生成渲染命令时,您需要了解如何分配帧缓冲内存。如果您渲染到一个 32-bpp 图像而不是渲染到两个图像,您可能必须以不同的方式划分帧缓冲区内存。以及如何分配帧缓冲内存会影响片段着色器代码的工作方式。毕竟,在渲染操作期间,片段着色器可以直接访问此帧缓冲区渲染内存。

这是渲染通道模型的基本思想:您正在渲染到大小不确定的特殊帧缓冲区内存。渲染通道系统复杂性的各个方面都基于此概念模型。

子通道是您确定当前要渲染的对象的部分。因为这会影响帧缓冲内存的排列,所以图形管线总是通过引用渲染通道的子通道来构建。同样,要在子通道中执行的辅助命令缓冲区必须提供将在其中使用的子通道。

当渲染通道实例开始在队列上执行时,它(概念上)将我们打算渲染到的附件图像复制到帧缓冲区渲染内存中。在渲染过程结束时,我们渲染的数据被复制回附件图像。

在执行渲染过程实例期间,附件图像的数据被认为是“不确定的”。虽然模型说我们正在复制到帧缓冲区渲染内存中,但 Vulkan 不希望在直接渲染到图像时强制实现实际复制内容。

因此,Vulkan 仅声明没有操作可以访问用作附件的图像,除了那些访问图像作为附件的操作。例如,您不能将附件图像作为纹理读取。但您可以将其作为输入附件读取。

这是对基于图块的渲染器工作方式的概念性描述。这就是作为 Vulkan 渲染通道架构基础的概念模型。渲染目标是不可访问的内存;它们是特殊的东西,只能通过特殊的方式访问。

您不能“仅”从 G 缓冲区读取数据,因为当您渲染到该 G 缓冲区时,它存在于图像中的特殊帧缓冲区内存中.

【讨论】:

  • 谢谢。总而言之 - 如果我想从附件中随机读取,我无法在渲染到附件的同一个子通道中执行此操作。 IE。附件不允许任何图像布局转换。但我可以在另一个子通道中执行此操作,其中图像现在不用作附件,而是像普通图像/缓冲区一样。我没听错吗?
  • @nikitablack:不。图像附加到渲染通道,而不是子通道。附件被一些子通道使用,但它们附加到渲染通道本身。当图像数据被复制进来时,它是渲染过程的开始,而当数据被复制到附件图像时,它只是渲染过程的结束。因此,在渲染过程结束之前,您不能将图像用于正常的图像操作。因此,如果您想做 SSAO 之类的事情,则必须在 单独的 渲染通道实例中。
【解决方案2】:

这两个功能主要存在于tile-based GPUs,这在移动设备中很常见,但从历史上看,在台式电脑上并不常见。这就是为什么 DX12 没有等价物,而 Metal (iOS) 有。尽管Nvidia'sAMD's 最近的架构现在也都做了基于图块的渲染变体,而且最近的 Windows-on-ARM PC 使用高通芯片(基于图块的 GPU),但看看 DX12 如何进化。

渲染通道的好处是在像素着色期间,您可以将帧缓冲区数据保存在片上内存中,而不是不断地读写外部内存。缓存有一些帮助,但如果没有重新排序像素着色,缓存往往会颠簸很多,因为它不足以存储整个帧缓冲区。一个相关的好处是,如果您要完全覆盖之前的帧缓冲区内容,则可以避免读取它们,并且如果在渲染过程结束后不需要它们,则可以避免在渲染过程结束时写出帧缓冲区内容。在许多应用中,基于 tile 的 GPU 无需从外部存储器读取和写入深度缓冲区数据或多重采样数据,从而节省了大量带宽和功率。

子通道是一项高级功能,在某些情况下,它允许驱动程序有效地将多个渲染通道合并为一个。目标和底层机制类似于 OpenGL ES Pixel Local Storage extension,但 API 略有不同,以便让更多 GPU 架构支持它并使其更具可扩展性/面向未来。这有帮助的经典示例是基本的延迟着色:第一个子通道为每个像素写出 gbuffer 数据,随后的子通道使用它来对像素进行明暗处理。 Gbuffers 可能很大,因此将所有这些都保留在芯片上并且永远不必将其读取或写入主内存是一件大事,尤其是在带宽和功率受限的移动 GPU 上。

【讨论】:

  • 谢谢。但我仍然无法得到它 - 是什么阻止我写入 GBuffer 并在 one 子通道中读取它?
  • @nikitablack 有些事情你不能用子通道自依赖来做。值得注意的是,流水线级的使用受到限制。此外,您不得更改图像布局。
  • @nikitablack:“是什么阻止了我在一个子通道中写入 GBuffer 并从中读取?”它可以。附加图像既可以是颜色附件,也可以是输入附件。你不能做的是任意从输入附件中读取。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-12
  • 2021-04-28
  • 2016-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多