Too many draw calls can ruin your app's performance. They slow down animations, drain battery life, and make your app laggy - especially on mobile devices. Here's how you can fix it:

  • Combine Textures and Materials: Use texture atlases to group textures into one, reducing material switches.
  • Optimize Canvases: Separate static and dynamic UI elements into different Canvases to avoid unnecessary redraws.
  • Batching: Ensure UI elements share the same material, Z value, and texture to enable batching.
  • Reduce Canvas Updates: Isolate frequently changing elements like health bars or timers in their own Canvas.
  • Use Profiling Tools: Analyze draw calls with Unity's Profiler and Frame Debugger to pinpoint bottlenecks.

Quick Tip: Aim for 50–200 draw calls for smooth performance, especially on mobile devices. Use Unity's Stats panel to monitor batches and SetPass calls in real time.

What Are Draw Calls in Unity UI

Unity

Draw Calls Explained

A draw call is essentially an instruction sent to the GPU, telling it how to render specific objects. This includes details like which textures, shaders, and buffers to use. According to Unity Documentation:

"To draw geometry on the screen, Unity issues draw calls to the graphics API. A draw call tells the graphics API what to draw and how to draw it." - Unity Documentation

The process isn't as simple as it sounds. The CPU has to prepare resources and manage state changes before the GPU can even get to work. These preparations often take more effort than the actual rendering. For instance, every time a material is switched, it triggers a render state change, adding more complexity to the process. The more materials involved, the more challenging it becomes.

If you want multiple UI elements to combine into a single draw call (a process called batching), they must share the same material. When different materials are used, Unity generates separate draw calls for each. For example, a poorly optimized table layout could result in as many as 19 draw calls.

Other factors can also increase draw calls. Overlapping elements or images with an alpha value of 0 still contribute to the rendering workload. Additionally, by default, Unity doesn't pack UI and Sprite textures into a texture atlas, which can lead to unnecessary draw call overhead.

Next, let’s explore how you can monitor and analyze these draw calls in Unity.

How to Check Draw Calls in Unity

To manage and optimize draw calls, you need to understand their structure. Unity offers built-in performance tools that make this easier. The Stats panel is a great starting point - it shows real-time data for the most recently rendered frame. This includes the number of batches (draw calls) and SetPass calls (material changes). SetPass calls, in particular, can have a noticeable impact on performance.

You can enable the Stats panel in the Game view while your project is running. For a deeper dive, Unity's Frame Debugger is invaluable. It lets you pause playback on a specific frame and inspect individual draw calls, helping you identify which UI elements might be causing issues.

Unity Optimize UI - Reduce your Draw Calls Improve your performance in 10 MINUTES!

Main Ways to Reduce Draw Calls

Reducing draw calls involves optimizing batching, managing materials efficiently, and handling Canvas updates smartly. Here's how you can fine-tune each of these areas for better performance.

Canvas Batching and Grouping

The Canvas component in Unity plays a key role in rendering UI elements by generating meshes and sending draw calls to the GPU. However, a major drawback is that Unity reprocesses the entire Canvas whenever any part of it changes, which can be a performance hit, especially for complex user interfaces.

To address this, separate static elements from dynamic ones by placing them on different Canvases based on how often they update. For instance, frequently changing elements like health bars or timers should be on their own Canvas to avoid triggering full redraws of static elements like background images or menu buttons.

For efficient batching, ensure that UI elements within the same Canvas share the same Z value, materials, and textures. Unity prioritizes batching methods, starting with the SRP Batcher and static batching, followed by GPU instancing, and finally dynamic batching. Keeping your UI hierarchy clean and avoiding unnecessary nesting helps maintain performance, though nesting can still be useful for organizing related groups of elements.

Material and Texture Atlasing

Switching materials can significantly increase draw calls, as it forces changes in the GPU's render state. Using texture atlases can minimize this by combining multiple textures into a single image, reducing the need for texture switching. For example, leveraging sprite atlases can cut draw calls drastically - going from 58 down to just 5 in some cases.

When creating sprite atlases, stick to power-of-two dimensions like 512×512, 1024×1024, or 2048×2048. These dimensions improve texture compression and enable efficient mipmap generation. Group related textures together in the same atlas, but avoid mixing unrelated assets, as this can unnecessarily increase texture size and reduce optimization benefits. Additionally, sprite atlases simplify material management by reducing the number of unique materials. For procedural content, dynamic texture atlases that load at different stages might also be worth exploring.

