From 08464ee26eada69ab9b642e78f2c1bd91205d04e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 3 Oct 2023 15:23:49 +0200 Subject: [PATCH] Checkpoint --- crates/gpui3/src/platform.rs | 12 +++-- crates/gpui3/src/platform/mac/metal_atlas.rs | 50 ++++++++++++++----- .../gpui3/src/platform/mac/metal_renderer.rs | 21 +++++++- crates/gpui3/src/platform/mac/text_system.rs | 16 +++--- crates/gpui3/src/platform/mac/window.rs | 15 ++++-- crates/gpui3/src/text_system.rs | 31 +++++++----- crates/gpui3/src/text_system/line.rs | 10 ++-- .../src/text_system/text_layout_cache.rs | 12 ++--- crates/gpui3/src/window.rs | 10 ++-- 9 files changed, 118 insertions(+), 59 deletions(-) diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index 2bd5b942e60b5e53d7306d5d392d980e44d0b99e..1179a83618ab8420170490fe817d3f03da06333c 100644 --- a/crates/gpui3/src/platform.rs +++ b/crates/gpui3/src/platform.rs @@ -6,8 +6,8 @@ mod mac; mod test; use crate::{ - AnyWindowHandle, Bounds, DevicePixels, Font, FontId, FontMetrics, GlyphId, LineLayout, - MonochromeSprite, Pixels, Point, Result, Scene, SharedString, Size, + AnyWindowHandle, Bounds, DevicePixels, Font, FontId, FontMetrics, GlyphId, MonochromeSprite, + Pixels, Point, RasterizedGlyphId, Result, Scene, ShapedLine, SharedString, Size, }; use anyhow::anyhow; use async_task::Runnable; @@ -146,6 +146,8 @@ pub trait PlatformWindow { fn on_appearance_changed(&self, callback: Box); fn is_topmost_for_position(&self, position: Point) -> bool; fn draw(&self, scene: Scene); + + fn glyph_atlas(&self) -> Arc>; } pub trait PlatformDispatcher: Send + Sync { @@ -170,7 +172,7 @@ pub trait PlatformTextSystem: Send + Sync { scale_factor: f32, options: RasterizationOptions, ) -> Option<(Bounds, Vec)>; - fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, FontId)]) -> LineLayout; + fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, FontId)]) -> ShapedLine; fn wrap_line( &self, text: &str, @@ -180,11 +182,11 @@ pub trait PlatformTextSystem: Send + Sync { ) -> Vec; } -pub trait PlatformAtlas { +pub trait PlatformAtlas: Send + Sync { fn get_or_insert_with( &self, key: Key, - build: impl FnOnce() -> (Size, Vec), + build: &dyn Fn() -> (Size, Vec), ) -> AtlasTile; fn clear(&self); diff --git a/crates/gpui3/src/platform/mac/metal_atlas.rs b/crates/gpui3/src/platform/mac/metal_atlas.rs index 926d7df8b67c064d619acfe5eb1adcd329b456b6..96cb1a64ed5eb0b6d721d008e930598cd7ab89b2 100644 --- a/crates/gpui3/src/platform/mac/metal_atlas.rs +++ b/crates/gpui3/src/platform/mac/metal_atlas.rs @@ -1,35 +1,54 @@ use crate::{AtlasTextureId, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size}; use collections::HashMap; +use derive_more::{Deref, DerefMut}; use etagere::BucketedAtlasAllocator; use foreign_types::ForeignType; -use metal::{Device, TextureDescriptor, TextureDescriptorRef}; +use metal::{Device, TextureDescriptor}; use objc::{msg_send, sel, sel_impl}; -use parking_lot::{RwLock, RwLockUpgradableReadGuard}; +use parking_lot::Mutex; use std::hash::Hash; -pub struct MetalAtlas(RwLock>); +pub struct MetalAtlas(Mutex>); + +impl MetalAtlas { + pub fn new( + size: Size, + pixel_format: metal::MTLPixelFormat, + device: Device, + ) -> Self { + let texture_descriptor = metal::TextureDescriptor::new(); + texture_descriptor.set_pixel_format(pixel_format); + texture_descriptor.set_width(size.width.into()); + texture_descriptor.set_height(size.height.into()); + MetalAtlas(Mutex::new(MetalAtlasState { + device: AssertSend(device), + texture_descriptor: AssertSend(texture_descriptor), + textures: Default::default(), + tiles_by_key: Default::default(), + })) + } +} struct MetalAtlasState { - device: Device, - texture_descriptor: TextureDescriptor, + device: AssertSend, + texture_descriptor: AssertSend, textures: Vec, tiles_by_key: HashMap, } impl PlatformAtlas for MetalAtlas where - Key: Eq + Hash, + Key: Eq + Hash + Send, { fn get_or_insert_with( &self, key: Key, - build: impl FnOnce() -> (Size, Vec), + build: &dyn Fn() -> (Size, Vec), ) -> AtlasTile { - let lock = self.0.upgradable_read(); + let mut lock = self.0.lock(); if let Some(tile) = lock.tiles_by_key.get(&key) { return tile.clone(); } else { - let mut lock = RwLockUpgradableReadGuard::upgrade(lock); let (size, bytes) = build(); lock.textures .iter_mut() @@ -45,7 +64,7 @@ where } fn clear(&self) { - self.0.write().tiles_by_key.clear(); + self.0.lock().tiles_by_key.clear(); } } @@ -62,7 +81,7 @@ impl MetalAtlasState { { let descriptor = unsafe { let descriptor_ptr: *mut metal::MTLTextureDescriptor = - msg_send![self.texture_descriptor, copy]; + msg_send![*self.texture_descriptor, copy]; metal::TextureDescriptor::from_ptr(descriptor_ptr) }; descriptor.set_width(min_size.width.into()); @@ -78,7 +97,7 @@ impl MetalAtlasState { let atlas_texture = MetalAtlasTexture { id: AtlasTextureId(self.textures.len()), allocator: etagere::BucketedAtlasAllocator::new(size.into()), - metal_texture, + metal_texture: AssertSend(metal_texture), }; self.textures.push(atlas_texture); self.textures.last_mut().unwrap() @@ -88,7 +107,7 @@ impl MetalAtlasState { struct MetalAtlasTexture { id: AtlasTextureId, allocator: BucketedAtlasAllocator, - metal_texture: metal::Texture, + metal_texture: AssertSend, } impl MetalAtlasTexture { @@ -162,3 +181,8 @@ impl From for Bounds { } } } + +#[derive(Deref, DerefMut)] +struct AssertSend(T); + +unsafe impl Send for AssertSend {} diff --git a/crates/gpui3/src/platform/mac/metal_renderer.rs b/crates/gpui3/src/platform/mac/metal_renderer.rs index d49b0d94f4dd82b99469ddaed12729d40070042c..56c0f130810f32f4eed3cb0605f3a9fb4737e718 100644 --- a/crates/gpui3/src/platform/mac/metal_renderer.rs +++ b/crates/gpui3/src/platform/mac/metal_renderer.rs @@ -1,4 +1,6 @@ -use crate::{point, size, DevicePixels, MonochromeSprite, Quad, Scene, Size}; +use crate::{ + point, size, DevicePixels, MetalAtlas, MonochromeSprite, Quad, RasterizedGlyphId, Scene, Size, +}; use bytemuck::{Pod, Zeroable}; use cocoa::{ base::{NO, YES}, @@ -7,7 +9,7 @@ use cocoa::{ }; use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange}; use objc::{self, msg_send, sel, sel_impl}; -use std::{ffi::c_void, mem, ptr}; +use std::{ffi::c_void, mem, ptr, sync::Arc}; const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. @@ -19,6 +21,7 @@ pub struct MetalRenderer { quad_pipeline_state: metal::RenderPipelineState, unit_vertices: metal::Buffer, instances: metal::Buffer, + glyph_atlas: Arc>, } impl MetalRenderer { @@ -88,6 +91,15 @@ impl MetalRenderer { ); let command_queue = device.new_command_queue(); + let glyph_atlas = Arc::new(MetalAtlas::new( + Size { + width: DevicePixels(1024), + height: DevicePixels(1024), + }, + MTLPixelFormat::A8Unorm, + device.clone(), + )); + Self { device, layer, @@ -95,6 +107,7 @@ impl MetalRenderer { quad_pipeline_state, unit_vertices, instances, + glyph_atlas, } } @@ -102,6 +115,10 @@ impl MetalRenderer { &*self.layer } + pub fn glyph_atlas(&self) -> &Arc> { + &self.glyph_atlas + } + pub fn draw(&mut self, scene: &mut Scene) { let layer = self.layer.clone(); let viewport_size = layer.drawable_size(); diff --git a/crates/gpui3/src/platform/mac/text_system.rs b/crates/gpui3/src/platform/mac/text_system.rs index 402a1db517900259b80623a9c433285c436c988d..9f1ea8a78f82303e0c52201c6e0195763641994b 100644 --- a/crates/gpui3/src/platform/mac/text_system.rs +++ b/crates/gpui3/src/platform/mac/text_system.rs @@ -1,7 +1,7 @@ use crate::{ - point, px, size, Bounds, Font, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, Glyph, - GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, RasterizationOptions, Result, Run, - SharedString, Size, + point, px, size, Bounds, Font, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, + GlyphId, Pixels, PlatformTextSystem, Point, RasterizationOptions, Result, ShapedGlyph, + ShapedLine, ShapedRun, SharedString, Size, }; use cocoa::appkit::{CGFloat, CGPoint}; use collections::HashMap; @@ -161,7 +161,7 @@ impl PlatformTextSystem for MacTextSystem { text: &str, font_size: Pixels, font_runs: &[(usize, FontId)], - ) -> LineLayout { + ) -> ShapedLine { self.0.write().layout_line(text, font_size, font_runs) } @@ -348,7 +348,7 @@ impl MacTextSystemState { text: &str, font_size: Pixels, font_runs: &[(usize, FontId)], - ) -> LineLayout { + ) -> ShapedLine { // Construct the attributed string, converting UTF8 ranges to UTF16 ranges. let mut string = CFMutableAttributedString::new(); { @@ -409,7 +409,7 @@ impl MacTextSystemState { { let glyph_utf16_ix = usize::try_from(*glyph_utf16_ix).unwrap(); ix_converter.advance_to_utf16_ix(glyph_utf16_ix); - glyphs.push(Glyph { + glyphs.push(ShapedGlyph { id: (*glyph_id).into(), position: point(position.x as f32, position.y as f32).map(px), index: ix_converter.utf8_ix, @@ -417,11 +417,11 @@ impl MacTextSystemState { }); } - runs.push(Run { font_id, glyphs }) + runs.push(ShapedRun { font_id, glyphs }) } let typographic_bounds = line.get_typographic_bounds(); - LineLayout { + ShapedLine { width: typographic_bounds.width.into(), ascent: typographic_bounds.ascent.into(), descent: typographic_bounds.descent.into(), diff --git a/crates/gpui3/src/platform/mac/window.rs b/crates/gpui3/src/platform/mac/window.rs index 3cf471b45ae9f27ccfd00e66b58c619ab6388027..b6974ef17209429267115b26dfcc2d302cc1ba5c 100644 --- a/crates/gpui3/src/platform/mac/window.rs +++ b/crates/gpui3/src/platform/mac/window.rs @@ -1,10 +1,10 @@ use super::{ns_string, MetalRenderer, NSRange}; use crate::{ - point, px, size, AnyWindowHandle, Bounds, Event, KeyDownEvent, Keystroke, MacScreen, Modifiers, - ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, MouseUpEvent, NSRectExt, - Pixels, Platform, PlatformDispatcher, PlatformInputHandler, PlatformScreen, PlatformWindow, - Point, Scene, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions, - WindowPromptLevel, + point, px, size, AnyWindowHandle, Bounds, Event, KeyDownEvent, Keystroke, MacScreen, + MetalAtlas, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, + MouseUpEvent, NSRectExt, Pixels, Platform, PlatformAtlas, PlatformDispatcher, + PlatformInputHandler, PlatformScreen, PlatformWindow, Point, RasterizedGlyphId, Scene, Size, + Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions, WindowPromptLevel, }; use block::ConcreteBlock; use cocoa::{ @@ -20,6 +20,7 @@ use core_graphics::display::CGRect; use ctor::ctor; use foreign_types::ForeignTypeRef; use futures::channel::oneshot; +use metal::{MTLPixelFormat, TextureDescriptor}; use objc::{ class, declare::ClassDecl, @@ -885,6 +886,10 @@ impl PlatformWindow for MacWindow { let _: () = msg_send![this.native_window.contentView(), setNeedsDisplay: YES]; } } + + fn glyph_atlas(&self) -> Arc> { + self.0.lock().renderer.glyph_atlas().clone() + } } fn get_scale_factor(native_window: id) -> f32 { diff --git a/crates/gpui3/src/text_system.rs b/crates/gpui3/src/text_system.rs index 38bb1fded4a3f1936ecdd5a45127fbced8857f17..4d8a0e59fbc3d2d2e682ccd69065d8476bd47a34 100644 --- a/crates/gpui3/src/text_system.rs +++ b/crates/gpui3/src/text_system.rs @@ -346,28 +346,35 @@ impl From for GlyphId { } } -#[derive(Clone, Debug)] -pub struct Glyph { - pub id: GlyphId, - pub position: Point, - pub index: usize, - pub is_emoji: bool, -} - #[derive(Default, Debug)] -pub struct LineLayout { +pub struct ShapedLine { pub font_size: Pixels, pub width: Pixels, pub ascent: Pixels, pub descent: Pixels, - pub runs: Vec, + pub runs: Vec, pub len: usize, } #[derive(Debug)] -pub struct Run { +pub struct ShapedRun { pub font_id: FontId, - pub glyphs: Vec, + pub glyphs: Vec, +} + +#[derive(Clone, Debug)] +pub struct ShapedGlyph { + pub id: GlyphId, + pub position: Point, + pub index: usize, + pub is_emoji: bool, +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct RasterizedGlyphId { + font_id: FontId, + glyph_id: GlyphId, + font_size: Pixels, } #[derive(Clone, Debug, Eq, PartialEq, Hash)] diff --git a/crates/gpui3/src/text_system/line.rs b/crates/gpui3/src/text_system/line.rs index 14f1d96f54994a4a24f53f6042081aa35d453726..c7444192070c9ac286840082166fcc241fa2eca5 100644 --- a/crates/gpui3/src/text_system/line.rs +++ b/crates/gpui3/src/text_system/line.rs @@ -1,6 +1,6 @@ use crate::{ - black, point, px, Bounds, FontId, Hsla, Layout, LineLayout, Pixels, Point, Run, RunStyle, - ShapedBoundary, UnderlineStyle, WindowContext, + black, point, px, Bounds, FontId, Hsla, Layout, Pixels, Point, RunStyle, ShapedBoundary, + ShapedLine, ShapedRun, UnderlineStyle, WindowContext, }; use anyhow::Result; use smallvec::SmallVec; @@ -8,7 +8,7 @@ use std::sync::Arc; #[derive(Default, Debug, Clone)] pub struct Line { - layout: Arc, + layout: Arc, style_runs: SmallVec<[StyleRun; 32]>, } @@ -20,7 +20,7 @@ struct StyleRun { } impl Line { - pub fn new(layout: Arc, runs: &[(usize, RunStyle)]) -> Self { + pub fn new(layout: Arc, runs: &[(usize, RunStyle)]) -> Self { let mut style_runs = SmallVec::new(); for (len, style) in runs { style_runs.push(StyleRun { @@ -32,7 +32,7 @@ impl Line { Self { layout, style_runs } } - pub fn runs(&self) -> &[Run] { + pub fn runs(&self) -> &[ShapedRun] { &self.layout.runs } diff --git a/crates/gpui3/src/text_system/text_layout_cache.rs b/crates/gpui3/src/text_system/text_layout_cache.rs index 59cfd300eea82b102e21d8c4714aeaf00c01be9f..e02122478bc470504cb58cbcc89529c61bd88800 100644 --- a/crates/gpui3/src/text_system/text_layout_cache.rs +++ b/crates/gpui3/src/text_system/text_layout_cache.rs @@ -1,4 +1,4 @@ -use crate::{FontId, Glyph, LineLayout, Pixels, PlatformTextSystem, Run}; +use crate::{FontId, Pixels, PlatformTextSystem, ShapedGlyph, ShapedLine, ShapedRun}; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; use smallvec::SmallVec; use std::{ @@ -9,8 +9,8 @@ use std::{ }; pub(crate) struct TextLayoutCache { - prev_frame: Mutex>>, - curr_frame: RwLock>>, + prev_frame: Mutex>>, + curr_frame: RwLock>>, platform_text_system: Arc, } @@ -35,7 +35,7 @@ impl TextLayoutCache { text: &'a str, font_size: Pixels, runs: &[(usize, FontId)], - ) -> Arc { + ) -> Arc { let key = &CacheKeyRef { text, font_size, @@ -146,8 +146,8 @@ pub struct ShapedBoundary { pub glyph_ix: usize, } -impl Run { - pub fn glyphs(&self) -> &[Glyph] { +impl ShapedRun { + pub fn glyphs(&self) -> &[ShapedGlyph] { &self.glyphs } } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index b4a893cb5653752c9178dbf41c371a6017ef2e64..9fe5e3bc19bb80dd2623240e8f1d0fb72c934eb5 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -1,7 +1,8 @@ use crate::{ - px, AnyView, AppContext, AvailableSpace, Bounds, Context, Effect, Element, EntityId, Handle, - LayoutId, MainThread, MainThreadOnly, Pixels, PlatformWindow, Point, Reference, Scene, Size, - StackContext, StackingOrder, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, + px, AnyView, AppContext, AvailableSpace, Bounds, Context, Effect, Element, EntityId, FontId, + GlyphId, Handle, LayoutId, MainThread, MainThreadOnly, Pixels, PlatformAtlas, PlatformWindow, + Point, RasterizedGlyphId, Reference, Scene, Size, StackContext, StackingOrder, Style, + TaffyLayoutEngine, WeakHandle, WindowOptions, }; use anyhow::Result; use futures::Future; @@ -14,6 +15,7 @@ pub struct AnyWindow {} pub struct Window { handle: AnyWindowHandle, platform_window: MainThreadOnly>, + glyph_atlas: Arc>, rem_size: Pixels, content_size: Size, layout_engine: TaffyLayoutEngine, @@ -31,6 +33,7 @@ impl Window { cx: &mut MainThread, ) -> Self { let platform_window = cx.platform().open_window(handle, options); + let glyph_atlas = platform_window.glyph_atlas(); let mouse_position = platform_window.mouse_position(); let content_size = platform_window.content_size(); let scale_factor = platform_window.scale_factor(); @@ -53,6 +56,7 @@ impl Window { Window { handle, platform_window, + glyph_atlas, rem_size: px(16.), content_size, layout_engine: TaffyLayoutEngine::new(),