第三章 GPU子系统设计:移动GPU架构的流水线设计

移动GPU这块,说实话,跟桌面GPU完全是两个物种。我早年刚转做手机SoC时,还拿桌面那套思路去套,结果被性能数据狠狠打了脸。移动端功耗墙摆在那,你堆再多的ALU也没用,电池扛不住。

今天咱们聊聊三大主流移动GPU——Mali、Adreno、Apple GPU的流水线设计,以及两种核心渲染模式的对比。嗯,这部分内容,我个人觉得是理解移动GPU性能调优的基石。

3.1 移动GPU的三大流派

先看一张整体架构对比图,我习惯用这种图来建立全局认知:

移动GPU三大架构对比 Mali (ARM) • Tile-based渲染 • 分块处理(16x16) • 统一着色器架构 • 低带宽消耗 • 适合中低端 流水线特点 几何处理 → 分块 → 光栅化 → 片元处理 代表: G76, G78, G710 Adreno (Qualcomm) • Tile-based渲染 • 灵活分块大小 • 灵活着色器调度 • 高填充率 • 适合中高端 流水线特点 几何处理 → 分块 → 光栅化 → 片元处理 代表: 640, 660, 730 Apple GPU • Tile-based延迟渲染 • 自定义指令集 • 统一内存架构 • 极致能效比 • 高端旗舰 流水线特点 几何处理 → 分块 → 延迟着色 → 合并 代表: A14, A15, A16 GPU 共同点:都采用Tile-based渲染,但实现细节和优化方向不同

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芯片,它的流水线设计有几个关键点:

  1. 几何处理阶段:顶点着色器处理顶点数据,生成图元
  2. 分块阶段(Tiling):把图元分配到各个tile中,生成tile列表
  3. 光栅化阶段:对每个tile内的图元进行光栅化
  4. 片元处理阶段:执行片元着色器,处理纹理、光照等

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。它的流水线设计最激进:

  1. Tile-Based延迟渲染(TBDR):在TBR基础上,增加了延迟着色阶段
  2. 自定义指令集:Apple GPU有自己的指令集,不是标准的OpenCL/SPIR-V
  3. 统一内存架构: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内完成所有计算

我个人最常用的调优流程:

  1. 先用profiler抓性能瓶颈(是几何瓶颈还是片元瓶颈?)
  2. 如果是片元瓶颈,检查overdraw和纹理带宽
  3. 如果是几何瓶颈,检查draw call数量和顶点数
  4. 针对具体架构做微调(比如Mali的tile大小固定,Adreno的纹理格式偏好)

嗯,移动GPU调优是个细活。没有银弹,只有对架构的深入理解。我见过太多团队,拿着桌面GPU的优化经验直接套到移动端,结果性能反而更差。你想想看,桌面GPU的带宽是移动端的10倍以上,优化思路能一样吗?

好了,这一章就聊到这。下一章咱们深入Vulkan和OpenGL ES的驱动层优化,看看怎么在API层面榨干GPU性能。


公众号:蓝海资料掘金营,微信deep3321