From a8c1958c7548f8a20b213d9a348067b2d0d4c1bd Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 3 Oct 2023 13:03:29 -0600 Subject: [PATCH] Checkpoint --- crates/gpui3/src/geometry.rs | 62 ++++++++-- crates/gpui3/src/platform.rs | 10 +- crates/gpui3/src/platform/mac/metal_atlas.rs | 22 ++-- .../gpui3/src/platform/mac/metal_renderer.rs | 110 +++++++++++++++--- crates/gpui3/src/platform/mac/shaders.metal | 59 +--------- crates/gpui3/src/platform/mac/text_system.rs | 52 +++++---- crates/gpui3/src/platform/mac/window.rs | 6 +- crates/gpui3/src/scene.rs | 23 ++-- crates/gpui3/src/style.rs | 17 ++- crates/gpui3/src/text_system.rs | 10 +- crates/gpui3/src/text_system/line.rs | 24 ++-- crates/gpui3/src/window.rs | 36 ++---- crates/storybook2/src/workspace.rs | 3 +- 13 files changed, 248 insertions(+), 186 deletions(-) diff --git a/crates/gpui3/src/geometry.rs b/crates/gpui3/src/geometry.rs index 951b1125cd964e6eda1d9330df3fba450c43733f..e5dadbd58da43c3c60480b21bdd283f26d82dd35 100644 --- a/crates/gpui3/src/geometry.rs +++ b/crates/gpui3/src/geometry.rs @@ -28,6 +28,15 @@ impl Point { } } +impl Point { + pub fn scale(&self, factor: f32) -> Point { + Point { + x: self.x.scale(factor), + y: self.y.scale(factor), + } + } +} + impl Mul for Point where T: Mul + Clone + Debug, @@ -122,6 +131,15 @@ impl Size { } } +impl Size { + pub fn scale(&self, factor: f32) -> Size { + Size { + width: self.width.scale(factor), + height: self.height.scale(factor), + } + } +} + impl Size { pub fn max(&self, other: &Self) -> Self { Size { @@ -207,7 +225,6 @@ pub struct Bounds { pub size: Size, } -// Bounds * Pixels = Bounds impl Mul for Bounds where T: Mul + Clone + Debug, @@ -277,6 +294,15 @@ impl> Bounds { } } +impl Bounds { + pub fn scale(&self, factor: f32) -> Bounds { + Bounds { + origin: self.origin.scale(factor), + size: self.size.scale(factor), + } + } +} + impl Copy for Bounds {} #[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)] @@ -462,8 +488,8 @@ impl Pixels { Self(self.0.floor()) } - pub fn to_device_pixels(&self, scale: f32) -> DevicePixels { - DevicePixels((self.0 * scale).ceil() as u32) + pub fn scale(&self, factor: f32) -> ScaledPixels { + ScaledPixels(self.0 * factor) } } @@ -542,22 +568,22 @@ impl From for f64 { SubAssign, )] #[repr(transparent)] -pub struct DevicePixels(pub(crate) u32); +pub struct DevicePixels(pub(crate) i32); impl DevicePixels { pub fn to_bytes(&self, bytes_per_pixel: u8) -> u32 { - self.0 * bytes_per_pixel as u32 + self.0 as u32 * bytes_per_pixel as u32 } } -impl From for u32 { +impl From for i32 { fn from(device_pixels: DevicePixels) -> Self { device_pixels.0 } } -impl From for DevicePixels { - fn from(val: u32) -> Self { +impl From for DevicePixels { + fn from(val: i32) -> Self { DevicePixels(val) } } @@ -570,7 +596,25 @@ impl From for u64 { impl From for DevicePixels { fn from(val: u64) -> Self { - DevicePixels(val as u32) + DevicePixels(val as i32) + } +} + +#[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)] +#[repr(transparent)] +pub struct ScaledPixels(pub(crate) f32); + +impl Eq for ScaledPixels {} + +impl Debug for ScaledPixels { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} px (scaled)", self.0) + } +} + +impl From for DevicePixels { + fn from(scaled: ScaledPixels) -> Self { + DevicePixels(scaled.0.ceil() as i32) } } diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index 5e5127fcf15cd0bcd692b13803fbf930f59e08b7..940633caaf0e2ce25a86310f2bcee66864b2ca90 100644 --- a/crates/gpui3/src/platform.rs +++ b/crates/gpui3/src/platform.rs @@ -7,7 +7,7 @@ mod test; use crate::{ AnyWindowHandle, Bounds, DevicePixels, Font, FontId, FontMetrics, GlyphId, Pixels, Point, - RasterizedGlyphId, Result, Scene, ShapedLine, SharedString, Size, + RasterizeGlyphParams, Result, Scene, ShapedLine, SharedString, Size, }; use anyhow::anyhow; use async_task::Runnable; @@ -147,7 +147,7 @@ pub trait PlatformWindow { fn is_topmost_for_position(&self, position: Point) -> bool; fn draw(&self, scene: Scene); - fn glyph_atlas(&self) -> Arc>; + fn glyph_atlas(&self) -> Arc>; } pub trait PlatformDispatcher: Send + Sync { @@ -165,8 +165,8 @@ pub trait PlatformTextSystem: Send + Sync { fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option; fn rasterize_glyph( &self, - glyph_id: &RasterizedGlyphId, - ) -> Result<(Bounds, Vec)>; + glyph_id: &RasterizeGlyphParams, + ) -> Result<(Size, Vec)>; fn layout_line(&self, text: &str, font_size: Pixels, runs: &[(usize, FontId)]) -> ShapedLine; fn wrap_line( &self, @@ -197,7 +197,7 @@ pub struct AtlasTile { #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(C)] -pub(crate) struct AtlasTextureId(pub(crate) u32); +pub(crate) struct AtlasTextureId(pub(crate) u32); // We use u32 instead of usize for Metal Shader Language compatibility #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[repr(C)] diff --git a/crates/gpui3/src/platform/mac/metal_atlas.rs b/crates/gpui3/src/platform/mac/metal_atlas.rs index 6924acf52ed175d62a222d773031b5c8a7a6be86..ae2d7b2d514d7f91f09375d16b27a80c7b8a2558 100644 --- a/crates/gpui3/src/platform/mac/metal_atlas.rs +++ b/crates/gpui3/src/platform/mac/metal_atlas.rs @@ -28,6 +28,10 @@ impl MetalAtlas { tiles_by_key: Default::default(), })) } + + pub(crate) fn texture(&self, id: AtlasTextureId) -> metal::Texture { + self.0.lock().textures[id.0 as usize].metal_texture.clone() + } } struct MetalAtlasState { @@ -123,10 +127,10 @@ impl MetalAtlasTexture { bounds: allocation.rectangle.into(), }; let region = metal::MTLRegion::new_2d( - u32::from(tile.bounds.origin.x) as u64, - u32::from(tile.bounds.origin.y) as u64, - u32::from(tile.bounds.size.width) as u64, - u32::from(tile.bounds.size.height) as u64, + tile.bounds.origin.x.into(), + tile.bounds.origin.y.into(), + tile.bounds.size.width.into(), + tile.bounds.size.height.into(), ); self.metal_texture.replace_region( region, @@ -149,15 +153,15 @@ impl MetalAtlasTexture { impl From> for etagere::Size { fn from(size: Size) -> Self { - etagere::Size::new(u32::from(size.width) as i32, u32::from(size.width) as i32) + etagere::Size::new(size.width.into(), size.width.into()) } } impl From for Point { fn from(value: etagere::Point) -> Self { Point { - x: DevicePixels::from(value.x as u32), - y: DevicePixels::from(value.y as u32), + x: DevicePixels::from(value.x), + y: DevicePixels::from(value.y), } } } @@ -165,8 +169,8 @@ impl From for Point { impl From for Size { fn from(size: etagere::Size) -> Self { Size { - width: DevicePixels::from(size.width as u32), - height: DevicePixels::from(size.height as u32), + width: DevicePixels::from(size.width), + height: DevicePixels::from(size.height), } } } diff --git a/crates/gpui3/src/platform/mac/metal_renderer.rs b/crates/gpui3/src/platform/mac/metal_renderer.rs index 19b5374e585c53ed3736e91011090d6c8e28dae7..dc93a8cfa0520d57616feb1b0b3ce483dea00f15 100644 --- a/crates/gpui3/src/platform/mac/metal_renderer.rs +++ b/crates/gpui3/src/platform/mac/metal_renderer.rs @@ -1,6 +1,6 @@ use crate::{ point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, Quad, - RasterizedGlyphId, Scene, Size, + RasterizeGlyphParams, Scene, Size, }; use cocoa::{ base::{NO, YES}, @@ -18,10 +18,11 @@ pub struct MetalRenderer { device: metal::Device, layer: metal::MetalLayer, command_queue: CommandQueue, - quad_pipeline_state: metal::RenderPipelineState, + quads_pipeline_state: metal::RenderPipelineState, + sprites_pipeline_state: metal::RenderPipelineState, unit_vertices: metal::Buffer, instances: metal::Buffer, - glyph_atlas: Arc>, + glyph_atlas: Arc>, } impl MetalRenderer { @@ -81,15 +82,24 @@ impl MetalRenderer { MTLResourceOptions::StorageModeManaged, ); - let quad_pipeline_state = build_pipeline_state( + let quads_pipeline_state = build_pipeline_state( &device, &library, - "quad", + "quads", "quad_vertex", "quad_fragment", PIXEL_FORMAT, ); + let sprites_pipeline_state = build_pipeline_state( + &device, + &library, + "sprites", + "monochrome_sprite_vertex", + "monochrome_sprite_fragment", + PIXEL_FORMAT, + ); + let command_queue = device.new_command_queue(); let glyph_atlas = Arc::new(MetalAtlas::new( Size { @@ -104,7 +114,8 @@ impl MetalRenderer { device, layer, command_queue, - quad_pipeline_state, + quads_pipeline_state, + sprites_pipeline_state, unit_vertices, instances, glyph_atlas, @@ -115,7 +126,7 @@ impl MetalRenderer { &*self.layer } - pub fn glyph_atlas(&self) -> &Arc> { + pub fn glyph_atlas(&self) -> &Arc> { &self.glyph_atlas } @@ -123,8 +134,8 @@ impl MetalRenderer { let layer = self.layer.clone(); let viewport_size = layer.drawable_size(); let viewport_size: Size = size( - (viewport_size.width.ceil() as u32).into(), - (viewport_size.height.ceil() as u32).into(), + (viewport_size.width.ceil() as i32).into(), + (viewport_size.height.ceil() as i32).into(), ); let drawable = if let Some(drawable) = layer.next_drawable() { drawable @@ -144,8 +155,8 @@ impl MetalRenderer { depth_texture_desc.set_pixel_format(metal::MTLPixelFormat::Depth32Float); depth_texture_desc.set_storage_mode(metal::MTLStorageMode::Private); depth_texture_desc.set_usage(metal::MTLTextureUsage::RenderTarget); - depth_texture_desc.set_width(u32::from(viewport_size.width) as u64); - depth_texture_desc.set_height(u32::from(viewport_size.height) as u64); + depth_texture_desc.set_width(i32::from(viewport_size.width) as u64); + depth_texture_desc.set_height(i32::from(viewport_size.height) as u64); let depth_texture = self.device.new_texture(&depth_texture_desc); let depth_attachment = render_pass_descriptor.depth_attachment().unwrap(); @@ -168,8 +179,8 @@ impl MetalRenderer { command_encoder.set_viewport(metal::MTLViewport { originX: 0.0, originY: 0.0, - width: u32::from(viewport_size.width) as f64, - height: u32::from(viewport_size.height) as f64, + width: i32::from(viewport_size.width) as f64, + height: i32::from(viewport_size.height) as f64, znear: 0.0, zfar: 1.0, }); @@ -226,7 +237,7 @@ impl MetalRenderer { } align_offset(offset); - command_encoder.set_render_pipeline_state(&self.quad_pipeline_state); + command_encoder.set_render_pipeline_state(&self.quads_pipeline_state); command_encoder.set_vertex_buffer( QuadInputIndex::Vertices as u64, Some(&self.unit_vertices), @@ -273,12 +284,77 @@ impl MetalRenderer { fn draw_monochrome_sprites( &mut self, texture_id: AtlasTextureId, - monochrome: &[MonochromeSprite], + sprites: &[MonochromeSprite], offset: &mut usize, viewport_size: Size, command_encoder: &metal::RenderCommandEncoderRef, ) { - // todo!() + // dbg!(sprites); + + if sprites.is_empty() { + return; + } + align_offset(offset); + + let texture = self.glyph_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; } } @@ -334,6 +410,6 @@ enum MonochromeSpriteInputIndex { Vertices = 0, Sprites = 1, ViewportSize = 2, - AtlasSize = 3, + AtlasTextureSize = 3, AtlasTexture = 4, } diff --git a/crates/gpui3/src/platform/mac/shaders.metal b/crates/gpui3/src/platform/mac/shaders.metal index 3fd1f3748b4741490b27eee6db8c3490ff98800e..7c98db779bc9f8f8ed19fd76bc771f8a967ab92f 100644 --- a/crates/gpui3/src/platform/mac/shaders.metal +++ b/crates/gpui3/src/platform/mac/shaders.metal @@ -126,7 +126,7 @@ vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex( constant Size_DevicePixels *viewport_size [[buffer(MonochromeSpriteInputIndex_ViewportSize)]], constant Size_DevicePixels *atlas_size - [[buffer(MonochromeSpriteInputIndex_AtlasSize)]]) { + [[buffer(MonochromeSpriteInputIndex_AtlasTextureSize)]]) { float2 unit_vertex = unit_vertices[unit_vertex_id]; MonochromeSprite sprite = sprites[sprite_id]; @@ -149,11 +149,13 @@ fragment float4 monochrome_sprite_fragment( MonochromeSpriteVertexOutput input [[stage_in]], constant MonochromeSprite *sprites [[buffer(MonochromeSpriteInputIndex_Sprites)]], - texture2d atlas + texture2d atlas_texture [[texture(MonochromeSpriteInputIndex_AtlasTexture)]]) { MonochromeSprite sprite = sprites[input.sprite_id]; - constexpr sampler atlas_sampler(mag_filter::linear, min_filter::linear); - float4 sample = atlas.sample(atlas_sampler, input.tile_position); + constexpr sampler atlas_texture_sampler(mag_filter::linear, + min_filter::linear); + float4 sample = + atlas_texture.sample(atlas_texture_sampler, input.tile_position); float clip_distance = quad_sdf(input.position.xy, sprite.clip_bounds, sprite.clip_corner_radii); float4 color = input.color; @@ -256,52 +258,3 @@ float quad_sdf(float2 point, Bounds_Pixels bounds, return distance; } - -// struct SpriteFragmentInput { -// float4 position [[position]]; -// float2 atlas_position; -// float4 color [[flat]]; -// uchar compute_winding [[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 float2 -// *viewport_size [[buffer(GPUISpriteVertexInputIndexViewportSize)]], -// constant float2 *atlas_size -// [[buffer(GPUISpriteVertexInputIndexAtlasSize)]] -// ) { -// float2 unit_vertex = unit_vertices[unit_vertex_id]; -// GPUISprite sprite = sprites[sprite_id]; -// float2 position = unit_vertex * sprite.target_size + sprite.origin; -// float4 device_position = to_device_position(position, *viewport_size); -// float2 atlas_position = (unit_vertex * sprite.source_size + -// sprite.atlas_origin) / *atlas_size; - -// return SpriteFragmentInput { -// device_position, -// atlas_position, -// coloru_to_colorf(sprite.color), -// sprite.compute_winding -// }; -// } - -// 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; -// float4 sample = atlas.sample(atlas_sampler, input.atlas_position); -// float mask; -// if (input.compute_winding) { -// mask = 1. - abs(1. - fmod(sample.r, 2.)); -// } else { -// mask = sample.a; -// } -// color.a *= mask; -// return color; -// } diff --git a/crates/gpui3/src/platform/mac/text_system.rs b/crates/gpui3/src/platform/mac/text_system.rs index f28badbb629216f64a1109c7c28bc92bcd1a5e3a..ea7c6a03022d60915fb0f7a3d42722637240a0bc 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, DevicePixels, Font, FontFeatures, FontId, FontMetrics, FontStyle, - FontWeight, GlyphId, Pixels, PlatformTextSystem, Point, RasterizedGlyphId, Result, ShapedGlyph, - ShapedLine, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS, + FontWeight, GlyphId, Pixels, PlatformTextSystem, Point, RasterizeGlyphParams, Result, + ShapedGlyph, ShapedLine, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS, }; use anyhow::anyhow; use cocoa::appkit::{CGFloat, CGPoint}; @@ -136,8 +136,8 @@ impl PlatformTextSystem for MacTextSystem { fn rasterize_glyph( &self, - glyph_id: &RasterizedGlyphId, - ) -> Result<(Bounds, Vec)> { + glyph_id: &RasterizeGlyphParams, + ) -> Result<(Size, Vec)> { self.0.read().rasterize_glyph(glyph_id) } @@ -232,8 +232,8 @@ impl MacTextSystemState { fn rasterize_glyph( &self, - glyph_id: &RasterizedGlyphId, - ) -> Result<(Bounds, Vec)> { + glyph_id: &RasterizeGlyphParams, + ) -> Result<(Size, Vec)> { let font = &self.fonts[glyph_id.font_id.0]; let scale = Transform2F::from_scale(glyph_id.scale_factor); let glyph_bounds = font.raster_bounds( @@ -252,18 +252,15 @@ impl MacTextSystemState { glyph_id.subpixel_variant.x.min(1) as i32, glyph_id.subpixel_variant.y.min(1) as i32, ); - let cx_bounds = RectI::new( - glyph_bounds.origin(), - glyph_bounds.size() + subpixel_padding, - ); + let bitmap_size = glyph_bounds.size() + subpixel_padding; - let mut bytes = vec![0; cx_bounds.width() as usize * cx_bounds.height() as usize]; + let mut bytes = vec![0; bitmap_size.x() as usize * bitmap_size.y() as usize]; let cx = CGContext::create_bitmap_context( Some(bytes.as_mut_ptr() as *mut _), - cx_bounds.width() as usize, - cx_bounds.height() as usize, + bitmap_size.x() as usize, + bitmap_size.y() as usize, 8, - cx_bounds.width() as usize, + bitmap_size.x() as usize, &CGColorSpace::create_device_gray(), kCGImageAlphaOnly, ); @@ -298,7 +295,7 @@ impl MacTextSystemState { cx, ); - Ok((cx_bounds.into(), bytes)) + Ok((bitmap_size.into(), bytes)) } } @@ -511,14 +508,23 @@ impl From for Bounds { impl From for Bounds { fn from(rect: RectI) -> Self { Bounds { - origin: point( - DevicePixels(rect.origin_x() as u32), - DevicePixels(rect.origin_y() as u32), - ), - size: size( - DevicePixels(rect.width() as u32), - DevicePixels(rect.height() as u32), - ), + origin: point(DevicePixels(rect.origin_x()), DevicePixels(rect.origin_y())), + size: size(DevicePixels(rect.width()), DevicePixels(rect.height())), + } + } +} + +impl From for Size { + fn from(value: Vector2I) -> Self { + size(value.x().into(), value.y().into()) + } +} + +impl From for Bounds { + fn from(rect: RectI) -> Self { + Bounds { + origin: point(rect.origin_x(), rect.origin_y()), + size: size(rect.width(), rect.height()), } } } diff --git a/crates/gpui3/src/platform/mac/window.rs b/crates/gpui3/src/platform/mac/window.rs index 0be5ebefdc3d214e7d89137b80b70d76a2465ba6..7d27976563a43ce7811e94276e50a510a8b80922 100644 --- a/crates/gpui3/src/platform/mac/window.rs +++ b/crates/gpui3/src/platform/mac/window.rs @@ -3,8 +3,8 @@ use crate::{ point, px, size, AnyWindowHandle, Bounds, Event, KeyDownEvent, Keystroke, MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, MouseUpEvent, NSRectExt, Pixels, Platform, PlatformAtlas, PlatformDispatcher, PlatformInputHandler, PlatformScreen, - PlatformWindow, Point, RasterizedGlyphId, Scene, Size, Timer, WindowAppearance, WindowBounds, - WindowKind, WindowOptions, WindowPromptLevel, + PlatformWindow, Point, RasterizeGlyphParams, Scene, Size, Timer, WindowAppearance, + WindowBounds, WindowKind, WindowOptions, WindowPromptLevel, }; use block::ConcreteBlock; use cocoa::{ @@ -886,7 +886,7 @@ impl PlatformWindow for MacWindow { } } - fn glyph_atlas(&self) -> Arc> { + fn glyph_atlas(&self) -> Arc> { self.0.lock().renderer.glyph_atlas().clone() } } diff --git a/crates/gpui3/src/scene.rs b/crates/gpui3/src/scene.rs index d8ca9f729d69c697ca8bfc3d07b869f108c0eea2..b4752ab3e9b03f882d8d2184f5b999cf4f01cf02 100644 --- a/crates/gpui3/src/scene.rs +++ b/crates/gpui3/src/scene.rs @@ -1,7 +1,7 @@ use std::{iter::Peekable, mem}; use super::{Bounds, Hsla, Pixels, Point}; -use crate::{AtlasTextureId, AtlasTile, Corners, Edges}; +use crate::{AtlasTextureId, AtlasTile, Corners, Edges, ScaledPixels}; use collections::BTreeMap; use smallvec::SmallVec; @@ -36,7 +36,6 @@ impl Scene { let primitive = primitive.into(); match primitive { Primitive::Quad(mut quad) => { - quad.scale(self.scale_factor); layer.quads.push(quad); } Primitive::Sprite(sprite) => { @@ -187,17 +186,17 @@ pub(crate) enum PrimitiveBatch<'a> { #[repr(C)] pub struct Quad { pub order: u32, - pub bounds: Bounds, - pub clip_bounds: Bounds, - pub clip_corner_radii: Corners, + pub bounds: Bounds, + pub clip_bounds: Bounds, + pub clip_corner_radii: Corners, pub background: Hsla, pub border_color: Hsla, - pub corner_radii: Corners, - pub border_widths: Edges, + pub corner_radii: Corners, + pub border_widths: Edges, } impl Quad { - pub fn vertices(&self) -> impl Iterator> { + pub fn vertices(&self) -> impl Iterator> { let x1 = self.bounds.origin.x; let y1 = self.bounds.origin.y; let x2 = x1 + self.bounds.size.width; @@ -210,14 +209,6 @@ impl Quad { ] .into_iter() } - - pub fn scale(&mut self, factor: f32) { - self.bounds *= factor; - self.clip_bounds *= factor; - self.clip_corner_radii *= factor; - self.corner_radii *= factor; - self.border_widths *= factor; - } } impl Ord for Quad { diff --git a/crates/gpui3/src/style.rs b/crates/gpui3/src/style.rs index aae76349c6e92811b59ff0caaae9ad28f7be43b9..431a87491f1f5d6f9a6a87114b48c119b881b2c3 100644 --- a/crates/gpui3/src/style.rs +++ b/crates/gpui3/src/style.rs @@ -182,6 +182,7 @@ impl Style { /// Paints the background of an element styled with this style. pub fn paint(&self, order: u32, bounds: Bounds, cx: &mut ViewContext) { let rem_size = cx.rem_size(); + let scale = cx.scale_factor(); let background_color = self.fill.as_ref().and_then(Fill::color); if background_color.is_some() || self.is_border_visible() { @@ -190,13 +191,19 @@ impl Style { layer_id, Quad { order, - bounds, - clip_bounds: bounds, // todo! - clip_corner_radii: self.corner_radii.map(|length| length.to_pixels(rem_size)), + bounds: bounds.scale(scale), + clip_bounds: bounds.scale(scale), // todo! + clip_corner_radii: self + .corner_radii + .map(|length| length.to_pixels(rem_size).scale(scale)), background: background_color.unwrap_or_default(), border_color: self.border_color.unwrap_or_default(), - corner_radii: self.corner_radii.map(|length| length.to_pixels(rem_size)), - border_widths: self.border_widths.map(|length| length.to_pixels(rem_size)), + corner_radii: self + .corner_radii + .map(|length| length.to_pixels(rem_size).scale(scale)), + border_widths: self + .border_widths + .map(|length| length.to_pixels(rem_size).scale(scale)), }, ); } diff --git a/crates/gpui3/src/text_system.rs b/crates/gpui3/src/text_system.rs index b3ddb468c34bf4aee6e9120a74922a9cb9d22adc..ec0a85ca1656593b61009081c5d42a4b6b8643af 100644 --- a/crates/gpui3/src/text_system.rs +++ b/crates/gpui3/src/text_system.rs @@ -217,8 +217,8 @@ impl TextSystem { pub fn rasterize_glyph( &self, - glyph_id: &RasterizedGlyphId, - ) -> Result<(Bounds, Vec)> { + glyph_id: &RasterizeGlyphParams, + ) -> Result<(Size, Vec)> { self.platform_text_system.rasterize_glyph(glyph_id) } } @@ -380,7 +380,7 @@ pub struct ShapedGlyph { } #[derive(Clone, Debug, PartialEq)] -pub struct RasterizedGlyphId { +pub struct RasterizeGlyphParams { pub(crate) font_id: FontId, pub(crate) glyph_id: GlyphId, pub(crate) font_size: Pixels, @@ -388,9 +388,9 @@ pub struct RasterizedGlyphId { pub(crate) scale_factor: f32, } -impl Eq for RasterizedGlyphId {} +impl Eq for RasterizeGlyphParams {} -impl Hash for RasterizedGlyphId { +impl Hash for RasterizeGlyphParams { fn hash(&self, state: &mut H) { self.font_id.0.hash(state); self.glyph_id.0.hash(state); diff --git a/crates/gpui3/src/text_system/line.rs b/crates/gpui3/src/text_system/line.rs index 6f8f9d5b0ccd5af78ab12fa25f696ac700b07d70..a3a578c7b1cedfdc5c69a9bfb58f016acf6852ba 100644 --- a/crates/gpui3/src/text_system/line.rs +++ b/crates/gpui3/src/text_system/line.rs @@ -157,35 +157,29 @@ impl Line { if let Some((_underline_origin, _underline_style)) = finished_underline { todo!() - // cx.scene().insert(Underline { - // origin: underline_origin, - // width: glyph_origin.x - underline_origin.x, - // thickness: underline_style.thickness.into(), - // color: underline_style.color.unwrap(), - // squiggly: underline_style.squiggly, - // }); } if glyph.is_emoji { todo!() - // cx.scene().push_image_glyph(scene::ImageGlyph { - // font_id: run.font_id, - // font_size: self.layout.font_size, - // id: glyph.id, - // origin: glyph_origin, - // }); } else { - if let Some((tile, bounds)) = cx + if let Some(tile) = cx .rasterize_glyph( run.font_id, glyph.id, self.layout.font_size, - cx.scale_factor(), glyph_origin, + cx.scale_factor(), ) .log_err() { let layer_id = cx.current_layer_id(); + + let bounds = Bounds { + origin: glyph_origin + todo!(), + size: todo!(), + }; + // cx.text_system().raster_bounds() + cx.scene().insert( layer_id, MonochromeSprite { diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 929823b977a58f2550836c3f63b0d74ea783b7b1..dc7dca03269bf90f48575a278962c26e83e67f20 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -1,9 +1,8 @@ use crate::{ - px, AnyView, AppContext, AtlasTile, AvailableSpace, Bounds, Context, DevicePixels, Effect, - Element, EntityId, FontId, GlyphId, Handle, LayoutId, MainThread, MainThreadOnly, - MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, RasterizedGlyphId, Reference, - Scene, Size, StackContext, StackingOrder, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, - SUBPIXEL_VARIANTS, + px, AnyView, AppContext, AtlasTile, AvailableSpace, Bounds, Context, Effect, Element, EntityId, + FontId, GlyphId, Handle, LayoutId, MainThread, MainThreadOnly, Pixels, PlatformAtlas, + PlatformWindow, Point, RasterizeGlyphParams, Reference, Scene, Size, StackContext, + StackingOrder, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::Result; use futures::Future; @@ -16,7 +15,7 @@ pub struct AnyWindow {} pub struct Window { handle: AnyWindowHandle, platform_window: MainThreadOnly>, - glyph_atlas: Arc>, + glyph_atlas: Arc>, rem_size: Pixels, content_size: Size, layout_engine: TaffyLayoutEngine, @@ -171,39 +170,26 @@ impl<'a, 'w> WindowContext<'a, 'w> { font_id: FontId, glyph_id: GlyphId, font_size: Pixels, - scale_factor: f32, target_position: Point, - ) -> Result<(AtlasTile, Bounds)> { + scale_factor: f32, + ) -> Result { let target_position = target_position * scale_factor; let subpixel_variant = Point { x: (target_position.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8, y: (target_position.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8, }; - let rasterized_glyph_id = RasterizedGlyphId { + let rasterized_glyph_id = RasterizeGlyphParams { font_id, glyph_id, font_size, subpixel_variant, scale_factor, }; - let mut offset = Default::default(); - let tile = self - .window + self.window .glyph_atlas .get_or_insert_with(&rasterized_glyph_id, &mut || { - let (bounds, pixels) = self.text_system().rasterize_glyph(&rasterized_glyph_id)?; - offset = bounds.origin; - Ok((bounds.size, pixels)) - })?; - - // Align bounding box surrounding glyph to pixel grid - let mut origin = (target_position * scale_factor).map(|p| p.floor()); - // Position glyph within bounding box - origin += offset.map(|o| px(u32::from(o) as f32)); - let size = tile.bounds.size.map(|b| px(b.0 as f32)); - let bounds = Bounds { origin, size }; - - Ok((tile, bounds)) + self.text_system().rasterize_glyph(&rasterized_glyph_id) + }) } pub(crate) fn draw(&mut self) -> Result<()> { diff --git a/crates/storybook2/src/workspace.rs b/crates/storybook2/src/workspace.rs index adc091b4b9047091723dc5819ce5e70feea9a91d..c48993a9afd5955dbafc4bb5b0e0f7512638fa25 100644 --- a/crates/storybook2/src/workspace.rs +++ b/crates/storybook2/src/workspace.rs @@ -4,7 +4,7 @@ use crate::{ themes::rose_pine_dawn, }; use gpui3::{ - div, img, svg, view, Context, Element, ParentElement, RootView, StyleHelpers, View, + black, div, img, svg, view, Context, Element, ParentElement, RootView, StyleHelpers, View, ViewContext, WindowContext, }; @@ -29,6 +29,7 @@ impl Workspace { let theme = rose_pine_dawn(); div() .font("Helvetica") + .text_color(black()) .text_base() .size_full() .fill(theme.middle.positive.default.background)