Reducing Canvas Updates

Canvas updates can be resource-intensive, especially when UI elements change frequently. To mitigate this, isolate components that update often - such as health bars, score counters, or notifications - on separate Canvases. This way, only the parts of the UI that change are redrawn, leaving static elements untouched.

Minimizing animations or effects that cause constant Canvas updates is another way to improve performance. Use Unity's Animation system or optimized tweening libraries to handle animations more efficiently, or move purely decorative animations to separate Canvases. Additionally, implementing object pooling for frequently created and destroyed elements, like damage indicators or popups, can help reduce the need for costly Canvas rebuilds. Grouping dynamic elements into sub-Canvases based on how often they update can further streamline performance.

sbb-itb-8abf120

Step-by-Step Guide to Fix Unity UI Draw Calls

Building on earlier optimization techniques, here’s a practical guide to pinpoint, address, and confirm draw call issues in Unity.

Find Problem Areas with Profiling

Start by opening the Unity Profiler and focusing on the Rendering Profiler module. Look for excessive batches, SetPass calls, triangles, and vertices, which can indicate performance bottlenecks. For a deeper dive, use the Frame Debugger to pause playback and inspect individual draw calls. Keep in mind that profiling in Editor mode reflects performance within the Unity Editor, while Player mode provides a more accurate view by profiling a built build of your game. To narrow down performance spikes, use Profiler Markers to tag specific sections of your code.

Fix UI Structure and Assets

Once you've identified problem areas, reorganize your UI layout. Separate static and dynamic UI elements by placing them on different Canvases. Ensure that all elements within a Canvas share the same Z value, materials, and textures to allow for batching. Disable Graphic Raycasters on Canvases that don’t require user interaction, and turn off the "Raycast Target" option for static or non-interactive UI elements.

As discussed earlier, combining materials and textures is key to improving batching. Use Unity's Sprite Atlas feature to merge multiple smaller textures into a single larger texture. For example, in a platformer game, you can create a texture atlas that includes all platform textures, which reduces the number of draw calls significantly.

Avoid creating unnecessary layers of UI elements. If layering is essential, consider merging overlaid elements at runtime to minimize the number of batches. For animated UI elements, use code-based animations or tweening systems instead of Animators, especially for elements that don’t change frequently. When pooling UI objects, make sure to disable objects before reparenting them to prevent additional Canvas rebuilds.

Test Results with Profiling Tools

After making optimizations, measure the impact on FPS, CPU, and GPU usage. Use frame time in milliseconds to verify that your game stays within the desired frame budget. For most games, the target is 60 FPS, but VR applications require at least 90 FPS to maintain immersion.

The Profile Analyzer tool is particularly useful for comparing profiling data from before and after your changes, giving you clear evidence of performance gains. Always test on your target devices, as performance can vary widely depending on hardware. Profile frequently throughout development to establish a baseline "performance signature". Begin with Deep Profiling turned off, as it can slow down performance, and enable it only when you need more detailed insights. If your game meets the frame budget after optimizing draw calls, consider using the Memory Profiler to identify any other potential inefficiencies. For deeper hardware-specific analysis, combine Unity's built-in profilers with platform-specific profiling tools. This layered approach ensures your optimizations are effective across different devices and platforms.

Draw Call Optimization Methods Compared

Understanding and comparing draw call optimization methods can help you achieve better performance for your Unity UI.

Comparison Table

Choosing the right optimization technique depends on your UI's structure, the type of content, and your performance goals. Here's a breakdown of the primary methods:

Technique Best Use Case Impact on Performance Potential Drawbacks
Canvas Batching and Grouping Complex UIs with frequent updates Cuts down on canvas rebuilds and draw calls Requires careful planning of UI hierarchy
Material and Texture Atlasing Scenes with diverse textures Reduces texture switching and draw calls Increases texture memory usage and demands atlas management
Reducing Canvas Updates UIs with animations or dynamic content Limits unnecessary canvas rebuilds Might need code changes or alternative animation strategies
Static Batching Non-moving, static elements Lowers draw calls significantly Increases memory usage and unsuitable for dynamic objects
Dynamic Batching Small, similar objects Automatically reduces draw calls Limited by vertex count and requires similar materials
GPU Instancing Many identical objects Greatly reduces draw calls and CPU load Needs instancing shaders and offers less flexibility for individual object modifications

