本文将从移动GPU的结构、参数、兼容性、跑分几方面让读者全方位对移动GPU有一定的概念。由于篇幅较长,分成两部分介绍,这是第一部分,讲解的是移动GPU的结构和相关参数。

前言

现在移动设备的“核战”越来越激烈,已经从CPU引发到了GPU上,于是“16核”、“8管线”、“MP4”、“三角形生成率”和“填充率”等各种吸引眼球的宣传铺天盖地而来。一直很希望能有些文章来介绍科普下,但或许是专业人士都觉得这些太基础,最后忍不住,只能由我这个半桶水的非专业人士来写点啥了。本文参考和引用了网上的一些资料,篇幅有限恕不一一列举。内容尽可能的科普浅显,但限于个人的知识层次、理解能力和表达能力,如果有不确切或者错误的地方,还请多多指正。


基本的3D流水线


首先我们来简单的介绍下3D的画面是如何生成的,一个基本的3D流水线如下图所示:

首先,运行在CPU上游戏引擎根据游戏中的一些参数,产生一系列的图元,将它们的顶点数据发送给GPU。

第二步,顶点处理器(Vertex Processor)对顶点数据进行一系列的变换和光照处理。简单的想想,游戏中的各个物体的坐标都是参照游戏中的世界坐标系的,而实际显示的画面是玩家视角或者摄像机视角,这中间就有许多坐标系的转换。这些活就需要顶点处理器来做,最终我们得到了我们所需要视角的画面。

但是,到这一步,画面还只是一些多边形,而实际显示在屏幕上的是一个个像素,这里就需要Rasterizer进行光栅化(Rasterization,3),从而将画面变成一个像素图。

第四步,对这些像素进行上色,Fragment Processor中的像素着色器(Pixel Shader)按照程序规定的算法,计算出画面中每个像素的颜色,之后第五步就是把结果输出到内存中,全部完成后拿去显示。当然在这整个过程中,还跟纹理贴图6有关系。所谓贴图就是把纹理(一个二维的静态图片)按照一定的算法给贴到游戏里的三角形表面上去。

参数,究竟靠不靠谱?

终端厂商在宣传他们手机芯片的GPU如何强劲时,往往会提到一些参数,最常见的就是三角形生成率和填充率。但实际上,不同公司的GPU,他们的这些理论参数,并不具有直接的可比性。我们也可以发现,有些GPU可能给出的理论参数很高,但实际表现却很一般,甚至不如一些参数低的GPU。这是因为,各个GPU的供应商,比如IMGtec(PowerVR SGX),高通(Adreno),Vivante(GC系列),ARM(Mali),nVIDIA(GeForce),他们给出这些理论数据的测试方式,可能不太一样。

比如三角形生成率,本身就受到很多测试因素的影响。例如,有些三角形在一开始就会被剔除掉(比如在屏幕外,或者太小了根本覆盖不到一个像素),不会被显示也不会需要执行太多的运算,那么这部分三角形到底应该算吗?如果算进去的话,三角形生成率自然就高了。或者,测试程序把一些已经计算好的坐标提交给GPU,那么GPU的Vertex Shader就不需要进行复杂的计算,数值自然就高了。再或者,并非生成一个三角形就一定需要处理三个顶点。如果有三角形共享顶点,用indexed的办法绘制,顶点的数目就可以减少。就像下图,2个三角形只需要处理4个顶点。如果测试的时候大量使用这种方式,也可以提高三角形生成率的数值。

同样,填充率反映了GPU的像素输出能力。但是厂家给出的理论值,很多都是没有贴图,没有Shader计算,仅仅是生成无色点的能力,跟实际使用的情况有较大的差距。又比如Imagination Technologies 的PowerVR SGX系列给出的填充率,并不是实际值,而是实际值乘以了一个2.5x的系数。这是由于PVR GPU架构的特殊性,可以剔除画面中被遮蔽的部分,不作渲染,减少了无用功。200MHz的SGX540,原生的填充率是400M,而由于这种技术的存在,IMG认为其等效填充率相当于1000M。在实际的场景中,如果遮蔽的部分较多,这个系数可能远超过2.5x。当然,如果场景中遮蔽较少,这个系数相应的也会变小。

