Optimize stack id in-memory layout

Kirill Bulatov created

Change summary

crates/gpui2/src/scene.rs  | 226 ++++++++++++++++++++--------------------
crates/gpui2/src/window.rs |  66 ++++-------
2 files changed, 136 insertions(+), 156 deletions(-)

Detailed changes

crates/gpui2/src/scene.rs 🔗

@@ -857,116 +857,116 @@ impl Bounds<ScaledPixels> {
     }
 }
 
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::{point, px, size, Size};
-    use smallvec::smallvec;
-
-    // todo!()
-    // #[test]
-    // fn test_scene() {
-    //     let mut scene = SceneBuilder::default();
-    //     assert_eq!(scene.layers_by_order.len(), 0);
-
-    //     // div with z_index(1)
-    //     //     glyph with z_index(1)
-    //     // div with z_index(1)
-    //     //      glyph with z_index(1)
-
-    //     scene.insert(
-    //         &smallvec![1].into(),
-    //         quad(
-    //             point(px(0.), px(0.)),
-    //             size(px(100.), px(100.)),
-    //             crate::black(),
-    //         ),
-    //     );
-    //     scene.insert(
-    //         &smallvec![1, 1].into(),
-    //         sprite(
-    //             point(px(0.), px(0.)),
-    //             size(px(10.), px(10.)),
-    //             crate::white(),
-    //         ),
-    //     );
-    //     scene.insert(
-    //         &smallvec![1].into(),
-    //         quad(
-    //             point(px(10.), px(10.)),
-    //             size(px(20.), px(20.)),
-    //             crate::green(),
-    //         ),
-    //     );
-    //     scene.insert(
-    //         &smallvec![1, 1].into(),
-    //         sprite(point(px(15.), px(15.)), size(px(5.), px(5.)), crate::blue()),
-    //     );
-
-    //     assert!(!scene.layers_by_order.is_empty());
-
-    //     for batch in scene.build().batches() {
-    //         println!("new batch");
-    //         match batch {
-    //             PrimitiveBatch::Quads(quads) => {
-    //                 for quad in quads {
-    //                     if quad.background == crate::black() {
-    //                         println!("  black quad");
-    //                     } else if quad.background == crate::green() {
-    //                         println!("  green quad");
-    //                     } else {
-    //                         todo!("  ((( bad quad");
-    //                     }
-    //                 }
-    //             }
-    //             PrimitiveBatch::MonochromeSprites { sprites, .. } => {
-    //                 for sprite in sprites {
-    //                     if sprite.color == crate::white() {
-    //                         println!("  white sprite");
-    //                     } else if sprite.color == crate::blue() {
-    //                         println!("  blue sprite");
-    //                     } else {
-    //                         todo!("  ((( bad sprite")
-    //                     }
-    //                 }
-    //             }
-    //             _ => todo!(),
-    //         }
-    //     }
-    // }
-
-    fn quad(origin: Point<Pixels>, size: Size<Pixels>, background: Hsla) -> Quad {
-        Quad {
-            order: 0,
-            bounds: Bounds { origin, size }.scale(1.),
-            background,
-            content_mask: ContentMask {
-                bounds: Bounds { origin, size },
-            }
-            .scale(1.),
-            border_color: Default::default(),
-            corner_radii: Default::default(),
-            border_widths: Default::default(),
-        }
-    }
-
-    fn sprite(origin: Point<Pixels>, size: Size<Pixels>, color: Hsla) -> MonochromeSprite {
-        MonochromeSprite {
-            order: 0,
-            bounds: Bounds { origin, size }.scale(1.),
-            content_mask: ContentMask {
-                bounds: Bounds { origin, size },
-            }
-            .scale(1.),
-            color,
-            tile: AtlasTile {
-                texture_id: AtlasTextureId {
-                    index: 0,
-                    kind: crate::AtlasTextureKind::Monochrome,
-                },
-                tile_id: crate::TileId(0),
-                bounds: Default::default(),
-            },
-        }
-    }
-}
+// todo!()
+// #[cfg(test)]
+// mod tests {
+//     use super::*;
+//     use crate::{point, px, size, Size};
+//     use smallvec::smallvec;
+
+// #[test]
+// fn test_scene() {
+//     let mut scene = SceneBuilder::default();
+//     assert_eq!(scene.layers_by_order.len(), 0);
+
+//     // div with z_index(1)
+//     //     glyph with z_index(1)
+//     // div with z_index(1)
+//     //      glyph with z_index(1)
+
+//     scene.insert(
+//         &smallvec![1].into(),
+//         quad(
+//             point(px(0.), px(0.)),
+//             size(px(100.), px(100.)),
+//             crate::black(),
+//         ),
+//     );
+//     scene.insert(
+//         &smallvec![1, 1].into(),
+//         sprite(
+//             point(px(0.), px(0.)),
+//             size(px(10.), px(10.)),
+//             crate::white(),
+//         ),
+//     );
+//     scene.insert(
+//         &smallvec![1].into(),
+//         quad(
+//             point(px(10.), px(10.)),
+//             size(px(20.), px(20.)),
+//             crate::green(),
+//         ),
+//     );
+//     scene.insert(
+//         &smallvec![1, 1].into(),
+//         sprite(point(px(15.), px(15.)), size(px(5.), px(5.)), crate::blue()),
+//     );
+
+//     assert!(!scene.layers_by_order.is_empty());
+
+//     for batch in scene.build().batches() {
+//         println!("new batch");
+//         match batch {
+//             PrimitiveBatch::Quads(quads) => {
+//                 for quad in quads {
+//                     if quad.background == crate::black() {
+//                         println!("  black quad");
+//                     } else if quad.background == crate::green() {
+//                         println!("  green quad");
+//                     } else {
+//                         todo!("  ((( bad quad");
+//                     }
+//                 }
+//             }
+//             PrimitiveBatch::MonochromeSprites { sprites, .. } => {
+//                 for sprite in sprites {
+//                     if sprite.color == crate::white() {
+//                         println!("  white sprite");
+//                     } else if sprite.color == crate::blue() {
+//                         println!("  blue sprite");
+//                     } else {
+//                         todo!("  ((( bad sprite")
+//                     }
+//                 }
+//             }
+//             _ => todo!(),
+//         }
+//     }
+// }
+
+//     fn quad(origin: Point<Pixels>, size: Size<Pixels>, background: Hsla) -> Quad {
+//         Quad {
+//             order: 0,
+//             bounds: Bounds { origin, size }.scale(1.),
+//             background,
+//             content_mask: ContentMask {
+//                 bounds: Bounds { origin, size },
+//             }
+//             .scale(1.),
+//             border_color: Default::default(),
+//             corner_radii: Default::default(),
+//             border_widths: Default::default(),
+//         }
+//     }
+
+//     fn sprite(origin: Point<Pixels>, size: Size<Pixels>, color: Hsla) -> MonochromeSprite {
+//         MonochromeSprite {
+//             order: 0,
+//             bounds: Bounds { origin, size }.scale(1.),
+//             content_mask: ContentMask {
+//                 bounds: Bounds { origin, size },
+//             }
+//             .scale(1.),
+//             color,
+//             tile: AtlasTile {
+//                 texture_id: AtlasTextureId {
+//                     index: 0,
+//                     kind: crate::AtlasTextureKind::Monochrome,
+//                 },
+//                 tile_id: crate::TileId(0),
+//                 bounds: Default::default(),
+//             },
+//         }
+//     }
+// }

