Draw Calls vs Batches optimization? [Unity 5]

After U5 was released, the new stats window no longer displays draw calls. Instead, it displays some “batches”.
2067869--134886--upload_2015-4-14_14-33-54.png

Also, looks like documentation about draw calls and batching has been updated and now it says (in the 1st paragraph):

So, they say I need to optimize batches instead of draw calls… Hm…

Then could anyone make it clear what exactly batch is? And how exactly it differs from draw call?

All this time I thought, that batch = draw call. When several meshes are batched it means they’re combined together and sent to a GPU (draw-call’ed) as a single mesh with single shader and a single set of parameters (including textures).

So how do I need to “reduce number of batches, not draw calls”?
What exactly do I need to do? Apply less batching? Whaaat? :eyes:

I googled this topic but all the answers I found so far only prove my point. When people speak about draw calls, batching and optimization, they usially mean “you need to batch as many meshes as possible to a single draw call”.

Am I missing something? Could anyone point me to the right direction?

P.S.: to Unity Technologies: you definitely need to explain the difference between “batch” and “draw call” terms much clearer in docs. Or, I should say, at least try to explain it at all.
So far you gave no definition to what the “batch” is, only to the process of batching.
And at the same time you tell people to optimize these abstract “batches”.

9 Likes

From my understanding,
1 drawcall = CPU tell GPU to actually “draw” something using GPU’s current render state.
1 batch = “change render state” needed( i would say the expensivepart is here, but not draw call itself)

The image below shows 4 drawcall & (1+3) batches.

Then, this image below shows also 4 drawcalls , but (1+1) batches.

1 White box = 1 drawcall
1 red box = 1 batch


What unity’s “dynamic batching” / “static batching” do is combine the mesh in CPU before GPU start rendering, it will reduce # of drawcall, but NOT # of batches.


The only way to reduce batches, is to reduce the number of material / # of pass in shaders.

Please correct me if I am wrong, I wish to understand drawcall/batch relation to performance also.

REF: Render Hell 2.0 | Simonschreibt.

12 Likes

@colin299

Thanks a lot for this very informative and illustrative link. I’ll make a closer look at the weekend, but it already looks like it can really help to understand this batches-vs-DCs topic.

You can see the meaning of batching in this nVidia’s reference page 2. Batch Batch Batch
In the ref, he says batch is

Every DrawIndexedPrimitive() is a batch
– Submits n number of triangles to GPU
– Same render state applies to all tris in batch
– SetState calls prior to Draw are part of batch

In fact, DrawIndexedPrimitive() is draw call, (glDrawElements in OpenGL) not batch. But the ref says it is batch.

And in Unity, You’ll notice that Batches Count and Draw Calls(in Profiler) are always the same.
Theoretically, they are different concept. But, Practically they always happened at the same time.

And I can not find the situation that Batch Count and Draw Call Count is different.
in the scene, there are Multi-Sub Object, Multi-Pass Shader objects. But they are always the same.

I think Unity just want to emphasize batching, not draw call.

SetPass is probably your state change and draw calls/batches can pretty much be treated with the same thinking. But as always, reduce everything. Reduce draw calls (batches) and reduce set passes :slight_smile:

I guess they could be different in the case that underlying API has an ability to be sent multiple draw calls from a single command. (I’m thinking instancing, but not sure if that would apply here?)
Or the opposite, that 1 draw call could actually result in more then 1 batch having to be done by unity or the underlying API.
Not sure I agree with unity’s decision to rename it, but in general I simply treat them the same.

I am still curious to learn how to do any of this… Here is my case:

  1. According to the frame debugger I have 40 draw calls.
  • 1 for Opaque geometry (camera background)
  • and 39 Unity UI transparent calls
  1. According to the stats I have 42 batches and
  2. 33 SetPass calls
  3. According to Profiler I have 32 SetPass Calls and 41 Draw Calls

Stepping through the Frame Debugger I notice that I have 4 render passes for graphics that are in the same atlas but they are not drawn as one pass… heck they are not even drawn in sequence. I have stuff from one atlas drawing in 2 passes, then something completely different from another atlas then skip back to the first one, then two more passes from 2 more atlases before skipping back to the first one…

1 atlas, 1 parent GameObject, 1 canvas, 1 sorting layer, 4 render passes to draw the 3 health bars. Ironically enough, the first health bar loads with background, hidden bar and health bar that goes over it but to element icon. The next pass draws the backgrounds of the other two power bars, the next one draws only the health bars and the next one draws the elements… All from the same atlas. why does it take Unity 4 render passes to draw something from the same atlas to the screen?

So I ask again… If even graphics from the same atlas draws in 4 draw calls and a 3D object with one material takes one render pass for every single individual mesh that uses that material then how do I get my draw calls down?

totally not sure if I should believe the 42 batches, the 40 render passes, the 32 WetPass calls, or the 41 Draw calls…

Oops. Just noticed the date on this thread as I hit the post button. Sorry for necro posting but this is my exact question and it seems to not have had a reply in the past 11 months… Can someone clue me in with the past 11 months of experience? Please? :slight_smile:

This is simply a guess, but regarding your example:
I think that when your looking at the frame debugger it’s skipping at Least one draw call, the one that copies it to the screen. So that being 1 lower does make sense.
However why the profiler and stats would not be the same is weirder, but it could likely be for a similar reason and/or the drawing of the stats themselves?