事实上三角形生成率和像素填充率作为衡量GPU性能的参数,在PC平台上,几年前就已经被淘汰了。由于从DX8开始,现代GPU都已经由可编程的Shader来代替固定功能的单元实现各种特效,所以Shader的计算能力成为很重要的一点,在移动平台也是一样的。

移动平台的特点和移动GPU的架构

不过呢,移动平台相比于PC平台,还是有很多不同的。从本质上看,是由功耗和体积两方面限制的,对于图形处理来说,主要是两点:

第一,是有限的带宽。实际上,要增加计算能力,在功耗允许的情况下,堆核心并不是一件难事,事实上我们也看到了不少SOC集成了四核乃至“16核”GPU。但是难点在于,需要有足够的带宽去满足这颗强大的GPU,避免其出现“饿死”的情况。在左图的移动平台中,CPU、GPU和总线被共同集成在一颗芯片上,称之为SOC。整个SOC,包括其中的CPU和GPU,共享有限的内存带宽。即使是相对高端的,采用64bit内存位宽的一些SOC,如三星4412,高通8064等,也只是6.4 - 8.5GB/s的带宽,相比起PC平台主内存十几GB/s的带宽,和PC GPU GDDR5显存动辄几十,不少都超过100GB/s的带宽,只能说是少的可怜。相对另类的苹果在iPad4中,给A6X芯片搭配了128bit的LPDDR2-1066,带宽达到了17GB/s,用以喂饱强大的SGX 554 MP4 GPU,但相比PC平台依旧是小巫见大巫。因此,移动平台要在有限的带宽下实现合理的性能,在不少时候,瓶颈可能并不在于计算能力上,而在于带宽上。

第二,相比PC平台的CPU,移动平台的CPU浮点较弱,在Cortex-A9开始虽然有所好转,但64bit的NEON跟桌面128bit甚至256bit的SIMD还是有显著差距,外加主频的差别。因此更多的计算也依赖硬件Vertex Shader去完成。

因此,移动平台的GPU相对于PC平台,也会有一些不同。我们回过头来看一下移动平台的GPU的一些架构。

首先是传统的IMR(Immediate Mode Rendering)架构

目前几乎所有的桌面GPU(nVIDIA,AMD)都是IMR架构,在移动领域,nVIDIA的GeForce ULP和Vivante的GC系列GPU都是属于IMR架构。IMR架构的GPU渲染完物体后,都会把结果写到系统内存中的帧缓存里,因此就可能出现GPU花了大量的时间渲染了一个被遮挡的看不见的物体,而最后这些结果在渲染完遮挡物后被覆盖,做了无用功。这个问题称之为Overdraw。虽然现代的IMR架构GPU在一定程度上可以避免这个问题,但要求应用程序将场景里的三角形按照严格的从前往后的顺序提交给GPU,要完全避免Overdraw还是很困难的。

另一方面,由于IMR架构的GPU频繁的读写和修改帧缓存,因此对带宽的要求比较高,同时也增加了电力的消耗。

所以,大部分的移动GPU都采用TBR(Tile Based Rendering)的架构

ARM的Mali GPU和高通的Adreno GPU采用TBR(分块渲染)架构,实际上IMG的PowerVR也是分块渲染的。TBR架构在把三角形场景变成像素图(光栅化)前,先把整个画面分成小块,这些小块的渲染在GPU上的高速缓存里进行,这样就避免了对帧缓存(位于系统内存里)的频繁读写和修改。当然,由于一个三角形可能被分在几个不同的块里,三角形的数据(几何数据)可能被需要多次读取,但总的来说还是能大大减少对系统内存的访问,节约了带宽的同时也减少了电力消耗。

当然,不同的GPU分块的大小也有所不同,PowerVR和Mali一般是16*16像素的块大小,而大部分的高通Adreno都带有256K的缓存,以256K作为块的大小进行渲染,高通称之为binning。

但是,除去PowerVR外的TBR GPU同IMR一样,还是不能避免Overdraw的问题。

而PowerVR的不同之处在于,它采用的TBDR(Tile Based Deferred Rendering)架构,可以彻底避免Overdraw的问题。

