4.7 性能:CPU 瓶颈 vs GPU 瓶颈 本节摘要:WebGL 掉帧时先分端。CPU 瓶颈表现为主线程长任务:过多 draw、每帧上传、编译、同步读回、场景图遍历。GPU 瓶颈表现为填充率、overdraw、重 FS、大纹理带宽、阴影 pass。优化必须对着那一端:合批减的是 CPU 提交;降分辨率与砍透明减的是 GPU 片元。把两边的药交叉吃,会出现“合批了更慢”或“降画质帧率不变”。本节用对照表收束全文,并把典型案例写成误诊对照,而不是外链作品集。
本节摘要:WebGL 掉帧时先分端。CPU 瓶颈表现为主线程长任务:过多 draw、每帧上传、编译、同步读回、场景图遍历。GPU 瓶颈表现为填充率、overdraw、重 FS、大纹理带宽、阴影 pass。优化必须对着那一端:合批减的是 CPU 提交;降分辨率与砍透明减的是 GPU 片元。把两边的药交叉吃,会出现“合批了更慢”或“降画质帧率不变”。本节用对照表收束全文,并把典型案例写成误诊对照,而不是外链作品集。
阅读完本节,你应当能够:
用户只说卡。你要问是操作也卡(主线程阻塞输入),还是画面顿、输入还跟手(GPU 或呈现)。readPixels、大数组排序、JSON 解析会堵输入。复杂 Bloom 加 4K 屏会顿画面。工具:浏览器性能记录、可选的扩展计时。没有记录就改着色器,属于猜。
全文的四组对照在这里合成诊断:版本决定你有没有实例化与 MRT 这些减税工具;可编程让 FS 可以贵到爆;CPU 准备过重时 GPU 空等;引擎合批帮 CPU,自定义材质写炸则帮倒忙。
帧时间 ≈ CPU 准备 + 等待GPU + GPU执行 + 合成 优化只砍其中最大项
| CPU 税 | 症状 | 药 | 错药 |
|---|---|---|---|
| draw 过多 | 物体一多就卡,GPU 利用率不高 | 合批、实例化 | 简化 FS |
| 每帧 bufferData | 动画卡、GC | STATIC + 蒙皮或公式 | 再加一张 4K 贴图 |
| 每帧编译 | 偶发卡一下 | 预热 program | 换过滤模式 |
| readPixels 同步 | 整帧尖刺 | 留 GPU 或小 FBO 偶发读 | 开 MSAA |
| getUniformLocation 热路径 | 中等物体数就卡 | 缓存位置 | 减灯光视觉质量 |
| 场景图无剔除 | CPU 遍历全世界 | 视锥剔除 | 阴影分辨率加倍 |
| GPU 税 | 症状 | 药 | 错药 |
|---|---|---|---|
| overdraw 透明 | 填充率满 | 减层、预乘、从前向后不透明 | 再合批更多透明 |
| 重 FS / PBR 全槽 | 大屏掉帧 | 减槽、移动档材质 | 微减 draw 数 |
| 无 mip 大图 | 远景闪且带宽 | 建 mip、缩源图 | 加各向异性硬撑 |
| 阴影高分辨率多 cascade | pass 时间长 | 降尺寸、减投射者 | 关垂直同步当优化 |
| 画布 backing store 过大 | 手机发烫 | 限制 drawingBuffer | 继续提高 CSS 尺寸 |
| discard 破坏早深度 | 树叶很贵 | 几何更贴、少 discard | 关深度 |

