Process

Cutting Draw Calls in Unity for Mobile

Draw calls are rarely the only problem, but they are often the first one on low-end phones. Here is how to measure them, which batching tools to reach for, and the habits that keep them down.

Vectra Play 5 min read
A developer looking at a frame profiler on a monitor with an Android phone running a game on the desk

Unity draw call optimization on mobile comes down to three moves: measure batches and SetPass calls with the Frame Debugger, share materials so objects can batch, and pick the right batching method. In URP that usually means the SRP Batcher for most objects, static batching for scenery, and GPU instancing for many identical meshes.

Measure before you change anything

Draw calls only matter if they are your bottleneck. On low-end Android, they often are, because the CPU spends time preparing each one. But confirm it first.

Open the Game view and click Stats. Watch two numbers: Batches and SetPass calls. SetPass calls are shader or material changes, and they are usually the more expensive of the two.

Then open Window > Analysis > Frame Debugger and step through a frame. It shows every draw and often tells you why two draws were not combined. That reason line is the most useful thing in this whole process.

Profile on the device, not the editor

Editor numbers are a guide, not the truth.

Build with Development Build and Autoconnect Profiler ticked, run on your slowest test phone, and check the CPU timeline. If rendering is a small slice of the frame, draw calls are not your problem. Our guide to debugging frame drops on Android covers the device setup.

The batching options and when to use each

Unity has several ways to combine draws. They suit different kinds of objects.

MethodBest forWhere to turn it on
SRP BatcherMost objects in URP with compatible shadersURP Asset settings
Static batchingScenery that never movesMark objects Batching Static
GPU instancingMany copies of one mesh and materialMaterial checkbox
Sprite atlases2D sprites and UISprite Atlas asset
Dynamic batchingVery small meshes, legacy setupsURP Asset, usually left off

In URP, the SRP Batcher is on by default in recent versions. It does not reduce the draw count shown in Stats, but it makes each draw much cheaper by cutting state changes. Check the Frame Debugger to see which objects it is batching.

Material habits that matter most

Most batching breaks come from materials, not meshes. A few habits keep them intact.

Share materials across objects. Ten crates using ten separate copies of a material break static batching and instancing. One shared material keeps both working.

Use sharedMaterial when you only read it. Touching renderer.material creates a new instance silently, and that instance breaks batching for that object.

// Creates a copy of the material on first access. Avoid in hot paths.
var tint = rend.material.color;

// Reads the shared asset. No copy, batching stays intact.
var sharedTint = rend.sharedMaterial.color;

Be careful with MaterialPropertyBlock in URP. Unity's documentation notes that renderers using a property block are not compatible with the SRP Batcher. If you need per-object colours on many copies, GPU instancing with per-instance properties is usually the better route.

Textures and atlases

Every unique texture tends to mean a unique material, which means another SetPass call. Packing textures together reduces that.

For 2D, create an atlas with Assets > Create > 2D > Sprite Atlas, drag your sprite folders in, and confirm the packer is enabled under Project Settings > Editor > Sprite Packer Mode. Our post on tilemap optimization for mobile shows how this applies to level art.

For 3D, a shared texture atlas across props lets them use one material. It is extra work in the art pipeline, so save it for the objects that appear most often on screen.

UI is a hidden source of draws

Canvas UI can add a surprising number of batches. A few rules help:

We cover the rest in Unity UI performance on mobile.

A rough working budget

There is no single correct number of draw calls for mobile. It depends on the device, the shaders, and everything else in the frame.

A practical approach: pick your weakest supported phone, build a test scene with your heaviest view, and find where the frame rate starts to drop. That point is your budget. Write it down and check new content against it every week.

The best budget is the one you measured yourself on the slowest phone you support. Borrowed numbers from forums rarely match your game.

What we would do

We would start every optimisation pass with the Frame Debugger, read the reason Unity gives for each broken batch, and fix the top three causes. In most mobile projects those are duplicated materials, too many unique textures, and a single huge UI canvas.

Then we would set a measured batch budget on a real low-end phone and check it in every weekly build, so the number never drifts back up.

The short version

If your game still stutters on low-end Android after a pass like this, send us a build and we will take a look.

Related reading: Unity mobile performance on low-end Android, Shader basics for devs, Android device fragmentation guide

#Unity#Mobile#Android#Development
Your turn

Got a game idea? We build it.

You bring the concept. We design, build, test and launch it, and you own 100% of the finished game.

Share Your Game Idea  →