WIP

Nathan Sobo created

Change summary

gpui/src/platform/mac/renderer.rs       | 49 ++++++++++++-----
gpui/src/platform/mac/shaders/shaders.h |  4 
gpui/src/platform/mac/sprite_cache.rs   | 72 ++++++++++++++++++++++++---
gpui/src/platform/mac/window.rs         |  2 
4 files changed, 101 insertions(+), 26 deletions(-)

Detailed changes

gpui/src/platform/mac/renderer.rs 🔗

@@ -1,28 +1,31 @@
-use std::{collections::HashMap, ffi::c_void, mem};
-
-use self::shaders::ToUchar4;
-
-use super::window::RenderContext;
-use crate::{color::ColorU, scene::Layer, Scene};
+use super::{sprite_cache::SpriteCache, window::RenderContext};
+use crate::{
+    color::ColorU,
+    geometry::vector::{vec2i, Vector2I},
+    scene::Layer,
+    Scene,
+};
 use anyhow::{anyhow, Result};
 use metal::{MTLResourceOptions, NSRange};
-use shaders::ToFloat2 as _;
+use shaders::{ToFloat2 as _, ToUchar4 as _, ToUint2 as _};
+use std::{collections::HashMap, ffi::c_void, mem};
 
 const SHADERS_METALLIB: &'static [u8] =
     include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
 const INSTANCE_BUFFER_SIZE: usize = 1024 * 1024; // This is an arbitrary decision. There's probably a more optimal value.
