Skip to main content

frust_engine/compile/
draw.rs

1//! The engine's draw record and its depth counter.
2//!
3//! A compiled frame is a flat list of [`EngineDraw`]s, each naming a paint, a
4//! depth, and the half-open range of strips the compiler generated for it. The
5//! strips themselves live in one shared
6//! [`StripStorage`](vello_common::strip_generator::StripStorage) so a whole
7//! frame uploads as a single instance buffer; a draw only borrows its slice of
8//! it.
9//!
10//! [`EngineDraw`] implements [`Drawable`] so the recorder can fold each draw's
11//! bounding box into the enclosing layer's. Per that trait's contract the
12//! caller slices the strips before the call, so `bbox` measures exactly the
13//! strips it is handed rather than re-applying `strip_range`.
14
15use core::ops::Range;
16
17use vello_common::geometry::RectU16;
18use vello_common::paint::Paint;
19use vello_common::record::Drawable;
20use vello_common::strip::Strip;
21use vello_common::util::strip_bbox;
22
23/// One recorded draw: a paint, a depth, and the strips it covers.
24///
25/// `paint` is a `vello_common` [`Paint`] — either an inline solid colour or an
26/// index into the frame's encoded-paint table. Carrying the vello type here
27/// (rather than a `peniko::Brush`) is what keeps the GPU-side conversion a
28/// plain field read, and is the seam the paint-encoding pass writes into.
29#[derive(Debug, Clone)]
30pub struct EngineDraw {
31    /// Paint applied to every strip in `strip_range`.
32    pub paint: Paint,
33    /// Painter's-algorithm depth, assigned by [`DepthCounter`].
34    ///
35    /// The back-most draw of a frame is `0` and each subsequent draw is one
36    /// greater, matching the GPU strip instance's `depth_index` contract: a
37    /// larger value is nearer the viewer and wins the depth test.
38    pub depth: u32,
39    /// Half-open range selecting this draw's strips from the frame's shared
40    /// strip storage.
41    pub strip_range: Range<usize>,
42}
43
44impl EngineDraw {
45    /// A draw covering `strip_range` with `paint` at `depth`.
46    pub fn new(paint: Paint, depth: u32, strip_range: Range<usize>) -> Self {
47        Self {
48            paint,
49            depth,
50            strip_range,
51        }
52    }
53}
54
55impl Drawable for EngineDraw {
56    fn bbox(&self, strips: &[Strip]) -> Option<RectU16> {
57        strip_bbox(strips)
58    }
59}
60
61/// Hands out the monotonically increasing depths a frame's draws are stamped
62/// with.
63///
64/// Draws are emitted in paint order, so the counter runs from `0` (back-most)
65/// upward and never repeats a value inside one frame. It saturates rather than
66/// wrapping: a frame with more than `u32::MAX` draws would otherwise reuse a
67/// depth and let a later draw lose the depth test to an earlier one, and the
68/// compiler has no error to report on the frame path for it.
69#[derive(Debug, Default, Clone, Copy)]
70pub struct DepthCounter {
71    next: u32,
72}
73
74impl DepthCounter {
75    /// A counter whose first handed-out depth is `0`.
76    pub fn new() -> Self {
77        Self::default()
78    }
79
80    /// The next depth, advancing the counter.
81    pub fn advance(&mut self) -> u32 {
82        let depth = self.next;
83        self.next = self.next.saturating_add(1);
84        depth
85    }
86
87    /// How many depths have been handed out.
88    pub fn count(&self) -> u32 {
89        self.next
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96    use vello_common::color::palette::css::RED;
97
98    #[test]
99    fn depths_start_at_zero_and_increase() {
100        let mut counter = DepthCounter::new();
101        assert_eq!(counter.advance(), 0);
102        assert_eq!(counter.advance(), 1);
103        assert_eq!(counter.advance(), 2);
104        assert_eq!(counter.count(), 3);
105    }
106
107    #[test]
108    fn depth_saturates_instead_of_wrapping() {
109        let mut counter = DepthCounter { next: u32::MAX };
110        assert_eq!(counter.advance(), u32::MAX);
111        assert_eq!(counter.advance(), u32::MAX);
112    }
113
114    #[test]
115    fn a_draw_with_no_strips_has_no_bbox() {
116        let draw = EngineDraw::new(Paint::from(RED), 0, 0..0);
117        assert!(draw.bbox(&[]).is_none());
118    }
119}