From 8d0fecf450f68a06ea308736c1e6372861d975af Mon Sep 17 00:00:00 2001 From: koe Date: Sun, 10 Mar 2024 19:43:50 -0500 Subject: [PATCH 1/7] reduce steady-state allocations in ui_stack_system --- crates/bevy_ui/src/stack.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ui/src/stack.rs b/crates/bevy_ui/src/stack.rs index 6acc994b6f71e..eec33126a29eb 100644 --- a/crates/bevy_ui/src/stack.rs +++ b/crates/bevy_ui/src/stack.rs @@ -31,6 +31,7 @@ struct StackingContextEntry { /// First generate a UI node tree (`StackingContext`) based on z-index. /// Then flatten that tree into back-to-front ordered `UiStack`. pub fn ui_stack_system( + mut cache: Local>, mut ui_stack: ResMut, root_node_query: Query, Without)>, zindex_query: Query<&ZIndex, With>, @@ -38,11 +39,13 @@ pub fn ui_stack_system( mut update_query: Query<&mut Node>, ) { // Generate `StackingContext` tree - let mut global_context = StackingContext::default(); + let mut global_context = cache.pop().unwrap_or_default(); + global_context.clear(); let mut total_entry_count: usize = 0; for entity in &root_node_query { insert_context_hierarchy( + &mut cache, &zindex_query, &children_query, entity, @@ -55,7 +58,7 @@ pub fn ui_stack_system( // Flatten `StackingContext` into `UiStack` ui_stack.uinodes.clear(); ui_stack.uinodes.reserve(total_entry_count); - fill_stack_recursively(&mut ui_stack.uinodes, &mut global_context); + fill_stack_recursively(&mut cache, &mut ui_stack.uinodes, &mut global_context); for (i, entity) in ui_stack.uinodes.iter().enumerate() { if let Ok(mut node) = update_query.get_mut(*entity) { @@ -66,6 +69,7 @@ pub fn ui_stack_system( /// Generate z-index based UI node tree fn insert_context_hierarchy( + cache: &mut Vec, zindex_query: &Query<&ZIndex, With>, children_query: &Query<&Children>, entity: Entity, @@ -73,7 +77,8 @@ fn insert_context_hierarchy( parent_context: Option<&mut StackingContext>, total_entry_count: &mut usize, ) { - let mut new_context = StackingContext::default(); + let mut new_context = cache.pop().unwrap_or_default(); + new_context.entries.clear(); if let Ok(children) = children_query.get(entity) { // Reserve space for all children. In practice, some may not get pushed since @@ -82,6 +87,7 @@ fn insert_context_hierarchy( for entity in children { insert_context_hierarchy( + cache, zindex_query, children_query, *entity, @@ -108,16 +114,17 @@ fn insert_context_hierarchy( } /// Flatten `StackingContext` (z-index based UI node tree) into back-to-front entities list -fn fill_stack_recursively(result: &mut Vec, stack: &mut StackingContext) { +fn fill_stack_recursively(cache: &mut Vec, result: &mut Vec, stack: &mut StackingContext) { // Sort entries by ascending z_index, while ensuring that siblings // with the same local z_index will keep their ordering. This results // in `back-to-front` ordering, low z_index = back; high z_index = front. stack.entries.sort_by_key(|e| e.z_index); - for entry in &mut stack.entries { + for entry in stack.entries.drain(..) { // Parent node renders before/behind child nodes result.push(entry.entity); - fill_stack_recursively(result, &mut entry.stack); + fill_stack_recursively(cache, result, &mut entry.stack); + cache.push(entry); } } From 4ac05443b704c3b42f076666afa5a4af443dcb97 Mon Sep 17 00:00:00 2001 From: koe Date: Sun, 10 Mar 2024 19:47:02 -0500 Subject: [PATCH 2/7] fmt --- crates/bevy_ui/src/stack.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/stack.rs b/crates/bevy_ui/src/stack.rs index eec33126a29eb..b876532e4b429 100644 --- a/crates/bevy_ui/src/stack.rs +++ b/crates/bevy_ui/src/stack.rs @@ -114,7 +114,11 @@ fn insert_context_hierarchy( } /// Flatten `StackingContext` (z-index based UI node tree) into back-to-front entities list -fn fill_stack_recursively(cache: &mut Vec, result: &mut Vec, stack: &mut StackingContext) { +fn fill_stack_recursively( + cache: &mut Vec, + result: &mut Vec, + stack: &mut StackingContext, +) { // Sort entries by ascending z_index, while ensuring that siblings // with the same local z_index will keep their ordering. This results // in `back-to-front` ordering, low z_index = back; high z_index = front. From fa7fa12c90063a43e889794f6a85185068a7bf4d Mon Sep 17 00:00:00 2001 From: koe Date: Sun, 10 Mar 2024 19:56:06 -0500 Subject: [PATCH 3/7] fix compile errors --- crates/bevy_ui/src/stack.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/crates/bevy_ui/src/stack.rs b/crates/bevy_ui/src/stack.rs index b876532e4b429..45294880ddcaa 100644 --- a/crates/bevy_ui/src/stack.rs +++ b/crates/bevy_ui/src/stack.rs @@ -15,6 +15,11 @@ pub struct UiStack { pub uinodes: Vec, } +#[derive(Default)] +pub struct StackingContextCache { + inner: Vec, +} + #[derive(Default)] struct StackingContext { pub entries: Vec, @@ -31,7 +36,7 @@ struct StackingContextEntry { /// First generate a UI node tree (`StackingContext`) based on z-index. /// Then flatten that tree into back-to-front ordered `UiStack`. pub fn ui_stack_system( - mut cache: Local>, + mut cache: Local, mut ui_stack: ResMut, root_node_query: Query, Without)>, zindex_query: Query<&ZIndex, With>, @@ -39,8 +44,8 @@ pub fn ui_stack_system( mut update_query: Query<&mut Node>, ) { // Generate `StackingContext` tree - let mut global_context = cache.pop().unwrap_or_default(); - global_context.clear(); + let mut global_context = cache.inner.pop().unwrap_or_default(); + global_context.entries.clear(); let mut total_entry_count: usize = 0; for entity in &root_node_query { @@ -69,7 +74,7 @@ pub fn ui_stack_system( /// Generate z-index based UI node tree fn insert_context_hierarchy( - cache: &mut Vec, + cache: &mut StackingContextCache, zindex_query: &Query<&ZIndex, With>, children_query: &Query<&Children>, entity: Entity, @@ -77,7 +82,7 @@ fn insert_context_hierarchy( parent_context: Option<&mut StackingContext>, total_entry_count: &mut usize, ) { - let mut new_context = cache.pop().unwrap_or_default(); + let mut new_context = cache.inner.pop().unwrap_or_default(); new_context.entries.clear(); if let Ok(children) = children_query.get(entity) { @@ -115,7 +120,7 @@ fn insert_context_hierarchy( /// Flatten `StackingContext` (z-index based UI node tree) into back-to-front entities list fn fill_stack_recursively( - cache: &mut Vec, + cache: &mut StackingContextCache, result: &mut Vec, stack: &mut StackingContext, ) { @@ -124,11 +129,11 @@ fn fill_stack_recursively( // in `back-to-front` ordering, low z_index = back; high z_index = front. stack.entries.sort_by_key(|e| e.z_index); - for entry in stack.entries.drain(..) { + for mut entry in stack.entries.drain(..) { // Parent node renders before/behind child nodes result.push(entry.entity); fill_stack_recursively(cache, result, &mut entry.stack); - cache.push(entry); + cache.inner.push(entry.stack); } } From 2faa20e29833cf212977e8a60d3cc55cd0bdb664 Mon Sep 17 00:00:00 2001 From: koe Date: Sun, 10 Mar 2024 20:01:37 -0500 Subject: [PATCH 4/7] cleanup --- crates/bevy_ui/src/stack.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ui/src/stack.rs b/crates/bevy_ui/src/stack.rs index 45294880ddcaa..24f44e96207bd 100644 --- a/crates/bevy_ui/src/stack.rs +++ b/crates/bevy_ui/src/stack.rs @@ -20,6 +20,17 @@ pub struct StackingContextCache { inner: Vec, } +impl StackingContextCache { + fn pop(&mut self) -> StackingContext { + self.inner.pop().unwrap_or_default() + } + + fn push(&mut self, mut context: StackingContext) { + context.entries.clear(); + self.inner.push(context); + } +} + #[derive(Default)] struct StackingContext { pub entries: Vec, @@ -44,8 +55,7 @@ pub fn ui_stack_system( mut update_query: Query<&mut Node>, ) { // Generate `StackingContext` tree - let mut global_context = cache.inner.pop().unwrap_or_default(); - global_context.entries.clear(); + let mut global_context = cache.pop(); let mut total_entry_count: usize = 0; for entity in &root_node_query { @@ -82,8 +92,7 @@ fn insert_context_hierarchy( parent_context: Option<&mut StackingContext>, total_entry_count: &mut usize, ) { - let mut new_context = cache.inner.pop().unwrap_or_default(); - new_context.entries.clear(); + let mut new_context = cache.pop(); if let Ok(children) = children_query.get(entity) { // Reserve space for all children. In practice, some may not get pushed since @@ -133,7 +142,7 @@ fn fill_stack_recursively( // Parent node renders before/behind child nodes result.push(entry.entity); fill_stack_recursively(cache, result, &mut entry.stack); - cache.inner.push(entry.stack); + cache.push(entry.stack); } } From dc575b4cbbe9fdfc8a52adf6ca9f5470bce374cb Mon Sep 17 00:00:00 2001 From: koe Date: Sun, 10 Mar 2024 20:03:37 -0500 Subject: [PATCH 5/7] maximal correctness --- crates/bevy_ui/src/stack.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/stack.rs b/crates/bevy_ui/src/stack.rs index 24f44e96207bd..b25106db05387 100644 --- a/crates/bevy_ui/src/stack.rs +++ b/crates/bevy_ui/src/stack.rs @@ -26,7 +26,9 @@ impl StackingContextCache { } fn push(&mut self, mut context: StackingContext) { - context.entries.clear(); + for entry in context.entries.drain(..) { + self.push(entry.stack); + } self.inner.push(context); } } From cb428c4354223af235e93972d4ef182f6cddeab1 Mon Sep 17 00:00:00 2001 From: koe Date: Mon, 11 Mar 2024 17:37:10 -0500 Subject: [PATCH 6/7] also cache the global context --- crates/bevy_ui/src/stack.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_ui/src/stack.rs b/crates/bevy_ui/src/stack.rs index b25106db05387..f7b0a1d673670 100644 --- a/crates/bevy_ui/src/stack.rs +++ b/crates/bevy_ui/src/stack.rs @@ -76,6 +76,7 @@ pub fn ui_stack_system( ui_stack.uinodes.clear(); ui_stack.uinodes.reserve(total_entry_count); fill_stack_recursively(&mut cache, &mut ui_stack.uinodes, &mut global_context); + cache.push(global_context); for (i, entity) in ui_stack.uinodes.iter().enumerate() { if let Ok(mut node) = update_query.get_mut(*entity) { From f7d2dbd10d9e2bfeaa154a1f81ff0275f1a2cfbf Mon Sep 17 00:00:00 2001 From: koe Date: Mon, 11 Mar 2024 17:52:08 -0500 Subject: [PATCH 7/7] restrict visibility --- crates/bevy_ui/src/stack.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ui/src/stack.rs b/crates/bevy_ui/src/stack.rs index f7b0a1d673670..cea45e91bde12 100644 --- a/crates/bevy_ui/src/stack.rs +++ b/crates/bevy_ui/src/stack.rs @@ -15,8 +15,9 @@ pub struct UiStack { pub uinodes: Vec, } +/// Caches stacking context buffers for use in [`ui_stack_system`]. #[derive(Default)] -pub struct StackingContextCache { +pub(crate) struct StackingContextCache { inner: Vec, } @@ -35,20 +36,20 @@ impl StackingContextCache { #[derive(Default)] struct StackingContext { - pub entries: Vec, + entries: Vec, } struct StackingContextEntry { - pub z_index: i32, - pub entity: Entity, - pub stack: StackingContext, + z_index: i32, + entity: Entity, + stack: StackingContext, } /// Generates the render stack for UI nodes. /// /// First generate a UI node tree (`StackingContext`) based on z-index. /// Then flatten that tree into back-to-front ordered `UiStack`. -pub fn ui_stack_system( +pub(crate) fn ui_stack_system( mut cache: Local, mut ui_stack: ResMut, root_node_query: Query, Without)>,