Skip to content

Commit

Permalink
Move damage tracking logic to compositor in iced_tiny_skia
Browse files Browse the repository at this point in the history
  • Loading branch information
hecrj committed Apr 27, 2023
1 parent d953d12 commit af0303f
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 182 deletions.
140 changes: 140 additions & 0 deletions graphics/src/damage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use crate::core::{Rectangle, Size};
use crate::Primitive;

use std::sync::Arc;

pub fn regions(a: &Primitive, b: &Primitive) -> Vec<Rectangle> {
match (a, b) {
(
Primitive::Group {
primitives: primitives_a,
},
Primitive::Group {
primitives: primitives_b,
},
) => return list(primitives_a, primitives_b),
(
Primitive::Clip {
bounds: bounds_a,
content: content_a,
},
Primitive::Clip {
bounds: bounds_b,
content: content_b,
},
) => {
if bounds_a == bounds_b {
return regions(content_a, content_b)
.into_iter()
.filter_map(|r| r.intersection(bounds_a))
.collect();
} else {
return vec![*bounds_a, *bounds_b];
}
}
(
Primitive::Translate {
translation: translation_a,
content: content_a,
},
Primitive::Translate {
translation: translation_b,
content: content_b,
},
) => {
if translation_a == translation_b {
return regions(content_a, content_b)
.into_iter()
.map(|r| r + *translation_a)
.collect();
}
}
(
Primitive::Cache { content: content_a },
Primitive::Cache { content: content_b },
) => {
if Arc::ptr_eq(content_a, content_b) {
return vec![];
}
}
_ if a == b => return vec![],
_ => {}
}

let bounds_a = a.bounds();
let bounds_b = b.bounds();

if bounds_a == bounds_b {
vec![bounds_a]
} else {
vec![bounds_a, bounds_b]
}
}

pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec<Rectangle> {
let damage = previous
.iter()
.zip(current)
.flat_map(|(a, b)| regions(a, b));

if previous.len() == current.len() {
damage.collect()
} else {
let (smaller, bigger) = if previous.len() < current.len() {
(previous, current)
} else {
(current, previous)
};

// Extend damage by the added/removed primitives
damage
.chain(bigger[smaller.len()..].iter().map(Primitive::bounds))
.collect()
}
}

pub fn group(
mut damage: Vec<Rectangle>,
scale_factor: f32,
bounds: Size<u32>,
) -> Vec<Rectangle> {
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(&region);

if union.area() - current.area() - region.area() <= AREA_THRESHOLD {
current = union;
} else {
output.push(current);
current = region;
}
}

output.push(current);
}

output
}
1 change: 1 addition & 0 deletions graphics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod viewport;

pub mod backend;
pub mod compositor;
pub mod damage;
pub mod primitive;
pub mod renderer;

Expand Down
90 changes: 0 additions & 90 deletions graphics/src/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,96 +208,6 @@ impl Primitive {
Self::Cache { content } => content.bounds(),
}
}

pub fn damage(&self, other: &Self) -> Vec<Rectangle> {
match (self, other) {
(
Primitive::Group {
primitives: primitives_a,
},
Primitive::Group {
primitives: primitives_b,
},
) => return Self::damage_list(primitives_a, primitives_b),
(
Primitive::Clip {
bounds: bounds_a,
content: content_a,
},
Primitive::Clip {
bounds: bounds_b,
content: content_b,
},
) => {
if bounds_a == bounds_b {
return content_a
.damage(content_b)
.into_iter()
.filter_map(|r| r.intersection(bounds_a))
.collect();
} else {
return vec![*bounds_a, *bounds_b];
}
}
(
Primitive::Translate {
translation: translation_a,
content: content_a,
},
Primitive::Translate {
translation: translation_b,
content: content_b,
},
) => {
if translation_a == translation_b {
return content_a
.damage(content_b)
.into_iter()
.map(|r| r + *translation_a)
.collect();
}
}
(
Primitive::Cache { content: content_a },
Primitive::Cache { content: content_b },
) => {
if Arc::ptr_eq(content_a, content_b) {
return vec![];
}
}
_ if self == other => return vec![],
_ => {}
}

let bounds_a = self.bounds();
let bounds_b = other.bounds();

if bounds_a == bounds_b {
vec![bounds_a]
} else {
vec![bounds_a, bounds_b]
}
}

pub fn damage_list(previous: &[Self], current: &[Self]) -> Vec<Rectangle> {
let damage =
previous.iter().zip(current).flat_map(|(a, b)| a.damage(b));

if previous.len() == current.len() {
damage.collect()
} else {
let (smaller, bigger) = if previous.len() < current.len() {
(previous, current)
} else {
(current, previous)
};

// Extend damage by the added/removed primitives
damage
.chain(bigger[smaller.len()..].iter().map(Primitive::bounds))
.collect()
}
}
}

/// A set of [`Vertex2D`] and indices representing a list of triangles.
Expand Down
80 changes: 3 additions & 77 deletions tiny_skia/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ pub struct Backend {

#[cfg(feature = "svg")]
vector_pipeline: crate::vector::Pipeline,

last_primitives: Vec<Primitive>,
last_background_color: Color,
last_size: Size<u32>,
}

impl Backend {
Expand All @@ -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),
}
}

Expand All @@ -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(
Expand Down Expand Up @@ -99,7 +73,7 @@ impl Backend {
);
}

for region in damage {
for &region in damage {
let path = tiny_skia::PathBuilder::from_rect(
tiny_skia::Rect::from_xywh(
region.x,
Expand Down Expand Up @@ -164,8 +138,6 @@ impl Backend {

#[cfg(feature = "svg")]
self.vector_pipeline.trim_cache();

true
}

fn draw_primitive(
Expand Down Expand Up @@ -629,52 +601,6 @@ fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) {
);
}

fn group_damage(
mut damage: Vec<Rectangle>,
scale_factor: f32,
bounds: Size<u32>,
) -> Vec<Rectangle> {
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(&region);

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();
Expand Down
Loading

0 comments on commit af0303f

Please sign in to comment.