Vulkan® Renderpasses

最初发布时间:
Graham Sellers

说明

Vulkan 中的 Renderpasses 已被更易于使用的动态渲染机制所取代。请阅读这篇 Khronos 博客 和官方 动态渲染扩展规范 中关于动态渲染的更多信息。

Vulkan™ 是一种高性能、低开销的图形 API,旨在让高级应用程序充分发挥现代 GPU 的能力。传统的 API 呈现的抽象行为就像命令立即执行一样,而 Vulkan 使用一种模型来暴露实际发生的情况;事实上,GPU 执行放置在内存中的命令,可能会乱序执行,并且这些命令缓冲区可以跨多个软件线程并行构建。此外,通过状态对象,大量相互关联的状态会同时呈现给图形驱动程序。这为驱动程序提供了在渲染时间之前充分优化 GPU 状态的机会,以最大化性能,而不会冒着与即时优化相关的卡顿和其他问题的风险。最终结果是更低、更一致的帧时间和更低的 CPU 开销,意味着为您的应用程序留出更多的 CPU 周期。

Vulkan 源自 AMD 的开创性 Mantle API。AMD 将 Mantle 规范、头文件和其他技术捐赠给了 Khronos Group,作为他们(当时尚未命名的)下一代 API 的基础。经过一年多的时间,在其他行业参与者的帮助下,Mantle 最终演变成了 Vulkan。这是一个漫长的过程,也许其中一些最显著的改变来自我们的移动领域成员,他们的 GPU 主要使用平铺架构,旨在最小化到内存的片外流量以节省功耗。我们移动成员提出的功能之一是 *renderpass* — 一个旨在让应用程序向驱动程序传达帧的高级结构的 object。平铺 GPU 驱动程序可以利用这些信息来确定何时将数据加载到芯片上和从芯片上卸载,是否将数据刷新到内存或丢弃平铺缓冲区的内容,甚至可以完成诸如调整用于分块和其他内部操作的内存分配大小等任务。这是 Mantle 没有的功能,也不是 Direct3D® 12 的一部分。

是否平铺

平铺 GPU 会将几何图形批量处理,确定几何图形落入帧缓冲区的哪些部分,然后对于帧缓冲区的每个区域,渲染击中该平铺的几何图形部分。这使得帧缓冲区访问非常一致,在许多情况下,可以在将数据写入内存之前,将一个帧缓冲区平铺的渲染完全在芯片上完成。AMD 不制造平铺 GPU。我们的 GPU 被称为 *前向* 或 *即时渲染器*。这意味着,当收到一个绘制某些几何图形的命令时,GPU 会将其绘制到它落入的任何位置,并在继续处理下一个命令之前完成处理。事物是流水线化的,命令可以重叠甚至乱序完成,但 GPU 中内置了特殊的硬件,可以在任何数据写入内存之前将其恢复到正确的顺序。我们的驱动程序通常不需要担心这个问题。那么,这些 renderpass object 与我们有什么关系?我们为什么关心?

在 Vulkan 中,renderpass object 包含帧的结构。最简单的形式是,renderpass 封装了帧缓冲区附件集、有关管道状态的基本信息,仅此而已。然而,renderpass 可以包含一个或多个 subpass 以及这些 subpass 之间关系的说明。事情在这里变得有趣起来。

每个 subpass 可以引用帧缓冲区附件的子集进行写入,也可以引用帧缓冲区附件的子集进行读取。这些可读的帧缓冲区附件被称为 *输入附件*,它们有效地包含同一像素上早期 subpass 的结果。与传统的渲染到纹理技术不同,后者允许每个传递读取前一个传递产生的任何像素,输入附件保证每个片段着色器只访问同一像素上由着色器调用生成的数据。此外,每个 subpass 包含有关在开始时(清除它、从内存恢复它,或不初始化它)和结束时(将其存回内存或丢弃它)如何处理每个附件的信息。subpass 之间的依赖关系由应用程序明确定义。这使得平铺渲染器能够确切知道何时需要刷新其平铺缓冲区、清除它、从内存恢复它,依此类推。

加速前向渲染

事实证明,像我们这样的前向渲染器也可以利用这类信息。以下是我们可能进行的优化的一些示例。

就像我们可以知道一个 subpass 依赖于早期 subpass 的结果一样,我们也可以知道一个 subpass *不* 依赖于早期 subpass。因此,我们有时可以并行或乱序渲染这些 subpass,而无需同步。如果一个 subpass 依赖于前一个 subpass 的结果,那么在传统的图形 API 中,驱动程序需要注入一个气泡到 GPU 流水线中,以便将渲染后端输出缓存与纹理单元输入缓存同步。然而,通过重新安排工作,我们可以指示渲染后端刷新其缓存,处理不相关的工作,然后在启动消耗 subpass 之前使纹理缓存失效。这消除了气泡并节省了 GPU 时间。

由于每个 subpass 都包含有关如何处理其附件的信息,因此我们可以知道应用程序将要清除一个附件,或者它不关心该附件的内容。这允许驱动程序将清除调度到实际渲染工作的前面,或者智能地决定使用哪种方法来清除附件(例如,使用计算着色器、固定功能硬件或 DMA 引擎)。如果应用程序说它不需要附件具有定义的数据,我们可以将附件带入部分压缩状态。这是指其中包含的数据是未定义的,但就硬件而言,其状态对于渲染来说是最优的。

在某些情况下,数据的内存布局对于最佳渲染和通过纹理单元读取是不同的。通过分析应用程序提供的数据依赖关系,我们的驱动程序可以决定何时执行布局更改、解压缩、格式转换等操作是最佳的。它还可以将其中一些操作分成几个阶段,并将它们与应用程序提供的渲染工作交错,这同样消除了流水线气泡并提高了效率。

最后,Vulkan 包含瞬时附件的概念。这些是在 renderpass 开始时处于未初始化或已清除状态的帧缓冲区附件,由一个或多个 subpass 写入,由一个或多个 subpass 消耗,并在 renderpass 结束时最终被丢弃。在这种情况下,附件中的数据仅存在于 renderpass 内,永远不需要写入主内存。虽然我们仍然会为这样的附件分配内存,但数据可能永远不会离开 GPU,而只存在于缓存中。这节省了带宽,降低了延迟,并提高了电源效率。

一等公民特性

Renderpasses 不应被视为“仅限移动设备”的功能。它是 Vulkan API 的一等公民特性,即使对于 GCN 架构等前向、即时渲染器,它也提供了大量优化和效率机会。我们初步的早期预览驱动程序包含一个 renderpass 编译器,该编译器已经执行了一些上述优化。我们有一长串的实验要做,并在接下来的几个月里上线越来越多的功能。简单地将几个传递合并到一个 subpass 中可能不会带来多大改进。然而,将尽可能多的帧放入尽可能少的 renderpass object 中,在软件和硬件性能方面都可能带来巨大的提升。

Graham Sellers

Graham Sellers 是 AMD 的一名首席软件架构师,从事图形驱动程序工作。提供第三方网站链接是为了方便起见,除非明确说明,AMD 对此类链接网站的内容不承担任何责任,也不表示任何认可。
© . This site is unofficial and not affiliated with AMD.