Skip to content

Performance and Shader Variants

What the toolkit costs, and the few choices that change it. For most games a screen of styled, animated text is cheap; these are the things worth knowing when there is a lot of it, or when it runs on a low end phone.

Each effect is a shader keyword, so a material only runs the code of the effects it has on. Turning an effect off removes its cost entirely; setting it to zero does not.

Every distinct combination of effects that some material uses is compiled as its own shader variant. Only the combinations your materials actually use are compiled, not every possible one.

  • In the editor, a combination compiles the first time something draws it. With Asynchronous Shader Compilation on (Project Settings → Editor, Unity’s default) the text draws in cyan for a moment meanwhile; with it off, the editor pauses.
  • In a build, each combination is compiled four times, once for each of UGUI’s mask states (no mask, RectMask2D, Mask, both), for each graphics API the build targets.
  • In the player, each variant is prepared the first time it draws, which can cause a small hitch. The demo avoids it by drawing every showcase once behind a loading cover; for a game, warm up the materials of a scene while a loading screen shows, or use a Shader Variant Collection.

So the number of variants grows with how many different looks you have. Materials that share the same set of effects, even with different values and colors, share one variant.

Because builds only include the combinations materials use, turning an effect on from code (with material.EnableKeyword) can ask for a variant the build does not have. Two safe ways to change a look at runtime:

  • Leave the effect on and fade it through its own values: a glow’s Attenuation, an outline’s color alpha, a Blend slider.
  • Swap to another material that already has the effect on. As long as something in the build references that material, its variant is included.

When outlines, glows or shadows reach further than the font atlas stores, the shader rebuilds the distance field around each letter, with up to 13 extra texture reads on those pixels. The material inspector shows a note when that happens. It is usually minor, and only adds up with a lot of large text on a slow GPU; a font asset with more padding avoids it. See Fonts and Font Assets.

While a text’s material has Extrude on, every letter gets a second copy that draws the sides and shadows, so the text has twice the vertices. It stays one draw call. The extrusion itself is found by stepping through the distance field, a handful of reads per pixel and never more than 32, so a deep extrusion over a lot of large text is among the heavier looks. See Bevel, Extrude and Lighting.

  • Each text is at least one draw call. The toolkit keeps data per text on its material, so texts are not batched together the way plain TextMeshPro texts sharing a material can be.
  • Each text layer is one more draw of the whole text.
  • Characters from another font asset draw in TextMeshPro’s own extra draws, as usual.
  • A still text costs almost nothing per frame.
  • A text with a playing Typewriter is rewritten every frame, along with its per letter data for the shader, for as long as it plays, loops included. The cost grows with the text’s length. A stopped typewriter costs nothing. Deactivate texts that are not on screen rather than leaving hundreds playing.
  • Text on a spline is placed again every frame it scrolls or travels.
  • A Warp costs nothing on a frame where its values do not change. When animated, or with a travelling Banner, it rewrites the text that frame.

Each text keeps two small buffers of per letter data for the shader, sized to its TextMeshPro mesh, and each text layer one more. A blurred copy of each font atlas used with Bevel, Outline or Drop Shadow is stored as a single channel texture, the size of the atlas.