Practical Rendering and Computation with Direct3D 11
+ -

1.2管道

2024-06-13 8 0

可以说,理解Direct3D11所需的最重要的概念是对其管道配置的清晰理解。Direct3D11规范定义了概念处理流水线以执行渲染计算,并最终产生渲染图像。之所以使用“管道”一词,是因为数据“流入”管道,在整个管道的每个阶段以某种方式进行处理,然后“流出”管道。在API的过去几次迭代中,对管道进行了几次更改,以简化管道并为其添加额外的功能。管道概念本身由多个阶段组成,每个阶段执行不同的操作。传递到每个阶段的数据在传递到下一阶段之前会以某种方式进行处理。每个单独的阶段都提供了一组独特的可配置参数,开发人员可以控制这些参数来自定义要执行的处理。

其中一些阶段被称为固定功能阶段,提供有限的定制能力。这些阶段通常暴露一个状态对象,该状态对象可以根据需要与所需的新配置绑定。
其它阶段被称为可编程阶段,通过允许在其中执行自定义程序,可提供更广泛的配置能力。这些程序通常被称为着色器程序,这个阶段被称为可编程着色器阶段。这些可编程着色器阶段可以实现各种不同的功能,而不是对传递到其中的数据执行一组固定的操作。

固定功能阶段:状态对象
可编程阶段:自定义程序-着色器程序

正是这些着色器程序为实现自定义渲染和计算算法提供了最大的灵活性。每个可编程着色器阶段都提供一个通用功能集,称为通用着色器核心,以提供其能力的某种程度的一致性。这些功能可以被视为一个工具箱,可用于所有可编程着色器阶段。纹理采样、算术指令集等操作在所有可编程阶段中都很常见。然而,每个阶段都提供了自己独特的功能,无论是在其指令集中还是在其输入/输出系统中,以允许执行不同类型的操作

从高层来看,目前有两种通用的管道范式——一种用于渲染,另一种用于计算。严格来说,这两种配置之间的区别有些松散,因为它们都可以用于其他目的。然而,这种区别是存在的,而且这两条管道的能力存在明显差异。我们将从渲染管道开始讨论这两个管道。

1.2.1渲染管道

渲染管道是现代GPU的起源。实始显卡加速器提供了硬件顶点转换,以加快3D应用程序的速度。从那时起,每一代新硬件都提供了额外的功能来执行越来越复杂的渲染。今天,我们有一个相当复杂的管道,可以在硬件中执行几乎任何算法。出版的书籍定期描述使用最新硬件的新技术,如(Engel,2009)和(Nguyen,2008)。在过去的5-10年里,实时渲染的进步水平确实在不断提高。

渲染管道旨在获取一组3D对象描述,并将其转换为适合在应用程序的输出窗口中显示的图像格式。在深入了解每个单独阶段的细节之前,让我们仔细看看完整的Direct3D11渲染管道。图1.2显示了流水线的框图,在本书的剩余部分中,我们将多次看到它,有几种不同的格式。

这里,固定功能和可编程两种不同类型的流水线级用不同的颜色描绘。固定功能级显示为绿色背景,可编程级显示为蓝色背景。每个阶段定义自己所需的输入数据格式,还定义执行时将生成的输出数据格式。我们将逐步了解管道,并简要讨论每个阶段及其预期目的。

160747379697

渲染管道的入口点是输入装配(assembler)程序阶段。此阶段负责从资源中读取输入数据,然后“组装”顶点以供稍后在管道中使用。这允许使用多个顶点缓冲区,还提供了使用实例化渲染的能力(在第3章中详细描述)。此外,还基于输入资源和所需的重新绘制配置来确定顶点的连接性。然后,组装的顶点和基元连接信息将沿管道传递。

顶点着色器阶段从输入装配阶段(assembly stage)读取组装的顶点数据,并一次处理一个顶点。这是流水线中的第一个可编程阶段,它将当前顶点着色器程序应用于每个输入顶点。它不能创建或破坏顶点;它只能处理提供给它的顶点。此外,每个顶点都是孤立处理的——来自一个顶点着色器调用的信息在另一个调用中永远无法访问。顶点阴影的主要职责是将顶点位置投影到片段空间中,但添加曲面(tessellation)阶段(下面讨论)在一定程度上改变了这一点。通常,必须对输入模型的每个顶点执行的任何操作都应在顶点着色器中执行。

接下来的三个阶段是管道中新添加的内容(D3D11中新添加的),以适应硬件安装,它们必须一起使用。外壳(hull)着色器阶段从顶点着色器接收原始着色器,并负责两个不同的操作。首先,外壳shader提供了一个函数,该函数每个基本体只运行一次,以确定一组曲面因子。曲面细分阶段使用这些因子来了解曲面或拆分当前基本体的精细程度。外壳着色器阶段必须执行的第二个操作对所需输出控制补丁配置中的每个控制点执行一次。当然,它必须创建控制点,这些控制点稍后将由域阴影层使用,以创建最终将在渲染中使用的实际曲面顶点。

