90年代初期,随处可见的三维图形交互仍然像科幻小说里的内容一般遥不可及。然而到了90年代末,几乎每一个新的计算机里面都包含着一个叫做GPU的图形处理单元,该部件能提供高效的,视觉效果丰富的三维交互式体验。 可以说,消费者对视频游戏的需求,制造技术的进步以及人们对天生具有并行处理能力的图形管道的一系列探索,促成了这样的戏剧性转变。今天,GPU在纯计算方面的能力,可以把最强大的CPU甩好几条街,并且这个差距还在不断扩大。 此外,GPU已经从传统的3D图形固定管线转为一个灵活的通用计算引擎。时至今日,GPU能够直接通过图形硬件实现许多并行算法。一个设计良好,可以发挥全部计算能力的算法利用GPU可以实现巨大的速度提升。诚然,GPU已经称为商业并行计算机不可不考虑的一部分。
图形管道 任何一个图形系统的任务是通过场景生成图片,例如一个帧率为60的视频游戏。这个场景的图形元素一般是这么几个:照亮场景的灯光,物体反射灯光的方式,观察者的位置和朝向。 传统意义上讲,GPU设计者们把图像生成过程描述为专业化处理阶段的一个硬件管道。然而,现在我们以一个更高的层次来描述这个管道;我们的目标是通过把实时渲染过程涉及到的方方面面的计算抽取表达出来,让图形程序开发者们把GPU当作一个通用的并行计算引擎来挖掘使用。
管道输入: 大多数实时图形系统都把任何东西看作由三角形组成,它们把复杂的形状,比如四边形或者曲面分割成为三角形。开发者们利用计算机图形库(比如OpenGL或者Direct3D),以一次一个顶点的方式把每一个三角形提交到图形管道中;GPU按照需要再把顶点组装成三角形。
模型变换: GPU可以通过模型本地坐标系把场景中的每一个逻辑部件定位出来,这对于那些有层次结构的物体来说是很方便的。然而这种方便有代价:开始渲染之前,GPU必须首先把所有物体变换到一个统一坐标系中。为了保证三角形不会被扭曲成弯曲的形状,这种变换被限制为简单的仿射变换,例如旋转,平移,缩放等等。 像侧边“齐次坐标系”提到的,通过把每个顶点在齐次坐标系中表示出来,图形系统可以把整个层次的物体变换统一为一次矩阵-向量乘法。对每秒可以高效处理百万顶点相关的浮点数运算的硬件的需求,推动了GPU并行计算的技术革新。 管道的这个阶段的输出是三角形流,所有的三角形都被统一到一个坐标系中,观察者位于这个坐标系的中心位置,观察者朝向和Z轴平齐(译者注:相机坐标系)。
光照: 一旦每个三角形都被统一到全局坐标系中,GPU就可以根据场景中的光照计算他们的颜色。作为一个例子,我们可以想象一下单点光源的情况(假想很小的一个电灯泡)。GPU处理多光源是通过把每个独立光的计算结果加起来。传统的图形管道支持Phong光照等式(B-T. Phong, “Illumination for Computer-enerated Images ,”Comm. ACM, June 1975, pp. 311-317),一个类似于塑料外观的现象级外观模型。材质会把散射光分量和高光结合。Phong光照等式这样给出最终颜色 C = Kd × Li ×(N.L) + Ks × Li × (R.V)^S. 数学本身不如计算结构重要;为了高效计算结果,GPU必须能够直接操作向量。这里,我们要对两个向量点乘好几次,对四个部件进行乘和加的操作。(译者注:这里作者表达的是光照就是一些浮点数组成的向量的点乘和相加操作)
投影: 图形管道下一步将已经染色的三角形投影到屏幕上。如同模型变换一样,GPU这里要做矩阵-向量的乘法操作,又一次需要能够高效应付浮点数向量运算的硬件。这一步的输出是屏幕坐标系下的三角形流,准备着下一步转换为像素。
光栅化: 每一个可见的屏幕空间下的三角形重叠在显示器的一些像素上。确定这些像素的过程称为光栅化。GPU设计师们这些年来整合了许多光栅化算法,最终确立了这么一条准则:每一个像素都可以独立于其他像素,可以被单独处理。因此,GPU可以并行得处理所有的像素。实际上有些特别出色的GPU针对每一个像素都一个处理核心。这种固有的独立性引导着GPU设计师们建立多条并行的管道。
贴纹理: 每个像素的实际颜色可以直接从光照计算中得到,然而为了增强真实感,被称作纹理的图片往往要贴在几何体上增强细节。GPU把纹理存储在显存中,每一个像素处理器在给像素着色或者修改像素颜色的时候都要去访问那部分显存。(译者注:纹理必然会被输送到显存,不然每次像素着色器访问内存实在太慢了) 为了减轻视觉假象带来的出现在屏幕上的纹理比实际分辨率大或者比实际分辨率小这种现象,实际上GPU需要多重纹理(译者注:这段没翻译好)因为对存储纹理的显存的访问模式很固定(邻近的像素访问的显存的位置也是邻近的),所以专门设计高速缓存可以帮助消除内存访问带来的延迟。
消隐面: 大多数场景中,一些物体会遮挡另一些物体。如果每一个像素仅仅是简单地写入到显示内存中(译者注:后台缓冲),那么最后提交的三角形肯定会显示到最前面。因此要想正确地消隐该隐藏的面,需要在渲染的时候把所有的三角形从前到后排序一遍,但这样代价太大,几乎任何场景都不可能这样实现。 现代GPU都提供了一个深度缓存,这块区域存储了每个像素点和观察者之间的距离。在写入显示内存之前,GPU将对当前像素点和之前已经在这个位置的像素点的距离做一个比较,仅仅当新像素点比之前像素点的距离近的时候,对应的显示内存才会更新。
图形管线的发展: GPU已经从一个图形管道的硬件实现,发展为可编程的计算基板。用于变换顶点和纹理像素处理的固定功能单元,已经被归入同一个处理器网格,或者叫做shaders,这个东西不仅能够接管之前的任务,而且还能够做更多。 在不停增长的可编程单元逐渐替代独立功能管线的过程中,这种变革已经进行了好几代。例如,NVIDIA GeForce3,于2001年推出,引入了可编程顶点着色器。该着色器提供了相应的单元可以让程序员进行矩阵-向量乘法,幂,平方根等运算,同时提供了一段短的默认程序,可以利用这些单元进行顶点变换和光照操作。 在像素处理方面,GeForce3也引入了有限的可操控性。让纹理处理的相关硬件作为一系列寄存器的组合进行编程可以实现奇异的视觉效果,如图中的“肥皂泡”。 在这之后的GPU引入了更强的灵活性,增加了更多的寄存器,增强了对长程序以及控制流原语如分支,循环,子程序的支持。 ATI的Radeon 9700(02年7月)和NVIDIA的GeForce FX(03年1月)把一直处于尴尬位置的寄存器组合替换成为完全可编程的像素着色器(译者注:之前像素着色器的可编程性相当有限)。NVIDIA的最新芯片,GeForce 8800(06年11月)在原始的三角形组装阶段也增加了可编程性,允许开发者控制经过变换的顶点组装成三角形这个步骤(译者注:Geometry Shader吧)。 如上图所示,现代GPU已经能够实现令人惊叹的逼真视觉效果。 伴随着精度的提高,可编程性进一步提高。传统的图形管道只能用8位整数表示每个颜色分量,允许范围内的值为0到255。ATI Radeon9700把颜色精度提高到24位浮点数,NVIDIA的GeForce FX也提高到16位和24位浮点数。两家厂商都宣布计划在接下来的芯片中会把精度提高到64位双精度浮点数。 为了满足图形性能的无情需求,GPU已经在积极地往并行设计方面靠拢。GPU一直在使用4矢量寄存器,就像Intel在CPU上的SSE指令那样。用在并行处理方面的四矢量处理器的数目一直在增加,GeForce FX上面只有四个,GeForce 6800 (2004年4月)上面有16个,GeForce 7800 (2005年5月)上面有24个。GeForce 8800实际包含128个标量着色处理器,他们以一个特殊的着色器时钟频率运行着,该始终频率为前置芯片的2.5倍(相对于像素输出),因此计算性能等同于128*2.5/4 = 80个四失量像素着色器。
统一着色器: 在由硬连线管道转为灵活的计算方式的变革中,最新的进展是统一着色器的引入。统一着色器第一次在用于Xbox 360平台游戏的ATIXenos芯片中实现,Nvidia 通过GeForce 8800芯片讲他们引入了PC平台。 用于顶点着色器,几何着色器和像素着色器的单独自定义处理器,已经被统一着色器的架构所取代。该架构提供大量的并行数据浮点数处理器网格,这个网格足够通用,能够处理前三种着色器的工作。 如图中所示,顶点,三角形和像素循环出入网格,而不是流入固定宽度的管道。 这种配置带来了更好的整体利用率,因为不同应用程序对不同着色器的需求差异很大,甚至同一程序的单帧这种差异也很大。(译者注:某些程序可能对顶点着色器利用率高,几何着色器相当于比较空闲,而另一些程序可能顶点着色器空闲,几何着色器利用率高,甚至在同一程序的不同帧这种差异性都很大,导致了某些着色器忙不过来,而另外一些着色器闲着没事做。统一着色器的思想就是负载均衡)。比如,视频游戏可能在某一帧的开始,用到大三角形来画天空和远处的地形,传统的图形管道中这会让像素处理器迅速处于负荷满载状态,而顶点处理器几乎是闲置状态;一毫秒之后,游戏可能会用到高细节几何体来表现角色和物体,这样又导致了顶点着色器繁忙,而像素着色器空闲。这种单帧间资源需求的剧烈震荡是游戏设计师处理负载均衡的噩梦,并且会导致玩家改变视点和动作时出现不可预料的表现效果。而另一方面,统一着色器能够针对具体需求,动态改变每种着色器占用处理器池的百分比。例如,在绘制天空的时候,GeForce 8800可能会把128个处理器中的90%拿出来给像素着色器用,10%拿出来给顶点着色器用,然后当绘制远处角色的几何模型时,会把这个比例反过来。结果就是,灵活的并行架构提高了GPU的利用率,并且为游戏设计师带来了更大的灵活性。
GPGPU 计算机图形高度并行的工作量,要求非常高的运算吞吐量和流数据内存带宽,但是由于最终每16毫秒显示一张图像,因此在独立运算方面能够忍受一定的延时。这些工作负载的特性造就了以下GPU架构:CPU针对低延时进行优化,而GPU针对高吞吐量优化。 GPU原始计算能力是相当惊人的:在简单的基准测试中,单一的GeForce 8800芯片能够每秒持续进行330亿次浮点数操作(http://graphics.stanford.edu/projects/ gpubench).GPU不断增长的能力,可编程性和精确性已经引起了对图形硬件通用计算的大量研究,简称GPGPU。GPGPU研究者们把GPU看作一个计算协作处理器,而不是一个图形处理设备。 GPU特殊的架构不能很好的适用于每一个算法。许多程序本质上是串行的,其特性在于不相干性和对内存访问的不可预测性。尽管如此,许多重要的问题需要大量的计算资源,很好地契合了GPU多核心运算密度;或者需要大量流数据,很好地契合了GPU流内存子系统。 GPU上移植一个精挑细选的算法,相对于跑在国家最新进CPU上的经过成熟优化过的代码,经常能够带来5到20倍的速度提升。目前已经发现,对那些契合度相当高的算法,这个速度提升甚至是100多倍。 值得注意的是,GPGPU成功的地方还是很多,包括斯坦福的Folding@home 项目,这个项目利用全世界用户电脑空闲的时间来研究蛋白质分解问题(http://folding.stanford.edu)。一种新的通过GPU加速的Folding@home客户端在其06年10月发布一个月之后就贡献了28,000Gfops。从2000年10月起,超过百分之18的总Gflops是由运行在Windows系统上的CPU客户端来实现的。 另一个GPGPU成功的故事是,北卡罗莱纳州大学和微软的研究院利用基于GPU的代码赢得了2006年印第安纳波利斯PennySort类别的TeraSort 赛事,该赛事利用基准测试对数据库的性价比做一个排序。(http://gamma.cs.unc.edu/GPUTERASORT).(译者注:对这部分我也很不熟悉,翻译得太生硬了sigh~大家只需要知道GPGPU又长脸了就成)。和GPU本身比较有关系的是,HavokFX产品利用GPGPU技术,对用在电脑游戏方面的增强物体真实性的物理计算进行了10倍的加速(www.havok.com).
现代GPU可以看作是第一代商业并行数据处理器。GPU巨大的计算能力和快速增长曲线,远远超过了传统的CPU,凸显出在数据并行处理方面的专业优势。 我们可以预期,未来GPU架构会进一步增强可编程性和通用性,但这并非没有限制;无论是厂商还是用户都不希望牺牲架构的专业性,因为正是这种专业性确保了GPU的成功。今天,GPU开发者们需要更高级的编程范式,以此来处理大规模多线程并行计算,这个问题同样会对多核CPU得生产厂商产生影响。 GPU厂商,图形开发者和GPGPU社区能不能超越计算机图形这个本源,在未来商业并行运算领域取得成功并开发出一整套桌面并行计算的计算模型,技术和框架?
原文下载链接,这次只能说是粗译,文中难免有不妥的地方,还望大家指正。