一、什么是DrawCall
DrawCall的含義就是CPU調用圖像編程接口,以命令GPU進行渲染的操作。
CPU和GPU通過使用一個命令緩沖區實現並行工作。命令緩沖區包含一個命令隊列,CPU向其中添加命令,GPU從中讀取命令,添加和讀取是相互獨立的,因此使得CPU和GPU可以獨立工作。命令緩沖區中的命令有很多種類,DrawCall就是其中一種。
二、為什么DrawCall多了會影響幀率
DrawCall中真正造成性能問題的元凶是CPU。
在每次調用DrawCall之前,CPU需要向GPU發送很多內容,包括數據、狀態和命令等。在這一階段,CPU需要完成很多工作,例如檢查渲染狀態等。而一旦CPU完成了這些准備工作,GPU就可以開始本次渲染。GPU的渲染能力很強,渲染速度往往快於CPU提交命令的速度。如果DrawCall的數量太多,CPU就會把大量時間花費在提交DrawCall上,造成CPU的過載。
三、DrawCall優化
優化有一下幾個解決方案:
1、使用Draw Call Batching,也就是批處理。Unity在運行時可以將一些物體進行合並,從而用一個DrawCall來渲染他們。具體下面會介紹。
2、通過把紋理打包成圖集來盡量減少材質的使用。
3、盡量少的使用反光,陰影之類的,因為那會使物體多次渲染。
Draw Call Batching技術
Unity內置了Draw Call Batching技術,它的主要目標就是在一次DrawCall中批量處理對個物體。只要物體的變換和材質相同,GPU就可以按完全相同的方式進行處理,即可以把它們放在一個Draw Call中。
Draw Call Batching技術存在缺陷,當它需要把一個Batch中的所有物體組合到一起,相當於創建了一個與這些物體加起來一樣大的物體。這就需要分配相應大小的內存,也需要消耗CPU時間。特別是對於移動的物體,每一幀都得重新進行組合。但對於靜止不動的物體,只需要進行一次組合。
Unity提供了Dynamic Batching和Static Batching兩種方式。
Dynamic Batching
Dynamic Batching是完全自動進行的,不需要也無法進行任何干預。
動態批處理的約束:
1、批處理動態物體需要在每個頂點上進行一定的開銷,所以動態批處理僅支持小於900頂點的網格物體。
2、如果着色器使用頂點位置,法線和UV值三種屬性,那么只能批處理300頂點以下的物體;如果着色器需要使用頂點位置,法線,UV0,UV1和切向量,那么只能批處理180頂點以下的物體。
3、不要使用縮放,分別擁有縮放大小(1,1,1)和(2,2,2)的兩個物體將不會進行批處理。
4、統一縮放的物體不會和非統一縮放的物體進行批處理。
5、使用縮放尺度(1,1,1)和(1,2,1)的兩個物體將不會進行批處理,但是使用縮放尺度(1,2,1)和(1,3,1)的兩個物體將可以進行批處理。
6、使用不同材質的實例化物體將會導致批處理失敗。
7、擁有lightmap的物體含有額外(隱藏)的材質屬性,比如:lightmap的偏移和縮放系數等。所以,擁有lightmap的物體將不會進行批處理(除非他們指向lightmap的同一部分)。
8、多通道的shader會妨礙批處理操作。比如,幾乎unity中所有的着色器在前向渲染中都支持多個光源,並為它們有效地開辟多個通道。
9、預設體的實例會自動地使用相同的網格模型和材質。
Static Batching
Static Batching需要把靜止的物體標記為Static,然后無論大小,都會組成Batch。
如何對動態加載的靜態物體進行靜態合批操作:
GameObject go = (GameObject)Instantiate(...);
go.isStatic = true;//將實例化的物體設置為靜態
go.transform.parent = root.transform;
gosList.Add(go);
gos = gosList.ToArray();
StaticBatchingUtility.Combine(gos, root);靜態合並
高效利用Draw Call Batching
1. 首先是盡量減少場景中使用的材質數量,即盡量共享材質,對於僅紋理不同的材質可以把紋理組合到一張更大的紋理中。
2. 然后是把不會移動的物體標記為Static。此外還可以通過CombineChildren腳本(StandardAssets/Scripts/UnityScripts/
CombineChildren)手動把物體組合在一起,但這個腳本會影響可見性測試,因為組合在一起的物體始終會被看作一個物體,從而會增加GPU要處理的幾何體數量,因此要小心使用。
3. 對於復雜的靜態場景,還可以考慮自行設計遮擋剔除算法,減少可見的物體數量同時也可以減少Draw Call。
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)
參考資料:https://blog.csdn.net/zhongdong00/article/details/80590396
