cocos2dx3.7.1版本的auto_batching 2020-10-23

cocos2dx的2.x版本和cocos2dx的3.x版本在渲染流程上有了很大的不同浓恳,通過(guò)某度大家可以查到寂恬。

其中還有一個(gè)優(yōu)化就是3.x使用了auto_batching技術(shù)來(lái)替代了2.x時(shí)代中的spriteBatchNode,通過(guò)了解我們能知道广辰,想要通過(guò)auto_batching來(lái)降低drawcall的話,有三個(gè)條件:

1.需確保精靈對(duì)象擁有相同的TextureId(精靈表單spritesheet);

2.確保它們都使用相同的混合函數(shù)

3.沒(méi)有使用shader去進(jìn)行修改

但為什么會(huì)有這三個(gè)條件吶翩活?或者說(shuō)都滿足這幾個(gè)條件后,那是因?yàn)槭裁磳?dǎo)致這些精靈可以auto_batching吶便贵?

首先菠镇,咱們先來(lái)看下3.x的渲染流程:(以下都是coocs2dx 3.7.1版本的源碼,沒(méi)用的我就刪掉了)

1.drawScene開(kāi)始繪制場(chǎng)景

if (_runningScene)

? ? {

? ? ? ? //clear draw stats

? ? ? ? _renderer->clearDrawStats();

? ? ? ? //render the scene

? ? ? ? _runningScene->render(_renderer);

? ? ? ? _eventDispatcher->dispatchEvent(_eventAfterVisit);

? ? }

2.遍歷場(chǎng)景的子節(jié)點(diǎn)

第一步中 的_runningScene->render(_renderer) render函數(shù)中會(huì)有一步visit(renderer, transform, 0)操作承璃,去遍歷所有子節(jié)點(diǎn)

3.調(diào)用每一個(gè)子節(jié)點(diǎn)的draw函數(shù)

voidSprite::draw(Renderer*renderer,constkmMat4&transform,booltransformUpdated)

{

????????// Don't do calculate the culling if the transform was not updated

????????_insideBounds=transformUpdated?isInsideBounds():_insideBounds;

? ? ? ? //在這個(gè)渲染命令上會(huì)有差別利耍,我用的3.7.1版本的渲染命令已經(jīng)換成了下面的_trianglesCommand,之前的是_quadCommand

具體是哪個(gè)版本換的盔粹,我沒(méi)有去跟蹤隘梨。

????????if(_insideBounds)

????????{

????????????????_quadCommand.init(_globalZOrder, _texture->getName(), _shaderProgram, _blendFunc,&_quad,1, transform);

????????????????renderer->addCommand(&_quadCommand);

????????}

????????if(_insideBounds)

????? ? {

? ? ????????? ? _trianglesCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, _polyInfo.triangles, transform, flags);

????????? ? ? ? renderer->addCommand(&_trianglesCommand);

????? ? }

}

4.初始化TrianglesCommand對(duì)象,這就是渲染命令

上面的代碼就是重點(diǎn)了舷嗡,初始化_trianglesCommand對(duì)象轴猎,這就是TrianglesCommand,渲染命令进萄。

其實(shí)渲染命令不僅僅只有TrianglesCommand捻脖,還有其他的锐峭,比如CustomCommand,自定義渲染命令郎仆,顧名思義只祠,就是我們用戶自己定制的命令,由于我沒(méi)有使用過(guò)扰肌,就不介紹了抛寝。

然后,接著就調(diào)用addCommand函數(shù)將渲染命令加入隊(duì)列曙旭。

這里有一點(diǎn)盗舰,也很重要,由于渲染命令有好幾種桂躏,所以addCommand的時(shí)候钻趋,其實(shí)是會(huì)根據(jù)不同的命令類型把渲染命令添加到不同的隊(duì)列。本文只想針對(duì)TrianglesCommand剂习,所以就忽略這一點(diǎn)蛮位,假設(shè)我們的所有命令都是TrianglesCommand。

5.draw函數(shù)執(zhí)行完鳞绕,就輪到渲染邏輯干事了

6.開(kāi)始渲染

Render的processRenderCommand會(huì)根據(jù)不同的Command來(lái)進(jìn)行篩選失仁,并做對(duì)應(yīng)的處理

//以下是對(duì)TRIANGLES_COMMAND 命令的處理

if( RenderCommand::Type::TRIANGLES_COMMAND == commandType)

? ? {

? ? ? ? // flush other queues

? ? ? ? flush3D();

? ? ? ? auto cmd = static_cast<TrianglesCommand*>(command);

? ? ? ? // flush own queue when buffer is full

? ? ? ? if(_filledVertex + cmd->getVertexCount() > VBO_SIZE || _filledIndex + cmd->getIndexCount() > INDEX_VBO_SIZE)

? ? ? ? {

? ? ? ? ? ? CCASSERT(cmd->getVertexCount()>= 0 && cmd->getVertexCount() < VBO_SIZE, "VBO for vertex is not big enough, please break the data down or use customized render command");

? ? ? ? ? ? CCASSERT(cmd->getIndexCount()>= 0 && cmd->getIndexCount() < INDEX_VBO_SIZE, "VBO for index is not big enough, please break the data down or use customized render command");

? ? ? ? ? ? drawBatchedTriangles();

? ? ? ? }

? ? ? ? // queue it

? ? ? ? _queuedTriangleCommands.push_back(cmd);

? ? ? ? _filledIndex += cmd->getIndexCount();

? ? ? ? _filledVertex += cmd->getVertexCount();

? ? }

