Yellow-Dog-Man / Resonite-Issues

Issue repository for Resonite.
https://resonite.com
139 stars 2 forks source link

Memory leak when changing size of DynamicSpriteFont #2771

Open JackTheFoxOtter opened 2 months ago

JackTheFoxOtter commented 2 months ago

Describe the bug?

When you change the size of a DynamicSpriteFont, it seems to cause a memory leak once a glyph with the new size is being loaded.

To Reproduce

Setup a DynamicSpriteFont, create a text that displays a sprite from it, change the resolution (I increased it from 256 to 512), and force it to load a new sprite.

Expected behavior

No memory leak!

Screenshots

https://github.com/user-attachments/assets/937856f9-63c9-4eff-8af2-60ccc674ca35

Resonite Version Number

Beta 2024.8.5.1341

What Platforms does this occur on?

Windows

What headset if any do you use?

Valve Index

Log Files

J4-C - 2024.8.5.1341 - 2024-08-16 16_56_33.log

Additional Context

No response

Reporters

No response

JackTheFoxOtter commented 2 months ago

Additional info: I did this on my (.Net 8.0) headless, which appears unaffected, it only memory leaked my client.

stiefeljackal commented 2 months ago

Duplicate of #88

JackTheFoxOtter commented 2 months ago

Kind of, but they might be related. #88 describes memory allocation issues for the StaticFont, this one is for the DynamicSpriteFont.

JackTheFoxOtter commented 2 months ago

Also for whatever reason I can't comment / upvote #88, looks like the issue is bugged (?)

stiefeljackal commented 2 months ago

Kind of, but they might be related. #88 describes memory allocation issues for the StaticFont, this one is for the DynamicSpriteFont.

Related, yes. However, they do follow the same logic as far as how the engine handles its font allocation.

Frooxius commented 2 months ago

These are sufficiently different implementations that the underlying cause can be very different.

Let's keep both open for now.

stiefeljackal commented 2 months ago

An additional investigation into this issue has pinpointed the cause of the excessive memory allocation to continuously occur in the method PackGlyphs in FrooxEngine.Font. To preface, this is in no way suggesting that this method needs to be fixed as outside parameters might need to be addressed as well. This purpose of his post is to provide the source of the memory issue and a possible lead to addressing the issue.

PackGlyphs utilizes a while loop to assist in the glyph atlas allocation. This loop somehow never terminates when MaxSize is set to certain values as described in this issue. Additionally, it appears that this issue may only occur for certain textures. To demonstrate this, an experiment was conducted and recorded. Within this experiment, two mods were used to help provide diagnostic information: !Console is used for logging mod output and Jworkz.ResoniteRandoFixes is used for simply printing the start and end of the PackGlyphs method call.

Please pardon the quality of the video as GitHub limits these to only 10 MB max, and this experiment lasted slightly longer. I do have the original video that can be sent upon request.

https://github.com/user-attachments/assets/4a1bc1e3-f7cf-4f61-bee5-f5f0de049ba3

Before recording, the following items were setup:

In the video, the following occurs in this order:

  1. MaxSize for DynamicSpriteFont is set to 512.
  2. Text content is updated to "" and parsed to show the default particle texture. Notice that the console printed out messages for "Packing glyphs" and "Done packing" to indicate that the glyph allocation had occurred and completed. Allocations for DynamicSpriteFont do not show the asset URL and instead displays an empty string (i.e., "Done packing glyphs for !" and "Packing Glyphas for . Entering While loop.").
  3. MaxSize for DynamicSpriteFont is set to 777.
  4. Text content is updated to "" and parsed to show the default particle texture. The glyph allocation occurs and displays a printed message.
  5. Text content is updated to "<sprite name" for the time being. Text is displayed as is and the console does not show new messages.
  6. The "Sprite Astroid.png" texture is spawned out and is used to replace the current texture for the Dynamic SpriteFont entries, "A" and "B" being those entries.
  7. Text content is updated to "" and is not parsed. Notice that there is only a "Packing glyphs" message without a "Done packing" message. Additionally, notice how the text field displays "" and yet the rendered text only shows "<sprite name=B" as well as the RAM utilization increasing. Within that method, the while loop does not terminate, causing the allocation to occur over and over again.

This behavior was also witnessed in another investigation that was conducted for #88. Although both components (StaticFont and DynamicSpriteFont) utilize sufficiently different implementations, they both utilize FrooxEngine.Font and the underlying PackGlyphs method and they both exhibit the same excessive memory allocation behavior that never ends when a sizing property is altered. This is just merely a conclusion after conducting the experiment above and the one in #88.