FTI - Optimize SceneTree traversal
This commit is contained in:
@ -36,6 +36,12 @@
|
||||
class Node3D;
|
||||
class Node;
|
||||
struct Transform3D;
|
||||
class SceneTreeFTITests;
|
||||
|
||||
#ifdef DEV_ENABLED
|
||||
// Uncomment this to verify traversal method results.
|
||||
// #define GODOT_SCENE_TREE_FTI_VERIFY
|
||||
#endif
|
||||
|
||||
#ifdef _3D_DISABLED
|
||||
// Stubs
|
||||
@ -62,19 +68,37 @@ public:
|
||||
// but this covers the custom case of multiple scene trees.
|
||||
|
||||
class SceneTreeFTI {
|
||||
friend class SceneTreeFTITests;
|
||||
|
||||
enum TraversalMode : unsigned {
|
||||
TM_DEFAULT,
|
||||
TM_LEGACY,
|
||||
TM_DEBUG,
|
||||
};
|
||||
|
||||
struct Data {
|
||||
static const uint32_t scene_tree_depth_limit = 32;
|
||||
|
||||
// Prev / Curr lists of Node3Ds having local xforms pumped.
|
||||
LocalVector<Node3D *> tick_xform_list[2];
|
||||
|
||||
// The frame lists are changed nodes that need to start traversal,
|
||||
// either longterm (on the tick list) or single frame forced.
|
||||
LocalVector<Node3D *> frame_xform_list;
|
||||
LocalVector<Node3D *> frame_xform_list_forced;
|
||||
|
||||
// Prev / Curr lists of Node3Ds having actively interpolated properties.
|
||||
LocalVector<Node3D *> tick_property_list[2];
|
||||
|
||||
LocalVector<Node3D *> frame_property_list;
|
||||
|
||||
LocalVector<Node3D *> request_reset_list;
|
||||
LocalVector<Node3D *> dirty_node_depth_lists[scene_tree_depth_limit];
|
||||
|
||||
// When we are using two alternating lists,
|
||||
// which one is current.
|
||||
uint32_t mirror = 0;
|
||||
|
||||
// Global on / off switch for SceneTreeFTI.
|
||||
bool enabled = false;
|
||||
|
||||
// Whether we are in physics ticks, or in a frame.
|
||||
@ -85,10 +109,21 @@ class SceneTreeFTI {
|
||||
|
||||
Mutex mutex;
|
||||
|
||||
bool debug = false;
|
||||
TraversalMode traversal_mode = TM_DEFAULT;
|
||||
bool use_optimized_traversal_method = true;
|
||||
|
||||
// DEBUGGING
|
||||
bool periodic_debug_log = false;
|
||||
uint32_t debug_node_count = 0;
|
||||
uint32_t debug_nodes_processed = 0;
|
||||
|
||||
} data;
|
||||
|
||||
void _update_dirty_nodes(Node *p_node, uint32_t p_current_frame, float p_interpolation_fraction, bool p_active, const Transform3D *p_parent_global_xform = nullptr, int p_depth = 0);
|
||||
#ifdef GODOT_SCENE_TREE_FTI_VERIFY
|
||||
SceneTreeFTITests *_tests = nullptr;
|
||||
#endif
|
||||
|
||||
void _update_dirty_nodes(Node *p_node, uint32_t p_current_half_frame, float p_interpolation_fraction, bool p_active, const Transform3D *p_parent_global_xform = nullptr, int p_depth = 0);
|
||||
void _update_request_resets();
|
||||
|
||||
void _reset_flags(Node *p_node);
|
||||
@ -96,6 +131,12 @@ class SceneTreeFTI {
|
||||
void _node_3d_notify_set_xform(Node3D &r_node);
|
||||
void _node_3d_notify_set_property(Node3D &r_node);
|
||||
|
||||
void _node_add_to_frame_list(Node3D &r_node, bool p_forced);
|
||||
void _node_remove_from_frame_list(Node3D &r_node, bool p_forced);
|
||||
|
||||
void _create_depth_lists();
|
||||
void _clear_depth_lists();
|
||||
|
||||
public:
|
||||
// Hottest function, allow inlining the data.enabled check.
|
||||
void node_3d_notify_changed(Node3D &r_node, bool p_transform_changed) {
|
||||
@ -123,7 +164,10 @@ public:
|
||||
void set_enabled(Node *p_root, bool p_enabled);
|
||||
bool is_enabled() const { return data.enabled; }
|
||||
|
||||
void set_debug_next_frame() { data.debug = true; }
|
||||
void set_debug_next_frame() { data.periodic_debug_log = true; }
|
||||
|
||||
SceneTreeFTI();
|
||||
~SceneTreeFTI();
|
||||
};
|
||||
|
||||
#endif // ndef _3D_DISABLED
|
||||
|
||||
Reference in New Issue
Block a user