案例 A:产品查看器转模型掉帧。误诊“显卡不行”,加了更贵的环境反射。真因常是 canvas 按设备像素比拉到 3x,FS PBR 全槽。药:cap 像素比、移动档减槽。这是 GPU。若模型零件上千且每个 Mesh 一次 draw,则先合批,那是 CPU。同一产品两种病,不能只记“查看器要优化阴影”。
案例 B:数据大屏折线。误诊简化着色。真因每帧从业务数组 new Float32Array 上传。药:环状缓冲 SubData,或点数量降采样。GPU 几乎闲。
案例 C:粒子节日页。加法混合全屏 overdraw,GPU 死。合批粒子到一次 draw 后 CPU 好了,画面更烫,因为更密的透明。药:限粒子数、降分辨率离屏再上屏、用预乘加法少采样。合批必要但不充分。
案例 D:从 WebGL1 迁 2.0 期望加速。若仍每帧 vertexAttribPointer、无 VAO、无实例化,合同换了习惯没换,帧时间几乎不动。2.0 不是性能开关,第 1.1 节说过。
引擎统计面板给出的 draw call、三角形、纹理内存要对照两端:draw call 高先看 CPU;三角形高且都在屏上才看 GPU;纹理内存高两边都可能(上传卡 CPU,采样卡 GPU)。不要只盯三角形数一个指标。
⚠️ 常见坑:在 CPU 瓶颈上降阴影贴图尺寸,数字好看、用户无感;在 GPU 瓶颈上做对象池,内存整齐、填充率照旧。记录前后帧时间,且分端。
💡 关键直觉:优化是减法。先减错误的工作(每帧上传静态网、全屏透明),再减正确但过贵的工作(PBR 槽、cascade)。加复杂缓存是最后一步。
电量与发热是移动端的第三张账单,常跟 GPU 填充绑定。桌面 60 帧不等于手机可接受。锁 30 帧加低 drawingBuffer,有时比“优化着色器 10%”更像产品。对照要写进档位:高档桌面、中档手机、低档关后处理。档位是效果路线表的运行时版。
没有。清单会过期,分端问题不会。你会遇到新的引擎、新的扩展、将来的 WebGPU,问句仍是:数据现在停在哪一端、合同是哪一份、变化粒度是什么。本文集反复练的是这三问。技巧条目可以丢,三问留下。
把效果路线收成三档。低档:WebGL1 或 2 均可,无阴影贴图、无后处理、半球光、POT 贴图、像素比 1。中档:平面影或 512 贴图、一层模糊、方向光逐片元、像素比 1.5。高档:级联或 1024 贴图、PBR 槽、IBL、像素比 2 cap。启动时按包等级与 GPU 时间预算选档,允许用户手动升。档位是 4.1 到 4.6 的运行时开关,不是另写三套引擎。
测量纪律:改动一次只动一个变量;记录 CPU 与 GPU 时间、draw 数、三角形、纹理内存;真机再测一次。开发机上合批的收益会被过强 GPU 藏住。停止条件:帧时间稳定在预算内,且下一刀要砍的是产品不接受的外观。没有停止条件,优化会吃掉材质。预算数字写进项目说明,例如手机 22 毫秒、桌面 16 毫秒。超了才开刀。
呈现与 vsync:浏览器合成不在你的 draw 里。CSS 滤镜、半透明 DOM 叠在 canvas 上,会让合成变贵,看起来像 WebGL 慢。对照方法:全屏 canvas 无 DOM 叠层测一次。若这时满帧,优化 DOM 而不是 FS。两端之外还有第三端:浏览器合成。本文集主讲 GL 两端,但诊断时不要忘了页面。
最后回到四组对照。版本给不给你实例化与 MRT;管线决定贵的公式在着色器;CPU 准备是否在搬砖;封装是否藏了多余 draw。优化会变成选择题而不是祈祷。这就是对比驱动贯穿到收口的原因:不问“还有什么技巧”,问“现在最大的账单在哪一格”。
合批顺序建议:先静态不透明按 program 排;再处理实例化同类;最后才动透明。透明合批收益小风险大。每一步测分端时间。回归:加新效果必须复测档位机。Bloom 能把中档打回 GPU 瓶颈。把性能测试写成清单挂在第 4.7 节旁边:draw 数、像素比、阴影尺寸、PBR 槽数。清单比灵感可靠。优化结束后删调试全屏四边形与 getError 循环,避免调试税留在生产。
透明合批增加了重叠填充。CPU 好了 GPU 死了。分端记录会显示 GPU 升。药是减层或降分辨率,不是继续合。合批只治 draw 税。
瓶颈不在阴影。可能在 drawingBuffer 或 PBR 槽或 DOM 合成。关一项测一项。不变就不是它。同时关五件无法归因。纪律比直觉重要。
CSS 滤镜、半透明叠层、大 DOM。全屏只留 canvas 测。满帧则治页面。第三端是合成。优化 GL 救不了滤镜。对照要包含这一端,否则 4.7 会误诊。
固定三台档位机。每次效果合入在三台测 CPU GPU 时间、draw、像素比、槽数。超预算打回。改动一次一事。调试 getError 循环禁止进主分支。DOM 叠层测试列入清单。停止条件写进项目说明。优化任务必须标明打的是 CPU 还是 GPU。不标明不接。回归用同一场景同一相机。没有固定场景的优化数字不可比。数字不可比就会变成感觉。感觉正是本教程反对的东西。对照要有尺子,尺子就是档位机加分端时间。
优化任务模板强制填:打 CPU 还是 GPU、预期指标、档位机编号、停止条件。不填不排期。合批更烫的案例写进团队 wiki 式备忘,防止重复交叉吃药。drawingBuffer cap 作为低档默认,而不是事后急救。DOM 叠层测试每月做一次,避免运营加滤镜把合成打爆还怪 WebGL。固定场景固定相机的录屏当回归基线。没有基线的数字会打架。打架时回到两端尺子:主线程长还是 GPU 长。尺子是第 2.1 节给全书的礼物,本章只是把它用到收口。收口之后若还想加技巧,先加档位,再加技巧。没有档位的技巧是库存,不是产品。
每次优化合入在三台档位机留下前后数字。没有数字的“感觉快了”不准合。感觉会被开发机独显骗。骗过之后手机发烫。发烫先看 drawingBuffer 与透明层数,这是 GPU。再看 draw 数,这是 CPU。两行数字决定下一刀。刀要停,停在预算内。预算写在说明里,说明比聊天记录硬。
现场对照时只改一个变量。同时改版本、封装、通道,归因会消失。消失之后只能靠感觉,感觉正是本书要拆掉的东西。把改动写成一条,测完再写下一条。一条一条,四组对照才用得上。用不上的对照表只是装饰。装饰填不满格子,格子空着就不要标完工。优化这一格改完,三台档位机留数字,不要用开发机感觉合入。数字要分 CPU 与 GPU 两行。少一行就还会交叉吃药。交叉吃药会砍外观却留卡顿,卡顿再回来时已经没有可砍的槽。先分端,再动刀,刀停在预算内。预算写进说明,说明比感觉硬。感觉来自开发机独显,独显不会替渠道里的手机付钱。手机预算用 22 毫秒,桌面用 16 毫秒,超了才开刀。开刀前先写打的是 CPU 还是 GPU,不写就不排期。这是本章也是全书的收口纪律。纪律让对照表从装饰变回尺子。尺子就是分端时间,不是技巧清单。清单会过期,分端问题不会过期。留住问题。
读到这里,四组对照应当能叠在同一张诊断表上。遇到新效果,先选路,再跟数据走,最后才谈微优化。