Unified · Split
| @@ -47,7 +47,7 @@ fn generate_shader_bindings() -> PathBuf { · 46 unmodified lines | |||
| 47 | "Pixels".into(), | 47 | "Pixels".into(), |
| 48 | "PointF".into(), | 48 | "PointF".into(), |
| 49 | "Hsla".into(), | 49 | "Hsla".into(), |
| 50 | "ScaledContentMask".into(), | 50 | "ContentMask".into(), |
| 51 | "Uniforms".into(), | 51 | "Uniforms".into(), |
| 52 | "AtlasTile".into(), | 52 | "AtlasTile".into(), |
| 53 | "ShadowInputIndex".into(), | 53 | "ShadowInputIndex".into(), |
| @@ -40,7 +40,7 @@ pub(crate) fn current_platform() -> Arc<dyn Platform> { · 39 unmodified lines | |||
| 40 | Arc::new(MacPlatform::new()) | 40 | Arc::new(MacPlatform::new()) |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | pub trait Platform: 'static { | 43 | pub(crate) trait Platform: 'static { |
| 44 | fn executor(&self) -> Executor; | 44 | fn executor(&self) -> Executor; |
| 45 | fn display_linker(&self) -> Arc<dyn PlatformDisplayLinker>; | 45 | fn display_linker(&self) -> Arc<dyn PlatformDisplayLinker>; |
| 46 | fn text_system(&self) -> Arc<dyn PlatformTextSystem>; | 46 | fn text_system(&self) -> Arc<dyn PlatformTextSystem>; |
| @@ -113,7 +113,7 @@ impl Debug for DisplayId { · 66 unmodified lines | |||
| 113 | 113 | ||
| 114 | unsafe impl Send for DisplayId {} | 114 | unsafe impl Send for DisplayId {} |
| 115 | 115 | ||
| 116 | pub trait PlatformWindow { | 116 | pub(crate) trait PlatformWindow { |
| 117 | fn bounds(&self) -> WindowBounds; | 117 | fn bounds(&self) -> WindowBounds; |
| 118 | fn content_size(&self) -> Size<Pixels>; | 118 | fn content_size(&self) -> Size<Pixels>; |
| 119 | fn scale_factor(&self) -> f32; | 119 | fn scale_factor(&self) -> f32; |
| @@ -194,11 +194,17 @@ pub enum AtlasKey { · 74 unmodified lines | |||
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | impl AtlasKey { | 196 | impl AtlasKey { |
| 197 | pub fn is_monochrome(&self) -> bool { | 197 | pub(crate) fn texture_kind(&self) -> AtlasTextureKind { |
| 198 | match self { | 198 | match self { |
| 199 | AtlasKey::Glyph(params) => !params.is_emoji, | 199 | AtlasKey::Glyph(params) => { |
| 200 | AtlasKey::Svg(_) => true, | 200 | if params.is_emoji { |
| 201 | AtlasKey::Image(_) => false, | 201 | AtlasTextureKind::Polychrome |
| 202 | } else { | ||
| 203 | AtlasTextureKind::Monochrome | ||
| 204 | } | ||
| 205 | } | ||
| 206 | AtlasKey::Svg(_) => AtlasTextureKind::Monochrome, | ||
| 207 | AtlasKey::Image(_) => AtlasTextureKind::Polychrome, | ||
| 202 | } | 208 | } |
| 203 | } | 209 | } |
| 204 | } | 210 | } |
| @@ -241,7 +247,19 @@ pub struct AtlasTile { · 36 unmodified lines | |||
| 241 | 247 | ||
| 242 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | 248 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 243 | #[repr(C)] | 249 | #[repr(C)] |
| 244 | pub(crate) struct AtlasTextureId(pub(crate) u32); // We use u32 instead of usize for Metal Shader Language compatibility | 250 | pub(crate) struct AtlasTextureId { |
| 251 | // We use u32 instead of usize for Metal Shader Language compatibility | ||
| 252 | pub(crate) index: u32, | ||
| 253 | pub(crate) kind: AtlasTextureKind, | ||
| 254 | } | ||
| 255 | |||
| 256 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 257 | #[repr(C)] | ||
| 258 | pub(crate) enum AtlasTextureKind { | ||
| 259 | Monochrome = 0, | ||
| 260 | Polychrome = 1, | ||
| 261 | Path = 2, | ||
| 262 | } | ||
| 245 | 263 | ||
| 246 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] | 264 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] |
| 247 | #[repr(C)] | 265 | #[repr(C)] |
| @@ -1,14 +1,14 @@ | |||
| 1 | use std::borrow::Cow; | ||
| 2 | |||
| 3 | use crate::{ | 1 | use crate::{ |
| 4 | AtlasKey, AtlasTextureId, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size, | 2 | AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas, |
| 3 | Point, Size, | ||
| 5 | }; | 4 | }; |
| 6 | use anyhow::{anyhow, Result}; | 5 | use anyhow::Result; |
| 7 | use collections::HashMap; | 6 | use collections::HashMap; |
| 8 | use derive_more::{Deref, DerefMut}; | 7 | use derive_more::{Deref, DerefMut}; |
| 9 | use etagere::BucketedAtlasAllocator; | 8 | use etagere::BucketedAtlasAllocator; |
| 10 | use metal::Device; | 9 | use metal::Device; |
| 11 | use parking_lot::Mutex; | 10 | use parking_lot::Mutex; |
| 11 | use std::borrow::Cow; | ||
| 12 | 12 | ||
| 13 | pub struct MetalAtlas(Mutex<MetalAtlasState>); | 13 | pub struct MetalAtlas(Mutex<MetalAtlasState>); |
| 14 | 14 | ||
| @@ -16,19 +16,31 @@ impl MetalAtlas { · 1 unmodified line | |||
| 16 | pub fn new(device: Device) -> Self { | 16 | pub fn new(device: Device) -> Self { |
| 17 | MetalAtlas(Mutex::new(MetalAtlasState { | 17 | MetalAtlas(Mutex::new(MetalAtlasState { |
| 18 | device: AssertSend(device), | 18 | device: AssertSend(device), |
| 19 | textures: Default::default(), | 19 | monochrome_textures: Default::default(), |
| 20 | polychrome_textures: Default::default(), | ||
| 21 | path_textures: Default::default(), | ||
| 20 | tiles_by_key: Default::default(), | 22 | tiles_by_key: Default::default(), |
| 21 | })) | 23 | })) |
| 22 | } | 24 | } |
| 23 | 25 | ||
| 24 | pub(crate) fn texture(&self, id: AtlasTextureId) -> metal::Texture { | 26 | pub(crate) fn metal_texture(&self, id: AtlasTextureId) -> metal::Texture { |
| 25 | self.0.lock().textures[id.0 as usize].metal_texture.clone() | 27 | self.0.lock().texture(id).metal_texture.clone() |
| 28 | } | ||
| 29 | |||
| 30 | pub(crate) fn allocate( | ||
| 31 | &self, | ||
| 32 | size: Size<DevicePixels>, | ||
| 33 | texture_kind: AtlasTextureKind, | ||
| 34 | ) -> AtlasTile { | ||
| 35 | self.0.lock().allocate(size, texture_kind) | ||
| 26 | } | 36 | } |
| 27 | } | 37 | } |
| 28 | 38 | ||
| 29 | struct MetalAtlasState { | 39 | struct MetalAtlasState { |
| 30 | device: AssertSend<Device>, | 40 | device: AssertSend<Device>, |
| 31 | textures: Vec<MetalAtlasTexture>, | 41 | monochrome_textures: Vec<MetalAtlasTexture>, |
| 42 | polychrome_textures: Vec<MetalAtlasTexture>, | ||
| 43 | path_textures: Vec<MetalAtlasTexture>, | ||
| 32 | tiles_by_key: HashMap<AtlasKey, AtlasTile>, | 44 | tiles_by_key: HashMap<AtlasKey, AtlasTile>, |
| 33 | } | 45 | } |
| 34 | 46 | ||
| @@ -43,23 +55,9 @@ impl PlatformAtlas for MetalAtlas { · 8 unmodified lines | |||
| 43 | return Ok(tile.clone()); | 55 | return Ok(tile.clone()); |
| 44 | } else { | 56 | } else { |
| 45 | let (size, bytes) = build()?; | 57 | let (size, bytes) = build()?; |
| 46 | let tile = lock | 58 | let tile = lock.allocate(size, key.texture_kind()); |
| 47 | .textures | 59 | let texture = lock.texture(tile.texture_id); |
| 48 | .iter_mut() | 60 | texture.upload(tile.bounds, &bytes); |
| 49 | .rev() | ||
| 50 | .find_map(|texture| { | ||
| 51 | if texture.monochrome == key.is_monochrome() { | ||
| 52 | texture.upload(size, &bytes) | ||
| 53 | } else { | ||
| 54 | None | ||
| 55 | } | ||
| 56 | }) | ||
| 57 | .or_else(|| { | ||
| 58 | let texture = lock.push_texture(size, key.is_monochrome()); | ||
| 59 | texture.upload(size, &bytes) | ||
| 60 | }) | ||
| 61 | .ok_or_else(|| anyhow!("could not allocate in new texture"))?; | ||
| 62 | lock.tiles_by_key.insert(key.clone(), tile.clone()); | ||
| 63 | Ok(tile) | 61 | Ok(tile) |
| 64 | } | 62 | } |
| 65 | } | 63 | } |
| @@ -70,10 +68,26 @@ impl PlatformAtlas for MetalAtlas { · 4 unmodified lines | |||
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | impl MetalAtlasState { | 70 | impl MetalAtlasState { |
| 71 | fn allocate(&mut self, size: Size<DevicePixels>, texture_kind: AtlasTextureKind) -> AtlasTile { | ||
| 72 | let textures = match texture_kind { | ||
| 73 | AtlasTextureKind::Monochrome => &mut self.monochrome_textures, | ||
| 74 | AtlasTextureKind::Polychrome => &mut self.polychrome_textures, | ||
| 75 | AtlasTextureKind::Path => &mut self.path_textures, | ||
| 76 | }; | ||
| 77 | textures | ||
| 78 | .iter_mut() | ||
| 79 | .rev() | ||
| 80 | .find_map(|texture| texture.allocate(size)) | ||
| 81 | .unwrap_or_else(|| { | ||
| 82 | let texture = self.push_texture(size, texture_kind); | ||
| 83 | texture.allocate(size).unwrap() | ||
| 84 | }) | ||
| 85 | } | ||
| 86 | |||
| 73 | fn push_texture( | 87 | fn push_texture( |
| 74 | &mut self, | 88 | &mut self, |
| 75 | min_size: Size<DevicePixels>, | 89 | min_size: Size<DevicePixels>, |
| 76 | monochrome: bool, | 90 | kind: AtlasTextureKind, |
| 77 | ) -> &mut MetalAtlasTexture { | 91 | ) -> &mut MetalAtlasTexture { |
| 78 | const DEFAULT_ATLAS_SIZE: Size<DevicePixels> = Size { | 92 | const DEFAULT_ATLAS_SIZE: Size<DevicePixels> = Size { |
| 79 | width: DevicePixels(1024), | 93 | width: DevicePixels(1024), |
| @@ -84,21 +98,38 @@ impl MetalAtlasState { · 4 unmodified lines | |||
| 84 | let texture_descriptor = metal::TextureDescriptor::new(); | 98 | let texture_descriptor = metal::TextureDescriptor::new(); |
| 85 | texture_descriptor.set_width(size.width.into()); | 99 | texture_descriptor.set_width(size.width.into()); |
| 86 | texture_descriptor.set_height(size.height.into()); | 100 | texture_descriptor.set_height(size.height.into()); |
| 87 | if monochrome { | 101 | let pixel_format = match kind { |
| 88 | texture_descriptor.set_pixel_format(metal::MTLPixelFormat::A8Unorm); | 102 | AtlasTextureKind::Monochrome => metal::MTLPixelFormat::A8Unorm, |
| 89 | } else { | 103 | AtlasTextureKind::Polychrome => metal::MTLPixelFormat::BGRA8Unorm, |
| 90 | texture_descriptor.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm); | 104 | AtlasTextureKind::Path => metal::MTLPixelFormat::R16Float, |
| 91 | } | 105 | }; |
| 106 | texture_descriptor.set_pixel_format(pixel_format); | ||
| 92 | let metal_texture = self.device.new_texture(&texture_descriptor); | 107 | let metal_texture = self.device.new_texture(&texture_descriptor); |
| 93 | 108 | ||
| 109 | let textures = match kind { | ||
| 110 | AtlasTextureKind::Monochrome => &mut self.monochrome_textures, | ||
| 111 | AtlasTextureKind::Polychrome => &mut self.polychrome_textures, | ||
| 112 | AtlasTextureKind::Path => &mut self.path_textures, | ||
| 113 | }; | ||
| 94 | let atlas_texture = MetalAtlasTexture { | 114 | let atlas_texture = MetalAtlasTexture { |
| 95 | id: AtlasTextureId(self.textures.len() as u32), | 115 | id: AtlasTextureId { |
| 116 | index: textures.len() as u32, | ||
| 117 | kind, | ||
| 118 | }, | ||
| 96 | allocator: etagere::BucketedAtlasAllocator::new(size.into()), | 119 | allocator: etagere::BucketedAtlasAllocator::new(size.into()), |
| 97 | metal_texture: AssertSend(metal_texture), | 120 | metal_texture: AssertSend(metal_texture), |
| 98 | monochrome, | ||
| 99 | }; | 121 | }; |
| 100 | self.textures.push(atlas_texture); | 122 | textures.push(atlas_texture); |
| 101 | self.textures.last_mut().unwrap() | 123 | textures.last_mut().unwrap() |
| 124 | } | ||
| 125 | |||
| 126 | fn texture(&self, id: AtlasTextureId) -> &MetalAtlasTexture { | ||
| 127 | let textures = match id.kind { | ||
| 128 | crate::AtlasTextureKind::Monochrome => &self.monochrome_textures, | ||
| 129 | crate::AtlasTextureKind::Polychrome => &self.polychrome_textures, | ||
| 130 | crate::AtlasTextureKind::Path => &self.path_textures, | ||
| 131 | }; | ||
| 132 | &textures[id.index as usize] | ||
| 102 | } | 133 | } |
| 103 | } | 134 | } |
| 104 | 135 | ||
| @@ -106,11 +137,10 @@ struct MetalAtlasTexture { · 1 unmodified line | |||
| 106 | id: AtlasTextureId, | 137 | id: AtlasTextureId, |
| 107 | allocator: BucketedAtlasAllocator, | 138 | allocator: BucketedAtlasAllocator, |
| 108 | metal_texture: AssertSend<metal::Texture>, | 139 | metal_texture: AssertSend<metal::Texture>, |
| 109 | monochrome: bool, | ||
| 110 | } | 140 | } |
| 111 | 141 | ||
| 112 | impl MetalAtlasTexture { | 142 | impl MetalAtlasTexture { |
| 113 | fn upload(&mut self, size: Size<DevicePixels>, bytes: &[u8]) -> Option<AtlasTile> { | 143 | fn allocate(&mut self, size: Size<DevicePixels>) -> Option<AtlasTile> { |
| 114 | let allocation = self.allocator.allocate(size.into())?; | 144 | let allocation = self.allocator.allocate(size.into())?; |
| 115 | let tile = AtlasTile { | 145 | let tile = AtlasTile { |
| 116 | texture_id: self.id, | 146 | texture_id: self.id, |
| @@ -120,20 +150,22 @@ impl MetalAtlasTexture { · 3 unmodified lines | |||
| 120 | size, | 150 | size, |
| 121 | }, | 151 | }, |
| 122 | }; | 152 | }; |
| 153 | Some(tile) | ||
| 154 | } | ||
| 123 | 155 | ||
| 156 | fn upload(&self, bounds: Bounds<DevicePixels>, bytes: &[u8]) { | ||
| 124 | let region = metal::MTLRegion::new_2d( | 157 | let region = metal::MTLRegion::new_2d( |
| 125 | tile.bounds.origin.x.into(), | 158 | bounds.origin.x.into(), |
| 126 | tile.bounds.origin.y.into(), | 159 | bounds.origin.y.into(), |
| 127 | tile.bounds.size.width.into(), | 160 | bounds.size.width.into(), |
| 128 | tile.bounds.size.height.into(), | 161 | bounds.size.height.into(), |
| 129 | ); | 162 | ); |
| 130 | self.metal_texture.replace_region( | 163 | self.metal_texture.replace_region( |
| 131 | region, | 164 | region, |
| 132 | 0, | 165 | 0, |
| 133 | bytes.as_ptr() as *const _, | 166 | bytes.as_ptr() as *const _, |
| 134 | u32::from(tile.bounds.size.width.to_bytes(self.bytes_per_pixel())) as u64, | 167 | u32::from(bounds.size.width.to_bytes(self.bytes_per_pixel())) as u64, |
| 135 | ); | 168 | ); |
| 136 | Some(tile) | ||
| 137 | } | 169 | } |
| 138 | 170 | ||
| 139 | fn bytes_per_pixel(&self) -> u8 { | 171 | fn bytes_per_pixel(&self) -> u8 { |
| @@ -1,12 +1,14 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, PolychromeSprite, | 2 | point, size, AtlasTextureId, AtlasTextureKind, AtlasTile, DevicePixels, MetalAtlas, |
| 3 | PrimitiveBatch, Quad, Scene, Shadow, Size, Underline, | 3 | MonochromeSprite, PathId, PolychromeSprite, PrimitiveBatch, Quad, Scene, Shadow, Size, |
| 4 | Underline, | ||
| 4 | }; | 5 | }; |
| 5 | use cocoa::{ | 6 | use cocoa::{ |
| 6 | base::{NO, YES}, | 7 | base::{NO, YES}, |
| 7 | foundation::NSUInteger, | 8 | foundation::NSUInteger, |
| 8 | quartzcore::AutoresizingMask, | 9 | quartzcore::AutoresizingMask, |
| 9 | }; | 10 | }; |
| 11 | use collections::HashMap; | ||
| 10 | use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange}; | 12 | use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange}; |
| 11 | use objc::{self, msg_send, sel, sel_impl}; | 13 | use objc::{self, msg_send, sel, sel_impl}; |
| 12 | use std::{ffi::c_void, mem, ptr, sync::Arc}; | 14 | use std::{ffi::c_void, mem, ptr, sync::Arc}; |
| @@ -14,7 +16,7 @@ use std::{ffi::c_void, mem, ptr, sync::Arc}; · 1 unmodified line | |||
| 14 | const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); | 16 | const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); |
| 15 | const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. | 17 | const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. |
| 16 | 18 | ||
| 17 | pub struct MetalRenderer { | 19 | pub(crate) struct MetalRenderer { |
| 18 | layer: metal::MetalLayer, | 20 | layer: metal::MetalLayer, |
| 19 | command_queue: CommandQueue, | 21 | command_queue: CommandQueue, |
| 20 | shadows_pipeline_state: metal::RenderPipelineState, | 22 | shadows_pipeline_state: metal::RenderPipelineState, |
| @@ -150,7 +152,7 @@ impl MetalRenderer { · 129 unmodified lines | |||
| 150 | &self.sprite_atlas | 152 | &self.sprite_atlas |
| 151 | } | 153 | } |
| 152 | 154 | ||
| 153 | pub fn draw(&mut self, scene: &mut Scene) { | 155 | pub fn draw(&mut self, scene: &Scene) { |
| 154 | let layer = self.layer.clone(); | 156 | let layer = self.layer.clone(); |
| 155 | let viewport_size = layer.drawable_size(); | 157 | let viewport_size = layer.drawable_size(); |
| 156 | let viewport_size: Size<DevicePixels> = size( | 158 | let viewport_size: Size<DevicePixels> = size( |
| @@ -192,6 +194,15 @@ impl MetalRenderer { · 35 unmodified lines | |||
| 192 | }); | 194 | }); |
| 193 | 195 | ||
| 194 | let mut instance_offset = 0; | 196 | let mut instance_offset = 0; |
| 197 | |||
| 198 | let mut path_tiles: HashMap<PathId, AtlasTile> = HashMap::default(); | ||
| 199 | for path in scene.paths() { | ||
| 200 | let tile = self | ||
| 201 | .sprite_atlas | ||
| 202 | .allocate(path.bounds.size.map(Into::into), AtlasTextureKind::Path); | ||
| 203 | path_tiles.insert(path.id, tile); | ||
| 204 | } | ||
| 205 | |||
| 195 | for batch in scene.batches() { | 206 | for batch in scene.batches() { |
| 196 | match batch { | 207 | match batch { |
| 197 | PrimitiveBatch::Shadows(shadows) => { | 208 | PrimitiveBatch::Shadows(shadows) => { |
| @@ -205,6 +216,9 @@ impl MetalRenderer { · 7 unmodified lines | |||
| 205 | PrimitiveBatch::Quads(quads) => { | 216 | PrimitiveBatch::Quads(quads) => { |
| 206 | self.draw_quads(quads, &mut instance_offset, viewport_size, command_encoder); | 217 | self.draw_quads(quads, &mut instance_offset, viewport_size, command_encoder); |
| 207 | } | 218 | } |
| 219 | PrimitiveBatch::Paths(paths) => { | ||
| 220 | // self.draw_paths(paths, &mut instance_offset, viewport_size, command_encoder); | ||
| 221 | } | ||
| 208 | PrimitiveBatch::Underlines(underlines) => { | 222 | PrimitiveBatch::Underlines(underlines) => { |
| 209 | self.draw_underlines( | 223 | self.draw_underlines( |
| 210 | underlines, | 224 | underlines, |
| @@ -441,7 +455,7 @@ impl MetalRenderer { · 230 unmodified lines | |||
| 441 | } | 455 | } |
| 442 | align_offset(offset); | 456 | align_offset(offset); |
| 443 | 457 | ||
| 444 | let texture = self.sprite_atlas.texture(texture_id); | 458 | let texture = self.sprite_atlas.metal_texture(texture_id); |
| 445 | let texture_size = size( | 459 | let texture_size = size( |
| 446 | DevicePixels(texture.width() as i32), | 460 | DevicePixels(texture.width() as i32), |
| 447 | DevicePixels(texture.height() as i32), | 461 | DevicePixels(texture.height() as i32), |
| @@ -512,7 +526,7 @@ impl MetalRenderer { · 64 unmodified lines | |||
| 512 | } | 526 | } |
| 513 | align_offset(offset); | 527 | align_offset(offset); |
| 514 | 528 | ||
| 515 | let texture = self.sprite_atlas.texture(texture_id); | 529 | let texture = self.sprite_atlas.metal_texture(texture_id); |
| 516 | let texture_size = size( | 530 | let texture_size = size( |
| 517 | DevicePixels(texture.width() as i32), | 531 | DevicePixels(texture.width() as i32), |
| 518 | DevicePixels(texture.height() as i32), | 532 | DevicePixels(texture.height() as i32), |
| @@ -911,7 +911,7 @@ impl PlatformWindow for MacWindow { · 910 unmodified lines | |||
| 911 | } | 911 | } |
| 912 | } | 912 | } |
| 913 | 913 | ||
| 914 | fn draw(&self, scene: crate::Scene) { | 914 | fn draw(&self, scene: Scene) { |
| 915 | let mut this = self.0.lock(); | 915 | let mut this = self.0.lock(); |
| 916 | this.scene_to_render = Some(scene); | 916 | this.scene_to_render = Some(scene); |
| 917 | unsafe { | 917 | unsafe { |
| @@ -1395,8 +1395,8 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) { · 477 unmodified lines | |||
| 1395 | unsafe { | 1395 | unsafe { |
| 1396 | let window_state = get_window_state(this); | 1396 | let window_state = get_window_state(this); |
| 1397 | let mut window_state = window_state.as_ref().lock(); | 1397 | let mut window_state = window_state.as_ref().lock(); |
| 1398 | if let Some(mut scene) = window_state.scene_to_render.take() { | 1398 | if let Some(scene) = window_state.scene_to_render.take() { |
| 1399 | window_state.renderer.draw(&mut scene); | 1399 | window_state.renderer.draw(&scene); |
| 1400 | } | 1400 | } |
| 1401 | } | 1401 | } |
| 1402 | } | 1402 | } |
| @@ -1,16 +1,12 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | point, px, AtlasTextureId, AtlasTile, Bounds, Corners, Edges, Hsla, Pixels, Point, | 2 | point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges, Hsla, Pixels, Point, |
| 3 | ScaledContentMask, ScaledPixels, | 3 | ScaledPixels, |
| 4 | }; | 4 | }; |
| 5 | use collections::BTreeMap; | 5 | use collections::BTreeMap; |
| 6 | use etagere::euclid::{Point3D, Vector3D}; | 6 | use etagere::euclid::{Point3D, Vector3D}; |
| 7 | use plane_split::{BspSplitter, Polygon as BspPolygon}; | 7 | use plane_split::{BspSplitter, Polygon as BspPolygon}; |
| 8 | use smallvec::SmallVec; | 8 | use smallvec::SmallVec; |
| 9 | use std::{ | 9 | use std::{fmt::Debug, iter::Peekable, mem, slice}; |
| 10 | iter::Peekable, | ||
| 11 | mem, slice, | ||
| 12 | sync::atomic::{AtomicU32, Ordering::SeqCst}, | ||
| 13 | }; | ||
| 14 | 10 | ||
| 15 | // Exported to metal | 11 | // Exported to metal |
| 16 | pub type PointF = Point<f32>; | 12 | pub type PointF = Point<f32>; |
| @@ -18,94 +14,57 @@ pub type StackingOrder = SmallVec<[u32; 16]>; · 1 unmodified line | |||
| 18 | pub type LayerId = u32; | 14 | pub type LayerId = u32; |
| 19 | pub type DrawOrder = u32; | 15 | pub type DrawOrder = u32; |
| 20 | 16 | ||
| 21 | #[derive(Debug)] | 17 | pub(crate) struct SceneBuilder { |
| 22 | pub struct Scene { | 18 | layers_by_order: BTreeMap<StackingOrder, LayerId>, |
| 23 | pub(crate) scale_factor: f32, | 19 | splitter: BspSplitter<(PrimitiveKind, usize)>, |
| 24 | pub(crate) layers: BTreeMap<StackingOrder, LayerId>, | 20 | shadows: Vec<Shadow>, |
| 25 | pub shadows: Vec<Shadow>, | 21 | quads: Vec<Quad>, |
| 26 | pub quads: Vec<Quad>, | 22 | paths: Vec<Path<ScaledPixels>>, |
| 27 | pub underlines: Vec<Underline>, | 23 | underlines: Vec<Underline>, |
| 28 | pub monochrome_sprites: Vec<MonochromeSprite>, | 24 | monochrome_sprites: Vec<MonochromeSprite>, |
| 29 | pub polychrome_sprites: Vec<PolychromeSprite>, | 25 | polychrome_sprites: Vec<PolychromeSprite>, |
| 30 | } | 26 | } |
| 31 | 27 | ||
| 32 | impl Scene { | 28 | impl SceneBuilder { |
| 33 | pub fn new(scale_factor: f32) -> Scene { | 29 | pub fn new() -> SceneBuilder { |
| 34 | Scene { | 30 | SceneBuilder { |
| 35 | scale_factor, | 31 | layers_by_order: BTreeMap::new(), |
| 36 | layers: BTreeMap::new(), | 32 | splitter: BspSplitter::new(), |
| 37 | shadows: Vec::new(), | 33 | shadows: Vec::new(), |
| 38 | quads: Vec::new(), | 34 | quads: Vec::new(), |
| 35 | paths: Vec::new(), | ||
| 39 | underlines: Vec::new(), | 36 | underlines: Vec::new(), |
| 40 | monochrome_sprites: Vec::new(), | 37 | monochrome_sprites: Vec::new(), |
| 41 | polychrome_sprites: Vec::new(), | 38 | polychrome_sprites: Vec::new(), |
| 42 | } | 39 | } |
| 43 | } | 40 | } |
| 44 | 41 | ||
| 45 | pub fn take(&mut self) -> Scene { | 42 | pub fn build(&mut self) -> Scene { |
| 46 | Scene { | ||
| 47 | scale_factor: self.scale_factor, | ||
| 48 | layers: mem::take(&mut self.layers), | ||
| 49 | shadows: mem::take(&mut self.shadows), | ||
| 50 | quads: mem::take(&mut self.quads), | ||
| 51 | underlines: mem::take(&mut self.underlines), | ||
| 52 | monochrome_sprites: mem::take(&mut self.monochrome_sprites), | ||
| 53 | polychrome_sprites: mem::take(&mut self.polychrome_sprites), | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | pub fn insert(&mut self, layer_id: StackingOrder, primitive: impl Into<Primitive>) { | ||
| 58 | let next_id = self.layers.len() as LayerId; | ||
| 59 | let layer_id = *self.layers.entry(layer_id).or_insert(next_id); | ||
| 60 | let primitive = primitive.into(); | ||
| 61 | match primitive { | ||
| 62 | Primitive::Shadow(mut shadow) => { | ||
| 63 | shadow.order = layer_id; | ||
| 64 | self.shadows.push(shadow); | ||
| 65 | } | ||
| 66 | Primitive::Quad(mut quad) => { | ||
| 67 | quad.order = layer_id; | ||
| 68 | self.quads.push(quad); | ||
| 69 | } | ||
| 70 | Primitive::Underline(mut underline) => { | ||
| 71 | underline.order = layer_id; | ||
| 72 | self.underlines.push(underline); | ||
| 73 | } | ||
| 74 | Primitive::MonochromeSprite(mut sprite) => { | ||
| 75 | sprite.order = layer_id; | ||
| 76 | self.monochrome_sprites.push(sprite); | ||
| 77 | } | ||
| 78 | Primitive::PolychromeSprite(mut sprite) => { | ||
| 79 | sprite.order = layer_id; | ||
| 80 | self.polychrome_sprites.push(sprite); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | pub(crate) fn batches(&mut self) -> impl Iterator<Item = PrimitiveBatch> { | ||
| 86 | // Map each layer id to a float between 0. and 1., with 1. closer to the viewer. | 43 | // Map each layer id to a float between 0. and 1., with 1. closer to the viewer. |
| 87 | let mut layer_z_values = vec![0.; self.layers.len()]; | 44 | let mut layer_z_values = vec![0.; self.layers_by_order.len()]; |
| 88 | for (ix, layer_id) in self.layers.values().enumerate() { | 45 | for (ix, layer_id) in self.layers_by_order.values().enumerate() { |
| 89 | layer_z_values[*layer_id as usize] = ix as f32 / self.layers.len() as f32; | 46 | layer_z_values[*layer_id as usize] = ix as f32 / self.layers_by_order.len() as f32; |
| 90 | } | 47 | } |
| 48 | self.layers_by_order.clear(); | ||
| 91 | 49 | ||
| 92 | // Add all primitives to the BSP splitter to determine draw order | 50 | // Add all primitives to the BSP splitter to determine draw order |
| 93 | // todo!("reuse the same splitter") | 51 | self.splitter.reset(); |
| 94 | let mut splitter = BspSplitter::new(); | ||
| 95 | 52 | ||
| 96 | for (ix, shadow) in self.shadows.iter().enumerate() { | 53 | for (ix, shadow) in self.shadows.iter().enumerate() { |
| 97 | let z = layer_z_values[shadow.order as LayerId as usize]; | 54 | let z = layer_z_values[shadow.order as LayerId as usize]; |
| 98 | splitter.add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix))); | 55 | self.splitter |
| 56 | .add(shadow.bounds.to_bsp_polygon(z, (PrimitiveKind::Shadow, ix))); | ||
| 99 | } | 57 | } |
| 100 | 58 | ||
| 101 | for (ix, quad) in self.quads.iter().enumerate() { | 59 | for (ix, quad) in self.quads.iter().enumerate() { |
| 102 | let z = layer_z_values[quad.order as LayerId as usize]; | 60 | let z = layer_z_values[quad.order as LayerId as usize]; |
| 103 | splitter.add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix))); | 61 | self.splitter |
| 62 | .add(quad.bounds.to_bsp_polygon(z, (PrimitiveKind::Quad, ix))); | ||
| 104 | } | 63 | } |
| 105 | 64 | ||
| 106 | for (ix, underline) in self.underlines.iter().enumerate() { | 65 | for (ix, underline) in self.underlines.iter().enumerate() { |
| 107 | let z = layer_z_values[underline.order as LayerId as usize]; | 66 | let z = layer_z_values[underline.order as LayerId as usize]; |
| 108 | splitter.add( | 67 | self.splitter.add( |
| 109 | underline | 68 | underline |
| 110 | .bounds | 69 | .bounds |
| 111 | .to_bsp_polygon(z, (PrimitiveKind::Underline, ix)), | 70 | .to_bsp_polygon(z, (PrimitiveKind::Underline, ix)), |
| @@ -114,7 +73,7 @@ impl Scene { · 2 unmodified lines | |||
| 114 | 73 | ||
| 115 | for (ix, monochrome_sprite) in self.monochrome_sprites.iter().enumerate() { | 74 | for (ix, monochrome_sprite) in self.monochrome_sprites.iter().enumerate() { |
| 116 | let z = layer_z_values[monochrome_sprite.order as LayerId as usize]; | 75 | let z = layer_z_values[monochrome_sprite.order as LayerId as usize]; |
| 117 | splitter.add( | 76 | self.splitter.add( |
| 118 | monochrome_sprite | 77 | monochrome_sprite |
| 119 | .bounds | 78 | .bounds |
| 120 | .to_bsp_polygon(z, (PrimitiveKind::MonochromeSprite, ix)), | 79 | .to_bsp_polygon(z, (PrimitiveKind::MonochromeSprite, ix)), |
| @@ -123,7 +82,7 @@ impl Scene { · 2 unmodified lines | |||
| 123 | 82 | ||
| 124 | for (ix, polychrome_sprite) in self.polychrome_sprites.iter().enumerate() { | 83 | for (ix, polychrome_sprite) in self.polychrome_sprites.iter().enumerate() { |
| 125 | let z = layer_z_values[polychrome_sprite.order as LayerId as usize]; | 84 | let z = layer_z_values[polychrome_sprite.order as LayerId as usize]; |
| 126 | splitter.add( | 85 | self.splitter.add( |
| 127 | polychrome_sprite | 86 | polychrome_sprite |
| 128 | .bounds | 87 | .bounds |
| 129 | .to_bsp_polygon(z, (PrimitiveKind::PolychromeSprite, ix)), | 88 | .to_bsp_polygon(z, (PrimitiveKind::PolychromeSprite, ix)), |
| @@ -132,10 +91,16 @@ impl Scene { · 2 unmodified lines | |||
| 132 | 91 | ||
| 133 | // Sort all polygons, then reassign the order field of each primitive to `draw_order` | 92 | // Sort all polygons, then reassign the order field of each primitive to `draw_order` |
| 134 | // We need primitives to be repr(C), hence the weird reuse of the order field for two different types. | 93 | // We need primitives to be repr(C), hence the weird reuse of the order field for two different types. |
| 135 | for (draw_order, polygon) in splitter.sort(Vector3D::new(0., 0., 1.)).iter().enumerate() { | 94 | for (draw_order, polygon) in self |
| 95 | .splitter | ||
| 96 | .sort(Vector3D::new(0., 0., 1.)) | ||
| 97 | .iter() | ||
| 98 | .enumerate() | ||
| 99 | { | ||
| 136 | match polygon.anchor { | 100 | match polygon.anchor { |
| 137 | (PrimitiveKind::Shadow, ix) => self.shadows[ix].order = draw_order as DrawOrder, | 101 | (PrimitiveKind::Shadow, ix) => self.shadows[ix].order = draw_order as DrawOrder, |
| 138 | (PrimitiveKind::Quad, ix) => self.quads[ix].order = draw_order as DrawOrder, | 102 | (PrimitiveKind::Quad, ix) => self.quads[ix].order = draw_order as DrawOrder, |
| 103 | (PrimitiveKind::Path, ix) => self.paths[ix].order = draw_order as DrawOrder, | ||
| 139 | (PrimitiveKind::Underline, ix) => { | 104 | (PrimitiveKind::Underline, ix) => { |
| 140 | self.underlines[ix].order = draw_order as DrawOrder | 105 | self.underlines[ix].order = draw_order as DrawOrder |
| 141 | } | 106 | } |
| @@ -148,13 +113,78 @@ impl Scene { · 6 unmodified lines | |||
| 148 | } | 113 | } |
| 149 | } | 114 | } |
| 150 | 115 | ||
| 151 | // Sort the primitives | ||
| 152 | self.shadows.sort_unstable(); | 116 | self.shadows.sort_unstable(); |
| 153 | self.quads.sort_unstable(); | 117 | self.quads.sort_unstable(); |
| 118 | self.paths.sort_unstable(); | ||
| 154 | self.underlines.sort_unstable(); | 119 | self.underlines.sort_unstable(); |
| 155 | self.monochrome_sprites.sort_unstable(); | 120 | self.monochrome_sprites.sort_unstable(); |
| 156 | self.polychrome_sprites.sort_unstable(); | 121 | self.polychrome_sprites.sort_unstable(); |
| 157 | 122 | ||
| 123 | Scene { | ||
| 124 | shadows: mem::take(&mut self.shadows), | ||
| 125 | quads: mem::take(&mut self.quads), | ||
| 126 | paths: mem::take(&mut self.paths), | ||
| 127 | underlines: mem::take(&mut self.underlines), | ||
| 128 | monochrome_sprites: mem::take(&mut self.monochrome_sprites), | ||
| 129 | polychrome_sprites: mem::take(&mut self.polychrome_sprites), | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | pub fn insert(&mut self, order: &StackingOrder, primitive: impl Into<Primitive>) { | ||
| 134 | let layer_id = if let Some(layer_id) = self.layers_by_order.get(order) { | ||
| 135 | *layer_id | ||
| 136 | } else { | ||
| 137 | let next_id = self.layers_by_order.len() as LayerId; | ||
| 138 | self.layers_by_order.insert(order.clone(), next_id); | ||
| 139 | next_id | ||
| 140 | }; | ||
| 141 | |||
| 142 | let primitive = primitive.into(); | ||
| 143 | match primitive { | ||
| 144 | Primitive::Shadow(mut shadow) => { | ||
| 145 | shadow.order = layer_id; | ||
| 146 | self.shadows.push(shadow); | ||
| 147 | } | ||
| 148 | Primitive::Quad(mut quad) => { | ||
| 149 | quad.order = layer_id; | ||
| 150 | self.quads.push(quad); | ||
| 151 | } | ||
| 152 | Primitive::Path(mut path) => { | ||
| 153 | path.order = layer_id; | ||
| 154 | path.id = PathId(self.paths.len()); | ||
| 155 | self.paths.push(path); | ||
| 156 | } | ||
| 157 | Primitive::Underline(mut underline) => { | ||
| 158 | underline.order = layer_id; | ||
| 159 | self.underlines.push(underline); | ||
| 160 | } | ||
| 161 | Primitive::MonochromeSprite(mut sprite) => { | ||
| 162 | sprite.order = layer_id; | ||
| 163 | self.monochrome_sprites.push(sprite); | ||
| 164 | } | ||
| 165 | Primitive::PolychromeSprite(mut sprite) => { | ||
| 166 | sprite.order = layer_id; | ||
| 167 | self.polychrome_sprites.push(sprite); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | pub(crate) struct Scene { | ||
| 174 | pub shadows: Vec<Shadow>, | ||
| 175 | pub quads: Vec<Quad>, | ||
| 176 | pub paths: Vec<Path<ScaledPixels>>, | ||
| 177 | pub underlines: Vec<Underline>, | ||
| 178 | pub monochrome_sprites: Vec<MonochromeSprite>, | ||
| 179 | pub polychrome_sprites: Vec<PolychromeSprite>, | ||
| 180 | } | ||
| 181 | |||
| 182 | impl Scene { | ||
| 183 | pub fn paths(&self) -> impl Iterator<Item = &Path<ScaledPixels>> { | ||
| 184 | self.paths.iter() | ||
| 185 | } | ||
| 186 | |||
| 187 | pub fn batches(&self) -> impl Iterator<Item = PrimitiveBatch> { | ||
| 158 | BatchIterator { | 188 | BatchIterator { |
| 159 | shadows: &self.shadows, | 189 | shadows: &self.shadows, |
| 160 | shadows_start: 0, | 190 | shadows_start: 0, |
| @@ -162,6 +192,9 @@ impl Scene { · 1 unmodified line | |||
| 162 | quads: &self.quads, | 192 | quads: &self.quads, |
| 163 | quads_start: 0, | 193 | quads_start: 0, |
| 164 | quads_iter: self.quads.iter().peekable(), | 194 | quads_iter: self.quads.iter().peekable(), |
| 195 | paths: &self.paths, | ||
| 196 | paths_start: 0, | ||
| 197 | paths_iter: self.paths.iter().peekable(), | ||
| 165 | underlines: &self.underlines, | 198 | underlines: &self.underlines, |
| 166 | underlines_start: 0, | 199 | underlines_start: 0, |
| 167 | underlines_iter: self.underlines.iter().peekable(), | 200 | underlines_iter: self.underlines.iter().peekable(), |
| @@ -176,12 +209,15 @@ impl Scene { · 8 unmodified lines | |||
| 176 | } | 209 | } |
| 177 | 210 | ||
| 178 | struct BatchIterator<'a> { | 211 | struct BatchIterator<'a> { |
| 179 | quads: &'a [Quad], | ||
| 180 | quads_start: usize, | ||
| 181 | quads_iter: Peekable<slice::Iter<'a, Quad>>, | ||
| 182 | shadows: &'a [Shadow], | 212 | shadows: &'a [Shadow], |
| 183 | shadows_start: usize, | 213 | shadows_start: usize, |
| 184 | shadows_iter: Peekable<slice::Iter<'a, Shadow>>, | 214 | shadows_iter: Peekable<slice::Iter<'a, Shadow>>, |
| 215 | quads: &'a [Quad], | ||
| 216 | quads_start: usize, | ||
| 217 | quads_iter: Peekable<slice::Iter<'a, Quad>>, | ||
| 218 | paths: &'a [Path<ScaledPixels>], | ||
| 219 | paths_start: usize, | ||
| 220 | paths_iter: Peekable<slice::Iter<'a, Path<ScaledPixels>>>, | ||
| 185 | underlines: &'a [Underline], | 221 | underlines: &'a [Underline], |
| 186 | underlines_start: usize, | 222 | underlines_start: usize, |
| 187 | underlines_iter: Peekable<slice::Iter<'a, Underline>>, | 223 | underlines_iter: Peekable<slice::Iter<'a, Underline>>, |
| @@ -255,6 +291,19 @@ impl<'a> Iterator for BatchIterator<'a> { · 67 unmodified lines | |||
| 255 | self.quads_start = quads_end; | 291 | self.quads_start = quads_end; |
| 256 | Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end])) | 292 | Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end])) |
| 257 | } | 293 | } |
| 294 | PrimitiveKind::Path => { | ||
| 295 | let paths_start = self.paths_start; | ||
| 296 | let mut paths_end = paths_start; | ||
| 297 | while self | ||
| 298 | .paths_iter | ||
| 299 | .next_if(|path| path.order <= max_order) | ||
| 300 | .is_some() | ||
| 301 | { | ||
| 302 | paths_end += 1; | ||
| 303 | } | ||
| 304 | self.paths_start = paths_end; | ||
| 305 | Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end])) | ||
| 306 | } | ||
| 258 | PrimitiveKind::Underline => { | 307 | PrimitiveKind::Underline => { |
| 259 | let underlines_start = self.underlines_start; | 308 | let underlines_start = self.underlines_start; |
| 260 | let mut underlines_end = underlines_start; | 309 | let mut underlines_end = underlines_start; |
| @@ -317,15 +366,16 @@ pub enum PrimitiveKind { · 56 unmodified lines | |||
| 317 | Shadow, | 366 | Shadow, |
| 318 | #[default] | 367 | #[default] |
| 319 | Quad, | 368 | Quad, |
| 369 | Path, | ||
| 320 | Underline, | 370 | Underline, |
| 321 | MonochromeSprite, | 371 | MonochromeSprite, |
| 322 | PolychromeSprite, | 372 | PolychromeSprite, |
| 323 | } | 373 | } |
| 324 | 374 | ||
| 325 | #[derive(Clone, Debug)] | ||
| 326 | pub enum Primitive { | 375 | pub enum Primitive { |
| 327 | Shadow(Shadow), | 376 | Shadow(Shadow), |
| 328 | Quad(Quad), | 377 | Quad(Quad), |
| 378 | Path(Path<ScaledPixels>), | ||
| 329 | Underline(Underline), | 379 | Underline(Underline), |
| 330 | MonochromeSprite(MonochromeSprite), | 380 | MonochromeSprite(MonochromeSprite), |
| 331 | PolychromeSprite(PolychromeSprite), | 381 | PolychromeSprite(PolychromeSprite), |
| @@ -335,6 +385,7 @@ pub enum Primitive { · 3 unmodified lines | |||
| 335 | pub(crate) enum PrimitiveBatch<'a> { | 385 | pub(crate) enum PrimitiveBatch<'a> { |
| 336 | Shadows(&'a [Shadow]), | 386 | Shadows(&'a [Shadow]), |
| 337 | Quads(&'a [Quad]), | 387 | Quads(&'a [Quad]), |
| 388 | Paths(&'a [Path<ScaledPixels>]), | ||
| 338 | Underlines(&'a [Underline]), | 389 | Underlines(&'a [Underline]), |
| 339 | MonochromeSprites { | 390 | MonochromeSprites { |
| 340 | texture_id: AtlasTextureId, | 391 | texture_id: AtlasTextureId, |
| @@ -351,7 +402,7 @@ pub(crate) enum PrimitiveBatch<'a> { · 10 unmodified lines | |||
| 351 | pub struct Quad { | 402 | pub struct Quad { |
| 352 | pub order: u32, // Initially a LayerId, then a DrawOrder. | 403 | pub order: u32, // Initially a LayerId, then a DrawOrder. |
| 353 | pub bounds: Bounds<ScaledPixels>, | 404 | pub bounds: Bounds<ScaledPixels>, |
| 354 | pub content_mask: ScaledContentMask, | 405 | pub content_mask: ContentMask<ScaledPixels>, |
| 355 | pub background: Hsla, | 406 | pub background: Hsla, |
| 356 | pub border_color: Hsla, | 407 | pub border_color: Hsla, |
| 357 | pub corner_radii: Corners<ScaledPixels>, | 408 | pub corner_radii: Corners<ScaledPixels>, |
| @@ -381,7 +432,7 @@ impl From<Quad> for Primitive { · 23 unmodified lines | |||
| 381 | pub struct Underline { | 432 | pub struct Underline { |
| 382 | pub order: u32, | 433 | pub order: u32, |
| 383 | pub bounds: Bounds<ScaledPixels>, | 434 | pub bounds: Bounds<ScaledPixels>, |
| 384 | pub content_mask: ScaledContentMask, | 435 | pub content_mask: ContentMask<ScaledPixels>, |
| 385 | pub thickness: ScaledPixels, | 436 | pub thickness: ScaledPixels, |
| 386 | pub color: Hsla, | 437 | pub color: Hsla, |
| 387 | pub wavy: bool, | 438 | pub wavy: bool, |
| @@ -411,7 +462,7 @@ pub struct Shadow { · 23 unmodified lines | |||
| 411 | pub order: u32, | 462 | pub order: u32, |
| 412 | pub bounds: Bounds<ScaledPixels>, | 463 | pub bounds: Bounds<ScaledPixels>, |
| 413 | pub corner_radii: Corners<ScaledPixels>, | 464 | pub corner_radii: Corners<ScaledPixels>, |
| 414 | pub content_mask: ScaledContentMask, | 465 | pub content_mask: ContentMask<ScaledPixels>, |
| 415 | pub color: Hsla, | 466 | pub color: Hsla, |
| 416 | pub blur_radius: ScaledPixels, | 467 | pub blur_radius: ScaledPixels, |
| 417 | } | 468 | } |
| @@ -439,7 +490,7 @@ impl From<Shadow> for Primitive { · 21 unmodified lines | |||
| 439 | pub struct MonochromeSprite { | 490 | pub struct MonochromeSprite { |
| 440 | pub order: u32, | 491 | pub order: u32, |
| 441 | pub bounds: Bounds<ScaledPixels>, | 492 | pub bounds: Bounds<ScaledPixels>, |
| 442 | pub content_mask: ScaledContentMask, | 493 | pub content_mask: ContentMask<ScaledPixels>, |
| 443 | pub color: Hsla, | 494 | pub color: Hsla, |
| 444 | pub tile: AtlasTile, | 495 | pub tile: AtlasTile, |
| 445 | } | 496 | } |
| @@ -470,7 +521,7 @@ impl From<MonochromeSprite> for Primitive { · 24 unmodified lines | |||
| 470 | pub struct PolychromeSprite { | 521 | pub struct PolychromeSprite { |
| 471 | pub order: u32, | 522 | pub order: u32, |
| 472 | pub bounds: Bounds<ScaledPixels>, | 523 | pub bounds: Bounds<ScaledPixels>, |
| 473 | pub content_mask: ScaledContentMask, | 524 | pub content_mask: ContentMask<ScaledPixels>, |
| 474 | pub corner_radii: Corners<ScaledPixels>, | 525 | pub corner_radii: Corners<ScaledPixels>, |
| 475 | pub tile: AtlasTile, | 526 | pub tile: AtlasTile, |
| 476 | pub grayscale: bool, | 527 | pub grayscale: bool, |
| @@ -497,21 +548,24 @@ impl From<PolychromeSprite> for Primitive { · 20 unmodified lines | |||
| 497 | } | 548 | } |
| 498 | } | 549 | } |
| 499 | 550 | ||
| 500 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] | 551 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] |
| 501 | pub struct PathId(u32); | 552 | pub(crate) struct PathId(pub(crate) usize); |
| 502 | 553 | ||
| 503 | pub struct PathBuilder { | 554 | #[derive(Debug)] |
| 504 | bounds: Bounds<Pixels>, | 555 | pub struct Path<P: Clone + Debug> { |
| 505 | vertices: Vec<PathVertex>, | 556 | pub(crate) id: PathId, |
| 506 | start: Option<Point<Pixels>>, | 557 | order: u32, |
| 507 | current: Point<Pixels>, | 558 | pub(crate) bounds: Bounds<P>, |
| 559 | pub(crate) vertices: Vec<PathVertex<P>>, | ||
| 560 | start: Option<Point<P>>, | ||
| 561 | current: Point<P>, | ||
| 508 | } | 562 | } |
| 509 | 563 | ||
| 510 | impl PathBuilder { | 564 | impl Path<Pixels> { |
| 511 | pub fn new() -> Self { | 565 | pub fn new() -> Self { |
| 512 | const NEXT_PATH_ID: AtomicU32 = AtomicU32::new(0); | ||
| 513 | |||
| 514 | Self { | 566 | Self { |
| 567 | id: PathId(0), | ||
| 568 | order: 0, | ||
| 515 | vertices: Vec::new(), | 569 | vertices: Vec::new(), |
| 516 | start: Default::default(), | 570 | start: Default::default(), |
| 517 | current: Default::default(), | 571 | current: Default::default(), |
| @@ -519,6 +573,21 @@ impl PathBuilder { · 1 unmodified line | |||
| 519 | } | 573 | } |
| 520 | } | 574 | } |
| 521 | 575 | ||
| 576 | pub fn scale(&self, factor: f32) -> Path<ScaledPixels> { | ||
| 577 | Path { | ||
| 578 | id: self.id, | ||
| 579 | order: self.order, | ||
| 580 | bounds: self.bounds.scale(factor), | ||
| 581 | vertices: self | ||
| 582 | .vertices | ||
| 583 | .iter() | ||
| 584 | .map(|vertex| vertex.scale(factor)) | ||
| 585 | .collect(), | ||
| 586 | start: self.start.map(|start| start.scale(factor)), | ||
| 587 | current: self.current.scale(factor), | ||
| 588 | } | ||
| 589 | } | ||
| 590 | |||
| 522 | pub fn line_to(&mut self, to: Point<Pixels>) { | 591 | pub fn line_to(&mut self, to: Point<Pixels>) { |
| 523 | if let Some(start) = self.start { | 592 | if let Some(start) = self.start { |
| 524 | self.push_triangle( | 593 | self.push_triangle( |
| @@ -568,23 +637,63 @@ impl PathBuilder { · 43 unmodified lines | |||
| 568 | self.vertices.push(PathVertex { | 637 | self.vertices.push(PathVertex { |
| 569 | xy_position: xy.0, | 638 | xy_position: xy.0, |
| 570 | st_position: st.0, | 639 | st_position: st.0, |
| 640 | content_mask: Default::default(), | ||
| 571 | }); | 641 | }); |
| 572 | self.vertices.push(PathVertex { | 642 | self.vertices.push(PathVertex { |
| 573 | xy_position: xy.1, | 643 | xy_position: xy.1, |
| 574 | st_position: st.1, | 644 | st_position: st.1, |
| 645 | content_mask: Default::default(), | ||
| 575 | }); | 646 | }); |
| 576 | self.vertices.push(PathVertex { | 647 | self.vertices.push(PathVertex { |
| 577 | xy_position: xy.2, | 648 | xy_position: xy.2, |
| 578 | st_position: st.2, | 649 | st_position: st.2, |
| 650 | content_mask: Default::default(), | ||
| 579 | }); | 651 | }); |
| 580 | } | 652 | } |
| 581 | } | 653 | } |
| 582 | 654 | ||
| 583 | #[derive(Clone, Debug)] | 655 | impl Eq for Path<ScaledPixels> {} |
| 656 | |||
| 657 | impl PartialEq for Path<ScaledPixels> { | ||
| 658 | fn eq(&self, other: &Self) -> bool { | ||
| 659 | self.order == other.order | ||
| 660 | } | ||
| 661 | } | ||
| 662 | |||
| 663 | impl Ord for Path<ScaledPixels> { | ||
| 664 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { | ||
| 665 | self.order.cmp(&other.order) | ||
| 666 | } | ||
| 667 | } | ||
| 668 | |||
| 669 | impl PartialOrd for Path<ScaledPixels> { | ||
| 670 | fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { | ||
| 671 | Some(self.cmp(other)) | ||
| 672 | } | ||
| 673 | } | ||
| 674 | |||
| 675 | impl From<Path<ScaledPixels>> for Primitive { | ||
| 676 | fn from(path: Path<ScaledPixels>) -> Self { | ||
| 677 | Primitive::Path(path) | ||
| 678 | } | ||
| 679 | } | ||
| 680 | |||
| 681 | #[derive(Debug)] | ||
| 584 | #[repr(C)] | 682 | #[repr(C)] |
| 585 | pub struct PathVertex { | 683 | pub struct PathVertex<P: Clone + Debug> { |
| 586 | pub xy_position: Point<Pixels>, | 684 | pub(crate) xy_position: Point<P>, |
| 587 | pub st_position: Point<f32>, | 685 | pub(crate) st_position: Point<f32>, |
| 686 | pub(crate) content_mask: ContentMask<P>, | ||
| 687 | } | ||
| 688 | |||
| 689 | impl PathVertex<Pixels> { | ||
| 690 | pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> { | ||
| 691 | PathVertex { | ||
| 692 | xy_position: self.xy_position.scale(factor), | ||
| 693 | st_position: self.st_position, | ||
| 694 | content_mask: self.content_mask.scale(factor), | ||
| 695 | } | ||
| 696 | } | ||
| 588 | } | 697 | } |
| 589 | 698 | ||
| 590 | #[derive(Copy, Clone, Debug)] | 699 | #[derive(Copy, Clone, Debug)] |
| @@ -619,15 +728,15 @@ mod tests { · 28 unmodified lines | |||
| 619 | 728 | ||
| 620 | #[test] | 729 | #[test] |
| 621 | fn test_scene() { | 730 | fn test_scene() { |
| 622 | let mut scene = Scene::new(1.0); | 731 | let mut scene = SceneBuilder::new(); |
| 623 | assert_eq!(scene.layers.len(), 0); | 732 | assert_eq!(scene.layers_by_order.len(), 0); |
| 624 | 733 | ||
| 625 | scene.insert(smallvec![1], quad()); | 734 | scene.insert(&smallvec![1], quad()); |
| 626 | scene.insert(smallvec![2], shadow()); | 735 | scene.insert(&smallvec![2], shadow()); |
| 627 | scene.insert(smallvec![3], quad()); | 736 | scene.insert(&smallvec![3], quad()); |
| 628 | 737 | ||
| 629 | let mut batches_count = 0; | 738 | let mut batches_count = 0; |
| 630 | for _ in scene.batches() { | 739 | for _ in scene.build().batches() { |
| 631 | batches_count += 1; | 740 | batches_count += 1; |
| 632 | } | 741 | } |
| 633 | assert_eq!(batches_count, 3); | 742 | assert_eq!(batches_count, 3); |
| @@ -1,8 +1,8 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, | 2 | phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, |
| 3 | CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle, | 3 | CornersRefinement, DefiniteLength, Edges, EdgesRefinement, Font, FontFeatures, FontStyle, |
| 4 | FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Quad, Rems, Result, RunStyle, Shadow, | 4 | FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems, Result, RunStyle, SharedString, |
| 5 | SharedString, Size, SizeRefinement, ViewContext, WindowContext, | 5 | Size, SizeRefinement, ViewContext, WindowContext, |
| 6 | }; | 6 | }; |
| 7 | use refineable::Refineable; | 7 | use refineable::Refineable; |
| 8 | use smallvec::SmallVec; | 8 | use smallvec::SmallVec; |
| @@ -243,51 +243,24 @@ impl Style { · 234 unmodified lines | |||
| 243 | /// Paints the background of an element styled with this style. | 243 | /// Paints the background of an element styled with this style. |
| 244 | pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) { | 244 | pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) { |
| 245 | let rem_size = cx.rem_size(); | 245 | let rem_size = cx.rem_size(); |
| 246 | let scale = cx.scale_factor(); | 246 | |
| 247 | 247 | cx.stack(0, |cx| { | |
| 248 | for shadow in &self.box_shadow { | 248 | cx.paint_shadows( |
| 249 | let content_mask = cx.content_mask(); | 249 | bounds, |
| 250 | let mut shadow_bounds = bounds; | 250 | self.corner_radii.to_pixels(bounds.size, rem_size), |
| 251 | shadow_bounds.origin += shadow.offset; | 251 | &self.box_shadow, |
| 252 | shadow_bounds.dilate(shadow.spread_radius); | 252 | ); |
| 253 | cx.stack(0, |cx| { | 253 | }); |
| 254 | let layer_id = cx.current_stacking_order(); | ||
| 255 | cx.scene().insert( | ||
| 256 | layer_id, | ||
| 257 | Shadow { | ||
| 258 | order: 0, | ||
| 259 | bounds: shadow_bounds.scale(scale), | ||
| 260 | content_mask: content_mask.scale(scale), | ||
| 261 | corner_radii: self | ||
| 262 | .corner_radii | ||
| 263 | .to_pixels(shadow_bounds.size, rem_size) | ||
| 264 | .scale(scale), | ||
| 265 | color: shadow.color, | ||
| 266 | blur_radius: shadow.blur_radius.scale(scale), | ||
| 267 | }, | ||
| 268 | ); | ||
| 269 | }) | ||
| 270 | } | ||
| 271 | 254 | ||
| 272 | let background_color = self.fill.as_ref().and_then(Fill::color); | 255 | let background_color = self.fill.as_ref().and_then(Fill::color); |
| 273 | if background_color.is_some() || self.is_border_visible() { | 256 | if background_color.is_some() || self.is_border_visible() { |
| 274 | let content_mask = cx.content_mask(); | ||
| 275 | cx.stack(1, |cx| { | 257 | cx.stack(1, |cx| { |
| 276 | let order = cx.current_stacking_order(); | 258 | cx.paint_quad( |
| 277 | cx.scene().insert( | 259 | bounds, |
| 278 | order, | 260 | self.corner_radii.to_pixels(bounds.size, rem_size), |
| 279 | Quad { | 261 | background_color.unwrap_or_default(), |
| 280 | order: 0, | 262 | self.border_widths.to_pixels(rem_size), |
| 281 | bounds: bounds.scale(scale), | 263 | self.border_color.unwrap_or_default(), |
| 282 | content_mask: content_mask.scale(scale), | ||
| 283 | background: background_color.unwrap_or_default(), | ||
| 284 | border_color: self.border_color.unwrap_or_default(), | ||
| 285 | corner_radii: self | ||
| 286 | .corner_radii | ||
| 287 | .to_pixels(bounds.size, rem_size) | ||
| 288 | .scale(scale), | ||
| 289 | border_widths: self.border_widths.to_pixels(rem_size).scale(scale), | ||
| 290 | }, | ||
| 291 | ); | 264 | ); |
| 292 | }); | 265 | }); |
| 293 | } | 266 | } |
| @@ -1,15 +1,17 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext, | 2 | image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext, |
| 3 | AvailableSpace, BorrowAppContext, Bounds, Context, Corners, DevicePixels, DisplayId, Effect, | 3 | AvailableSpace, BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, |
| 4 | Element, EntityId, FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread, | 4 | Edges, Effect, Element, EntityId, FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, |
| 5 | MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, | 5 | MainThread, MainThreadOnly, MonochromeSprite, Path, Pixels, PlatformAtlas, PlatformWindow, |
| 6 | PolychromeSprite, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, | 6 | Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, |
| 7 | SharedString, Size, StackingOrder, Style, TaffyLayoutEngine, Task, Underline, UnderlineStyle, | 7 | SceneBuilder, Shadow, SharedString, Size, StackingOrder, Style, TaffyLayoutEngine, Task, |
| 8 | WeakHandle, WindowOptions, SUBPIXEL_VARIANTS, | 8 | Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS, |
| 9 | }; | 9 | }; |
| 10 | use anyhow::Result; | 10 | use anyhow::Result; |
| 11 | use smallvec::SmallVec; | 11 | use smallvec::SmallVec; |
| 12 | use std::{any::TypeId, borrow::Cow, future::Future, marker::PhantomData, mem, sync::Arc}; | 12 | use std::{ |
| 13 | any::TypeId, borrow::Cow, fmt::Debug, future::Future, marker::PhantomData, mem, sync::Arc, | ||
| 14 | }; | ||
| 13 | use util::ResultExt; | 15 | use util::ResultExt; |
| 14 | 16 | ||
| 15 | pub struct AnyWindow {} | 17 | pub struct AnyWindow {} |
| @@ -25,8 +27,9 @@ pub struct Window { · 9 unmodified lines | |||
| 25 | pub(crate) root_view: Option<AnyView<()>>, | 27 | pub(crate) root_view: Option<AnyView<()>>, |
| 26 | mouse_position: Point<Pixels>, | 28 | mouse_position: Point<Pixels>, |
| 27 | current_stacking_order: StackingOrder, | 29 | current_stacking_order: StackingOrder, |
| 28 | content_mask_stack: Vec<ContentMask>, | 30 | content_mask_stack: Vec<ContentMask<Pixels>>, |
| 29 | pub(crate) scene: Scene, | 31 | scale_factor: f32, |
| 32 | pub(crate) scene_builder: SceneBuilder, | ||
| 30 | pub(crate) dirty: bool, | 33 | pub(crate) dirty: bool, |
| 31 | } | 34 | } |
| 32 | 35 | ||
| @@ -47,7 +50,8 @@ impl Window { · 14 unmodified lines | |||
| 47 | let cx = cx.to_async(); | 50 | let cx = cx.to_async(); |
| 48 | move |content_size, scale_factor| { | 51 | move |content_size, scale_factor| { |
| 49 | cx.update_window(handle, |cx| { | 52 | cx.update_window(handle, |cx| { |
| 50 | cx.window.scene = Scene::new(scale_factor); | 53 | cx.window.scale_factor = scale_factor; |
| 54 | cx.window.scene_builder = SceneBuilder::new(); | ||
| 51 | cx.window.content_size = content_size; | 55 | cx.window.content_size = content_size; |
| 52 | cx.window.display_id = cx | 56 | cx.window.display_id = cx |
| 53 | .window | 57 | .window |
| @@ -75,20 +79,22 @@ impl Window { · 21 unmodified lines | |||
| 75 | mouse_position, | 79 | mouse_position, |
| 76 | current_stacking_order: SmallVec::new(), | 80 | current_stacking_order: SmallVec::new(), |
| 77 | content_mask_stack: Vec::new(), | 81 | content_mask_stack: Vec::new(), |
| 78 | scene: Scene::new(scale_factor), | 82 | scale_factor, |
| 83 | scene_builder: SceneBuilder::new(), | ||
| 79 | dirty: true, | 84 | dirty: true, |
| 80 | } | 85 | } |
| 81 | } | 86 | } |
| 82 | } | 87 | } |
| 83 | 88 | ||
| 84 | #[derive(Clone, Debug)] | 89 | #[derive(Clone, Debug, Default, PartialEq, Eq)] |
| 85 | pub struct ContentMask { | 90 | #[repr(C)] |
| 86 | pub bounds: Bounds<Pixels>, | 91 | pub struct ContentMask<P: Clone + Debug> { |
| 92 | pub bounds: Bounds<P>, | ||
| 87 | } | 93 | } |
| 88 | 94 | ||
| 89 | impl ContentMask { | 95 | impl ContentMask<Pixels> { |
| 90 | pub fn scale(&self, factor: f32) -> ScaledContentMask { | 96 | pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> { |
| 91 | ScaledContentMask { | 97 | ContentMask { |
| 92 | bounds: self.bounds.scale(factor), | 98 | bounds: self.bounds.scale(factor), |
| 93 | } | 99 | } |
| 94 | } | 100 | } |
| @@ -99,12 +105,6 @@ impl ContentMask { · 4 unmodified lines | |||
| 99 | } | 105 | } |
| 100 | } | 106 | } |
| 101 | 107 | ||
| 102 | #[derive(Default, Clone, Debug, PartialEq, Eq)] | ||
| 103 | #[repr(C)] | ||
| 104 | pub struct ScaledContentMask { | ||
| 105 | bounds: Bounds<ScaledPixels>, | ||
| 106 | } | ||
| 107 | |||
| 108 | pub struct WindowContext<'a, 'w> { | 108 | pub struct WindowContext<'a, 'w> { |
| 109 | app: Reference<'a, AppContext>, | 109 | app: Reference<'a, AppContext>, |
| 110 | window: Reference<'w, Window>, | 110 | window: Reference<'w, Window>, |
| @@ -234,7 +234,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 123 unmodified lines | |||
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | pub fn scale_factor(&self) -> f32 { | 236 | pub fn scale_factor(&self) -> f32 { |
| 237 | self.window.scene.scale_factor | 237 | self.window.scale_factor |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | pub fn rem_size(&self) -> Pixels { | 240 | pub fn rem_size(&self) -> Pixels { |
| @@ -245,10 +245,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 4 unmodified lines | |||
| 245 | self.window.mouse_position | 245 | self.window.mouse_position |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | pub fn scene(&mut self) -> &mut Scene { | ||
| 249 | &mut self.window.scene | ||
| 250 | } | ||
| 251 | |||
| 252 | pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R { | 248 | pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R { |
| 253 | self.window.current_stacking_order.push(order); | 249 | self.window.current_stacking_order.push(order); |
| 254 | let result = f(self); | 250 | let result = f(self); |
| @@ -256,8 +252,69 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 1 unmodified line | |||
| 256 | result | 252 | result |
| 257 | } | 253 | } |
| 258 | 254 | ||
| 259 | pub fn current_stacking_order(&self) -> StackingOrder { | 255 | pub fn paint_shadows( |
| 260 | self.window.current_stacking_order.clone() | 256 | &mut self, |
| 257 | bounds: Bounds<Pixels>, | ||
| 258 | corner_radii: Corners<Pixels>, | ||
| 259 | shadows: &[BoxShadow], | ||
| 260 | ) { | ||
| 261 | let scale_factor = self.scale_factor(); | ||
| 262 | let content_mask = self.content_mask(); | ||
| 263 | let window = &mut *self.window; | ||
| 264 | for shadow in shadows { | ||
| 265 | let mut shadow_bounds = bounds; | ||
| 266 | shadow_bounds.origin += shadow.offset; | ||
| 267 | shadow_bounds.dilate(shadow.spread_radius); | ||
| 268 | window.scene_builder.insert( | ||
| 269 | &window.current_stacking_order, | ||
| 270 | Shadow { | ||
| 271 | order: 0, | ||
| 272 | bounds: shadow_bounds.scale(scale_factor), | ||
| 273 | content_mask: content_mask.scale(scale_factor), | ||
| 274 | corner_radii: corner_radii.scale(scale_factor), | ||
| 275 | color: shadow.color, | ||
| 276 | blur_radius: shadow.blur_radius.scale(scale_factor), | ||
| 277 | }, | ||
| 278 | ); | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | pub fn paint_quad( | ||
| 283 | &mut self, | ||
| 284 | bounds: Bounds<Pixels>, | ||
| 285 | corner_radii: Corners<Pixels>, | ||
| 286 | background: impl Into<Hsla>, | ||
| 287 | border_widths: Edges<Pixels>, | ||
| 288 | border_color: impl Into<Hsla>, | ||
| 289 | ) { | ||
| 290 | let scale_factor = self.scale_factor(); | ||
| 291 | let content_mask = self.content_mask(); | ||
| 292 | |||
| 293 | let window = &mut *self.window; | ||
| 294 | window.scene_builder.insert( | ||
| 295 | &window.current_stacking_order, | ||
| 296 | Quad { | ||
| 297 | order: 0, | ||
| 298 | bounds: bounds.scale(scale_factor), | ||
| 299 | content_mask: content_mask.scale(scale_factor), | ||
| 300 | background: background.into(), | ||
| 301 | border_color: border_color.into(), | ||
| 302 | corner_radii: corner_radii.scale(scale_factor), | ||
| 303 | border_widths: border_widths.scale(scale_factor), | ||
| 304 | }, | ||
| 305 | ); | ||
| 306 | } | ||
| 307 | |||
| 308 | pub fn paint_path(&mut self, mut path: Path<Pixels>) { | ||
| 309 | let scale_factor = self.scale_factor(); | ||
| 310 | let content_mask = self.content_mask(); | ||
| 311 | for vertex in &mut path.vertices { | ||
| 312 | vertex.content_mask = content_mask.clone(); | ||
| 313 | } | ||
| 314 | let window = &mut *self.window; | ||
| 315 | window | ||
| 316 | .scene_builder | ||
| 317 | .insert(&window.current_stacking_order, path.scale(scale_factor)); | ||
| 261 | } | 318 | } |
| 262 | 319 | ||
| 263 | pub fn paint_underline( | 320 | pub fn paint_underline( |
| @@ -277,9 +334,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 13 unmodified lines | |||
| 277 | size: size(width, height), | 334 | size: size(width, height), |
| 278 | }; | 335 | }; |
| 279 | let content_mask = self.content_mask(); | 336 | let content_mask = self.content_mask(); |
| 280 | let layer_id = self.current_stacking_order(); | 337 | let window = &mut *self.window; |
| 281 | self.window.scene.insert( | 338 | window.scene_builder.insert( |
| 282 | layer_id, | 339 | &window.current_stacking_order, |
| 283 | Underline { | 340 | Underline { |
| 284 | order: 0, | 341 | order: 0, |
| 285 | bounds: bounds.scale(scale_factor), | 342 | bounds: bounds.scale(scale_factor), |
| @@ -317,7 +374,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 31 unmodified lines | |||
| 317 | 374 | ||
| 318 | let raster_bounds = self.text_system().raster_bounds(¶ms)?; | 375 | let raster_bounds = self.text_system().raster_bounds(¶ms)?; |
| 319 | if !raster_bounds.is_zero() { | 376 | if !raster_bounds.is_zero() { |
| 320 | let layer_id = self.current_stacking_order(); | ||
| 321 | let tile = | 377 | let tile = |
| 322 | self.window | 378 | self.window |
| 323 | .sprite_atlas | 379 | .sprite_atlas |
| @@ -330,9 +386,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 6 unmodified lines | |||
| 330 | size: tile.bounds.size.map(Into::into), | 386 | size: tile.bounds.size.map(Into::into), |
| 331 | }; | 387 | }; |
| 332 | let content_mask = self.content_mask().scale(scale_factor); | 388 | let content_mask = self.content_mask().scale(scale_factor); |
| 333 | 389 | let window = &mut *self.window; | |
| 334 | self.window.scene.insert( | 390 | window.scene_builder.insert( |
| 335 | layer_id, | 391 | &window.current_stacking_order, |
| 336 | MonochromeSprite { | 392 | MonochromeSprite { |
| 337 | order: 0, | 393 | order: 0, |
| 338 | bounds, | 394 | bounds, |
| @@ -366,7 +422,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 27 unmodified lines | |||
| 366 | 422 | ||
| 367 | let raster_bounds = self.text_system().raster_bounds(¶ms)?; | 423 | let raster_bounds = self.text_system().raster_bounds(¶ms)?; |
| 368 | if !raster_bounds.is_zero() { | 424 | if !raster_bounds.is_zero() { |
| 369 | let layer_id = self.current_stacking_order(); | ||
| 370 | let tile = | 425 | let tile = |
| 371 | self.window | 426 | self.window |
| 372 | .sprite_atlas | 427 | .sprite_atlas |
| @@ -379,9 +434,10 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 6 unmodified lines | |||
| 379 | size: tile.bounds.size.map(Into::into), | 434 | size: tile.bounds.size.map(Into::into), |
| 380 | }; | 435 | }; |
| 381 | let content_mask = self.content_mask().scale(scale_factor); | 436 | let content_mask = self.content_mask().scale(scale_factor); |
| 437 | let window = &mut *self.window; | ||
| 382 | 438 | ||
| 383 | self.window.scene.insert( | 439 | window.scene_builder.insert( |
| 384 | layer_id, | 440 | &window.current_stacking_order, |
| 385 | PolychromeSprite { | 441 | PolychromeSprite { |
| 386 | order: 0, | 442 | order: 0, |
| 387 | bounds, | 443 | bounds, |
| @@ -411,7 +467,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 23 unmodified lines | |||
| 411 | .map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)), | 467 | .map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)), |
| 412 | }; | 468 | }; |
| 413 | 469 | ||
| 414 | let layer_id = self.current_stacking_order(); | ||
| 415 | let tile = | 470 | let tile = |
| 416 | self.window | 471 | self.window |
| 417 | .sprite_atlas | 472 | .sprite_atlas |
| @@ -421,8 +476,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 3 unmodified lines | |||
| 421 | })?; | 476 | })?; |
| 422 | let content_mask = self.content_mask().scale(scale_factor); | 477 | let content_mask = self.content_mask().scale(scale_factor); |
| 423 | 478 | ||
| 424 | self.window.scene.insert( | 479 | let window = &mut *self.window; |
| 425 | layer_id, | 480 | window.scene_builder.insert( |
| 481 | &window.current_stacking_order, | ||
| 426 | MonochromeSprite { | 482 | MonochromeSprite { |
| 427 | order: 0, | 483 | order: 0, |
| 428 | bounds, | 484 | bounds, |
| @@ -446,7 +502,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 17 unmodified lines | |||
| 446 | let bounds = bounds.scale(scale_factor); | 502 | let bounds = bounds.scale(scale_factor); |
| 447 | let params = RenderImageParams { image_id: data.id }; | 503 | let params = RenderImageParams { image_id: data.id }; |
| 448 | 504 | ||
| 449 | let order = self.current_stacking_order(); | ||
| 450 | let tile = self | 505 | let tile = self |
| 451 | .window | 506 | .window |
| 452 | .sprite_atlas | 507 | .sprite_atlas |
| @@ -456,8 +511,9 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 3 unmodified lines | |||
| 456 | let content_mask = self.content_mask().scale(scale_factor); | 511 | let content_mask = self.content_mask().scale(scale_factor); |
| 457 | let corner_radii = corner_radii.scale(scale_factor); | 512 | let corner_radii = corner_radii.scale(scale_factor); |
| 458 | 513 | ||
| 459 | self.window.scene.insert( | 514 | let window = &mut *self.window; |
| 460 | order, | 515 | window.scene_builder.insert( |
| 516 | &window.current_stacking_order, | ||
| 461 | PolychromeSprite { | 517 | PolychromeSprite { |
| 462 | order: 0, | 518 | order: 0, |
| 463 | bounds, | 519 | bounds, |
| @@ -467,7 +523,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 3 unmodified lines | |||
| 467 | grayscale, | 523 | grayscale, |
| 468 | }, | 524 | }, |
| 469 | ); | 525 | ); |
| 470 | |||
| 471 | Ok(()) | 526 | Ok(()) |
| 472 | } | 527 | } |
| 473 | 528 | ||
| @@ -485,7 +540,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 11 unmodified lines | |||
| 485 | 540 | ||
| 486 | root_view.paint(layout, &mut (), &mut frame_state, cx)?; | 541 | root_view.paint(layout, &mut (), &mut frame_state, cx)?; |
| 487 | cx.window.root_view = Some(root_view); | 542 | cx.window.root_view = Some(root_view); |
| 488 | let scene = cx.window.scene.take(); | 543 | let scene = cx.window.scene_builder.build(); |
| 489 | 544 | ||
| 490 | cx.run_on_main(view, |_, cx| { | 545 | cx.run_on_main(view, |_, cx| { |
| 491 | cx.window | 546 | cx.window |
| @@ -557,7 +612,11 @@ pub trait BorrowWindow: BorrowAppContext { · 65 unmodified lines | |||
| 557 | fn window(&self) -> &Window; | 612 | fn window(&self) -> &Window; |
| 558 | fn window_mut(&mut self) -> &mut Window; | 613 | fn window_mut(&mut self) -> &mut Window; |
| 559 | 614 | ||
| 560 | fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R { | 615 | fn with_content_mask<R>( |
| 616 | &mut self, | ||
| 617 | mask: ContentMask<Pixels>, | ||
| 618 | f: impl FnOnce(&mut Self) -> R, | ||
| 619 | ) -> R { | ||
| 561 | let mask = mask.intersect(&self.content_mask()); | 620 | let mask = mask.intersect(&self.content_mask()); |
| 562 | self.window_mut().content_mask_stack.push(mask); | 621 | self.window_mut().content_mask_stack.push(mask); |
| 563 | let result = f(self); | 622 | let result = f(self); |
| @@ -565,7 +624,7 @@ pub trait BorrowWindow: BorrowAppContext { · 1 unmodified line | |||
| 565 | result | 624 | result |
| 566 | } | 625 | } |
| 567 | 626 | ||
| 568 | fn content_mask(&self) -> ContentMask { | 627 | fn content_mask(&self) -> ContentMask<Pixels> { |
| 569 | self.window() | 628 | self.window() |
| 570 | .content_mask_stack | 629 | .content_mask_stack |
| 571 | .last() | 630 | .last() |