xref: /aosp_15_r20/external/skia/third_party/vello/src/encoding.rs (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 // Copyright 2023 Google LLC
2 //
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 
6 use crate::ffi;
7 use {
8     peniko::{
9         kurbo::{Affine, Cap, Join, PathEl, Point, Stroke},
10         Brush, Color, Fill, Mix,
11     },
12     std::pin::Pin,
13     vello_encoding::{
14         BumpEstimator, Encoding as VelloEncoding, PathEncoder, RenderConfig, Transform,
15     },
16 };
17 
18 pub(crate) struct Encoding {
19     encoding: VelloEncoding,
20     estimator: BumpEstimator,
21 }
22 
new_encoding() -> Box<Encoding>23 pub(crate) fn new_encoding() -> Box<Encoding> {
24     Box::new(Encoding::new())
25 }
26 
27 impl Encoding {
new() -> Encoding28     fn new() -> Encoding {
29         // An encoding blob that doesn't represent a scene fragment (i.e. a reused blob that is
30         // appended to a root encoding), then we need to initialize the transform and linewidth
31         // streams with first entries (an identity transform and -1 linewidth value). Resetting
32         // the encoding as non-fragment achieves this.
33         let mut encoding = VelloEncoding::new();
34         encoding.reset();
35         Encoding { encoding, estimator: BumpEstimator::new(), }
36     }
37 
is_empty(&self) -> bool38     pub fn is_empty(&self) -> bool {
39         self.encoding.is_empty()
40     }
41 
reset(&mut self)42     pub fn reset(&mut self) {
43         self.encoding.reset();
44         self.estimator.reset();
45     }
46 
fill( &mut self, style: ffi::Fill, transform: ffi::Affine, brush: &ffi::Brush, path_iter: Pin<&mut ffi::PathIterator>, )47     pub fn fill(
48         &mut self,
49         style: ffi::Fill,
50         transform: ffi::Affine,
51         brush: &ffi::Brush,
52         path_iter: Pin<&mut ffi::PathIterator>,
53     ) {
54         let t = Transform::from_kurbo(&transform.into());
55         self.encoding.encode_transform(t);
56         self.encoding.encode_fill_style(style.into());
57         if self.encode_path(path_iter, &t, None) {
58             self.encoding.encode_brush(&Brush::from(brush), 1.0)
59         }
60     }
61 
stroke( &mut self, style: &ffi::Stroke, transform: ffi::Affine, brush: &ffi::Brush, path_iter: Pin<&mut ffi::PathIterator>, )62     pub fn stroke(
63         &mut self,
64         style: &ffi::Stroke,
65         transform: ffi::Affine,
66         brush: &ffi::Brush,
67         path_iter: Pin<&mut ffi::PathIterator>,
68     ) {
69         let t = Transform::from_kurbo(&transform.into());
70         self.encoding.encode_transform(t);
71 
72         // TODO: process any dash pattern here using kurbo's dash expander unless Graphite
73         // handles dashing already.
74         let stroke = style.into();
75         self.encoding.encode_stroke_style(&stroke);
76         if self.encode_path(path_iter, &t, Some(&stroke)) {
77             self.encoding.encode_brush(&Brush::from(brush), 1.0);
78         }
79     }
80 
begin_clip(&mut self, transform: ffi::Affine, path_iter: Pin<&mut ffi::PathIterator>)81     pub fn begin_clip(&mut self, transform: ffi::Affine, path_iter: Pin<&mut ffi::PathIterator>) {
82         let t = Transform::from_kurbo(&transform.into());
83         self.encoding.encode_transform(t);
84         self.encoding.encode_fill_style(Fill::NonZero);
85         self.encode_path(path_iter, &t, None);
86         self.encoding.encode_begin_clip(Mix::Clip.into(), /*alpha=*/ 1.0);
87     }
88 
end_clip(&mut self)89     pub fn end_clip(&mut self) {
90         self.encoding.encode_end_clip();
91     }
92 
append(&mut self, other: &Encoding)93     pub fn append(&mut self, other: &Encoding) {
94         self.encoding.append(&other.encoding, &None);
95         self.estimator.append(&other.estimator, None);
96     }
97 
prepare_render( &self, width: u32, height: u32, background: &ffi::Color, ) -> Box<RenderConfiguration>98     pub fn prepare_render(
99         &self,
100         width: u32,
101         height: u32,
102         background: &ffi::Color,
103     ) -> Box<RenderConfiguration> {
104         let mut packed_scene = Vec::new();
105         let layout = vello_encoding::resolve_solid_paths_only(&self.encoding, &mut packed_scene);
106         let mut config = RenderConfig::new(&layout, width, height, &background.into());
107 
108         let bump_estimate = self.estimator.tally(None);
109         //println!("bump: {bump_estimate}");
110         config.buffer_sizes.bin_data = bump_estimate.binning;
111         config.buffer_sizes.seg_counts = bump_estimate.seg_counts;
112         config.buffer_sizes.segments = bump_estimate.segments;
113         config.buffer_sizes.lines = bump_estimate.lines;
114         config.gpu.binning_size = bump_estimate.binning.len();
115         config.gpu.seg_counts_size = bump_estimate.seg_counts.len();
116         config.gpu.segments_size = bump_estimate.segments.len();
117         config.gpu.lines_size = bump_estimate.lines.len();
118 
119         Box::new(RenderConfiguration {
120             packed_scene,
121             config,
122         })
123     }
124 
encode_path( &mut self, iter: Pin<&mut ffi::PathIterator>, transform: &Transform, stroke: Option<&Stroke>, ) -> bool125     fn encode_path(
126         &mut self,
127         iter: Pin<&mut ffi::PathIterator>,
128         transform: &Transform,
129         stroke: Option<&Stroke>,
130     ) -> bool {
131         let mut encoder = self.encoding.encode_path(/*is_fill=*/ stroke.is_none());
132 
133         // Wrap the input iterator inside a custom iterator, so that the path gets
134         // encoded as the estimator runs through it.
135         let path = IterablePathEncoder { iter, encoder: &mut encoder };
136         self.estimator.count_path(path, transform, stroke);
137         encoder.finish(/*insert_path_marker=*/ true) != 0
138     }
139 }
140 
141 // This is path element iterator that encodes path elements as it gets polled.
142 struct IterablePathEncoder<'a, 'b> {
143     iter: Pin<&'a mut ffi::PathIterator>,
144     encoder: &'a mut PathEncoder<'b>,
145 }
146 
147 impl Iterator for IterablePathEncoder<'_, '_> {
148     type Item = PathEl;
149 
next(&mut self) -> Option<Self::Item>150     fn next(&mut self) -> Option<Self::Item> {
151         let mut path_el = ffi::PathElement::default();
152         if !unsafe { self.iter.as_mut().next_element(&mut path_el) } {
153             return None;
154         }
155         Some(match path_el.verb {
156             ffi::PathVerb::MoveTo => {
157                 let p = &path_el.points[0];
158                 self.encoder.move_to(p.x, p.y);
159                 PathEl::MoveTo(p.into())
160             }
161             ffi::PathVerb::LineTo => {
162                 let p = &path_el.points[1];
163                 self.encoder.line_to(p.x, p.y);
164                 PathEl::LineTo(p.into())
165             }
166             ffi::PathVerb::QuadTo => {
167                 let p0 = &path_el.points[1];
168                 let p1 = &path_el.points[2];
169                 self.encoder.quad_to(p0.x, p0.y, p1.x, p1.y);
170                 PathEl::QuadTo(p0.into(), p1.into())
171             }
172             ffi::PathVerb::CurveTo => {
173                 let p0 = &path_el.points[1];
174                 let p1 = &path_el.points[2];
175                 let p2 = &path_el.points[3];
176                 self.encoder.cubic_to(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
177                 PathEl::CurveTo(p0.into(), p1.into(), p2.into())
178             }
179             ffi::PathVerb::Close => {
180                 self.encoder.close();
181                 PathEl::ClosePath
182             }
183             _ => panic!("invalid path verb"),
184         })
185     }
186 }
187 
188 pub(crate) struct RenderConfiguration {
189     packed_scene: Vec<u8>,
190     config: RenderConfig,
191 }
192 
193 impl RenderConfiguration {
config_uniform_buffer_size(self: &RenderConfiguration) -> usize194     pub fn config_uniform_buffer_size(self: &RenderConfiguration) -> usize {
195         std::mem::size_of::<vello_encoding::ConfigUniform>()
196     }
197 
scene_buffer_size(self: &RenderConfiguration) -> usize198     pub fn scene_buffer_size(self: &RenderConfiguration) -> usize {
199         self.packed_scene.len()
200     }
201 
write_config_uniform_buffer(self: &RenderConfiguration, out_buffer: &mut [u8]) -> bool202     pub fn write_config_uniform_buffer(self: &RenderConfiguration, out_buffer: &mut [u8]) -> bool {
203         let bytes = bytemuck::bytes_of(&self.config.gpu);
204         if out_buffer.len() < bytes.len() {
205             return false;
206         }
207         out_buffer.copy_from_slice(bytes);
208         true
209     }
210 
write_scene_buffer(self: &RenderConfiguration, out_buffer: &mut [u8]) -> bool211     pub fn write_scene_buffer(self: &RenderConfiguration, out_buffer: &mut [u8]) -> bool {
212         if out_buffer.len() < self.packed_scene.len() {
213             return false;
214         }
215         out_buffer.copy_from_slice(&self.packed_scene);
216         true
217     }
218 
workgroup_counts(self: &RenderConfiguration) -> ffi::DispatchInfo219     pub fn workgroup_counts(self: &RenderConfiguration) -> ffi::DispatchInfo {
220         (&self.config.workgroup_counts).into()
221     }
222 
buffer_sizes(self: &RenderConfiguration) -> ffi::BufferSizes223     pub fn buffer_sizes(self: &RenderConfiguration) -> ffi::BufferSizes {
224         (&self.config.buffer_sizes).into()
225     }
226 }
227 
228 impl Iterator for Pin<&mut ffi::PathIterator> {
229     type Item = PathEl;
230 
next(&mut self) -> Option<PathEl>231     fn next(&mut self) -> Option<PathEl> {
232         let mut path_el = ffi::PathElement::default();
233         if !unsafe { self.as_mut().next_element(&mut path_el) } {
234             return None;
235         }
236         Some(match path_el.verb {
237             ffi::PathVerb::MoveTo => {
238                 let p = &path_el.points[0];
239                 PathEl::MoveTo(p.into())
240             }
241             ffi::PathVerb::LineTo => {
242                 let p = &path_el.points[1];
243                 PathEl::LineTo(p.into())
244             }
245             ffi::PathVerb::QuadTo => {
246                 let p0 = &path_el.points[1];
247                 let p1 = &path_el.points[2];
248                 PathEl::QuadTo(p0.into(), p1.into())
249             }
250             ffi::PathVerb::CurveTo => {
251                 let p0 = &path_el.points[1];
252                 let p1 = &path_el.points[2];
253                 let p2 = &path_el.points[3];
254                 PathEl::CurveTo(p0.into(), p1.into(), p2.into())
255             }
256             ffi::PathVerb::Close => PathEl::ClosePath,
257             _ => panic!("invalid path verb"),
258         })
259     }
260 }
261 
262 impl From<&ffi::Point> for Point {
from(src: &ffi::Point) -> Self263     fn from(src: &ffi::Point) -> Self {
264         Self::new(src.x.into(), src.y.into())
265     }
266 }
267 
268 impl Default for ffi::PathVerb {
default() -> Self269     fn default() -> Self {
270         Self::MoveTo
271     }
272 }
273 
274 impl From<ffi::Affine> for Affine {
from(src: ffi::Affine) -> Self275     fn from(src: ffi::Affine) -> Self {
276         Self::new([
277             src.matrix[0] as f64,
278             src.matrix[1] as f64,
279             src.matrix[2] as f64,
280             src.matrix[3] as f64,
281             src.matrix[4] as f64,
282             src.matrix[5] as f64,
283         ])
284     }
285 }
286 
287 impl From<&ffi::Color> for Color {
from(src: &ffi::Color) -> Self288     fn from(src: &ffi::Color) -> Self {
289         Self {
290             r: src.r,
291             g: src.g,
292             b: src.b,
293             a: src.a,
294         }
295     }
296 }
297 
298 impl From<&ffi::Brush> for Brush {
from(src: &ffi::Brush) -> Self299     fn from(src: &ffi::Brush) -> Self {
300         match src.kind {
301             ffi::BrushKind::Solid => Brush::Solid(Color::from(&src.data.solid)),
302             _ => panic!("invalid brush kind"),
303         }
304     }
305 }
306 
307 impl From<ffi::Fill> for Fill {
from(src: ffi::Fill) -> Self308     fn from(src: ffi::Fill) -> Self {
309         match src {
310             ffi::Fill::NonZero => Self::NonZero,
311             ffi::Fill::EvenOdd => Self::EvenOdd,
312             _ => panic!("invalid fill type"),
313         }
314     }
315 }
316 
317 impl From<&ffi::Stroke> for Stroke {
from(src: &ffi::Stroke) -> Self318     fn from(src: &ffi::Stroke) -> Self {
319         let cap = match src.cap {
320             ffi::CapStyle::Butt => Cap::Butt,
321             ffi::CapStyle::Square => Cap::Square,
322             ffi::CapStyle::Round => Cap::Round,
323             _ => panic!("invalid cap style"),
324         };
325         Self {
326             width: src.width as f64,
327             join: match src.join {
328                 ffi::JoinStyle::Bevel => Join::Bevel,
329                 ffi::JoinStyle::Miter => Join::Miter,
330                 ffi::JoinStyle::Round => Join::Round,
331                 _ => panic!("invalid join style"),
332             },
333             miter_limit: src.miter_limit as f64,
334             start_cap: cap,
335             end_cap: cap,
336             // Skia expands a dash effect by transforming the encoded path, so don't need to handle
337             // that here.
338             dash_pattern: Default::default(),
339             dash_offset: 0.,
340         }
341     }
342 }
343 
344 impl From<&vello_encoding::WorkgroupSize> for ffi::WorkgroupSize {
from(src: &vello_encoding::WorkgroupSize) -> Self345     fn from(src: &vello_encoding::WorkgroupSize) -> Self {
346         Self {
347             x: src.0,
348             y: src.1,
349             z: src.2,
350         }
351     }
352 }
353 
354 impl From<&vello_encoding::WorkgroupCounts> for ffi::DispatchInfo {
from(src: &vello_encoding::WorkgroupCounts) -> Self355     fn from(src: &vello_encoding::WorkgroupCounts) -> Self {
356         Self {
357             use_large_path_scan: src.use_large_path_scan,
358             path_reduce: (&src.path_reduce).into(),
359             path_reduce2: (&src.path_reduce2).into(),
360             path_scan1: (&src.path_scan1).into(),
361             path_scan: (&src.path_scan).into(),
362             bbox_clear: (&src.bbox_clear).into(),
363             flatten: (&src.flatten).into(),
364             draw_reduce: (&src.draw_reduce).into(),
365             draw_leaf: (&src.draw_leaf).into(),
366             clip_reduce: (&src.clip_reduce).into(),
367             clip_leaf: (&src.clip_leaf).into(),
368             binning: (&src.binning).into(),
369             tile_alloc: (&src.tile_alloc).into(),
370             path_count_setup: (&src.path_count_setup).into(),
371             backdrop: (&src.backdrop).into(),
372             coarse: (&src.coarse).into(),
373             path_tiling_setup: (&src.path_tiling_setup).into(),
374             fine: (&src.fine).into(),
375         }
376     }
377 }
378 
379 impl From<&vello_encoding::BufferSizes> for ffi::BufferSizes {
from(src: &vello_encoding::BufferSizes) -> Self380     fn from(src: &vello_encoding::BufferSizes) -> Self {
381         Self {
382             path_reduced: src.path_reduced.size_in_bytes(),
383             path_reduced2: src.path_reduced2.size_in_bytes(),
384             path_reduced_scan: src.path_reduced_scan.size_in_bytes(),
385             path_monoids: src.path_monoids.size_in_bytes(),
386             path_bboxes: src.path_bboxes.size_in_bytes(),
387             draw_reduced: src.draw_reduced.size_in_bytes(),
388             draw_monoids: src.draw_monoids.size_in_bytes(),
389             info: src.info.size_in_bytes(),
390             clip_inps: src.clip_inps.size_in_bytes(),
391             clip_els: src.clip_els.size_in_bytes(),
392             clip_bics: src.clip_bics.size_in_bytes(),
393             clip_bboxes: src.clip_bboxes.size_in_bytes(),
394             draw_bboxes: src.draw_bboxes.size_in_bytes(),
395             bump_alloc: src.bump_alloc.size_in_bytes(),
396             indirect_count: src.indirect_count.size_in_bytes(),
397             bin_headers: src.bin_headers.size_in_bytes(),
398             paths: src.paths.size_in_bytes(),
399             lines: src.lines.size_in_bytes(),
400             bin_data: src.bin_data.size_in_bytes(),
401             tiles: src.tiles.size_in_bytes(),
402             seg_counts: src.seg_counts.size_in_bytes(),
403             segments: src.segments.size_in_bytes(),
404             ptcl: src.ptcl.size_in_bytes(),
405         }
406     }
407 }
408