Cocos2d-x 之效能檢測
OpenGL 效能指標
cocos2d-x 中有三個跟 OpenGL 相關的效能指標,遊戲執行時顯示在左下角;cocos2d-x 預設會顯示這些效能指標,可以手動在程式碼在開啟或關閉,C++ 專案在 AppDelegate 的 applicationDidFinishLaunching 函式中設定
Director::getInstance()->setDisplayStats(true);
lua 專案在配置檔案 config.lua 中設定
CC_SHOW_FPS = true
FPS(Frames Per Second)
fps 是幀率,顧名思義就是每秒繪製多少幀。幀率設定得超高,畫面重新整理得越頻繁,遊戲看起來更順暢;但這也意味著每秒要做的運算更多,更加耗 CPU 或 GPU,而且如果運算量過大的話,可能會出現卡幀。一般遊戲的幀率不會低於 30 幀,實時性要求比較高的場景可以設定成 60 幀。這個指標可以幫助我們檢視遊戲在什麼時候計算量過大,然後降低計算量或分散計算到多個幀中去。GL Calls
gl call 是 opengl 渲染的次數,即每一幀呼叫 opengl 指令的次數。這個數字越小越好,優化的方向有- 使用 SpriteBatchNode 來批量處理
- 將小圖片打包成合圖,載入到 SpriteFrameCache 中
- 不可見的元素設定為不可見,而不是設定透明度為 0
使用 SpriteBatchNode 是 2.x 的做法,3.0 之後官方不建議使用。這種方式要求所有 Sprite 都要先新增到 SpriteBatchNode 上,雖然能提升效率,但有很多限制,而且某些情況下反而會降低效率。比如有 Sprite 在螢幕外時,SpriteBtachNode 並不會作檢查,而是直接渲染所有的 Sprite;而直接使用 Sprite 的方式會判斷 Sprite 是否在螢幕外,如果在螢幕外則不渲染。3.0 之後直接使用 Sprite 也可批量處理,只要多個 Sprite 使用同張紋理並且使用相同的著色器和混合函式(SpriteBatchNode 也有這些要求),所以推薦直接使用 Sprite 而不是 SpriteBatchNode。
使用 SpriteBatchNode
local batch = cc.SpriteBatchNode:create("popcap.png")
for i = 1, 10 do
local sprite = cc.Sprite:create("popcap.png")
batch:addChild(sprite)
end
self:addChild(batch)
batch:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
直接使用 Sprite
for i = 1, 10 do
self ._icon=cc.Sprite:create("popcap.png")
self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
self:addChild(self._icon)
end
兩種情況的 gl call 都是 1
把圖片事先載入到精靈幀緩衝區並不影響 gl call,只是建立精靈時會快一些而已;但把小圖片打包成合圖,再載入到精靈幀緩衝區,則可以降低 gl call。
直接使用 Sprite
for i = 1, 10 do
self._icon=cc.Sprite:create("popcap.png")
self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
self:addChild(self._icon)
end
for i = 1, 10 do
self._icon=cc.Sprite:create("popcap2.png")
self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
self:addChild(self._icon)
end
使用 SpriteFrameCache
local sf = sfc:getSpriteFrameByName("popcap.png")
for i = 1, 10 do
self._icon = cc.Sprite:createWithSpriteFrame(sf)
self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
self:addChild(self._icon)
end
sf = sfc:getSpriteFrameByName("popcap2.png")
for i = 1, 10 do
self._icon = cc.Sprite:createWithSpriteFrame(sf)
self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
self:addChild(self._icon)
end
第二種方式因為 popcap.png 和 popcap2.png 在同一個合圖裡,所以建立二十個精靈只需要繪製一次;而第一種方式 popcap.png 和 popcap2.png 是兩張不同的精靈,所以會繪製兩次。
對於螢幕外或者被隱藏的 UI,將其 visible 設為 false,這樣就不會繪製;如果設定透明度為 0,則還是會繪製。
self._icon = cc.Sprite:create("popcap.png")
self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
self._icon:setOpacity(0)
self:addChild(self._icon)
self._icon = cc.Sprite:create("popcap.png")
self._icon:setPosition(cc.p(win_size.width / 2, win_size.height / 2))
self._icon:setVisible(false)
self:addChild(self._icon)
- GL Verts
gl verts 是指傳送給顯示卡的頂點數,這個數也是越小越好。頂點數直接與遊戲的顯示物件相關,一張矩形圖片一般繪製 6 個頂點,像上面的例子建立 10 個 Sprite 的時候頂點數是 60,建立 20 個 Sprite 的時候頂點數是 120。使用 SpriteBatchNode 或 SpriteFrameCache 都不能降低頂點數,只能實現批量渲染,減少繪製次數,但該繪製多少精靈就得繪製多少精靈,即使這些精靈使用同樣的貼圖。降低頂點數的方法是將看不見的元素設為不可見,不是設定透明度為 0,這點和 gl call 一樣,參見上面的例子執行結果。
總結
- 不使用 SpriteBatchNode
- 把小圖打包成合圖並載入到 SpriteFramecache
- 不需要的元素及時從顯示列表移除
- 看不見的元素設定 visible 為 false
整合 android-ndk-profiler
首先,從 android-ndk-profiler 上下載,直接 download zip 壓縮包或者使用 git
git clone [email protected].com:richq/android-ndk-profiler.git
下下來之後的目錄結構
|-android-ndk-profiler
|-docs
|-example
|-jni
|-test
我們要用的就是 jni 目錄下的檔案,在特定的目錄下新建一個資料夾 android-ndk-profiler
,把 jni 目錄下的所有檔案拷到新建的資料夾下面。這裡說的特定的目錄是指 ndk 能搜尋到的目錄,我用的 cocos2d-x3.10,有兩種建立專案的方式,原始碼方式和預編譯庫方式,使用原始碼方式建立的專案 ndk 能搜尋到的目錄如下:
使用預編譯庫建立的專案 ndk 能搜尋到的目錄如下:
總結起來就是 \%COCOS_ROOT%; %COCOS_ROOT%/cocos; %COCOS_ROOT%/external; %COCOS_ROOT%/scripting 這四個路徑。只不過原始碼的方式會在專案的根目錄下建立一個 cocos2d-x 目錄,然後把引擎的原始碼拷貝過來,因此 ndk 搜尋的目錄基於專案路徑。而預編譯庫的方式不會拷貝任何原始碼,因此 ndk 搜尋的路徑基於引擎安裝的目錄。
把 android-ndk-profiler/jni 下面的檔案拷貝到這四個路徑之一,比如拷貝到 %COCOS_ROOT%/external/android-ndk-profiler 目錄下,然後修改 android.mk 檔案,新增下面的程式碼
APP_DEBUG := $(strip $(NDK_DEBUG))
ifeq ($(APP_DEBUG),1)
LOCAL_CFLAGS := -pg
LOCAL_STATIC_LIBRARIES += android-ndk-profiler
endif
ifeq ($(APP_DEBUG),1)
$(call import-module,android-ndk-profiler)
endif
然後以 debug 方式進行編譯,編譯成功說明 android-ndk-profiler 已經成功整合到專案了。編譯方式有
預設工程的編譯方式和 ndk 的編譯方式都是 debug,所以直接使用下面命令即可
cocos compile -p android
如果不想把 android-ndk-profiler/jni 下面的檔案拷貝到這四個路徑之一,而是想放在其它地方,則要擴充套件 ndk 路徑,在 android.mk 中新增
ANDROID_NDK_PROFILER_PATH := D:/work/project/frameworks
$(call import-add-path,$(ANDROID_NDK_PROFILER_PATH))
LOCAL_C_INCLUDES += $(ANDROID_NDK_PROFILER_PATH)
這樣就可以把檔案放在 D:/work/project/frameworks
目錄下了。
接下來就是在程式碼中使用 android-ndk-profiler 了,開啟 AppDelegate.cpp,新增下面程式碼
#if (COCOS2D_DEBUG>0 && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "android-ndk-profiler/prof.h"
#endif
bool AppDelegate::applicationDidFinishLaunching()
{
//...
#if (COCOS2D_DEBUG>0 && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
monstartup("libcocos2dlua.so");
#endif
}
void AppDelegate::applicationDidEnterBackground()
{
//...
#if (COCOS2D_DEBUG>0 && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
moncleanup();
#endif
}
monstartup 的引數根據具體的專案型別而定,我建立的是 lua 專案,所以是 libcocos2dlua.so,可以到 proj.android/lib/\armeabi
下檢視。
然後重新進行編譯,可能會出現下面的錯誤
jni/../../Classes/AppDelegate.cpp:82: error: undefined reference to 'monstartup'
這是因為在連結 android-ndk-profiler 庫時失敗,開啟 android.mk,新增
LOCAL_STATIC_LIBRARIES := cocos2d_lua_static
LOCAL_STATIC_LIBRARIES += cocos2d_simulator_static
# 新新增
LOCAL_STATIC_LIBRARIES += android-ndk-profiler
再重新編譯,可能會出現下面的錯誤
這是因為使用的 ndk 版本沒有 ucontext_t 這個型別,換了 ndk 版本就可以了,像我開始用的是 ndk-r10c,改用 ndk-r10e 就可以了。
還有一點要注意的,為了能正常生成報告,我們的遊戲必須有寫入檔案的許可權,開啟 AndroidMainfest.xml 檔案,看看有沒有下面這一句,如果沒有的話則加上
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
解讀效能分析報告
把 android-ndk-profiler 整合在遊戲之後,在 android 手機上跑一遍遊戲,會生成一個 gmon.out 檔案,這個檔案就是我們需要的效能分析報告。預設生成的 gmon.out 的路徑為 /sdcard/gmon.out,即放在內部儲存的根目錄。如果想自定義存放位置,則在呼叫 moncleanup
之前指定存放位置
setenv("CPUPROFILE", "/data/data/com.example.application/files/gmon.out", 1);
moncleanup();
把 gmon.out 拷貝到電腦上,這是一個二進位制檔案,無法直接檢視內容,得先轉換成文字檔案。ndk 提供了專門的轉換工具
cd android-ndk-r10e/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/
./arm-linux-androideabi-gprof \
專案路徑/proj.android/obj/local/armeabi/libcocos2dlua.so \
存放路徑/gmon.out > gmon.txt
下面看看 gmon.txt 的內容
Flat profile:
Each sample counts as inf seconds.
% cumulative self self total
time seconds seconds calls Ts/call Ts/call name
6.52 inf inf __addsf3
5.98 inf inf cocos2d::MathUtilC::transformVec4(float const*, float, float, float, float, float*)
4.89 inf inf inflate_fast
3.26 inf inf __mulsf3
2.17 inf inf cocos2d::Node::processParentFlags(cocos2d::Mat4 const&, unsigned int)
1.63 inf inf cocos2d::ComponentContainer::visit(float)
1.63 inf inf cocos2d::Node::visit(cocos2d::Renderer*, cocos2d::Mat4 const&, unsigned int)
1.36 inf inf cocos2d::Renderer::fillQuads(cocos2d::QuadCommand const*)
1.36 inf inf void cocos2d::Scheduler::scheduleUpdate<cocos2d::Node>(cocos2d::Node*, int, bool)::{lambda(float)#1}::operator()(float) const
1.36 inf inf adler32
1.09 inf inf std::_Deque_iterator<cocos2d::Mat4, cocos2d::Mat4&, cocos2d::Mat4*>::operator--()
0.82 inf inf cocos2d::ui::Button::adaptRenderers()
0.82 inf inf cocos2d::Director::drawScene()
0.82 inf inf cocos2d::Renderer::drawBatchedTriangles()
0.82 inf inf cocos2d::Node::isVisitableByVisitingCamera() const
Call graph (explanation follows)
granularity: each sample hit covers 2 byte(s) for 0.17% of 5.99 seconds
index % time self children called name
<spontaneous>
[1] 19.4 1.16 0.00 png_read_filter_row_paeth_multibyte_pixel [1]
-----------------------------------------------
<spontaneous>
[2] 15.5 0.93 0.00 cocos2d::Image::premultipliedAlpha() [2]
-----------------------------------------------
<spontaneous>
[3] 14.5 0.87 0.00 cocos2d::Texture2D::convertRGBA8888ToRGBA4444(unsigned char const*, int, unsigned char*) [3]
-----------------------------------------------
<spontaneous>
[4] 7.2 0.43 0.00 profCount [4]
-----------------------------------------------
<spontaneous>
[5] 4.0 0.24 0.00 png_read_filter_row_up [5]
-----------------------------------------------
解釋一下含義
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
函式 程式 函式 函式 函式 函式 函式名
消耗 累計 本身 呼叫 平均 平均
時間 執行 執行 次數 執行 執行
佔程 時間 時間 時間 時間
序運 (不 (包
行時 包 括
間的 括 被
百分 被 調
比 調 用
用 時
時 間)
間)
Call graph (explanation follows)
granularity: each sample hit covers 2 byte(s) for 0.17% of 5.99 seconds
index % time self children called name
索引 函式 函式 函式的 被呼叫 函式名
值 執行 本身 子函式 次數
時間 執行 執行
佔程 時間 時間
序運
行時
間百
分比
相關推薦
Cocos2d-x 之效能檢測
OpenGL 效能指標 cocos2d-x 中有三個跟 OpenGL 相關的效能指標,遊戲執行時顯示在左下角;cocos2d-x 預設會顯示這些效能指標,可以手動在程式碼在開啟或關閉,C++ 專案在 AppDelegate 的 applicationDidFi
cocos2d-x之淺析Hello World
source child 核心 內容 creat 哪些 項目 恢復 精靈sprite ***************************************轉載請註明出處:http://blog.csdn.net/lttree*****************
[寒江孤葉丶的Cocos2d-x之旅_33]RichTextEx一款通過HTML標簽控制文字樣式的富文本控件
ast number blink js版本號 領取 size 創建 sub require RichTextEx一款通過HTML標簽控制文字樣式的富文本控件 原創文章,歡迎轉載。轉載請註明:文章來自[寒江孤葉丶的Cocos2d-x之旅系列] 博客地址
Cocos2d-x之CCTouchDispatcher事件分發
使用過CCLayer的都應該知道,CCLayer的眾多父類中有CCTouchDelegate這麼一個類,他使CCLayer能接收touch事件成為可能。cocos2d-x的touch事件是由CCTouchDispatcher這個touch分發器類來進行派發的,所有需要接收to
Cocos2d-x之下載安裝和配置
一、下載 1.Cococs2d-x下載地址 推薦下載cocos2d-x-v3.10版本,自帶建立專案的cococs軟體,就不用在cmd中敲命令了(不過敲命令還是顯得高大上一些)。 2.Android NDK和Android SDK的下載地址: 在
【玩轉cocos2d-x之十二】plist解析工具:Anti_TexturePacker
之前拿了一些別人的圖片素材,是用TexturePacker打包合成的,結果寫程式的時候不知道每個合成前小png圖的名字是什麼,只能一個一個從plist檔案中找,然後猜測對應的名字,再進行顯示,如果不對,
【玩轉cocos2d-x之三十九】Cocos2d-x 3.0截圖功能整合
3.0的截圖和2.x的截圖基本上相同,都是利用RenderTexture來處理,在渲染之前呼叫call函式,然後呼叫Cocos的場景visit函式對其進行渲染,渲染結束後呼叫end函式即可。只是3.0截圖需要在截完屏的下一幀才能處理RenderTexture,這點要注意。關
【玩轉cocos2d-x之二十六】資料結構CCDictionary
CCDictionary在cocos2d-x中被大量的應用,比如CCTexureCache,CCSpriteFramCache等等。 1.實現原理 1.1.uthash CCDiction
【玩轉cocos2d-x之三十四】繪圖:CCDrawingPrimitives和CCDrawNode
最近忙出翔了,這年過的也揪心。好久沒來更新部落格了,今天就來寫一寫cocos2d-x中圖形的繪製。 1.概述 其實cocos2d-x封裝了大量的opengl的繪圖函式,我們可以很輕鬆的在遊戲
【玩轉cocos2d-x之三十】點九圖和輸入框的使用
登入介面一個帳號/密碼輸入框或者主角命名框是少不了的。這節就來了解一下點九圖的輸入框的使用。這裡只是介紹基礎知識,並不進行平臺的移植,也不處理跨平臺可能出現的問題。 1.點九圖CCScale9S
【玩轉cocos2d-x之二十九】利用CCClipingNode做遊戲遮罩
新手引導是遊戲中必備的(除了奇葩的MT用一段動畫開始),也是玩家對遊戲的第一印象,重要性不言而喻。一般採用的遮罩的形式來突出引導重點,同時遮蔽其他功能。這裡簡單的介紹一下游戲遮罩的實現,並給出一個
【玩轉cocos2d-x之二十二】多執行緒和同步02-售票
pthread有很多不同應用,官網都有相應的API解釋和Sample,這裡不再重複,本文主要介紹一個cocos2d-x多執行緒和同步示例。 1.售票 孫鑫老師的C++和Java多執行緒售票一直讓
【玩轉cocos2d-x之二十三】多執行緒和同步03-圖片非同步載入
cocos2d-x中和Android,Windows都一樣,如果在主執行緒中處理一些耗時操作,那麼主執行緒就會出現阻塞現象,表現在介面上就是卡住,未響應等情況。為了避免這種情況的出現,我們需要在後
【玩轉cocos2d-x之四十】如何在Cocos2d-x 3.0中使用opengl shader?
有小夥伴提出了這個問題,其實GLProgramCocos2d-x引擎自帶了。完全可以直接拿來用。先上圖吧。使用opengl前後的對比: 1.在cpp中使用openGL shader。 (1)新
【玩轉cocos2d-x之三十七】粒子系統的載入優化
Cocos2d-x的粒子系統是通過載入plist生成的。plist包含兩部分內容:粒子系統屬性和粒子紋理。然而每次呼叫create都會對plist進行讀取解析,如果重複地使用同一個粒子效果,這樣的呼叫明顯是低效冗餘的。所以我們要做的是,將粒子系統屬性和粒子紋理分別抽出。 (
cocos2d-x之碼農工作筆記 CCNode常用函式(2.0.4)
//版本cocos2d-x2.0.4 CCNode* node =CCNode::create();//生產一個CCNode* node->getZOrder();//獲取節點繪製的順序 node->getPosition();//獲取節點在
cocos2d-x之碼農工作筆記CCScrollView
【此文部分內容載錄 http://blog.csdn.net/xujiezhige/article/details/8558999】 近期工作中要使用CCScrollView,但是網上相對的資料比較
cocos2d-x之物理引擎box2d(2)
小滿(bill man)個人原創,歡迎轉載,轉載請註明地址,小滿(bill man)的專欄地址http://blog.csdn.net/bill_man 由於box2d的內容比較多,它也有自己的testbed例子,所以關於比較深入的box2d引擎內容,我準備單開一個專題去研
Cocos2d-x之LUA指令碼引擎深入分析
另:本章所用Cocos2d-x版本為: 大家好,又是一週過去了,這一週忙的有點焦頭爛額,除了工作照例每天加班到九點外,工具箱又做了大幅改進,新的論壇遊戲兔子game2z也上線了,Cocos2d-x的學習時間被壓縮的很少了,現在是凌晨一點零六分,看著妻子睡熟的樣子,我也只能告訴自已
android ndk 崩潰捕獲(cocos2d-x 之android崩潰捕獲)
ndk 崩潰捕獲 ,我們可以採用 breakpad是一個跨平臺的c++崩潰處理系統。包括:dmp生成模組、 上傳模組、 伺服器儲存模組、解析dmp模組 等。 這裡我只大概說一下dmp生成模組。 1、編譯靜態庫解壓並拷貝breakpad原始碼目錄到專案中,編譯: 指令