This table serves as a quick reference to weigh each method's strengths and drawbacks. Below, we dive into some key aspects of these techniques.

Canvas batching focuses on grouping similar UI elements to minimize rendering overhead. While effective, it struggles with dynamic content that frequently changes. Material and texture atlasing, on the other hand, reduces the burden of texture switching by combining textures into a single atlas. However, this approach can increase texture memory usage and requires diligent management of the atlas.

For UIs with animations or frequent changes, reducing canvas updates can be a game-changer by cutting down on unnecessary canvas rebuilds. This, however, might require tweaking your code or rethinking how animations are handled.

Static batching works wonders for non-moving objects by consolidating them into fewer draw calls, though it’s not a fit for dynamic elements. Dynamic batching, meanwhile, automatically groups small, similar objects to reduce draw calls but has limitations, such as vertex count and material uniformity. GPU instancing shines when rendering a large number of identical objects, drastically cutting CPU load, though it requires instancing shaders and offers limited flexibility for per-object tweaks.

Each of these methods tackles a different performance bottleneck, from CPU processing to texture management. For the best results, combining multiple techniques is often the way to go, ensuring your UI performs smoothly across different scenarios.

Conclusion

Optimizing draw calls in Unity UI is crucial for ensuring smooth performance on mobile devices, which directly impacts user engagement. Since draw calls can be resource-heavy - often taxing the CPU more during preparation than the actual rendering process - reducing them is a key step toward creating efficient, responsive applications.

Beyond being a technical requirement, draw call optimization offers clear strategic benefits. It helps improve frame rates, lowers power consumption, and simplifies future updates. On the flip side, neglecting optimization can lead to noticeable issues like battery drain and laggy performance, both of which can drive users away and hurt retention rates.

By implementing the techniques discussed, developers can build apps that not only perform better but also encourage longer usage sessions, ultimately boosting user satisfaction and loyalty.

At Zee Palm, we know how critical it is to optimize Unity UI for mobile apps. With over a decade of experience and a portfolio of more than 100 completed projects, our team specializes in crafting high-performance, user-centric solutions. Whether you're building healthcare apps, education platforms, or custom mobile applications, we ensure your Unity UI runs efficiently on all devices, delivering a seamless experience that keeps users engaged.

FAQs

How can I use Unity's tools to identify and fix draw call issues?

To tackle and fix draw call problems in Unity, start by diving into the Unity Profiler. This tool provides essential data on rendering performance, including metrics like draw calls, batches, and set pass calls. These insights help pinpoint areas where optimization is needed, especially if you're dealing with excessive draw calls or inefficient batching.

After that, turn to the Frame Debugger for a closer look at each frame. It breaks down how draw calls are handled and exposes performance issues like broken batching or unnecessary set pass calls. With this detailed information, you can focus on specific changes to boost your project's performance and minimize lag.

What are the challenges of using texture atlases in Unity, and how can I address them?

Using texture atlases in Unity can boost performance, but they also bring some hurdles. One major concern is GPU memory usage. Large atlases can lead to performance dips, such as cache misses, if their size exceeds the ideal range for rendering. For instance, extremely large textures (like 8192 x 8192) might not be supported on certain devices. They can also cause inefficient mipmap selection, especially when only small sections of the atlas are in use. Another common issue is visible seams in normal maps, particularly with tiling textures.

To address these challenges, try using smaller, task-specific atlases to better manage memory and improve mipmap efficiency. Texture streaming is another useful approach - it allows only the required parts of a texture to load when needed. Additionally, make sure your atlas size matches the capabilities of your target platform, and fine-tune compression settings to balance performance and visual quality effectively.

Why does separating static and dynamic UI elements into different Canvases improve performance in Unity?

When working with Unity, splitting static and dynamic UI elements into separate Canvases can significantly improve performance. Here's why: every time a UI element changes, Unity only updates the Canvas that contains that element, rather than reprocessing the entire UI. This means static elements remain untouched, avoiding unnecessary redraws.

By keeping static elements (those that stay the same) separate from dynamic ones (those that change often), you can reduce CPU usage, cut down on draw calls, and keep frame rates smooth. This approach is particularly helpful for intricate UIs that combine static visuals with interactive components.