TextMeshPro - Precull DoRebuilds performance

Hello,

I use textmeshpro in my application.
Sometimes, textmeshpro eat a lot of framerate by rebuilding its textmeshpro.

I uploaded an example that show 278.44 ms of process.
It’s very huge and not acceptable.

I’m working on 1.4.1
Is it an internal lack of performance or are there some tips and tricks to avoid this spike ?

Best regards

Satochu

I’ll need more information with regards to those text objects.

How many text objects?

Are you using dynamic font assets?

How much text / number of characters does each contain?

Are you using text auto size on all of them?

Alternatively, you can submit a bug report with the project and steps for me to reproduce / check the behavior.

Hello,

Unfortunately, I can’t export a runnable projects (private business application).

  • I use something like 20 TextMeshPro.
  • I use some Dynamic font assets
  • The text isn’t very long, the longuest one is like 40 characters. But The most texts are like 10 characters.
  • Everything is autosized

I tried to find what is taking so much.
I deleted 4 texts and get back like 100 ms.
Here is a sample :

Update:

I removed Auto size and it seems to fix the performance problems.
But I need autosize because my texts are translated.

Is it a way to refresh label size without having autoSize checked ?
Like this :

MyTextMeshPro = “NewLabelLonger”;
MyTextMeshPro.RefreshSize();

???

Text Auto Sizing requires multiple passes to determine the optimum point size for the given text container size. This can have significant performance overhead and has such I do not recommend using auto size on all text objects.

In addition to performance overhead, using auto size on different text objects is likely to result in different point size which from a design point of view is not ideal. For instance, if you have 5 buttons in a UI, the text point size should be the same for all of them. It is fine to use different point size but similar text objects should use the same point size.

My recommendation is to identify groups of text objects that should have the same point size. Then for each group, use one of the text objects, typically the one with the most characters to figure out the optimum point size. Then disabling auto size on this test object and then manually set the point size on it and the other text objects in that group. This ensures auto size is only used once per group of text objects.

You should maintain a list of these groups and list of text objects within these groups. Whenever a new scene is loaded, you would iterate through the relevant groups to as per above find the optimum point size and then manually setting it on the other relevant text objects.

In terms of changing point size, changing the .fontSize property will change the point size. On the object you are testing since you want this result within the same frame, you will have to use the ForceMeshUpdate() on the text object. As such you would …

Here is a very simple implementation example

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class TextAutoSizeController : MonoBehaviour
{
    public TMP_Text[] TextObjects;

    private void Awake()
    {
        if (TextObjects == null || TextObjects.Length == 0)
            return;

        // Iterate over each of the text objects in the array to find a good test candidate
        // There are different ways to figure out the best candidate
        // Preferred width works fine for single line text objects
        int candidateIndex = 0;
        float maxPreferredWidth = 0;

        for (int i = 0; i < TextObjects.Length; i++)
        {
            float preferredWidth = TextObjects[i].preferredWidth;
            if (preferredWidth > maxPreferredWidth)
            {
                maxPreferredWidth = preferredWidth;
                candidateIndex = i;
            }
        }

        // Force an update of the candidate text object so we can retrieve its optimum point size.
        TextObjects[candidateIndex].enableAutoSizing = true;
        TextObjects[candidateIndex].ForceMeshUpdate();
        float optimumPointSize = TextObjects[candidateIndex].fontSize;

        // Disable auto size on our test candidate
        TextObjects[candidateIndex].enableAutoSizing = false;

        // Iterate over all other text objects to set the point size
        for (int i = 0; i < TextObjects.Length; i++)
            TextObjects[i].fontSize = optimumPointSize;
    }
}

Add the following scrip to an empty game object. Populate the public array with text objects that all have auto size disabled. These would be text objects that you expect to end up all at the same point size.

Screen shot of the scene setup before entering playmode

Result when using just auto size on these objects

As you can see they end up with different point size which is weird from a design point of view.

Now with auto size disabled and using the example script we get the following result.

In this case they are all using the same final point size and we only used auto size on one text object so better performance.