相比TBR更进一步的是,TBDR在光栅化之后,有一个HSR(Hidden Surface Removal))硬件单元,通过对一个块内的三角形进行测试,剔除掉被遮挡的三角形,合成一幅由所有可见部分组成的画面,交给后续的流水线去渲染。这样不可见部分就不需要Pixel Shader去做相应的计算,也不需要去拾取相应的纹理,节省了计算量的同时也节省了带宽,对移动设备来说有很大的帮助。

说说被忽略的Shader

接下来我们回到Shader。Shader是GPU里负责计算的主要部分,同时占得面积最大,耗电也最多。当今的桌面GPU往往都不再谈三角形生成率,或是像素填充率了,给的指标都是Shader的计算能力——GFLOPS。可见,Shader性能会越来越重要。移动GPU也有着这样的趋势。我们看一下Anandtech测试的各款GPU的GLBenchmark的Egypt HD 1080p Offscreen得分:

右边的绿色数字是该GPU在FP16精度下大致的计算性能,单位为GFLOPS。可以看到除去个别的GPU,Egypt成绩跟Shader计算能力的相关性还是比较明显的。

先做一点铺垫:

首先,对于浮点数做一次加法或者乘法,都算是一次操作,记作1 FLOPS。浮点数是有一定的精度的,比如16bit的浮点数,精度就是FP16。再高一点的FP32就是32bit的浮点数,也就是常说的单精度;更高的就是64bit的双精度FP64了。一般来说,只有FP32和FP64的操作才能算是FLOPS。

在移动平台的OpenGL ES里,可以指定高、中、低三种不同的精度。对不同的GPU来说,高、中、低精度的实际值略有差别。如下图所示:

对于Adreno和GC系列,无论何种选择何种精度,都会按照FP32精度进行计算。而Mali-400和Tegra的ULP GeForce的Pixel Shader部分不支持高精度,最高只支持中等的FP16精度。绝大部分游戏的Pixel Shader计算都采用中等(FP16)的精度,而Vertex Shader的计算一般是FP32的精度。

其次,关于统一渲染架构(Unified Shader)和分离的渲染架构(Discrete Shader)。前者的Shader既能进行Vertex的计算,也能进行Pixel的计算,例如PowerVR,Adreno,GC系列。后者的Vertex Shader和Pixel Shader是分开的,典型的比如Mali-400和ULP GeForce。相对来说,统一渲染架构的Shader利用率会高些,在遇到三角形特别多像素特别少,或者相反的情况下,Shader的计算能力不容易被浪费。

最后,由于顶点坐标(xyzw)和像素颜色(rgba)都具有四个属性,为了提高效率,Shader往往被设计成Vec4的SIMD,也就是可以对四个数据进行打包,然后用一条指令同样的处理。当然如果数据少于四个,计算能力就被浪费了。也有设计成一次只能处理一个数据的标量(scalar)单元。

各家GPU的Shader组成

1. 高通Adreno系列

Adreno系列为统一渲染架构,shader ALU为典型的Vec4 + Scalar,Vec4每周期可以处理4个FP32的MAD运算(乘加运算,记为2 FLOPS),Scalar单元不能做MAD,所以,

一个Adreno的Shader单元,每周期可提供的浮点操作数为4×2 + 1= 9 FLOPS。

主流Adreno GPU运算能力:

Adreno 200, 2 Vec4+1, 133MHz,2.4GFLOPS

Adreno 205, 4 Vec4+1, 266MHz,9.5GFLOPS 

Adreno 220, 8 Vec4+1, 266MHz,19.1GFLOPS 

Adreno 225, 8 Vec4+1, 400MHz,28.8GFLOPS 

Adreno 320, 如果是16Vec4+1, 跑400MHz的话,就是57GFLOPS

以上都是FP32的计算能力,由于OPENGL ES里,高中低精度Adreno都是按照FP32跑,因此在低精度的情况下,也不能获得性能提升。

2. PowerVR SGX系列

2.1 旧的SGX5系列

包括SGX530/531/535/540/545,其Shader计算单元为USSE。USSE一个周期,可以对4个FX10(10bit的定点数,比FP16精度更低) 或者 2个FP16 或者 1个FP32 进行MADD操作。由于FP32才算是正常意义上的FLOPS,所以其性能每周期2 FLOPS。但是当两个FP32的操作共享一个操作数时,USSE也可以在一个周期里处理,此时就是2个FP32的MAD操作,4 FLOPS。所以,USSE的FP32性能,每周期为2~4 FLOPS。

