vello_cpu/dispatch/multi_threaded/
worker.rs1use crate::Level;
5use crate::dispatch::multi_threaded::{
6 RecordedCommand, RecordedCommandSender, RecordedCommandTask, RenderTask, RenderTaskType,
7};
8use std::vec::Vec;
9use vello_common::clip::PathDataRef;
10use vello_common::geometry::RectU16;
11use vello_common::strip_generator::{GenerationMode, StripGenerator, StripStorage};
12use vello_common::util::strip_bbox;
13
14#[derive(Debug)]
15pub(crate) struct Worker {
16 strip_generator: StripGenerator,
17 strip_storage: StripStorage,
18 thread_id: u8,
19}
20
21impl Worker {
22 pub(crate) fn new(width: u16, height: u16, thread_id: u8, level: Level) -> Self {
23 let strip_generator = StripGenerator::new(width, height, level);
24 let strip_storage = StripStorage::default();
25
26 Self {
27 strip_generator,
28 strip_storage,
29 thread_id,
30 }
31 }
32
33 pub(crate) fn init(&mut self, alphas: Vec<u8>) {
34 self.strip_storage.alphas = alphas;
35 }
36
37 pub(crate) fn thread_id(&self) -> u8 {
38 self.thread_id
39 }
40
41 pub(crate) fn reset(&mut self, width: u16, height: u16) {
42 self.strip_generator.reset(width, height);
43 }
44
45 pub(crate) fn run_render_task(
46 &mut self,
47 mut render_task: RenderTask,
48 result_sender: &mut RecordedCommandSender,
49 ) {
50 let num_tasks = render_task.allocation_group.render_tasks.len();
51 self.strip_storage.strips.clear();
52 self.strip_storage
53 .set_generation_mode(GenerationMode::Append);
54 let task_idx = render_task.idx;
55 let path_clip = render_task.clip_path.as_ref().map(|c| PathDataRef {
56 strips: c.strips.as_ref(),
57 alphas: c.alphas.as_ref(),
58 bbox: c.bbox,
59 });
60
61 for task in render_task
62 .allocation_group
63 .render_tasks
64 .drain(0..num_tasks)
65 {
66 match task {
67 RenderTaskType::FillPath {
68 path_range,
69 transform,
70 paint,
71 fill_rule,
72 blend_mode,
73 aliasing_threshold,
74 mask,
75 } => {
76 let start = self.strip_storage.strips.len() as u32;
77 let path = &render_task.allocation_group.path
78 [path_range.start as usize..path_range.end as usize];
79
80 self.strip_generator.generate_filled_path(
81 path.iter().copied(),
82 fill_rule,
83 transform,
84 aliasing_threshold,
85 &mut self.strip_storage,
86 path_clip,
87 );
88 let end = self.strip_storage.strips.len() as u32;
89
90 let recorded_command = RecordedCommand::RenderPath {
91 thread_id: self.thread_id,
92 strips: start..end,
93 blend_mode,
94 paint,
95 mask,
96 };
97
98 render_task
99 .allocation_group
100 .recorded_commands
101 .push(recorded_command);
102 }
103 RenderTaskType::StrokePath {
104 path_range,
105 transform,
106 paint,
107 blend_mode,
108 stroke,
109 aliasing_threshold,
110 mask,
111 } => {
112 let start = self.strip_storage.strips.len() as u32;
113 let path = &render_task.allocation_group.path
114 [path_range.start as usize..path_range.end as usize];
115
116 self.strip_generator.generate_stroked_path(
117 path.iter().copied(),
118 &stroke,
119 transform,
120 aliasing_threshold,
121 &mut self.strip_storage,
122 path_clip,
123 );
124 let end = self.strip_storage.strips.len() as u32;
125
126 let recorded_command = RecordedCommand::RenderPath {
127 thread_id: self.thread_id,
128 strips: start..end,
129 blend_mode,
130 paint,
131 mask,
132 };
133
134 render_task
135 .allocation_group
136 .recorded_commands
137 .push(recorded_command);
138 }
139 RenderTaskType::PushLayer {
140 clip_path,
141 blend_mode,
142 opacity,
143 mask,
144 fill_rule,
145 aliasing_threshold,
146 } => {
147 let (clip, clip_bbox) = if let Some((path_range, transform)) = clip_path {
148 let start = self.strip_storage.strips.len() as u32;
149 let path = &render_task.allocation_group.path
150 [path_range.start as usize..path_range.end as usize];
151
152 self.strip_generator.generate_filled_path(
153 path.iter().copied(),
154 fill_rule,
155 transform,
156 aliasing_threshold,
157 &mut self.strip_storage,
158 path_clip,
159 );
160
161 let end = self.strip_storage.strips.len() as u32;
162 let range = start..end;
163 let bbox = strip_bbox(
164 &self.strip_storage.strips[range.start as usize..range.end as usize],
165 )
166 .unwrap_or(RectU16::ZERO);
167
168 (Some(range), Some(bbox))
169 } else {
170 (None, None)
171 };
172
173 let recorded_command = RecordedCommand::PushLayer {
174 thread_id: self.thread_id,
175 clip_path: clip,
176 clip_bbox,
177 blend_mode,
178 mask,
179 opacity,
180 };
181
182 render_task
183 .allocation_group
184 .recorded_commands
185 .push(recorded_command);
186 }
187 RenderTaskType::PopLayer => {
188 render_task
189 .allocation_group
190 .recorded_commands
191 .push(RecordedCommand::PopLayer);
192 }
193 }
194 }
195
196 let taken_strips = std::mem::replace(
197 &mut self.strip_storage.strips,
198 render_task.allocation_group.strips,
199 );
200 render_task.allocation_group.strips = taken_strips;
201
202 let task = RecordedCommandTask {
203 allocation_group: render_task.allocation_group,
204 };
205
206 result_sender.send(task_idx as usize, task).unwrap();
207 }
208
209 pub(crate) fn finalize(&mut self) -> Vec<u8> {
210 std::mem::take(&mut self.strip_storage.alphas)
211 }
212}