Huge hitch on asynchronously loaded scene addition to the running scene

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Ricard Rovira

I’m getting a huge hitch on loading a scene (10 seconds in editor) using an asynchronous loading module.

It’s an asset that when preloaded into the scene the simple and synchronous way makes the play in editor take 10 seconds to launch, so I’m trying to be more responsive by loading in background.

This part flies like a breeze (the actual loading, on another thread):

godot::Ref<godot::PackedScene> scene = godot::ResourceLoader::get_singleton()->load(hullPath, "PackedScene");
godot::Node* spaceship = scene->instance();
promisedSpaceship.extractPromise().set_value(spaceship);

Then this takes ten seconds (since the node is already loaded and instanced, I’d assume it would be fast… this is called synchronously):

godot::Node* finalNode = nodeFuture.get();
if (finalNode->is_class("Spatial")) {
    ((godot::Spatial*) finalNode)->set_transform(startingTransform);
}
this->replace_by(finalNode);

I’d assume that the most time would be consumed by the “load” call. But it’s the addition to the tree that creates the huge slowdown.

What can be done from the loading thread for it to bear those 10 seconds instead of the main thread?

:bust_in_silhouette: Reply From: Zylann

To sum it up:

  • Loading resources in a thread should be fine.
  • Instancing a scene… I’m not sure but I don’t see what could go wrong since it remains pretty isolated.
  • Adding to the tree: nope.

Make sure your visual, audio and physics servers are configured in such a way their API is thread-safe (at least don’t set them to be “single-unsafe”).

Assuming thread safety is respected, the slowness could come from mainly two factors:

  • There is an absurd amount of nodes as child of the branch you are adding
  • Something is executing in ENTER_TREE or READY notification of the nodes you are adding, and that thing has to deal with a huge amount of data/operations (or queries to visual or physics server)

Hard to say how to proceed without knowing which one is going on. You may want to narrow down your profiling a bit further.

I’m not adding to the scene tree from a thread. The inclusion to the tree is the only thing that I’m doing in the main thread (second code bit). I’ll investigate further, it’s probably my fault but I don’t see where.
When I’m back home I’ll test if the ready function is the culprit, it’s my main suspect.

Ricard Rovira | 2019-12-02 13:47

I was indeed doing some heavy work on the ready override. I’ve moved it to the init override, but the hang still stands for it’s well over 10 seconds. I suspect std::future and std::promise lock, even using the std::future::wait-for(0) recommended by everyone.

Ricard Rovira | 2019-12-03 08:55

What is the heavy work?

Zylann | 2019-12-03 21:44