Skip to content

Commit e9299d8

Browse files
committed
optimize
1 parent 3c50159 commit e9299d8

File tree

3 files changed

+85
-3
lines changed

3 files changed

+85
-3
lines changed

scene/main/node.cpp

+60
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ void Node::_notification(int p_notification) {
239239
memdelete(data.path_cache);
240240
data.path_cache = nullptr;
241241
}
242+
// reset the cached_hierarchy_path
243+
data.cached_hierarchy_path.clear();
242244
} break;
243245

244246
case NOTIFICATION_PAUSED: {
@@ -577,6 +579,9 @@ void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) {
577579
data.children_cache[i]->data.index = i;
578580
}
579581
}
582+
583+
data.cached_hierarchy_path.clear();
584+
580585
// notification second
581586
move_child_notify(p_child);
582587
notification(NOTIFICATION_CHILD_ORDER_CHANGED);
@@ -2049,6 +2054,61 @@ bool Node::is_ancestor_of(const Node *p_node) const {
20492054
return false;
20502055
}
20512056

2057+
void Node::precompute_hierarchy_path() const {
2058+
if (data.cached_hierarchy_path.size() == data.depth) {
2059+
// Skip if already cached and valid
2060+
return;
2061+
}
2062+
2063+
// Resize to avoid reallocation
2064+
data.cached_hierarchy_path.resize(data.depth);
2065+
2066+
// Fill the path from the node to the root
2067+
const Node *n = this;
2068+
for (int i = data.depth - 1; i >= 0; --i) {
2069+
data.cached_hierarchy_path.write[i] = n->get_index();
2070+
n = n->data.parent;
2071+
}
2072+
}
2073+
2074+
bool Node::is_greater_than_cached(const Node *p_node) const {
2075+
// Ensure paths are precomputed
2076+
precompute_hierarchy_path();
2077+
p_node->precompute_hierarchy_path();
2078+
2079+
const Vector<int> &this_path = data.cached_hierarchy_path;
2080+
const Vector<int> &that_path = p_node->data.cached_hierarchy_path;
2081+
2082+
const int this_size = this_path.size();
2083+
const int that_size = that_path.size();
2084+
const int min_size = MIN(this_size, that_size);
2085+
2086+
const int *this_data = this_path.ptr();
2087+
const int *that_data = that_path.ptr();
2088+
2089+
int cmp_result = memcmp(this_data, that_data, min_size * sizeof(int));
2090+
if (cmp_result != 0) {
2091+
// cmp_result > 0 means the first mismatching byte in this_data is bigger
2092+
// cmp_result < 0 means the first mismatching byte in this_data is smaller
2093+
return cmp_result > 0;
2094+
}
2095+
2096+
return this_size > that_size;
2097+
//
2098+
// // Compare paths lexicographically
2099+
// int min_size = MIN(this_path.size(), that_path.size());
2100+
// for (int i = 0; i < min_size; ++i) {
2101+
// if (this_path[i] != that_path[i]) {
2102+
// return this_path[i] > that_path[i];
2103+
// }
2104+
// }
2105+
2106+
// If paths are equal up to the shortest length, the deeper node is greater
2107+
// return this_path.size() > that_path.size();
2108+
}
2109+
2110+
2111+
20522112
bool Node::is_greater_than(const Node *p_node) const {
20532113
ERR_FAIL_NULL_V(p_node, false);
20542114
ERR_FAIL_COND_V(!data.inside_tree, false);

scene/main/node.h

+17-3
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,23 @@ class Node : public Object {
150150
};
151151

152152
struct ComparatorWithPriority {
153-
bool operator()(const Node *p_a, const Node *p_b) const { return p_b->data.process_priority == p_a->data.process_priority ? p_b->is_greater_than(p_a) : p_b->data.process_priority > p_a->data.process_priority; }
153+
bool operator()(const Node *p_a, const Node *p_b) const {
154+
if (p_b->data.process_priority == p_a->data.process_priority) {
155+
return p_b->is_greater_than_cached(p_a);
156+
} else {
157+
return p_b->data.process_priority > p_a->data.process_priority;
158+
}
159+
}
154160
};
155161

156162
struct ComparatorWithPhysicsPriority {
157-
bool operator()(const Node *p_a, const Node *p_b) const { return p_b->data.physics_process_priority == p_a->data.physics_process_priority ? p_b->is_greater_than(p_a) : p_b->data.physics_process_priority > p_a->data.physics_process_priority; }
163+
bool operator()(const Node *p_a, const Node *p_b) const {
164+
if (p_b->data.physics_process_priority == p_a->data.physics_process_priority) {
165+
return p_b->is_greater_than_cached(p_a);
166+
} else {
167+
return p_b->data.physics_process_priority > p_a->data.physics_process_priority;
168+
}
169+
}
158170
};
159171

160172
// This Data struct is to avoid namespace pollution in derived classes.
@@ -241,7 +253,7 @@ class Node : public Object {
241253
mutable bool is_auto_translate_dirty = true;
242254

243255
mutable NodePath *path_cache = nullptr;
244-
256+
mutable Vector<int> cached_hierarchy_path;
245257
} data;
246258

247259
Ref<MultiplayerAPI> multiplayer;
@@ -451,6 +463,8 @@ class Node : public Object {
451463
_FORCE_INLINE_ bool is_inside_tree() const { return data.inside_tree; }
452464

453465
bool is_ancestor_of(const Node *p_node) const;
466+
void precompute_hierarchy_path() const;
467+
bool is_greater_than_cached(const Node *p_node) const;
454468
bool is_greater_than(const Node *p_node) const;
455469

456470
NodePath get_path() const;

scene/main/scene_tree.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,14 @@ void SceneTree::_process_group(ProcessGroup *p_group, bool p_physics) {
928928
return;
929929
}
930930

931+
// Precompute hierarchy paths for all nodes before sorting to prevent extra work
932+
{
933+
ZoneScopedN("SceneTree::_process_group Precompute Hierarchy Paths");
934+
for (Node *node : nodes) {
935+
node->precompute_hierarchy_path();
936+
}
937+
}
938+
931939
if (p_physics) {
932940
if (p_group->physics_node_order_dirty) {
933941
ZoneScopedN("SceneTree::_process_group Physics Node Sort");

0 commit comments

Comments
 (0)