-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unrequire ComputedNode
#16906
base: main
Are you sure you want to change the base?
Unrequire ComputedNode
#16906
Conversation
…de and if so, remove its `ComputedNode` component (if it has one). When updating the stack indices add a `ComputedNode` to Nodes without one.
Oh good catch. @pcwalton this might help explain your weird perf issues with UI layout. After some chewing, I like this approach better than adding some disabling marker: it doesn't make sense for us to keep the data around due to how long-lived Display::None states are. It also prevents weird footguns where you're checking stale derived data. |
I think his issue is because the stack indices, clipping rects and border values are alway recomputed every frame regardless of changes to the layout. It used to not be a problem but recent changes, especially ghost nodes, have made those updates a lot more expensive.
Yeah lots of query filters can be confusing, removal is definitely better imo. |
UiSystem::Prepare.after(UiSystem::Stack).after(Animation), | ||
UiSystem::Layout, | ||
UiSystem::PostLayout, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UiSystem::Prepare
was explicitly added to be the first ui system set. That way you can reliably do .before(UiSystem::Prepare)
and your systems will never mess up ui calculations.
It looks like you're using the results of UiSystem::Stack
in systems in Prepare
now. I think you need to do a larger rearranging of systems to accommodate this so Prepare
remains the first set.
Imo the alternative to consider is something like Ultimately I think adding enabled/disabled "runtime" states to components in Bevy ECS would be a nice generic solve to this problem. Lets us keep things in memory while also "hiding" components from systems. But in lieu of that feature, I'm kind of biased toward leaving ComputedNode as required and eating the complexity of checking the enabled flags in the few internal places where that matters. |
if node.display == Display::None { | ||
commands.entity(id).remove::<ComputedNode>(); | ||
} | ||
if visited_root_nodes.contains(&id) { | ||
continue; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if node.display == Display::None { | |
commands.entity(id).remove::<ComputedNode>(); | |
} | |
if visited_root_nodes.contains(&id) { | |
continue; | |
} | |
if visited_root_nodes.contains(&id) { | |
continue; | |
} | |
if node.display == Display::None { | |
commands.entity(id).remove::<ComputedNode>(); | |
} |
for (id, node, maybe_global_zindex, maybe_zindex) in | ||
root_node_query.iter_many(ui_root_nodes.iter()) | ||
{ | ||
if node.display != Display::None { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This behavior is not the same as the zindex_global_node_query
case below (which looks correct)
if node_query.get(node_entity).unwrap().display == Display::None { | ||
remove_computed_nodes_recursive(node_entity, commands, ui_children); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if node_query.get(node_entity).unwrap().display == Display::None { | |
remove_computed_nodes_recursive(node_entity, commands, ui_children); | |
} | |
if node_query.get(node_entity).unwrap().display == Display::None { | |
remove_computed_nodes_recursive(node_entity, commands, ui_children); | |
return; | |
} | |
Objective
UI nodes with
Display::None
set are meant to be removed from the layout and ignored but because all we do to signal removal is set the size to zero the inactive nodes get caught up in all the UI queries which is catastrophically terrible for performance and causes a few bugs.Fixes #16904
Solution
Remove
ComputedNode
fromNode
's required components and instead add or remove it automatically inui_stack_system
during the walk to update the stack indices depending on the state of theNode::display
field.I bashed this out really quickly and it's a bit rough. I expect there to be some bugs and some things need a clean up. I'm convinced the idea is sound though and it's ready enough to test and review.
Testing
Migration Guide
ComputedNode
is no longer a required component forNode
, instead it's added or removed automatically byui_stack_system
.