How to see why your draw calls are not batched in 5.6

I am sure that you know about Unity’s built-in Dynamic and Static Batching, which help reduce the number of draw calls in your game.

You can see Batching working in the Stats window when the “Saved by batching” count is greater than zero. But unfortunately it is much harder to tell why Batching is NOT working. The Unity Manual provides some information about why this might be happening, though you have to rely on an educated guess based on that information.

Fortunately, Unity 5.6 adds a new feature to the Frame Debugger which says exactly why Unity started a new batch.

Frame Debugger is a window in Unity which shows every batch in your game along with additional details about shaders, textures, and numerous settings used in a batch. The Frame Debugger window can be opened from the Window > Frame Debugger menu and has been available since Unity 5.0.

Before digging deeper into cases when Unity starts a new batch, let’s talk about what batches and batching are.

With Unity 5.6 the Frame Debugger now says exactly why Unity started a new batch.

Batch

To draw an object on screen in your game Unity needs to issue a “Draw” command to the graphics API. This action is essentially called a “Draw Call”. But before doing this, Unity also needs to set all the GPU states required to draw this object: mesh, shader, textures, blending settings and other shader properties. State change commands plus one or more draw commands is what we call a Batch.

Batching

What makes a batch slow is the GPU state change commands, while draw commands are actually pretty cheap. This is why Unity tries to pack several objects being rendered using the same GPU state into one batch. This process is called Batching.

Unity has three types of batching: static batching, dynamic batching and GPU instancing.

Static batching combines static meshes in one or more large meshes at build time and at run time renders them as one batch per mesh.

Dynamic batching takes several small meshes each frame, transforms their vertices on the CPU, groups many similar vertices together, and draws them all in one go.

GPU instancing(added in Unity 5.4) draws many identical objects with different positions, rotations, and other shader properties in fewer draw calls.

What breaks batching

Sometimes you can clearly see in the editor that objects you expect to be batched, for some reason, are not. First of all, check if batching is enabled in Player Settings. It sounds silly, but you won’t believe how many support requests we’ve received where this was the culprit.

Especially for you, we’ve prepared a sample project which illustrates all the cases when Unity has to start a new batch. Please clone it to your machine to follow along. Note that you need Unity 5.6 with the updated Frame Debugger to see the batch breaking causes illustrated in this project.

Here are batch breaking causes from the sample project (as of Unity 5.6). Each says why the object being rendered is in a separate batch:

31 Comments

The new frame debugger is great, and I’m loving all the new extra information it’s giving me.

I’m curious, how does Unity choose what object belong to which combined mesh? And is there a way to manually help it along? For example, in the editor sorting / ordering gameobjects based on their world position, or transform index.

I’m working on a large open world game, and identical large rock objects which I’d assume would be perfect for batching are actually batched like 2-3 at a time. The new debugger tells me that it’s because they belong to different combined meshes. So it’s almost like Unity is randomly picking objects around the scene, and combining them regardless of their proximity to one another, or their world position relative to one another, or their transform index as children.

It would be great to have a little bit more transparency with this, even at build time, as the whole batching process still seems like black magic most of the time.

A ‘forward light’ is just a light in forward rendering path (probably needs better wording). This means that some of your draw calls appear to be rendered in forward even if the camera is set to deferred. This happens when the shader doesn’t provide a deferred pass (LightMode = Deferred).

I just tried out on a relatively big scene with static batching on. I’ve found out some failed to batch together for “Different Combined Meshes” while sharing the same material. It made me realize that some of those automatically generated 64k verts combined meshes, are combining meshes with different material (so with several submeshes), and thus leaving meshes with shared material in different combined meshes which then failed to be drawn at once.

Is there a way to configure that ? I mean combining meshes that have different materials won’t get batched together anyway (since you need the material change), so I would prefer to force the mesh combining step to get combined meshes by same material in the scene, so as to get better result in term of draw calls numbers. That would be sweet.

I have many objects which are identical, yet they can’t be batched. The frame debugger states that the material is different than the previous one. Of course it is different because the previous object is a totally different one. Why does this matter and how can I force Unity to draw objects in some order so that the gnomes in charge of batching are happy?

This depends on your scene. When rendering a scene, Unity sorts all objects (front to back for opaque objects and back to front for transparent objects) and puts them into groups. If your objects happen to be far away along camera forward axis they will end up in different groups and will not be batched.

you can use Material.renderQueue to control the render order of objects – I used this to break unity’s sorting and force batching for the same objects at different depths from camera. It used to be only accessible from script, but I believe new unity has this exposed in material inspector.

Thank you very much for this structured and clean explanations. The only thing what i would like to know is how to avoid batch break when using light probes. Will it be possible to use light probes with dynamic batching at all?

These APIs don’t magically let you draw millions of different objects on screen, you will still have to optimize your content manually or rely on Unity to do so. But of course, it really depends on your project — make sure that batching doesn’t take more resources than it tries to save by testing with batching disabled.

This is exciting, I hope you will further improve this, like adding:
– color code the meshes that are batched together.
– selecting mesh in hierarchy selects corresponding batches in frame debugger.
– improvements to frame debugger batch list: option for stack view vs tree view without all the hierarchy clutter.
– ability to know how many batches a specific light or object contributes to.
– highlight objects that cost high amounts of batches.
etc…
That sort of things, cheers.