1use crate::RenderMode;
5use crate::dispatch::Dispatcher;
6use crate::fine::{F32Kernel, Fine, FineKernel, U8Kernel};
7use crate::kurbo::{Affine, BezPath, Stroke};
8use crate::peniko::{BlendMode, Fill};
9use crate::region::Regions;
10use vello_common::coarse::{MODE_CPU, Wide};
11use vello_common::encode::EncodedPaint;
12use vello_common::fearless_simd::{Level, Simd, dispatch};
13use vello_common::mask::Mask;
14use vello_common::paint::Paint;
15use vello_common::strip::Strip;
16use vello_common::strip_generator::{StripGenerator, StripStorage};
17
18#[derive(Debug)]
19pub(crate) struct SingleThreadedDispatcher {
20 wide: Wide,
21 strip_generator: StripGenerator,
22 strip_storage: StripStorage,
23 level: Level,
24}
25
26impl SingleThreadedDispatcher {
27 pub(crate) fn new(width: u16, height: u16, level: Level) -> Self {
28 let wide = Wide::<MODE_CPU>::new(width, height);
29 let strip_generator = StripGenerator::new(width, height, level);
30 let strip_storage = StripStorage::default();
31
32 Self {
33 wide,
34 strip_generator,
35 strip_storage,
36 level,
37 }
38 }
39
40 fn rasterize_f32(
41 &self,
42 buffer: &mut [u8],
43 width: u16,
44 height: u16,
45 encoded_paints: &[EncodedPaint],
46 ) {
47 dispatch!(self.level, simd => self.rasterize_with::<_, F32Kernel>(simd, buffer, width, height, encoded_paints));
48 }
49
50 fn rasterize_u8(
51 &self,
52 buffer: &mut [u8],
53 width: u16,
54 height: u16,
55 encoded_paints: &[EncodedPaint],
56 ) {
57 dispatch!(self.level, simd => self.rasterize_with::<_, U8Kernel>(simd, buffer, width, height, encoded_paints));
58 }
59
60 fn rasterize_with<S: Simd, F: FineKernel<S>>(
61 &self,
62 simd: S,
63 buffer: &mut [u8],
64 width: u16,
65 height: u16,
66 encoded_paints: &[EncodedPaint],
67 ) {
68 let mut buffer = Regions::new(width, height, buffer);
69 let mut fine = Fine::<S, F>::new(simd);
70
71 buffer.update_regions(|region| {
72 let x = region.x;
73 let y = region.y;
74
75 let wtile = self.wide.get(x, y);
76 fine.set_coords(x, y);
77
78 fine.clear(wtile.bg);
79 for cmd in &wtile.cmds {
80 fine.run_cmd(cmd, &self.strip_storage.alphas, encoded_paints);
81 }
82
83 fine.pack(region);
84 });
85 }
86}
87
88impl Dispatcher for SingleThreadedDispatcher {
89 fn wide(&self) -> &Wide {
90 &self.wide
91 }
92
93 fn fill_path(
94 &mut self,
95 path: &BezPath,
96 fill_rule: Fill,
97 transform: Affine,
98 paint: Paint,
99 aliasing_threshold: Option<u8>,
100 ) {
101 let wide = &mut self.wide;
102
103 self.strip_generator.generate_filled_path(
104 path,
105 fill_rule,
106 transform,
107 aliasing_threshold,
108 &mut self.strip_storage,
109 );
110
111 wide.generate(&self.strip_storage.strips, paint, 0);
112 }
113
114 fn stroke_path(
115 &mut self,
116 path: &BezPath,
117 stroke: &Stroke,
118 transform: Affine,
119 paint: Paint,
120 aliasing_threshold: Option<u8>,
121 ) {
122 let wide = &mut self.wide;
123
124 self.strip_generator.generate_stroked_path(
125 path,
126 stroke,
127 transform,
128 aliasing_threshold,
129 &mut self.strip_storage,
130 );
131
132 wide.generate(&self.strip_storage.strips, paint, 0);
133 }
134
135 fn push_layer(
136 &mut self,
137 clip_path: Option<&BezPath>,
138 fill_rule: Fill,
139 clip_transform: Affine,
140 blend_mode: BlendMode,
141 opacity: f32,
142 aliasing_threshold: Option<u8>,
143 mask: Option<Mask>,
144 ) {
145 let clip = if let Some(c) = clip_path {
146 self.strip_generator.generate_filled_path(
147 c,
148 fill_rule,
149 clip_transform,
150 aliasing_threshold,
151 &mut self.strip_storage,
152 );
153
154 Some(self.strip_storage.strips.as_slice())
155 } else {
156 None
157 };
158
159 self.wide.push_layer(clip, blend_mode, mask, opacity, 0);
160 }
161
162 fn pop_layer(&mut self) {
163 self.wide.pop_layer();
164 }
165
166 fn reset(&mut self) {
167 self.wide.reset();
168 self.strip_generator.reset();
169 self.strip_storage.clear();
170 }
171
172 fn flush(&mut self) {}
173
174 fn rasterize(
175 &self,
176 buffer: &mut [u8],
177 render_mode: RenderMode,
178 width: u16,
179 height: u16,
180 encoded_paints: &[EncodedPaint],
181 ) {
182 match render_mode {
183 RenderMode::OptimizeSpeed => self.rasterize_u8(buffer, width, height, encoded_paints),
184 RenderMode::OptimizeQuality => {
185 self.rasterize_f32(buffer, width, height, encoded_paints);
186 }
187 }
188 }
189
190 fn generate_wide_cmd(&mut self, strip_buf: &[Strip], paint: Paint) {
191 self.wide.generate(strip_buf, paint, 0);
192 }
193
194 fn strip_storage_mut(&mut self) -> &mut StripStorage {
195 &mut self.strip_storage
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202 use crate::kurbo::Rect;
203 use vello_common::color::palette::css::BLUE;
204 use vello_common::kurbo::Shape;
205 use vello_common::paint::PremulColor;
206
207 #[test]
208 fn buffers_cleared_on_reset() {
209 let mut dispatcher = SingleThreadedDispatcher::new(100, 100, Level::new());
210
211 dispatcher.fill_path(
212 &Rect::new(0.0, 0.0, 50.0, 50.0).to_path(0.1),
213 Fill::NonZero,
214 Affine::IDENTITY,
215 Paint::Solid(PremulColor::from_alpha_color(BLUE)),
216 None,
217 );
218
219 assert!(!dispatcher.strip_storage.alphas.is_empty());
221 assert!(!dispatcher.wide.get(0, 0).cmds.is_empty());
222
223 dispatcher.reset();
224
225 assert!(dispatcher.strip_storage.alphas.is_empty());
227 assert!(dispatcher.wide.get(0, 0).cmds.is_empty());
228 }
229}