Checkpoint

Antonio Scandurra created

Change summary

crates/gpui3/src/geometry.rs                    |   6 
crates/gpui3/src/platform.rs                    |  27 ++
crates/gpui3/src/platform/mac/metal_atlas.rs    |   2 
crates/gpui3/src/platform/mac/metal_renderer.rs |  10 
crates/gpui3/src/scene.rs                       | 160 +++++++++---------
crates/gpui3/src/style.rs                       |   3 
6 files changed, 121 insertions(+), 87 deletions(-)

Detailed changes

crates/gpui3/src/geometry.rs 🔗

@@ -206,7 +206,7 @@ impl Size<Length> {
     }
 }
 
-#[derive(Refineable, Clone, Default, Debug, PartialEq)]
+#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
 #[refineable(debug)]
 #[repr(C)]
 pub struct Bounds<T: Clone + Debug> {
@@ -289,7 +289,7 @@ impl<T: Clone + Debug + PartialOrd + Add<T, Output = T>> Bounds<T> {
 
 impl<T: Clone + Debug + Copy> Copy for Bounds<T> {}
 
-#[derive(Refineable, Clone, Default, Debug)]
+#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
 #[refineable(debug)]
 #[repr(C)]
 pub struct Edges<T: Clone + Debug> {
@@ -396,7 +396,7 @@ impl Edges<AbsoluteLength> {
     }
 }
 
-#[derive(Refineable, Clone, Default, Debug)]
+#[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
 #[refineable(debug)]
 #[repr(C)]
 pub struct Corners<T: Clone + Debug> {

crates/gpui3/src/platform.rs 🔗

@@ -14,6 +14,7 @@ use async_task::Runnable;
 use futures::channel::oneshot;
 use seahash::SeaHasher;
 use serde::{Deserialize, Serialize};
+use std::cmp::Ordering;
 use std::ffi::c_void;
 use std::hash::{Hash, Hasher};
 use std::{
@@ -187,7 +188,7 @@ pub trait PlatformAtlas<Key>: Send + Sync {
     fn clear(&self);
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 #[repr(C)]
 pub struct AtlasTile {
     pub(crate) texture_id: AtlasTextureId,
@@ -195,11 +196,31 @@ pub struct AtlasTile {
     pub(crate) bounds_in_atlas: Bounds<DevicePixels>,
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 #[repr(C)]
 pub(crate) struct AtlasTextureId(pub(crate) usize);
 
-pub(crate) type TileId = etagere::AllocId;
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[repr(C)]
+pub(crate) struct TileId(pub(crate) etagere::AllocId);
+
+impl From<etagere::AllocId> for TileId {
+    fn from(id: etagere::AllocId) -> Self {
+        Self(id)
+    }
+}
+
+impl Ord for TileId {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.0.serialize().cmp(&other.0.serialize())
+    }
+}
+
+impl PartialOrd for TileId {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
 
 pub trait PlatformInputHandler {
     fn selected_text_range(&self) -> Option<Range<usize>>;

crates/gpui3/src/platform/mac/metal_atlas.rs 🔗

@@ -119,7 +119,7 @@ impl MetalAtlasTexture {
         let allocation = self.allocator.allocate(size)?;
         let tile = AtlasTile {
             texture_id: self.id,
-            tile_id: allocation.id,
+            tile_id: allocation.id.into(),
             bounds_in_atlas: allocation.rectangle.into(),
         };
         let region = metal::MTLRegion::new_2d(

crates/gpui3/src/platform/mac/metal_renderer.rs 🔗

@@ -1,5 +1,6 @@
 use crate::{
-    point, size, DevicePixels, MetalAtlas, MonochromeSprite, Quad, RasterizedGlyphId, Scene, Size,
+    point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, Quad,
+    RasterizedGlyphId, Scene, Size,
 };
 use bytemuck::{Pod, Zeroable};
 use cocoa::{
@@ -186,8 +187,12 @@ impl MetalRenderer {
                             command_encoder,
                         );
                     }
-                    crate::PrimitiveBatch::Sprites(sprites) => {
+                    crate::PrimitiveBatch::Sprites {
+                        texture_id,
+                        sprites,
+                    } => {
                         self.draw_monochrome_sprites(
+                            texture_id,
                             sprites,
                             &mut instance_offset,
                             viewport_size,
@@ -270,6 +275,7 @@ impl MetalRenderer {
 
     fn draw_monochrome_sprites(
         &mut self,
+        texture_id: AtlasTextureId,
         monochrome: &[MonochromeSprite],
         offset: &mut usize,
         viewport_size: Size<DevicePixels>,

crates/gpui3/src/scene.rs 🔗

@@ -1,8 +1,10 @@
 use std::{iter::Peekable, mem};
 
 use super::{Bounds, Hsla, Pixels, Point};
-use crate::{AtlasTile, Corners, DevicePixels, Edges};
+use crate::{AtlasTextureId, AtlasTile, Corners, Edges};
 use bytemuck::{Pod, Zeroable};
+use collections::BTreeMap;
+use smallvec::SmallVec;
 
 // Exported to metal
 pub type PointF = Point<f32>;
@@ -38,8 +40,7 @@ impl Scene {
                 quad.scale(self.scale_factor);
                 layer.quads.push(quad);
             }
-            Primitive::Sprite(mut sprite) => {
-                sprite.scale(self.scale_factor);
+            Primitive::Sprite(sprite) => {
                 layer.sprites.push(sprite);
             }
         }
@@ -58,8 +59,8 @@ pub(crate) struct SceneLayer {
 
 impl SceneLayer {
     pub fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> {
-        self.quads.sort_unstable_by(|a, b| a.order.cmp(&b.order));
-        self.sprites.sort_unstable_by(|a, b| a.order.cmp(&b.order));
+        self.quads.sort_unstable();
+        self.sprites.sort_unstable();
 
         BatchIterator::new(
             &self.quads,
@@ -75,7 +76,6 @@ where
     Q: Iterator<Item = &'a Quad>,
     S: Iterator<Item = &'a MonochromeSprite>,
 {
-    next_batch_kind: Option<PrimitiveKind>,
     quads: &'a [Quad],
     sprites: &'a [MonochromeSprite],
     quads_start: usize,
@@ -92,41 +92,52 @@ where
     type Item = PrimitiveBatch<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
-        if let Some(batch_kind) = self.next_batch_kind.take() {
-            match batch_kind {
-                PrimitiveKind::Quad => {
-                    let max_order = self
-                        .next_order(Some(PrimitiveKind::Quad))
-                        .unwrap_or(u32::MAX);
-                    let quads_start = self.quads_start;
-                    let quads_end = quads_start
-                        + self
-                            .quads_iter
-                            .by_ref()
-                            .take_while(|quad| quad.order <= max_order)
-                            .count();
-                    self.quads_start = quads_end;
-                    Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
-                }
-                PrimitiveKind::Sprite => {
-                    let max_order = self
-                        .next_order(Some(PrimitiveKind::Sprite))
-                        .unwrap_or(u32::MAX);
-                    let sprites_start = self.sprites_start;
-                    let sprites_end = sprites_start
-                        + self
-                            .sprites_iter
-                            .by_ref()
-                            .take_while(|sprite| sprite.order <= max_order)
-                            .count();
-                    self.sprites_start = sprites_end;
-                    Some(PrimitiveBatch::Sprites(
-                        &self.sprites[sprites_start..sprites_end],
-                    ))
-                }
-            }
+        let mut kinds_and_orders = [
+            (PrimitiveKind::Quad, self.quads_iter.peek().map(|q| q.order)),
+            (
+                PrimitiveKind::Sprite,
+                self.sprites_iter.peek().map(|s| s.order),
+            ),
+        ];
+        kinds_and_orders.sort_by_key(|(_, order)| order.unwrap_or(u32::MAX));
+
+        let first = kinds_and_orders[0];
+        let second = kinds_and_orders[1];
+        let (batch_kind, max_order) = if first.1.is_some() {
+            (first.0, second.1.unwrap_or(u32::MAX))
         } else {
-            None
+            return None;
+        };
+
+        match batch_kind {
+            PrimitiveKind::Quad => {
+                let quads_start = self.quads_start;
+                let quads_end = quads_start
+                    + self
+                        .quads_iter
+                        .by_ref()
+                        .take_while(|quad| quad.order <= max_order)
+                        .count();
+                self.quads_start = quads_end;
+                Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
+            }
+            PrimitiveKind::Sprite => {
+                let texture_id = self.sprites_iter.peek().unwrap().tile.texture_id;
+                let sprites_start = self.sprites_start;
+                let sprites_end = sprites_start
+                    + self
+                        .sprites_iter
+                        .by_ref()
+                        .take_while(|sprite| {
+                            sprite.order <= max_order && sprite.tile.texture_id == texture_id
+                        })
+                        .count();
+                self.sprites_start = sprites_end;
+                Some(PrimitiveBatch::Sprites {
+                    texture_id,
+                    sprites: &self.sprites[sprites_start..sprites_end],
+                })
+            }
         }
     }
 }
@@ -142,39 +153,14 @@ where
         sprites: &'a [MonochromeSprite],
         sprites_iter: Peekable<S>,
     ) -> Self {
-        let mut this = Self {
+        Self {
             quads,
             quads_start: 0,
             quads_iter,
             sprites,
             sprites_start: 0,
             sprites_iter,
-            next_batch_kind: None,
-        };
-        this.next_order(None); // Called for its side effect of setting this.next_batch_kind
-        this
-    }
-
-    fn next_order(&mut self, exclude_kind: Option<PrimitiveKind>) -> Option<u32> {
-        let mut next_order = u32::MAX;
-
-        if exclude_kind != Some(PrimitiveKind::Quad) {
-            if let Some(next_quad) = self.quads_iter.peek() {
-                self.next_batch_kind = Some(PrimitiveKind::Quad);
-                next_order = next_quad.order;
-            }
         }
-
-        if exclude_kind != Some(PrimitiveKind::Sprite) {
-            if let Some(next_sprite) = self.sprites_iter.peek() {
-                if next_sprite.order < next_order {
-                    self.next_batch_kind = Some(PrimitiveKind::Sprite);
-                    next_order = next_sprite.order;
-                }
-            }
-        }
-
-        (next_order < u32::MAX).then_some(next_order)
     }
 }
 
@@ -190,12 +176,15 @@ pub enum Primitive {
     Sprite(MonochromeSprite),
 }
 
-pub enum PrimitiveBatch<'a> {
+pub(crate) enum PrimitiveBatch<'a> {
     Quads(&'a [Quad]),
-    Sprites(&'a [MonochromeSprite]),
+    Sprites {
+        texture_id: AtlasTextureId,
+        sprites: &'a [MonochromeSprite],
+    },
 }
 
-#[derive(Debug, Copy, Clone, Zeroable, Pod)]
+#[derive(Debug, Copy, Clone, Zeroable, Pod, Eq, PartialEq)]
 #[repr(C)]
 pub struct Quad {
     pub order: u32,
@@ -232,13 +221,25 @@ impl Quad {
     }
 }
 
+impl Ord for Quad {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.order.cmp(&other.order)
+    }
+}
+
+impl PartialOrd for Quad {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
 impl From<Quad> for Primitive {
     fn from(quad: Quad) -> Self {
         Primitive::Quad(quad)
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq)]
 #[repr(C)]
 pub struct MonochromeSprite {
     pub order: u32,
@@ -247,9 +248,18 @@ pub struct MonochromeSprite {
     pub tile: AtlasTile,
 }
 
-impl MonochromeSprite {
-    pub fn scale(&mut self, factor: f32) {
-        self.bounds *= factor;
+impl Ord for MonochromeSprite {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        match self.order.cmp(&other.order) {
+            std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
+            order => order,
+        }
+    }
+}
+
+impl PartialOrd for MonochromeSprite {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
     }
 }
 
@@ -261,7 +271,3 @@ impl From<MonochromeSprite> for Primitive {
 
 #[derive(Copy, Clone, Debug)]
 pub struct AtlasId(pub(crate) usize);
-
-use collections::BTreeMap;
-use etagere::AllocId as TileId;
-use smallvec::SmallVec;

crates/gpui3/src/style.rs 🔗

@@ -185,8 +185,9 @@ impl Style {
 
         let background_color = self.fill.as_ref().and_then(Fill::color);
         if background_color.is_some() || self.is_border_visible() {
+            let layer_id = cx.current_layer_id();
             cx.scene().insert(
-                todo!(),
+                layer_id,
                 Quad {
                     order,
                     bounds,