Cg 编程/可编程图形管道
这里介绍的可编程图形管道与 OpenGL (ES) 2.0 管道、WebGL 管道和 Direct3D 8.0 管道非常相似。因此,它是当今大多数台式电脑和移动设备的可编程图形管道的最低公分母。
GPU 是高度并行的处理器。这是它们性能的主要原因。事实上,它们实现了两种并行性:垂直并行和水平并行。
- 垂直并行描述了在管道不同阶段进行并行处理。这个概念在福特汽车公司的装配线发展中也至关重要:许多工人可以在相对简单的任务上并行工作。这使得大规模生产(因此也使得大规模消费)成为可能。在 GPU 处理单元的上下文中,简单任务对应于不太复杂的处理单元,这可以节省成本和功耗。
- 水平并行描述了在多个管道中处理工作的可能性。这允许比单个管道中的垂直并行实现更多的并行。同样,这个概念也应用于福特汽车公司和其他许多行业。在 GPU 的上下文中,图形管道的水平并行是实现现代 GPU 性能的重要特征。
下图展示了垂直并行(以方框表示的阶段处理)和水平并行(以方框之间的多个箭头表示的每个阶段的多个处理单元)的说明。
顶点数据 | 例如,由 3D 建模工具提供的三角形网格 | |||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ | 许多顶点并行处理 | |||
顶点着色器 | 一个小的 Cg 程序(或其他着色语言)应用于每个顶点 | |||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ | ||||
图元装配 | 设置图元,例如三角形、线条和点 | |||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ | 许多图元并行处理 | |||
光栅化 | 对图元(例如三角形)覆盖的所有像素进行数据的插值 | |||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ | 许多片段(对应于像素)并行处理 | |||
片段着色器 | 一个小的 Cg 程序(或其他着色语言)应用于每个片段(即覆盖的像素) | |||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ | ||||
每片段操作 | 对每个片段(即覆盖的像素)进行可配置操作 | |||
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ | 许多片段的结果并行写入帧缓冲区 | |||
帧缓冲区 | 存储计算出的片段颜色的像素数组 |
在下图中,任何两个阶段之间只有一个箭头。但是,应该理解的是,GPU 通常以大规模的水平并行实现图形管道。只有图形管道的软件实现,例如 Mesa 3D (参见维基百科条目),通常实现单个管道。
OpenGL ES 1.x、核心 OpenGL 1.x 和 Direct3D 7.x 的管道是可配置的固定功能管道,即无法在这些管道中包含程序。在 OpenGL (ES) 2.0、WebGL 和 Direct3D 8.0 中,管道的两个阶段(顶点着色器和片段着色器阶段)是可编程的,即在这些阶段应用了用 Cg(或其他着色语言)编写的程序(着色器)。在下图中,可编程阶段以绿色方框表示,固定功能阶段以灰色方框表示,数据以蓝色方框表示。
顶点数据 | 例如,由 3D 建模工具提供的三角形网格 | |||
↓ | ||||
顶点着色器 | 一个小的 Cg 程序应用于每个顶点 | |||
↓ | ||||
图元装配 | 设置图元,例如三角形、线条和点 | |||
↓ | ||||
光栅化 | 对图元覆盖的所有像素进行数据的插值(例如颜色) | |||
↓ | ||||
片段着色器 | 一个小的 Cg 程序应用于每个片段(即覆盖的像素) | |||
↓ | ||||
每片段操作 | 对每个片段(即覆盖的像素)进行可配置操作 | |||
↓ | ||||
帧缓冲区 | 存储计算出的片段颜色的像素数组 |
顶点着色器和片段着色器阶段将在特定平台教程中更详细地讨论。光栅化阶段在“光栅化”部分中进行讨论,每片段操作在“每片段操作”部分中进行讨论。
图元装配阶段主要包括将图元裁剪到视锥体(屏幕上可见的空间部分)以及可选的对正面和/或背面图元的剔除。这些可能性将在特定平台教程中更详细地讨论。
为了对 Cg 顶点和片段着色器进行编程,理解每个着色器的输入和输出非常重要。为此,了解数据如何在管道的各个阶段之间进行通信也很有用。这在下图中进行了说明
顶点数据 | ||||
↓ | 带有语义的顶点输入参数(例如 POSITION 、COLOR 、NORMAL 、TEXCOORD0 、TEXCOORD1 等) | |||
顶点着色器 | ← | 统一参数;在某些情况下,纹理数据(图像) | ||
↓ | 带有语义的顶点输出参数(特别是 POSITION 、SV_POSITION 和 PSIZE ,但也包括 COLOR 、TEXCOORD0 、TEXCOORD1 等) | |||
图元装配 | ||||
↓ | 顶点输出参数 | |||
光栅化 | ||||
↓ | 片段输入参数(在像素上插值),带有语义(对应于顶点输出参数的语义) | |||
片段着色器 | ← | 统一参数(每个图元都恒定)和纹理数据 | ||
↓ | 带有语义的片段输出参数(特别是 COLOR 和 DEPTH ) | |||
每片段操作 | ||||
↓ | 片段颜色和片段深度 | |||
帧缓冲区 |
顶点输入参数是根据顶点数据定义的。对于每个顶点输入参数,必须定义一个语义,它指定参数如何与固定功能管道中的数据相关。语义的例子有 POSITION
、COLOR
、NORMAL
、TEXCOORD0
、TEXCOORD1
等。这使得即使使用最初为固定功能管道设计的 API 也可以使用 Cg 程序。例如,顶点位置的顶点输入参数应该使用 POSITION
语义,以便所有 API 都可以为此输入参数提供适当的数据。请注意,顶点位置位于对象坐标系中,即这是在 3D 建模工具中指定的坐标。
统一参数(或制服)对于渲染特定图元(例如三角形)时执行的所有顶点着色器和所有片段着色器具有相同的值。但是,它们可以针对其他图元进行更改。通常,它们对构成网格的大量图元集具有相同的值。通常,顶点变换、光源和材料的规范等被指定为制服。
顶点输出参数由顶点着色器计算,即每个顶点有一组这些参数的值。必须为每个参数指定一个语义,例如 POSITION
、SV_POSITION
、COLOR
、TEXCOORD0
、TEXCOORD1
等。通常,必须有一个具有 POSITION
或 SV_POSITION
语义的输出参数,它决定了图元在屏幕上的渲染位置(“SV” 代表“系统值”,可以具有特殊含义)。点图元的大小可以通过具有 PSIZE
语义的输出参数来指定。其他参数将针对图元覆盖的每个像素进行插值(参见“光栅化”部分)。
片段输入参数是从顶点输出参数插值到图元覆盖的每个像素的。类似于顶点输出参数,必须为每个片段输入参数指定一个语义。这些语义用于将顶点输出参数与片段输入参数匹配。因此,顶点着色器和片段着色器中对应参数的名称可以不同,只要语义相同即可。
片段输出参数由片段着色器计算。必须指定一个语义,它决定了该值在以下固定功能管道中的使用方式。大多数片段着色器都指定了一个具有 COLOR
语义的输出参数。即使没有指定具有 DEPTH
语义的输出参数,片段深度也是隐式计算的。
纹理数据包括一个统一采样器,它指定纹理采样单元,而纹理采样单元又指定从中获取颜色的纹理图像。
其他数据在特定平台的教程中进行描述。
Cg 使用的可编程图形管道模型在Nvidia 的 Cg 教程的第一章中进行了描述。
< Cg 编程