Use LocalVector for Node3D and CanvasItem children#107481
Use LocalVector for Node3D and CanvasItem children#107481Repiteo merged 1 commit intogodotengine:masterfrom
LocalVector for Node3D and CanvasItem children#107481Conversation
Node3D and CanvasItem children change to LocalVectorLocalVector for Node3D and CanvasItem children
I might be missing something here, but isn't this a pretty serious change? Moving nodes around changes their processing order, and in the case of 2D their drawing order. |
You are missing something. Draw / processing order is determined by It's a peculiar arrangement. The There's only about 5 or so uses of the |
d27ba23 to
ad82425
Compare
ad82425 to
af2b9be
Compare
|
Thanks! |
Node3Dmaintains its own list ofNode3D-only children (separate from theNode), in order to (in theory) make child iteration faster for only node3d children. The same happens withCanvasItemandCanvasItemchildren.The problem is that these lists are stored as a linked list, and there is no reason to require linked list. Linked lists are bad for cache.
Forward port of #107480
Benchmark
(See 3.x PR, but gains should be similar in 4.x)
before: 157 fps
after: 280 fps
The benchmark creates a large number of
Node3Dchildren to the root node, then rotates the root. This stresses the_propagate_transform_changed()which utilizes the children list.Notes
Node3Dchildren list entirely and utilizing theNodechildren list instead with fast casting, but this PR is still faster (because of no need for cast checks).NULLchecks in the original were redundant, I don't think these pointers can beNULLgiven the code here.SceneTreeFTInow it is faster, instead ofNodechildren. Not 100% on this yet, but worth looking into.CanvasItem, the same applies.Additional
These lists are similar in 3.x and 4.x. Unlike the
Nodechildren list, they are unordered, so no need to change when rearranging children, only when entering / exiting tree, and removing items is O(1) rather than O(N).Instead of relying on the ability of linked list to remove an element fast, we use
remove_at_unorderedto remove elements in O(1). With linear lists, and keeping an ID of which child we are in the parent list, we have to rejig the child that is moved duringremove_at_unordered(), and reassign its child ID. That should be the only thing required to keep the IDs in sync.