Draw Call就是CPU调用图形编程接口,比如DirectX或OpenGL,来命令GPU进行渲染的操作。
例如,DirectX中的DrawIndexedPrimitive命令,OpenGL中的glDrawElement命令。
1.CPU和GPU并行工作的原理
为了CPU和GPU可以并行工作,就需要一个命令缓冲区(Command Buffer)
命令缓冲区包含了一个命令队列,由CPU向其中添加命令,而由GPU从中读取命令。添加和读取的过程是相互独立的,因此命令缓冲区可以使CPU和GPU相互独立工作。当CPU需要渲染一些对象时,它可以向命令缓冲区添加命令,而GPU完成了上一次的渲染任务后,它就可以从命令队列里取出一个命令并执行它。
命令缓冲区中的命令有很多种类,而Draw Call是其中的一种,其它命令还有改变渲染状态等命令(改变使用的Shader,使用不同的纹理等)。
2.为什么 Draw Call多了会影响帧率?
在每次调用Draw Call之前,CPU需要向GPU发送很多内容,包括数据,状态,命令等。在这一阶段,CPU需要完成很多工作,例如检查渲染状态等。而一旦CPU完成了这些准备工作,GPU就可以开始本次的渲染。GPU的渲染能力是很强的,渲染300个和3000个三角网格通常没有什么区别,因此渲染速度往往快于CPU提交命令的速度。如果Draw Call的数量太多,CPU就会把大量时间花费在提交Draw Call命令上,造成CPU的过载。
*因此造成Draw Call性能问题的元凶是CPU。
3.如何减少DrawCall?
提交大量很小的Draw Call会造成CPU的性能瓶颈,即CPU把时间都花费在准备Draw Call的工作上了。那么,一个很显然的优化想法就是把很多小的Draw Call合并成一个大的Draw Call,这就是批处理的思想。
需要注意的是,由于我们需要在CPU的内存中合并网格,而合并的过程是需要消耗时间的。因此,批处理更适合静态的物体,例如不会移动的大地,石头等,对于这些静态物体我们只需合并一次即可。当然,我们也可以对动态物体进行批处理。但是,由于这些物体是不断运动的,因此每一帧都需要重新进行合并然后再发送给GPU,这对空间和时间都会造成一定的影响。