2
0
Эх сурвалжийг харах

`SceneTreeFTI` - Fix `force_update` flag getting out of sync with invisible nodes

If the `force_update` flag remained set after the node was removed from the update lists, the node would never be updated in future. This could occur with hidden nodes that were moved after hiding.
lawnjelly 3 сар өмнө
parent
commit
a7b7d96f96

+ 18 - 7
scene/main/scene_tree_fti.cpp

@@ -291,7 +291,12 @@ void SceneTreeFTI::_create_depth_lists() {
 			}
 			}
 #endif
 #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) {
 			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;
 				continue;
 			}
 			}
 
 
@@ -520,14 +525,14 @@ void SceneTreeFTI::_update_dirty_nodes(Node *p_node, uint32_t p_current_half_fra
 
 
 	if (p_active) {
 	if (p_active) {
 #ifdef GODOT_SCENE_TREE_FTI_PRINT_TREE
 #ifdef GODOT_SCENE_TREE_FTI_PRINT_TREE
-		bool dirty = s->data.dirty & Node3D::DIRTY_GLOBAL_INTERPOLATED;
+		bool dirty = s->_test_dirty_bits(Node3D::DIRTY_GLOBAL_INTERPOLATED_TRANSFORM);
 
 
 		if (data.periodic_debug_log && !data.use_optimized_traversal_method && !data.frame_start) {
 		if (data.periodic_debug_log && !data.use_optimized_traversal_method && !data.frame_start) {
 			String sz;
 			String sz;
 			for (int n = 0; n < p_depth; n++) {
 			for (int n = 0; n < p_depth; n++) {
 				sz += "\t";
 				sz += "\t";
 			}
 			}
-			print_line(sz + p_node->get_name() + (dirty ? " DIRTY" : "") + (s->get_transform() == Transform() ? "\t[IDENTITY]" : ""));
+			print_line(sz + p_node->get_name() + (dirty ? " DIRTY" : "") + (s->get_transform() == Transform3D() ? "\t[IDENTITY]" : ""));
 		}
 		}
 #endif
 #endif
 
 
@@ -575,11 +580,6 @@ void SceneTreeFTI::_update_dirty_nodes(Node *p_node, uint32_t p_current_half_fra
 		// Upload to RenderingServer the interpolated global xform.
 		// Upload to RenderingServer the interpolated global xform.
 		s->fti_update_servers_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.
 		// Ensure branches are only processed once on each traversal.
 		s->data.fti_processed = true;
 		s->data.fti_processed = true;
 
 
@@ -719,6 +719,17 @@ void SceneTreeFTI::frame_update(Node *p_root, bool p_frame_start) {
 
 
 #endif //  not GODOT_SCENE_TREE_FTI_VERIFY
 #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++) {
+		Node3D *s = data.frame_xform_list_forced[n];
+		s->data.fti_frame_xform_force_update = false;
+	}
 	data.frame_xform_list_forced.clear();
 	data.frame_xform_list_forced.clear();
 
 
 	if (!p_frame_start && data.periodic_debug_log) {
 	if (!p_frame_start && data.periodic_debug_log) {