This commit is contained in:
Antonio Scandurra 2023-10-04 11:53:20 +02:00
parent 4cf2ba20c2
commit cd1c137542
7 changed files with 235 additions and 15 deletions

View file

@ -148,6 +148,7 @@ pub trait PlatformWindow {
fn draw(&self, scene: Scene); fn draw(&self, scene: Scene);
fn monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas>; fn monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas>;
fn polychrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas>;
} }
pub trait PlatformDispatcher: Send + Sync { pub trait PlatformDispatcher: Send + Sync {

View file

@ -1,5 +1,6 @@
use crate::{ use crate::{
point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, Quad, Scene, Size, point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, PolychromeSprite,
Quad, Scene, Size,
}; };
use cocoa::{ use cocoa::{
base::{NO, YES}, base::{NO, YES},
@ -21,6 +22,7 @@ pub struct MetalRenderer {
unit_vertices: metal::Buffer, unit_vertices: metal::Buffer,
instances: metal::Buffer, instances: metal::Buffer,
monochrome_sprite_atlas: Arc<MetalAtlas>, monochrome_sprite_atlas: Arc<MetalAtlas>,
polychrome_sprite_atlas: Arc<MetalAtlas>,
} }
impl MetalRenderer { impl MetalRenderer {
@ -107,6 +109,14 @@ impl MetalRenderer {
MTLPixelFormat::A8Unorm, MTLPixelFormat::A8Unorm,
device.clone(), device.clone(),
)); ));
let polychrome_sprite_atlas = Arc::new(MetalAtlas::new(
Size {
width: DevicePixels(1024),
height: DevicePixels(768),
},
MTLPixelFormat::BGRA8Unorm,
device.clone(),
));
Self { Self {
layer, layer,
@ -116,6 +126,7 @@ impl MetalRenderer {
unit_vertices, unit_vertices,
instances, instances,
monochrome_sprite_atlas, monochrome_sprite_atlas,
polychrome_sprite_atlas,
} }
} }
@ -127,6 +138,10 @@ impl MetalRenderer {
&self.monochrome_sprite_atlas &self.monochrome_sprite_atlas
} }
pub fn polychrome_sprite_atlas(&self) -> &Arc<MetalAtlas> {
&self.polychrome_sprite_atlas
}
pub fn draw(&mut self, scene: &mut Scene) { pub fn draw(&mut self, scene: &mut Scene) {
let layer = self.layer.clone(); let layer = self.layer.clone();
let viewport_size = layer.drawable_size(); let viewport_size = layer.drawable_size();
@ -180,7 +195,7 @@ impl MetalRenderer {
command_encoder, command_encoder,
); );
} }
crate::PrimitiveBatch::Sprites { crate::PrimitiveBatch::MonochromeSprites {
texture_id, texture_id,
sprites, sprites,
} => { } => {
@ -192,6 +207,18 @@ impl MetalRenderer {
command_encoder, 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; *offset = next_offset;
} }
fn draw_polychrome_sprites(
&mut self,
texture_id: AtlasTextureId,
sprites: &[PolychromeSprite],
offset: &mut usize,
viewport_size: Size<DevicePixels>,
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<DevicePixels> as *const _,
// );
// command_encoder.set_vertex_bytes(
// MonochromeSpriteInputIndex::AtlasTextureSize as u64,
// mem::size_of_val(&texture_size) as u64,
// &texture_size as *const Size<DevicePixels> 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::<MonochromeSprite>() * 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( fn build_pipeline_state(

View file

@ -889,6 +889,10 @@ impl PlatformWindow for MacWindow {
fn monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas> { fn monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
self.0.lock().renderer.monochrome_sprite_atlas().clone() self.0.lock().renderer.monochrome_sprite_atlas().clone()
} }
fn polychrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
self.0.lock().renderer.polychrome_sprite_atlas().clone()
}
} }
fn get_scale_factor(native_window: id) -> f32 { fn get_scale_factor(native_window: id) -> f32 {

View file

@ -38,8 +38,11 @@ impl Scene {
Primitive::Quad(quad) => { Primitive::Quad(quad) => {
layer.quads.push(quad); layer.quads.push(quad);
} }
Primitive::Sprite(sprite) => { Primitive::MonochromeSprite(sprite) => {
layer.sprites.push(sprite); layer.monochrome_sprites.push(sprite);
}
Primitive::PolychromeSprite(sprite) => {
layer.polychrome_sprites.push(sprite);
} }
} }
} }
@ -52,19 +55,20 @@ impl Scene {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub(crate) struct SceneLayer { pub(crate) struct SceneLayer {
pub quads: Vec<Quad>, pub quads: Vec<Quad>,
pub sprites: Vec<MonochromeSprite>, pub monochrome_sprites: Vec<MonochromeSprite>,
pub polychrome_sprites: Vec<PolychromeSprite>,
} }
impl SceneLayer { impl SceneLayer {
pub fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> { pub fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> {
self.quads.sort_unstable(); self.quads.sort_unstable();
self.sprites.sort_unstable(); self.monochrome_sprites.sort_unstable();
BatchIterator::new( BatchIterator::new(
&self.quads, &self.quads,
self.quads.iter().peekable(), self.quads.iter().peekable(),
&self.sprites, &self.monochrome_sprites,
self.sprites.iter().peekable(), self.monochrome_sprites.iter().peekable(),
) )
} }
} }
@ -131,7 +135,7 @@ where
}) })
.count(); .count();
self.sprites_start = sprites_end; self.sprites_start = sprites_end;
Some(PrimitiveBatch::Sprites { Some(PrimitiveBatch::MonochromeSprites {
texture_id, texture_id,
sprites: &self.sprites[sprites_start..sprites_end], sprites: &self.sprites[sprites_start..sprites_end],
}) })
@ -171,15 +175,20 @@ pub enum PrimitiveKind {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Primitive { pub enum Primitive {
Quad(Quad), Quad(Quad),
Sprite(MonochromeSprite), MonochromeSprite(MonochromeSprite),
PolychromeSprite(PolychromeSprite),
} }
pub(crate) enum PrimitiveBatch<'a> { pub(crate) enum PrimitiveBatch<'a> {
Quads(&'a [Quad]), Quads(&'a [Quad]),
Sprites { MonochromeSprites {
texture_id: AtlasTextureId, texture_id: AtlasTextureId,
sprites: &'a [MonochromeSprite], sprites: &'a [MonochromeSprite],
}, },
PolychromeSprites {
texture_id: AtlasTextureId,
sprites: &'a [PolychromeSprite],
},
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
@ -256,7 +265,37 @@ impl PartialOrd for MonochromeSprite {
impl From<MonochromeSprite> for Primitive { impl From<MonochromeSprite> for Primitive {
fn from(sprite: MonochromeSprite) -> Self { 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<ScaledPixels>,
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<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl From<PolychromeSprite> for Primitive {
fn from(sprite: PolychromeSprite) -> Self {
Primitive::PolychromeSprite(sprite)
} }
} }

View file

@ -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<H: Hasher>(&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)] #[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Font { pub struct Font {
pub family: SharedString, pub family: SharedString,

View file

@ -159,7 +159,13 @@ impl Line {
} }
if glyph.is_emoji { if glyph.is_emoji {
todo!() cx.paint_emoji(
glyph_origin,
layout.order,
run.font_id,
glyph.id,
self.layout.font_size,
)?;
} else { } else {
cx.paint_glyph( cx.paint_glyph(
glyph_origin, glyph_origin,

View file

@ -2,8 +2,8 @@ use crate::{
px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners, px, AnyView, AppContext, AvailableSpace, BorrowAppContext, Bounds, Context, Corners,
DevicePixels, Effect, Element, EntityId, FontId, GlyphId, Handle, Hsla, IsZero, LayerId, DevicePixels, Effect, Element, EntityId, FontId, GlyphId, Handle, Hsla, IsZero, LayerId,
LayoutId, MainThread, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, LayoutId, MainThread, MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow,
Point, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, SharedString, Size, Point, PolychromeSprite, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene,
Style, TaffyLayoutEngine, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS, SharedString, Size, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
}; };
use anyhow::Result; use anyhow::Result;
use futures::Future; use futures::Future;
@ -17,6 +17,7 @@ pub struct Window {
handle: AnyWindowHandle, handle: AnyWindowHandle,
platform_window: MainThreadOnly<Box<dyn PlatformWindow>>, platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
monochrome_sprite_atlas: Arc<dyn PlatformAtlas>, monochrome_sprite_atlas: Arc<dyn PlatformAtlas>,
polychrome_sprite_atlas: Arc<dyn PlatformAtlas>,
rem_size: Pixels, rem_size: Pixels,
content_size: Size<Pixels>, content_size: Size<Pixels>,
layout_engine: TaffyLayoutEngine, layout_engine: TaffyLayoutEngine,
@ -36,6 +37,7 @@ impl Window {
) -> Self { ) -> Self {
let platform_window = cx.platform().open_window(handle, options); let platform_window = cx.platform().open_window(handle, options);
let monochrome_sprite_atlas = platform_window.monochrome_sprite_atlas(); 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 mouse_position = platform_window.mouse_position();
let content_size = platform_window.content_size(); let content_size = platform_window.content_size();
let scale_factor = platform_window.scale_factor(); let scale_factor = platform_window.scale_factor();
@ -59,6 +61,7 @@ impl Window {
handle, handle,
platform_window, platform_window,
monochrome_sprite_atlas, monochrome_sprite_atlas,
polychrome_sprite_atlas,
rem_size: px(16.), rem_size: px(16.),
content_size, content_size,
layout_engine: TaffyLayoutEngine::new(), layout_engine: TaffyLayoutEngine::new(),
@ -300,6 +303,52 @@ impl<'a, 'w> WindowContext<'a, 'w> {
Ok(()) Ok(())
} }
pub fn paint_emoji(
&mut self,
origin: Point<Pixels>,
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(&params)?;
if !raster_bounds.is_zero() {
let layer_id = self.current_layer_id();
let tile = self
.window
.polychrome_sprite_atlas
.get_or_insert_with(&params.clone().into(), &mut || {
self.text_system().rasterize_glyph(&params)
})?;
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<()> { pub(crate) fn draw(&mut self) -> Result<()> {
let unit_entity = self.unit_entity.clone(); let unit_entity = self.unit_entity.clone();
self.update_entity(&unit_entity, |_, cx| { self.update_entity(&unit_entity, |_, cx| {