开发游戏时,一定被时时提醒要减少 Draw Call,当然Unity也不例外,打开Game Window里的 Stats,可以看到 Draw Call 与 Batched 的数字。但到底什么是 Draw Call?影响的效能是来自 CPU?还是 GPU?
首先,让我们定义何为 “Draw Call”:
“一个 Draw Call,等于呼叫一次 DrawIndexedPrimitive (DX) or glDrawElements (OGL),等于一个 Batch”
摸过 DirectX 或 OpenGL 的人来说,对 DrawIndexedPrimitive 与 glDrawElements 这 API 一定不陌生。当我们准备好资料 (通常为三角面的顶点资讯) 要 GPU 划出来时,一定得呼叫这个函式。换句话说,如果在画面上有一张 “木" 椅子、一张 “铁" 桌子,那理论上就会有两个 Draw Call。
有看到特别点出 “木" 与 “铁" 吗?这代表两物件是使用不同材质球或者不同的 Shader。在 DirectX 或 OpenGL 里,对不同物件指定不同贴图或不同 Shader 的描述,就会需要呼叫两次Draw Call。Procedure code如下:
<table class="devcodetools "><tbody><tr><td> </td><td width="99%"> </td><td style="width: 16px; height: 16px;"> </td></tr></tbody></table><div class="devcodeoverflow"><table class="devcodearea " width="100%"><tbody><tr><td class="devcodelines" width="1%">1</td><td class="devcodelinesarea"><pre class="devcode devcodeline" name="code" style="white-space: pre-wrap; word-wrap: break-word;">SetShader<span style="color: rgb(0, 128, 0);">(</span> “Diffuse<span style="color: rgb(102, 102, 102);">" );</span>2
<span style="color: rgb(102, 102, 102);">SetTexture( “铁"</span> <span style="color: rgb(0, 128, 0);">)</span><span style="color: rgb(0, 128, 0);">;</span>3
DrawPrimitive<span style="color: rgb(0, 128, 0);">(</span> DeskVertexBuffer <span style="color: rgb(0, 128, 0);">)</span><span style="color: rgb(0, 128, 0);">;</span>4
5
SetShader<span style="color: rgb(0, 128, 0);">(</span> “VertexLight<span style="color: rgb(102, 102, 102);">" );</span>6
<span style="color: rgb(102, 102, 102);">SetTexture( “木"</span> <span style="color: rgb(0, 128, 0);">)</span><span style="color: rgb(0, 128, 0);">;</span>7
DrawPrimitive<span style="color: rgb(0, 128, 0);">(</span> ChairVertexBuffer <span style="color: rgb(0, 128, 0);">)</span><span style="color: rgb(0, 128, 0);">;</span>
每次对 Shader 的更动或者贴图的更动,基本上就是对 Rendering Pipeline 的设定做修改,所以需要不同的 Draw Call 来完成物件的绘制。现在了解为什么 Unity 官方文件里,老是要你尽量使用同样材质球,以减少 Draw Call 数量了吧!
再来谈到 Batch,其实也是 Draw Call 的另一种称呼。你可以想成每一次的 Draw Call 会产生一个 Batch,而 Batch 里装的是物件顶点资料,Batch 由 CPU 透过 “驱动程式” 将顶点资料送往 GPU,GPU接手后将物件画在画面上。由此可知,越多 Draw Call,CPU 就越忙碌。这下更清楚知道 Draw Call 数量所影响的是 CPU 效能而非 GPU。
NVIDIA 在 GDC 曾提出,25K batchs/sec 会吃满 1GHz 的 CPU,100的使用率。所以他们推出了一条公式,来预估游戏中大概可以 Run 多少个 Batch:
举个例子:如果你的目标是游戏跑30FPS、使用2GHz的CPU、20š„工作量拨给Draw Call来使用,那你每秒可以有多少Draw Call呢?
333 Batchs/Frame = 25K * 2 * (0.2/30)
那既然 Batch 是个箱子,里头装着物件的顶点资料,再依据我们上面的描述,那表示同样材质或 Shader 的物件,可以合并成一个 Batch 送往 GPU,这样就是最省事的方法!
Unity在 Player Setting 里的两个功能选项 Static Batching 与 Dynamic Batching。功能描述如下:
根据上述的说明,相信大家对降低 Draw Call 这件事有更深一层的认识吧!还有什么不清楚或者错误的地方,还请大家能够留言回复。
*****************************************************************************************************************
性能有时是美术同学无法估计和考量的,因为他们不理解引擎底层运作机制,导致与程序矛盾滋生。
强大的研发团队,需要强有力的技术主导。留个尾巴