From cd1c1375422edef5b62b13b330c37b2e7736ef34 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 4 Oct 2023 11:53:20 +0200 Subject: [PATCH] WIP --- crates/gpui3/src/platform.rs | 1 + .../gpui3/src/platform/mac/metal_renderer.rs | 106 +++++++++++++++++- crates/gpui3/src/platform/mac/window.rs | 4 + crates/gpui3/src/scene.rs | 59 ++++++++-- crates/gpui3/src/text_system.rs | 19 ++++ crates/gpui3/src/text_system/line.rs | 8 +- crates/gpui3/src/window.rs | 53 ++++++++- 7 files changed, 235 insertions(+), 15 deletions(-) diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index c7ed3d68fb85c2c8dab6fa92625f8375482d84a2..0a3504915227db9b2dff27e65678a26957bf09ee 100644 --- a/crates/gpui3/src/platform.rs +++ b/crates/gpui3/src/platform.rs @@ -148,6 +148,7 @@ pub trait PlatformWindow { fn draw(&self, scene: Scene); fn monochrome_sprite_atlas(&self) -> Arc; + fn polychrome_sprite_atlas(&self) -> Arc; } pub trait PlatformDispatcher: Send + Sync { diff --git a/crates/gpui3/src/platform/mac/metal_renderer.rs b/crates/gpui3/src/platform/mac/metal_renderer.rs index 8e4e8805a97befe1a507dbca25707fd442f518d8..c65e82a0e7609573da3d818bde1c4116c95aaad1 100644 --- a/crates/gpui3/src/platform/mac/metal_renderer.rs +++ b/crates/gpui3/src/platform/mac/metal_renderer.rs @@ -1,5 +1,6 @@ use crate::{ - point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, Quad, Scene, Size, + point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, PolychromeSprite, + Quad, Scene, Size, }; use cocoa::{ base::{NO, YES}, @@ -21,6 +22,7 @@ pub struct MetalRenderer { unit_vertices: metal::Buffer, instances: metal::Buffer, monochrome_sprite_atlas: Arc, + polychrome_sprite_atlas: Arc, } impl MetalRenderer { @@ -107,6 +109,14 @@ impl MetalRenderer { MTLPixelFormat::A8Unorm, device.clone(), )); + let polychrome_sprite_atlas = Arc::new(MetalAtlas::new( + Size { + width: DevicePixels(1024), + height: DevicePixels(768), + }, + MTLPixelFormat::BGRA8Unorm, + device.clone(), + )); Self { layer, @@ -116,6 +126,7 @@ impl MetalRenderer { unit_vertices, instances, monochrome_sprite_atlas, + polychrome_sprite_atlas, } } @@ -127,6 +138,10 @@ impl MetalRenderer { &self.monochrome_sprite_atlas } + pub fn polychrome_sprite_atlas(&self) -> &Arc { + &self.polychrome_sprite_atlas + } + pub fn draw(&mut self, scene: &mut Scene) { let layer = self.layer.clone(); let viewport_size = layer.drawable_size(); @@ -180,7 +195,7 @@ impl MetalRenderer { command_encoder, ); } - crate::PrimitiveBatch::Sprites { + crate::PrimitiveBatch::MonochromeSprites { texture_id, sprites, } => { @@ -192,6 +207,18 @@ impl MetalRenderer { command_encoder, ); } + crate::PrimitiveBatch::PolychromeSprites { + texture_id, + sprites, + } => { + self.draw_polychrome_sprites( + texture_id, + sprites, + &mut instance_offset, + viewport_size, + command_encoder, + ); + } } } } @@ -337,6 +364,81 @@ impl MetalRenderer { ); *offset = next_offset; } + + fn draw_polychrome_sprites( + &mut self, + texture_id: AtlasTextureId, + sprites: &[PolychromeSprite], + offset: &mut usize, + viewport_size: Size, + command_encoder: &metal::RenderCommandEncoderRef, + ) { + todo!() + // if sprites.is_empty() { + // return; + // } + // align_offset(offset); + + // let texture = self.monochrome_sprite_atlas.texture(texture_id); + // let texture_size = size( + // DevicePixels(texture.width() as i32), + // DevicePixels(texture.height() as i32), + // ); + // command_encoder.set_render_pipeline_state(&self.sprites_pipeline_state); + // command_encoder.set_vertex_buffer( + // MonochromeSpriteInputIndex::Vertices as u64, + // Some(&self.unit_vertices), + // 0, + // ); + // command_encoder.set_vertex_buffer( + // MonochromeSpriteInputIndex::Sprites as u64, + // Some(&self.instances), + // *offset as u64, + // ); + // command_encoder.set_vertex_bytes( + // MonochromeSpriteInputIndex::ViewportSize as u64, + // mem::size_of_val(&viewport_size) as u64, + // &viewport_size as *const Size as *const _, + // ); + // command_encoder.set_vertex_bytes( + // MonochromeSpriteInputIndex::AtlasTextureSize as u64, + // mem::size_of_val(&texture_size) as u64, + // &texture_size as *const Size as *const _, + // ); + // command_encoder.set_fragment_buffer( + // MonochromeSpriteInputIndex::Sprites as u64, + // Some(&self.instances), + // *offset as u64, + // ); + // command_encoder.set_fragment_texture( + // MonochromeSpriteInputIndex::AtlasTexture as u64, + // Some(&texture), + // ); + + // let sprite_bytes_len = mem::size_of::() * sprites.len(); + // let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) }; + // unsafe { + // ptr::copy_nonoverlapping( + // sprites.as_ptr() as *const u8, + // buffer_contents, + // sprite_bytes_len, + // ); + // } + + // let next_offset = *offset + sprite_bytes_len; + // assert!( + // next_offset <= INSTANCE_BUFFER_SIZE, + // "instance buffer exhausted" + // ); + + // command_encoder.draw_primitives_instanced( + // metal::MTLPrimitiveType::Triangle, + // 0, + // 6, + // sprites.len() as u64, + // ); + // *offset = next_offset; + } } fn build_pipeline_state( diff --git a/crates/gpui3/src/platform/mac/window.rs b/crates/gpui3/src/platform/mac/window.rs index 521ec95fe9c4f8f7046c8ff6b2bb4cfea4449e1a..4cfbe2ef360e9b5f8a92b34fc7a792e2671ca49f 100644 --- a/crates/gpui3/src/platform/mac/window.rs +++ b/crates/gpui3/src/platform/mac/window.rs @@ -889,6 +889,10 @@ impl PlatformWindow for MacWindow { fn monochrome_sprite_atlas(&self) -> Arc { self.0.lock().renderer.monochrome_sprite_atlas().clone() } + + fn polychrome_sprite_atlas(&self) -> Arc { + self.0.lock().renderer.polychrome_sprite_atlas().clone() + } } fn get_scale_factor(native_window: id) -> f32 { diff --git a/crates/gpui3/src/scene.rs b/crates/gpui3/src/scene.rs index 6ffc6e0bb3aa698296ce2b4e27b0b2cbe34597ed..0918b28f3c88488eaa8a832d96ec6073fe0f9a80 100644 --- a/crates/gpui3/src/scene.rs +++ b/crates/gpui3/src/scene.rs @@ -38,8 +38,11 @@ impl Scene { Primitive::Quad(quad) => { layer.quads.push(quad); } - Primitive::Sprite(sprite) => { - layer.sprites.push(sprite); + Primitive::MonochromeSprite(sprite) => { + layer.monochrome_sprites.push(sprite); + } + Primitive::PolychromeSprite(sprite) => { + layer.polychrome_sprites.push(sprite); } } } @@ -52,19 +55,20 @@ impl Scene { #[derive(Debug, Default)] pub(crate) struct SceneLayer { pub quads: Vec, - pub sprites: Vec, + pub monochrome_sprites: Vec, + pub polychrome_sprites: Vec, } impl SceneLayer { pub fn batches(&mut self) -> impl Iterator { self.quads.sort_unstable(); - self.sprites.sort_unstable(); + self.monochrome_sprites.sort_unstable(); BatchIterator::new( &self.quads, self.quads.iter().peekable(), - &self.sprites, - self.sprites.iter().peekable(), + &self.monochrome_sprites, + self.monochrome_sprites.iter().peekable(), ) } } @@ -131,7 +135,7 @@ where }) .count(); self.sprites_start = sprites_end; - Some(PrimitiveBatch::Sprites { + Some(PrimitiveBatch::MonochromeSprites { texture_id, sprites: &self.sprites[sprites_start..sprites_end], }) @@ -171,15 +175,20 @@ pub enum PrimitiveKind { #[derive(Clone, Debug)] pub enum Primitive { Quad(Quad), - Sprite(MonochromeSprite), + MonochromeSprite(MonochromeSprite), + PolychromeSprite(PolychromeSprite), } pub(crate) enum PrimitiveBatch<'a> { Quads(&'a [Quad]), - Sprites { + MonochromeSprites { texture_id: AtlasTextureId, sprites: &'a [MonochromeSprite], }, + PolychromeSprites { + texture_id: AtlasTextureId, + sprites: &'a [PolychromeSprite], + }, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -256,7 +265,37 @@ impl PartialOrd for MonochromeSprite { impl From for Primitive { fn from(sprite: MonochromeSprite) -> Self { - Primitive::Sprite(sprite) + Primitive::MonochromeSprite(sprite) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +#[repr(C)] +pub struct PolychromeSprite { + pub order: u32, + pub bounds: Bounds, + pub content_mask: ScaledContentMask, + pub tile: AtlasTile, +} + +impl Ord for PolychromeSprite { + 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 PolychromeSprite { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl From for Primitive { + fn from(sprite: PolychromeSprite) -> Self { + Primitive::PolychromeSprite(sprite) } } diff --git a/crates/gpui3/src/text_system.rs b/crates/gpui3/src/text_system.rs index 6deaad925c41b1de5c95feb02d3b7feeefc735bd..fb8885ec00bc5bb04cd7199117d7870034f1326c 100644 --- a/crates/gpui3/src/text_system.rs +++ b/crates/gpui3/src/text_system.rs @@ -404,6 +404,25 @@ impl Hash for RenderGlyphParams { } } +#[derive(Clone, Debug, PartialEq)] +pub struct RenderEmojiParams { + pub(crate) font_id: FontId, + pub(crate) glyph_id: GlyphId, + pub(crate) font_size: Pixels, + pub(crate) scale_factor: f32, +} + +impl Eq for RenderEmojiParams {} + +impl Hash for RenderEmojiParams { + fn hash(&self, state: &mut H) { + self.font_id.0.hash(state); + self.glyph_id.0.hash(state); + self.font_size.0.to_bits().hash(state); + self.scale_factor.to_bits().hash(state); + } +} + #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct Font { pub family: SharedString, diff --git a/crates/gpui3/src/text_system/line.rs b/crates/gpui3/src/text_system/line.rs index 3cccd51977df52f56a9bfe19db8a11006654e1b0..e4c81531a8a02ddcb9689fc19c4b61a08c6ab0cf 100644 --- a/crates/gpui3/src/text_system/line.rs +++ b/crates/gpui3/src/text_system/line.rs @@ -159,7 +159,13 @@ impl Line { } if glyph.is_emoji { - todo!() + cx.paint_emoji( + glyph_origin, + layout.order, + run.font_id, + glyph.id, + self.layout.font_size, + )?; } else { cx.paint_glyph( glyph_origin, diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 829c3695a1e793ed6276a9e2d876167b71b109d3..97297ecd0359dbf52e578a27687aa82e26049ec2 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -2,8 +2,8 @@ use crate::{ px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners, DevicePixels, Effect, Element, EntityId, FontId, GlyphId, Handle, Hsla, IsZero, LayerId, LayoutId, MainThread, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, - Point, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, SharedString, Size, - Style, TaffyLayoutEngine, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS, + Point, PolychromeSprite, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, + SharedString, Size, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::Result; use futures::Future; @@ -17,6 +17,7 @@ pub struct Window { handle: AnyWindowHandle, platform_window: MainThreadOnly>, monochrome_sprite_atlas: Arc, + polychrome_sprite_atlas: Arc, rem_size: Pixels, content_size: Size, layout_engine: TaffyLayoutEngine, @@ -36,6 +37,7 @@ impl Window { ) -> Self { let platform_window = cx.platform().open_window(handle, options); let monochrome_sprite_atlas = platform_window.monochrome_sprite_atlas(); + let polychrome_sprite_atlas = platform_window.polychrome_sprite_atlas(); let mouse_position = platform_window.mouse_position(); let content_size = platform_window.content_size(); let scale_factor = platform_window.scale_factor(); @@ -59,6 +61,7 @@ impl Window { handle, platform_window, monochrome_sprite_atlas, + polychrome_sprite_atlas, rem_size: px(16.), content_size, layout_engine: TaffyLayoutEngine::new(), @@ -300,6 +303,52 @@ impl<'a, 'w> WindowContext<'a, 'w> { Ok(()) } + pub fn paint_emoji( + &mut self, + origin: Point, + order: u32, + font_id: FontId, + glyph_id: GlyphId, + font_size: Pixels, + ) -> Result<()> { + let scale_factor = self.scale_factor(); + let glyph_origin = origin.scale(scale_factor); + let params = RenderGlyphParams { + font_id, + glyph_id, + font_size, + subpixel_variant: Default::default(), + scale_factor, + }; + + let raster_bounds = self.text_system().raster_bounds(¶ms)?; + if !raster_bounds.is_zero() { + let layer_id = self.current_layer_id(); + let tile = self + .window + .polychrome_sprite_atlas + .get_or_insert_with(¶ms.clone().into(), &mut || { + self.text_system().rasterize_glyph(¶ms) + })?; + let bounds = Bounds { + origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into), + size: tile.bounds.size.map(Into::into), + }; + let content_mask = self.content_mask().scale(scale_factor); + + self.window.scene.insert( + layer_id, + PolychromeSprite { + order, + bounds, + content_mask, + tile, + }, + ); + } + Ok(()) + } + pub(crate) fn draw(&mut self) -> Result<()> { let unit_entity = self.unit_entity.clone(); self.update_entity(&unit_entity, |_, cx| {