在這個(gè)函數(shù)drawBatchedTriangles()中,你會(huì)發(fā)現(xiàn):(想自己了解細(xì)節(jié)的話们何,可以到CCRenderer.cpp中查看)

for(const auto& cmd : _queuedTriangleCommands)

{

? ? ? ? auto currentMaterialID = cmd->getMaterialID();

? ? ? ? const bool batchable = !cmd->isSkipBatching();

? ? ? ? fillVerticesAndIndices(cmd);

? ? ? ? // in the same batch ?

? ? ? ? if (batchable && (prevMaterialID == currentMaterialID || firstCommand))

? ? ? ? {

? ? ? ? ? ? _triBatchesToDraw[batchesTotal].indicesToDraw += cmd->getIndexCount();

? ? ? ? ? ? _triBatchesToDraw[batchesTotal].cmd = cmd;

? ? ? ? }else{

????????}

}

//上面的粗體部分就是判斷是否是同一紋理萄焦。

你肯定會(huì)驚訝,what冤竹?拂封??這就行了鹦蠕?為什么要用auto_batching必須要相同紋理冒签、相同混合函數(shù)、相同shader吶片部?

關(guān)鍵是這個(gè):(sprite的draw函數(shù))

_trianglesCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, _polyInfo.triangles, transform, flags);

跟這 TrianglesCommand::init()進(jìn)去看下镣衡,你會(huì)發(fā)現(xiàn):

if( _textureID != textureID || _blendType.src != blendType.src || _blendType.dst != blendType.dst || _glProgramState != glProgramState) {

? ? ? ? _textureID = textureID;

? ? ? ? _blendType = blendType;

? ? ? ? _glProgramState = glProgramState;

? ? ? ? generateMaterialID();

? ? }

在這個(gè)加粗的函數(shù)中,你會(huì)發(fā)現(xiàn)档悠,它做了什么吶廊鸥?

// glProgramState is hashed because it contains:

//? *? uniforms/values

//? *? glProgram

//

// we safely can when the same glProgramState is being used then they share those states

// if they don't have the same glProgramState, they might still have the same

// uniforms/values and glProgram, but it would be too expensive to check the uniforms.

struct {

void* glProgramState;

GLuint textureId;

GLenum blendSrc;

GLenum blendDst;

} hashMe;

// NOTE: Initialize hashMe struct to make the value of padding bytes be filled with zero.

// It's important since XXH32 below will also consider the padding bytes which probably

// are set to random values by different compilers.

memset(&hashMe, 0, sizeof(hashMe));

hashMe.textureId = _textureID;

hashMe.blendSrc = _blendType.src;

hashMe.blendDst = _blendType.dst;

hashMe.glProgramState = _glProgramState;

_materialID = XXH32((const void*)&hashMe, sizeof(hashMe), 0);

他會(huì)給自身的command命令綁定一個(gè)_materialID 。這就是auto_batching的原因辖所。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惰说,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缘回,更是在濱河造成了極大的恐慌吆视,老刑警劉巖典挑,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異啦吧,居然都是意外死亡您觉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門授滓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)琳水,“玉大人,你說(shuō)我怎么就攤上這事般堆≡谛ⅲ” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵淮摔,是天一觀的道長(zhǎng)私沮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)和橙,這世上最難降的妖魔是什么仔燕? 我笑而不...
    開(kāi)封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮魔招,結(jié)果婚禮上涨享,老公的妹妹穿的比我還像新娘。我一直安慰自己仆百,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布奔脐。 她就那樣靜靜地躺著俄周,像睡著了一般。 火紅的嫁衣襯著肌膚如雪髓迎。 梳的紋絲不亂的頭發(fā)上峦朗,一...
    開(kāi)封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音排龄,去河邊找鬼波势。 笑死,一個(gè)胖子當(dāng)著我的面吹牛橄维,可吹牛的內(nèi)容都是我干的尺铣。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼争舞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼凛忿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起竞川,我...
    開(kāi)封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤店溢,失蹤者是張志新(化名)和其女友劉穎叁熔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體床牧,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡荣回,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了戈咳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片心软。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖除秀,靈堂內(nèi)的尸體忽然破棺而出糯累,到底是詐尸還是另有隱情,我是刑警寧澤册踩,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布泳姐,位于F島的核電站,受9級(jí)特大地震影響暂吉,放射性物質(zhì)發(fā)生泄漏胖秒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一慕的、第九天 我趴在偏房一處隱蔽的房頂上張望阎肝。 院中可真熱鬧,春花似錦肮街、人聲如沸风题。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)沛硅。三九已至,卻和暖如春绕辖,著一層夾襖步出監(jiān)牢的瞬間摇肌,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工仪际, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留围小,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓树碱,卻偏偏與公主長(zhǎng)得像肯适,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子成榜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348