forma_render/
segment.rs

1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{cell::Cell, num::NonZeroU64};
16
17use rayon::prelude::*;
18
19use crate::{
20    composition::InnerLayer,
21    consts,
22    math::AffineTransform,
23    utils::{ExtendTuple10, ExtendTuple3},
24    Path,
25};
26
27const MIN_LEN: usize = 1_024;
28
29fn integers_between(a: f32, b: f32) -> u32 {
30    let min = a.min(b);
31    let max = a.max(b);
32
33    0.max((max.ceil() - min.floor() - 1.0) as u32)
34}
35
36/// This returns a value that is similar (but not identical!) to the Manhattan Distance between
37/// two segment endpoints. We'll call it the "Manhattan Block Distance". You can think of this as
38/// the number of city blocks which are touched by a piecewise horizontal/vertical path between the
39/// points.
40///
41/// # Examples
42///
43/// ```text
44/// (0.5, 0.5) -> (0.3, 0.7)
45/// ```
46/// In this case, there are no integers between `0.5` and `0.3`, nor between `0.5` and `0.7`: both
47/// points reside on the same "city block", so the length is `1`.
48/// NOTE: by this metric, a degenerate segment `(0.5, 0.5) -> (0.5, 0.5)` also has length `1`.
49///
50/// ```text
51/// (0.9, 1.9) -> (1.1, 0.1)
52/// ```
53/// The x-coordinates `0.9` and `1.1` are on adjacent "city blocks", which contributes `1` to the
54/// to the segment length (even though the distance between them is only `0.2`). Similarly, the
55/// y-coordinates `1.9` and `0.1` are on adjacent "city blocks", which also contributes `1` to the
56/// segment length (even though the distance between them is `1.8`, almost `2`!).  This gives a total
57/// segment length of `3`:
58///   - `1` for the starting block
59///   - `1` to move horizontally from `0.9` to `1.1`
60///   - `1` to move vertically from `1.9` to `0.1`
61fn manhattan_segment_length(p0x: f32, p1x: f32, p0y: f32, p1y: f32) -> u32 {
62    integers_between(p0x, p1x) + integers_between(p0y, p1y) + 1
63}
64
65fn prefix_sum(vals: &mut [u32]) -> u32 {
66    let mut sum = 0;
67    for val in vals {
68        sum += *val;
69        *val = sum;
70    }
71
72    sum
73}
74
75#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
76#[repr(transparent)]
77pub struct GeomId(NonZeroU64);
78
79impl GeomId {
80    #[cfg(test)]
81    pub fn get(self) -> u64 {
82        self.0.get() - 1
83    }
84
85    #[inline]
86    pub fn next(self) -> Self {
87        Self(
88            NonZeroU64::new(
89                self.0
90                    .get()
91                    .checked_add(1)
92                    .expect("id should never reach u64::MAX"),
93            )
94            .unwrap(),
95        )
96    }
97}
98
99impl Default for GeomId {
100    #[inline]
101    fn default() -> Self {
102        Self(NonZeroU64::new(1).unwrap())
103    }
104}
105
106#[derive(Debug, Default)]
107pub struct SegmentBuffer {
108    view: SegmentBufferView,
109    cached_len: Cell<usize>,
110    cached_until: Cell<usize>,
111}
112
113impl SegmentBuffer {
114    // This type is only used in forma where it does not need `is_empty`.
115    #[allow(clippy::len_without_is_empty)]
116    #[inline]
117    pub fn len(&self) -> usize {
118        if self.view.ids.len() <= self.cached_until.get() {
119            self.cached_len.get()
120        } else {
121            let new_len = self.cached_len.get()
122                + self.view.ids[self.cached_until.get()..]
123                    .iter()
124                    .filter(|id| id.is_some())
125                    .count();
126
127            self.cached_len.set(new_len);
128            self.cached_until.set(self.view.ids.len());
129
130            new_len
131        }
132    }
133
134    #[inline]
135    pub fn push_path(&mut self, id: GeomId, path: &Path) {
136        path.push_segments_to(&mut self.view.x, &mut self.view.y, id, &mut self.view.ids);
137
138        self.view.ids.resize(
139            self.view.x.len().checked_sub(1).unwrap_or_default(),
140            Some(id),
141        );
142
143        if self
144            .view
145            .ids
146            .last()
147            .map(Option::is_some)
148            .unwrap_or_default()
149        {
150            self.view.ids.push(None);
151        }
152    }
153
154    #[cfg(test)]
155    pub fn push(&mut self, id: GeomId, segment: [crate::math::Point; 2]) {
156        let new_point_needed =
157            if let (Some(&x), Some(&y)) = (self.view.x.last(), self.view.y.last()) {
158                let last_point = crate::math::Point { x, y };
159
160                last_point != segment[0]
161            } else {
162                true
163            };
164
165        if new_point_needed {
166            self.view.x.push(segment[0].x);
167            self.view.y.push(segment[0].y);
168        }
169
170        self.view.x.push(segment[1].x);
171        self.view.y.push(segment[1].y);
172
173        if self.view.ids.len() >= 2 {
174            match self.view.ids[self.view.ids.len() - 2] {
175                Some(last_id) if last_id != id => {
176                    self.view.ids.push(Some(id));
177                    self.view.ids.push(None);
178                }
179                _ => {
180                    self.view.ids.pop();
181                    self.view.ids.push(Some(id));
182                    self.view.ids.push(None);
183                }
184            }
185        } else {
186            self.view.ids.push(Some(id));
187            self.view.ids.push(None);
188        }
189    }
190
191    pub fn retain<F>(&mut self, mut f: F)
192    where
193        F: FnMut(GeomId) -> bool,
194    {
195        let len = self.view.x.len();
196        let mut del = 0;
197        let mut prev_id = None;
198
199        for i in 0..len {
200            // `None` IDs will always belong to the previous ID.
201            // Thus, if an ID is removed here, its None will be removed as well.
202
203            let id = self.view.ids[i];
204            let should_retain = id
205                .or(prev_id)
206                .map(&mut f)
207                .expect("consecutive None values should not exist in ids");
208            prev_id = id;
209
210            if !should_retain {
211                del += 1;
212                continue;
213            }
214
215            if del > 0 {
216                self.view.x.swap(i - del, i);
217                self.view.y.swap(i - del, i);
218                self.view.ids.swap(i - del, i);
219            }
220        }
221
222        if del > 0 {
223            self.view.x.truncate(len - del);
224            self.view.y.truncate(len - del);
225            self.view.ids.truncate(len - del);
226        }
227    }
228
229    pub fn fill_cpu_view<F>(mut self, layers: F) -> SegmentBufferView
230    where
231        F: Fn(GeomId) -> Option<InnerLayer> + Send + Sync,
232    {
233        let ps_layers = self.view.x.par_windows(2).with_min_len(MIN_LEN).zip_eq(
234            self.view.y.par_windows(2).with_min_len(MIN_LEN).zip_eq(
235                self.view.ids[..self.view.ids.len().checked_sub(1).unwrap_or_default()]
236                    .par_iter()
237                    .with_min_len(MIN_LEN),
238            ),
239        );
240        let par_iter = ps_layers.map(|(xs, (ys, &id))| {
241            let empty_line = Default::default();
242
243            let p0x = xs[0];
244            let p0y = ys[0];
245            let p1x = xs[1];
246            let p1y = ys[1];
247
248            if id.is_none() {
249                // Returns a length of 0 so that the line segments between two
250                // polygonal chains generate no pixel segments.
251                return empty_line;
252            }
253
254            let layer = match id.and_then(&layers) {
255                Some(layer) => layer,
256                None => return empty_line,
257            };
258
259            if let InnerLayer {
260                is_enabled: false, ..
261            } = layer
262            {
263                return empty_line;
264            }
265
266            let order = match layer.order {
267                Some(order) => order.as_u32(),
268                None => return empty_line,
269            };
270
271            fn transform_point(point: (f32, f32), transform: &AffineTransform) -> (f32, f32) {
272                (
273                    transform
274                        .ux
275                        .mul_add(point.0, transform.vx.mul_add(point.1, transform.tx)),
276                    transform
277                        .uy
278                        .mul_add(point.0, transform.vy.mul_add(point.1, transform.ty)),
279                )
280            }
281
282            let transform = layer
283                .affine_transform
284                .as_ref()
285                .map(|transform| &transform.0);
286
287            let (p0x, p0y, p1x, p1y) = if let Some(transform) = transform {
288                let (p0x, p0y) = transform_point((p0x, p0y), transform);
289                let (p1x, p1y) = transform_point((p1x, p1y), transform);
290
291                (p0x, p0y, p1x, p1y)
292            } else {
293                (p0x, p0y, p1x, p1y)
294            };
295
296            if p0y == p1y {
297                return empty_line;
298            }
299
300            let dx = p1x - p0x;
301            let dy = p1y - p0y;
302            let dx_recip = dx.recip();
303            let dy_recip = dy.recip();
304
305            // We compute the two line parameters that correspond to the first horizontal and first
306            // vertical intersections with the pixel grid from point `p0` towards `p1`.
307            let t_offset_x = if dx != 0.0 {
308                ((p0x.ceil() - p0x) * dx_recip).max((p0x.floor() - p0x) * dx_recip)
309            } else {
310                0.0
311            };
312            let t_offset_y = if dy != 0.0 {
313                ((p0y.ceil() - p0y) * dy_recip).max((p0y.floor() - p0y) * dy_recip)
314            } else {
315                0.0
316            };
317
318            let a = dx_recip.abs();
319            let b = dy_recip.abs();
320            let c = t_offset_x;
321            let d = t_offset_y;
322
323            let length = manhattan_segment_length(p0x, p1x, p0y, p1y);
324
325            // Converting to sub-pixel space on the fly by multiplying with `PIXEL_WIDTH`.
326            (
327                order,
328                p0x * consts::PIXEL_WIDTH as f32,
329                p0y * consts::PIXEL_WIDTH as f32,
330                dx * consts::PIXEL_WIDTH as f32,
331                dy * consts::PIXEL_WIDTH as f32,
332                a,
333                b,
334                c,
335                d,
336                length,
337            )
338        });
339
340        ExtendTuple10::new((
341            &mut self.view.orders,
342            &mut self.view.x0,
343            &mut self.view.y0,
344            &mut self.view.dx,
345            &mut self.view.dy,
346            &mut self.view.a,
347            &mut self.view.b,
348            &mut self.view.c,
349            &mut self.view.d,
350            &mut self.view.lengths,
351        ))
352        .par_extend(par_iter);
353
354        prefix_sum(&mut self.view.lengths);
355
356        self.view
357    }
358
359    pub fn fill_gpu_view<F>(mut self, layers: F) -> SegmentBufferView
360    where
361        F: Fn(GeomId) -> Option<InnerLayer> + Send + Sync,
362    {
363        fn transform_point(point: (f32, f32), transform: &AffineTransform) -> (f32, f32) {
364            (
365                transform
366                    .ux
367                    .mul_add(point.0, transform.vx.mul_add(point.1, transform.tx)),
368                transform
369                    .uy
370                    .mul_add(point.0, transform.vy.mul_add(point.1, transform.ty)),
371            )
372        }
373
374        if !self.view.ids.is_empty() {
375            let point = match self.view.ids[0].and_then(&layers) {
376                None
377                | Some(
378                    InnerLayer {
379                        is_enabled: false, ..
380                    }
381                    | InnerLayer { order: None, .. },
382                ) => Default::default(),
383                Some(InnerLayer {
384                    affine_transform: None,
385                    ..
386                }) => [self.view.x[0], self.view.y[0]],
387                Some(InnerLayer {
388                    affine_transform: Some(transform),
389                    ..
390                }) => {
391                    let (x, y) = transform_point((self.view.x[0], self.view.y[0]), &transform.0);
392                    [x, y]
393                }
394            };
395            self.view.points.push(point);
396        }
397
398        let ps_layers = self.view.x.par_windows(2).with_min_len(MIN_LEN).zip_eq(
399            self.view
400                .y
401                .par_windows(2)
402                .with_min_len(MIN_LEN)
403                .zip_eq(self.view.ids.par_windows(2).with_min_len(MIN_LEN)),
404        );
405        let par_iter = ps_layers.map(|(xs, (ys, ids))| {
406            const NONE: u32 = u32::MAX;
407            let p0x = xs[0];
408            let p0y = ys[0];
409            let (p1x, p1y) = match ids[0].or(ids[1]).and_then(&layers) {
410                None
411                | Some(
412                    InnerLayer {
413                        is_enabled: false, ..
414                    }
415                    | InnerLayer { order: None, .. },
416                ) => (0.0, 0.0),
417                Some(InnerLayer {
418                    affine_transform: None,
419                    ..
420                }) => (xs[1], ys[1]),
421                Some(InnerLayer {
422                    affine_transform: Some(transform),
423                    ..
424                }) => transform_point((xs[1], ys[1]), &transform.0),
425            };
426
427            let layer = match ids[0].and_then(&layers) {
428                Some(layer) => layer,
429                // Points at then end of segment chain have to be transformed for the compute shader.
430                None => return (0, [p1x, p1y], NONE),
431            };
432
433            if let InnerLayer {
434                is_enabled: false, ..
435            } = layer
436            {
437                return (0, [p1x, p1y], NONE);
438            }
439
440            let order = match layer.order {
441                Some(order) => order.as_u32(),
442                None => return (0, [p1x, p1y], NONE),
443            };
444
445            let transform = layer
446                .affine_transform
447                .as_ref()
448                .map(|transform| &transform.0);
449
450            let (p0x, p0y) = if let Some(transform) = transform {
451                transform_point((p0x, p0y), transform)
452            } else {
453                (p0x, p0y)
454            };
455
456            if p0y == p1y {
457                return (0, [p1x, p1y], NONE);
458            }
459            let length = integers_between(p0x, p1x) + integers_between(p0y, p1y) + 1;
460
461            (length, [p1x, p1y], order)
462        });
463
464        ExtendTuple3::new((
465            &mut self.view.lengths,
466            &mut self.view.points,
467            &mut self.view.orders,
468        ))
469        .par_extend(par_iter);
470
471        prefix_sum(&mut self.view.lengths);
472
473        self.view
474    }
475}
476
477// `x`, `y` and `ids` have the same size and encode polygonal chains.
478// In `ids`, `None` identifies the last element of a chain.
479//
480// `points` and `lengths` have the same size and encode pixel segment
481// generators.
482#[derive(Debug, Default)]
483pub struct SegmentBufferView {
484    pub x: Vec<f32>,
485    pub y: Vec<f32>,
486    pub ids: Vec<Option<GeomId>>,
487    pub orders: Vec<u32>,
488    /// Lines' p0 x-coordinates multiplied by `PIXEL_WIDTH`.
489    pub x0: Vec<f32>,
490    /// Lines' p0 y-coordinates multiplied by `PIXEL_WIDTH`.
491    pub y0: Vec<f32>,
492    /// Line slopes' x-coordinates multiplied by `PIXEL_WIDTH`.
493    pub dx: Vec<f32>,
494    /// Line slopes' y-coordinates multiplied by `PIXEL_WIDTH`.
495    pub dy: Vec<f32>,
496    /// x-coordinate arithmetic progression coefficients. (`a` from `a * t + c`)
497    pub a: Vec<f32>,
498    /// y-coordinate arithmetic progression coefficients. (`b` from `b * t + d`)
499    pub b: Vec<f32>,
500    /// x-coordinate arithmetic progression coefficients. (`c` from `a * t + c`)
501    pub c: Vec<f32>,
502    /// y-coordinate arithmetic progression coefficients. (`d` from `b * t + d`)
503    pub d: Vec<f32>,
504    pub points: Vec<[f32; 2]>,
505    /// Lengths in number of pixel segments that a line would produce. See
506    /// [`manhattan_segment_length`].
507    pub lengths: Vec<u32>,
508}
509
510impl SegmentBufferView {
511    #[inline]
512    pub fn recycle(mut self) -> SegmentBuffer {
513        self.orders.clear();
514        self.x0.clear();
515        self.y0.clear();
516        self.dx.clear();
517        self.dy.clear();
518        self.a.clear();
519        self.b.clear();
520        self.c.clear();
521        self.d.clear();
522        self.lengths.clear();
523        self.points.clear();
524
525        SegmentBuffer {
526            view: self,
527            ..Default::default()
528        }
529    }
530
531    pub fn len(&self) -> usize {
532        self.lengths.last().copied().unwrap_or_default() as usize
533    }
534
535    pub fn inner_len(&self) -> usize {
536        self.x.len() - 1
537    }
538}