Since auto size is typically used to handle resolution variance between devices which is something that needs to be addressed when loading a scene the first time, this also means we only have to do this once unless the text will be changing of course.

7 Likes

Hello,

Thank you for your detailed answer.
I tried something similar and could get ~100ms from the initialization !
I’ll continue to optimize group of texts to reduce CPU consommation.

Can you tell me, when the textMeshPro force an autosize update ?
So that i might optimize further more by correctly understanding this.

Is it another way to keep performance when the entire application is able to be translated ?
The reason I have ALL my texts setted in autoSize is because I allow the user to do a hot translate.
I have a solution to manually pass throught each TMP to revalidate size but is there another way to do it ?

Best regards,

Julien

When Text Auto Size is enabled, any change to the text object’s properties that affect layout (like the text for instance) will result in an update of the text and auto size.

So whenever a user changes the language, you should re-run the equivalent of the process I outlined in my previous post.

1 Like

Ok, thank you for the information.
I hope there will be some internal optimization for TMP.

I could optimize like 200ms but I use TextMeshPro with autosize (refreshed manually) inside a canvas (mask).
So during the animation, the TMP refresh non stop.

I’ll continue optimizing and wait a possible futur release.

Thank you for this :slight_smile:

Auto Size is an iterative process where multiple point size values have to be tested to determine the Optimum point size. The greater the auto size range the more potential iterations and resulting performance overhead. This is not something that can be much further optimized.

Like I said before, you should always strive to minimize the use of Auto Size. Auto size should not be left enabled on text objects that are not static or will be changing.

Like I said before, once you have determined the Optimum point size based on some screen resolution / language, you should not have to change the point size again. For instance, as you switch from English to German, you should find the new Optimum point size for the German text. Once you have this new Optimum point size, all text object groups should be using that Optimum point size with Auto size disabled.

If you are animating any part of your UI that includes text objects, those text objects should have auto size disabled. There is no reason to have auto size remain enabled especially when animating those objects.

I haven’t looked at the code, maybe it’s implemented that way already or maybe it makes no sense what I’m going to say, but perhaps some sort of binary-search like auto size algorithm would improve performance?

It is implemented using binary search.

Reducing the point size accuracy which is at 0.05 to something higher like 0.25 or 0.5 would reduce the number of iterations by a few but those gains will never be as significant as using this feature in a conservative way and only when it is needed.

To quote Spider-Man, “With great power comes great responsibility” … auto-size is a powerful feature and it must be used wisely and strategically.

P.S. The above doesn’t mean I won’t keep looking for ways to potentially improve upon this feature but more importantly the overall performance of the parser and layout system which would yield better overall gains.

1 Like

Ok, thank you for the details.
I guess I can keep in cache the evaluated size when I need a resize to search inside dictionnary.

I got all explaination i needed :slight_smile:
TY !!!

From my experience, if you target more than one language, pretty much every text ends up using auto-size.

1 Like

Yes, and this is the problem !
I have text taht need to be translated (at any moment) inside animation.
I guess I’ll keep in cache evaluated fontsize. I’ll keep spike lag but only in the first access :slight_smile:

How is this text translated? Trying to understand the “at any moment” part.

How is this text animated? I mean from a visual point of view.

The user can clic a button to change language at any moment of the application. (I don’t like that but it’s required)

There are so many type of animation, for example a box that move with text inside and the text is manipulated (size, alpha, …). so it trigger a rebuild of textmeshpro

Is the translated text known at build time or is the text coming from user input or some external source where the text is not known ahead of time?

Moving a text object should not require a rebuild of the text object.

By size do you mean point size or scale of the text object?

Scale changes should not trigger a rebuild of the text object. Point size changes will so it is best to animate scale and not point size.

The translated text comes from and translation file with text content and sometimes it uses some unknown value like score, pseudo, location, …

For the animation, I guess we manipulate everything but I can say it because it’s designer job.
I’ll speak with them to avoid changing point size so !

Hello,

I just up this post for a last question before next release.
Can I Improve performance by reducing autosizing precision ?

I saw the parameters in the settings : “Text auto size ratios”.