As for why Unity isn’t bacthing things from the same atlas the way you want it to, generally the reason would be that it’s not sure if they might overlap or not, and is thereby forced to draw them in the z order necessary if they were transparent.
Generally transparent stuff is near impossible to batch and/or not worth batching. Some UI’s do batch optimizations, however the calculations of overlap ect can easily take a bit of time, and would need to be re-done as soon as something changes position, size, rotation ect.

p.s. See if the exact difference stays the same no matter how many/few things you have.

I actually did a few tests and had some interesting observations:

4 Images not overlapping = 1 draw call
4 images where all 4 overlap each other = 1 draw call

I have a very complex prefab with loads of Images that are enabled/disabled at any given time, some with Animators on them and in one instance one is from another atlas and when the game is running is always hidden until needed but when needed it is moved to a separate parent object that houses only the instances of that Image until it is to be “destroyed”. At that point it is simply disabled and returned to the prefab in question.

Now here is the interesting bit… That prefab takes up 3 draw calls. I duplicate it and I still get 3 draw calls. Then I move it so it doesn’t cover the other one exactly and now I have 6 draw calls. I move it up further so it doesn’t overlap the other one at all and suddenly it goes back down to 3 again.

It seems that overlapping Image components are only an issue when they are partially overlapping. Strange. Strange in the sense that the offending Image is not duplicated but all draw calls from the entire prefab hierarchy. Though that kinda actually makes sense…

So here is the question… I have a Health bar background as an Image. Then I have a yellow health bar on top of it.On top of the yellow health bar I have a red one. So when you take damage the red one shows your actual HP while the yellow one gradually updates to catch up. I have three of these health bars and then I have a separate image unrelated to the health bars and they are all in the same atlas and they all have transparency. None of them are scaled.

Draw call 1 draws this unrelated graphic as well as the one health bar complete with all it’s overlapping parts.
Draw call 2 draws the other two health bar’s but only draws the background
Draw call 3 draws the missing health bars themselves

So my original question remains… one atlas, one prefab, 3 instances + 1 unrelated graphic. Why does the one instance draw completely, together with the unrelated image, while the other two instances of the same prefab is drawn in 2 additional passes. Notice that I am saying additional passes because it should have been drawn together with the first instance and the unrelated graphic from the same atlas. Why then are the other instances drawn separately and why does the first one contain the background AND the two overlapping graphics while the other instances draw the background and the overlapping graphics in 2 separate passes?

It is still a mystery but pointing me in the direction of overlapping graphics, thanks for that at least. :slight_smile:

Educated guess as to the reason for overlaps increasing the count - shaders without alpha blending can be drawn in any order thanks to z-buffering. Alpha blended shaders however require that objects be drawn in the right order so that objects at the front can overlay the pixels of objects behind them. Therefore, Unity won’t batch alpha-blended objects which overlap, as their draw order must be preserved (as opposed to combining them and drawing them at the same time).

1 Like

They can, yes. But they should be drawn front-to-back. This way, any opaque pixel covered by any other opaque geometry won’t be re-calculated.

Sure. My point is just that dynamic batching is far easier for opaque materials (and alpha tested, since there’s no blending involved) than for alpha blended. You might get overdraw, (and generally this is cheaper than increased setpass calls), but it’ll still work - unlike blending.

Hello all, Thanks for such a good informative thread, I personally never worked with unity other than just importing objects to see if the normal are flipped or not, my question is basically how to reduce the batches? is it something to do with actual objects or the textures?

I am not sure about this explanation :

‘‘batches with dynamic batching enabled is 589, it’s still a bit to hight, it would be good if you could put props textures to atlases.’’

Any help would be appreciated.

Thanks.

1 Like

First, sorry for replying years later.
That said, the community’s knowledge about this topic has greatly increased since the changes made to Unity.

Most of the answers are scattered around the forums, I will try to be as concise as I can. And I will provide the mos important links I found on this topic.

Before I explain this I have to say that the texture (Atlas or not) and material are not the same thing. You can have one Atlas texture for the entire model of a tavern while having different materials for the walls and floor using this same Atlas, each material would be rendered in it’s own pass.

So, MrDude’s problem with atlas texture rendering through various passes can be caused by many things. The most common are:

1- Various objects with the same material and not eligible for Batching static.
1.2- There will be one batch for each object rendered, plus the material on each one.
1.3- In case this object was eligible for Batching static, it would have one render for the “grouped” meshes and one for the only material applied to it. If that was the case, turning off one of the objects would not reduce the batch calls because they are all made in one (This affects RAM)

2- One object with various materials.
2.1- There will be one batch for this single mesh, and one batch for every material on this object.
2.2- In case you had duplicates of this objects AND they applied for Batching static, you would see no increasing on the batches, because they would be “grouped” on the same object. So still one for the big mesh and one for each material.

I will leave here the more relevant links I found on this topic:
https://docs.unity3d.com/2021.2/Documentation/Manual/optimizing-draw-calls.html
https://answers.unity.com/questions/589302/combination-of-basic-meshes-or-one-big-mesh.html
https://discussions.unity.com/t/636704
https://answers.unity.com/questions/9607/what-is-a-reasonable-number-of-draw-calls-relative.html

If you find any fixes on this comment or topic or want to add something, feel free to do it.