Detailed changes
@@ -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;
@@ -192,12 +192,12 @@ pub trait PlatformAtlas<Key>: Send + Sync {
pub struct AtlasTile {
pub(crate) texture_id: AtlasTextureId,
pub(crate) tile_id: TileId,
- pub(crate) bounds_in_atlas: Bounds<DevicePixels>,
+ pub(crate) bounds: Bounds<DevicePixels>,
}
#[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)]
@@ -98,7 +98,7 @@ impl<Key> MetalAtlasState<Key> {
}
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)
}
@@ -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<DevicePixels> as *const _,
);
let quad_bytes_len = mem::size_of::<Quad>() * quads.len();
@@ -279,7 +278,7 @@ impl MetalRenderer {
viewport_size: Size<DevicePixels>,
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<DevicePixels>,
+enum MonochromeSpriteInputIndex {
+ Vertices = 0,
+ Sprites = 1,
+ ViewportSize = 2,
+ AtlasSize = 3,
+ AtlasTexture = 4,
}
@@ -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<float> 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 {
@@ -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,
@@ -243,6 +243,8 @@ impl From<Quad> for Primitive {
pub struct MonochromeSprite {
pub order: u32,
pub bounds: Bounds<Pixels>,
+ pub clip_bounds: Bounds<Pixels>,
+ pub clip_corner_radii: Corners<Pixels>,
pub color: Hsla,
pub tile: AtlasTile,
}
@@ -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;
@@ -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,
- // });
}
}
@@ -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))