From f99c6b3ecd6e91eb0a5caa96bfb71ee03f5018dd Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Thu, 5 Jun 2025 19:59:45 +0100 Subject: [PATCH] `SceneTreeFTI` - Fix `force_update` flag for invisible nodes --- scene/main/scene_tree_fti.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/scene/main/scene_tree_fti.cpp b/scene/main/scene_tree_fti.cpp index 8a832c852ec..b4f4e6d3bb8 100644 --- a/scene/main/scene_tree_fti.cpp +++ b/scene/main/scene_tree_fti.cpp @@ -288,7 +288,12 @@ void SceneTreeFTI::_create_depth_lists() { } #endif + // Prevent being added to the dest_list twice when on + // the frame_xform_list AND the frame_xform_list_forced. if ((l == 0) && s->data.fti_frame_xform_force_update) { +#ifdef GODOT_SCENE_TREE_FTI_EXTRA_CHECKS + DEV_ASSERT(data.frame_xform_list_forced.find(s) != -1); +#endif continue; } @@ -563,11 +568,6 @@ void SceneTreeFTI::_update_dirty_spatials(Node *p_node, uint32_t p_current_half_ // Upload to VisualServer the interpolated global xform. s->fti_update_servers_xform(); - // Only do this at most for one frame, - // it is used to catch objects being removed from the tick lists - // that have a deferred frame update. - s->data.fti_frame_xform_force_update = false; - // Ensure branches are only processed once on each traversal. s->data.fti_processed = true; @@ -706,6 +706,17 @@ void SceneTreeFTI::frame_update(Node *p_root, bool p_frame_start) { #endif // not GODOT_SCENE_TREE_FTI_VERIFY + // In theory we could clear the `force_update` flags from the nodes in the traversal. + // The problem is that hidden nodes are not recursed into, therefore the flags would + // never get cleared and could get out of sync with the forced list. + // So instead we are clearing them here manually. + // This is not ideal in terms of cache coherence so perhaps another method can be + // explored in future. + uint32_t forced_list_size = data.frame_xform_list_forced.size(); + for (uint32_t n = 0; n < forced_list_size; n++) { + Spatial *s = data.frame_xform_list_forced[n]; + s->data.fti_frame_xform_force_update = false; + } data.frame_xform_list_forced.clear(); if (!p_frame_start && data.periodic_debug_log) {