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 monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas>;
fn polychrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas>;
}
pub trait PlatformDispatcher: Send + Sync {

View file

@ -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<MetalAtlas>,
polychrome_sprite_atlas: Arc<MetalAtlas>,
}
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<MetalAtlas> {
&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<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(

View file

@ -889,6 +889,10 @@ impl PlatformWindow for MacWindow {
fn monochrome_sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
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 {

View file

@ -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<Quad>,
pub sprites: Vec<MonochromeSprite>,
pub monochrome_sprites: Vec<MonochromeSprite>,
pub polychrome_sprites: Vec<PolychromeSprite>,
}
impl SceneLayer {
pub fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> {
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<MonochromeSprite> 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<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)]
pub struct Font {
pub family: SharedString,

View file

@ -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,

View file

@ -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<Box<dyn PlatformWindow>>,
monochrome_sprite_atlas: Arc<dyn PlatformAtlas>,
polychrome_sprite_atlas: Arc<dyn PlatformAtlas>,
rem_size: Pixels,
content_size: Size<Pixels>,
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<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<()> {
let unit_entity = self.unit_entity.clone();
self.update_entity(&unit_entity, |_, cx| {