Skip to content

Lesson 053|Overdraw 与 Fill Rate:DrawCall 不高为什么仍然会卡? ​

Tags: #Creator2.x #Stage04 #Overdraw #FillRate #GPUDifficulty: ⭐⭐⭐⭐☆


真实问题:一个全屏弹窗只有 6 个 DrawCall,低端机为什么掉到 20 FPS ​

弹窗层依次绘制:

text
游戏背景
→ 全屏模糊截图
→ 黑色半透明 Mask
→ 半透明 Dialog 阴影
→ 粒子亮点
→ UI 内容

屏幕中央像素可能被写五六次。DrawCall 很少,但每次覆盖面积巨大,Fragment Shader 和混合带宽成为瓶颈。

🎯 本课目标 ​

本课回答一个常见性能问题:

DrawCall 已经很低,为什么画面在低端设备上仍然卡?

答案经常在像素阶段:Overdraw、Fill Rate、纹理带宽和 Fragment Shader。


二、Overdraw 是什么 ​

同一个屏幕像素被多次绘制,就是 Overdraw:

text
背景绘制一次
透明面板再绘制
按钮再绘制
文字再绘制
粒子再绘制

最终可能一个像素被处理 5 次甚至更多。

Overdraw 关注的不是“最终有多少屏幕像素”,而是为了得到这些像素,前面发生了多少次片元工作。

假设屏幕中央依次绘制背景、模糊图、黑色遮罩、面板阴影、面板和粒子:

text
最终像素:1 个结果
候选片元与混合:可能 6 次

如果最后的不透明面板完全覆盖下层,前面的部分工作对最终画面没有贡献,但 GPU 可能已经执行完了。


三、Fill Rate 是什么 ​

Fill Rate 可以粗略理解为 GPU 每秒处理和写入像素的能力。它受到:

  • 屏幕分辨率。
  • 覆盖面积。
  • Overdraw 层数。
  • Fragment Shader 复杂度。
  • 纹理采样和带宽。

影响。

高分辨率设备更容易暴露全屏透明和后处理成本。

分辨率增长是面积级的:

text
1280×720  ≈ 92 万像素
1920×1080 ≈ 207 万像素
2560×1440 ≈ 369 万像素

同样六层全屏效果,从 720p 到 1440p,基础覆盖像素约放大四倍。DrawCall 可以完全不变,但每个 Pass 的 Fragment、纹理读取和目标写入都会随面积增长。


四、为什么 2D UI 也会有严重 Overdraw ​

UI 常见结构:

text
全屏背景
→ 半透明遮罩
→ 面板背景
→ 九宫格边框
→ 图标
→ 文字
→ 阴影和特效

每一层都可能覆盖相同区域。视觉上只是一个面板,GPU 看到的是多次片段处理。


五、优化方向 ​

  • 删除完全被覆盖的底层装饰。
  • 缩小透明节点的实际尺寸。
  • 避免大面积透明阴影和模糊。
  • 将静态层合成一张图片。
  • 降低粒子和特效覆盖区域。
  • 简化 Fragment Shader 和采样次数。
  • 在目标设备上测量,不用编辑器主观判断。

六、DrawCall 与 Overdraw 的关系 ​

text
DrawCall:提交多少次
Overdraw:像素被处理多少次

可以出现:

text
DrawCall 少 + Overdraw 高 → GPU 仍然卡
DrawCall 多 + Overdraw 低 → CPU 提交可能卡

优化方向必须先判断瓶颈属于 CPU 还是 GPU。


七、案例:全屏透明遮罩 ​

一个半透明遮罩覆盖整屏:

text
遮罩只占一个 Sprite
但覆盖所有像素

它可能不增加很多 DrawCall,却增加整屏 Fragment 混合。若同时叠加模糊和粒子,GPU 成本会快速增长。

把遮罩 opacity 从 150 降到 50,只改变混合结果,不一定减少覆盖:

text
四边形仍覆盖全屏
→ 片元仍生成
→ Shader 仍运行
→ Blend 仍执行

真正减少像素工作通常需要缩小几何覆盖、减少层数、降低 RenderTarget 分辨率、简化 Shader,或避免提交不可见对象。


八、测量方法 ​

建议记录:

text
目标设备和分辨率
GPU Frame Time
Overdraw 可视化结果
透明层数量
纹理采样次数
修改前后帧时间

只在编辑器里看 FPS 不足以证明优化有效。


九、常见误区 ​

误区一:DrawCall 少就没有 GPU 问题 ​

像素计算和带宽可能是主要瓶颈。

误区二:透明图片面积不重要 ​

面积决定可能产生的 Fragment 数量。

误区三:把所有透明效果都删掉 ​

应先定位贡献最大的层,再平衡视觉和性能。

误区四:Overdraw 颜色图就是最终性能 ​

它是诊断工具,还要结合真实设备和时间数据。



十、深入推导:Overdraw 与 Fill Rate 的数量级 ​

屏幕分辨率 1920×1080,约 207 万像素。若平均每像素绘制 4 次:

text
约 207 万 × 4
= 约 829 万片元覆盖

若每个片元还要多次纹理采样与混合,工作继续增加。实际 GPU 有裁剪、缓存、Early-Z 等机制,公式只用于数量级理解。

Fill Rate 可理解为单位时间能处理/写入的像素量,受:

  • 分辨率;
  • 覆盖次数;
  • Shader 复杂度;
  • 纹理采样;
  • Blend;
  • RenderTarget 格式;
  • GPU 架构和带宽。

