From 0f7abffc0e94b4bb9f8117db633bfd07d900eb93 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 22 Mar 2023 00:36:57 +0100 Subject: Draft (very) basic incremental rendering for `iced_tiny_skia` --- graphics/src/primitive.rs | 151 ++++++++++++++++++++++++++++++++++++++++++++-- graphics/src/renderer.rs | 2 +- 2 files changed, 148 insertions(+), 5 deletions(-) (limited to 'graphics/src') diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index 195b62da..bbf300b0 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -7,7 +7,7 @@ use bytemuck::{Pod, Zeroable}; use std::sync::Arc; /// A rendering primitive. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] #[non_exhaustive] pub enum Primitive { /// A text primitive @@ -147,10 +147,153 @@ impl Primitive { content: Box::new(self), } } + + pub fn bounds(&self) -> Rectangle { + match self { + Self::Text { + bounds, + horizontal_alignment, + vertical_alignment, + .. + } => { + let mut bounds = *bounds; + + bounds.x = match horizontal_alignment { + alignment::Horizontal::Left => bounds.x, + alignment::Horizontal::Center => { + bounds.x - bounds.width / 2.0 + } + alignment::Horizontal::Right => bounds.x - bounds.width, + }; + + bounds.y = match vertical_alignment { + alignment::Vertical::Top => bounds.y, + alignment::Vertical::Center => { + bounds.y - bounds.height / 2.0 + } + alignment::Vertical::Bottom => bounds.y - bounds.height, + }; + + bounds.expand(1.0) + } + Self::Quad { bounds, .. } + | Self::Image { bounds, .. } + | Self::Svg { bounds, .. } + | Self::Clip { bounds, .. } => bounds.expand(1.0), + Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => { + Rectangle::with_size(*size) + } + #[cfg(feature = "tiny-skia")] + Self::Fill { path, .. } | Self::Stroke { path, .. } => { + let bounds = path.bounds(); + + Rectangle { + x: bounds.x(), + y: bounds.y(), + width: bounds.width(), + height: bounds.height(), + } + .expand(1.0) + } + Self::Group { primitives } => primitives + .iter() + .map(Self::bounds) + .fold(Rectangle::with_size(Size::ZERO), |a, b| { + Rectangle::union(&a, &b) + }), + Self::Translate { + translation, + content, + } => content.bounds() + *translation, + Self::Cache { content } => content.bounds(), + } + } + + pub fn damage(&self, other: &Self) -> Vec { + match (self, other) { + ( + Primitive::Group { + primitives: primitives_a, + }, + Primitive::Group { + primitives: primitives_b, + }, + ) => return Self::damage_list(primitives_a, primitives_b), + ( + Primitive::Clip { + bounds: bounds_a, + content: content_a, + }, + Primitive::Clip { + bounds: bounds_b, + content: content_b, + }, + ) => { + if bounds_a == bounds_b { + return content_a.damage(content_b); + } else { + return vec![*bounds_a, *bounds_b]; + } + } + ( + Primitive::Translate { + translation: translation_a, + content: content_a, + }, + Primitive::Translate { + translation: translation_b, + content: content_b, + }, + ) => { + if translation_a == translation_b { + return content_a.damage(content_b); + } + } + ( + Primitive::Cache { content: content_a }, + Primitive::Cache { content: content_b }, + ) => { + if Arc::ptr_eq(content_a, content_b) { + return vec![]; + } + } + _ if self == other => return vec![], + _ => {} + } + + let bounds_a = self.bounds(); + let bounds_b = other.bounds(); + + if bounds_a == bounds_b { + vec![bounds_a] + } else { + vec![bounds_a, bounds_b] + } + } + + pub fn damage_list(previous: &[Self], current: &[Self]) -> Vec { + let damage = + previous.iter().zip(current).flat_map(|(a, b)| a.damage(b)); + + if previous.len() == current.len() { + damage.collect() + } else { + let (smaller, bigger) = if previous.len() < current.len() { + (previous, current) + } else { + (current, previous) + }; + + // Extend damage by the added/removed primitives + damage + .chain(bigger[smaller.len()..].iter().map(Primitive::bounds)) + .collect() + } + } } /// A set of [`Vertex2D`] and indices representing a list of triangles. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Mesh2D { /// The vertices of the mesh pub vertices: Vec, @@ -162,7 +305,7 @@ pub struct Mesh2D { } /// A two-dimensional vertex. -#[derive(Copy, Clone, Debug, Zeroable, Pod)] +#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)] #[repr(C)] pub struct Vertex2D { /// The vertex position in 2D space. @@ -170,7 +313,7 @@ pub struct Vertex2D { } /// A two-dimensional vertex with a color. -#[derive(Copy, Clone, Debug, Zeroable, Pod)] +#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)] #[repr(C)] pub struct ColoredVertex2D { /// The vertex position in 2D space. diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index 7bc462ef..23e594be 100644 --- a/graphics/src/renderer.rs +++ b/graphics/src/renderer.rs @@ -32,7 +32,7 @@ impl Renderer { } } - /// Returns the [`Backend`] of the [`Renderer`]. + /// Returns a reference to the [`Backend`] of the [`Renderer`]. pub fn backend(&self) -> &B { &self.backend } -- cgit From 6270c33ed9823c67f6b6e6dac8fd32521e4ac5a9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 4 Apr 2023 20:47:53 +0200 Subject: Keep playing with incremental rendering (still very slow) --- graphics/src/primitive.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'graphics/src') diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index bbf300b0..f079ff6f 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -230,7 +230,11 @@ impl Primitive { }, ) => { if bounds_a == bounds_b { - return content_a.damage(content_b); + return content_a + .damage(content_b) + .into_iter() + .filter_map(|r| r.intersection(bounds_a)) + .collect(); } else { return vec![*bounds_a, *bounds_b]; } @@ -246,7 +250,11 @@ impl Primitive { }, ) => { if translation_a == translation_b { - return content_a.damage(content_b); + return content_a + .damage(content_b) + .into_iter() + .map(|r| r + *translation_a) + .collect(); } } ( -- cgit From f8cd1faa286daaf34cc532bf6d34b932b32eb35a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 04:10:00 +0200 Subject: Group damage regions by area increase --- graphics/src/primitive.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'graphics/src') diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index f079ff6f..01546dcb 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -178,8 +178,8 @@ impl Primitive { } Self::Quad { bounds, .. } | Self::Image { bounds, .. } - | Self::Svg { bounds, .. } - | Self::Clip { bounds, .. } => bounds.expand(1.0), + | Self::Svg { bounds, .. } => bounds.expand(1.0), + Self::Clip { bounds, .. } => *bounds, Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => { Rectangle::with_size(*size) } -- cgit From ba07abe5c8d3f6fb175e13f5cd10f74ee8ab460c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 8 Apr 2023 07:08:03 +0200 Subject: Expand bounds of `Text` primitives a bit further --- graphics/src/primitive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'graphics/src') diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index 01546dcb..7f2c8ae2 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -174,7 +174,7 @@ impl Primitive { alignment::Vertical::Bottom => bounds.y - bounds.height, }; - bounds.expand(1.0) + bounds.expand(1.5) } Self::Quad { bounds, .. } | Self::Image { bounds, .. } -- cgit From af0303f95e27737d9de8915f939b60a2bc3282ae Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 27 Apr 2023 15:10:41 +0200 Subject: Move damage tracking logic to `compositor` in `iced_tiny_skia` --- graphics/src/damage.rs | 140 ++++++++++++++++++++++++++++++++++++++++++++++ graphics/src/lib.rs | 1 + graphics/src/primitive.rs | 90 ----------------------------- 3 files changed, 141 insertions(+), 90 deletions(-) create mode 100644 graphics/src/damage.rs (limited to 'graphics/src') diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs new file mode 100644 index 00000000..63604150 --- /dev/null +++ b/graphics/src/damage.rs @@ -0,0 +1,140 @@ +use crate::core::{Rectangle, Size}; +use crate::Primitive; + +use std::sync::Arc; + +pub fn regions(a: &Primitive, b: &Primitive) -> Vec { + match (a, b) { + ( + Primitive::Group { + primitives: primitives_a, + }, + Primitive::Group { + primitives: primitives_b, + }, + ) => return list(primitives_a, primitives_b), + ( + Primitive::Clip { + bounds: bounds_a, + content: content_a, + }, + Primitive::Clip { + bounds: bounds_b, + content: content_b, + }, + ) => { + if bounds_a == bounds_b { + return regions(content_a, content_b) + .into_iter() + .filter_map(|r| r.intersection(bounds_a)) + .collect(); + } else { + return vec![*bounds_a, *bounds_b]; + } + } + ( + Primitive::Translate { + translation: translation_a, + content: content_a, + }, + Primitive::Translate { + translation: translation_b, + content: content_b, + }, + ) => { + if translation_a == translation_b { + return regions(content_a, content_b) + .into_iter() + .map(|r| r + *translation_a) + .collect(); + } + } + ( + Primitive::Cache { content: content_a }, + Primitive::Cache { content: content_b }, + ) => { + if Arc::ptr_eq(content_a, content_b) { + return vec![]; + } + } + _ if a == b => return vec![], + _ => {} + } + + let bounds_a = a.bounds(); + let bounds_b = b.bounds(); + + if bounds_a == bounds_b { + vec![bounds_a] + } else { + vec![bounds_a, bounds_b] + } +} + +pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec { + let damage = previous + .iter() + .zip(current) + .flat_map(|(a, b)| regions(a, b)); + + if previous.len() == current.len() { + damage.collect() + } else { + let (smaller, bigger) = if previous.len() < current.len() { + (previous, current) + } else { + (current, previous) + }; + + // Extend damage by the added/removed primitives + damage + .chain(bigger[smaller.len()..].iter().map(Primitive::bounds)) + .collect() + } +} + +pub fn group( + mut damage: Vec, + scale_factor: f32, + bounds: Size, +) -> Vec { + use std::cmp::Ordering; + + const AREA_THRESHOLD: f32 = 20_000.0; + + let bounds = Rectangle { + x: 0.0, + y: 0.0, + width: bounds.width as f32, + height: bounds.height as f32, + }; + + damage.sort_by(|a, b| { + a.x.partial_cmp(&b.x) + .unwrap_or(Ordering::Equal) + .then_with(|| a.y.partial_cmp(&b.y).unwrap_or(Ordering::Equal)) + }); + + let mut output = Vec::new(); + let mut scaled = damage + .into_iter() + .filter_map(|region| (region * scale_factor).intersection(&bounds)) + .filter(|region| region.width >= 1.0 && region.height >= 1.0); + + if let Some(mut current) = scaled.next() { + for region in scaled { + let union = current.union(®ion); + + if union.area() - current.area() - region.area() <= AREA_THRESHOLD { + current = union; + } else { + output.push(current); + current = region; + } + } + + output.push(current); + } + + output +} diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index 0c50db52..e3de4025 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -28,6 +28,7 @@ mod viewport; pub mod backend; pub mod compositor; +pub mod damage; pub mod primitive; pub mod renderer; diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index 7f2c8ae2..1751d03a 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -208,96 +208,6 @@ impl Primitive { Self::Cache { content } => content.bounds(), } } - - pub fn damage(&self, other: &Self) -> Vec { - match (self, other) { - ( - Primitive::Group { - primitives: primitives_a, - }, - Primitive::Group { - primitives: primitives_b, - }, - ) => return Self::damage_list(primitives_a, primitives_b), - ( - Primitive::Clip { - bounds: bounds_a, - content: content_a, - }, - Primitive::Clip { - bounds: bounds_b, - content: content_b, - }, - ) => { - if bounds_a == bounds_b { - return content_a - .damage(content_b) - .into_iter() - .filter_map(|r| r.intersection(bounds_a)) - .collect(); - } else { - return vec![*bounds_a, *bounds_b]; - } - } - ( - Primitive::Translate { - translation: translation_a, - content: content_a, - }, - Primitive::Translate { - translation: translation_b, - content: content_b, - }, - ) => { - if translation_a == translation_b { - return content_a - .damage(content_b) - .into_iter() - .map(|r| r + *translation_a) - .collect(); - } - } - ( - Primitive::Cache { content: content_a }, - Primitive::Cache { content: content_b }, - ) => { - if Arc::ptr_eq(content_a, content_b) { - return vec![]; - } - } - _ if self == other => return vec![], - _ => {} - } - - let bounds_a = self.bounds(); - let bounds_b = other.bounds(); - - if bounds_a == bounds_b { - vec![bounds_a] - } else { - vec![bounds_a, bounds_b] - } - } - - pub fn damage_list(previous: &[Self], current: &[Self]) -> Vec { - let damage = - previous.iter().zip(current).flat_map(|(a, b)| a.damage(b)); - - if previous.len() == current.len() { - damage.collect() - } else { - let (smaller, bigger) = if previous.len() < current.len() { - (previous, current) - } else { - (current, previous) - }; - - // Extend damage by the added/removed primitives - damage - .chain(bigger[smaller.len()..].iter().map(Primitive::bounds)) - .collect() - } - } } /// A set of [`Vertex2D`] and indices representing a list of triangles. -- cgit From 38f82ab35fd24a1aaf96728148b2826211956a9f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 27 Apr 2023 15:25:59 +0200 Subject: Expand damage regions of `Clip` primitives a bit --- graphics/src/damage.rs | 6 ++++-- graphics/src/primitive.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'graphics/src') diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs index 63604150..5aab06b1 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -17,19 +17,21 @@ pub fn regions(a: &Primitive, b: &Primitive) -> Vec { Primitive::Clip { bounds: bounds_a, content: content_a, + .. }, Primitive::Clip { bounds: bounds_b, content: content_b, + .. }, ) => { if bounds_a == bounds_b { return regions(content_a, content_b) .into_iter() - .filter_map(|r| r.intersection(bounds_a)) + .filter_map(|r| r.intersection(&bounds_a.expand(1.0))) .collect(); } else { - return vec![*bounds_a, *bounds_b]; + return vec![bounds_a.expand(1.0), bounds_b.expand(1.0)]; } } ( diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index 1751d03a..d6a2c4c4 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -179,7 +179,7 @@ impl Primitive { Self::Quad { bounds, .. } | Self::Image { bounds, .. } | Self::Svg { bounds, .. } => bounds.expand(1.0), - Self::Clip { bounds, .. } => *bounds, + Self::Clip { bounds, .. } => bounds.expand(1.0), Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => { Rectangle::with_size(*size) } -- cgit