-
-
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
Simplified ui_stack_system
#9889
Simplified ui_stack_system
#9889
Conversation
…ering away those nodes.
clean up and cargo fmt
…ZIndex` and `GlobalZIndex` respectively.
That makes sense to me. While both are kinds of zindex, they have different implications, both conceptually and in the implementation. I'm curious to know what maintainers think of the naming, i.e. should ZIndex be renamed to |
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.
There are a few minor missing changes I commented about, but otherwise this looks good to me. This makes ZIndex
a simpler component and "hides" global z-index behavior which is probably a good thing since it's an escape hatch and isn't meant to be used in most UI's. Unlike the previous PR, this is not a feature regression so it's less controversial in my opinion (as long as the API change is deemed uncontroversial as well).
Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com>
Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com>
My thinking is that keeping I'm not bothered about the naming though, if there is a consensus in favour of |
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 makes a lot of sense and uses the ECS better. Im in favor of the current naming (ZIndex + GlobalZIndex)
crates/bevy_ui/src/stack.rs
Outdated
.ok() | ||
.map(|zindex| (*entity, zindex.map(|zindex| zindex.0).unwrap_or(0))) | ||
}) | ||
.collect(); |
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.
No need to collect, use a shared vec sourced from a local and clear -> extend
here.
crates/bevy_ui/src/stack.rs
Outdated
.map(|zindex| (*entity, zindex.map(|zindex| zindex.0).unwrap_or(0))) | ||
}) | ||
.collect(); | ||
radsort::sort_by_key(&mut z_children, |k| k.1); |
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.
Not clear that radsort
is better than std::sort
here either, since most nodes will have only a handful of children. To use std::sort_unstable
you can add an index
for each child and sort by (z_index, child_index)
.
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.
Another reviewer said to try using radsort and it seemed to be an improvement with my benchmarks but I forgot that those benchmarks were with very large numbers of children which isn't the typical usage case.
crates/bevy_ui/src/stack.rs
Outdated
for (i, entity) in ui_stack.uinodes.iter().enumerate() { | ||
if let Ok(mut node) = update_query.get_mut(*entity) { | ||
node.bypass_change_detection().stack_index = i as u32; | ||
} | ||
} |
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.
The traversal_stack
is never inserted to ui_stack
. Am I missing something here? Also how are children supposed to be inserted relative to their parents within the global stack?
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.
I'm puzzled how this passes CI, it appears to have serious bugs.
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.
traversal_stack
is used to navigate the tree, not insert the nodes.
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.
Abandoned the iterative version using stack traversal anyway, and went back to walking the tree recursively, copying your stack of cached buffers approach from main to avoid the vec allocations. I don't understand why the iterative version is so much less efficient though. It just has one buffer for storing and sorting the children it reuses, which seems so much better.
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.
Looks correct now, minor doc comments. Also would like to see an updated perf graph.
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
# Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes bevyengine#9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
Objective
ui_stack_system
generates a tree ofStackingContexts
which it then flattens to get theUiStack
.But there's no need to construct a new tree. We can query for nodes with a global
ZIndex
, add those nodes to the root nodes list and then build theUiStack
from a walk of the existing layout tree, ignoring any branches that have a globalZindex
.Fixes #9877
Solution
Split the
ZIndex
enum into two separate components,ZIndex
andGlobalZIndex
Query for nodes with a
GlobalZIndex
, add those nodes to the root nodes list and then build theUiStack
from a walk of the existing layout tree, filtering branches byWithout<GlobalZIndex>
so we don't revisit nodes.(Yellow is this PR, red is main)
Changelog
Zindex
ZIndex
enum has been split into two separate componentsZIndex
(which replacesZIndex::Local
) andGlobalZIndex
(which replacesZIndex::Global
). An entity can have both aZIndex
andGlobalZIndex
, in comparisonsZIndex
breaks ties if twoGlobalZIndex
values are equal.ui_stack_system
StackingContexts
, query for nodes with aGlobalZIndex
, add those nodes to the root nodes list and then build theUiStack
from a walk of the existing layout tree, filtering branches byWithout<GlobalZIndex
so we don't revisit nodes.Migration Guide
The
ZIndex
enum has been split into two separate componentsZIndex
(which replacesZIndex::Local
) andGlobalZIndex
(which replacesZIndex::Global
). An entity can have both aZIndex
andGlobalZIndex
, in comparisonsZIndex
breaks ties if twoGlobalZindex
values are equal.