十一、Creator 2.4.x 实验:缩分辨率验证像素瓶颈 ​

场景 ​

创建 8 个全屏半透明 Sprite,颜色不同,可逐层启用。保持同 Texture/材质,尽量不让 DrawCall 成为主要变量。

OverdrawProbe.ts ​

ts
const { ccclass, property } = cc._decorator;

@ccclass
export default class OverdrawProbe extends cc.Component {
    @property([cc.Node])
    layers: cc.Node[] = [];

    showCount(count: number) {
        for (let i = 0; i < this.layers.length; i++) {
            this.layers[i].active = i < count;
        }
    }

    setScale(value: number) {
        for (const layer of this.layers) {
            layer.scale = value;
        }
    }
}

对照步骤 ​

  1. 只显示 1 层,记录帧时间。
  2. 显示 4 层、8 层,保持 DrawCall 记录。
  3. 将所有层 scale 从 1 降为 0.5,观察覆盖面积。
  4. 在不同预览分辨率或目标设备分辨率测试。
  5. 用平台 GPU 工具的 Overdraw/Frame Capture(若可用)验证热点。

如果降低分辨率或覆盖面积显著改善,而 DrawCall 变化很小,像素阶段是强证据。

十二、透明大图的“空白”为什么也有成本 ​

一个 1024×1024 粒子贴图只有中间 100×100 发光,其余 Alpha 为 0。四边形仍覆盖完整 1024 区域,透明片元通常仍要采样和执行 Shader。

优化方向:

  • 裁掉纹理透明留白;
  • 缩小粒子 Quad;
  • 降低同时活跃数量;
  • 避免多层全屏半透明;
  • 使用较小 RenderTexture;
  • 对遮挡完全不透明区域利用合适裁剪/深度策略。

Alpha 为 0 通常是采样纹理之后才知道。GPU 可能已经完成 UV 插值和纹理读取,才得到“完全透明”。即使 Shader 使用 discard,也不表示前面的工作全部消失,其效果还依赖平台与 Shader。

更稳定的优化是收紧粒子或 UI Quad 的几何范围,让透明留白从一开始就不生成片元。

十三、真实项目故障:新机流畅、旧机 UI 发热掉帧 ​

现象 ​

DrawCall 只有 12,CPU Frame 也稳定。旧设备 GPU 占用高且发热,几分钟后降频。

根因 ​

首页使用三层全屏动态渐变、实时模糊、透明视频和粒子。高分辨率屏幕把像素量放大,持续 GPU 满载导致热降频。

修复 ​

  • 静态背景合成;
  • 模糊降采样且按需刷新;
  • 视频与粒子在不可见时暂停;
  • 低端档关闭部分层;
  • 限制目标渲染分辨率;
  • 做 10~20 分钟热稳定测试,而非只测启动一分钟。

十四、DrawCall 与 Overdraw 的取舍 ​

把多个层离线合成一张图:

text
DrawCall 下降
Overdraw 下降
纹理内存可能上升
动态性下降
包体可能上升

把大 Atlas 拆小:

text
纹理生命周期更合理
透明留白可能减少
DrawCall 可能上升

优化是多指标决策,不能只守一个数字。

可以用二维表选择优先方向:

现象CPU SubmitGPU 像素优先验证
很多小图、状态分散高风险可能较低合批、Texture、Material
少量全屏多采样 Pass可能较低高风险分辨率、采样、RenderTarget
大量大粒子可能中等高风险活跃数、面积、重叠
大量动态 Label高风险视面积而定排版、字形、刷新频率

同一页面可能同时有两类瓶颈。先解决一个后,另一个才会成为新的最大成本。

十五、故障诊断 ​

DrawCall 低、CPU 低、GPU 高 ​

优先测试分辨率、覆盖面积、Shader、纹理采样和 RenderTexture。

降低 opacity 没改善 ​

Alpha 更低不代表少画片元,覆盖与混合仍发生。应减少层、面积或 Shader 工作。

隐藏看似无关的大背景后改善 ​

检查背景是否有透明区域、复杂材质、超屏尺寸或多 Camera 重复绘制。

十六、练习、推导答案与版本边界 ​

Creator Profiler 不一定提供完整 GPU 分解;应结合 Chrome/平台 GPU 工具、真机与分辨率对照。不同 GPU 的 Fill Rate 和热行为差异很大。

  1. DrawCall 低为何不代表 Fill Rate 低? 一个 DrawCall 可以覆盖全屏并执行复杂多采样 Shader。
  2. opacity 0 是否保证无 Fragment 成本? 不保证。若几何仍提交,Shader 通常仍需运行后才得到 Alpha。
  3. 为什么降半宽高可能大幅改善? 像素数约变为四分之一,全屏 Pass 的采样/写入随之大降。
  4. 如何证明是像素瓶颈? 在逻辑与批次基本不变时降低分辨率/覆盖面积/Shader 复杂度,观察 GPU 帧时间显著变化。

能力验收 ​

你应该能估算分辨率与平均覆盖层数形成的片元数量级,解释透明留白为什么仍可能执行 Shader,并通过分辨率、覆盖面积和 Shader 复杂度三个控制变量证明像素瓶颈。

本课总结 ​

text
Overdraw 衡量像素重复处理。
Fill Rate 受面积、层数、Shader 和带宽影响。
DrawCall 和 Overdraw 是不同维度。
低 DrawCall 不代表低 GPU 成本。

十一、下一课预告 ​

text
Lesson054|阶段复习:一次 UI 修改如何经过 Renderer 到达 GPU?