44.性能优化-CPU-图形-DrawCall
44.1 知识点
DrawCall 是什么
DrawCall(绘制调用) 在 Unity 中有时也会被称为 SetPass Call(设置参数调用)。它的本质是 CPU 向 GPU 发送一次绘制指令,告诉 GPU:画什么、怎么画、用什么材质、用哪段几何数据。
一次 CPU → GPU 的 DrawCall 流程通常包含:
- CPU 设置渲染状态
- 绑定要用的 Shader 程序(顶点着色器、片段着色器等)
- 绑定材质参数(纹理、颜色、常量缓冲区)
- 绑定几何数据(网格顶点缓冲、索引缓冲)
- 设置混合模式、深度测试、剔除方式等 GPU 状态
- CPU 发送绘制命令
告诉 GPU 从哪块缓冲取数据、绘制多少个顶点/三角形。 - GPU 执行绘制
按状态和数据进行顶点处理、光栅化、片元处理等,最终输出到帧缓冲。
关键点: 一次 DrawCall ≈ 一次“准备渲染状态 + 发送命令”。即使绘制的三角形很少,CPU 也会有固定提交开销。DrawCall 过多会明显影响 CPU 性能。
简化理解代码(仅示意):
// 步骤 1:准备渲染状态(材质、Shader、网格、渲染状态)
// 步骤 2:提交绘制命令(由引擎/驱动完成)
// 步骤 3:GPU 执行绘制
DrawCall 为什么会影响 CPU 性能
DrawCall 过程中常见的 CPU 开销包括:
- 状态切换开销:每次 DrawCall 可能需要重新绑定材质、贴图、Shader,GPU 需刷新缓存,CPU 也要组织新状态命令。
- 数据绑定开销:为每个批次上传模型矩阵、材质参数等常量缓冲区数据。
- 命令组织开销:CPU 调用图形 API(OpenGL、DirectX 等)生成命令缓冲,驱动内部也可能有锁、同步、内存分配等。
- 排序与剔除开销:为减少状态切换,CPU 提交前会做排序;有时还要可见性计算。
- 多 Pass 重复提交:阴影、深度、后处理等可能让每个物体产生额外 DrawCall。
每个 DrawCall 都需要 CPU 准备数据、切换状态、调用图形 API 等操作,固定提交成本会随着 DrawCall 数量增多累积到毫秒级,最终占满渲染线程(Render Thread)。
如果 DrawCall 太多,CPU 花大量时间准备批次,GPU 反而等待,帧率被 CPU 限制。
在 Unity 中做什么会增加 DrawCall
常见原因包括:
- 材质 / Shader 不一致:纹理、颜色、参数不同。
- 相同材质,不同纹理:同一 Shader 但贴图不同。
- 不同渲染队列:不同队列会分开渲染。
- 不同透明度:透明队列中 Unity 按深度排序。
- 不同 Shader 变体:同一 Shader 文件但变体不同。
- UI 元素位于不同 Canvas。
- Shader 多 Pass:阴影、深度、后处理等带来额外 DrawCall。
- 其它情况。
减少 DrawCall 的优化思路
常用方向包括:
- 合批处理(Static/Dynamic Batching、GPU Instancing 等)
- 合并贴图(图集、合并材质)
- 减少 Shader 变体(精简关键字、剔除无用变体)
- 优化 UI(合并 Canvas、减少过度拆分)
- 其它按项目场景调整
示例(仅示意合批思路):
// 步骤 1:统一材质 / Shader,减少状态切换
// 步骤 2:静态物体启用 Static Batching 或合并网格
// 步骤 3:动态重复物体使用 GPU Instancing
44.2 知识点代码
Lesson44_性能优化_CPU_图形_DrawCall.cs
public class Lesson44_性能优化_CPU_图形_DrawCall
{
#region 知识点一 DrawCall是什么
//DrawCall(绘制调用)在Unity中有时也会被称为 SetPass Call(设置参数调用)
//本质上是 CPU 向 GPU 发送一条绘制指令
//告诉 GPU 要画什么、怎么画、用什么材质、用哪段几何数据
//从CPU到GPU的一次DrawCall的流程包含:
//1.CPU设置渲染状态
// 绑定要用的 Shader 程序(顶点着色器、片段着色器等)
// 绑定材质参数(纹理、颜色、常量缓冲区)
// 绑定几何数据(网格顶点缓冲、索引缓冲)
// 设置混合模式、深度测试、剔除方式等 GPU 状态
//2.CPU发送绘制命令
// 告诉 GPU 从哪块缓冲取数据、绘制多少个顶点/三角形
//3.GPU执行绘制
// 按状态和数据进行顶点处理、光栅化、片元处理等,最终输出到帧缓冲
//关键点
//一次DrawCall ≈ 一次 准备渲染状态 + 发送命令
//即使画很少的三角形,也有固定的 CPU 提交开销
//如果DrawCall数量过多,会严重影响CPU性能
#endregion
#region 知识点二 DrawCall为什么会影响CPU性能
//DrawCall过程中常见的开销:
//1.状态切换的开销
// 每个 DrawCall 可能要重新绑定材质、贴图、Shader,GPU 需要刷新缓存,CPU 也要组织新的状态命令
//2.数据绑定的开销
// 为每个批次上传模型矩阵、材质参数等常量缓冲区数据
//3.命令组织的开销
// CPU 需要调用驱动 API 生成命令缓冲,驱动内部也会有锁、同步、内存分配等操作
//4.排序与剔除的开销
// 为减少状态切换,CPU 会在提交前排序批次;有时还要做可见性计算
//5.多Pass重复提交的开销
// 阴影、深度、后处理等,每个物体可能需要额外 DrawCall
//等等
//每个 DrawCall 都需要进行 CPU 准备数据、切换状态、调用图形 API(OpenGL、DirectX等)等操作
//都会有固定的CPU提交成本
//而这些成本会随着DrawCall的数量增多,累积耗时到毫秒级别
//从而占满 CPU 渲染线程(Render Thread) 时间
//并且如果DrawCall太多
//CPU 花太多时间准备批次,GPU 可能处于等待状态,从而导致帧率被CPU限制
//而GPU其实还是空闲状态
#endregion
#region 知识点三 在Unity中做什么会增加DrawCall
//1.材质、Shader不一致
// 纹理、颜色、参数不同
//2.相同材质,不同纹理
// 同一个Shader,但是使用的纹理贴图不同
//3.不同的渲染队列
// 不同渲染队列会分开渲染
//4.不同的透明度
// 透明队列中,Unity会按深度排序
//5.不同的Shader变体
// 看似一个 Shader 文件,但变体不同
//6.UI元素位于不同Canvas
//7.Shader中多个Pass(阴影、深度、后处理等)
//等等
#endregion
#region 知识点四 减少DrawCall的优化思路
//1.合批处理
//2.合并贴图
//3.减少Shader变体
//4.优化UI
//等等
#endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com