From cd9713e890a8da2b4bdba82b724ad77a1e089402 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Wed, 18 Jun 2025 16:02:01 +0100 Subject: [PATCH] Fast child iteration in `Node`, `Spatial`, `CanvasItem` --- core/local_vector.h | 9 +++++++++ scene/2d/canvas_item.cpp | 4 +++- scene/3d/spatial.cpp | 11 ++++------- scene/3d/spatial.h | 1 - scene/main/node.cpp | 36 ++++++++++++++++++++---------------- 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/core/local_vector.h b/core/local_vector.h index cf1a19bcd6d..5c64f76dc4e 100644 --- a/core/local_vector.h +++ b/core/local_vector.h @@ -194,6 +194,15 @@ public: return data[p_index]; } + _FORCE_INLINE_ const T &get_unchecked(U p_index) const { + DEV_ASSERT(p_index < count); + return data[p_index]; + } + _FORCE_INLINE_ T &get_unchecked(U p_index) { + DEV_ASSERT(p_index < count); + return data[p_index]; + } + void fill(T p_val) { for (U i = 0; i < count; i++) { data[i] = p_val; diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index a7d363dc41f..64a0452035e 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -1029,8 +1029,10 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) { } } + CanvasItem **children = p_node->data.canvas_item_children.ptr(); + for (uint32_t n = 0; n < p_node->data.canvas_item_children.size(); n++) { - CanvasItem *ci = p_node->data.canvas_item_children[n]; + CanvasItem *ci = children[n]; if (!ci->toplevel) { _notify_transform(ci); } diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 79f37ed89e0..6e3b8010d11 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -104,10 +104,10 @@ void Spatial::_propagate_transform_changed(Spatial *p_origin) { return; //already dirty */ - data.children_lock++; + Spatial **children = data.spatial_children.ptr(); for (uint32_t n = 0; n < data.spatial_children.size(); n++) { - Spatial *s = data.spatial_children[n]; + Spatial *s = children[n]; // Don't propagate to a toplevel. if (!s->data.toplevel_active) { @@ -123,8 +123,6 @@ void Spatial::_propagate_transform_changed(Spatial *p_origin) { get_tree()->xform_change_list.add(&xform_change); } data.dirty |= DIRTY_GLOBAL | DIRTY_GLOBAL_INTERPOLATED; - - data.children_lock--; } void Spatial::notification_callback(int p_message_type) { @@ -872,7 +870,7 @@ void Spatial::_propagate_visibility_changed() { #endif for (uint32_t n = 0; n < data.spatial_children.size(); n++) { - Spatial *s = data.spatial_children[n]; + Spatial *s = data.spatial_children.get_unchecked(n); if (s->data.visible) { s->_propagate_visibility_changed(); @@ -901,7 +899,7 @@ void Spatial::_propagate_merging_allowed(bool p_merging_allowed) { data.merging_allowed = p_merging_allowed; for (uint32_t n = 0; n < data.spatial_children.size(); n++) { - Spatial *s = data.spatial_children[n]; + Spatial *s = data.spatial_children.get_unchecked(n); s->_propagate_merging_allowed(p_merging_allowed); } } @@ -1248,7 +1246,6 @@ Spatial::Spatial() : _define_ancestry(AncestralClass::SPATIAL); data.dirty = DIRTY_NONE; - data.children_lock = 0; data.ignore_notification = false; data.toplevel = false; diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 240cf9ce033..93f749d1140 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -133,7 +133,6 @@ private: bool merging_allowed : 1; - int children_lock; Spatial *parent; // An unordered vector of `Spatial` children only. diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 875a75bc0cd..3a54e4cf2b0 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -183,7 +183,7 @@ void Node::_propagate_ready() { data.ready_notified = true; data.blocked++; for (int i = 0; i < data.children.size(); i++) { - data.children[i]->_propagate_ready(); + data.children.get_unchecked(i)->_propagate_ready(); } data.blocked--; @@ -235,7 +235,7 @@ void Node::_propagate_physics_interpolation_reset_requested(bool p_requested) { data.blocked++; for (int i = 0; i < data.children.size(); i++) { - data.children[i]->_propagate_physics_interpolation_reset_requested(p_requested); + data.children.get_unchecked(i)->_propagate_physics_interpolation_reset_requested(p_requested); } data.blocked--; } @@ -281,8 +281,9 @@ void Node::_propagate_enter_tree() { //block while adding children for (int i = 0; i < data.children.size(); i++) { - if (!data.children[i]->is_inside_tree()) { // could have been added in enter_tree - data.children[i]->_propagate_enter_tree(); + Node *child = data.children.get_unchecked(i); + if (!child->is_inside_tree()) { // could have been added in enter_tree + child->_propagate_enter_tree(); } } @@ -429,7 +430,7 @@ void Node::move_child(Node *p_child, int p_pos) { data.blocked++; //new pos first for (int i = motion_from; i <= motion_to; i++) { - data.children[i]->data.pos = i; + data.children.get_unchecked(i)->data.pos = i; } // notification second move_child_notify(p_child); @@ -456,7 +457,7 @@ void Node::_propagate_groups_dirty() { } for (int i = 0; i < data.children.size(); i++) { - data.children[i]->_propagate_groups_dirty(); + data.children.get_unchecked(i)->_propagate_groups_dirty(); } } @@ -563,9 +564,11 @@ void Node::_propagate_pause_owner(Node *p_owner) { void Node::_propagate_pause_change_notification(int p_notification) { notification(p_notification); + Node **children = data.children.ptr(); + for (int i = 0; i < data.children.size(); i++) { - if (data.children[i]->data.pause_mode == PAUSE_MODE_INHERIT) { - data.children[i]->_propagate_pause_change_notification(p_notification); + if (children[i]->data.pause_mode == PAUSE_MODE_INHERIT) { + children[i]->_propagate_pause_change_notification(p_notification); } } } @@ -575,7 +578,7 @@ void Node::set_network_master(int p_peer_id, bool p_recursive) { if (p_recursive) { for (int i = 0; i < data.children.size(); i++) { - data.children[i]->set_network_master(p_peer_id, true); + data.children.get_unchecked(i)->set_network_master(p_peer_id, true); } } } @@ -1400,7 +1403,8 @@ int Node::get_child_count() const { Node *Node::get_child(int p_index) const { ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr); - return data.children[p_index]; + // Index already checked above, can use unsafe version here. + return data.children.get_unchecked(p_index); } Node *Node::_get_child_by_name(const StringName &p_name) const { @@ -1468,7 +1472,7 @@ Node *Node::get_node_or_null(const NodePath &p_path) const { next = nullptr; for (int j = 0; j < current->data.children.size(); j++) { - Node *child = current->data.children[j]; + Node *child = current->data.children.get_unchecked(j); if (child->data.name == name) { next = child; @@ -1936,7 +1940,7 @@ void Node::_print_tree(const Node *p_node) { void Node::_propagate_reverse_notification(int p_notification) { data.blocked++; for (int i = data.children.size() - 1; i >= 0; i--) { - data.children[i]->_propagate_reverse_notification(p_notification); + data.children.get_unchecked(i)->_propagate_reverse_notification(p_notification); } notification(p_notification, true); @@ -1953,7 +1957,7 @@ void Node::_propagate_deferred_notification(int p_notification, bool p_reverse) } for (int i = 0; i < data.children.size(); i++) { - data.children[i]->_propagate_deferred_notification(p_notification, p_reverse); + data.children.get_unchecked(i)->_propagate_deferred_notification(p_notification, p_reverse); } if (p_reverse) { @@ -1968,7 +1972,7 @@ void Node::propagate_notification(int p_notification) { notification(p_notification); for (int i = 0; i < data.children.size(); i++) { - data.children[i]->propagate_notification(p_notification); + data.children.get_unchecked(i)->propagate_notification(p_notification); } data.blocked--; } @@ -1981,7 +1985,7 @@ void Node::propagate_call(const StringName &p_method, const Array &p_args, const } for (int i = 0; i < data.children.size(); i++) { - data.children[i]->propagate_call(p_method, p_args, p_parent_first); + data.children.get_unchecked(i)->propagate_call(p_method, p_args, p_parent_first); } if (!p_parent_first && has_method(p_method)) { @@ -1998,7 +2002,7 @@ void Node::_propagate_replace_owner(Node *p_owner, Node *p_by_owner) { data.blocked++; for (int i = 0; i < data.children.size(); i++) { - data.children[i]->_propagate_replace_owner(p_owner, p_by_owner); + data.children.get_unchecked(i)->_propagate_replace_owner(p_owner, p_by_owner); } data.blocked--; }