+const ATLAS_SIZE: Vector2I = vec2i(1024, 768);
 
 pub struct Renderer {
+    sprite_cache: SpriteCache,
     quad_pipeline_state: metal::RenderPipelineState,
     shadow_pipeline_state: metal::RenderPipelineState,
     sprite_pipeline_state: metal::RenderPipelineState,
     unit_vertices: metal::Buffer,
     instances: metal::Buffer,
-    sprite_cache: SpriteCache,
 }
 
 impl Renderer {
-    pub fn new(device: &metal::DeviceRef, pixel_format: metal::MTLPixelFormat) -> Result<Self> {
+    pub fn new(device: metal::Device, pixel_format: metal::MTLPixelFormat) -> Result<Self> {
         let library = device
             .new_library_with_data(SHADERS_METALLIB)
             .map_err(|message| anyhow!("error building metal library: {}", message))?;
@@ -46,8 +49,9 @@ impl Renderer {
         );
 
         Ok(Self {
+            sprite_cache: SpriteCache::new(device, ATLAS_SIZE),
             quad_pipeline_state: build_pipeline_state(
-                device,
+                &device,
                 &library,
                 "quad",
                 "quad_vertex",
@@ -55,7 +59,7 @@ impl Renderer {
                 pixel_format,
             )?,
             shadow_pipeline_state: build_pipeline_state(
-                device,
+                &device,
                 &library,
                 "shadow",
                 "shadow_vertex",
@@ -63,7 +67,7 @@ impl Renderer {
                 pixel_format,
             )?,
             sprite_pipeline_state: build_pipeline_state(
-                device,
+                &device,
                 &library,
                 "sprite",
                 "sprite_vertex",
@@ -268,14 +272,14 @@ impl Renderer {
         for glyph in layer.glyphs() {
             let (atlas, bounds) =
                 self.sprite_cache
-                    .rasterize_glyph(glyph.font_id, glyph.font_size, glyph.glyph_id);
+                    .render_glyph(glyph.font_id, glyph.font_size, glyph.glyph_id);
             sprites
                 .entry(atlas)
                 .or_insert_with(Vec::new)
                 .push(shaders::GPUISprite {
                     origin: glyph.origin.to_float2(),
-                    size: bounds.size().to_float2(),
-                    atlas_origin: bounds.origin().to_float2(),
+                    size: bounds.size().to_uint2(),
+                    atlas_origin: bounds.origin().to_uint2(),
                     color: glyph.color.to_uchar4(),
                 });
         }
@@ -358,6 +362,8 @@ mod shaders {
     #![allow(non_camel_case_types)]
     #![allow(non_snake_case)]
 
+    use pathfinder_geometry::vector::Vector2I;
+
     use crate::{color::ColorU, geometry::vector::Vector2F};
     use std::mem;
 
@@ -371,6 +377,10 @@ mod shaders {
         fn to_uchar4(&self) -> vector_uchar4;
     }
 
+    pub trait ToUint2 {
+        fn to_uint2(&self) -> vector_uint2;
+    }
+
     impl ToFloat2 for (f32, f32) {
         fn to_float2(&self) -> vector_float2 {
             unsafe {
@@ -405,4 +415,13 @@ mod shaders {
             vec
         }
     }
+
+    impl ToUint2 for Vector2I {
+        fn to_uint2(&self) -> vector_uint2 {
+            let mut output = self.y() as vector_uint2;
+            output <<= 32;
+            output |= self.x() as vector_uint2;
+            output
+        }
+    }
 }

gpui/src/platform/mac/shaders/shaders.h 🔗

@@ -44,7 +44,7 @@ typedef enum {
 
 typedef struct {
     vector_float2 origin;
-    vector_float2 size;
-    vector_float2 atlas_origin;
+    vector_uint2 size;
+    vector_uint2 atlas_origin;
     vector_uchar4 color;
 } GPUISprite;

gpui/src/platform/mac/sprite_cache.rs 🔗

@@ -1,19 +1,75 @@
-use crate::geometry::vector::Vector2I;
+use std::{collections::HashMap, sync::Arc};
+
+use crate::{
+    fonts::{FontId, GlyphId},
+    geometry::{rect::RectI, vector::Vector2I},
+    FontCache,
+};
 use etagere::BucketedAtlasAllocator;
+use metal::{MTLPixelFormat, TextureDescriptor};
+use ordered_float::OrderedFloat;
+
+#[derive(Hash, Eq, PartialEq)]
+struct GlyphDescriptor {
+    font_id: FontId,
+    font_size: OrderedFloat<f32>,
+    glyph_id: GlyphId,
+}
 
-struct SpriteCache {
-    atlasses: Vec<etagere::BucketedAtlasAllocator>,
+pub struct SpriteCache {
+    font_cache: Arc<FontCache>,
+    device: metal::Device,
+    size: Vector2I,
+    atlasses: Vec<Atlas>,
+    glyphs: HashMap<GlyphDescriptor, (usize, RectI)>,
 }
 
 impl SpriteCache {
-    fn new(size: Vector2I) -> Self {
-        let size = etagere::Size::new(size.x(), size.y());
+    pub fn new(device: metal::Device, size: Vector2I) -> Self {
         Self {
-            atlasses: vec![BucketedAtlasAllocator::new(size)],
+            device,
+            size,
+            atlasses: vec![Atlas::new(&device, size)],
+            glyphs: Default::default(),
         }
     }
 
-    fn render_glyph(&mut self) {
-        self.atlasses.last().unwrap()
+    pub fn render_glyph(
+        &mut self,
+        font_id: FontId,
+        font_size: f32,
+        glyph_id: GlyphId,
+    ) -> (usize, RectI) {
+        self.glyphs
+            .entry(GlyphDescriptor {
+                font_id,
+                font_size: OrderedFloat(font_size),
+                glyph_id,
+            })
+            .or_insert_with(|| {
+                let rendered_glyph = self.font_cache.render_glyph(font_id, font_size, glyph_id);
+                // let atlas = self.atlasses.last_mut().unwrap();
+                todo!()
+            })
+            .clone()
+    }
+}
+
+struct Atlas {
+    allocator: BucketedAtlasAllocator,
+    texture: metal::Texture,
+}
+
+impl Atlas {
+    fn new(device: &metal::DeviceRef, size: Vector2I) -> Self {
+        let descriptor = TextureDescriptor::new();
+        descriptor.set_pixel_format(MTLPixelFormat::A8Unorm);
+        descriptor.set_width(size.x() as u64);
+        descriptor.set_height(size.y() as u64);
+
+        Self {
+            allocator: BucketedAtlasAllocator::new(etagere::Size::new(size.x(), size.y())),
+            texture: device.new_texture(&descriptor),
+        }
     }
 }

gpui/src/platform/mac/window.rs 🔗

@@ -192,7 +192,7 @@ impl Window {
                 synthetic_drag_counter: 0,
                 executor,
                 scene_to_render: Default::default(),
-                renderer: Renderer::new(&device, PIXEL_FORMAT)?,
+                renderer: Renderer::new(device, PIXEL_FORMAT)?,
                 command_queue: device.new_command_queue(),
                 device,
                 layer,