Cocos2d-x 學習筆記(26) 從源碼學習 DrawCall 的降低方法
- 2019 年 10 月 23 日
- 筆記
本文鏈接:https://www.cnblogs.com/deepcho/p/cocos2dx-drawcall-glcalls.html
1. 屏幕左下角
我們通常在Cocos2d-x項目運行前,在AppDelegate::applicationDidFinishLaunching()方法中,執行
director->setDisplayStats(true);
用於開啟屏幕左下角的數據顯示,數據一共三行,分別是:
第一行GL verts表示此時繪製的頂點數。
第二行GL calls表示此時DrawCall數量。
第三行表示此時的FPS。
我們研究第二行的GL calls,也就是DrawCall的相關知識。
2. bool _displayStats
左下角數據通過Director的setDisplayStats方法控制顯示與否。該方法僅改變了Director的_displayStats變量,我們可以猜測是該變量控制了數據顯示。該變量默認為false,所以要開啟數據顯示的話,需要手動修改該變量。
另外,Director::setDefaultValues(void)方法也會修改_displayStats。下面看setDefaultValues方法的被調用過程。
在程序入口Application::run()方法調用的AppDelegate::applicationDidFinishLaunching()方法的第一行,執行了:
Configuration::getInstance()->loadConfigFile("configs/config-example.plist");
可以猜測該行是加載了一個plist配置文件,因為其執行的位置很靠前,應該是設置了Cocos2d-x項目的一些重要變量。
打開該plist發現剛才的預測正確。該plist文件如下:
loadConfigFile方法僅設置了Configuration單例對象的幾個變量。在該方法最後,執行了:
Director::getInstance()->getEventDispatcher()->dispatchEvent(_loadedEvent);
該行表面看是分發了一個我們自定義的事件,實際上重要的是,這是Director在程序內的初始化位置。
因為此時不存在Director單例對象,所以執行Director::init()方法。在init方法第一行,執行了:
setDefaultValues();
該方法是對剛才的Configuration單例對象plist文件內與Director和圖像紋理相關的內容進行設置,包括這幾個內容:
_oldAnimationInterval _animationInterval(1.0/fps)
_displayStats
_projection (3d、2d、CUSTOM)
Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::RGBA8888)
Image::setPVRImagesHavePremultipliedAlpha(pvr_alpha_premultiplied)
所以,這是在我們手動調用setDisplayStats方法之前對_displayStats的一次設置,這次設置是通過在setDefaultValues方法中加載plist配置文件進行的。
3. ssize_t _drawnBatches
在幀循環內的Director::drawScene()方法中,會對_displayStats進行判斷,為true時分別執行showStats()方法和calculateMPF()方法。
showStats()方法是直接輸出三行數據到屏幕左下角。其中DrawCall的值是Renderer成員變量_drawnBatches。
DrawCall的值就是_drawnBatches的值,_drawnBatches的增加僅在Renderer::drawBatchedTriangles()方法中進行,如下:
/************** 3: Draw *************/ for (int i=0; i<batchesTotal; ++i) { CC_ASSERT(_triBatchesToDraw[i].cmd && "Invalid batch"); _triBatchesToDraw[i].cmd->useMaterial(); glDrawElements(GL_TRIANGLES, (GLsizei) _triBatchesToDraw[i].indicesToDraw, GL_UNSIGNED_SHORT, (GLvoid*) (_triBatchesToDraw[i].offset*sizeof(_indices[0])) ); _drawnBatches++; _drawnVertices += _triBatchesToDraw[i].indicesToDraw; }
所以,表面上看想辦法降低batchesTotal的值就能降低DrawCall的值。
從上篇文章對Renderer渲染的學習中可以總結出降低DrawCall的大致思路:
同GlobalZOrder的元素中,元素被添加到節點的順序就是渲染命令的添加順序。當兩個命令相鄰且同材質ID的情況下,這兩個命令的索引是被添加到同一個_triBatchesToDraw的索引中,而_triBatchesToDraw的索引是在被GL一次繪製,_triBatchesToDraw的數量決定了batchesTotal的值,也就是DrawCall的值。所以,我們要想實現一次DrawCall中繪製多個元素,就要儘可能讓不同元素添加到節點的順序是相鄰的且不被打斷,並且它們的材質ID一致,從而這些元素頂點索引被整合到一起,在一次glDrawElements方法中被繪製。
本文鏈接:https://www.cnblogs.com/deepcho/p/cocos2dx-drawcall-glcalls.html