当曲面细分(tessellation)阶段从外壳着色器接收到其数据时,它会使用几种算法中的一种来确定当前基本体类型的适当采样模式。根据曲面细分因子(来自外壳着色器)及其自身配置(实际上也在外壳着色器中指定),它将确定需要对当前基本体中的哪些点进行采样,以便将输入基本体镶嵌成更小的部分。曲面细分段的输出实际上是传递给域着色器的一组重心坐标。

域着色器除了使用外壳着色器生成的控制点外,还使用这些重心坐标来创建新的顶点。它可以使用为当前基本体、纹理、程序算法或任何其他生成的控制点的完整列表,将每个曲面细分点的重心“位置”转换为输出几何体,并将其传递到管道中的下一阶段。这种决定如何从曲面细分阶段的放大输出生成结果几何体的灵活性为实现许多不同类型的镶嵌细分算法提供了很大的自由度。

几何体着色器阶段位于下一个管道位置。顾名思义,几何体着色器在几何级别上操作。在实践中,这意味着它对完整的几何基元进行操作,也产生几何基元。这个阶段既可以添加数据元素,也可以从管道中删除数据元素,这允许一些有趣的非传统用途。此外,它可以将一种类型的几何图形作为输入,并生成不同类型的几何图元作为输出。这允许将单个顶点转换为完整三角形,甚至多个三角形。几何体着色器也是处理后的几何体可以从管道流式传输到缓冲区资源的管道。这是在流输出阶段完成的。

几何体从几何体着色器发出后,它已完成在几何体级别上操作的管道部分。从这一点开始,几何体被光栅化,并在片段级别进行处理。片段本质上是与渲染目标中的像素相对应的一组数据,如果该像素通过管道的其余部分,则可能用于更新该像素的当前值。片段级数据的生成从固定功能光栅化器阶段开始。光栅化器通过确定渲染目标的哪些像素被几何体覆盖,从传递给它的几何数据中生成片段。每个片段接收所有逐顶点属性的插值版本,以提供稍后在管道中进行进一步处理所需的信息。此外,光栅化器为每个片段生成一个深度值,该值稍后将用于输出合并阶段的可见性测试。

生成片段后,将调用像素着色器进行处理。像素着色器需要为绑定到管道的每个渲染目标输出生成颜色值输出。为了实现这一点,它可以对纹理进行采样或对传入的片段属性执行计算。此外,它还可以覆盖光栅化器阶段产生的深度值,以允许在像素着色器阶段实现专用算法。

像素着色器完成工作后,其输出将传递到输出合并阶段。它必须正确地将像素着色器输出与绑定的深度/模版和渲染目标资源“合并”。这包括执行深度和模板测试,执行混合功能,最后将输出实际写入适当的资源。

这是对每个管道阶段的简要高级概述,但在使用每个阶段时还需要考虑更多细节。在第3章“渲染管道”中,我们将更深入地了解每个阶段的所有可用配置和功能。在达到这一点之前,在继续我们对API的概述时,请记住管道的概述。

1.2.2计算管道

对于Direct3D11附带的所有其他新管道阶段,还有一个尚未讨论的附加阶段——计算着色器阶段。该阶段旨在执行传统渲染范式之外的计算,因此被认为与传统渲染管道分开执行。通过这种方式,它实现了一个专用于通用计算的单级管道。将GPU用于渲染以外的目的的总体趋势已直接纳入Direct3D 11 API,并在计算着色器中得到了体现。

已经向计算着色器提供了几个功能,这些功能有助于实现更通用的算法的灵活处理环境。第一个新功能是添加了一个结构化的线程模型,使开发人员在使用GPU的可用并行度来实现高度并行的算法方面有很大的自由度。以前,着色器程序的调用仅限于特定阶段如何处理输入(例如,为生成的每个片段调用一次像素着色器程序),开发人员无法直接控制线程的使用方式。计算着色器阶段不再是这种情况。

使计算机着色器阶段更加灵活的第二个新功能是声明和使用“组共享内存”块的能力。然后,线程组内的所有线程都可以访问该内存块。这允许在执行期间在线程之间进行通信,而这在渲染管道中通常是不可能的。有了通信的可能,通过共享加载的数据或中间计算,有可能显著提高效率

最后,介绍了对资源的随机读写访问的概念(我们将在本章的“资源”部分进一步讨论)。这代表了与我们已经讨论过的着色器阶段相比的一个重大变化,后者只允许将资源绑定为输入或输出。对完整资源的读写能力为线程之间的通信提供了另一种途径。

这三个新概念结合在一起,引入了一个非常灵活的通用处理阶段,既可用于渲染计算,也可用于通用计算。我们将在第5章“计算管道”中更深入地了解计算着色器,在本书的后半部分,有几个示例算法广泛使用了计算着色器。

0 篇笔记 写笔记

作者信息
站长漫谈
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!