shader 成本模型:ALU、采样、带宽与 overdraw

Unity 知识 · Shader 区域 · 性能与调试 · 第 1 篇 更新于 2026-10-15

「这个 shader 贵不贵」不该靠猜。这篇给一个可以先算后测的成本模型:一个 Draw 的成本 = 每次绘制开销 + 顶点成本 + 片元成本 × 有效像素数,每一项都有明确的量纲和平台前提。

先分清 CPU 瓶颈还是 GPU 瓶颈

  • CPU 侧:Draw Call 提交、状态切换、参数上传。SRP Batcher 削的是这块(见 /notes/unity/structure-4/),GPU Instancing 削的是相同网格的提交次数。
  • GPU 侧:本模型讨论的 shader 成本。Profiler 的 Render 模块 + Frame Debugger 的 Draw 数先定位是哪侧(见 /notes/unity/performance-2/)。

片元成本 = 执行次数 × 每次的代价

执行次数由覆盖像素数与 overdraw 决定,这里平台差异是决定性的:

桌面(IMR)移动(TBDR,如 Mali/PowerVR/Apple)
架构按画序直接写帧缓冲先把三角形分块进 tile memory,块内做完再写出
overdraw每一层都付全价片元成本不透明且 ZWrite On、不读颜色、无 discard 时,被挡住的片元根本不执行(HSR)
推论减少全屏大透明、砍多余 Pass不透明 overdraw 便宜;透明/混合/discard 破坏 HSR,才是移动端杀手

所以「全屏大透明特效」在桌面尚可、在移动端是头号成本——同一个 shader 两平台的账完全不同,任何优化结论都要带平台前提。

每次的代价按贵到便宜排:

  1. 带宽(纹理采样):移动端头号瓶颈。成本 = 读的字节数:大贴图、各向异性过滤、mip 选错(放大采样)都在读更多字节。缓解:合理分辨率与压缩格式(ASTC)、图集、避免无谓的高精度格式。
  2. 依赖采样链:第二次采样的 UV 来自第一次采样结果,流水线停顿(见 /notes/unity/principles-4/)。
  3. ALU:现代 GPU 吞吐极高,PBR 全套公式(见 /notes/unity/lighting-3/)在移动端也通常不是第一瓶颈——但 fp32 在移动 GPU 上常是 fp16 的一半吞吐,精度选择见 /notes/unity/performance-3/。
  4. 插值器与寄存器:超限会 spill 到显存,成本跳变——看编译产物的寄存器数(见 /notes/unity/performance-2/)。

顶点成本

顶点数 × 每次顶点程序代价。常规网格下远小于片元成本;例外:高模角色(数万顶点 × 多 Pass)、顶点动画 + 蒙皮、以及多 Pass 效果把顶点成本乘遍数(倒模描边 = 2 倍几何,见 /notes/unity/effects-3/)。

每次绘制开销

每个 Draw Call 的固定成本(绑定、提交)。变体切换(keyword 改动引发程序切换)、材质参数重传(SRP Batcher 不兼容时)都落在这里(见 /notes/unity/engineering-3/、/notes/unity/engineering-1/)。

改之前的预估清单

  1. Frame Debugger 数 Draw:这个材质画了几遍(Pass 数)?
  2. 估算片元次数:屏幕覆盖面积 × overdraw 层数(透明特效重点数这个)。
  3. Shader Inspector 看变体的指令数/采样数/寄存器数(每平台)。
  4. 按上表判断瓶颈类别,再动手改——改完必须复测(见 /notes/unity/performance-2/)。

移动端优化顺序(经验值)

  1. 砍全屏透明/混合 overdraw(特效面积、粒子叠加)。
  2. 砍带宽:贴图分辨率与格式、采样次数、依赖链。
  3. 砍精度:能 half 不 float(见 /notes/unity/performance-3/)。
  4. 砍 Pass 数与变体数。
  5. 最后才抠 ALU 公式——通常收益最小。

桌面顺序不同:overdraw 排第一(IMR 无 HSR),Draw Call 数在大型场景常先于单 shader 成本爆掉。

自检三问

  • 同一个全屏透明特效,为什么移动端比桌面贵一个量级?
  • discard 在 TBDR 上为什么特别贵?
  • 预估一个描边材质的总成本,要乘哪些系数?