crates/gpui2/src/window.rs 🔗

@@ -39,7 +39,7 @@ use std::{
         Arc,
     },
 };
-use util::{post_inc, ResultExt};
+use util::ResultExt;
 
 const ACTIVE_DRAG_Z_INDEX: u8 = 1;
 
@@ -49,25 +49,21 @@ const ACTIVE_DRAG_Z_INDEX: u8 = 1;
 pub struct StackingOrder {
     #[deref]
     #[deref_mut]
-    context_stack: SmallVec<[StackingContext; 64]>,
-}
-
-#[derive(Clone, Ord, PartialOrd, PartialEq, Eq)]
-pub struct StackingContext {
-    // TODO kb use u16 and/or try to push the `id` above into the stacking order
-    z_index: u8,
-    id: u16,
+    context_stack: SmallVec<[u8; 64]>,
+    id: u32,
 }
 
 impl std::fmt::Debug for StackingOrder {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let mut stacks = self.context_stack.iter().peekable();
+        write!(f, "[({}): ", self.id)?;
         while let Some(z_index) = stacks.next() {
-            write!(f, "{}.{}", z_index.z_index, z_index.id)?;
+            write!(f, "{z_index}")?;
             if stacks.peek().is_some() {
                 write!(f, "->")?;
             }
         }
+        write!(f, "]")?;
         Ok(())
     }
 }
