Skip to content

Commit 1c056c7

Browse files
committed
Merge pull request godotengine#107481 from lawnjelly/localvector_children
Use `LocalVector` for `Node3D` and `CanvasItem` children
2 parents 3fa7c65 + af2b9be commit 1c056c7

File tree

4 files changed

+91
-33
lines changed

4 files changed

+91
-33
lines changed

scene/3d/node_3d.cpp

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,15 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) {
108108
return;
109109
}
110110

111-
for (Node3D *&E : data.children) {
112-
if (E->data.top_level) {
113-
continue; //don't propagate to a top_level
111+
for (uint32_t n = 0; n < data.node3d_children.size(); n++) {
112+
Node3D *s = data.node3d_children[n];
113+
114+
// Don't propagate to a toplevel.
115+
if (!s->data.top_level) {
116+
s->_propagate_transform_changed(p_origin);
114117
}
115-
E->_propagate_transform_changed(p_origin);
116118
}
119+
117120
#ifdef TOOLS_ENABLED
118121
if ((!data.gizmos.is_empty() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
119122
#else
@@ -148,9 +151,11 @@ void Node3D::_notification(int p_what) {
148151
}
149152

150153
if (data.parent) {
151-
data.C = data.parent->data.children.push_back(this);
152-
} else {
153-
data.C = nullptr;
154+
data.index_in_parent = data.parent->data.node3d_children.size();
155+
data.parent->data.node3d_children.push_back(this);
156+
} else if (data.index_in_parent != UINT32_MAX) {
157+
data.index_in_parent = UINT32_MAX;
158+
ERR_PRINT("Node3D ENTER_TREE detected without EXIT_TREE, recovering.");
154159
}
155160

156161
if (data.top_level && !Engine::get_singleton()->is_editor_hint()) {
@@ -202,11 +207,27 @@ void Node3D::_notification(int p_what) {
202207
if (xform_change.in_list()) {
203208
get_tree()->xform_change_list.remove(&xform_change);
204209
}
205-
if (data.C) {
206-
data.parent->data.children.erase(data.C);
210+
211+
if (data.parent) {
212+
if (data.index_in_parent != UINT32_MAX) {
213+
// Aliases
214+
uint32_t c = data.index_in_parent;
215+
LocalVector<Node3D *> &parent_children = data.parent->data.node3d_children;
216+
217+
parent_children.remove_at_unordered(c);
218+
219+
// After unordered remove, we need to inform the moved child
220+
// what their new id is in the parent children list.
221+
if (parent_children.size() > c) {
222+
parent_children[c]->data.index_in_parent = c;
223+
}
224+
} else {
225+
ERR_PRINT("Node3D index_in_parent unset at EXIT_TREE.");
226+
}
207227
}
228+
data.index_in_parent = UINT32_MAX;
229+
208230
data.parent = nullptr;
209-
data.C = nullptr;
210231
_update_visibility_parent(true);
211232
_disable_client_physics_interpolation();
212233
} break;
@@ -1070,11 +1091,12 @@ void Node3D::_propagate_visibility_changed() {
10701091
}
10711092
#endif
10721093

1073-
for (Node3D *c : data.children) {
1074-
if (!c || !c->data.visible) {
1075-
continue;
1094+
for (uint32_t n = 0; n < data.node3d_children.size(); n++) {
1095+
Node3D *s = data.node3d_children[n];
1096+
1097+
if (s->data.visible) {
1098+
s->_propagate_visibility_changed();
10761099
}
1077-
c->_propagate_visibility_changed();
10781100
}
10791101
}
10801102

@@ -1307,7 +1329,7 @@ void Node3D::_update_visibility_parent(bool p_update_root) {
13071329
RS::get_singleton()->instance_set_visibility_parent(vi->get_instance(), data.visibility_parent);
13081330
}
13091331

1310-
for (Node3D *c : data.children) {
1332+
for (Node3D *c : data.node3d_children) {
13111333
c->_update_visibility_parent(false);
13121334
}
13131335
}

scene/3d/node_3d.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,12 @@ class Node3D : public Node {
150150
RID visibility_parent;
151151

152152
Node3D *parent = nullptr;
153-
List<Node3D *> children;
154-
List<Node3D *>::Element *C = nullptr;
153+
154+
// An unordered vector of `Spatial` children only.
155+
// This is a subset of the `Node::children`, purely
156+
// an optimization for faster traversal.
157+
LocalVector<Node3D *> node3d_children;
158+
uint32_t index_in_parent = UINT32_MAX;
155159

156160
ClientPhysicsInterpolationData *client_physics_interpolation_data = nullptr;
157161

scene/main/canvas_item.cpp

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,15 @@ void CanvasItem::_notification(int p_what) {
317317

318318
if (ci) {
319319
parent_visible_in_tree = ci->is_visible_in_tree();
320-
C = ci->children_items.push_back(this);
320+
321+
data.index_in_parent = ci->data.canvas_item_children.size();
322+
ci->data.canvas_item_children.push_back(this);
321323
} else {
324+
if (data.index_in_parent != UINT32_MAX) {
325+
data.index_in_parent = UINT32_MAX;
326+
ERR_PRINT("CanvasItem ENTER_TREE detected without EXIT_TREE, recovering.");
327+
}
328+
322329
CanvasLayer *cl = Object::cast_to<CanvasLayer>(parent);
323330

324331
if (cl) {
@@ -388,10 +395,27 @@ void CanvasItem::_notification(int p_what) {
388395
get_tree()->xform_change_list.remove(&xform_change);
389396
}
390397
_exit_canvas();
391-
if (C) {
392-
Object::cast_to<CanvasItem>(get_parent())->children_items.erase(C);
393-
C = nullptr;
398+
399+
CanvasItem *parent = Object::cast_to<CanvasItem>(get_parent());
400+
if (parent) {
401+
if (data.index_in_parent != UINT32_MAX) {
402+
// Aliases
403+
uint32_t c = data.index_in_parent;
404+
LocalVector<CanvasItem *> &parent_children = parent->data.canvas_item_children;
405+
406+
parent_children.remove_at_unordered(c);
407+
408+
// After unordered remove, we need to inform the moved child
409+
// what their new id is in the parent children list.
410+
if (parent_children.size() > c) {
411+
parent_children[c]->data.index_in_parent = c;
412+
}
413+
} else {
414+
ERR_PRINT("CanvasItem index_in_parent unset at EXIT_TREE.");
415+
}
394416
}
417+
data.index_in_parent = UINT32_MAX;
418+
395419
if (window) {
396420
window->disconnect(SceneStringName(visibility_changed), callable_mp(this, &CanvasItem::_window_visibility_changed));
397421
window = nullptr;
@@ -1057,11 +1081,11 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) {
10571081
}
10581082
}
10591083

1060-
for (CanvasItem *ci : p_node->children_items) {
1061-
if (ci->top_level) {
1062-
continue;
1084+
for (uint32_t n = 0; n < p_node->data.canvas_item_children.size(); n++) {
1085+
CanvasItem *ci = p_node->data.canvas_item_children[n];
1086+
if (!ci->top_level) {
1087+
_notify_transform(ci);
10631088
}
1064-
_notify_transform(ci);
10651089
}
10661090
}
10671091

@@ -1612,9 +1636,11 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
16121636
_update_self_texture_filter(texture_filter_cache);
16131637

16141638
if (p_propagate) {
1615-
for (CanvasItem *E : children_items) {
1616-
if (!E->top_level && E->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
1617-
E->_update_texture_filter_changed(true);
1639+
for (uint32_t n = 0; n < data.canvas_item_children.size(); n++) {
1640+
CanvasItem *ci = data.canvas_item_children[n];
1641+
1642+
if (!ci->top_level && ci->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
1643+
ci->_update_texture_filter_changed(true);
16181644
}
16191645
}
16201646
}
@@ -1666,9 +1692,10 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
16661692
_update_self_texture_repeat(texture_repeat_cache);
16671693

16681694
if (p_propagate) {
1669-
for (CanvasItem *E : children_items) {
1670-
if (!E->top_level && E->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
1671-
E->_update_texture_repeat_changed(true);
1695+
for (uint32_t n = 0; n < data.canvas_item_children.size(); n++) {
1696+
CanvasItem *ci = data.canvas_item_children[n];
1697+
if (!ci->top_level && ci->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
1698+
ci->_update_texture_repeat_changed(true);
16721699
}
16731700
}
16741701
}

scene/main/canvas_item.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,13 @@ class CanvasItem : public Node {
8383
Color modulate = Color(1, 1, 1, 1);
8484
Color self_modulate = Color(1, 1, 1, 1);
8585

86-
List<CanvasItem *> children_items;
87-
List<CanvasItem *>::Element *C = nullptr;
86+
struct Data {
87+
// An unordered vector of `CanvasItem` children only.
88+
// This is a subset of the `Node::children`, purely
89+
// an optimization for faster traversal.
90+
LocalVector<CanvasItem *> canvas_item_children;
91+
uint32_t index_in_parent = UINT32_MAX;
92+
} data;
8893

8994
int light_mask = 1;
9095
uint32_t visibility_layer = 1;

0 commit comments

Comments
 (0)