godotengine / godot

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

Threaded resource loading can still cause stutters #80770

Open KoBeWi opened 1 year ago

KoBeWi commented 1 year ago

Godot version

4.2 dev3

System information

Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1060 (NVIDIA; 30.0.15.1403) - Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz (8 Threads)

Issue description

I have a title screen with some big animation divided into multiple spritesheets. Only the first spritesheet is loaded with the scene, for other spritesheets I used threaded loading to make loading faster and also avoid stutters. Unfortunately it doesn't seem to help. ResourceLoader.load_threaded_get(current_loaded_texture) specifically causes stutters (I do check for THREAD_LOAD_LOADED).

I attached MRP that displays the issue quite clearly. It's best observed in a non-dev build.

I think #79117 is similar, but it mentions load_threaded_request() instead.

Steps to reproduce

  1. Open the MRP
  2. Run it
  3. Notice that the animation (the camera movement) has stutters
  4. Press any key to reload the scene. It's best to see it multiple times
  5. In the main scene click the root Node and disable use_textures
  6. Run the project again. load_threaded_get() is no longer called and the animation is smooth

Minimal reproduction project

https://ufile.io/4ndknuqp (the project was too big for direct upload)

smix8 commented 1 year ago

The RenderingServer is single-threaded.

What this and the other issue have imo in common is the misunderstanding what the Resourceloader threaded can help with.

The Resourceloader threaded can only help with stutters caused by IO loading.

The Resourceloader threaded can not help with stutters caused by server setup, e.g. a single-threaded RenderingServer that is stalled and takes too long to setup a new 4k texture.

E.g. if you load a 3D character mesh with full assets like materials and 4k texture in Godot with background threads you are guaranteed to have unsolvable runtime stutters because the RenderingServer can not handle this setup in time after the threaded loading was finished as the servers have no time sliced setups for heavy assets.

KoBeWi commented 1 year ago

I thought there were a few threading improvements that should make it possible to avoid such issues. E.g. this PR #45852

Koalamana9 commented 10 months ago

Unfortunately this is still relevant in 4.2 beta 5, load_threaded_get causes noticeable stutters when loading a single 4k texture while game is playing, and shader caching is not the cause of these stutters, it's something else.

lanalancia commented 4 months ago

Still relevant on 4.2.2 stable

My workaround is using load in a thread instead:

func _ready():
   Thread.new().start(instantiate_threaded)

func instantiate_threaded():
    var scene = load(SCENE).instantiate()
    parent.add_child.call_deferred(scene) # must use call_deferred, otherwise won't add a child