@@ -296,7 +292,7 @@ pub(crate) struct Frame {
     pub(crate) scene_builder: SceneBuilder,
     pub(crate) depth_map: Vec<(StackingOrder, Bounds<Pixels>)>,
     pub(crate) z_index_stack: StackingOrder,
-    pub(crate) stacking_context_id_stack: Vec<u16>,
+    pub(crate) next_stacking_order_id: u32,
     content_mask_stack: Vec<ContentMask<Pixels>>,
     element_offset_stack: Vec<Point<Pixels>>,
 }
@@ -310,7 +306,7 @@ impl Frame {
             dispatch_tree,
             scene_builder: SceneBuilder::default(),
             z_index_stack: StackingOrder::default(),
-            stacking_context_id_stack: vec![0],
+            next_stacking_order_id: 0,
             depth_map: Default::default(),
             content_mask_stack: Vec::new(),
             element_offset_stack: Vec::new(),
@@ -322,8 +318,7 @@ impl Frame {
         self.mouse_listeners.values_mut().for_each(Vec::clear);
         self.dispatch_tree.clear();
         self.depth_map.clear();
-        self.stacking_context_id_stack.clear();
-        self.stacking_context_id_stack.push(0);
+        self.next_stacking_order_id = 0;
     }
 
     fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
@@ -947,20 +942,14 @@ impl<'a> WindowContext<'a> {
     /// Called during painting to invoke the given closure in a new stacking context. The given
     /// z-index is interpreted relative to the previous call to `stack`.
     pub fn with_z_index<R>(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R {
-        let id = post_inc(
-            self.window
-                .next_frame
-                .stacking_context_id_stack
-                .last_mut()
-                .unwrap(),
-        );
-        self.window.next_frame.stacking_context_id_stack.push(0);
-        self.window
-            .next_frame
-            .z_index_stack
-            .push(StackingContext { z_index, id });
+        let new_stacking_order_id = self.window.next_frame.next_stacking_order_id;
+        let new_next_stacking_order_id = new_stacking_order_id + 1;
+
+        self.window.next_frame.next_stacking_order_id = 0;
+        self.window.next_frame.z_index_stack.id = new_stacking_order_id;
+        self.window.next_frame.z_index_stack.push(z_index);
         let result = f(self);
-        self.window.next_frame.stacking_context_id_stack.pop();
+        self.window.next_frame.next_stacking_order_id = new_next_stacking_order_id;
         self.window.next_frame.z_index_stack.pop();
         result
     }
@@ -2077,23 +2066,14 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
     /// Called during painting to invoke the given closure in a new stacking context. The given
     /// z-index is interpreted relative to the previous call to `stack`.
     fn with_z_index<R>(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R {
-        let id = post_inc(
-            self.window_mut()
-                .next_frame
-                .stacking_context_id_stack
-                .last_mut()
-                .unwrap(),
-        );
-        self.window_mut()
-            .next_frame
-            .stacking_context_id_stack
-            .push(0);
-        self.window_mut()
-            .next_frame
-            .z_index_stack
-            .push(StackingContext { z_index, id });
+        let new_stacking_order_id = self.window_mut().next_frame.next_stacking_order_id;
+        let new_next_stacking_order_id = new_stacking_order_id + 1;
+
+        self.window_mut().next_frame.next_stacking_order_id = 0;
+        self.window_mut().next_frame.z_index_stack.id = new_stacking_order_id;
+        self.window_mut().next_frame.z_index_stack.push(z_index);
         let result = f(self);
-        self.window_mut().next_frame.stacking_context_id_stack.pop();
+        self.window_mut().next_frame.next_stacking_order_id = new_next_stacking_order_id;
         self.window_mut().next_frame.z_index_stack.pop();
         result
     }