Refactor Node Processing

* Node processing works on the concept of process groups.
* A node group can be inherited, run on main thread, or a sub-thread.
* Groups can be ordered.
* Process priority is now present for physics.

This is the first steps towards implementing https://github.com/godotengine/godot-proposals/issues/6424.
No threading or thread guards exist yet in most of the scene code other than Node. That will have to be added later.
This commit is contained in:
Juan Linietsky
2023-04-10 18:45:53 +02:00
parent cf8ad12b56
commit 98c655ec8d
18 changed files with 1155 additions and 186 deletions

View File

@ -33,6 +33,7 @@
#include "core/os/main_loop.h"
#include "core/os/thread_safe.h"
#include "core/templates/paged_allocator.h"
#include "core/templates/self_list.h"
#include "scene/resources/mesh.h"
@ -86,6 +87,34 @@ public:
typedef void (*IdleCallback)();
private:
CallQueue::Allocator *process_group_call_queue_allocator = nullptr;
struct ProcessGroup {
CallQueue call_queue;
Vector<Node *> nodes;
Vector<Node *> physics_nodes;
bool node_order_dirty = true;
bool physics_node_order_dirty = true;
bool removed = false;
Node *owner = nullptr;
uint64_t last_pass = 0;
};
struct ProcessGroupSort {
_FORCE_INLINE_ bool operator()(const ProcessGroup *p_left, const ProcessGroup *p_right) const;
};
PagedAllocator<ProcessGroup, true> group_allocator; // Allocate groups on pages, to enhance cache usage.
LocalVector<ProcessGroup *> process_groups;
bool process_groups_dirty = true;
LocalVector<ProcessGroup *> local_process_group_cache; // Used when processing to group what needs to
uint64_t process_last_pass = 1;
ProcessGroup default_process_group;
bool node_threading_disabled = false;
struct Group {
Vector<Node *> nodes;
bool changed = false;
@ -117,7 +146,7 @@ private:
StringName node_renamed_name = "node_renamed";
int64_t current_frame = 0;
int node_count = 0;
int nodes_in_tree_count = 0;
#ifdef TOOLS_ENABLED
Node *edited_scene_root = nullptr;
@ -134,8 +163,10 @@ private:
};
// Safety for when a node is deleted while a group is being called.
int call_lock = 0;
HashSet<Node *> call_skip; // Skip erased nodes.
bool processing = false;
int nodes_removed_on_group_call_lock = 0;
HashSet<Node *> nodes_removed_on_group_call; // Skip erased nodes.
List<ObjectID> delete_queue;
@ -143,7 +174,7 @@ private:
bool ugc_locked = false;
void _flush_ugc();
_FORCE_INLINE_ void _update_group_order(Group &g, bool p_use_priority = false);
_FORCE_INLINE_ void _update_group_order(Group &g);
TypedArray<Node> _get_nodes_in_group(const StringName &p_group);
@ -187,7 +218,15 @@ private:
void remove_from_group(const StringName &p_group, Node *p_node);
void make_group_changed(const StringName &p_group);
void _notify_group_pause(const StringName &p_group, int p_notification);
void _process_group(ProcessGroup *p_group, bool p_physics);
void _process_groups_thread(uint32_t p_index, bool p_physics);
void _process(bool p_physics);
void _remove_process_group(Node *p_node);
void _add_process_group(Node *p_node);
void _remove_node_from_process_group(Node *p_node, Node *p_owner);
void _add_node_to_process_group(Node *p_node, Node *p_owner);
void _call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
void _call_group(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
@ -383,6 +422,7 @@ public:
static void add_idle_callback(IdleCallback p_callback);
void set_disable_node_threading(bool p_disable);
//default texture settings
SceneTree();