移动端 TBR 架构
移动端 GPU 架构 - TBR 与 TBDR 详解
移动 GPU 与桌面 GPU 是两种架构哲学。本文深入基于瓦片的渲染(TBR/TBDR),解释它为何是移动端性能的地基。
引言:移动 GPU 的核心约束是带宽与功耗
移动 SoC 的 GPU 与 CPU 共享同一块系统内存,内存带宽远小于桌面独显,且访问外部内存极其耗电(发热、降频的主因)。所以移动 GPU 的设计目标是:尽量少访问外部内存。TBR/TBDR 正是为此而生。
一、两种架构:IMR vs TBR
| 桌面 IMR(即时模式渲染) | 移动 TBR(基于瓦片的渲染) | |
|---|---|---|
| 处理单位 | 整个 framebuffer | 小瓦片(Tile),如 16×16 / 32×32 |
| 帧缓冲位置 | 片外显存(VRAM) | 渲染时在片上 SRAM(Tile Buffer) |
| 每像素读写 | 走外部总线 | 在片上完成 |
| 带宽压力 | 大 | 小(只在最后写出 1× 结果) |
| 代表 | 桌面 NVIDIA/AMD | Mali、Adreno、PowerVR、Apple |
IMR 逐三角形直接写显存里的帧缓冲/深度缓冲,每次读写都走外部总线。TBR 则把屏幕切成小瓦片,每个瓦片的所有渲染都在片上高速 SRAM 中完成,最后只把结果写回一次。
二、TBR 的两阶段渲染流程
TBR 把一帧分成两个 Pass:
- ① Binning:先跑完所有几何,算出每个瓦片被哪些三角形覆盖,生成图元列表(写入外部的 Parameter Buffer / FrameData)。
- ② Rendering:逐瓦片处理 —— 该瓦片的光栅化、着色、深度/模板测试全在片上 Tile Buffer 完成,结束后只把最终颜色写回系统内存。
代价:几何要处理两遍相关数据(Binning 阶段的图元列表有外部写入开销);几何量极大时 Parameter Buffer 带宽也需注意。
三、片上内存与带宽收益
TBR 的核心收益是大幅削减外部内存流量:

