From 48ad53baddbff58b0b706c67acbd7664a2b3462b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 21 Dec 2023 19:52:15 +0100 Subject: [PATCH] Revert "Revert "Optimize order rendering and border drawing"" --- Cargo.lock | 12 ---- crates/gpui2/Cargo.toml | 1 - crates/gpui2/src/geometry.rs | 21 ++++++ crates/gpui2/src/scene.rs | 126 +++++++---------------------------- crates/gpui2/src/style.rs | 60 +++++++++++++++-- crates/gpui2/src/window.rs | 1 + 6 files changed, 101 insertions(+), 120 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8d8c1cc0d..1bcbd3be38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4066,7 +4066,6 @@ dependencies = [ "parking", "parking_lot 0.11.2", "pathfinder_geometry", - "plane-split", "png", "postage", "rand 0.8.5", @@ -6662,17 +6661,6 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" -[[package]] -name = "plane-split" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f7d82649829ecdef8e258790b0587acf0a8403f0ce963473d8e918acc1643" -dependencies = [ - "euclid", - "log", - "smallvec", -] - [[package]] name = "plist" version = "1.5.0" diff --git a/crates/gpui2/Cargo.toml b/crates/gpui2/Cargo.toml index afb5d3ea0c..bf0ac955a5 100644 --- a/crates/gpui2/Cargo.toml +++ b/crates/gpui2/Cargo.toml @@ -56,7 +56,6 @@ uuid = { version = "1.1.2", features = ["v4"] } waker-fn = "1.1.0" slotmap = "1.0.6" schemars.workspace = true -plane-split = "0.18.0" bitflags = "2.4.0" [dev-dependencies] diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index f58435d7b9..6b4d9ae807 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -1590,6 +1590,15 @@ impl Edges { left: self.left.scale(factor), } } + + /// Returns the maximum value of any edge. + /// + /// # Returns + /// + /// The maximum `Pixels` value among all four edges. + pub fn max(&self) -> Pixels { + self.top.max(self.right).max(self.bottom).max(self.left) + } } impl Into> for f32 { @@ -1740,6 +1749,18 @@ impl Corners { bottom_left: self.bottom_left.scale(factor), } } + + /// Returns the maximum value of any corner. + /// + /// # Returns + /// + /// The maximum `Pixels` value among all four corners. + pub fn max(&self) -> Pixels { + self.top_left + .max(self.top_right) + .max(self.bottom_right) + .max(self.bottom_left) + } } impl Corners { diff --git a/crates/gpui2/src/scene.rs b/crates/gpui2/src/scene.rs index e6b601b62f..cb62ce314f 100644 --- a/crates/gpui2/src/scene.rs +++ b/crates/gpui2/src/scene.rs @@ -3,8 +3,6 @@ use crate::{ ScaledPixels, StackingOrder, }; use collections::BTreeMap; -use etagere::euclid::{Point3D, Vector3D}; -use plane_split::{BspSplitter, Polygon as BspPolygon}; use std::{fmt::Debug, iter::Peekable, mem, slice}; // Exported to metal @@ -19,7 +17,6 @@ pub type DrawOrder = u32; pub(crate) struct SceneBuilder { last_order: Option<(StackingOrder, LayerId)>, layers_by_order: BTreeMap, - splitter: BspSplitter<(PrimitiveKind, usize)>, shadows: Vec, quads: Vec, paths: Vec>, @@ -34,7 +31,6 @@ impl Default for SceneBuilder { SceneBuilder { last_order: None, layers_by_order: BTreeMap::new(), - splitter: BspSplitter::new(), shadows: Vec::new(), quads: Vec::new(), paths: Vec::new(), @@ -48,103 +44,47 @@ impl Default for SceneBuilder { impl SceneBuilder { pub fn build(&mut self) -> Scene { - // Map each layer id to a float between 0. and 1., with 1. closer to the viewer. - let mut layer_z_values = vec![0.; self.layers_by_order.len()]; + let mut orders = vec![0; self.layers_by_order.len()]; for (ix, layer_id) in self.layers_by_order.values().enumerate() { - layer_z_values[*layer_id as usize] = ix as f32 / self.layers_by_order.len() as f32; + orders[*layer_id as usize] = ix as u32; } self.layers_by_order.clear(); self.last_order = None; - // Add all primitives to the BSP splitter to determine draw order - self.splitter.reset(); - - for (ix, shadow) in self.shadows.iter().enumerate() { - let z = layer_z_values[shadow.order as LayerId as usize]; - self.splitter - .add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix))); + for shadow in &mut self.shadows { + shadow.order = orders[shadow.order as usize]; } + self.shadows.sort_by_key(|shadow| shadow.order); - for (ix, quad) in self.quads.iter().enumerate() { - let z = layer_z_values[quad.order as LayerId as usize]; - self.splitter - .add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix))); + for quad in &mut self.quads { + quad.order = orders[quad.order as usize]; } + self.quads.sort_by_key(|quad| quad.order); - for (ix, path) in self.paths.iter().enumerate() { - let z = layer_z_values[path.order as LayerId as usize]; - self.splitter - .add(path.bounds.to_bsp_polygon(z, (PrimitiveKind::Path, ix))); + for path in &mut self.paths { + path.order = orders[path.order as usize]; } + self.paths.sort_by_key(|path| path.order); - for (ix, underline) in self.underlines.iter().enumerate() { - let z = layer_z_values[underline.order as LayerId as usize]; - self.splitter.add( - underline - .bounds - .to_bsp_polygon(z, (PrimitiveKind::Underline, ix)), - ); + for underline in &mut self.underlines { + underline.order = orders[underline.order as usize]; } + self.underlines.sort_by_key(|underline| underline.order); - for (ix, monochrome_sprite) in self.monochrome_sprites.iter().enumerate() { - let z = layer_z_values[monochrome_sprite.order as LayerId as usize]; - self.splitter.add( - monochrome_sprite - .bounds - .to_bsp_polygon(z, (PrimitiveKind::MonochromeSprite, ix)), - ); + for monochrome_sprite in &mut self.monochrome_sprites { + monochrome_sprite.order = orders[monochrome_sprite.order as usize]; } + self.monochrome_sprites.sort_by_key(|sprite| sprite.order); - for (ix, polychrome_sprite) in self.polychrome_sprites.iter().enumerate() { - let z = layer_z_values[polychrome_sprite.order as LayerId as usize]; - self.splitter.add( - polychrome_sprite - .bounds - .to_bsp_polygon(z, (PrimitiveKind::PolychromeSprite, ix)), - ); + for polychrome_sprite in &mut self.polychrome_sprites { + polychrome_sprite.order = orders[polychrome_sprite.order as usize]; } + self.polychrome_sprites.sort_by_key(|sprite| sprite.order); - for (ix, surface) in self.surfaces.iter().enumerate() { - let z = layer_z_values[surface.order as LayerId as usize]; - self.splitter.add( - surface - .bounds - .to_bsp_polygon(z, (PrimitiveKind::Surface, ix)), - ); + for surface in &mut self.surfaces { + surface.order = orders[surface.order as usize]; } - - // Sort all polygons, then reassign the order field of each primitive to `draw_order` - // We need primitives to be repr(C), hence the weird reuse of the order field for two different types. - for (draw_order, polygon) in self - .splitter - .sort(Vector3D::new(0., 0., 1.)) - .iter() - .enumerate() - { - match polygon.anchor { - (PrimitiveKind::Shadow, ix) => self.shadows[ix].order = draw_order as DrawOrder, - (PrimitiveKind::Quad, ix) => self.quads[ix].order = draw_order as DrawOrder, - (PrimitiveKind::Path, ix) => self.paths[ix].order = draw_order as DrawOrder, - (PrimitiveKind::Underline, ix) => { - self.underlines[ix].order = draw_order as DrawOrder - } - (PrimitiveKind::MonochromeSprite, ix) => { - self.monochrome_sprites[ix].order = draw_order as DrawOrder - } - (PrimitiveKind::PolychromeSprite, ix) => { - self.polychrome_sprites[ix].order = draw_order as DrawOrder - } - (PrimitiveKind::Surface, ix) => self.surfaces[ix].order = draw_order as DrawOrder, - } - } - - self.shadows.sort_unstable(); - self.quads.sort_unstable(); - self.paths.sort_unstable(); - self.underlines.sort_unstable(); - self.monochrome_sprites.sort_unstable(); - self.polychrome_sprites.sort_unstable(); - self.surfaces.sort_unstable(); + self.surfaces.sort_by_key(|surface| surface.order); Scene { shadows: mem::take(&mut self.shadows), @@ -845,23 +785,3 @@ impl PathVertex { #[derive(Copy, Clone, Debug)] pub struct AtlasId(pub(crate) usize); - -impl Bounds { - fn to_bsp_polygon(&self, z: f32, anchor: A) -> BspPolygon { - let upper_left = self.origin; - let upper_right = self.upper_right(); - let lower_right = self.lower_right(); - let lower_left = self.lower_left(); - - BspPolygon::from_points( - [ - Point3D::new(upper_left.x.into(), upper_left.y.into(), z as f64), - Point3D::new(upper_right.x.into(), upper_right.y.into(), z as f64), - Point3D::new(lower_right.x.into(), lower_right.y.into(), z as f64), - Point3D::new(lower_left.x.into(), lower_left.y.into(), z as f64), - ], - anchor, - ) - .expect("Polygon should not be empty") - } -} diff --git a/crates/gpui2/src/style.rs b/crates/gpui2/src/style.rs index 3e9593b0fd..de54da79b3 100644 --- a/crates/gpui2/src/style.rs +++ b/crates/gpui2/src/style.rs @@ -402,13 +402,65 @@ impl Style { if self.is_border_visible() { cx.with_z_index(3, |cx| { - cx.paint_quad(quad( + let corner_radii = self.corner_radii.to_pixels(bounds.size, rem_size); + let border_widths = self.border_widths.to_pixels(rem_size); + let max_border_width = border_widths.max(); + let max_corner_radius = corner_radii.max(); + + let top_bounds = Bounds::from_corners( + bounds.origin, + bounds.upper_right() + + point(Pixels::ZERO, max_border_width.max(max_corner_radius)), + ); + let bottom_bounds = Bounds::from_corners( + bounds.lower_left() + - point(Pixels::ZERO, max_border_width.max(max_corner_radius)), + bounds.lower_right(), + ); + let left_bounds = Bounds::from_corners( + top_bounds.lower_left(), + bottom_bounds.origin + point(max_border_width, Pixels::ZERO), + ); + let right_bounds = Bounds::from_corners( + top_bounds.lower_right() - point(max_border_width, Pixels::ZERO), + bottom_bounds.upper_right(), + ); + + let quad = quad( bounds, - self.corner_radii.to_pixels(bounds.size, rem_size), + corner_radii, Hsla::transparent_black(), - self.border_widths.to_pixels(rem_size), + border_widths, self.border_color.unwrap_or_default(), - )); + ); + + cx.with_content_mask(Some(ContentMask { bounds: top_bounds }), |cx| { + cx.paint_quad(quad.clone()); + }); + cx.with_content_mask( + Some(ContentMask { + bounds: right_bounds, + }), + |cx| { + cx.paint_quad(quad.clone()); + }, + ); + cx.with_content_mask( + Some(ContentMask { + bounds: bottom_bounds, + }), + |cx| { + cx.paint_quad(quad.clone()); + }, + ); + cx.with_content_mask( + Some(ContentMask { + bounds: left_bounds, + }), + |cx| { + cx.paint_quad(quad); + }, + ); }); } diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index e57984fa0d..c20e2f7b94 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -3074,6 +3074,7 @@ impl From<(&'static str, u64)> for ElementId { } /// A rectangle, to be rendered on the screen by GPUI at the given position and size. +#[derive(Clone)] pub struct PaintQuad { bounds: Bounds, corner_radii: Corners,