Designing a performant UI in Unity
A quote from Unity:
Problem: When a single element changes on the UI Canvas, it dirties the whole Canvas.
Solution: Split up your Canvases.
(Source: https://unity.com/how-to/unity-ui-optimization-tips)
Why is this the case? How might you think about the Canvas system in Unity to intuitively understand this idea?
The canvas lifecycle works as a retained mode GUI as opposed to an immediate mode GUI. A retained mode GUI and the canvas lifecycle works like this:
- The Canvas is initialized and drawn. Unity saves it to a texture.
- Unity projects the texture to the screen every frame and composites it with the scene and other canvases.
- If any element on the canvas changes, Unity re-draws that entire canvas and saves the new “drawing” to a texture.
So the canvas like a layer in a photoshop document. If you change one element of the layer, “Photoshop” (Unity) needs to redraw the entire layer (canvas) that frame.
It makes a lot of sense to redraw the entire canvas if all of the elements on the canvas have changed, but it makes less sense to redraw the entire canvas if only a small percentage of elements on the canvas have changed.
In an immediate mode GUI (aka IMGUI), there is no retained texture, so the entire performance cost of assembling and drawing the GUI is incurred every frame. In some cases, this can actually be kind of nice - the performance cost is constant so you avoid hiccups.
You can force retained mode GUI to behave like an IMGUI from a performance perspective by telling Unity that the canvas is dirty every frame.
Most of the time, though, retained mode GUI is more performant and allows for more complex UI designs with far more elements on screen, since the performance cost is incurred once (when the UI is first drawn).