- IMR:颜色/深度每像素都读写外部显存;开 MSAA 更是成倍。
- TBR:颜色/深度在片上反复读写(近乎零外部带宽),只在瓦片完成时写出 1× 最终颜色;深度/模板通常无需写回外部。
这带来两个重要推论:
- MSAA 近乎免费:多采样点存在片上 Tile Buffer,Resolve 也在片上,只写出 1×。
- 深度/模板可不写回:若后续不需要,声明为 不 store(DONT_CARE)/ memoryless,省下大量带宽。
四、TBDR:基于瓦片的延迟渲染
部分移动 GPU(PowerVR、Apple)是 TBDR(Tile-Based Deferred Rendering),在 TBR 基础上多了隐面消除(HSR, Hidden Surface Removal):
- 在瓦片内先解算可见性(哪些片元最终可见),再对可见片元着色 → 从根本上消除不透明物体的 Overdraw。
- 效果类似硬件级的完美 Early-Z,但更彻底。
对比(大致):
| 厂商 | 架构 | 特点 |
|---|---|---|
| Arm Mali | TBR | 部分型号有 Forward Pixel Kill 等剔除 |
| Qualcomm Adreno | TBR(含 FlexRender,可切 IMR-like) | 灵活,可按情况选模式 |
| Imagination PowerVR | TBDR | HSR 隐面消除,Overdraw 抑制强 |
| Apple GPU | TBDR | 源自 PowerVR 谱系,片上内存大 |
五、对移动端优化的启示
理解 TBR/TBDR 后,很多移动端"玄学优化"就有了根据:
| 做法 | 原因 |
|---|---|
| 正确设置 RT 的 Load/Store Action | 不需要的历史内容用 Clear/DontCare load、不需要的结果用 DontCare store,避免瓦片进出时的无谓外部读写 |
| 用 memoryless / transient 附件 | 深度、MSAA、临时 RT 只存在于片上,不分配系统内存 |
| 避免帧中途频繁切换 RT | 每次切 RT 会刷新(flush)瓦片到内存,打断片上流水,带宽暴增 |
| 避免在 Pass 中途读回颜色/深度 | 强制解析瓦片到内存,破坏 TBR 优势(很多后处理写法在移动端很贵) |
| MSAA 优先于后处理 AA | 片上 MSAA 近乎免费,而全屏后处理 AA 有带宽成本 |
| 仍要控制 Overdraw | TBDR 能消不透明 Overdraw,但半透明混合仍会重复着色 |
| 纹理压缩(ASTC) | 直接降采样带宽。 |
六、Framebuffer Fetch:同像素可读、跨像素需解析
上一节说"避免在 Pass 中途读回颜色/深度",但这有个重要辨析 —— 要区分读的是当前像素还是其它像素:
| 读什么 | 能否在 Pass 中途读 | 代价 | 手段 |
|---|---|---|---|
| 当前正在写的那个像素的颜色/深度 | 能 | 廉价(数据就在片上瓦片) | Framebuffer Fetch / Input Attachment |
| RT 的其它像素(邻域/整张采样) | 不能(需先解析回内存) | 昂贵(flush + 回读) | 拆成独立 Pass / ping-pong 双缓冲 |
当前像素:Framebuffer Fetch(廉价,且被鼓励)
当前像素就在片上 Tile Buffer 里,读它几乎免费。这就是可编程混合(programmable blending) 的基础:
- Vulkan:Subpass Input Attachment(读同一 render pass 前序 subpass 在当前像素产出的值)。
- Metal:片段着色器的
[[color(n)]]输入 / programmable blending。 - OpenGL ES:
GL_EXT_shader_framebuffer_fetch。 - Unity:URP 支持 Framebuffer Fetch,可在 RenderGraph 里用 Input Attachment 合并 Pass、让中间结果留在片上。
跨像素:必须先解析(这才是要避免的回读)
TBR 上只有当前瓦片在片上,RT 的其它像素可能还没算、也不在内存。想任意采样,就得结束 Pass → 解析瓦片写回内存 → 当纹理绑定 → 新 Pass 采样,这就是昂贵的 flush + 回读。需要邻域采样(模糊/折射/扭曲)应拆 Pass 或用 ping-pong。
它是移动端延迟渲染省带宽的关键
移动端延迟渲染正是靠 Framebuffer Fetch/Input Attachment:在同一 render pass 内片上读 G-Buffer 做光照,避免把肥厚 G-Buffer 写回系统内存再读回 —— 直接缓解了"延迟渲染在移动端带宽爆炸"的问题。这也是为什么"延迟渲染在移动端要谨慎,但用对 Framebuffer Fetch 就可行"。
七、注意点
- 几何不是免费的:TBR 的 Binning 要处理全部几何并写图元列表,几何量过大会让 Parameter Buffer 带宽成为新瓶颈 —— 移动端仍需 LOD、剔除。
- 真机测量:TBR 行为、带宽、发热只有在真机 + 平台工具(Arm Streamline、Android GPU Inspector、Xcode)上才准,编辑器/桌面测不出。
- 延迟渲染在移动端要谨慎:大 G-Buffer 与 TBR 的片上思路冲突,带宽代价高。
附:核心概念速查
| 概念 | 说明 |
|---|---|
| IMR | 即时模式渲染,桌面架构,直接读写显存帧缓冲 |
| TBR | 基于瓦片渲染,片上 Tile Buffer,两阶段(Binning + Rendering) |
| TBDR | TBR + 隐面消除(HSR),消除不透明 Overdraw(PowerVR/Apple) |
| Tile Buffer | 片上高速 SRAM,一个瓦片的颜色/深度驻留于此 |
| Binning Pass | 把图元按瓦片归类,生成每瓦片图元列表 |
| memoryless / DontCare | 声明附件只在片上、不写回,省带宽 |
| HSR | 隐面消除,着色前解算可见性 |
总结
TBR/TBDR 是移动 GPU 为应对带宽和功耗约束而采用的架构设计,核心思路是将屏幕划分为小瓦片,在片上 SRAM 中完成每个瓦片的所有渲染操作,最终只写回一次结果,从而大幅降低外部内存访问。TBDR 在此基础上通过隐面消除进一步消除不透明物体的 Overdraw。理解这些机制能为移动端渲染优化提供明确的指导:合理设置 Load/Store Action、使用 memoryless 附件、避免频繁 RT 切换和 Pass 中回读、优先使用片上 MSAA 和 Framebuffer Fetch,并在几何处理上保持克制。移动端性能优化应始终以减少外部内存访问为根本原则。
