UPL6-1——DrawCall
UPL6-1——DrawCall
DrawCall
DrawCall(绘制调用)在 Unity 中有时也会被称为 SetPass Call(设置参数调用),本质上是 CPU 向 GPU 发送一条绘制指令
告诉 GPU 要画什么、怎么画、用什么材质、用哪段几何数据,从 CPU 到 GPU 的一次DrawCall的流程包含:
-
CPU设置渲染状态
- 绑定要用的 Shader 程序(顶点着色器、片段着色器等)
- 绑定材质参数(纹理、颜色、常量缓冲区)
- 绑定几何数据(网格顶点缓冲、索引缓冲)
- 设置混合模式、深度测试、剔除方式等 GPU 状态
-
CPU发送绘制命令
告诉 GPU 从哪块缓冲取数据、绘制多少个顶点/三角形
-
GPU执行绘制
按状态和数据进行顶点处理、光栅化、片元处理等,最终输出到帧缓冲
关键点:一次 DrawCall ≈ 一次 准备渲染状态 + 发送命令,即使画很少的三角形,也有固定的 CPU 提交开销
如果 DrawCall 数量过多,会严重影响 CPU 性能
DrawCall 为什么会影响 CPU 性能
DrawCall 过程中常见的开销:
-
状态切换的开销
每个 DrawCall 可能要重新绑定材质、贴图、Shader,GPU 需要刷新缓存,CPU 也要组织新的状态命令
-
数据绑定的开销
为每个批次上传模型矩阵、材质参数等常量缓冲区数据
-
命令组织的开销
CPU 需要调用驱动 API 生成命令缓冲,驱动内部也会有锁、同步、内存分配等操作
-
排序与剔除的开销
为减少状态切换,CPU 会在提交前排序批次;有时还要做可见性计算
-
多Pass重复提交的开销
阴影、深度、后处理等,每个物体可能需要额外 DrawCall
等等
每个 DrawCall 都需要进行 CPU 准备数据、切换状态、调用图形 API(OpenGL、DirectX 等)等操作,都会有固定的CPU提交成本
而这些成本会随着DrawCall的数量增多,累积耗时到毫秒级别,从而占满 CPU 渲染线程(Render Thread) 时间
并且如果 DrawCall 太多,CPU 花太多时间准备批次,GPU 可能处于等待状态,
从而导致帧率被 CPU 限制,而 GPU 其实还是空闲状态
在 Unity 中做什么会增加 DrawCall
- 材质、Shader 不一致:纹理、颜色、参数不同
- 相同材质,不同纹理:同一个Shader,但是使用的纹理贴图不同
- 不同的渲染队列:不同渲染队列会分开渲染
- 不同的透明度:透明队列中,Unity 会按深度排序
- 不同的Shader变体:看似一个 Shader 文件,但变体不同
- UI 元素位于不同 Canvas
- Shader 中多个 Pass(阴影、深度、后处理等)
等等
减少 DrawCall 的优化思路
- 合批处理
- 合并贴图(将若干个 UI 小图合并为图集)
- 减少 Shader 变体
- 优化 UI
等等
