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 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') 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 { .. } => { -- 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/backend.rs') 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 +++++++++++++++++++++++++++++------------------ 1 file changed, 171 insertions(+), 104 deletions(-) (limited to 'tiny_skia/src/backend.rs') 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(); -- 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/backend.rs') 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 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tiny_skia/src/backend.rs') 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( -- 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/backend.rs') 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 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/backend.rs') 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 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'tiny_skia/src/backend.rs') 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( -- 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 ++---------------------------------------------- 1 file changed, 3 insertions(+), 77 deletions(-) (limited to 'tiny_skia/src/backend.rs') 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(); -- cgit