From b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 3 Apr 2024 21:07:54 +0200 Subject: Redesign `iced_wgpu` layering architecture --- wgpu/src/layer.rs | 617 ++++++++++++++++++++++++++---------------------------- 1 file changed, 300 insertions(+), 317 deletions(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index cc767c25..5c23669a 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -1,343 +1,326 @@ -//! Organize rendering primitives into a flattened list of layers. -mod image; -mod pipeline; -mod text; - -pub mod mesh; - -pub use image::Image; -pub use mesh::Mesh; -pub use pipeline::Pipeline; -pub use text::Text; - -use crate::core; -use crate::core::alignment; -use crate::core::{ - Color, Font, Pixels, Point, Rectangle, Size, Transformation, Vector, -}; -use crate::graphics; +use crate::core::renderer; +use crate::core::{Background, Color, Point, Rectangle, Transformation}; use crate::graphics::color; -use crate::graphics::Viewport; -use crate::primitive::{self, Primitive}; +use crate::graphics::text::{Editor, Paragraph}; +use crate::graphics::Mesh; +use crate::image::{self, Image}; use crate::quad::{self, Quad}; +use crate::text::{self, Text}; +use crate::triangle; -/// A group of primitives that should be clipped together. -#[derive(Debug)] -pub struct Layer<'a> { - /// The clipping bounds of the [`Layer`]. - pub bounds: Rectangle, +use std::cell::{self, RefCell}; +use std::rc::Rc; - /// The quads of the [`Layer`]. - pub quads: quad::Batch, - - /// The triangle meshes of the [`Layer`]. - pub meshes: Vec>, - - /// The text of the [`Layer`]. - pub text: Vec>, +pub enum Layer<'a> { + Live(&'a Live), + Cached(cell::Ref<'a, Cached>), +} - /// The images of the [`Layer`]. - pub images: Vec, +pub enum LayerMut<'a> { + Live(&'a mut Live), + Cached(cell::RefMut<'a, Cached>), +} - /// The custom pipelines of this [`Layer`]. - pub pipelines: Vec, +pub struct Stack { + live: Vec, + cached: Vec>>, + order: Vec, + transformations: Vec, + previous: Vec, + current: usize, + live_count: usize, } -impl<'a> Layer<'a> { - /// Creates a new [`Layer`] with the given clipping bounds. - pub fn new(bounds: Rectangle) -> Self { +impl Stack { + pub fn new() -> Self { Self { - bounds, - quads: quad::Batch::default(), - meshes: Vec::new(), - text: Vec::new(), - images: Vec::new(), - pipelines: Vec::new(), + live: vec![Live::default()], + cached: Vec::new(), + order: vec![Kind::Live], + transformations: vec![Transformation::IDENTITY], + previous: Vec::new(), + current: 0, + live_count: 1, } } - /// Creates a new [`Layer`] for the provided overlay text. - /// - /// This can be useful for displaying debug information. - pub fn overlay(lines: &'a [impl AsRef], viewport: &Viewport) -> Self { - let mut overlay = - Layer::new(Rectangle::with_size(viewport.logical_size())); - - for (i, line) in lines.iter().enumerate() { - let text = text::Cached { - content: line.as_ref(), - bounds: Rectangle::new( - Point::new(11.0, 11.0 + 25.0 * i as f32), - Size::INFINITY, - ), - color: Color::new(0.9, 0.9, 0.9, 1.0), - size: Pixels(20.0), - line_height: core::text::LineHeight::default(), - font: Font::MONOSPACE, - horizontal_alignment: alignment::Horizontal::Left, - vertical_alignment: alignment::Vertical::Top, - shaping: core::text::Shaping::Basic, - clip_bounds: Rectangle::with_size(Size::INFINITY), - }; - - overlay.text.push(Text::Cached(text.clone())); - - overlay.text.push(Text::Cached(text::Cached { - bounds: text.bounds + Vector::new(-1.0, -1.0), - color: Color::BLACK, - ..text - })); - } + pub fn draw_quad(&mut self, quad: renderer::Quad, background: Background) { + let transformation = self.transformations.last().unwrap(); + let bounds = quad.bounds * *transformation; + + let quad = Quad { + position: [bounds.x, bounds.y], + size: [bounds.width, bounds.height], + border_color: color::pack(quad.border.color), + border_radius: quad.border.radius.into(), + border_width: quad.border.width, + shadow_color: color::pack(quad.shadow.color), + shadow_offset: quad.shadow.offset.into(), + shadow_blur_radius: quad.shadow.blur_radius, + }; + + self.live[self.current].quads.add(quad, &background); + } - overlay + pub fn draw_paragraph( + &mut self, + paragraph: &Paragraph, + position: Point, + color: Color, + clip_bounds: Rectangle, + ) { + let paragraph = Text::Paragraph { + paragraph: paragraph.downgrade(), + position, + color, + clip_bounds, + transformation: self.transformations.last().copied().unwrap(), + }; + + self.live[self.current].text.push(paragraph); } - /// Distributes the given [`Primitive`] and generates a list of layers based - /// on its contents. - pub fn generate( - primitives: &'a [Primitive], - viewport: &Viewport, - ) -> Vec { - let first_layer = - Layer::new(Rectangle::with_size(viewport.logical_size())); - - let mut layers = vec![first_layer]; - - for primitive in primitives { - Self::process_primitive( - &mut layers, - Transformation::IDENTITY, - primitive, - 0, - ); - } + pub fn draw_editor( + &mut self, + editor: &Editor, + position: Point, + color: Color, + clip_bounds: Rectangle, + ) { + let paragraph = Text::Editor { + editor: editor.downgrade(), + position, + color, + clip_bounds, + transformation: self.transformations.last().copied().unwrap(), + }; + + self.live[self.current].text.push(paragraph); + } - layers + pub fn draw_text( + &mut self, + text: crate::core::Text, + position: Point, + color: Color, + clip_bounds: Rectangle, + ) { + let transformation = self.transformation(); + + let paragraph = Text::Cached { + content: text.content, + bounds: Rectangle::new(position, text.bounds) * transformation, + color, + size: text.size * transformation.scale_factor(), + line_height: text.line_height, + font: text.font, + horizontal_alignment: text.horizontal_alignment, + vertical_alignment: text.vertical_alignment, + shaping: text.shaping, + clip_bounds: clip_bounds * transformation, + }; + + self.live[self.current].text.push(paragraph); } - fn process_primitive( - layers: &mut Vec, - transformation: Transformation, - primitive: &'a Primitive, - current_layer: usize, + pub fn draw_image( + &mut self, + handle: crate::core::image::Handle, + filter_method: crate::core::image::FilterMethod, + bounds: Rectangle, ) { - match primitive { - Primitive::Paragraph { - paragraph, - position, - color, - clip_bounds, - } => { - let layer = &mut layers[current_layer]; - - layer.text.push(Text::Paragraph { - paragraph: paragraph.clone(), - position: *position, - color: *color, - clip_bounds: *clip_bounds, - transformation, - }); - } - Primitive::Editor { - editor, - position, - color, - clip_bounds, - } => { - let layer = &mut layers[current_layer]; - - layer.text.push(Text::Editor { - editor: editor.clone(), - position: *position, - color: *color, - clip_bounds: *clip_bounds, - transformation, - }); - } - Primitive::Text { - content, - bounds, - size, - line_height, - color, - font, - horizontal_alignment, - vertical_alignment, - shaping, - clip_bounds, - } => { - let layer = &mut layers[current_layer]; - - layer.text.push(Text::Cached(text::Cached { - content, - bounds: *bounds + transformation.translation(), - size: *size * transformation.scale_factor(), - line_height: *line_height, - color: *color, - font: *font, - horizontal_alignment: *horizontal_alignment, - vertical_alignment: *vertical_alignment, - shaping: *shaping, - clip_bounds: *clip_bounds * transformation, - })); - } - graphics::Primitive::RawText(raw) => { - let layer = &mut layers[current_layer]; + let image = Image::Raster { + handle, + filter_method, + bounds: bounds * self.transformation(), + }; - layer.text.push(Text::Raw { - raw: raw.clone(), - transformation, - }); - } - Primitive::Quad { - bounds, - background, - border, - shadow, - } => { - let layer = &mut layers[current_layer]; - let bounds = *bounds * transformation; - - let quad = Quad { - position: [bounds.x, bounds.y], - size: [bounds.width, bounds.height], - border_color: color::pack(border.color), - border_radius: border.radius.into(), - border_width: border.width, - shadow_color: shadow.color.into_linear(), - shadow_offset: shadow.offset.into(), - shadow_blur_radius: shadow.blur_radius, - }; - - layer.quads.add(quad, background); - } - Primitive::Image { - handle, - filter_method, - bounds, - } => { - let layer = &mut layers[current_layer]; - - layer.images.push(Image::Raster { - handle: handle.clone(), - filter_method: *filter_method, - bounds: *bounds * transformation, - }); + self.live[self.current].images.push(image); + } + + pub fn draw_svg( + &mut self, + handle: crate::core::svg::Handle, + color: Option, + bounds: Rectangle, + ) { + let svg = Image::Vector { + handle, + color, + bounds: bounds * self.transformation(), + }; + + self.live[self.current].images.push(svg); + } + + pub fn draw_mesh(&mut self, mut mesh: Mesh) { + match &mut mesh { + Mesh::Solid { transformation, .. } + | Mesh::Gradient { transformation, .. } => { + *transformation = *transformation * self.transformation(); } - Primitive::Svg { - handle, - color, + } + + self.live[self.current].meshes.push(mesh); + } + + pub fn draw_layer(&mut self, mut layer: Live) { + layer.transformation = layer.transformation * self.transformation(); + + if self.live_count == self.live.len() { + self.live.push(layer); + } else { + self.live[self.live_count] = layer; + } + + self.live_count += 1; + self.order.push(Kind::Live); + } + + pub fn draw_cached_layer(&mut self, layer: &Rc>) { + { + let mut layer = layer.borrow_mut(); + layer.transformation = self.transformation() * layer.transformation; + } + + self.cached.push(layer.clone()); + self.order.push(Kind::Cache); + } + + pub fn push_clip(&mut self, bounds: Option) { + self.previous.push(self.current); + self.order.push(Kind::Live); + + self.current = self.live_count; + self.live_count += 1; + + let bounds = bounds.map(|bounds| bounds * self.transformation()); + + if self.current == self.live.len() { + self.live.push(Live { bounds, - } => { - let layer = &mut layers[current_layer]; - - layer.images.push(Image::Vector { - handle: handle.clone(), - color: *color, - bounds: *bounds * transformation, - }); - } - Primitive::Group { primitives } => { - // TODO: Inspect a bit and regroup (?) - for primitive in primitives { - Self::process_primitive( - layers, - transformation, - primitive, - current_layer, - ); - } - } - Primitive::Clip { bounds, content } => { - let layer = &mut layers[current_layer]; - let translated_bounds = *bounds * transformation; - - // Only draw visible content - if let Some(clip_bounds) = - layer.bounds.intersection(&translated_bounds) - { - let clip_layer = Layer::new(clip_bounds); - layers.push(clip_layer); - - Self::process_primitive( - layers, - transformation, - content, - layers.len() - 1, - ); - } - } - Primitive::Transform { - transformation: new_transformation, - content, - } => { - Self::process_primitive( - layers, - transformation * *new_transformation, - content, - current_layer, - ); - } - Primitive::Cache { content } => { - Self::process_primitive( - layers, - transformation, - content, - current_layer, - ); + ..Live::default() + }); + } else { + self.live[self.current].bounds = bounds; + } + } + + pub fn pop_clip(&mut self) { + self.current = self.previous.pop().unwrap(); + } + + pub fn push_transformation(&mut self, transformation: Transformation) { + self.transformations + .push(self.transformation() * transformation); + } + + pub fn pop_transformation(&mut self) { + let _ = self.transformations.pop(); + } + + fn transformation(&self) -> Transformation { + self.transformations.last().copied().unwrap() + } + + pub fn iter_mut(&mut self) -> impl Iterator> { + let mut live = self.live.iter_mut(); + let mut cached = self.cached.iter_mut(); + + self.order.iter().map(move |kind| match kind { + Kind::Live => LayerMut::Live(live.next().unwrap()), + Kind::Cache => { + LayerMut::Cached(cached.next().unwrap().borrow_mut()) } - Primitive::Custom(custom) => match custom { - primitive::Custom::Mesh(mesh) => match mesh { - graphics::Mesh::Solid { buffers, size } => { - let layer = &mut layers[current_layer]; - - let bounds = - Rectangle::with_size(*size) * transformation; - - // Only draw visible content - if let Some(clip_bounds) = - layer.bounds.intersection(&bounds) - { - layer.meshes.push(Mesh::Solid { - transformation, - buffers, - clip_bounds, - }); - } - } - graphics::Mesh::Gradient { buffers, size } => { - let layer = &mut layers[current_layer]; - - let bounds = - Rectangle::with_size(*size) * transformation; - - // Only draw visible content - if let Some(clip_bounds) = - layer.bounds.intersection(&bounds) - { - layer.meshes.push(Mesh::Gradient { - transformation, - buffers, - clip_bounds, - }); - } - } - }, - primitive::Custom::Pipeline(pipeline) => { - let layer = &mut layers[current_layer]; - let bounds = pipeline.bounds * transformation; - - if let Some(clip_bounds) = - layer.bounds.intersection(&bounds) - { - layer.pipelines.push(Pipeline { - bounds, - viewport: clip_bounds, - primitive: pipeline.primitive.clone(), - }); - } - } - }, + }) + } + + pub fn iter(&self) -> impl Iterator> { + let mut live = self.live.iter(); + let mut cached = self.cached.iter(); + + self.order.iter().map(move |kind| match kind { + Kind::Live => Layer::Live(live.next().unwrap()), + Kind::Cache => Layer::Cached(cached.next().unwrap().borrow()), + }) + } + + pub fn clear(&mut self) { + for live in &mut self.live[..self.live_count] { + live.bounds = None; + live.transformation = Transformation::IDENTITY; + + live.quads.clear(); + live.meshes.clear(); + live.text.clear(); + live.images.clear(); } + + self.current = 0; + self.live_count = 1; + + self.order.clear(); + self.order.push(Kind::Live); + + self.cached.clear(); + self.previous.clear(); + } +} + +impl Default for Stack { + fn default() -> Self { + Self::new() } } + +#[derive(Default)] +pub struct Live { + pub bounds: Option, + pub transformation: Transformation, + pub quads: quad::Batch, + pub meshes: triangle::Batch, + pub text: text::Batch, + pub images: image::Batch, +} + +impl Live { + pub fn into_cached(self) -> Cached { + Cached { + bounds: self.bounds, + transformation: self.transformation, + last_transformation: None, + quads: quad::Cache::Staged(self.quads), + meshes: triangle::Cache::Staged(self.meshes), + text: text::Cache::Staged(self.text), + images: self.images, + } + } +} + +#[derive(Default)] +pub struct Cached { + pub bounds: Option, + pub transformation: Transformation, + pub last_transformation: Option, + pub quads: quad::Cache, + pub meshes: triangle::Cache, + pub text: text::Cache, + pub images: image::Batch, +} + +impl Cached { + pub fn update(&mut self, live: Live) { + self.bounds = live.bounds; + self.transformation = live.transformation; + + self.quads.update(live.quads); + self.meshes.update(live.meshes); + self.text.update(live.text); + self.images = live.images; + } +} + +enum Kind { + Live, + Cache, +} -- cgit From 394e599c3a096b036aabdd6f850c4a7c518d44fa Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 5 Apr 2024 00:40:39 +0200 Subject: Fix layer transformations --- wgpu/src/layer.rs | 65 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 5c23669a..1c9638b0 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -13,17 +13,17 @@ use std::rc::Rc; pub enum Layer<'a> { Live(&'a Live), - Cached(cell::Ref<'a, Cached>), + Cached(Transformation, cell::Ref<'a, Cached>), } pub enum LayerMut<'a> { Live(&'a mut Live), - Cached(cell::RefMut<'a, Cached>), + Cached(Transformation, cell::RefMut<'a, Cached>), } pub struct Stack { live: Vec, - cached: Vec>>, + cached: Vec<(Transformation, Rc>)>, order: Vec, transformations: Vec, previous: Vec, @@ -92,7 +92,7 @@ impl Stack { position, color, clip_bounds, - transformation: self.transformations.last().copied().unwrap(), + transformation: self.transformation(), }; self.live[self.current].text.push(paragraph); @@ -178,36 +178,31 @@ impl Stack { } pub fn draw_cached_layer(&mut self, layer: &Rc>) { - { - let mut layer = layer.borrow_mut(); - layer.transformation = self.transformation() * layer.transformation; - } - - self.cached.push(layer.clone()); + self.cached.push((self.transformation(), layer.clone())); self.order.push(Kind::Cache); } pub fn push_clip(&mut self, bounds: Option) { - self.previous.push(self.current); - self.order.push(Kind::Live); - - self.current = self.live_count; - self.live_count += 1; - - let bounds = bounds.map(|bounds| bounds * self.transformation()); - - if self.current == self.live.len() { - self.live.push(Live { - bounds, - ..Live::default() - }); - } else { - self.live[self.current].bounds = bounds; - } + // self.previous.push(self.current); + // self.order.push(Kind::Live); + + // self.current = self.live_count; + // self.live_count += 1; + + // let bounds = bounds.map(|bounds| bounds * self.transformation()); + + // if self.current == self.live.len() { + // self.live.push(Live { + // bounds, + // ..Live::default() + // }); + // } else { + // self.live[self.current].bounds = bounds; + // } } pub fn pop_clip(&mut self) { - self.current = self.previous.pop().unwrap(); + // self.current = self.previous.pop().unwrap(); } pub fn push_transformation(&mut self, transformation: Transformation) { @@ -224,13 +219,17 @@ impl Stack { } pub fn iter_mut(&mut self) -> impl Iterator> { + dbg!(self.order.len()); let mut live = self.live.iter_mut(); let mut cached = self.cached.iter_mut(); self.order.iter().map(move |kind| match kind { Kind::Live => LayerMut::Live(live.next().unwrap()), Kind::Cache => { - LayerMut::Cached(cached.next().unwrap().borrow_mut()) + let (transformation, layer) = cached.next().unwrap(); + let layer = layer.borrow_mut(); + + LayerMut::Cached(*transformation * layer.transformation, layer) } }) } @@ -241,7 +240,12 @@ impl Stack { self.order.iter().map(move |kind| match kind { Kind::Live => Layer::Live(live.next().unwrap()), - Kind::Cache => Layer::Cached(cached.next().unwrap().borrow()), + Kind::Cache => { + let (transformation, layer) = cached.next().unwrap(); + let layer = layer.borrow(); + + Layer::Cached(*transformation * layer.transformation, layer) + } }) } @@ -288,7 +292,6 @@ impl Live { Cached { bounds: self.bounds, transformation: self.transformation, - last_transformation: None, quads: quad::Cache::Staged(self.quads), meshes: triangle::Cache::Staged(self.meshes), text: text::Cache::Staged(self.text), @@ -301,7 +304,6 @@ impl Live { pub struct Cached { pub bounds: Option, pub transformation: Transformation, - pub last_transformation: Option, pub quads: quad::Cache, pub meshes: triangle::Cache, pub text: text::Cache, @@ -311,7 +313,6 @@ pub struct Cached { impl Cached { pub fn update(&mut self, live: Live) { self.bounds = live.bounds; - self.transformation = live.transformation; self.quads.update(live.quads); self.meshes.update(live.meshes); -- cgit From 4a356cfc16f3b45d64826732009d9feeac016b28 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 5 Apr 2024 01:24:34 +0200 Subject: Enable clipping and disable v-sync for now --- wgpu/src/layer.rs | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 1c9638b0..d415da72 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -183,26 +183,26 @@ impl Stack { } pub fn push_clip(&mut self, bounds: Option) { - // self.previous.push(self.current); - // self.order.push(Kind::Live); - - // self.current = self.live_count; - // self.live_count += 1; - - // let bounds = bounds.map(|bounds| bounds * self.transformation()); - - // if self.current == self.live.len() { - // self.live.push(Live { - // bounds, - // ..Live::default() - // }); - // } else { - // self.live[self.current].bounds = bounds; - // } + self.previous.push(self.current); + self.order.push(Kind::Live); + + self.current = self.live_count; + self.live_count += 1; + + let bounds = bounds.map(|bounds| bounds * self.transformation()); + + if self.current == self.live.len() { + self.live.push(Live { + bounds, + ..Live::default() + }); + } else { + self.live[self.current].bounds = bounds; + } } pub fn pop_clip(&mut self) { - // self.current = self.previous.pop().unwrap(); + self.current = self.previous.pop().unwrap(); } pub fn push_transformation(&mut self, transformation: Transformation) { @@ -219,7 +219,6 @@ impl Stack { } pub fn iter_mut(&mut self) -> impl Iterator> { - dbg!(self.order.len()); let mut live = self.live.iter_mut(); let mut cached = self.cached.iter_mut(); -- cgit From 6d3e1d835e1688fbc58622a03a784ed25ed3f0e1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 5 Apr 2024 23:59:21 +0200 Subject: Decouple caching from layering and simplify everything --- wgpu/src/layer.rs | 258 +++++++++++++++++++++++++++--------------------------- 1 file changed, 127 insertions(+), 131 deletions(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index d415da72..4c864cb0 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -8,39 +8,46 @@ use crate::quad::{self, Quad}; use crate::text::{self, Text}; use crate::triangle; -use std::cell::{self, RefCell}; -use std::rc::Rc; - -pub enum Layer<'a> { - Live(&'a Live), - Cached(Transformation, cell::Ref<'a, Cached>), +pub struct Layer { + pub bounds: Rectangle, + pub quads: quad::Batch, + pub triangles: triangle::Batch, + pub text: text::Batch, + pub images: image::Batch, } -pub enum LayerMut<'a> { - Live(&'a mut Live), - Cached(Transformation, cell::RefMut<'a, Cached>), +impl Default for Layer { + fn default() -> Self { + Self { + bounds: Rectangle::INFINITE, + quads: quad::Batch::default(), + triangles: triangle::Batch::default(), + text: text::Batch::default(), + images: image::Batch::default(), + } + } } pub struct Stack { - live: Vec, - cached: Vec<(Transformation, Rc>)>, - order: Vec, + layers: Vec, transformations: Vec, previous: Vec, + pending_meshes: Vec>, + pending_text: Vec>, current: usize, - live_count: usize, + active_count: usize, } impl Stack { pub fn new() -> Self { Self { - live: vec![Live::default()], - cached: Vec::new(), - order: vec![Kind::Live], + layers: vec![Layer::default()], transformations: vec![Transformation::IDENTITY], - previous: Vec::new(), + previous: vec![], + pending_meshes: vec![Vec::new()], + pending_text: vec![Vec::new()], current: 0, - live_count: 1, + active_count: 1, } } @@ -59,7 +66,7 @@ impl Stack { shadow_blur_radius: quad.shadow.blur_radius, }; - self.live[self.current].quads.add(quad, &background); + self.layers[self.current].quads.add(quad, &background); } pub fn draw_paragraph( @@ -77,7 +84,7 @@ impl Stack { transformation: self.transformations.last().copied().unwrap(), }; - self.live[self.current].text.push(paragraph); + self.pending_text[self.current].push(paragraph); } pub fn draw_editor( @@ -87,7 +94,7 @@ impl Stack { color: Color, clip_bounds: Rectangle, ) { - let paragraph = Text::Editor { + let editor = Text::Editor { editor: editor.downgrade(), position, color, @@ -95,7 +102,7 @@ impl Stack { transformation: self.transformation(), }; - self.live[self.current].text.push(paragraph); + self.pending_text[self.current].push(editor); } pub fn draw_text( @@ -107,12 +114,13 @@ impl Stack { ) { let transformation = self.transformation(); - let paragraph = Text::Cached { + let text = Text::Cached { content: text.content, bounds: Rectangle::new(position, text.bounds) * transformation, color, size: text.size * transformation.scale_factor(), - line_height: text.line_height, + line_height: text.line_height.to_absolute(text.size) + * transformation.scale_factor(), font: text.font, horizontal_alignment: text.horizontal_alignment, vertical_alignment: text.vertical_alignment, @@ -120,7 +128,7 @@ impl Stack { clip_bounds: clip_bounds * transformation, }; - self.live[self.current].text.push(paragraph); + self.pending_text[self.current].push(text); } pub fn draw_image( @@ -135,7 +143,7 @@ impl Stack { bounds: bounds * self.transformation(), }; - self.live[self.current].images.push(image); + self.layers[self.current].images.push(image); } pub fn draw_svg( @@ -150,7 +158,7 @@ impl Stack { bounds: bounds * self.transformation(), }; - self.live[self.current].images.push(svg); + self.layers[self.current].images.push(svg); } pub fn draw_mesh(&mut self, mut mesh: Mesh) { @@ -161,51 +169,86 @@ impl Stack { } } - self.live[self.current].meshes.push(mesh); + self.pending_meshes[self.current].push(mesh); } - pub fn draw_layer(&mut self, mut layer: Live) { - layer.transformation = layer.transformation * self.transformation(); + pub fn draw_mesh_group(&mut self, meshes: Vec) { + self.flush_pending(); - if self.live_count == self.live.len() { - self.live.push(layer); - } else { - self.live[self.live_count] = layer; - } + let transformation = self.transformation(); - self.live_count += 1; - self.order.push(Kind::Live); + self.layers[self.current] + .triangles + .push(triangle::Item::Group { + transformation, + meshes, + }); } - pub fn draw_cached_layer(&mut self, layer: &Rc>) { - self.cached.push((self.transformation(), layer.clone())); - self.order.push(Kind::Cache); + pub fn draw_mesh_cache(&mut self, cache: triangle::Cache) { + self.flush_pending(); + + let transformation = self.transformation(); + + self.layers[self.current] + .triangles + .push(triangle::Item::Cached { + transformation, + cache, + }); + } + + pub fn draw_text_group(&mut self, text: Vec) { + self.flush_pending(); + + let transformation = self.transformation(); + + self.layers[self.current].text.push(text::Item::Group { + transformation, + text, + }); + } + + pub fn draw_text_cache(&mut self, cache: text::Cache) { + self.flush_pending(); + + let transformation = self.transformation(); + + self.layers[self.current].text.push(text::Item::Cached { + transformation, + cache, + }); } - pub fn push_clip(&mut self, bounds: Option) { + pub fn push_clip(&mut self, bounds: Rectangle) { self.previous.push(self.current); - self.order.push(Kind::Live); - self.current = self.live_count; - self.live_count += 1; + self.current = self.active_count; + self.active_count += 1; - let bounds = bounds.map(|bounds| bounds * self.transformation()); + let bounds = bounds * self.transformation(); - if self.current == self.live.len() { - self.live.push(Live { + if self.current == self.layers.len() { + self.layers.push(Layer { bounds, - ..Live::default() + ..Layer::default() }); + self.pending_meshes.push(Vec::new()); + self.pending_text.push(Vec::new()); } else { - self.live[self.current].bounds = bounds; + self.layers[self.current].bounds = bounds; } } pub fn pop_clip(&mut self) { + self.flush_pending(); + self.current = self.previous.pop().unwrap(); } pub fn push_transformation(&mut self, transformation: Transformation) { + self.flush_pending(); + self.transformations .push(self.transformation() * transformation); } @@ -218,109 +261,62 @@ impl Stack { self.transformations.last().copied().unwrap() } - pub fn iter_mut(&mut self) -> impl Iterator> { - let mut live = self.live.iter_mut(); - let mut cached = self.cached.iter_mut(); - - self.order.iter().map(move |kind| match kind { - Kind::Live => LayerMut::Live(live.next().unwrap()), - Kind::Cache => { - let (transformation, layer) = cached.next().unwrap(); - let layer = layer.borrow_mut(); + pub fn iter_mut(&mut self) -> impl Iterator { + self.flush_pending(); - LayerMut::Cached(*transformation * layer.transformation, layer) - } - }) + self.layers[..self.active_count].iter_mut() } - pub fn iter(&self) -> impl Iterator> { - let mut live = self.live.iter(); - let mut cached = self.cached.iter(); - - self.order.iter().map(move |kind| match kind { - Kind::Live => Layer::Live(live.next().unwrap()), - Kind::Cache => { - let (transformation, layer) = cached.next().unwrap(); - let layer = layer.borrow(); - - Layer::Cached(*transformation * layer.transformation, layer) - } - }) + pub fn iter(&self) -> impl Iterator { + self.layers[..self.active_count].iter() } pub fn clear(&mut self) { - for live in &mut self.live[..self.live_count] { - live.bounds = None; - live.transformation = Transformation::IDENTITY; + for (live, pending_meshes) in self.layers[..self.active_count] + .iter_mut() + .zip(self.pending_meshes.iter_mut()) + { + live.bounds = Rectangle::INFINITE; live.quads.clear(); - live.meshes.clear(); + live.triangles.clear(); live.text.clear(); live.images.clear(); + pending_meshes.clear(); } self.current = 0; - self.live_count = 1; - - self.order.clear(); - self.order.push(Kind::Live); - - self.cached.clear(); + self.active_count = 1; self.previous.clear(); } -} -impl Default for Stack { - fn default() -> Self { - Self::new() - } -} + // We want to keep the allocated memory + #[allow(clippy::drain_collect)] + fn flush_pending(&mut self) { + let transformation = self.transformation(); -#[derive(Default)] -pub struct Live { - pub bounds: Option, - pub transformation: Transformation, - pub quads: quad::Batch, - pub meshes: triangle::Batch, - pub text: text::Batch, - pub images: image::Batch, -} + let pending_meshes = &mut self.pending_meshes[self.current]; + if !pending_meshes.is_empty() { + self.layers[self.current] + .triangles + .push(triangle::Item::Group { + transformation, + meshes: pending_meshes.drain(..).collect(), + }); + } -impl Live { - pub fn into_cached(self) -> Cached { - Cached { - bounds: self.bounds, - transformation: self.transformation, - quads: quad::Cache::Staged(self.quads), - meshes: triangle::Cache::Staged(self.meshes), - text: text::Cache::Staged(self.text), - images: self.images, + let pending_text = &mut self.pending_text[self.current]; + if !pending_text.is_empty() { + self.layers[self.current].text.push(text::Item::Group { + transformation, + text: pending_text.drain(..).collect(), + }); } } } -#[derive(Default)] -pub struct Cached { - pub bounds: Option, - pub transformation: Transformation, - pub quads: quad::Cache, - pub meshes: triangle::Cache, - pub text: text::Cache, - pub images: image::Batch, -} - -impl Cached { - pub fn update(&mut self, live: Live) { - self.bounds = live.bounds; - - self.quads.update(live.quads); - self.meshes.update(live.meshes); - self.text.update(live.text); - self.images = live.images; +impl Default for Stack { + fn default() -> Self { + Self::new() } } - -enum Kind { - Live, - Cache, -} -- cgit From d922b478156488a7bc03c6e791e05c040d702634 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 8 Apr 2024 15:04:35 +0200 Subject: Reintroduce support for custom primitives in `iced_wgpu` --- wgpu/src/layer.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index c8c27c61..7a18e322 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -4,6 +4,7 @@ use crate::graphics::color; use crate::graphics::text::{Editor, Paragraph}; use crate::graphics::Mesh; use crate::image::{self, Image}; +use crate::primitive::{self, Primitive}; use crate::quad::{self, Quad}; use crate::text::{self, Text}; use crate::triangle; @@ -13,6 +14,7 @@ pub struct Layer { pub bounds: Rectangle, pub quads: quad::Batch, pub triangles: triangle::Batch, + pub primitives: primitive::Batch, pub text: text::Batch, pub images: image::Batch, } @@ -23,6 +25,7 @@ impl Default for Layer { bounds: Rectangle::INFINITE, quads: quad::Batch::default(), triangles: triangle::Batch::default(), + primitives: primitive::Batch::default(), text: text::Batch::default(), images: image::Batch::default(), } @@ -222,6 +225,18 @@ impl Stack { }); } + pub fn draw_primitive( + &mut self, + bounds: Rectangle, + primitive: Box, + ) { + let bounds = bounds * self.transformation(); + + self.layers[self.current] + .primitives + .push(primitive::Instance { bounds, primitive }); + } + pub fn push_clip(&mut self, bounds: Rectangle) { self.previous.push(self.current); @@ -282,6 +297,7 @@ impl Stack { live.quads.clear(); live.triangles.clear(); + live.primitives.clear(); live.text.clear(); live.images.clear(); pending_meshes.clear(); -- cgit From 6ad5bb3597f640ac329801adf735d633bf0a512f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 9 Apr 2024 22:25:16 +0200 Subject: Port `iced_tiny_skia` to new layering architecture --- wgpu/src/layer.rs | 301 +++++++++++++++++++++++------------------------------- 1 file changed, 127 insertions(+), 174 deletions(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 7a18e322..9526c5a8 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -1,6 +1,8 @@ use crate::core::renderer; use crate::core::{Background, Color, Point, Rectangle, Transformation}; +use crate::graphics; use crate::graphics::color; +use crate::graphics::layer; use crate::graphics::text::{Editor, Paragraph}; use crate::graphics::Mesh; use crate::image::{self, Image}; @@ -9,6 +11,8 @@ use crate::quad::{self, Quad}; use crate::text::{self, Text}; use crate::triangle; +pub type Stack = layer::Stack; + #[derive(Debug)] pub struct Layer { pub bounds: Rectangle, @@ -17,48 +21,18 @@ pub struct Layer { pub primitives: primitive::Batch, pub text: text::Batch, pub images: image::Batch, + pending_meshes: Vec, + pending_text: Vec, } -impl Default for Layer { - fn default() -> Self { - Self { - bounds: Rectangle::INFINITE, - quads: quad::Batch::default(), - triangles: triangle::Batch::default(), - primitives: primitive::Batch::default(), - text: text::Batch::default(), - images: image::Batch::default(), - } - } -} - -#[derive(Debug)] -pub struct Stack { - layers: Vec, - transformations: Vec, - previous: Vec, - pending_meshes: Vec>, - pending_text: Vec>, - current: usize, - active_count: usize, -} - -impl Stack { - pub fn new() -> Self { - Self { - layers: vec![Layer::default()], - transformations: vec![Transformation::IDENTITY], - previous: vec![], - pending_meshes: vec![Vec::new()], - pending_text: vec![Vec::new()], - current: 0, - active_count: 1, - } - } - - pub fn draw_quad(&mut self, quad: renderer::Quad, background: Background) { - let transformation = self.transformations.last().unwrap(); - let bounds = quad.bounds * *transformation; +impl Layer { + pub fn draw_quad( + &mut self, + quad: renderer::Quad, + background: Background, + transformation: Transformation, + ) { + let bounds = quad.bounds * transformation; let quad = Quad { position: [bounds.x, bounds.y], @@ -71,7 +45,7 @@ impl Stack { shadow_blur_radius: quad.shadow.blur_radius, }; - self.layers[self.current].quads.add(quad, &background); + self.quads.add(quad, &background); } pub fn draw_paragraph( @@ -80,16 +54,17 @@ impl Stack { position: Point, color: Color, clip_bounds: Rectangle, + transformation: Transformation, ) { let paragraph = Text::Paragraph { paragraph: paragraph.downgrade(), position, color, clip_bounds, - transformation: self.transformations.last().copied().unwrap(), + transformation, }; - self.pending_text[self.current].push(paragraph); + self.pending_text.push(paragraph); } pub fn draw_editor( @@ -98,16 +73,17 @@ impl Stack { position: Point, color: Color, clip_bounds: Rectangle, + transformation: Transformation, ) { let editor = Text::Editor { editor: editor.downgrade(), position, color, clip_bounds, - transformation: self.transformation(), + transformation, }; - self.pending_text[self.current].push(editor); + self.pending_text.push(editor); } pub fn draw_text( @@ -116,9 +92,8 @@ impl Stack { position: Point, color: Color, clip_bounds: Rectangle, + transformation: Transformation, ) { - let transformation = self.transformation(); - let text = Text::Cached { content: text.content, bounds: Rectangle::new(position, text.bounds) * transformation, @@ -133,7 +108,7 @@ impl Stack { clip_bounds: clip_bounds * transformation, }; - self.pending_text[self.current].push(text); + self.pending_text.push(text); } pub fn draw_image( @@ -141,14 +116,15 @@ impl Stack { handle: crate::core::image::Handle, filter_method: crate::core::image::FilterMethod, bounds: Rectangle, + transformation: Transformation, ) { let image = Image::Raster { handle, filter_method, - bounds: bounds * self.transformation(), + bounds: bounds * transformation, }; - self.layers[self.current].images.push(image); + self.images.push(image); } pub fn draw_svg( @@ -156,72 +132,87 @@ impl Stack { handle: crate::core::svg::Handle, color: Option, bounds: Rectangle, + transformation: Transformation, ) { let svg = Image::Vector { handle, color, - bounds: bounds * self.transformation(), + bounds: bounds * transformation, }; - self.layers[self.current].images.push(svg); + self.images.push(svg); } - pub fn draw_mesh(&mut self, mut mesh: Mesh) { + pub fn draw_mesh( + &mut self, + mut mesh: Mesh, + transformation: Transformation, + ) { match &mut mesh { - Mesh::Solid { transformation, .. } - | Mesh::Gradient { transformation, .. } => { - *transformation = *transformation * self.transformation(); + Mesh::Solid { + transformation: local_transformation, + .. + } + | Mesh::Gradient { + transformation: local_transformation, + .. + } => { + *local_transformation = *local_transformation * transformation; } } - self.pending_meshes[self.current].push(mesh); + self.pending_meshes.push(mesh); } - pub fn draw_mesh_group(&mut self, meshes: Vec) { - self.flush_pending(); - - let transformation = self.transformation(); + pub fn draw_mesh_group( + &mut self, + meshes: Vec, + transformation: Transformation, + ) { + self.flush_meshes(); - self.layers[self.current] - .triangles - .push(triangle::Item::Group { - transformation, - meshes, - }); + self.triangles.push(triangle::Item::Group { + meshes, + transformation, + }); } - pub fn draw_mesh_cache(&mut self, cache: triangle::Cache) { - self.flush_pending(); - - let transformation = self.transformation(); + pub fn draw_mesh_cache( + &mut self, + cache: triangle::Cache, + transformation: Transformation, + ) { + self.flush_meshes(); - self.layers[self.current] - .triangles - .push(triangle::Item::Cached { - transformation, - cache, - }); + self.triangles.push(triangle::Item::Cached { + cache, + transformation, + }); } - pub fn draw_text_group(&mut self, text: Vec) { - self.flush_pending(); - - let transformation = self.transformation(); + pub fn draw_text_group( + &mut self, + text: Vec, + transformation: Transformation, + ) { + self.flush_text(); - self.layers[self.current].text.push(text::Item::Group { - transformation, + self.text.push(text::Item::Group { text, + transformation, }); } - pub fn draw_text_cache(&mut self, cache: text::Cache) { - self.flush_pending(); - - let transformation = self.transformation(); + pub fn draw_text_cache( + &mut self, + cache: text::Cache, + transformation: Transformation, + ) { + self.flush_text(); - self.layers[self.current].text.push(text::Item::Cached { - transformation, + self.text.push(text::Item::Cached { cache, + transformation, }); } @@ -229,112 +220,74 @@ impl Stack { &mut self, bounds: Rectangle, primitive: Box, + transformation: Transformation, ) { - let bounds = bounds * self.transformation(); + let bounds = bounds * transformation; - self.layers[self.current] - .primitives + self.primitives .push(primitive::Instance { bounds, primitive }); } - pub fn push_clip(&mut self, bounds: Rectangle) { - self.previous.push(self.current); - - self.current = self.active_count; - self.active_count += 1; - - let bounds = bounds * self.transformation(); - - if self.current == self.layers.len() { - self.layers.push(Layer { - bounds, - ..Layer::default() + fn flush_meshes(&mut self) { + if !self.pending_meshes.is_empty() { + self.triangles.push(triangle::Item::Group { + transformation: Transformation::IDENTITY, + meshes: self.pending_meshes.drain(..).collect(), }); - self.pending_meshes.push(Vec::new()); - self.pending_text.push(Vec::new()); - } else { - self.layers[self.current].bounds = bounds; } } - pub fn pop_clip(&mut self) { - self.flush_pending(); - - self.current = self.previous.pop().unwrap(); - } - - pub fn push_transformation(&mut self, transformation: Transformation) { - self.flush_pending(); - - self.transformations - .push(self.transformation() * transformation); - } - - pub fn pop_transformation(&mut self) { - let _ = self.transformations.pop(); - } - - fn transformation(&self) -> Transformation { - self.transformations.last().copied().unwrap() + fn flush_text(&mut self) { + if !self.pending_text.is_empty() { + self.text.push(text::Item::Group { + transformation: Transformation::IDENTITY, + text: self.pending_text.drain(..).collect(), + }); + } } +} - pub fn iter_mut(&mut self) -> impl Iterator { - self.flush_pending(); - - self.layers[..self.active_count].iter_mut() +impl graphics::Layer for Layer { + fn with_bounds(bounds: Rectangle) -> Self { + Self { + bounds, + ..Self::default() + } } - pub fn iter(&self) -> impl Iterator { - self.layers[..self.active_count].iter() + fn flush(&mut self) { + self.flush_meshes(); + self.flush_text(); } - pub fn clear(&mut self) { - for (live, pending_meshes) in self.layers[..self.active_count] - .iter_mut() - .zip(self.pending_meshes.iter_mut()) - { - live.bounds = Rectangle::INFINITE; - - live.quads.clear(); - live.triangles.clear(); - live.primitives.clear(); - live.text.clear(); - live.images.clear(); - pending_meshes.clear(); - } - - self.current = 0; - self.active_count = 1; - self.previous.clear(); + fn resize(&mut self, bounds: Rectangle) { + self.bounds = bounds; } - // We want to keep the allocated memory - #[allow(clippy::drain_collect)] - fn flush_pending(&mut self) { - let transformation = self.transformation(); - - let pending_meshes = &mut self.pending_meshes[self.current]; - if !pending_meshes.is_empty() { - self.layers[self.current] - .triangles - .push(triangle::Item::Group { - transformation, - meshes: pending_meshes.drain(..).collect(), - }); - } + fn reset(&mut self) { + self.bounds = Rectangle::INFINITE; - let pending_text = &mut self.pending_text[self.current]; - if !pending_text.is_empty() { - self.layers[self.current].text.push(text::Item::Group { - transformation, - text: pending_text.drain(..).collect(), - }); - } + self.quads.clear(); + self.triangles.clear(); + self.primitives.clear(); + self.text.clear(); + self.images.clear(); + self.pending_meshes.clear(); + self.pending_text.clear(); } } -impl Default for Stack { +impl Default for Layer { fn default() -> Self { - Self::new() + Self { + bounds: Rectangle::INFINITE, + quads: quad::Batch::default(), + triangles: triangle::Batch::default(), + primitives: primitive::Batch::default(), + text: text::Batch::default(), + images: image::Batch::default(), + pending_meshes: Vec::new(), + pending_text: Vec::new(), + } } } -- cgit