什么是Draw Call?
Draw Call 本身的含义很简单,就是CPU调用图像编程接口,如OpenGL 中的glDrawElements 命令或者DirectX 中的DrawlndexedPrimitive命令,以命令GPU 进行渲染的操作。
一个常见的误区是, Draw Call 中造成性能问题的元凶是GPU,认为GPU 上的状态切换是耗时的,其实不是的,真正“拖后腿”其实的是CPU。
为什么Draw Call 多了会影响帧率?
我们先来做一个实验:请创建10 000 个小文件,每个文件的大小为1KB,然后把它们从一个文件夹复制到另一个文件夹。你会发现,尽管这些文件的空间总和不超过10MB ,但要花费很长时间。现在,我们再来创建一个单独的文件,它的大小是10MB,然后也把它从一个文件夹复制到另一个文件夹。而这次复制的时间却少很多!这是为什么呢?明明它们所包含的内容大小是一样的。原因在于,每一个复制动作需要很多额外的操作,例如分配内存、创建各种元数据等。如你所见,这些操作将造成很多额外的性能开销,如果我们复制了很多小文件,那么这个开销将会很大。
渲染的过程虽然和上面的实验有很大不同,但从感性角度上是很类似的。在每次调用Draw Call 之前, CPU 需要向GPU 发送很多内容,包括数据、状态和命令等。在这一阶段, CPU 需要完成很多工作,例如检查渲染状态等。而一旦CPU 完成了这些准备工作, GPU 就可以开始本次的渲染。GPU 的渲染能力是很强的,渲染200 个还是2 000 个三角网格通常没有什么区别,因此渲染速度往往快于CPU 提交命令的速度。如果Draw Call 的数量太多, CPU 就会把大量时间花费在提交Draw Call 上,造成CPU 的过载。图2.20 显示了这样一个例子。
![](http://imgtec.eetrend.com/files/2019-10/%E5%8D%9A%E5%AE%A2/100045691-82962-1.png)
如何减少Draw Call?
尽管减少Draw Call 的方法有很多,但我们这里仅讨论使用批处理(Batching )的方法。
我们讲过,提交大量很小的Draw Call 会造成CPU 的性能瓶颈,即CPU 把时间都花费在准备Draw Call 的工作上了。那么,一个很显然的优化想法就是把很多小的DrawCall 合并成一个大的Draw Call ,这就是批处理的思想。图2.21 显示了批处理所做的工作。
需要注意的是,由于我们需要在CPU 的内存中合并网格,而合并的过程是需要消耗时间的。因此,批处理技术更加适合于那些静态的物体,例如不会移动的大地、石头等,对于这些静态物体我们只需要合并一次即可。当然,我们也可以对动态物体进行批处理。但是,由于这些物体是不断运动的,因此每一帧都需要重新进行合并然后再发送给GPU,这对空间和时间都会造成一定的影响。
![](http://imgtec.eetrend.com/files/2019-10/%E5%8D%9A%E5%AE%A2/100045691-82963-2.png)
在游戏开发过程中,为了减少Draw Call 的开销,有两点需要注意。
( 1) 避免使用大量很小的网格。当不可避免地需要使用很小的网格结构时,考虑是否可以合并它们。
(2)避免使用过多的材质。尽量在不同的网格之间共用同一个材质。
本文摘自《Unity Shader入门精要》
出处:https://blog.csdn.net/e295166319/article/details/78595008