From ad7974608b4cba79a5b500262da124e4da0c30ba Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 23 Mar 2021 19:11:56 +0100 Subject: [PATCH] WIP Co-Authored-By: Nathan Sobo --- Cargo.lock | 47 ++++++++ gpui/Cargo.toml | 1 + gpui/build.rs | 3 +- gpui/src/app.rs | 1 + gpui/src/fonts.rs | 112 +++++++++++------- gpui/src/platform/mac/app.rs | 5 +- gpui/src/platform/mac/renderer.rs | 121 ++++++++++++-------- gpui/src/platform/mac/shaders/shaders.h | 16 ++- gpui/src/platform/mac/shaders/shaders.metal | 42 ++++++- gpui/src/platform/mac/sprite_cache.rs | 67 +++++++++-- gpui/src/platform/mac/window.rs | 6 +- gpui/src/platform/mod.rs | 3 +- gpui/src/scene.rs | 2 +- gpui/src/text_layout.rs | 2 +- 14 files changed, 311 insertions(+), 117 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be9df0b8d2..602b2d6db4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,11 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "aho-corasick" version = "0.7.15" @@ -424,6 +430,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crossbeam-channel" version = "0.4.4" @@ -477,6 +492,16 @@ dependencies = [ "syn", ] +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + [[package]] name = "dirs" version = "3.0.1" @@ -776,6 +801,7 @@ dependencies = [ "pathfinder_color", "pathfinder_geometry", "pin-project", + "png", "rand 0.8.3", "replace_with", "smallvec", @@ -923,6 +949,15 @@ dependencies = [ "objc", ] +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + [[package]] name = "nb-connect" version = "1.0.3" @@ -1103,6 +1138,18 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide", +] + [[package]] name = "polling" version = "2.0.2" diff --git a/gpui/Cargo.toml b/gpui/Cargo.toml index 6cd0e889e2..e6843dce2e 100644 --- a/gpui/Cargo.toml +++ b/gpui/Cargo.toml @@ -14,6 +14,7 @@ parking_lot = "0.11.1" pathfinder_color = "0.5" pathfinder_geometry = "0.5" pin-project = "1.0.5" +png = "0.16" rand = "0.8.3" replace_with = "0.1.7" smallvec = "1.6.1" diff --git a/gpui/build.rs b/gpui/build.rs index 030145f2dd..b6d0f6ee8c 100644 --- a/gpui/build.rs +++ b/gpui/build.rs @@ -89,7 +89,8 @@ fn generate_shader_bindings() { .whitelist_type("GPUIQuad") .whitelist_type("GPUIShadowInputIndex") .whitelist_type("GPUIShadow") - .whitelist_type("GPUISpriteInputIndex") + .whitelist_type("GPUISpriteVertexInputIndex") + .whitelist_type("GPUISpriteFragmentInputIndex") .whitelist_type("GPUISprite") .parse_callbacks(Box::new(bindgen::CargoCallbacks)) .generate() diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 9183ce1b7d..eedf8e89c9 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -620,6 +620,7 @@ impl MutableAppContext { title: "Zed".into(), }, self.foreground.clone(), + self.fonts.clone(), ) { Err(e) => log::error!("error opening window: {}", e), Ok(mut window) => { diff --git a/gpui/src/fonts.rs b/gpui/src/fonts.rs index 27824bcc6d..c1e877b54f 100644 --- a/gpui/src/fonts.rs +++ b/gpui/src/fonts.rs @@ -1,5 +1,10 @@ -use crate::geometry::vector::{vec2f, Vector2F}; +use crate::geometry::{ + rect::RectI, + vector::{vec2f, Vector2F, Vector2I}, +}; use anyhow::{anyhow, Result}; +use cocoa::appkit::CGPoint; +use core_graphics::{base::CGGlyph, color_space::CGColorSpace, context::CGContext}; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; pub use font_kit::properties::{Properties, Weight}; @@ -9,6 +14,9 @@ use font_kit::{ use ordered_float::OrderedFloat; use std::{collections::HashMap, sync::Arc}; +#[allow(non_upper_case_globals)] +const kCGImageAlphaOnly: u32 = 7; + pub type GlyphId = u32; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -179,47 +187,43 @@ impl FontCache { self.scale_metric(self.metric(font_id, |m| m.descent), font_id, font_size) } - // pub fn render_emoji(&self, glyph_id: GlyphId, font_size: f32) -> Result { - // let key = (glyph_id, OrderedFloat(font_size)); + pub fn render_glyph( + &self, + font_id: FontId, + font_size: f32, + glyph_id: GlyphId, + scale_factor: f32, + ) -> Option<(Vector2I, Vec)> { + let native_font = self.native_font(font_id, font_size); + let glyph_id = glyph_id as CGGlyph; + let glyph_bounds = + native_font.get_bounding_rects_for_glyphs(Default::default(), &[glyph_id]); + let position = CGPoint::new(-glyph_bounds.origin.x, -glyph_bounds.origin.y); + let width = (glyph_bounds.size.width * scale_factor as f64).ceil() as usize; + let height = (glyph_bounds.size.height * scale_factor as f64).ceil() as usize; - // { - // if let Some(image) = self.0.read().emoji_images.get(&key) { - // return Ok(image.clone()); - // } - // } + if width == 0 || height == 0 { + None + } else { + let mut ctx = CGContext::create_bitmap_context( + None, + width, + height, + 8, + width, + &CGColorSpace::create_device_gray(), + kCGImageAlphaOnly, + ); + ctx.scale(scale_factor as f64, scale_factor as f64); + native_font.draw_glyphs(&[glyph_id], &[position], ctx.clone()); + ctx.flush(); - // let font_id = self.emoji_font_id()?; - // let bounding_box = self.bounding_box(font_id, font_size); - // let width = (4.0 * bounding_box.x()) as usize; - // let height = (4.0 * bounding_box.y()) as usize; - // let mut ctx = CGContext::create_bitmap_context( - // None, - // width, - // height, - // 8, - // width * 4, - // &CGColorSpace::create_device_rgb(), - // kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault, - // ); - // ctx.scale(4.0, 4.0); - - // let native_font = self.native_font(font_id, font_size); - // let glyph = glyph_id.0 as CGGlyph; - // let glyph_bounds = native_font.get_bounding_rects_for_glyphs(Default::default(), &[glyph]); - // let position = CGPoint::new(glyph_bounds.origin.x, -glyph_bounds.origin.y); - - // native_font.draw_glyphs(&[glyph], &[position], ctx.clone()); - - // ctx.flush(); - - // let image = Pattern::from_image(Image::new( - // vec2i(ctx.width() as i32, ctx.height() as i32), - // Arc::new(u8_slice_to_color_slice(&ctx.data()).into()), - // )); - // self.0.write().emoji_images.insert(key, image.clone()); - - // Ok(image) - // } + Some(( + Vector2I::new(width as i32, height as i32), + Vec::from(ctx.data()), + )) + } + } fn emoji_font_id(&self) -> Result { let state = self.0.upgradable_read(); @@ -285,3 +289,31 @@ fn push_font(state: &mut FontCacheState, font: Font) -> FontId { state.fonts_by_name.insert(name, font_id); font_id } + +#[cfg(test)] +mod tests { + use std::{fs::File, io::BufWriter, path::Path}; + + use super::*; + + #[test] + fn test_render_glyph() { + let cache = FontCache::new(); + let family_id = cache.load_family(&["Fira Code"]).unwrap(); + let font_id = cache.select_font(family_id, &Default::default()).unwrap(); + let glyph_id = cache.font(font_id).glyph_for_char('m').unwrap(); + let (size, bytes) = cache.render_glyph(font_id, 16.0, glyph_id, 1.).unwrap(); + + let path = Path::new(r"/Users/as-cii/Desktop/image.png"); + let file = File::create(path).unwrap(); + let ref mut w = BufWriter::new(file); + + let mut encoder = png::Encoder::new(w, size.x() as u32, size.y() as u32); + encoder.set_color(png::ColorType::Grayscale); + encoder.set_depth(png::BitDepth::Eight); + let mut writer = encoder.write_header().unwrap(); + + writer.write_image_data(&bytes).unwrap(); // Save + dbg!(size, bytes); + } +} diff --git a/gpui/src/platform/mac/app.rs b/gpui/src/platform/mac/app.rs index 58c184d81f..cb1f3cca91 100644 --- a/gpui/src/platform/mac/app.rs +++ b/gpui/src/platform/mac/app.rs @@ -1,5 +1,5 @@ use super::{BoolExt as _, Dispatcher, Window}; -use crate::{executor, platform}; +use crate::{executor, platform, FontCache}; use anyhow::Result; use cocoa::base::id; use objc::{class, msg_send, sel, sel_impl}; @@ -33,7 +33,8 @@ impl platform::App for App { &self, options: platform::WindowOptions, executor: Rc, + font_cache: Arc, ) -> Result> { - Ok(Box::new(Window::open(options, executor)?)) + Ok(Box::new(Window::open(options, executor, font_cache)?)) } } diff --git a/gpui/src/platform/mac/renderer.rs b/gpui/src/platform/mac/renderer.rs index ad01acca7b..2a9ae35312 100644 --- a/gpui/src/platform/mac/renderer.rs +++ b/gpui/src/platform/mac/renderer.rs @@ -3,17 +3,16 @@ use crate::{ color::ColorU, geometry::vector::{vec2i, Vector2I}, scene::Layer, - Scene, + FontCache, Scene, }; use anyhow::{anyhow, Result}; use metal::{MTLResourceOptions, NSRange}; -use shaders::{ToFloat2 as _, ToUchar4 as _, ToUint2 as _}; -use std::{collections::HashMap, ffi::c_void, mem}; +use shaders::{ToFloat2 as _, ToUchar4 as _}; +use std::{collections::HashMap, ffi::c_void, mem, sync::Arc}; 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, @@ -25,7 +24,11 @@ pub struct Renderer { } impl Renderer { - pub fn new(device: metal::Device, pixel_format: metal::MTLPixelFormat) -> Result { + pub fn new( + device: metal::Device, + pixel_format: metal::MTLPixelFormat, + font_cache: Arc, + ) -> Result { let library = device .new_library_with_data(SHADERS_METALLIB) .map_err(|message| anyhow!("error building metal library: {}", message))?; @@ -48,8 +51,9 @@ impl Renderer { MTLResourceOptions::StorageModeManaged, ); + let atlas_size: Vector2I = vec2i(1024, 768); Ok(Self { - sprite_cache: SpriteCache::new(device, ATLAS_SIZE), + sprite_cache: SpriteCache::new(device.clone(), atlas_size, font_cache), quad_pipeline_state: build_pipeline_state( &device, &library, @@ -261,43 +265,35 @@ impl Renderer { return; } - align_offset(offset); - let next_offset = *offset + layer.glyphs().len() * mem::size_of::(); - assert!( - next_offset <= INSTANCE_BUFFER_SIZE, - "instance buffer exhausted" - ); - - let mut sprites = HashMap::new(); + let mut sprites_by_atlas = HashMap::new(); for glyph in layer.glyphs() { - let (atlas, bounds) = - self.sprite_cache - .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_uint2(), - atlas_origin: bounds.origin().to_uint2(), - color: glyph.color.to_uchar4(), - }); + if let Some((atlas, bounds)) = self.sprite_cache.render_glyph( + glyph.font_id, + glyph.font_size, + glyph.id, + scene.scale_factor(), + ) { + sprites_by_atlas + .entry(atlas) + .or_insert_with(Vec::new) + .push(shaders::GPUISprite { + origin: (glyph.origin * scene.scale_factor()).to_float2(), + size: (bounds.size().to_f32() * scene.scale_factor()).to_float2(), + atlas_origin: bounds.origin().to_float2(), + color: glyph.color.to_uchar4(), + }); + } } ctx.command_encoder .set_render_pipeline_state(&self.sprite_pipeline_state); ctx.command_encoder.set_vertex_buffer( - shaders::GPUISpriteInputIndex_GPUISpriteInputIndexVertices as u64, + shaders::GPUISpriteVertexInputIndex_GPUISpriteVertexInputIndexVertices as u64, Some(&self.unit_vertices), 0, ); - ctx.command_encoder.set_vertex_buffer( - shaders::GPUISpriteInputIndex_GPUISpriteInputIndexSprites as u64, - Some(&self.instances), - *offset as u64, - ); ctx.command_encoder.set_vertex_bytes( - shaders::GPUISpriteInputIndex_GPUISpriteInputIndexUniforms as u64, + shaders::GPUISpriteVertexInputIndex_GPUISpriteVertexInputIndexUniforms as u64, mem::size_of::() as u64, [shaders::GPUIUniforms { viewport_size: ctx.drawable_size.to_float2(), @@ -310,8 +306,41 @@ impl Renderer { as *mut shaders::GPUISprite }; - for glyph in layer.glyphs() { - let sprite = self.sprite_cache.rasterize_glyph(); + for (atlas_id, sprites) in sprites_by_atlas { + align_offset(offset); + let next_offset = *offset + sprites.len() * mem::size_of::(); + assert!( + next_offset <= INSTANCE_BUFFER_SIZE, + "instance buffer exhausted" + ); + + ctx.command_encoder.set_vertex_buffer( + shaders::GPUISpriteVertexInputIndex_GPUISpriteVertexInputIndexSprites as u64, + Some(&self.instances), + *offset as u64, + ); + + let texture = self.sprite_cache.atlas_texture(atlas_id).unwrap(); + ctx.command_encoder.set_fragment_texture( + shaders::GPUISpriteFragmentInputIndex_GPUISpriteFragmentInputIndexAtlas as u64, + Some(texture), + ); + + unsafe { + std::ptr::copy_nonoverlapping(sprites.as_ptr(), buffer_contents, sprites.len()); + } + self.instances.did_modify_range(NSRange { + location: *offset as u64, + length: (next_offset - *offset) as u64, + }); + *offset = next_offset; + + ctx.command_encoder.draw_primitives_instanced( + metal::MTLPrimitiveType::Triangle, + 0, + 6, + sprites.len() as u64, + ); } } } @@ -377,10 +406,6 @@ 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 { @@ -403,6 +428,15 @@ mod shaders { } } + impl ToFloat2 for Vector2I { + fn to_float2(&self) -> vector_float2 { + let mut output = self.y() as vector_float2; + output <<= 32; + output |= self.x() as vector_float2; + output + } + } + impl ToUchar4 for ColorU { fn to_uchar4(&self) -> vector_uchar4 { let mut vec = self.a as vector_uchar4; @@ -415,13 +449,4 @@ 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 - } - } } diff --git a/gpui/src/platform/mac/shaders/shaders.h b/gpui/src/platform/mac/shaders/shaders.h index 44bbf07220..cabb9304de 100644 --- a/gpui/src/platform/mac/shaders/shaders.h +++ b/gpui/src/platform/mac/shaders/shaders.h @@ -37,14 +37,18 @@ typedef struct { } GPUIShadow; typedef enum { - GPUISpriteInputIndexVertices = 0, - GPUISpriteInputIndexSprites = 1, - GPUISpriteInputIndexUniforms = 2, -} GPUISpriteInputIndex; + GPUISpriteVertexInputIndexVertices = 0, + GPUISpriteVertexInputIndexSprites = 1, + GPUISpriteVertexInputIndexUniforms = 2, +} GPUISpriteVertexInputIndex; + +typedef enum { + GPUISpriteFragmentInputIndexAtlas = 0, +} GPUISpriteFragmentInputIndex; typedef struct { vector_float2 origin; - vector_uint2 size; - vector_uint2 atlas_origin; + vector_float2 size; + vector_float2 atlas_origin; vector_uchar4 color; } GPUISprite; diff --git a/gpui/src/platform/mac/shaders/shaders.metal b/gpui/src/platform/mac/shaders/shaders.metal index 0b6a37c441..422a9faf40 100644 --- a/gpui/src/platform/mac/shaders/shaders.metal +++ b/gpui/src/platform/mac/shaders/shaders.metal @@ -56,8 +56,7 @@ vertex QuadFragmentInput quad_vertex( } fragment float4 quad_fragment( - QuadFragmentInput input [[stage_in]], - constant GPUIUniforms *uniforms [[buffer(GPUIQuadInputIndexUniforms)]] + QuadFragmentInput input [[stage_in]] ) { float2 half_size = input.quad.size / 2.; float2 center = input.quad.origin + half_size; @@ -115,8 +114,7 @@ vertex ShadowFragmentInput shadow_vertex( } fragment float4 shadow_fragment( - ShadowFragmentInput input [[stage_in]], - constant GPUIUniforms *uniforms [[buffer(GPUIShadowInputIndexUniforms)]] + ShadowFragmentInput input [[stage_in]] ) { float sigma = input.shadow.sigma; float corner_radius = input.shadow.corner_radius; @@ -141,3 +139,39 @@ fragment float4 shadow_fragment( return float4(1., 1., 1., alpha) * coloru_to_colorf(input.shadow.color); } + +struct SpriteFragmentInput { + float4 position [[position]]; + float2 atlas_position; + float4 color [[flat]]; +}; + +vertex SpriteFragmentInput sprite_vertex( + uint unit_vertex_id [[vertex_id]], + uint sprite_id [[instance_id]], + constant float2 *unit_vertices [[buffer(GPUISpriteVertexInputIndexVertices)]], + constant GPUISprite *sprites [[buffer(GPUISpriteVertexInputIndexSprites)]], + constant GPUIUniforms *uniforms [[buffer(GPUISpriteVertexInputIndexUniforms)]] +) { + float2 unit_vertex = unit_vertices[unit_vertex_id]; + GPUISprite sprite = sprites[sprite_id]; + float2 position = unit_vertex * sprite.size + sprite.origin; + float2 atlas_position = unit_vertex * sprite.size + sprite.atlas_origin; + float4 device_position = to_device_position(position, uniforms->viewport_size); + + return SpriteFragmentInput { + device_position, + atlas_position, + coloru_to_colorf(sprite.color), + }; +} + +fragment float4 sprite_fragment( + SpriteFragmentInput input [[stage_in]], + texture2d atlas [[ texture(GPUISpriteFragmentInputIndexAtlas) ]] +) { + constexpr sampler atlas_sampler(mag_filter::linear, min_filter::linear); + float4 color = input.color; + color.a *= atlas.sample(atlas_sampler, input.atlas_position).r; + return color; +} diff --git a/gpui/src/platform/mac/sprite_cache.rs b/gpui/src/platform/mac/sprite_cache.rs index 186f0eb198..3b444f0953 100644 --- a/gpui/src/platform/mac/sprite_cache.rs +++ b/gpui/src/platform/mac/sprite_cache.rs @@ -2,7 +2,10 @@ use std::{collections::HashMap, sync::Arc}; use crate::{ fonts::{FontId, GlyphId}, - geometry::{rect::RectI, vector::Vector2I}, + geometry::{ + rect::RectI, + vector::{vec2i, Vector2I}, + }, FontCache, }; use etagere::BucketedAtlasAllocator; @@ -17,19 +20,21 @@ struct GlyphDescriptor { } pub struct SpriteCache { - font_cache: Arc, device: metal::Device, - size: Vector2I, + atlas_size: Vector2I, + font_cache: Arc, atlasses: Vec, - glyphs: HashMap, + glyphs: HashMap>, } impl SpriteCache { - pub fn new(device: metal::Device, size: Vector2I) -> Self { + pub fn new(device: metal::Device, size: Vector2I, font_cache: Arc) -> Self { + let atlasses = vec![Atlas::new(&device, size)]; Self { device, - size, - atlasses: vec![Atlas::new(&device, size)], + atlas_size: size, + font_cache, + atlasses, glyphs: Default::default(), } } @@ -39,7 +44,12 @@ impl SpriteCache { font_id: FontId, font_size: f32, glyph_id: GlyphId, - ) -> (usize, RectI) { + scale_factor: f32, + ) -> Option<(usize, RectI)> { + let font_cache = &self.font_cache; + let atlasses = &mut self.atlasses; + let atlas_size = self.atlas_size; + let device = &self.device; self.glyphs .entry(GlyphDescriptor { font_id, @@ -47,12 +57,27 @@ impl SpriteCache { 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!() + let (size, mask) = + font_cache.render_glyph(font_id, font_size, glyph_id, scale_factor)?; + assert!(size.x() < atlas_size.x()); + assert!(size.y() < atlas_size.y()); + + let atlas = atlasses.last_mut().unwrap(); + if let Some(bounds) = atlas.try_insert(size, &mask) { + Some((atlasses.len() - 1, bounds)) + } else { + let mut atlas = Atlas::new(device, atlas_size); + let bounds = atlas.try_insert(size, &mask).unwrap(); + atlasses.push(atlas); + Some((atlasses.len() - 1, bounds)) + } }) .clone() } + + pub fn atlas_texture(&self, atlas_id: usize) -> Option<&metal::TextureRef> { + self.atlasses.get(atlas_id).map(|a| a.texture.as_ref()) + } } struct Atlas { @@ -72,4 +97,24 @@ impl Atlas { texture: device.new_texture(&descriptor), } } + + fn try_insert(&mut self, size: Vector2I, mask: &[u8]) -> Option { + let allocation = self + .allocator + .allocate(etagere::size2(size.x(), size.y()))?; + + let bounds = allocation.rectangle; + let region = metal::MTLRegion::new_2d( + bounds.min.x as u64, + bounds.min.y as u64, + bounds.width() as u64, + bounds.height() as u64, + ); + self.texture + .replace_region(region, 0, mask.as_ptr() as *const _, size.x() as u64); + Some(RectI::from_points( + vec2i(bounds.min.x, bounds.min.y), + vec2i(bounds.max.x, bounds.max.y), + )) + } } diff --git a/gpui/src/platform/mac/window.rs b/gpui/src/platform/mac/window.rs index 3ccc8d3eb3..98e40aa6a3 100644 --- a/gpui/src/platform/mac/window.rs +++ b/gpui/src/platform/mac/window.rs @@ -2,7 +2,7 @@ use crate::{ executor, geometry::vector::Vector2F, platform::{self, Event, WindowContext}, - Scene, + FontCache, Scene, }; use anyhow::{anyhow, Result}; use cocoa::{ @@ -31,6 +31,7 @@ use std::{ ffi::c_void, mem, ptr, rc::{Rc, Weak}, + sync::Arc, time::Duration, }; @@ -140,6 +141,7 @@ impl Window { pub fn open( options: platform::WindowOptions, executor: Rc, + font_cache: Arc, ) -> Result { const PIXEL_FORMAT: metal::MTLPixelFormat = metal::MTLPixelFormat::BGRA8Unorm; @@ -192,7 +194,7 @@ impl Window { synthetic_drag_counter: 0, executor, scene_to_render: Default::default(), - renderer: Renderer::new(device, PIXEL_FORMAT)?, + renderer: Renderer::new(device.clone(), PIXEL_FORMAT, font_cache)?, command_queue: device.new_command_queue(), device, layer, diff --git a/gpui/src/platform/mod.rs b/gpui/src/platform/mod.rs index 6ab2146225..a5e2ed3411 100644 --- a/gpui/src/platform/mod.rs +++ b/gpui/src/platform/mod.rs @@ -9,7 +9,7 @@ pub mod current { use crate::{ executor, geometry::{rect::RectF, vector::Vector2F}, - Scene, + FontCache, Scene, }; use anyhow::Result; use async_task::Runnable; @@ -32,6 +32,7 @@ pub trait App { &self, options: WindowOptions, executor: Rc, + font_cache: Arc, ) -> Result>; } diff --git a/gpui/src/scene.rs b/gpui/src/scene.rs index 3edc373055..cd478a8493 100644 --- a/gpui/src/scene.rs +++ b/gpui/src/scene.rs @@ -38,7 +38,7 @@ pub struct Shadow { pub struct Glyph { pub font_id: FontId, pub font_size: f32, - pub glyph_id: GlyphId, + pub id: GlyphId, pub origin: Vector2F, pub color: ColorU, } diff --git a/gpui/src/text_layout.rs b/gpui/src/text_layout.rs index 1a75ca527f..0a9717b388 100644 --- a/gpui/src/text_layout.rs +++ b/gpui/src/text_layout.rs @@ -228,7 +228,7 @@ impl Line { ctx.scene.push_glyph(scene::Glyph { font_id: run.font_id, font_size: self.font_size, - glyph_id: glyph.id, + id: glyph.id, origin: glyph_origin, color, });