Hey, after updating to TMPro 2.1.4 on unity 2019.4.21f1 a large number of players of our game are experiencing a native crash coming from TMPro when one of our game objects gets enabled. I’m trying to figure out how I could possibly debug this to fix it
I notice that the FontEngine documentation does not reference the GetGlyphIndex function, but does have a TryGetGlyphIndex which makes me think that GetGlyphIndex can fail?
Any help would be appreciated, truncated call stack below
Are you able to reproduce the behavior on your end?
If so, any chance you could submit a bug report with project for me to look at or provide me with some repro to look at?
EDIT: If you are unable to submit a bug report or provide me with access to the project, you can always try to make the following change around line 725 in the TMP_FontAsset.cs file.
if (m_AtlasPopulationMode == AtlasPopulationMode.Dynamic)
{
if (FontEngine.LoadFontFace(sourceFontFile, m_FaceInfo.pointSize) != FontEngineError.Success)
{
Debug.LogWarning("Unable to load font face for [" + sourceFontFile.name + "].");
return;
}
}
If you then get a log warning, it would indicate some issue loading the font face and possibly some issue with the font object.
P.S. If this crash only occurs in a build, you will most likely need to make this change in the Global Package Cache to make it persistent so we can figure out if the issue is font object related.
Thanks for the response, I’ll try to create a project which mimics the issue later this week (I cant distribute the project which is experiencing the issue)
Ill also make that change later this week to see if I get the warning
Just been going through the changes we made between releases and we added a call to Resources.UnloadUnusedAssets()… I imagine that’s probably actually what the cause of the issue is
No clue how that functions with referenced Font assets
The reason this issue is happening now is the result of recent changes I made to reduce to memory overhead when using Font objects. In previous releases, the FontEngine would use GetFontData() on the font object which would return a copy of a byte[ ] that contains the entire font file. Given this was a copy, the FontEngine would cache it resulting in the overall memory overhead being 3X the size of the font file. With the change, the font object returns a reference to the font data so that we only get 1x of memory overhead but as we are seeing now, if this font object is unloaded, the FontEngine ends up using re-allocated memory.
What surprises me is Resources.UnloadUnusedAssets() unloading the font data although this font is referenced by the font asset where as such it should not unload it.
This new piece of information does give me something to look at so again thanks for sharing.
Essentially, Players connect to a lobby, then load into an online match within a different scene and server.
They play their game out, and when they return to the Lobby we call Resources.UnloadUnusedAssets().
When they go into the next game, the first object they load which has a TMP pro asset on seems to have a chance of failing, because it not a 100% repro. These game objects are loaded from an addressable package which is probably useful info.
Tomorrow, Ill do a build with the call to Resources.UnloadUnusedAssets() and one without to test
Maybe as a result of Addressable being Async we end up with the font asset trying to access the font object before it was reloaded.
By the way, I did add a new API to the FontEngine in UnityEngine.TextCore.LowLevel
/// <summary>
/// Unloads all currently loaded font faces and removes them from the cache.
/// </summary>
/// <returns>A value of zero (0) if the font faces were successfully unloaded and removed from the cache.</returns>
public static FontEngineError UnloadAllFontFaces()
Assuming this is not an Async issue, calling FontEngine.UnloadAllFontFaces() right after Resources.UnloadUnusedAssets() might do the trick. This would force the FontEngine to re-fetch the font data from the font object.
Calling UnloadAllFontFaces() after the call to Resources.UnloadUnusedAssets() causes it to not crash when we load in more prefabs with TMPro text on, however loading a couple of the assets in succession causes the new ones to not render. So for now, my fix will be to remove my call to UnloadUnusedAssets()
I had a shot at making a small test project and was unable to do so. These assets that are loading in are years old by this point, and recreating it just didn’t yield the same results.
Now that we know the issue is related to unloading of resources, I’ll take a closer look into this. More specifically, I would like to understand why the font data of a font object which is referenced by a font asset is getting flushed. This might be a separate bug / unexpected behavior.
Besides the above, calling UnloadAllFontFaces() only clears the FontEngine font face cache which means the next time a character needs to be added to a font asset, the font face will have to be loaded from the font file again instead of from the cache. This has an impact on performance but should not affect anything already contained in the font asset. So I would like to figure out why this is resulting in some of the text objects not rendering correctly.
I think we have a similar problem. But it appears in the editor. After changing the code, we click on Play, then the editor closes with the following error:
Unfortunately, we can’t repeat on a test project.
The problem goes away if we replace “Atlas popuplation mode” from Dynamic to Static in our project. But we need Dynamic mode.
This issue would occur when a font face was previously loaded from a Font object where this font object (more specifically the font data which is a byte array of the font file) is destroyed / deallocated somehow.
Similar to the other user, are you using Resources.UnloadUnusedAssets() or creating new font assets at runtime or loading some of these resources from an Asset Bundle or Addressables? Can you think of anything that would result in the font used by one of those font assets to be destroyed?
Do all these font assets have a reference to their source font?
See if making the following changes in the TMP_FontAsset.cs file resolves the issue.
You will need to make the changes in the Global Package Cache\packages\com.unity.textmeshpro@1.5.4\Scripts\Runtime\TMP_FontAsset.cs file in order to make these changes persistent.
If you are using Unity 2019.4 then the package location will be com.unity.textmeshpro@2.1.4. For Unity 2020 or newer, it will be com.unity.textmeshpro@3.0.4
Note that I am still unable to reproduce the issue on my end but the above change should prevent calls to FontEngine.GetGlyphIndex when unable to successfully loading the requested font face.
I get the same issue, crash every build or so… and yes I am using addressable
Will see if I can make the change
Unity 2021.1.1f1 (was doing the same on 2020.2) and TMP 3.0.4
It seem to improve it a lot for me…
Can’t log a bug report, project too big and it always fail while uploading, but if you want I can send you a link in pm to download. Just PM me