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