History

Checkpoint

Antonio Scandurra committed 3 years ago

Commit d889cde1 parent 6a4c2a08 files · +463 −258Browse files

Unified · Split

8 files
  1. crates/gpui3/build.rs +1 −1
  2. crates/gpui3/src/platform.rs +25 −7
  3. crates/gpui3/src/platform/mac/metal_atlas.rs +75 −43
  4. crates/gpui3/src/platform/mac/metal_renderer.rs +20 −6
  5. crates/gpui3/src/platform/mac/window.rs +3 −3
  6. crates/gpui3/src/scene.rs +214 −105
  7. crates/gpui3/src/style.rs +16 −43
  8. crates/gpui3/src/window.rs +109 −50
crates/gpui3/build.rs+1−1
@@ -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(),
crates/gpui3/src/platform.rs+25−7
@@ -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
43pub trait Platform: 'static {43pub(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
114unsafe impl Send for DisplayId {}114unsafe impl Send for DisplayId {}
115 115
116pub trait PlatformWindow {116pub(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
196impl AtlasKey {196impl 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)]
244pub(crate) struct AtlasTextureId(pub(crate) u32); // We use u32 instead of usize for Metal Shader Language compatibility250pub(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)]
258pub(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)]
crates/gpui3/src/platform/mac/metal_atlas.rs+75−43
@@ -1,14 +1,14 @@
1use std::borrow::Cow;
2
3use crate::{1use crate::{
4 AtlasKey, AtlasTextureId, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size,2 AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas,
3 Point, Size,
5};4};
6use anyhow::{anyhow, Result};5use anyhow::Result;
7use collections::HashMap;6use collections::HashMap;
8use derive_more::{Deref, DerefMut};7use derive_more::{Deref, DerefMut};
9use etagere::BucketedAtlasAllocator;8use etagere::BucketedAtlasAllocator;
10use metal::Device;9use metal::Device;
11use parking_lot::Mutex;10use parking_lot::Mutex;
11use std::borrow::Cow;
12 12
13pub struct MetalAtlas(Mutex<MetalAtlasState>);13pub 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
29struct MetalAtlasState {39struct 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 = lock58 let tile = lock.allocate(size, key.texture_kind());
47 .textures59 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
72impl MetalAtlasState {70impl 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
112impl MetalAtlasTexture {142impl 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 {
crates/gpui3/src/platform/mac/metal_renderer.rs+20−6
@@ -1,12 +1,14 @@
1use crate::{1use 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};
5use cocoa::{6use cocoa::{
6 base::{NO, YES},7 base::{NO, YES},
7 foundation::NSUInteger,8 foundation::NSUInteger,
8 quartzcore::AutoresizingMask,9 quartzcore::AutoresizingMask,
9};10};
11use collections::HashMap;
10use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange};12use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange};
11use objc::{self, msg_send, sel, sel_impl};13use objc::{self, msg_send, sel, sel_impl};
12use std::{ffi::c_void, mem, ptr, sync::Arc};14use std::{ffi::c_void, mem, ptr, sync::Arc};
@@ -14,7 +16,7 @@ use std::{ffi::c_void, mem, ptr, sync::Arc}; · 1 unmodified line
14const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));16const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
15const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value.17const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value.
16 18
17pub struct MetalRenderer {19pub(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_atlas152 &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),
crates/gpui3/src/platform/mac/window.rs+3−3
@@ -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}
crates/gpui3/src/scene.rs+214−105
@@ -1,16 +1,12 @@
1use crate::{1use 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};
5use collections::BTreeMap;5use collections::BTreeMap;
6use etagere::euclid::{Point3D, Vector3D};6use etagere::euclid::{Point3D, Vector3D};
7use plane_split::{BspSplitter, Polygon as BspPolygon};7use plane_split::{BspSplitter, Polygon as BspPolygon};
8use smallvec::SmallVec;8use smallvec::SmallVec;
9use std::{9use 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 metal11// Exported to metal
16pub type PointF = Point<f32>;12pub type PointF = Point<f32>;
@@ -18,94 +14,57 @@ pub type StackingOrder = SmallVec<[u32; 16]>; · 1 unmodified line
18pub type LayerId = u32;14pub type LayerId = u32;
19pub type DrawOrder = u32;15pub type DrawOrder = u32;
20 16
21#[derive(Debug)]17pub(crate) struct SceneBuilder {
22pub 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
32impl Scene {28impl 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 order50 // 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 underline68 underline
110 .bounds69 .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_sprite77 monochrome_sprite
119 .bounds78 .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_sprite86 polychrome_sprite
128 .bounds87 .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 DrawOrder105 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
173pub(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
182impl 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
178struct BatchIterator<'a> {211struct 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)]
326pub enum Primitive {375pub 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
335pub(crate) enum PrimitiveBatch<'a> {385pub(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
351pub struct Quad {402pub 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
381pub struct Underline {432pub 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
439pub struct MonochromeSprite {490pub 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
470pub struct PolychromeSprite {521pub 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)]
501pub struct PathId(u32);552pub(crate) struct PathId(pub(crate) usize);
502 553
503pub struct PathBuilder {554#[derive(Debug)]
504 bounds: Bounds<Pixels>,555pub 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
510impl PathBuilder {564impl 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)]655impl Eq for Path<ScaledPixels> {}
656
657impl PartialEq for Path<ScaledPixels> {
658 fn eq(&self, other: &Self) -> bool {
659 self.order == other.order
660 }
661}
662
663impl Ord for Path<ScaledPixels> {
664 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
665 self.order.cmp(&other.order)
666 }
667}
668
669impl PartialOrd for Path<ScaledPixels> {
670 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
671 Some(self.cmp(other))
672 }
673}
674
675impl 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)]
585pub struct PathVertex {683pub 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
689impl 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);
crates/gpui3/src/style.rs+16−43
@@ -1,8 +1,8 @@
1use crate::{1use 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};
7use refineable::Refineable;7use refineable::Refineable;
8use smallvec::SmallVec;8use 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 }
crates/gpui3/src/window.rs+109−50
@@ -1,15 +1,17 @@
1use crate::{1use 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};
10use anyhow::Result;10use anyhow::Result;
11use smallvec::SmallVec;11use smallvec::SmallVec;
12use std::{any::TypeId, borrow::Cow, future::Future, marker::PhantomData, mem, sync::Arc};12use std::{
13 any::TypeId, borrow::Cow, fmt::Debug, future::Future, marker::PhantomData, mem, sync::Arc,
14};
13use util::ResultExt;15use util::ResultExt;
14 16
15pub struct AnyWindow {}17pub 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 = cx56 cx.window.display_id = cx
53 .window57 .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)]
85pub struct ContentMask {90#[repr(C)]
86 pub bounds: Bounds<Pixels>,91pub struct ContentMask<P: Clone + Debug> {
92 pub bounds: Bounds<P>,
87}93}
88 94
89impl ContentMask {95impl 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)]
104pub struct ScaledContentMask {
105 bounds: Bounds<ScaledPixels>,
106}
107
108pub struct WindowContext<'a, 'w> {108pub 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_factor237 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_position245 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 result252 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(&params)?;375 let raster_bounds = self.text_system().raster_bounds(&params)?;
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.window378 self.window
323 .sprite_atlas379 .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(&params)?;423 let raster_bounds = self.text_system().raster_bounds(&params)?;
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.window426 self.window
372 .sprite_atlas427 .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.window471 self.window
417 .sprite_atlas472 .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 = self505 let tile = self
451 .window506 .window
452 .sprite_atlas507 .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.window546 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 result624 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_stack629 .content_mask_stack
571 .last()630 .last()

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t