Move damage tracking logic to compositor in iced_tiny_skia
This commit is contained in:
parent
d953d12c38
commit
af0303f95e
5 changed files with 183 additions and 182 deletions
140
graphics/src/damage.rs
Normal file
140
graphics/src/damage.rs
Normal file
|
|
@ -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(®ion);
|
||||
|
||||
if union.area() - current.area() - region.area() <= AREA_THRESHOLD {
|
||||
current = union;
|
||||
} else {
|
||||
output.push(current);
|
||||
current = region;
|
||||
}
|
||||
}
|
||||
|
||||
output.push(current);
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ mod viewport;
|
|||
|
||||
pub mod backend;
|
||||
pub mod compositor;
|
||||
pub mod damage;
|
||||
pub mod primitive;
|
||||
pub mod renderer;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue