Godot 4 的渲染器选择界面(rendering/renderer/rendering_method)给 Forward+ 配了一个兄弟选项:Mobile。两者代码并排躺在 servers/rendering/renderer_rd/ 下——forward_clustered/render_forward_clustered.cpp 和 forward_mobile/render_forward_mobile.cpp——共享 RD、共享场景剔除、共享 shadow atlas,但 Mobile 少了长长一截特性清单:没有 cluster shading、没有 SDFGI、没有 SSAO/SSIL、没有 volumetric fog,光源上限也从"每 cluster 32"变成全局性的紧约束。这不是功能没做完,是针对移动端 GPU 物理结构的有意识裁剪。这篇用带宽账本解释每一项。
tile-based GPU 的第一性原理
桌面 GPU(immediate-mode)的片元着色器执行单元直接对着主存里的 framebuffer 读写,带宽就是性能。移动端 GPU(Apple、Mali、Adreno、PowerVR)是 tile-based:光栅化前先把屏幕分成小块(tile,常见 16×16 或 32×32),把这块的 depth/color 加载到片上 SRAM(tile memory,容量 KB 到几百 KB 量级),整个 tile 的深度测试和混合都在片上完成,最后一次性写回主存。
这带来两个直接推论:
- 片上驻留是免费午餐:color/depth 在 tile 内存里反复读写几乎不耗带宽,同一块数据在主存里往返一次就是实打实的字节数。100 万像素 32 位 color + 32 位 depth,一帧读一遍写一遍就是 16MB,60fps 就是 1GB/s——这只是"碰一次"的代价。
- 任何迫使中途写回/重读的设计都在烧这顿饭:中途把 framebuffer 当纹理采样(屏幕空间效果)、多渲染目标塞爆 tile 内存、全量屏障把 tile 刷回主存,每条都在把免费的变成付费的。
Mobile 渲染器的特性清单,几乎就是这两条推论的逐项展开。
砍掉 cluster shading:省一个 pass 和一张表
上一篇算过 cluster 的账:GPU 路径每帧要跑 2~3 个 compute dispatch、上传灯参数、主 pass 前插屏障。在桌面 GPU 上这是小头;在 tile-based GPU 上,compute dispatch 之间和 compute→fragment 之间的屏障会打断 tile 流水,且 cluster 数据结构(偏移表+索引池)要在主存和片上之间搬运。Mobile 版换了条路:光源不做空间预分桶,而是逐对象(per-object)光照——绘制一个 mesh 实例时,用一张按对象 ID 索引的小光照列表,着色器只算这张列表上的灯。灯总数被全局上限卡住(4.x 默认每类数十盏量级,具体以 rendering/limits 下的 mobile 相关项为准),超过直接不渲染或按距离裁。
代价写进了限制清单:全局灯数天花板、大范围灯重叠场景效果差。收益是结构性的:主 pass 变成单次前向遍历,没有预计算 pass、没有 cluster 表、没有相关屏障——整条渲染路径就是"阴影 → 主 pass → 后处理"三段,中间无停顿,tile 流水线一路吃完。
砍掉屏幕空间效果:它们全是"重读 framebuffer"
SSAO、SSIL、SSS、volumetric fog、SDFGI 的共同点是把已渲染的 color/depth 当输入再采一遍。在 immediate-mode GPU 上这是多几个全屏 pass 的事;在 tile-based GPU 上,等这个 pass 跑的时候,上一 pass 的 framebuffer 已经写回主存了,采一次就是全分辨率的一次读——SDFGI 还要级联体素 + 探针,带宽开销是数倍于全屏。Mobile 版的选择是把它们整组拿掉,移动端要环境光遮蔽靠烘焙(LightmapGI)或贴花近似,这不是降级,是把移动端付不起的支付手段从清单里划掉。
分辨率与 MSAA 的账
Mobile 默认更低的内部渲染分辨率加 upsampling,少渲染的像素是平方级省带宽。MSAA 在 tile-based GPU 上是特例:多重采样样本驻留 tile 内存,resolve(平均成单样本)发生在写回时——MSAA 4x 的额外成本主要是片元着色次数和片上空间,不是主存带宽,所以 Mobile 保留 MSAA 是划算的,和桌面上的感受正相反。
取舍全景
怎么选
官方文档的建议是桌面选 Forward+,移动端和网页选 Compatibility,Mobile 处在两者之间——这个定位本身就是结论:Mobile 是给吃得消 Vulkan、但硬件是 tile-based 的新设备准备的(近几年的中高端手机、Apple Silicon 跑 macOS 的省电场景)。实测上一个中型 3D 场景,M 系列芯片上 Mobile 比 Forward+ 帧率只高几个百分点,但功耗明显下降,风扇场景(掌机、笔记本离电)差异才是它的主场。
反过来,如果你的目标设备是 Mali 低端或 Web,Mobile 都还不是终点:Compatibility(GLES3/WebGL2)才是,那篇接着讲。还有一个实操提醒:Mobile 与 Forward+ 的 shader 变体不互通,切换渲染方法会触发全量 shader 重编译,CI 上跑两个渲染器要各备一份缓存。
本文基于 Godot 4.x 源码:servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp 与 forward_clustered/render_forward_clustered.cpp 的特性矩阵对照,参数以各版本 rendering/limits 项目设置为准。