I’ve been trying to find ways to reduce the draw calls due to the usage of labels in certain places, like ui::ImageView
with a child label added as ui::ListView
items, where we can’t easily set the labels to a different global Z layer given that the ListView
needs clipping enabled. What happens there is that it switches between the sprite sheet being used for the ImageView
and the BM font texture for every single item in the ListView
, which adds up to a considerable number of draw calls.
So, given that BM Labels are rendered using QuadCommand
, I modified it to instead us TriangleCommand
, so I can have the BM font texture embedded in the larger sprite sheet, in the hope that I can manage to get them batched together (assuming they’re using the same shader and such).
Anyhow, I don’t know enough about these things to see any possible issues, so if anyone has advice or suggestions, then please do mention them.
I modified the following code to change them to TriangleCommand:
CCLabel.c
:
void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
...
const auto textureAtlas = _batchNodes.at(0)->getTextureAtlas();
const auto totalQuads = textureAtlas->getTotalQuads();
TrianglesCommand::Triangles triangles;
triangles.indices = textureAtlas->getIndices();
triangles.verts = (V3F_C4B_T2F*)textureAtlas->getQuads();
triangles.vertCount = 4 * totalQuads;
triangles.indexCount = 6 * totalQuads;
_trianglesCommand.init(_globalZOrder, textureAtlas->getTexture()->getName(), getGLProgramState(), _blendFunc, triangles, transform, flags);
renderer->addCommand(&_trianglesCommand);
// The following is the QuadCommand that was replaced
//auto textureAtlas = _batchNodes.at(0)->getTextureAtlas();
//auto texture = textureAtlas->getTexture();
//_quadCommand.init(_globalZOrder, texture, getGLProgramState(),
// _blendFunc, textureAtlas->getQuads(), textureAtlas->getTotalQuads(), transform, flags);
//renderer->addCommand(&_quadCommand);
....
CCTextureAtlas.h
:
GLushort* getIndices() { return _indices; }
The code above works, and renders the labels in their entirety. The next step is to figure out the best way to get the BM font to handle a texture in a larger sprite sheet.
I noticed another thread regarding this same issue, https://discuss.cocos2d-x.org/t/mixing-sprites-and-bitmap-fonts-on-a-single-texture-to-limit-draw-calls/26088/6, but the discussion seemed to stop without any results.
Is there any reason this wasn’t done previously, or any reason it shouldn’t be done this way?
EDIT:
There is some support in the current Cocos2d-x code for supplying a BM font texture that exists inside a bigger texture, so the following worked (went from 60+ draw calls to 2…):
const auto fontFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName("arimo_40.png"); // This is in a larget texture
const auto label = Label::createWithBMFont("arimo_40.fnt", "TEXT", TextHAlignment::CENTER, 0, fontFrame->getRectInPixels().origin);
arimo_40.fnt is modified to reference the larger spritesheet name, which for this example is “spritesheet-0.png”:
info face="Arimo" size=40 bold=1 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0
common lineHeight=40 base=32 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0
page id=0 file="spritesheet-0.png"
The only thing it doesn’t seem to support is if the font texture is rotated inside the bigger sprite sheet, but that’s something that may be easy to fix.