我过去曾经有过使用DirectX12的经验,我不记得类似于Vulkan渲染过程的东西,所以我无法进行类比.如果我正确理解同一个子通道内的命令缓冲区不需要同步.那么为什么要复杂化并使它们成倍增加呢?为什么我不能只使用一个命令缓冲区并将所有与帧相关的信息放在那里?
想象一下,GPU无法直接渲染图像.想象一下,它只能渲染到特殊的帧缓冲存储器,它与常规图像存储器完全分开.你无法直接与这个帧缓冲存储器通信,也无法从中分配.但是,在渲染操作期间,您可以将图像中的数据复制到其中,将数据从中读取到图像中,当然也可以渲染到此内部存储器中.
现在想象一下,您的特殊帧缓冲内存的大小是固定的,粒度比要呈现给(也许是整个帧缓冲区的大小小多小).为了能够渲染到比帧缓冲区内存更大的图像,您基本上必须多次执行这些目标的所有渲染命令.为避免多次运行顶点处理,您需要一种方法来存储顶点处理阶段的输出.
此外,在生成渲染命令时,您需要了解如何分配帧缓冲内存.如果渲染到一个32-bpp图像,则可能必须以不同方式划分帧缓冲区内存,而不是渲染为两个.如何分配帧缓冲区内存可能会影响片段着色器代码的工作方式.毕竟,在渲染操作期间,片段着色器可以直接访问该帧缓冲渲染存储器.
这是渲染过程模型的基本思想:您正在渲染到具有不确定大小的特殊帧缓冲内存.渲染过程系统的复杂性的每个方面都基于这个概念模型.
子通道是您确定目前正在渲染的内容的部分.因为这会影响帧缓冲存储器排列,所以总是通过引用渲染通道的子通道来构建图形管线.类似地,要在子通道中执行的辅助命令缓冲区必须提供将在其中使用的子通道.
当渲染过程实例开始在队列上执行时,它(概念上)将我们打算渲染的附件图像复制到帧缓冲渲染内存中.在渲染过程结束时,我们渲染的数据将被复制回附件图像.
在执行渲染过程实例期间,附件图像的数据被视为"不确定".虽然模型说我们正在复制到帧缓冲渲染内存,但Vulkan不想强制实现实际复制东西,如果它们直接渲染到图像.
因此,Vulkan仅表示没有操作可以访问用作附件的图像,除了那些以图像形式作为附件访问的图像.例如,您无法将附件图像作为纹理读取.但您可以将其作为输入附件阅读.
这是基于图块的渲染器工作方式的概念性描述.这是概念模型,是Vulkan渲染传递体系结构的基础.渲染目标不是可访问的内存; 它们是特殊的东西,只能通过特殊方式获取.
你不能"只是"从G-缓冲区,因为,当你渲染到G缓冲区,它在特殊的帧缓冲存储器中存在读取不是形象呢.
这两个功能主要存在于基于图块的GPU中,这在移动设备中很常见,但从历史上看在台式计算机上并不常见。这就是DX12没有等效项而Metal(iOS)具有等效项的原因。尽管Nvidia和AMD的最新体系结构现在也都进行了基于图块的渲染,并且随着最近使用Qualcomm芯片(基于图块的GPU)的ARM上Windows PC,看到DX12的发展将很有趣。
渲染过程的好处是,在像素着色期间,您可以将帧缓冲数据保留在片内存储器中,而不必不断地读写外部存储器。缓存可以帮助一些人,但是如果不对像素阴影重新排序,则缓存往往会发生很大变化,因为缓存不足以存储整个帧缓冲区。一个相关的好处是,如果您将要完全覆盖以前的帧缓冲区内容,则可以避免读取它们;如果在渲染通道结束后不需要它们,则可以避免在渲染过程的末尾写出帧缓冲区内容。在许多应用中,基于图块的GPU无需在外部存储器中读取或写入深度缓冲数据或多样本数据,从而节省了大量带宽和功耗。
子通道是一项高级功能,在某些情况下,允许驱动程序将多个渲染通道有效地合并为一个。目标和基本机制与OpenGL ES Pixel Local Storage扩展类似,但API有所不同,以便允许更多GPU架构来支持它并使其更具可扩展性/面向未来。可以帮助解决问题的经典示例是基本的延迟着色:第一个子通道为每个像素写出gbuffer数据,随后的子通道使用该数据来对像素进行光照和着色。Gbuffer可能非常庞大,因此将所有内容保留在芯片上,而不必将其读取或写入主内存是一件大事,尤其是在带宽和功耗受到更多限制的移动GPU上。