vello_cpu/dispatch/multi_threaded/
cost.rs1pub(crate) const COST_THRESHOLD: f32 = 250.0;
8
9use crate::dispatch::multi_threaded::RenderTaskType;
10use crate::kurbo::{Affine, PathEl, PathSeg, Point, segments};
11
12pub(crate) fn estimate_render_task_cost(task: &RenderTaskType, paths: &[PathEl]) -> f32 {
14 const LAYER_COST: f32 = 10.0;
15
16 match task {
17 RenderTaskType::FillPath {
18 path_range,
19 transform,
20 ..
21 } => {
22 let path = &paths[path_range.start as usize..path_range.end as usize];
23 estimate_path_cost(segments(path.iter().copied()), *transform, false)
24 }
25 RenderTaskType::StrokePath {
26 path_range,
27 transform,
28 ..
29 } => {
30 let path = &paths[path_range.start as usize..path_range.end as usize];
31 estimate_path_cost(segments(path.iter().copied()), *transform, true)
32 }
33 RenderTaskType::PushLayer { clip_path, .. } => {
34 LAYER_COST
35 + clip_path
36 .as_ref()
37 .map(|(path_range, transform)| {
38 let path = &paths[path_range.start as usize..path_range.end as usize];
39 estimate_path_cost(segments(path.iter().copied()), *transform, false)
40 })
41 .unwrap_or(0.0)
42 }
43 RenderTaskType::PopLayer => LAYER_COST,
44 }
45}
46
47pub(crate) fn estimate_path_cost(
64 path: impl IntoIterator<Item = PathSeg>,
65 transform: Affine,
66 is_stroke: bool,
67) -> f32 {
68 let cost_data = PathCostData::new(path, transform);
69
70 const CURVE_MULTIPLIER: f32 = 2.5;
73 const STROKE_MULTIPLIER: f32 = 1.5;
74
75 let mut cost = cost_data.num_line_segments as f32;
76 cost += cost_data.num_curve_segments as f32 * CURVE_MULTIPLIER;
77 cost += cost * (cost_data.path_length as f32 / 1024.0);
78
79 cost *= if is_stroke { STROKE_MULTIPLIER } else { 1.0 };
80 cost
81}
82
83struct PathCostData {
84 num_line_segments: u64,
85 num_curve_segments: u64,
86 path_length: f64,
87}
88
89impl PathCostData {
90 fn new(path: impl IntoIterator<Item = PathSeg>, transform: Affine) -> Self {
91 let mut num_line_segments = 0;
92 let mut num_curve_segments = 0;
93 let mut path_length = 0.0;
94
95 let mut register_path_length = |mut p0: Point, mut p1: Point| {
96 p0 = transform * p0;
97 p1 = transform * p1;
98 let dx = (p1.x - p0.x).abs();
100 let dy = (p1.y - p0.y).abs();
101 path_length += dx + dy;
102 };
103
104 for seg in path.into_iter() {
105 match seg {
106 PathSeg::Line(l) => {
107 num_line_segments += 1;
108
109 register_path_length(l.p0, l.p1);
110 }
111 PathSeg::Quad(q) => {
112 num_curve_segments += 1;
113
114 register_path_length(q.p0, q.p2);
115 }
116 PathSeg::Cubic(c) => {
117 num_curve_segments += 1;
118
119 register_path_length(c.p0, c.p3);
120 }
121 }
122 }
123
124 Self {
125 num_line_segments,
126 num_curve_segments,
127 path_length,
128 }
129 }
130}