diff --git a/crates/gpui3/build.rs b/crates/gpui3/build.rs index 138cef6b83..64d14ee285 100644 --- a/crates/gpui3/build.rs +++ b/crates/gpui3/build.rs @@ -45,11 +45,12 @@ fn generate_shader_bindings() -> PathBuf { "Pixels".into(), "PointF".into(), "Hsla".into(), + "Uniforms".into(), + "AtlasTile".into(), "Quad".into(), "QuadInputIndex".into(), - "QuadUniforms".into(), - "AtlasTile".into(), "MonochromeSprite".into(), + "MonochromeSpriteInputIndex".into(), ]); config.no_includes = true; config.enumeration.prefix_with_name = true; diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index a86b2459e0..5e5127fcf1 100644 --- a/crates/gpui3/src/platform.rs +++ b/crates/gpui3/src/platform.rs @@ -192,12 +192,12 @@ pub trait PlatformAtlas: Send + Sync { pub struct AtlasTile { pub(crate) texture_id: AtlasTextureId, pub(crate) tile_id: TileId, - pub(crate) bounds_in_atlas: Bounds, + pub(crate) bounds: Bounds, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(C)] -pub(crate) struct AtlasTextureId(pub(crate) usize); +pub(crate) struct AtlasTextureId(pub(crate) u32); #[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 db1347e557..6924acf52e 100644 --- a/crates/gpui3/src/platform/mac/metal_atlas.rs +++ b/crates/gpui3/src/platform/mac/metal_atlas.rs @@ -98,7 +98,7 @@ impl MetalAtlasState { } let atlas_texture = MetalAtlasTexture { - id: AtlasTextureId(self.textures.len()), + id: AtlasTextureId(self.textures.len() as u32), allocator: etagere::BucketedAtlasAllocator::new(size.into()), metal_texture: AssertSend(metal_texture), }; @@ -120,24 +120,19 @@ impl MetalAtlasTexture { let tile = AtlasTile { texture_id: self.id, tile_id: allocation.id.into(), - bounds_in_atlas: allocation.rectangle.into(), + bounds: allocation.rectangle.into(), }; let region = metal::MTLRegion::new_2d( - u32::from(tile.bounds_in_atlas.origin.x) as u64, - u32::from(tile.bounds_in_atlas.origin.y) as u64, - u32::from(tile.bounds_in_atlas.size.width) as u64, - u32::from(tile.bounds_in_atlas.size.height) as u64, + 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, ); self.metal_texture.replace_region( region, 0, bytes.as_ptr() as *const _, - u32::from( - tile.bounds_in_atlas - .size - .width - .to_bytes(self.bytes_per_pixel()), - ) as u64, + u32::from(tile.bounds.size.width.to_bytes(self.bytes_per_pixel())) as u64, ); Some(tile) } diff --git a/crates/gpui3/src/platform/mac/metal_renderer.rs b/crates/gpui3/src/platform/mac/metal_renderer.rs index 27d47054e9..19b5374e58 100644 --- a/crates/gpui3/src/platform/mac/metal_renderer.rs +++ b/crates/gpui3/src/platform/mac/metal_renderer.rs @@ -242,12 +242,11 @@ impl MetalRenderer { Some(&self.instances), *offset as u64, ); - let quad_uniforms = QuadUniforms { viewport_size }; command_encoder.set_vertex_bytes( - QuadInputIndex::Uniforms as u64, - mem::size_of_val(&quad_uniforms) as u64, - &quad_uniforms as *const QuadUniforms as *const _, + QuadInputIndex::ViewportSize as u64, + mem::size_of_val(&viewport_size) as u64, + &viewport_size as *const Size as *const _, ); let quad_bytes_len = mem::size_of::() * quads.len(); @@ -279,7 +278,7 @@ impl MetalRenderer { viewport_size: Size, command_encoder: &metal::RenderCommandEncoderRef, ) { - todo!() + // todo!() } } @@ -327,11 +326,14 @@ fn align_offset(offset: &mut usize) { enum QuadInputIndex { Vertices = 0, Quads = 1, - Uniforms = 2, + ViewportSize = 2, } -#[derive(Debug, Clone, Copy)] #[repr(C)] -pub(crate) struct QuadUniforms { - viewport_size: Size, +enum MonochromeSpriteInputIndex { + Vertices = 0, + Sprites = 1, + ViewportSize = 2, + AtlasSize = 3, + AtlasTexture = 4, } diff --git a/crates/gpui3/src/platform/mac/shaders.metal b/crates/gpui3/src/platform/mac/shaders.metal index 76fb0e2d1c..3fd1f3748b 100644 --- a/crates/gpui3/src/platform/mac/shaders.metal +++ b/crates/gpui3/src/platform/mac/shaders.metal @@ -4,71 +4,36 @@ using namespace metal; float4 hsla_to_rgba(Hsla hsla); -float4 to_device_position(float2 pixel_position, float2 viewport_size); +float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds, + Bounds_Pixels clip_bounds, + constant Size_DevicePixels *viewport_size); +float quad_sdf(float2 point, Bounds_Pixels bounds, Corners_Pixels corner_radii); struct QuadVertexOutput { float4 position [[position]]; - float4 background_color; - float4 border_color; - uint quad_id; + float4 background_color [[flat]]; + float4 border_color [[flat]]; + uint quad_id [[flat]]; }; -vertex QuadVertexOutput quad_vertex( - uint unit_vertex_id [[vertex_id]], uint quad_id [[instance_id]], - constant float2 *unit_vertices [[buffer(QuadInputIndex_Vertices)]], - constant Quad *quads [[buffer(QuadInputIndex_Quads)]], - constant QuadUniforms *uniforms [[buffer(QuadInputIndex_Uniforms)]]) { +vertex QuadVertexOutput quad_vertex(uint unit_vertex_id [[vertex_id]], + uint quad_id [[instance_id]], + constant float2 *unit_vertices + [[buffer(QuadInputIndex_Vertices)]], + constant Quad *quads + [[buffer(QuadInputIndex_Quads)]], + constant Size_DevicePixels *viewport_size + [[buffer(QuadInputIndex_ViewportSize)]]) { float2 unit_vertex = unit_vertices[unit_vertex_id]; Quad quad = quads[quad_id]; - float2 position_2d = - unit_vertex * float2(quad.bounds.size.width, quad.bounds.size.height) + - float2(quad.bounds.origin.x, quad.bounds.origin.y); - position_2d.x = max(quad.clip_bounds.origin.x, position_2d.x); - position_2d.x = min(quad.clip_bounds.origin.x + quad.clip_bounds.size.width, - position_2d.x); - position_2d.y = max(quad.clip_bounds.origin.y, position_2d.y); - position_2d.y = min(quad.clip_bounds.origin.y + quad.clip_bounds.size.height, - position_2d.y); - - float2 viewport_size = float2((float)uniforms->viewport_size.width, - (float)uniforms->viewport_size.height); - float4 device_position = to_device_position(position_2d, viewport_size); + float4 device_position = to_device_position(unit_vertex, quad.bounds, + quad.clip_bounds, viewport_size); float4 background_color = hsla_to_rgba(quad.background); float4 border_color = hsla_to_rgba(quad.border_color); return QuadVertexOutput{device_position, background_color, border_color, quad_id}; } -float quad_sdf(float2 point, Bounds_Pixels bounds, - Corners_Pixels corner_radii) { - float2 half_size = float2(bounds.size.width, bounds.size.height) / 2.; - float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size; - float2 center_to_point = point - center; - float corner_radius; - if (center_to_point.x < 0.) { - if (center_to_point.y < 0.) { - corner_radius = corner_radii.top_left; - } else { - corner_radius = corner_radii.bottom_left; - } - } else { - if (center_to_point.y < 0.) { - corner_radius = corner_radii.top_right; - } else { - corner_radius = corner_radii.bottom_right; - } - } - - float2 rounded_edge_to_point = - abs(center_to_point) - half_size + corner_radius; - float distance = - length(max(0., rounded_edge_to_point)) + - min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - - corner_radius; - - return distance; -} - fragment float4 quad_fragment(QuadVertexOutput input [[stage_in]], constant Quad *quads [[buffer(QuadInputIndex_Quads)]]) { @@ -145,6 +110,57 @@ fragment float4 quad_fragment(QuadVertexOutput input [[stage_in]], saturate(0.5 - distance) * saturate(0.5 - clip_distance)); } +struct MonochromeSpriteVertexOutput { + float4 position [[position]]; + float2 tile_position; + float4 color [[flat]]; + uint sprite_id [[flat]]; +}; + +vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex( + uint unit_vertex_id [[vertex_id]], uint sprite_id [[instance_id]], + constant float2 *unit_vertices + [[buffer(MonochromeSpriteInputIndex_Vertices)]], + constant MonochromeSprite *sprites + [[buffer(MonochromeSpriteInputIndex_Sprites)]], + constant Size_DevicePixels *viewport_size + [[buffer(MonochromeSpriteInputIndex_ViewportSize)]], + constant Size_DevicePixels *atlas_size + [[buffer(MonochromeSpriteInputIndex_AtlasSize)]]) { + + float2 unit_vertex = unit_vertices[unit_vertex_id]; + MonochromeSprite sprite = sprites[sprite_id]; + float4 device_position = to_device_position( + unit_vertex, sprite.bounds, sprite.clip_bounds, viewport_size); + + float2 tile_origin = + float2(sprite.tile.bounds.origin.x, sprite.tile.bounds.origin.y); + float2 tile_size = + float2(sprite.tile.bounds.size.width, sprite.tile.bounds.size.height); + float2 tile_position = + (tile_origin + unit_vertex * tile_size) / + float2((float)atlas_size->width, (float)atlas_size->height); + float4 color = hsla_to_rgba(sprite.color); + return MonochromeSpriteVertexOutput{device_position, tile_position, color, + sprite_id}; +} + +fragment float4 monochrome_sprite_fragment( + MonochromeSpriteVertexOutput input [[stage_in]], + constant MonochromeSprite *sprites + [[buffer(MonochromeSpriteInputIndex_Sprites)]], + texture2d atlas + [[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); + float clip_distance = + quad_sdf(input.position.xy, sprite.clip_bounds, sprite.clip_corner_radii); + float4 color = input.color; + color.a *= sample.a * saturate(0.5 - clip_distance); + return color; +} + float4 hsla_to_rgba(Hsla hsla) { float h = hsla.h * 6.0; // Now, it's an angle but scaled in [0, 6) range float s = hsla.s; @@ -193,10 +209,52 @@ float4 hsla_to_rgba(Hsla hsla) { return rgba; } -float4 to_device_position(float2 pixel_position, float2 viewport_size) { - return float4(pixel_position / viewport_size * float2(2., -2.) + - float2(-1., 1.), - 0., 1.); +float4 to_device_position(float2 unit_vertex, Bounds_Pixels bounds, + Bounds_Pixels clip_bounds, + constant Size_DevicePixels *input_viewport_size) { + float2 position = + unit_vertex * float2(bounds.size.width, bounds.size.height) + + float2(bounds.origin.x, bounds.origin.y); + position.x = max(clip_bounds.origin.x, position.x); + position.x = min(clip_bounds.origin.x + clip_bounds.size.width, position.x); + position.y = max(clip_bounds.origin.y, position.y); + position.y = min(clip_bounds.origin.y + clip_bounds.size.height, position.y); + + float2 viewport_size = float2((float)input_viewport_size->width, + (float)input_viewport_size->height); + float2 device_position = + position / viewport_size * float2(2., -2.) + float2(-1., 1.); + return float4(device_position, 0., 1.); +} + +float quad_sdf(float2 point, Bounds_Pixels bounds, + Corners_Pixels corner_radii) { + float2 half_size = float2(bounds.size.width, bounds.size.height) / 2.; + float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size; + float2 center_to_point = point - center; + float corner_radius; + if (center_to_point.x < 0.) { + if (center_to_point.y < 0.) { + corner_radius = corner_radii.top_left; + } else { + corner_radius = corner_radii.bottom_left; + } + } else { + if (center_to_point.y < 0.) { + corner_radius = corner_radii.top_right; + } else { + corner_radius = corner_radii.bottom_right; + } + } + + float2 rounded_edge_to_point = + abs(center_to_point) - half_size + corner_radius; + float distance = + length(max(0., rounded_edge_to_point)) + + min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - + corner_radius; + + return distance; } // struct SpriteFragmentInput { diff --git a/crates/gpui3/src/platform/mac/window.rs b/crates/gpui3/src/platform/mac/window.rs index b6974ef172..0be5ebefdc 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, - 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, + 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, }; use block::ConcreteBlock; use cocoa::{ @@ -20,7 +20,6 @@ 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, diff --git a/crates/gpui3/src/scene.rs b/crates/gpui3/src/scene.rs index 5ca3f14c0a..d8ca9f729d 100644 --- a/crates/gpui3/src/scene.rs +++ b/crates/gpui3/src/scene.rs @@ -243,6 +243,8 @@ impl From for Primitive { pub struct MonochromeSprite { pub order: u32, pub bounds: Bounds, + pub clip_bounds: Bounds, + pub clip_corner_radii: Corners, pub color: Hsla, pub tile: AtlasTile, } diff --git a/crates/gpui3/src/text_system.rs b/crates/gpui3/src/text_system.rs index ba5cadba98..b3ddb468c3 100644 --- a/crates/gpui3/src/text_system.rs +++ b/crates/gpui3/src/text_system.rs @@ -10,8 +10,8 @@ use line_wrapper::*; pub use text_layout_cache::*; use crate::{ - px, Bounds, DevicePixels, Hsla, Pixels, PlatformTextSystem, Point, RasterizationOptions, - Result, SharedString, Size, UnderlineStyle, + px, Bounds, DevicePixels, Hsla, Pixels, PlatformTextSystem, Point, Result, SharedString, Size, + UnderlineStyle, }; use collections::HashMap; use core::fmt; diff --git a/crates/gpui3/src/text_system/line.rs b/crates/gpui3/src/text_system/line.rs index 98b0abcdbd..6f8f9d5b0c 100644 --- a/crates/gpui3/src/text_system/line.rs +++ b/crates/gpui3/src/text_system/line.rs @@ -1,7 +1,6 @@ use crate::{ - black, point, px, Bounds, FontId, Hsla, Layout, MonochromeSprite, Pixels, Point, - RasterizedGlyphId, RunStyle, ShapedBoundary, ShapedLine, ShapedRun, UnderlineStyle, - WindowContext, + black, point, px, Bounds, Corners, FontId, Hsla, Layout, MonochromeSprite, Pixels, Point, + RunStyle, ShapedBoundary, ShapedLine, ShapedRun, UnderlineStyle, WindowContext, }; use anyhow::Result; use smallvec::SmallVec; @@ -192,20 +191,13 @@ impl Line { MonochromeSprite { order: layout.order, bounds, + clip_bounds: bounds, + clip_corner_radii: Corners::default(), color, tile, }, ); } - - // cx.scene().insert(Symbol { - // order: layout.order, - // origin, - // font_id: run.font_id, - // font_size: self.layout.font_size, - // id: glyph.id, - // color, - // }); } } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index de518fb93f..929823b977 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -200,7 +200,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { 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_in_atlas.size.map(|b| px(b.0 as f32)); + let size = tile.bounds.size.map(|b| px(b.0 as f32)); let bounds = Bounds { origin, size }; Ok((tile, bounds))