godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.11k stars 20.2k forks source link

Animating FontVariations causes memory leak(?) #95427

Open juralumin opened 1 month ago

juralumin commented 1 month ago

Tested versions

Tested in 4.2.1.stable and 4.3.rc3.

System information

Godot v4.2.1.stable - Windows 10.0.22631 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3090 (NVIDIA; 31.0.15.4601) - 11th Gen Intel(R) Core(TM) i9-11900K @ 3.50GHz (16 Threads)

Issue description

When animating a FontVariation in an AnimationPlayer, ram and vram usage skyrockets. In 4.3.rc3, the Video RAM tab shows a ton of entries for an empty resource: ",Texture,1024x1024x1 LumAlpha8,2.66 MiB". The animation in question simply increased the Y scale of the font and was used so the font outline would have a consistent width as scaling normally seems to make it look a little off. It was semi-inconsistent but at times could increase ram use from 120-ish mb to over 12gb. This is especially bad when the game is maximised.

Steps to reproduce

Make a font variation and have it be animated with an AnimationPlayer. In my case it was a 1 second long animation where it starts at a higher y scale and ends at its original y scale, with elastic easing at 60fps.

Minimal reproduction project (MRP)

leak.zip

bruvzg commented 1 month ago

Currently, all font caches (for each used size and variation) exist as long as Font resource is loaded. In most cases, only a small amount of different variations and sizes are in use and there's no reason to unload them. We probably should change it to LRU, but currently you can clean the cache by calling clear_cache method of the Font.

Calinou commented 1 month ago

For animation purposes, consider using a method that doesn't require re-rendering the font every time its variation changes by a tiny amount. This will avoid stuttering during gameplay, which can occur if the requestedfont variation isn't cached (especially at large font sizes, i.e. >= 65 when taking oversampling into account).

For example, you can use multiple overlaid labels that are moved independently of each other, or a shader on a single label node that dilates/erodes it.