第三章 GPU子系统设计:移动GPU架构的流水线设计
移动GPU这块,说实话,跟桌面GPU完全是两个物种。我早年刚转做手机SoC时,还拿桌面那套思路去套,结果被性能数据狠狠打了脸。移动端功耗墙摆在那,你堆再多的ALU也没用,电池扛不住。
今天咱们聊聊三大主流移动GPU——Mali、Adreno、Apple GPU的流水线设计,以及两种核心渲染模式的对比。嗯,这部分内容,我个人觉得是理解移动GPU性能调优的基石。
3.1 移动GPU的三大流派
先看一张整体架构对比图,我习惯用这种图来建立全局认知:
3.2 Tile-Based渲染 vs Immediate Mode渲染
先讲清楚这两种模式。你想想看,一个游戏画面是1920x1080的,GPU要处理将近200万个像素。如果每个像素都直接写回显存,带宽压力有多大?
Immediate Mode渲染(IMR):这是桌面GPU的老路子。几何数据进来,直接画,画完就写帧缓冲。优点是延迟低,缺点是带宽消耗大。我早期在PC显卡上做调优时,IMR的显存带宽经常是瓶颈。
Tile-Based渲染(TBR):移动GPU的主流方案。把屏幕切成小块(tile),比如16x16或32x32像素。每个tile在片上SRAM里完成所有计算,再一次性写回显存。说白了,就是用面积换带宽。
核心差异总结:
- IMR:像素直接写帧缓冲,带宽消耗大,适合高功耗场景
- TBR:分块处理,片上缓存,带宽节省60%-80%
- 移动端几乎全部采用TBR或其变体
3.3 Mali GPU的流水线设计
Mali是ARM的亲儿子,也是市面上最广泛的移动GPU。我调过好几款Mali芯片,它的流水线设计有几个关键点:
- 几何处理阶段:顶点着色器处理顶点数据,生成图元
- 分块阶段(Tiling):把图元分配到各个tile中,生成tile列表
- 光栅化阶段:对每个tile内的图元进行光栅化
- 片元处理阶段:执行片元着色器,处理纹理、光照等
Mali的tile大小固定为16x16像素。为什么是16x16?我猜是平衡了片上SRAM大小和分块开销。太小了分块管理成本高,太大了片上缓存装不下。
调优小技巧:
Mali对overdraw(重复绘制)非常敏感。因为每个tile内的像素都要经过片元着色器,如果同一个像素被画了多次,性能会直线下降。我曾经在一个项目中,把overdraw从3.5降到1.8,帧率直接翻倍。
3.4 Adreno GPU的流水线设计
Adreno是高通的GPU,从骁龙800系列开始就一直是性能标杆。它的流水线跟Mali类似,但有几个独特之处:
- 灵活分块:Adreno的tile大小可以动态调整,从16x16到32x32不等
- 灵活着色器调度:支持wavefront(类似NVIDIA的warp)调度,效率更高
- 高填充率:Adreno的ROP单元数量通常比同代Mali多
我记得有一次调骁龙865的GPU,发现它的tile大小在复杂场景下会自动切换到32x32。为什么?因为大tile可以减少分块开销,但需要更多片上缓存。Adreno的缓存管理确实有两把刷子。
避坑指南:
我曾经在Adreno上遇到一个诡异问题:某个场景帧率突然掉到30fps。查了半天,发现是纹理格式不对。Adreno对某些压缩纹理格式(如ASTC)支持很好,但如果你用了ETC2,性能会差很多。嗯,纹理格式的选择,直接影响带宽和性能。
3.5 Apple GPU的流水线设计
Apple GPU是苹果自研的,从A11开始逐步替换PowerVR。它的流水线设计最激进:
- Tile-Based延迟渲染(TBDR):在TBR基础上,增加了延迟着色阶段
- 自定义指令集:Apple GPU有自己的指令集,不是标准的OpenCL/SPIR-V
- 统一内存架构:CPU和GPU共享内存,不需要显存拷贝
TBDR的核心思想是:先做几何处理,生成所有片元数据,再统一进行着色计算。这样做的好处是,可以避免重复计算。比如多个三角形覆盖同一个像素,TBDR只计算一次。
我测试过A15 GPU的TBDR性能,在复杂光照场景下,比同功耗的Adreno快30%左右。当然,Apple GPU的封闭生态也是优势,驱动和硬件可以深度耦合优化。
3.6 三种架构的对比表格
| 特性 | Mali | Adreno | Apple GPU |
|---|---|---|---|
| 渲染模式 | TBR | TBR | TBDR |
| Tile大小 | 16x16固定 | 16x16~32x32动态 | 32x32固定 |
| 着色器架构 | 统一着色器 | 统一着色器 | 统一着色器 |
| 带宽效率 | 中等 | 高 | 极高 |
| 典型功耗 | 2-5W | 3-8W | 2-6W |
| 生态 | 开放(OpenGL/Vulkan) | 开放(OpenGL/Vulkan) | 封闭(Metal) |
3.7 性能调优的核心思路
不管哪种架构,移动GPU调优有几个共通原则:
- 减少overdraw:用Early-Z测试,提前丢弃被遮挡的片元
- 优化纹理带宽:使用压缩纹理格式(ASTC、ETC2)
- 减少draw call:合并小物体,减少CPU-GPU通信开销
- 利用tile缓存:尽量在同一个tile内完成所有计算
我个人最常用的调优流程:
- 先用profiler抓性能瓶颈(是几何瓶颈还是片元瓶颈?)
- 如果是片元瓶颈,检查overdraw和纹理带宽
- 如果是几何瓶颈,检查draw call数量和顶点数
- 针对具体架构做微调(比如Mali的tile大小固定,Adreno的纹理格式偏好)
嗯,移动GPU调优是个细活。没有银弹,只有对架构的深入理解。我见过太多团队,拿着桌面GPU的优化经验直接套到移动端,结果性能反而更差。你想想看,桌面GPU的带宽是移动端的10倍以上,优化思路能一样吗?
好了,这一章就聊到这。下一章咱们深入Vulkan和OpenGL ES的驱动层优化,看看怎么在API层面榨干GPU性能。
公众号:蓝海资料掘金营,微信deep3321