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` --- tiny_skia/src/backend.rs | 68 +++++++++++++++++++++++++++++++++++++- tiny_skia/src/primitive.rs | 82 ---------------------------------------------- 2 files changed, 67 insertions(+), 83 deletions(-) delete mode 100644 tiny_skia/src/primitive.rs (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 58076b84..fe84f83b 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -17,6 +17,9 @@ pub struct Backend { #[cfg(feature = "svg")] vector_pipeline: crate::vector::Pipeline, + + last_primitives: Vec, + last_background_color: Color, } impl Backend { @@ -31,6 +34,9 @@ impl Backend { #[cfg(feature = "svg")] vector_pipeline: crate::vector::Pipeline::new(), + + last_primitives: Vec::new(), + last_background_color: Color::BLACK, } } @@ -43,10 +49,48 @@ impl Backend { background_color: Color, overlay: &[T], ) { - pixels.fill(into_color(background_color)); + let damage = if self.last_background_color == background_color { + Primitive::damage_list(&self.last_primitives, primitives) + } else { + vec![Rectangle::with_size(viewport.logical_size())] + }; + + if damage.is_empty() { + return; + } + + self.last_primitives = primitives.to_vec(); + self.last_background_color = background_color; let scale_factor = viewport.scale_factor() as f32; + dbg!(&damage); + + for region in &damage { + let region = *region * scale_factor; + + pixels.fill_path( + &tiny_skia::PathBuilder::from_rect( + tiny_skia::Rect::from_xywh( + region.x, + region.y, + region.width.min(viewport.physical_width() as f32), + region.height.min(viewport.physical_height() as f32), + ) + .expect("Create damage rectangle"), + ), + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color( + background_color, + )), + ..Default::default() + }, + tiny_skia::FillRule::default(), + tiny_skia::Transform::identity(), + None, + ); + } + for primitive in primitives { self.draw_primitive( primitive, @@ -55,6 +99,7 @@ impl Backend { None, scale_factor, Vector::ZERO, + &damage, ); } @@ -81,6 +126,7 @@ impl Backend { None, scale_factor, Vector::ZERO, + &[], ); } @@ -101,6 +147,7 @@ impl Backend { clip_bounds: Option, scale_factor: f32, translation: Vector, + damage: &[Rectangle], ) { match primitive { Primitive::Quad { @@ -110,6 +157,10 @@ impl Backend { border_width, border_color, } => { + if !damage.iter().any(|damage| damage.intersects(bounds)) { + return; + } + let transform = tiny_skia::Transform::from_translate( translation.x, translation.y, @@ -165,6 +216,13 @@ impl Backend { horizontal_alignment, vertical_alignment, } => { + if !damage + .iter() + .any(|damage| damage.intersects(&primitive.bounds())) + { + return; + } + self.text_pipeline.draw( content, (*bounds + translation) * scale_factor, @@ -179,6 +237,10 @@ impl Backend { } #[cfg(feature = "image")] Primitive::Image { handle, bounds } => { + if !damage.iter().any(|damage| damage.intersects(bounds)) { + return; + } + let transform = tiny_skia::Transform::from_translate( translation.x, translation.y, @@ -248,6 +310,7 @@ impl Backend { clip_bounds, scale_factor, translation, + damage, ); } } @@ -262,6 +325,7 @@ impl Backend { clip_bounds, scale_factor, translation + *offset, + damage, ); } Primitive::Clip { bounds, content } => { @@ -284,6 +348,7 @@ impl Backend { Some(bounds), scale_factor, translation, + damage, ); if let Some(bounds) = clip_bounds { @@ -300,6 +365,7 @@ impl Backend { clip_bounds, scale_factor, translation, + damage, ); } Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => { diff --git a/tiny_skia/src/primitive.rs b/tiny_skia/src/primitive.rs deleted file mode 100644 index 22daaedc..00000000 --- a/tiny_skia/src/primitive.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::{Rectangle, Vector}; - -use std::sync::Arc; - -#[derive(Debug, Clone)] -pub enum Primitive { - /// A group of primitives - Group { - /// The primitives of the group - primitives: Vec, - }, - /// A clip primitive - Clip { - /// The bounds of the clip - bounds: Rectangle, - /// The content of the clip - content: Box, - }, - /// A primitive that applies a translation - Translate { - /// The translation vector - translation: Vector, - - /// The primitive to translate - content: Box, - }, - /// A cached primitive. - /// - /// This can be useful if you are implementing a widget where primitive - /// generation is expensive. - Cached { - /// The cached primitive - cache: Arc, - }, - /// A basic primitive. - Basic(iced_graphics::Primitive), -} - -impl iced_graphics::backend::Primitive for Primitive { - fn translate(self, translation: Vector) -> Self { - Self::Translate { - translation, - content: Box::new(self), - } - } - - fn clip(self, bounds: Rectangle) -> Self { - Self::Clip { - bounds, - content: Box::new(self), - } - } -} - -#[derive(Debug, Clone, Default)] -pub struct Recording(pub(crate) Vec); - -impl iced_graphics::backend::Recording for Recording { - type Primitive = Primitive; - - fn push(&mut self, primitive: Primitive) { - self.0.push(primitive); - } - - fn push_basic(&mut self, basic: iced_graphics::Primitive) { - self.0.push(Primitive::Basic(basic)); - } - - fn group(self) -> Self::Primitive { - Primitive::Group { primitives: self.0 } - } - - fn clear(&mut self) { - self.0.clear(); - } -} - -impl Recording { - pub fn primitives(&self) -> &[Primitive] { - &self.0 - } -} -- 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) --- tiny_skia/src/backend.rs | 232 ++++++++++++++++++++++++++++++----------------- 1 file changed, 150 insertions(+), 82 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index fe84f83b..8101082a 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -20,6 +20,7 @@ pub struct Backend { last_primitives: Vec, last_background_color: Color, + last_size: Size, } impl Backend { @@ -37,6 +38,7 @@ impl Backend { last_primitives: Vec::new(), last_background_color: Color::BLACK, + last_size: Size::new(0, 0), } } @@ -47,9 +49,13 @@ impl Backend { primitives: &[Primitive], viewport: &Viewport, background_color: Color, - overlay: &[T], + _overlay: &[T], ) { - let damage = if self.last_background_color == background_color { + let physical_size = viewport.physical_size(); + + let damage = if self.last_background_color == background_color + && self.last_size == physical_size + { Primitive::damage_list(&self.last_primitives, primitives) } else { vec![Rectangle::with_size(viewport.logical_size())] @@ -61,24 +67,46 @@ impl Backend { self.last_primitives = primitives.to_vec(); self.last_background_color = background_color; + self.last_size = physical_size; let scale_factor = viewport.scale_factor() as f32; + let physical_bounds = Rectangle { + x: 0.0, + y: 0.0, + width: physical_size.width as f32, + height: physical_size.height as f32, + }; - dbg!(&damage); + dbg!(damage.len()); + + 'draw_regions: for (i, region) in damage.iter().enumerate() { + for previous in damage.iter().take(i) { + if previous.contains(region.position()) + && previous.contains( + region.position() + + Vector::new(region.width, region.height), + ) + { + continue 'draw_regions; + } + } - for region in &damage { let region = *region * scale_factor; + let Some(region) = physical_bounds.intersection(®ion) else { continue }; + + let path = tiny_skia::PathBuilder::from_rect( + tiny_skia::Rect::from_xywh( + region.x, + region.y, + region.width.min(viewport.physical_width() as f32), + region.height.min(viewport.physical_height() as f32), + ) + .expect("Create damage rectangle"), + ); + pixels.fill_path( - &tiny_skia::PathBuilder::from_rect( - tiny_skia::Rect::from_xywh( - region.x, - region.y, - region.width.min(viewport.physical_width() as f32), - region.height.min(viewport.physical_height() as f32), - ) - .expect("Create damage rectangle"), - ), + &path, &tiny_skia::Paint { shader: tiny_skia::Shader::SolidColor(into_color( background_color, @@ -89,47 +117,64 @@ impl Backend { tiny_skia::Transform::identity(), None, ); - } - for primitive in primitives { - self.draw_primitive( - primitive, - pixels, - clip_mask, - None, - scale_factor, - Vector::ZERO, - &damage, - ); - } + adjust_clip_mask(clip_mask, pixels, region); - for (i, text) in overlay.iter().enumerate() { - const OVERLAY_TEXT_SIZE: f32 = 20.0; - - self.draw_primitive( - &Primitive::Text { - content: text.as_ref().to_owned(), - size: OVERLAY_TEXT_SIZE, - bounds: Rectangle { - x: 10.0, - y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, - width: f32::INFINITY, - height: f32::INFINITY, - }, - color: Color::BLACK, - font: Font::MONOSPACE, - horizontal_alignment: alignment::Horizontal::Left, - vertical_alignment: alignment::Vertical::Top, - }, - pixels, - clip_mask, - None, - scale_factor, - Vector::ZERO, - &[], - ); + for primitive in primitives { + self.draw_primitive( + primitive, + pixels, + clip_mask, + region, + scale_factor, + Vector::ZERO, + ); + } + + //pixels.stroke_path( + // &path, + // &tiny_skia::Paint { + // shader: tiny_skia::Shader::SolidColor(into_color( + // Color::from_rgb(1.0, 0.0, 0.0), + // )), + // anti_alias: true, + // ..tiny_skia::Paint::default() + // }, + // &tiny_skia::Stroke { + // width: 1.0, + // ..tiny_skia::Stroke::default() + // }, + // tiny_skia::Transform::identity(), + // None, + //); } + //for (i, text) in overlay.iter().enumerate() { + // const OVERLAY_TEXT_SIZE: f32 = 20.0; + + // self.draw_primitive( + // &Primitive::Text { + // content: text.as_ref().to_owned(), + // size: OVERLAY_TEXT_SIZE, + // bounds: Rectangle { + // x: 10.0, + // y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, + // width: f32::INFINITY, + // height: f32::INFINITY, + // }, + // color: Color::BLACK, + // font: Font::MONOSPACE, + // horizontal_alignment: alignment::Horizontal::Left, + // vertical_alignment: alignment::Vertical::Top, + // }, + // pixels, + // clip_mask, + // Rectangle::EMPTY, + // scale_factor, + // Vector::ZERO, + // ); + //} + self.text_pipeline.trim_cache(); #[cfg(feature = "image")] @@ -144,10 +189,9 @@ impl Backend { primitive: &Primitive, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: &mut tiny_skia::ClipMask, - clip_bounds: Option, + clip_bounds: Rectangle, scale_factor: f32, translation: Vector, - damage: &[Rectangle], ) { match primitive { Primitive::Quad { @@ -157,7 +201,9 @@ impl Backend { border_width, border_color, } => { - if !damage.iter().any(|damage| damage.intersects(bounds)) { + if !clip_bounds + .intersects(&((*bounds + translation) * scale_factor)) + { return; } @@ -168,7 +214,6 @@ impl Backend { .post_scale(scale_factor, scale_factor); let path = rounded_rectangle(*bounds, *border_radius); - let clip_mask = clip_bounds.map(|_| clip_mask as &_); pixels.fill_path( &path, @@ -185,7 +230,7 @@ impl Backend { }, tiny_skia::FillRule::EvenOdd, transform, - clip_mask, + Some(clip_mask), ); if *border_width > 0.0 { @@ -203,7 +248,7 @@ impl Backend { ..tiny_skia::Stroke::default() }, transform, - clip_mask, + Some(clip_mask), ); } } @@ -216,10 +261,9 @@ impl Backend { horizontal_alignment, vertical_alignment, } => { - if !damage - .iter() - .any(|damage| damage.intersects(&primitive.bounds())) - { + if !clip_bounds.intersects( + &((primitive.bounds() + translation) * scale_factor), + ) { return; } @@ -232,12 +276,14 @@ impl Backend { *horizontal_alignment, *vertical_alignment, pixels, - clip_bounds.map(|_| clip_mask as &_), + Some(clip_mask), ); } #[cfg(feature = "image")] Primitive::Image { handle, bounds } => { - if !damage.iter().any(|damage| damage.intersects(bounds)) { + if !clip_bounds + .intersects(&((*bounds + translation) * scale_factor)) + { return; } @@ -252,7 +298,7 @@ impl Backend { *bounds, pixels, transform, - clip_bounds.map(|_| clip_mask as &_), + Some(clip_mask), ); } #[cfg(feature = "svg")] @@ -275,6 +321,20 @@ impl Backend { rule, transform, } => { + let bounds = path.bounds(); + + if !clip_bounds.intersects( + &((Rectangle { + x: bounds.x(), + y: bounds.y(), + width: bounds.width(), + height: bounds.height(), + } + translation) + * scale_factor), + ) { + return; + } + pixels.fill_path( path, paint, @@ -282,7 +342,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - clip_bounds.map(|_| clip_mask as &_), + Some(clip_mask), ); } Primitive::Stroke { @@ -291,6 +351,20 @@ impl Backend { stroke, transform, } => { + let bounds = path.bounds(); + + if !clip_bounds.intersects( + &((Rectangle { + x: bounds.x(), + y: bounds.y(), + width: bounds.width(), + height: bounds.height(), + } + translation) + * scale_factor), + ) { + return; + } + pixels.stroke_path( path, paint, @@ -298,7 +372,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - clip_bounds.map(|_| clip_mask as &_), + Some(clip_mask), ); } Primitive::Group { primitives } => { @@ -310,7 +384,6 @@ impl Backend { clip_bounds, scale_factor, translation, - damage, ); } } @@ -325,7 +398,6 @@ impl Backend { clip_bounds, scale_factor, translation + *offset, - damage, ); } Primitive::Clip { bounds, content } => { @@ -339,22 +411,19 @@ impl Backend { return; } - adjust_clip_mask(clip_mask, pixels, bounds); + if let Some(bounds) = clip_bounds.intersection(&bounds) { + adjust_clip_mask(clip_mask, pixels, bounds); - self.draw_primitive( - content, - pixels, - clip_mask, - Some(bounds), - scale_factor, - translation, - damage, - ); + self.draw_primitive( + content, + pixels, + clip_mask, + bounds, + scale_factor, + translation, + ); - if let Some(bounds) = clip_bounds { - adjust_clip_mask(clip_mask, pixels, bounds); - } else { - clip_mask.clear(); + adjust_clip_mask(clip_mask, pixels, clip_bounds); } } Primitive::Cache { content } => { @@ -365,7 +434,6 @@ impl Backend { clip_bounds, scale_factor, translation, - damage, ); } Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => { -- 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 --- tiny_skia/src/backend.rs | 275 +++++++++++++++++++++++++++++------------------ tiny_skia/src/text.rs | 16 ++- 2 files changed, 184 insertions(+), 107 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 8101082a..b1417409 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -49,7 +49,7 @@ impl Backend { primitives: &[Primitive], viewport: &Viewport, background_color: Color, - _overlay: &[T], + overlay: &[T], ) { let physical_size = viewport.physical_size(); @@ -70,37 +70,20 @@ impl Backend { self.last_size = physical_size; let scale_factor = viewport.scale_factor() as f32; - let physical_bounds = Rectangle { - x: 0.0, - y: 0.0, - width: physical_size.width as f32, - height: physical_size.height as f32, - }; - - dbg!(damage.len()); - 'draw_regions: for (i, region) in damage.iter().enumerate() { - for previous in damage.iter().take(i) { - if previous.contains(region.position()) - && previous.contains( - region.position() - + Vector::new(region.width, region.height), - ) - { - continue 'draw_regions; - } - } + let damage = group_damage(damage, scale_factor, physical_size); - let region = *region * scale_factor; - - let Some(region) = physical_bounds.intersection(®ion) else { continue }; + if !overlay.is_empty() { + pixels.fill(into_color(background_color)); + } + for region in damage { let path = tiny_skia::PathBuilder::from_rect( tiny_skia::Rect::from_xywh( region.x, region.y, - region.width.min(viewport.physical_width() as f32), - region.height.min(viewport.physical_height() as f32), + region.width, + region.height, ) .expect("Create damage rectangle"), ); @@ -111,6 +94,7 @@ impl Backend { shader: tiny_skia::Shader::SolidColor(into_color( background_color, )), + anti_alias: false, ..Default::default() }, tiny_skia::FillRule::default(), @@ -131,49 +115,62 @@ impl Backend { ); } - //pixels.stroke_path( - // &path, - // &tiny_skia::Paint { - // shader: tiny_skia::Shader::SolidColor(into_color( - // Color::from_rgb(1.0, 0.0, 0.0), - // )), - // anti_alias: true, - // ..tiny_skia::Paint::default() - // }, - // &tiny_skia::Stroke { - // width: 1.0, - // ..tiny_skia::Stroke::default() - // }, - // tiny_skia::Transform::identity(), - // None, - //); + if !overlay.is_empty() { + pixels.stroke_path( + &path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color( + Color::from_rgb(1.0, 0.0, 0.0), + )), + anti_alias: false, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: 1.0, + ..tiny_skia::Stroke::default() + }, + tiny_skia::Transform::identity(), + None, + ); + } } - //for (i, text) in overlay.iter().enumerate() { - // const OVERLAY_TEXT_SIZE: f32 = 20.0; - - // self.draw_primitive( - // &Primitive::Text { - // content: text.as_ref().to_owned(), - // size: OVERLAY_TEXT_SIZE, - // bounds: Rectangle { - // x: 10.0, - // y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, - // width: f32::INFINITY, - // height: f32::INFINITY, - // }, - // color: Color::BLACK, - // font: Font::MONOSPACE, - // horizontal_alignment: alignment::Horizontal::Left, - // vertical_alignment: alignment::Vertical::Top, - // }, - // pixels, - // clip_mask, - // Rectangle::EMPTY, - // scale_factor, - // Vector::ZERO, - // ); - //} + if !overlay.is_empty() { + let bounds = Rectangle { + x: 0.0, + y: 0.0, + width: viewport.physical_width() as f32, + height: viewport.physical_height() as f32, + }; + + adjust_clip_mask(clip_mask, pixels, bounds); + + for (i, text) in overlay.iter().enumerate() { + const OVERLAY_TEXT_SIZE: f32 = 20.0; + + self.draw_primitive( + &Primitive::Text { + content: text.as_ref().to_owned(), + size: OVERLAY_TEXT_SIZE, + bounds: Rectangle { + x: 10.0, + y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, + width: bounds.width - 1.0, + height: bounds.height - 1.0, + }, + color: Color::BLACK, + font: Font::MONOSPACE, + horizontal_alignment: alignment::Horizontal::Left, + vertical_alignment: alignment::Vertical::Top, + }, + pixels, + clip_mask, + bounds, + scale_factor, + Vector::ZERO, + ); + } + } self.text_pipeline.trim_cache(); @@ -201,12 +198,15 @@ impl Backend { border_width, border_color, } => { - if !clip_bounds - .intersects(&((*bounds + translation) * scale_factor)) - { + let physical_bounds = (*bounds + translation) * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then(|| clip_mask as &_); + let transform = tiny_skia::Transform::from_translate( translation.x, translation.y, @@ -230,7 +230,7 @@ impl Backend { }, tiny_skia::FillRule::EvenOdd, transform, - Some(clip_mask), + clip_mask, ); if *border_width > 0.0 { @@ -248,7 +248,7 @@ impl Backend { ..tiny_skia::Stroke::default() }, transform, - Some(clip_mask), + clip_mask, ); } } @@ -261,12 +261,16 @@ impl Backend { horizontal_alignment, vertical_alignment, } => { - if !clip_bounds.intersects( - &((primitive.bounds() + translation) * scale_factor), - ) { + let physical_bounds = + (primitive.bounds() + translation) * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then(|| clip_mask as &_); + self.text_pipeline.draw( content, (*bounds + translation) * scale_factor, @@ -276,7 +280,7 @@ impl Backend { *horizontal_alignment, *vertical_alignment, pixels, - Some(clip_mask), + clip_mask, ); } #[cfg(feature = "image")] @@ -323,18 +327,21 @@ impl Backend { } => { let bounds = path.bounds(); - if !clip_bounds.intersects( - &((Rectangle { - x: bounds.x(), - y: bounds.y(), - width: bounds.width(), - height: bounds.height(), - } + translation) - * scale_factor), - ) { + let physical_bounds = (Rectangle { + x: bounds.x(), + y: bounds.y(), + width: bounds.width(), + height: bounds.height(), + } + translation) + * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then(|| clip_mask as &_); + pixels.fill_path( path, paint, @@ -342,7 +349,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - Some(clip_mask), + clip_mask, ); } Primitive::Stroke { @@ -353,18 +360,21 @@ impl Backend { } => { let bounds = path.bounds(); - if !clip_bounds.intersects( - &((Rectangle { - x: bounds.x(), - y: bounds.y(), - width: bounds.width(), - height: bounds.height(), - } + translation) - * scale_factor), - ) { + let physical_bounds = (Rectangle { + x: bounds.x(), + y: bounds.y(), + width: bounds.width(), + height: bounds.height(), + } + translation) + * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then(|| clip_mask as &_); + pixels.stroke_path( path, paint, @@ -372,7 +382,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - Some(clip_mask), + clip_mask, ); } Primitive::Group { primitives } => { @@ -403,15 +413,26 @@ impl Backend { Primitive::Clip { bounds, content } => { let bounds = (*bounds + translation) * scale_factor; - if bounds.x + bounds.width <= 0.0 - || bounds.y + bounds.height <= 0.0 - || bounds.x as u32 >= pixels.width() - || bounds.y as u32 >= pixels.height() - { - return; - } + if bounds == clip_bounds { + self.draw_primitive( + content, + pixels, + clip_mask, + bounds, + scale_factor, + translation, + ); + } else if let Some(bounds) = clip_bounds.intersection(&bounds) { + if bounds.x + bounds.width <= 0.0 + || bounds.y + bounds.height <= 0.0 + || bounds.x as u32 >= pixels.width() + || bounds.y as u32 >= pixels.height() + || bounds.width <= 1.0 + || bounds.height <= 1.0 + { + return; + } - if let Some(bounds) = clip_bounds.intersection(&bounds) { adjust_clip_mask(clip_mask, pixels, bounds); self.draw_primitive( @@ -614,11 +635,57 @@ fn adjust_clip_mask( pixels.height(), &path, tiny_skia::FillRule::EvenOdd, - true, + false, ) .expect("Set path of clipping area"); } +fn group_damage( + 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 +} + impl iced_graphics::Backend for Backend { fn trim_measurements(&mut self) { self.text_pipeline.trim_measurement_cache(); diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs index 865132b4..512503e0 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -336,6 +336,7 @@ struct Cache { entries: FxHashMap, recently_used: FxHashSet, hasher: HashBuilder, + trim_count: usize, } #[cfg(not(target_arch = "wasm32"))] @@ -345,11 +346,14 @@ type HashBuilder = twox_hash::RandomXxHashBuilder64; type HashBuilder = std::hash::BuildHasherDefault; impl Cache { + const TRIM_INTERVAL: usize = 300; + fn new() -> Self { Self { entries: FxHashMap::default(), recently_used: FxHashSet::default(), hasher: HashBuilder::default(), + trim_count: 0, } } @@ -404,10 +408,16 @@ impl Cache { } fn trim(&mut self) { - self.entries - .retain(|key, _| self.recently_used.contains(key)); + if self.trim_count > Self::TRIM_INTERVAL { + self.entries + .retain(|key, _| self.recently_used.contains(key)); - self.recently_used.clear(); + self.recently_used.clear(); + + self.trim_count = 0; + } else { + self.trim_count += 1; + } } } -- cgit From 1bba9a080f796276d5da87bf8decd2ed89ef218a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 05:49:30 +0200 Subject: Fix `Svg` and `Image` primitives in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index b1417409..8bc2321c 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -205,7 +205,7 @@ impl Backend { } let clip_mask = (!physical_bounds.is_within(&clip_bounds)) - .then(|| clip_mask as &_); + .then_some(clip_mask as &_); let transform = tiny_skia::Transform::from_translate( translation.x, @@ -269,7 +269,7 @@ impl Backend { } let clip_mask = (!physical_bounds.is_within(&clip_bounds)) - .then(|| clip_mask as &_); + .then_some(clip_mask as &_); self.text_pipeline.draw( content, @@ -285,25 +285,23 @@ impl Backend { } #[cfg(feature = "image")] Primitive::Image { handle, bounds } => { - if !clip_bounds - .intersects(&((*bounds + translation) * scale_factor)) - { + let physical_bounds = (*bounds + translation) * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then_some(clip_mask as &_); + let transform = tiny_skia::Transform::from_translate( translation.x, translation.y, ) .post_scale(scale_factor, scale_factor); - self.raster_pipeline.draw( - handle, - *bounds, - pixels, - transform, - Some(clip_mask), - ); + self.raster_pipeline + .draw(handle, *bounds, pixels, transform, clip_mask); } #[cfg(feature = "svg")] Primitive::Svg { @@ -311,12 +309,21 @@ impl Backend { bounds, color, } => { + let physical_bounds = (*bounds + translation) * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { + return; + } + + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then_some(clip_mask as &_); + self.vector_pipeline.draw( handle, *color, (*bounds + translation) * scale_factor, pixels, - clip_bounds.map(|_| clip_mask as &_), + clip_mask, ); } Primitive::Fill { @@ -340,7 +347,7 @@ impl Backend { } let clip_mask = (!physical_bounds.is_within(&clip_bounds)) - .then(|| clip_mask as &_); + .then_some(clip_mask as &_); pixels.fill_path( path, @@ -373,7 +380,7 @@ impl Backend { } let clip_mask = (!physical_bounds.is_within(&clip_bounds)) - .then(|| clip_mask as &_); + .then_some(clip_mask as &_); pixels.stroke_path( path, -- cgit From 4ede482ab5ff6364237f5f4626784075045d5dfb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 18:41:40 +0200 Subject: Present new frame only when damaged in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 6 ++++-- tiny_skia/src/window/compositor.rs | 14 ++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 8bc2321c..0b534bba 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -50,7 +50,7 @@ impl Backend { viewport: &Viewport, background_color: Color, overlay: &[T], - ) { + ) -> bool { let physical_size = viewport.physical_size(); let damage = if self.last_background_color == background_color @@ -62,7 +62,7 @@ impl Backend { }; if damage.is_empty() { - return; + return false; } self.last_primitives = primitives.to_vec(); @@ -179,6 +179,8 @@ impl Backend { #[cfg(feature = "svg")] self.vector_pipeline.trim_cache(); + + true } fn draw_primitive( diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index cea1cabf..6e4bb6ef 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -106,7 +106,7 @@ pub fn present>( ) -> Result<(), compositor::SurfaceError> { let physical_size = viewport.physical_size(); - backend.draw( + let drawn = backend.draw( &mut tiny_skia::PixmapMut::from_bytes( bytemuck::cast_slice_mut(&mut surface.buffer), physical_size.width, @@ -120,11 +120,13 @@ pub fn present>( overlay, ); - surface.window.set_buffer( - &surface.buffer, - physical_size.width as u16, - physical_size.height as u16, - ); + if drawn { + surface.window.set_buffer( + &surface.buffer, + physical_size.width as u16, + physical_size.height as u16, + ); + } Ok(()) } -- cgit From e134a82f4ca67346fc9095a0d488122737cfb0d8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 18:42:27 +0200 Subject: Switch debug mode to fade old primitives and display damage in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 97 ++++++++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 37 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 0b534bba..974faa74 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -74,7 +74,30 @@ impl Backend { let damage = group_damage(damage, scale_factor, physical_size); if !overlay.is_empty() { - pixels.fill(into_color(background_color)); + let path = tiny_skia::PathBuilder::from_rect( + tiny_skia::Rect::from_xywh( + 0.0, + 0.0, + physical_size.width as f32, + physical_size.height as f32, + ) + .expect("Create damage rectangle"), + ); + + pixels.fill_path( + &path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color(Color { + a: 0.1, + ..background_color + })), + anti_alias: false, + ..Default::default() + }, + tiny_skia::FillRule::default(), + tiny_skia::Transform::identity(), + None, + ); } for region in damage { @@ -135,42 +158,42 @@ impl Backend { } } - if !overlay.is_empty() { - let bounds = Rectangle { - x: 0.0, - y: 0.0, - width: viewport.physical_width() as f32, - height: viewport.physical_height() as f32, - }; - - adjust_clip_mask(clip_mask, pixels, bounds); - - for (i, text) in overlay.iter().enumerate() { - const OVERLAY_TEXT_SIZE: f32 = 20.0; - - self.draw_primitive( - &Primitive::Text { - content: text.as_ref().to_owned(), - size: OVERLAY_TEXT_SIZE, - bounds: Rectangle { - x: 10.0, - y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, - width: bounds.width - 1.0, - height: bounds.height - 1.0, - }, - color: Color::BLACK, - font: Font::MONOSPACE, - horizontal_alignment: alignment::Horizontal::Left, - vertical_alignment: alignment::Vertical::Top, - }, - pixels, - clip_mask, - bounds, - scale_factor, - Vector::ZERO, - ); - } - } + //if !overlay.is_empty() { + // let bounds = Rectangle { + // x: 0.0, + // y: 0.0, + // width: viewport.physical_width() as f32, + // height: viewport.physical_height() as f32, + // }; + + // adjust_clip_mask(clip_mask, pixels, bounds); + + // for (i, text) in overlay.iter().enumerate() { + // const OVERLAY_TEXT_SIZE: f32 = 20.0; + + // self.draw_primitive( + // &Primitive::Text { + // content: text.as_ref().to_owned(), + // size: OVERLAY_TEXT_SIZE, + // bounds: Rectangle { + // x: 10.0, + // y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, + // width: bounds.width - 1.0, + // height: bounds.height - 1.0, + // }, + // color: Color::BLACK, + // font: Font::MONOSPACE, + // horizontal_alignment: alignment::Horizontal::Left, + // vertical_alignment: alignment::Vertical::Top, + // }, + // pixels, + // clip_mask, + // bounds, + // scale_factor, + // Vector::ZERO, + // ); + // } + //} self.text_pipeline.trim_cache(); -- cgit From 92d61e5c592818745abbab245a82cb14b262ae67 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 19:23:48 +0200 Subject: Use `softbuffer` fork with owned pixel buffer --- tiny_skia/src/window/compositor.rs | 42 +++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 16 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 6e4bb6ef..5b1e56a4 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -5,6 +5,7 @@ use crate::{Backend, Renderer, Settings}; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use std::marker::PhantomData; +use std::num::NonZeroU32; pub struct Compositor { clip_mask: tiny_skia::ClipMask, @@ -12,8 +13,7 @@ pub struct Compositor { } pub struct Surface { - window: softbuffer::GraphicsContext, - buffer: Vec, + window: softbuffer::Surface, } impl crate::graphics::Compositor for Compositor { @@ -36,14 +36,20 @@ impl crate::graphics::Compositor for Compositor { width: u32, height: u32, ) -> Surface { - let window = - unsafe { softbuffer::GraphicsContext::new(window, window) } - .expect("Create softbuffer for window"); + let platform = unsafe { softbuffer::Context::new(window) } + .expect("Create softbuffer context"); - Surface { - window, - buffer: vec![0; width as usize * height as usize], - } + let mut window = unsafe { softbuffer::Surface::new(&platform, window) } + .expect("Create softbuffer surface"); + + window + .resize( + NonZeroU32::new(width).unwrap(), + NonZeroU32::new(height).unwrap(), + ) + .expect("Resize surface"); + + Surface { window } } fn configure_surface( @@ -52,7 +58,13 @@ impl crate::graphics::Compositor for Compositor { width: u32, height: u32, ) { - surface.buffer.resize((width * height) as usize, 0); + surface + .window + .resize( + NonZeroU32::new(width).unwrap(), + NonZeroU32::new(height).unwrap(), + ) + .expect("Resize surface"); } fn fetch_information(&self) -> Information { @@ -106,9 +118,11 @@ pub fn present>( ) -> Result<(), compositor::SurfaceError> { let physical_size = viewport.physical_size(); + let mut buffer = surface.window.buffer_mut().expect("Get window buffer"); + let drawn = backend.draw( &mut tiny_skia::PixmapMut::from_bytes( - bytemuck::cast_slice_mut(&mut surface.buffer), + bytemuck::cast_slice_mut(&mut buffer), physical_size.width, physical_size.height, ) @@ -121,11 +135,7 @@ pub fn present>( ); if drawn { - surface.window.set_buffer( - &surface.buffer, - physical_size.width as u16, - physical_size.height as u16, - ); + let _ = buffer.present(); } Ok(()) -- cgit From 940a47eafd098dce3567a95c38dc8697b0fc7115 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 19:30:07 +0200 Subject: Revert "Use `softbuffer` fork with owned pixel buffer" This reverts commit 92d61e5c592818745abbab245a82cb14b262ae67. The owned pixel buffer zeroes the data in some platforms. `softbuffer` will need some first-class support for damage regions. --- tiny_skia/src/window/compositor.rs | 42 +++++++++++++++----------------------- 1 file changed, 16 insertions(+), 26 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 5b1e56a4..6e4bb6ef 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -5,7 +5,6 @@ use crate::{Backend, Renderer, Settings}; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use std::marker::PhantomData; -use std::num::NonZeroU32; pub struct Compositor { clip_mask: tiny_skia::ClipMask, @@ -13,7 +12,8 @@ pub struct Compositor { } pub struct Surface { - window: softbuffer::Surface, + window: softbuffer::GraphicsContext, + buffer: Vec, } impl crate::graphics::Compositor for Compositor { @@ -36,20 +36,14 @@ impl crate::graphics::Compositor for Compositor { width: u32, height: u32, ) -> Surface { - let platform = unsafe { softbuffer::Context::new(window) } - .expect("Create softbuffer context"); + let window = + unsafe { softbuffer::GraphicsContext::new(window, window) } + .expect("Create softbuffer for window"); - let mut window = unsafe { softbuffer::Surface::new(&platform, window) } - .expect("Create softbuffer surface"); - - window - .resize( - NonZeroU32::new(width).unwrap(), - NonZeroU32::new(height).unwrap(), - ) - .expect("Resize surface"); - - Surface { window } + Surface { + window, + buffer: vec![0; width as usize * height as usize], + } } fn configure_surface( @@ -58,13 +52,7 @@ impl crate::graphics::Compositor for Compositor { width: u32, height: u32, ) { - surface - .window - .resize( - NonZeroU32::new(width).unwrap(), - NonZeroU32::new(height).unwrap(), - ) - .expect("Resize surface"); + surface.buffer.resize((width * height) as usize, 0); } fn fetch_information(&self) -> Information { @@ -118,11 +106,9 @@ pub fn present>( ) -> Result<(), compositor::SurfaceError> { let physical_size = viewport.physical_size(); - let mut buffer = surface.window.buffer_mut().expect("Get window buffer"); - let drawn = backend.draw( &mut tiny_skia::PixmapMut::from_bytes( - bytemuck::cast_slice_mut(&mut buffer), + bytemuck::cast_slice_mut(&mut surface.buffer), physical_size.width, physical_size.height, ) @@ -135,7 +121,11 @@ pub fn present>( ); if drawn { - let _ = buffer.present(); + surface.window.set_buffer( + &surface.buffer, + physical_size.width as u16, + physical_size.height as u16, + ); } Ok(()) -- cgit From 16e6efe020e75d51958875fa198196534679af8d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 8 Apr 2023 05:58:27 +0200 Subject: Use `pixels` for presentation in `iced_tiny_skia` when possible --- tiny_skia/src/window/compositor.rs | 76 +++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 13 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 6e4bb6ef..5a0097df 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -11,9 +11,13 @@ pub struct Compositor { _theme: PhantomData, } -pub struct Surface { - window: softbuffer::GraphicsContext, - buffer: Vec, +pub enum Surface { + Cpu { + window: softbuffer::GraphicsContext, + buffer: Vec, + }, + #[cfg(feature = "gpu")] + Gpu { pixels: pixels::Pixels }, } impl crate::graphics::Compositor for Compositor { @@ -36,11 +40,29 @@ impl crate::graphics::Compositor for Compositor { width: u32, height: u32, ) -> Surface { + #[cfg(feature = "gpu")] + { + let surface_texture = + pixels::SurfaceTexture::new(width, height, window); + + if let Ok(pixels) = + pixels::PixelsBuilder::new(width, height, surface_texture) + .texture_format(pixels::wgpu::TextureFormat::Bgra8UnormSrgb) + .build() + { + log::info!("GPU surface created"); + + return Surface::Gpu { pixels }; + } + } + let window = unsafe { softbuffer::GraphicsContext::new(window, window) } .expect("Create softbuffer for window"); - Surface { + log::info!("CPU surface created"); + + Surface::Cpu { window, buffer: vec![0; width as usize * height as usize], } @@ -52,7 +74,19 @@ impl crate::graphics::Compositor for Compositor { width: u32, height: u32, ) { - surface.buffer.resize((width * height) as usize, 0); + match surface { + Surface::Cpu { buffer, .. } => { + buffer.resize((width * height) as usize, 0); + } + #[cfg(feature = "gpu")] + Surface::Gpu { pixels } => { + pixels + .resize_surface(width, height) + .expect("Resize surface"); + + pixels.resize_buffer(width, height).expect("Resize buffer"); + } + } } fn fetch_information(&self) -> Information { @@ -106,9 +140,15 @@ pub fn present>( ) -> Result<(), compositor::SurfaceError> { let physical_size = viewport.physical_size(); + let buffer = match surface { + Surface::Cpu { buffer, .. } => bytemuck::cast_slice_mut(buffer), + #[cfg(feature = "gpu")] + Surface::Gpu { pixels } => pixels.frame_mut(), + }; + let drawn = backend.draw( &mut tiny_skia::PixmapMut::from_bytes( - bytemuck::cast_slice_mut(&mut surface.buffer), + buffer, physical_size.width, physical_size.height, ) @@ -121,12 +161,22 @@ pub fn present>( ); if drawn { - surface.window.set_buffer( - &surface.buffer, - physical_size.width as u16, - physical_size.height as u16, - ); + match surface { + Surface::Cpu { window, buffer } => { + window.set_buffer( + buffer, + physical_size.width as u16, + physical_size.height as u16, + ); + + Ok(()) + } + #[cfg(feature = "gpu")] + Surface::Gpu { pixels } => { + pixels.render().map_err(|_| compositor::SurfaceError::Lost) + } + } + } else { + Ok(()) } - - Ok(()) } -- cgit From 435b54e57ecdaf08b1f36626f0000438895c909d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 26 Apr 2023 16:09:36 +0200 Subject: Revert "Use `pixels` for presentation in `iced_tiny_skia` when possible" This reverts commit 16e6efe020e75d51958875fa198196534679af8d. --- tiny_skia/src/window/compositor.rs | 76 +++++++------------------------------- 1 file changed, 13 insertions(+), 63 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 5a0097df..6e4bb6ef 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -11,13 +11,9 @@ pub struct Compositor { _theme: PhantomData, } -pub enum Surface { - Cpu { - window: softbuffer::GraphicsContext, - buffer: Vec, - }, - #[cfg(feature = "gpu")] - Gpu { pixels: pixels::Pixels }, +pub struct Surface { + window: softbuffer::GraphicsContext, + buffer: Vec, } impl crate::graphics::Compositor for Compositor { @@ -40,29 +36,11 @@ impl crate::graphics::Compositor for Compositor { width: u32, height: u32, ) -> Surface { - #[cfg(feature = "gpu")] - { - let surface_texture = - pixels::SurfaceTexture::new(width, height, window); - - if let Ok(pixels) = - pixels::PixelsBuilder::new(width, height, surface_texture) - .texture_format(pixels::wgpu::TextureFormat::Bgra8UnormSrgb) - .build() - { - log::info!("GPU surface created"); - - return Surface::Gpu { pixels }; - } - } - let window = unsafe { softbuffer::GraphicsContext::new(window, window) } .expect("Create softbuffer for window"); - log::info!("CPU surface created"); - - Surface::Cpu { + Surface { window, buffer: vec![0; width as usize * height as usize], } @@ -74,19 +52,7 @@ impl crate::graphics::Compositor for Compositor { width: u32, height: u32, ) { - match surface { - Surface::Cpu { buffer, .. } => { - buffer.resize((width * height) as usize, 0); - } - #[cfg(feature = "gpu")] - Surface::Gpu { pixels } => { - pixels - .resize_surface(width, height) - .expect("Resize surface"); - - pixels.resize_buffer(width, height).expect("Resize buffer"); - } - } + surface.buffer.resize((width * height) as usize, 0); } fn fetch_information(&self) -> Information { @@ -140,15 +106,9 @@ pub fn present>( ) -> Result<(), compositor::SurfaceError> { let physical_size = viewport.physical_size(); - let buffer = match surface { - Surface::Cpu { buffer, .. } => bytemuck::cast_slice_mut(buffer), - #[cfg(feature = "gpu")] - Surface::Gpu { pixels } => pixels.frame_mut(), - }; - let drawn = backend.draw( &mut tiny_skia::PixmapMut::from_bytes( - buffer, + bytemuck::cast_slice_mut(&mut surface.buffer), physical_size.width, physical_size.height, ) @@ -161,22 +121,12 @@ pub fn present>( ); if drawn { - match surface { - Surface::Cpu { window, buffer } => { - window.set_buffer( - buffer, - physical_size.width as u16, - physical_size.height as u16, - ); - - Ok(()) - } - #[cfg(feature = "gpu")] - Surface::Gpu { pixels } => { - pixels.render().map_err(|_| compositor::SurfaceError::Lost) - } - } - } else { - Ok(()) + surface.window.set_buffer( + &surface.buffer, + physical_size.width as u16, + physical_size.height as u16, + ); } + + Ok(()) } -- cgit From f0fa5f76cb0b0e451b3fc86b1678403c103867e4 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 26 Apr 2023 16:15:53 +0200 Subject: Remove `debug` overlay from `iced_tiny_skia` for now --- tiny_skia/src/backend.rs | 38 -------------------------------------- 1 file changed, 38 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 974faa74..756e46b3 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,4 +1,3 @@ -use crate::core::alignment; use crate::core::text; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::graphics::backend; @@ -158,43 +157,6 @@ impl Backend { } } - //if !overlay.is_empty() { - // let bounds = Rectangle { - // x: 0.0, - // y: 0.0, - // width: viewport.physical_width() as f32, - // height: viewport.physical_height() as f32, - // }; - - // adjust_clip_mask(clip_mask, pixels, bounds); - - // for (i, text) in overlay.iter().enumerate() { - // const OVERLAY_TEXT_SIZE: f32 = 20.0; - - // self.draw_primitive( - // &Primitive::Text { - // content: text.as_ref().to_owned(), - // size: OVERLAY_TEXT_SIZE, - // bounds: Rectangle { - // x: 10.0, - // y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, - // width: bounds.width - 1.0, - // height: bounds.height - 1.0, - // }, - // color: Color::BLACK, - // font: Font::MONOSPACE, - // horizontal_alignment: alignment::Horizontal::Left, - // vertical_alignment: alignment::Vertical::Top, - // }, - // pixels, - // clip_mask, - // bounds, - // scale_factor, - // Vector::ZERO, - // ); - // } - //} - self.text_pipeline.trim_cache(); #[cfg(feature = "image")] -- cgit From 9c63eb7df559e58b14188b4096e9bd206444bbf3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 26 Apr 2023 16:46:27 +0200 Subject: Update `tiny-skia` and `resvg` --- tiny_skia/src/backend.rs | 33 ++++++++++++++------------------- tiny_skia/src/raster.rs | 2 +- tiny_skia/src/text.rs | 2 +- tiny_skia/src/vector.rs | 8 +++++--- tiny_skia/src/window/compositor.rs | 14 +++++++------- 5 files changed, 28 insertions(+), 31 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 756e46b3..16a7f9b8 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -44,7 +44,7 @@ impl Backend { pub fn draw>( &mut self, pixels: &mut tiny_skia::PixmapMut<'_>, - clip_mask: &mut tiny_skia::ClipMask, + clip_mask: &mut tiny_skia::Mask, primitives: &[Primitive], viewport: &Viewport, background_color: Color, @@ -124,7 +124,7 @@ impl Backend { None, ); - adjust_clip_mask(clip_mask, pixels, region); + adjust_clip_mask(clip_mask, region); for primitive in primitives { self.draw_primitive( @@ -172,7 +172,7 @@ impl Backend { &mut self, primitive: &Primitive, pixels: &mut tiny_skia::PixmapMut<'_>, - clip_mask: &mut tiny_skia::ClipMask, + clip_mask: &mut tiny_skia::Mask, clip_bounds: Rectangle, scale_factor: f32, translation: Vector, @@ -427,7 +427,7 @@ impl Backend { return; } - adjust_clip_mask(clip_mask, pixels, bounds); + adjust_clip_mask(clip_mask, bounds); self.draw_primitive( content, @@ -438,7 +438,7 @@ impl Backend { translation, ); - adjust_clip_mask(clip_mask, pixels, clip_bounds); + adjust_clip_mask(clip_mask, clip_bounds); } } Primitive::Cache { content } => { @@ -611,11 +611,9 @@ fn arc_to( } } -fn adjust_clip_mask( - clip_mask: &mut tiny_skia::ClipMask, - pixels: &tiny_skia::PixmapMut<'_>, - bounds: Rectangle, -) { +fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) { + clip_mask.clear(); + let path = { let mut builder = tiny_skia::PathBuilder::new(); builder.push_rect(bounds.x, bounds.y, bounds.width, bounds.height); @@ -623,15 +621,12 @@ fn adjust_clip_mask( builder.finish().unwrap() }; - clip_mask - .set_path( - pixels.width(), - pixels.height(), - &path, - tiny_skia::FillRule::EvenOdd, - false, - ) - .expect("Set path of clipping area"); + clip_mask.fill_path( + &path, + tiny_skia::FillRule::EvenOdd, + false, + tiny_skia::Transform::default(), + ); } fn group_damage( diff --git a/tiny_skia/src/raster.rs b/tiny_skia/src/raster.rs index 2fd73f8c..3887ec8d 100644 --- a/tiny_skia/src/raster.rs +++ b/tiny_skia/src/raster.rs @@ -31,7 +31,7 @@ impl Pipeline { bounds: Rectangle, pixels: &mut tiny_skia::PixmapMut<'_>, transform: tiny_skia::Transform, - clip_mask: Option<&tiny_skia::ClipMask>, + clip_mask: Option<&tiny_skia::Mask>, ) { if let Some(image) = self.cache.borrow_mut().allocate(handle) { let width_scale = bounds.width / image.width() as f32; diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs index f5994d09..1246bbd5 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -50,7 +50,7 @@ impl Pipeline { horizontal_alignment: alignment::Horizontal, vertical_alignment: alignment::Vertical, pixels: &mut tiny_skia::PixmapMut<'_>, - clip_mask: Option<&tiny_skia::ClipMask>, + clip_mask: Option<&tiny_skia::Mask>, ) { let font_system = self.font_system.get_mut(); let key = Key { diff --git a/tiny_skia/src/vector.rs b/tiny_skia/src/vector.rs index 8509b761..fc411fdd 100644 --- a/tiny_skia/src/vector.rs +++ b/tiny_skia/src/vector.rs @@ -32,7 +32,7 @@ impl Pipeline { color: Option, bounds: Rectangle, pixels: &mut tiny_skia::PixmapMut<'_>, - clip_mask: Option<&tiny_skia::ClipMask>, + clip_mask: Option<&tiny_skia::Mask>, ) { if let Some(image) = self.cache.borrow_mut().draw( handle, @@ -72,6 +72,8 @@ struct RasterKey { impl Cache { fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> { + use usvg::TreeParsing; + let id = handle.id(); if let hash_map::Entry::Vacant(entry) = self.trees.entry(id) { @@ -131,9 +133,9 @@ impl Cache { resvg::render( tree, if size.width > size.height { - usvg::FitTo::Width(size.width) + resvg::FitTo::Width(size.width) } else { - usvg::FitTo::Height(size.height) + resvg::FitTo::Height(size.height) }, tiny_skia::Transform::default(), image.as_mut(), diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 6e4bb6ef..7523e06f 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -7,13 +7,13 @@ use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use std::marker::PhantomData; pub struct Compositor { - clip_mask: tiny_skia::ClipMask, _theme: PhantomData, } pub struct Surface { window: softbuffer::GraphicsContext, buffer: Vec, + clip_mask: tiny_skia::Mask, } impl crate::graphics::Compositor for Compositor { @@ -43,6 +43,8 @@ impl crate::graphics::Compositor for Compositor { Surface { window, buffer: vec![0; width as usize * height as usize], + clip_mask: tiny_skia::Mask::new(width, height) + .expect("Create clip mask"), } } @@ -53,6 +55,8 @@ impl crate::graphics::Compositor for Compositor { height: u32, ) { surface.buffer.resize((width * height) as usize, 0); + surface.clip_mask = + tiny_skia::Mask::new(width, height).expect("Create clip mask"); } fn fetch_information(&self) -> Information { @@ -72,7 +76,6 @@ impl crate::graphics::Compositor for Compositor { ) -> Result<(), SurfaceError> { renderer.with_primitives(|backend, primitives| { present( - self, backend, surface, primitives, @@ -85,18 +88,15 @@ impl crate::graphics::Compositor for Compositor { } pub fn new(settings: Settings) -> (Compositor, Backend) { - // TOD ( Compositor { - clip_mask: tiny_skia::ClipMask::new(), _theme: PhantomData, }, Backend::new(settings), ) } -pub fn present>( - compositor: &mut Compositor, +pub fn present>( backend: &mut Backend, surface: &mut Surface, primitives: &[Primitive], @@ -113,7 +113,7 @@ pub fn present>( physical_size.height, ) .expect("Create pixel map"), - &mut compositor.clip_mask, + &mut surface.clip_mask, primitives, viewport, background_color, -- 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` --- tiny_skia/src/backend.rs | 80 ++------------------------------------ tiny_skia/src/window/compositor.rs | 54 ++++++++++++++++++------- 2 files changed, 42 insertions(+), 92 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 16a7f9b8..9c69e1d2 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -16,10 +16,6 @@ pub struct Backend { #[cfg(feature = "svg")] vector_pipeline: crate::vector::Pipeline, - - last_primitives: Vec, - last_background_color: Color, - last_size: Size, } impl Backend { @@ -34,10 +30,6 @@ impl Backend { #[cfg(feature = "svg")] vector_pipeline: crate::vector::Pipeline::new(), - - last_primitives: Vec::new(), - last_background_color: Color::BLACK, - last_size: Size::new(0, 0), } } @@ -47,31 +39,13 @@ impl Backend { clip_mask: &mut tiny_skia::Mask, primitives: &[Primitive], viewport: &Viewport, + damage: &[Rectangle], background_color: Color, overlay: &[T], - ) -> bool { + ) { let physical_size = viewport.physical_size(); - - let damage = if self.last_background_color == background_color - && self.last_size == physical_size - { - Primitive::damage_list(&self.last_primitives, primitives) - } else { - vec![Rectangle::with_size(viewport.logical_size())] - }; - - if damage.is_empty() { - return false; - } - - self.last_primitives = primitives.to_vec(); - self.last_background_color = background_color; - self.last_size = physical_size; - let scale_factor = viewport.scale_factor() as f32; - let damage = group_damage(damage, scale_factor, physical_size); - if !overlay.is_empty() { let path = tiny_skia::PathBuilder::from_rect( tiny_skia::Rect::from_xywh( @@ -99,7 +73,7 @@ impl Backend { ); } - for region in damage { + for ®ion in damage { let path = tiny_skia::PathBuilder::from_rect( tiny_skia::Rect::from_xywh( region.x, @@ -164,8 +138,6 @@ impl Backend { #[cfg(feature = "svg")] self.vector_pipeline.trim_cache(); - - true } fn draw_primitive( @@ -629,52 +601,6 @@ fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) { ); } -fn group_damage( - 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 -} - impl iced_graphics::Backend for Backend { fn trim_measurements(&mut self) { self.text_pipeline.trim_measurement_cache(); diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 7523e06f..d3dffb18 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -1,5 +1,6 @@ -use crate::core::Color; +use crate::core::{Color, Rectangle}; use crate::graphics::compositor::{self, Information, SurfaceError}; +use crate::graphics::damage; use crate::graphics::{Error, Primitive, Viewport}; use crate::{Backend, Renderer, Settings}; @@ -14,6 +15,8 @@ pub struct Surface { window: softbuffer::GraphicsContext, buffer: Vec, clip_mask: tiny_skia::Mask, + last_primitives: Vec, + last_background_color: Color, } impl crate::graphics::Compositor for Compositor { @@ -45,6 +48,8 @@ impl crate::graphics::Compositor for Compositor { buffer: vec![0; width as usize * height as usize], clip_mask: tiny_skia::Mask::new(width, height) .expect("Create clip mask"), + last_primitives: Vec::new(), + last_background_color: Color::BLACK, } } @@ -57,6 +62,8 @@ impl crate::graphics::Compositor for Compositor { surface.buffer.resize((width * height) as usize, 0); surface.clip_mask = tiny_skia::Mask::new(width, height).expect("Create clip mask"); + + surface.last_primitives.clear(); } fn fetch_information(&self) -> Information { @@ -105,28 +112,45 @@ pub fn present>( overlay: &[T], ) -> Result<(), compositor::SurfaceError> { let physical_size = viewport.physical_size(); + let scale_factor = viewport.scale_factor() as f32; + + let mut pixels = &mut tiny_skia::PixmapMut::from_bytes( + bytemuck::cast_slice_mut(&mut surface.buffer), + physical_size.width, + physical_size.height, + ) + .expect("Create pixel map"); + + let damage = if surface.last_background_color == background_color { + damage::list(&surface.last_primitives, primitives) + } else { + vec![Rectangle::with_size(viewport.logical_size())] + }; + + if damage.is_empty() { + return Ok(()); + } + + surface.last_primitives = primitives.to_vec(); + surface.last_background_color = background_color; + + let damage = damage::group(damage, scale_factor, physical_size); - let drawn = backend.draw( - &mut tiny_skia::PixmapMut::from_bytes( - bytemuck::cast_slice_mut(&mut surface.buffer), - physical_size.width, - physical_size.height, - ) - .expect("Create pixel map"), + backend.draw( + &mut pixels, &mut surface.clip_mask, primitives, viewport, + &damage, background_color, overlay, ); - if drawn { - surface.window.set_buffer( - &surface.buffer, - physical_size.width as u16, - physical_size.height as u16, - ); - } + surface.window.set_buffer( + &surface.buffer, + physical_size.width as u16, + physical_size.height as u16, + ); Ok(()) } -- cgit From 92d808ee73b261b639a4a8d1d4f930cd61a380c6 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 27 Apr 2023 15:16:05 +0200 Subject: Fix double reference in `compositor` in `iced_tiny_skia` --- tiny_skia/src/window/compositor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index d3dffb18..1bcce6fe 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -114,7 +114,7 @@ pub fn present>( let physical_size = viewport.physical_size(); let scale_factor = viewport.scale_factor() as f32; - let mut pixels = &mut tiny_skia::PixmapMut::from_bytes( + let mut pixels = tiny_skia::PixmapMut::from_bytes( bytemuck::cast_slice_mut(&mut surface.buffer), physical_size.width, physical_size.height, -- cgit From eb1b2bf24174759bba8c63db0ec89c7c6d15d191 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 27 Apr 2023 15:45:02 +0200 Subject: Invalidate `last_primitives` on resize in `iced_tiny_skia` --- tiny_skia/src/window/compositor.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 1bcce6fe..3bc06970 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -15,7 +15,7 @@ pub struct Surface { window: softbuffer::GraphicsContext, buffer: Vec, clip_mask: tiny_skia::Mask, - last_primitives: Vec, + last_primitives: Option>, last_background_color: Color, } @@ -48,7 +48,7 @@ impl crate::graphics::Compositor for Compositor { buffer: vec![0; width as usize * height as usize], clip_mask: tiny_skia::Mask::new(width, height) .expect("Create clip mask"), - last_primitives: Vec::new(), + last_primitives: None, last_background_color: Color::BLACK, } } @@ -62,8 +62,7 @@ impl crate::graphics::Compositor for Compositor { surface.buffer.resize((width * height) as usize, 0); surface.clip_mask = tiny_skia::Mask::new(width, height).expect("Create clip mask"); - - surface.last_primitives.clear(); + surface.last_primitives = None; } fn fetch_information(&self) -> Information { @@ -121,17 +120,20 @@ pub fn present>( ) .expect("Create pixel map"); - let damage = if surface.last_background_color == background_color { - damage::list(&surface.last_primitives, primitives) - } else { - vec![Rectangle::with_size(viewport.logical_size())] - }; + let damage = surface + .last_primitives + .as_deref() + .and_then(|last_primitives| { + (surface.last_background_color == background_color) + .then(|| damage::list(last_primitives, primitives)) + }) + .unwrap_or_else(|| vec![Rectangle::with_size(viewport.logical_size())]); if damage.is_empty() { return Ok(()); } - surface.last_primitives = primitives.to_vec(); + surface.last_primitives = Some(primitives.to_vec()); surface.last_background_color = background_color; let damage = damage::group(damage, scale_factor, physical_size); -- cgit From a755472ee35dfb7839f989becafc6028921a3b99 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 27 Apr 2023 15:51:51 +0200 Subject: Remove unnecessary `last_` prefix in `Surface` of `iced_tiny_skia` --- tiny_skia/src/window/compositor.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'tiny_skia/src') diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 3bc06970..9999a188 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -15,8 +15,8 @@ pub struct Surface { window: softbuffer::GraphicsContext, buffer: Vec, clip_mask: tiny_skia::Mask, - last_primitives: Option>, - last_background_color: Color, + primitives: Option>, + background_color: Color, } impl crate::graphics::Compositor for Compositor { @@ -48,8 +48,8 @@ impl crate::graphics::Compositor for Compositor { buffer: vec![0; width as usize * height as usize], clip_mask: tiny_skia::Mask::new(width, height) .expect("Create clip mask"), - last_primitives: None, - last_background_color: Color::BLACK, + primitives: None, + background_color: Color::BLACK, } } @@ -62,7 +62,7 @@ impl crate::graphics::Compositor for Compositor { surface.buffer.resize((width * height) as usize, 0); surface.clip_mask = tiny_skia::Mask::new(width, height).expect("Create clip mask"); - surface.last_primitives = None; + surface.primitives = None; } fn fetch_information(&self) -> Information { @@ -121,10 +121,10 @@ pub fn present>( .expect("Create pixel map"); let damage = surface - .last_primitives + .primitives .as_deref() .and_then(|last_primitives| { - (surface.last_background_color == background_color) + (surface.background_color == background_color) .then(|| damage::list(last_primitives, primitives)) }) .unwrap_or_else(|| vec![Rectangle::with_size(viewport.logical_size())]); @@ -133,8 +133,8 @@ pub fn present>( return Ok(()); } - surface.last_primitives = Some(primitives.to_vec()); - surface.last_background_color = background_color; + surface.primitives = Some(primitives.to_vec()); + surface.background_color = background_color; let damage = damage::group(damage, scale_factor, physical_size); -- cgit