赞
踩
编程多处理器GPU与编程其他多处理器(如多核CPU)在本质上有所不同。GPU提供了比CPU高两个到三个数量级的线程和数据并行性,能够扩展到数百个处理器核心和数万个并发线程。GPU持续增加其并行性,大约每12到18个月翻一番,这是通过摩尔定律提高集成电路密度以及不断提升的架构效率实现的。为了覆盖不同市场细分领域广泛的价格和性能范围,不同的GPU产品实现了数量大相径庭的处理器和线程。
然而,用户期望游戏、图形、图像及计算应用能够在任何GPU上运行,无论该GPU执行多少并行线程或拥有多少并行处理器核心,而且他们期望更昂贵的GPU(拥有更多线程和核心)能更快地运行应用程序。因此,GPU编程模型和应用程序设计为能够透明地扩展到广泛的并行度范围。
驱动GPU中大量并行线程和核心的主要动力是实时图形性能——需要以至少每秒60帧的交互式帧率渲染高分辨率的复杂3D场景。相应地,诸如Cg( C for graphics)和HLSL(高级着色语言)等图形着色语言的可扩展编程模型旨在通过许多独立的并行线程来利用大规模并行性,并且可以无差别地扩展到任意数量的处理器核心。
同样,CUDA可扩展并行编程模型使一般并行计算应用程序能够利用大量的并行线程,并且能够透明地扩展到任意数量的并行处理器核心。
在这些可扩展的编程模型中,程序员只需为单个线程编写代码,而GPU则会并行运行数以百万计的线程实例。因此,程序能够透明地适应广泛硬件并行度范围内的扩展。这一简洁的范式源于图形API和着色语言,它们描述了如何对单个顶点或单个像素进行着色。自上世纪90年代末以来,随着GPU快速增加其并行性和性能,这一范式仍然保持着有效性。
本节首先简要介绍如何使用图形API和编程语言来为实时图形应用程序编程GPU,然后描述如何使用C语言和CUDA编程模型为视觉计算以及通用并行计算应用程序编程GPU。
API(应用程序编程接口)在GPU和处理器的快速、成功发展中扮演了重要角色。目前存在两个主要的标准图形API:OpenGL和Direct3D,其中Direct3D是微软DirectX多媒体编程接口的一部分。OpenGL是一个开放标准[Segal and Akeley, 2006 ; Kessenich, 2006],最初由硅谷图形公司提出并定义。OpenGL标准的持续开发与扩展由行业联盟Khronos负责管理。而作为事实上的标准,Direct3D的定义和发展则由微软及其合作伙伴推动前进[Blythe, 2006]。
OpenGL:一种开放标准图形API。
Direct3D :由微软及其合作伙伴定义的图形应用程序接口。
Segal, M. and K. Akeley [2006]. Th e OpenGL Graphics System: A Specifi cation, Version 2.1, Dec. 1, 2006 . www.opengl.org/documentation/specs/.
Kessenich, J. [2006]. Th e OpenGL Shading Language, Language Version 1.20, Sept . 2006 . www.opengl.org/
documentation/specs/.
Blythe , D. [ 2006 ]. “ Th e Direct3D 10 System ” , ACM Trans. Graphics Vol. 25 , no. 3 (July) , 724 – 34 .
OpenGL和Direct3D在结构上相似,并随着GPU硬件的进步不断迅速演进。它们共同定义了一个逻辑图形处理流水线,该流水线被映射到GPU硬件及处理器上,同时为可编程流水线阶段提供了相应的编程模型和语言支持。这两种API与GPU硬件紧密结合,共同驱动着实时图形和视觉计算应用的发展。
图B.3.1展示了Direct3D 10逻辑图形流水线的结构,OpenGL也有类似的图形流水线构造。API和逻辑流水线为可编程着色器阶段(用蓝色标注)提供了数据流处理的基础架构与支持。3D应用程序向GPU发送一系列按照几何基本元素(点、线、三角形和多边形)分组的顶点。
输入装配器收集顶点和基本几何元素。顶点着色器程序执行每顶点处理,包括将顶点的三维坐标转换为屏幕坐标,并进行光照计算以确定顶点颜色。几何着色器程序执行每基本元素处理,可以添加或丢弃基本几何元素。设置及光栅化单元生成被几何基本元素覆盖的像素片段(片段是对像素潜在的贡献)。像素着色器程序执行每片段处理,包括插值每个片段参数、纹理映射和着色。
像素着色器大量使用采样和过滤方法访问被称为纹理的大规模一维、二维或三维数组,利用插值浮点坐标。着色器通过纹理访问实现地图、函数、贴花、图像和数据等功能。光栅操作处理(或输出合并)阶段执行深度缓冲区深度测试和模板测试,这可能丢弃隐藏的像素片段或将像素的深度替换为片段的深度,同时还执行颜色混合操作,将片段颜色与像素颜色相结合,并将融合后的颜色写入像素中。
纹理:一种支持使用插值坐标进行采样和过滤查找的一维、二维或三维数组。
图形API和图形流水线为处理每个顶点、基本几何元素以及像素片段的着色器程序提供输入、输出、内存对象以及所需的基础结构和资源。
实时图形应用中使用了多种不同的着色器(Shader)程序来模拟不同材质与光的交互,并实现复杂光照和阴影渲染。着色语言基于数据流或流式编程模型,该模型与逻辑图形流水线相呼应。
着色器:一种用于处理图形数据(如顶点或像素片段)的程序。
着色语言:一种图形渲染语言,通常采用数据流或流式编程模型。
顶点着色器程序将三角形顶点的位置映射到屏幕上,改变它们的位置、颜色或方向。通常情况下,一个顶点着色器线程接收一个浮点型(x, y, z, w)顶点坐标作为输入,并计算出浮点型(x, y, z)屏幕坐标。
几何着色器程序对由多个顶点定义的几何基本元素(如线条和三角形)进行操作,更改它们或者生成附加的基本元素。像素片段着色器则逐个“着色”每个像素,在其像素采样位置(x, y)计算渲染图像的浮点型红绿蓝透明度(RGBA)颜色贡献值。
着色器(以及GPU)在所有像素颜色计算中都采用浮点数运算,以消除在处理具有复杂光照、阴影及高动态范围场景时可能出现的可见失真现象。
对于这三种类型的图形着色器,由于每个着色器都在独立的数据上工作,产生独立的结果,并且没有副作用,因此可以并行运行许多程序实例,作为独立的并行线程。独立的顶点、基本几何元素和像素进一步使得相同的图形程序能在处理不同数量并行顶点、基本元素和像素的不同规模GPU上运行。因此,图形程序能够透明地适应具有不同并行性和性能等级的GPU。
用户使用一种通用目标级别的高级语言为这三种逻辑图形线程编写程序。HLSL(高级着色语言)和Cg(用于图形的C语言)是常用的两种。它们具有类似于C语言的语法,并提供了一系列丰富的库函数,用于矩阵运算、三角函数、插值、纹理访问和过滤等操作,但与通用计算语言相比有很大的局限性:目前它们缺乏通用内存访问、指针、文件I/O和递归功能。HLSL和Cg假定程序存在于逻辑图形流水线内部,因此I/O是隐含的。例如,像素片段着色器可能期望几何法线和多个纹理坐标已经在上游固定功能阶段进行了插值,它可以简单地将一个值赋给COLOR输出参数,将其传递至下游与其他像素颜色进行混合,而这个像素位置是隐含的(x, y)坐标。
GPU硬件为每个顶点、每个基本几何元素和每个像素片段创建一个新的独立线程来执行顶点、几何或像素着色器程序。在视频游戏中,大部分线程执行的是像素着色器程序,因为像素片段的数量通常比顶点多10到20倍,而且复杂的光照和阴影处理需要更大的像素着色器线程与顶点着色器线程的比例。
图形着色器编程模型驱动了GPU架构的发展,使其能高效地在大量并行处理器核心上执行成千上万条独立的细粒度线程。
考虑以下Cg像素着色器程序,它实现了“环境映射”渲染技术。对于每个像素线程,该着色器接收五个参数,包括用于采样表面颜色所需的二维浮点型纹理图像坐标以及一个表示视方向在表面反射的三维浮点向量。另外三个“统一”(uniform)参数在不同像素实例(线程)之间不会发生变化。
着色器在两个纹理图像中查找颜色:首先通过二维纹理访问获取表面颜色,然后通过立方体贴图(对应于立方体六个面的六张图像)的三维纹理访问获得与反射方向相对应的外部世界颜色。最后,使用称为“lerp”或线性插值函数的加权平均方法计算最终的四分量(红色、绿色、蓝色、alpha通道)浮点型颜色。
void refection(
float2 texCoord : TEXCOORD0,
float3 refection_dir : TEXCOORD1,
out float4 color : COLOR,
uniform float shiny,
uniform sampler2D surfaceMap,
uniform samplerCUBE envMap)
{
// Fetch the surface color from a texture
float4 surfaceColor = tex2D(surfaceMap, texCoord);
// Fetch reflected color by sampling a cube map
float4 reflectedColor = texCUBE(environmentMap, refection_dir);
// Output is weighted average of the two colors
color = lerp(surfaceColor, refectedColor, shiny);
}
尽管这个着色器程序仅有三行代码,但它却能激活GPU硬件的大量功能。对于每次纹理获取操作,GPU的纹理子系统会在采样坐标附近进行多次内存访问以采样图像颜色,并使用浮点数过滤算法对最终结果进行插值。多线程GPU并行执行成千上万这些轻量级的Cg像素着色器线程,并深度交织它们以隐藏纹理获取和内存延迟。
Cg编程语言专注于程序员从单个顶点、基本几何元素或像素的角度来编写程序,而GPU则将这些实现为单个线程;着色器程序透明地扩展以利用可用处理器上的线程并行性。作为针对特定应用设计的语言,Cg提供了一系列丰富且有用的数据类型、库函数以及语言结构,以便表达各种不同的渲染技术。
图B.3.2展示了一个由片段像素着色器渲染的皮肤效果。真实的皮肤与单一肉色调颜料看起来大不相同,这是因为光在重新发射前会大量散射。在这个复杂的着色器中,模拟了具有独特次表面散射行为的三层皮肤,从而赋予皮肤视觉上的深度感和半透明效果。散射可以通过在一个加宽的“纹理”空间中的模糊卷积来建模,其中红色比绿色更模糊,蓝色则模糊得较少。编译后的Cg着色器执行1400条指令来计算一个皮肤像素的颜色。
随着GPU在实时图形处理中展现出卓越的浮点性能和极高的流式内存带宽,它们吸引了许多超越传统图形处理的高度并行应用。起初,只有通过将应用程序包装成图形渲染算法的方式才能利用这种强大的性能,但这种通用GPU(GPGPU)方法往往显得笨拙且具有局限性。最近,CUDA编程模型提供了一种更为简便的方法,能够使用C编程语言轻松利用GPU可扩展的高性能浮点计算能力和内存带宽。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。