主流SGX5 GPU运算能力:

SGX530, 2USSE,200MHz,0.8~1.6 GFLOPS

MTK的SGX531,2USSE,300MHz,2USSE,1.2~2.4 GFLOPS

三星蜂鸟SGX540,4USSE,200MHz,1.6~3.2 GFLOPS

OMAP4460,ATOM Z2460的SGX540 400MHz, 4USSE,3.2~6.4 GFLOPS

不过在FP16下,也就是大多数游戏的Pixel Shader精度下,相比FP32的最差情况下就能翻倍了。同样在更低精度的FX10下,还能再翻倍。

2.2 SGX 5XT系列

包括SGX543/544/554,和它们的各种多核版本。其Shader计算单元为USSE2。USSE2不像之前那样了,是个Vec4+scalar的架构,单周期支持4个FP32的MAD操作,外加一个简单的scalar操作(ADD/MUL),这样跟Adreno一样,每周期 9 FLOPS。

单个543/544包含4个USSE2,性能基本一样,544多一些DX的API支持。单个554则包含8个USSE2。

主流SGX5XT GPU运算能力:

iPhone 4S里的543MP2,2×4=8个USSE2,200MHz,14.4 GFLOPS

OMAP4470里的单个544,384MHz,4USSE2,跟上面类似

全志A31里的544MP2,所谓的8管线就是8USSE2,300MHz,也有21.6 GFLOPS

iPad3里的A5X,543MP4,16USSE2,250MHz,36 GFLOPS

iPad4的A6X,554MP4,32USSE2,280MHz,就突破80 GFLOPS了


在运算较低精度的FP16时,USSE2的性能还能有一定的提升。

3. ARM Mali系列

3.1 Mali-400

Mali-400并非Unified Shader,是顶点和像素处理分开的

一个顶点处理器包含一个Vertex Shader ,Vec4,支持FP32精度

一个像素处理器包含一个Vec4的Pixel Shader,以及一个TMU, Shader支持FP16精度

主流Mali GPU运算能力:

一个Mali-400“单核”,400MHz下,计算能力为6.4 GFLOPS

Exynos 4210的Mali-400 MP4,266MHz,则为10.6 GFLOPS

Galaxy S3的Mali-400 MP4, 440MHz,则为17.6 GFLOPS

Note2的Mali-400 MP4,运行在533MHz,则为21 GFLOPS

当然这些都是FP16…… 因为Mali-400的Pixel Shader不支持FP32精度。

3.2 Mali-T6xx系列

T6xx采用新架构,Shader为统一渲染架构。其中T604/624/628 ,一个核心含有2个ALU,而T658/678,为强化计算型,一个core含有4个ALU。

每个ALU是个128bit wide的Vector Unit加上一个32bit的Scalar单元组成。

所以,单精度(FP32)性能为每周期9个,同USSE2。

那么Exynos 5250里533MHz的Mali-T604 四核,FP32的计算能力为 38.4 GFLOPS

同样,因为游戏里用的多的Pixel Shader是FP16精度,而T604的VU ALU此时处理能力能翻倍变成8个,这样每周期就是8*2 + 1 =17个。符合ARM宣称的500MHz下单个T604核心17GFLOPS,四核心68GFLOPS的数据。

那么Exynos 5250里533MHz的Mali-T604 四核,FP16的计算能力为 72.5 GFLOPS

4. GeForce ULP

GeForce ULP同Mali-400,是分离的Shader架构。其Vertex Shader和Pixel Shader都是Scalar的,并非Vec4。顶点支持FP32精度,像素部分支持FP20和FX10精度。所以,

“8核”Tegra 2, 4VS + 4PS,300MHz,计算能力为4.8 GFLOPS

“12核”Terga3,4VS + 8PS,520MHz,计算能力为12.5 GFLOPS 

5. Vivante的GC系列

跟Adreno差不多,也是Vec4 +1的结构,同样高中低精度都按照FP32计算,低精度下不会有提升。

RK29的GC800, 1Vec4+1, 450MHz,4 GFLOPS

飞思卡尔i.MX6的GC2000, 4Vec4+1,600MHz,21.6 GFLOPS

海思K3V2的GC4000,8Vec4+1,480MHz,34.6 GFLOPS

GPU“兼容性”

