Search Unity

TextMesh Pro TextMeshProUGUI.LateUpdate() = performance spike

Discussion in 'UGUI & TextMesh Pro' started by serbusfish, Oct 9, 2018.

  1. serbusfish

    serbusfish

    Joined:
    Dec 27, 2016
    Posts:
    247
    For some reason I keep getting regular performance stutters and according to the profiler it is caused by TextMesh late update. I installed TextMeshPro today, I dont believe I have used it in a way that should cause performance issues, I created 6 separate UI objects, and one of my scripts can change the text during gameplay, that's really all i've done?
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    TextMesh Pro does use LateUpdate() to check if the scale of the text objects has changed between frames. However, unless you have a lot of text objects, you should not see any measurable performance impact from this.

    Can you post an example of the script you are using to change the text?

    P.S. In the next release of TMP due in part to the [ExecuteInEditMode] attribute being deprecated for Unity 2019.1, TextMesh Pro will be using an update manager instead of LateUpdate(). This will result in a slight performance improvement.
     
  3. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    I have 1535 TextMesh instances in scene, it takes 0.64ms.
    That's quite expensive for doing 'nothing'.

    If it would be possible to disable such detection on per-instance basis, I'd disable it on 99.5% of instances.

    If it would be possible to disable only globally for all TextMeshes, I'd be okay with that too.
    I can add component to 0.5% which would do that.

    To be sure, I'm talking about text meshes on 3d objects in 3d scene, not UGUI canvas texts.
    I can imagine it's not problem for canvas texts, there's usually no more than hundred of them.

    Unity 2018.3.2f1
     
  4. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    I was able to "optimize" it by using this inherited class instead

    Code (CSharp):
    1. public class TextMeshProFast : TMPro.TextMeshPro
    2. {
    3.     private void LateUpdate()
    4.     {
    5.         // This is defined to disable private LateUpdate in base class
    6.         // Base class implementation detects scale changes and updates text
    7.         // It takes 0.64ms for 1530 instances
    8.     }
    9. }
    10.  
    Attached profiler screenshot, this 'hack' is about 5-6x faster (measure in build)

    EDIT:
    After changing all instances to TextMeshProFast, it takes 0.12ms, that's 5.33x improvement
     

    Attached Files:

    Last edited: Jan 25, 2019
    justtime likes this.
  5. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I have replaced the use of LateUpdate in the next release of TMP for a manager which should provide some improvements. I'll re-run some benchmarks and provide results thereafter.

    In terms of your hack just be mindful that LateUpdate is mostly used to account for scaling changes on the text object. Provided the scale of your text object will not change, your teak should be fine :)
     
  6. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    Hi Stephan,
    I've encountered the issue again, it has smaller impact but it's still there.

    Since it now uses manager and InternalUpdate, I'm unable to "fix it" myself.
    Can you please make InternalUpdate public or provide some mechanism to prevent it?
    - a simple checkbox in some Advanced section of TextMeshPro would be okay (would prevent InternalUpdate registration into manager)

    I have a lot of texts in scene, which don't scale. There's no need to call method which does "nothing".
    5000 texts take 1.8 ms in Profiler, that's a lot of frame budget.

    It would be also nice to add Profiler BeginSample/EndSample around manager rebuilds, I took me a loooong time to figure out why Camera.FireOnPreCull was so slow.

    Using version 2.0.1 in Unity 2019.2.9

    Thank you!
     
  7. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    I was able to reintroduce the hack in following manner :)
    It increases a cost of OnEnable a little, but reduces update cost to zero.
    (properly implemented functionality in package would have no impact on OnEnable)

    Btw, I'm not sure about queue implementation in TMP_UpdateManager, inserts are O(1), but removals are O(n), which is a little concerning.

    EDIT: I just tested disabling 5000 regular TextMeshPro and it spend over 1000ms in "UnRegisterTextObjectForUpdate", other queues are fine, because they are cleared after processing, but update it not.

    Thankfully TextMeshProFast solves issue with disabling, because it keeps internalUpdateQueue empty :)

    Code (CSharp):
    1. using TMPro;
    2.  
    3. public class TextMeshProFast : TextMeshPro
    4. {
    5.     protected override void OnEnable()
    6.     {
    7.         // Registers into update and graphic rebuild
    8.         base.OnEnable();
    9.  
    10.         // Unregisters from everything
    11.         TMP_UpdateManager.UnRegisterTextElementForRebuild(this);
    12.  
    13.         // Registers into graphic rebuild
    14.         TMP_UpdateManager.RegisterTextElementForGraphicRebuild(this);
    15.  
    16.         // Registers into layout rebuild when needed
    17.         if (m_autoSizeTextContainer)
    18.         {
    19.             TMP_UpdateManager.RegisterTextElementForLayoutRebuild(this);
    20.         }
    21.     }
    22. }
    23.  
     
    Last edited: Oct 26, 2019
  8. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I have been thinking about this and considering adding an option to the Inspector's static pulldown options to mark the text object scale as static or add this property in the Extra Settings of the text object. This would internally exclude the text object from the internal update.

    Update
    I went ahead and adding the option in the Extra Settings as seen below

    upload_2019-10-26_15-47-38.png

    When Enabled, this will exclude the text object from InternalUpdate callbacks. As such, if the scale of the text object or potential parent changes, the text object's SDF Scale will not be updated potentially resulting in the text becoming blurry or too sharp.

    Changes to properties of the text object will continue to behave as expected.
     
    Last edited: Oct 26, 2019
  9. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    Thank you very much!
     
  10. marcel_z

    marcel_z

    Joined:
    Sep 5, 2018
    Posts:
    1
    In which release version will this be available and will it only be for the 3d Texts or also for UI?
     
  11. ProgrammingWhileSleeping

    ProgrammingWhileSleeping

    Joined:
    Nov 10, 2017
    Posts:
    17
    Bumping this thread as I have a problem here which causes 65 of my TMProUGUI instances to cause huge drawbacks to the renderer.

    upload_2020-7-12_18-30-14.png

    I can confirm that the TMProUGUI is causing it because whenever I disable that component alone, the game performs really well at 60 fps but when it's enabled it's running at around 30-45fps.
     
  12. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    You can mark the text objects with IsScaleStatic in the extra settings of the text objects. This will remove them from the update loop.
     
  13. ProgrammingWhileSleeping

    ProgrammingWhileSleeping

    Joined:
    Nov 10, 2017
    Posts:
    17
    Thank you Stephan, I don't have that option, I probably have an older version, should I update this? Or do you have another option for me to have the optimal performance. Thanks!
    upload_2020-7-18_16-48-2.png
     
  14. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    This option is only available in the latest releases.which are:

    Version 1.5.0 for Unity 2018.4
    Version 2.1.0 for Unity 2019.x
    Version 3.0.0 for Unity 2020.x
     
  15. ProgrammingWhileSleeping

    ProgrammingWhileSleeping

    Joined:
    Nov 10, 2017
    Posts:
    17
    Thanks, I haven't had the need to update it though as the conversion from TMP GUI to TMP gave a massive increase on the performance.
     
  16. iMobCoding

    iMobCoding

    Joined:
    Feb 13, 2017
    Posts:
    165
    As TMP is now almost a part of Unity core, isn't maybe better if Unity Devs add some event on scale change so you can handle it internally? Adding IsScaleStatic isn't so intuitive...
     
    Peter77 likes this.
  17. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I brought this up a few times but the issue is related to the RectTransform and the dispatcher. But having an event similar to OnRectTransformDimensionsChange but for scale would be so nice.
     
    iMobCoding likes this.
  18. jeffdyerSRTMarine

    jeffdyerSRTMarine

    Joined:
    Jan 23, 2019
    Posts:
    12
    I have a similar problem. We have an application tracking ships, each ship has a label for it's name. We now have access to over 100,000 vessel's positions and when they are all loaded (zoomed right out on map) after closing the application in editor it takes many minute to finish closing cleanly, seems to be calling the OnDestroy() method for every label which in turn calls the TMP_UpdateManager unregister methods - how can I avoid this?