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}