Adreno GPU Architecture
0 前言
Adreno GPU为无缝配合骁龙CPU和DSP而设计,帮助支持处理密集型GPGPU(通用GPU)计算任务[18]。和其它移动GPU一样,受限于芯片的面积、功耗以及成本等因素,Adreno GPU只能牺牲部分性能和带宽来求得性价比和电池续航力的平衡[7]。移动GPU的劣势主要表现在理论性能和带宽[7],因此其构架和PC GPU有所不同。
1 GPU构架
目前在GPU领域主要有IMR、TBR及TBDR三种主流架构[7]。
1.1 IMR
IMR(Immediate Mode Rendering),提交的每个渲染命令都会立即开始执行,并且该渲染命令会在整条流水线中执行完毕后才开始执行下一个渲染命令[7]。
优点:
- 简单直接,在一帧里面执行FBO操作时,不会因为需要清空缓冲的渲染指令而影响性能;
- 不需要片上高速缓存来保存中间结果;
- 不需要缓存Triangle List;
缺点:
- 渲染过程存在浪费带宽的情况;
- 渲染命令在执行需要随时读写frame buffer,depth buffer和stencil buffer,这带来大量的内存带宽消耗,在移动平台上面访问片外内存是最消耗电量和最耗时的操作。
由于上述原因,IMR模式不适用于移动GPU,但在PC GPU领域一统江湖[7]。
1.2 TBR
TBR(Tile Based Rendering)它将需要渲染的画面分成一个个的矩形区块(tile),tile一般是4x4或者8x4的矩形块。 模型的顶点经过Vertex Shader运算以后会组装成一个个的triangle,这些triangle会被缓存在一个triangle cache里面。 如果某个triangle需要在某个tile里面绘制,那么就会在该tile的triangle list中存一个索引。一帧里面所有的渲染命令都经执行完Vertex Shader生成triangle以后,每个tile就会拥有一个triangle list,这list就包含了需要在该tile内部绘制的所有triangle。 然后GPU再基于triangle list执行每个tile的raster和Per-fragment operation[7]。
优点:
- 执行raster和Per-fragment operation时不需要反复的访问frame buffer,depth buffer,stencil buffer。 这是因为GPU可以把整个tile的frame buffer/depth buffer/stencil buffer保存在一个片上的高速缓存中,这样GPU就直接访问tile,而不需要访问外部内存。 这大大减少了内存的带宽消耗,也意味着能耗的降低。
缺点:
- 需要保存Vertex Shader执行后的结果以及每个tile的triangle list。 这意味着如果场景里面有很多的顶点,那么片上缓存就不可能存下这么多顶点信息和triangle list,就不得不依靠外部内存来存储,就会拥有额外的带宽消耗。
- 如果在一帧里面有两遍及其以上的渲染,那么就需要使用Frame buffer object来缓存中间结果,这对TBR又是一大性能损耗。
由于上述原因,在桌面GPU领域TBR没有任何优势,因此其完全退出桌面GPU市场。 但是在移动GPU市场它更能适应性能/带宽/能耗三者的平衡,因此得到广泛应用[7]。例如Adreno GPU在渲染游戏画面时,将画面分割为一个个小块,逐一进行渲染,而不是像传统地对画面整体做渲染,最大限度地减少不必要的主机内存数据流量以降低功耗[4]。
当游戏的Draw Call过多时,肯定会让功耗增大,而这时芯片的温控机制会开始起作用,限制其性能的发挥,这就会出现我们常看到的卡顿、Crash等现象。Tiled渲染可以避免这种情况[4]。
1.3 TBDR
TBDR(Tile Based Deferred Rendering)算是TBR的近亲,它跟TBR原理相似,但是通过HSR(Hidden Surface Removal,隐藏面消除)操作,在执行Pixel Shader之前进一步减少了不需要渲染的fragment,降低了带宽需求。在执行Pixel Shader之前,对Raster生成的每个像素都做depth test的比较,剔除被遮挡的像素,这就是HSR的原理。 理论上经过HSR剔除以后,TBDR每帧需要渲染的像素上限就是屏幕像素的数量(没有考虑alpha blend的情况下)。 而传统的TBR在执行复杂一点的游戏时可能需要渲染6倍于屏幕的像素。PowerVR GPU采用就是该构架[7]。
2 Adreno GPU Architecture
Adreno GPU同时支持上述IMR和TBR两种模式,并且可以根据画面的复杂度,在两者之间动态切换,这就是Flex Render技术[4]。当然,有限的帧缓冲区带宽和更低的功耗要求,使得TBR成为Adreno GPU更为有效的方式。在Adreno GPU内部有一个独立的快速缓存叫GMEM[4],例如Adreno 630 GMEM大小为1MB。Adreno GPU TBR实现细节如下所示:
每个图像都会被分割为一个个小的bin(高通内部将这些被分割成一个个方块的图像称为bin)。bin的大小由GMEM的大小除以渲染目标的格式(包括深度缓存的格式)和大小来决定。软件会为每个bin创建一个三角形“可见性数据流”。渲染过程会利用可见性数据流来绘制可见的像素点。每个bin的所有像素都被画到GMEM中,GPU会降GMEM中混合好的像素,以一个整体的形式写回到系统内存的帧缓冲区中,这叫做一次“Resolve”[4]:
3 Game optimization
篇幅所限,详见《Adreno GPU Game Optimization》。
参考资料
[5]GPU渲染简介
[8]Android性能优化典范——GPU渲染(Profile GPU Rendering)
[10]各种移动GPU压缩纹理的使用方法
[11]GPU图形流水线
[12]安卓手机GPU OpenCL总结
[13]Unity3D - 图形性能优化
[14]关于GPU的几点建议
[16]GPU性能调试技巧
[18]Adreno -- 百度百科
[19]Adreno™ Graphics Processing Units
[20]GPU参数解释