现在还有个经常被提到的是GPU的“兼容性”问题,这里就要涉及到各个GPU支持的纹理格式了。

首先是ETC1,这个是OPENGL ES 2.0支持的纹理格式,大家都得支持。但这个纹理的一个缺点是不支持alpha通道,所以对于有alpha通道的纹理,就要拆成2个纹理去读取,效率低,浪费了带宽。

而PVRTC是PowerVR自家的纹理格式,同样ATITC是高通Adreno的纹理格式,此外S3TC就是桌面很常见的DXT,微软DirectX 3D的纹理格式,这些都是支持alpha通道的。

PowerVR GPU支持自家的PVRTC和通用的ETC1(iOS下的PVR GPU只支持PVRTC),Adreno支持自家的ATITC和通用的ETC1,NV的GeForce和Vivante的GC系列支持DXT和ETC1,剩下Mali-400只支持ETC1。所以,对应不同的GPU,会有不同的游戏数据包。通用数据包,一般都会采用ETC1,虽然通用,但由于不支持alpha通道要贴图2次,对于非Mali的GPU其实都算是吃亏了。如果用自己支持的其他格式,就不用受这个苦了。对于贴图单元(TMU,Texture Mapping Unit)数目相对较少的Adreno 2xx系列,恐怕更是吃亏。

当然,纹理的支持度只是兼容性的一方面,并不是兼容性问题的全部。

各家的“多核”

GPU硬件的部分基本说完了,这里总结一个表格,同时给出了GPU厂商官方定义的一个“核”的内容,谁的核里料多,谁比较不厚道,应该也是一目了然了吧。面对各种“16核”“8管线”的宣传,大家也应该能比较清楚的辨别了吧。

跑分跟实际表现不一样?优化很重要!

最后,规格只是GPU的一个方面,实际表现跟架构也有很大的关系。更进一步的,就算是Benchmark中跑分差不多的GPU,在不同的游戏中,实际表现也会有差别。

首先,Benchmark程序,大部分都是公平的,所以本质上,Benchmark都是“零优化”程序,公平起见,他们的纹理会用RGBA的PNG,TGA,或者ETC1纹理,不会用到各个GPU自家的格式。

但是游戏不一样,游戏可以做相应的优化。例如PVR的GPU,可以用4bpp甚至2bpp的PVRTC纹理,相比于未压缩的贴图就可以节省8倍甚至16倍的带宽。而没有被优化到的情况下,可能只能跟着Mali用不支持alpha通道的ETC1,做2次贴图,浪费带宽。部分厂商甚至在通用数据包里放了一些未压缩贴图,那差距就更大了。同款游戏,跑分接近的GPU,iOS上的特效更好,流畅度更佳,就有优化的原因。

其次,Benchmark在一定程度上都是相对超前的。大部分GPU跑Benchmark的帧率,都不会到流畅的级别(要是满帧了还怎么测出区别)。早期的Benchmark可能更加侧重贴图和像素部分。新一代的Benchmark则提升了场景复杂度,对多边形和Shader计算的压力进一步增大,例如GLBenchmark 从2.1到2.5的提升。因此,一些三角形生成能力和原生Shader计算能力高的GPU,比如Adreno 220/225,得分提升就会比较明显。而Mali-400则在2.5中遇到三角形生成的瓶颈,得分表现不如之前。

而游戏是给人玩的,终端厂商或是SOC厂商可以跟游戏厂商合作,针对GPU的特点进行相应的优化。不同GPU侧重很不一样,比如Mali-400,三角形很弱,像素部分,填充率强。高通Adreno 2xx,Vivante的GPU,多边形很强,Shader计算强,但填充率较弱。如果场景对Mali优化,游戏商可以减少画面中多边形的量,用贴图和像素部分实现更多的特效。这样对Adreno 2xx系列不利。如果对Adreno优化,则可以增加场景复杂度,用更多的三角形进行更精细的建模,但这样对Mali则不利。这只是一方面,在一些细节上,还可以进行更深层次的优化,各家的GPU也都会提供相应的工具。

最后,GPU的跑分在一定程度上能反映GPU的实际性能,但最终在游戏中的表现还是很看厂商优化的。所以也不要一味的盯着跑分,多问问玩过的朋友,多看看实测,会更有帮助。