Tutorial: Improving Your DrawCall in Cocos Creator 2D Games

Improving Your DrawCall in Cocos Creator 2D Games

When it comes to game performance optimization, DrawCall is absolutely inevitable. “Cocos Star Writer” summer flock discusses custom node tree order rendering that could help to optimize DrawCall.

Here the author provides some ways to change the rendering order, and the code is not standardized. But we think this idea is great to look at. In addition, no large-scale testing has been done here, and it is impossible to predict whether this modification will cause unknown errors. If you want to use actual projects, please test more.


I was caught in an interview a few days ago and asked a series of questions about DrawCall. It’s a pity that I have been making 3D games for the past two years, and I have hardly paid any attention to DrawCall in 2D. I can only say that the answer is reluctant. So after I came back, I learned about the source code of Cocos, and gave birth to a rendering submission order that bypassed the node tree, and maximized the effect of merging DrawCall by specifying the submission order of each node. After an afternoon of trials, I finally gained something.

Principles of DrawCall Merging

Picture1

The picture above is a list that is commonly used in games. Let’s take a look at this list:

  • content is the parent node of the list

  • green0, green1, green2 are the cells of the three lists

  • Each cell consists of green (green picture), yellow (yellow picture), label0 (a bmf text)

  • The green picture and the yellow picture have been included in the same sticker collection

Then if the rendering batch is submitted according to Cocos’s traditional deep access layout of the number of nodes, the submission order will be:

Canvas → Camera → content → green0 → yellow0 → label0 → green1 → yellow1 → label1 → green2 → yellow2 → label2

According to the principle of DrawCall and batch, if multiple consecutively submitted nodes use the same atlas when rendering submission, then the DrawCalls of these multiple nodes will be merged. So as shown below, there will be 6 DrawCalls. Originally green0 and yellow0 could be merged, then label0 interrupted the merge, then green1 and yellow1 could merge, and label1 interrupted the merge again. In other words, each cell will occupy 2 DrawCalls. If there are N cells, then the list will have 2N DrawCalls.

Picture2

Improvement in thinking

At this time, some smart friends have thought that if I submit the rendering order:

green0 → green1 → green2 → yellow0 → yellow1 → yellow2 (DC is used once at this time) → label0 → label1 → label2 (2 DCs are used at this time)

Wouldn’t that be beautiful and give you a promotion and a pay rise to the top of your company?

Then we need a feature that can break the order of rendering submissions. At the same time, if I don’t use this function, I will still submit it according to the traditional number of nodes. The best situation is that most nodes submit batches in the original way; and I can specify a node so that this node and its children will be rendered in the order I specify.

A node tree as shown in the figure above, where ABCDEFG are all node groups. When rendering, the order of walking is still AB->D->C->E->F->G. However , when the two node groups of D and G are rendered, they are rendered in the order specified by themselves. In this way, the rendering logic between D and G is independent of each other, and there will be no confusion, but the rendering of the G-node cluster will always follow the D-node cluster.

After a reminder from a fellow forum member, here we also need to consider the transparency overlay.

Take the above figure as an example, on the traditional node tree:

D apparent transparency = A transparency x B transparency x D transparency

But after disrupting the submission order, if the transparency is calculated as described above, the code consumption will increase a lot, so I modified it to:

Transparency of any child node = Transparency of node A x Transparency of any child node itself

Usage instructions

I first select the content node.

In order to satisfy the function, I modified the source code of UITransform.ts and added 2 properties to it:

  • After SpanEffected is checked, it means that this node and all its child nodes have become a node group. In this node group, all the rendering submission order is specified by the user.

  • RenderIndex is the priority of rendering. Under the content node group, the lower the rendering priority, the earlier the rendering will be submitted.

Then we set the rendering submission priority under the content node group as shown in the following figure:

At this point, the rendering order we submitted has become:

content → green0 → green1 → green2 → yellow0 → yellow1 → yellow2 → label0 → label1 → label2

Then in theory there are only 2 DrawCalls. We use spectorJs to verify.

As you can see, it is true, there are only 2 DrawCalls. At this point, you’re done.

Code modification

The UITansform.ts file is modified as follows:

Picture9

The number of lines of batcher-2d.ts code modification is from line 610 to line 658. I packaged the modified source code (the code for calculating the transparency part has been re-added).

If you’d like to play with my example code, check out my project inside the Chinese Cocos forum under the name “修改后的源码.zip”

2 Likes