| //! Render commands for a single row of strips. |
| |
| // Copyright 2026 the Vello Authors |
| // SPDX-License-Identifier: Apache-2.0 OR MIT |
| |
| use crate::coarse::depth::BucketRange; |
| use crate::peniko::BlendMode; |
| use crate::util::Span; |
| use core::num::NonZeroU32; |
| use vello_common::mask::Mask; |
| use vello_common::paint::Paint; |
| |
| // TODO: If we wanted to, we could likely reduce the memory footprint from 16 bytes to 8 bytes |
| // by using 4 bits from a span (since tile size is 4, for `x` and `width` we can always store |
| // the value divided by 4), and creating a bit-packed representation of all commands. |
| |
| /// A bucketed render command. |
| #[derive(Debug, Clone, Copy)] |
| pub(crate) enum RenderCmd { |
| /// See [`PaintFill`]. |
| PaintFill(PaintFill), |
| /// Push a new temporary layer buffer. |
| PushBuf(Option<Span>), |
| /// Pop the last temporary layer buffer. |
| PopBuf, |
| /// See [`LayerFill`]. |
| LayerFill(LayerFill), |
| } |
| |
| /// Fill a span with the given paint and optionally some alpha coverage. |
| #[derive(Debug, Clone, Copy)] |
| pub(crate) struct PaintFill { |
| pub(crate) span: Span, |
| alpha_idx: Option<AlphaIdx>, |
| pub(crate) attrs_idx: u32, |
| } |
| |
| impl PaintFill { |
| pub(crate) fn new(span: Span, alpha_idx: Option<u32>, attrs_idx: u32) -> Self { |
| Self { |
| span, |
| alpha_idx: alpha_idx.map(AlphaIdx::new), |
| attrs_idx, |
| } |
| } |
| |
| pub(crate) fn alpha_idx(self) -> Option<u32> { |
| self.alpha_idx.map(AlphaIdx::get) |
| } |
| } |
| |
| /// Fill a whole range of depth buckets with the given paint. |
| #[derive(Debug, Clone, Copy)] |
| pub(crate) struct DepthFill { |
| bucket_range: BucketRange, |
| pub(crate) attrs_idx: u32, |
| } |
| |
| impl DepthFill { |
| pub(crate) fn new(bucket_range: BucketRange, attrs_idx: u32) -> Self { |
| Self { |
| bucket_range, |
| attrs_idx, |
| } |
| } |
| |
| pub(crate) fn bucket_range(self) -> BucketRange { |
| self.bucket_range |
| } |
| |
| pub(crate) fn span(self) -> Span { |
| self.bucket_range.span() |
| } |
| } |
| |
| /// Composite a span from the current temporary layer buffer into the parent |
| /// buffer and optionally apply some alpha coverage. |
| #[derive(Debug, Clone, Copy)] |
| pub(crate) struct LayerFill { |
| pub(crate) span: Span, |
| alpha_idx: Option<AlphaIdx>, |
| pub(crate) attrs_idx: u32, |
| } |
| |
| impl LayerFill { |
| pub(crate) fn new(span: Span, alpha_idx: Option<u32>, attrs_idx: u32) -> Self { |
| Self { |
| span, |
| alpha_idx: alpha_idx.map(AlphaIdx::new), |
| attrs_idx, |
| } |
| } |
| |
| pub(crate) fn alpha_idx(self) -> Option<u32> { |
| self.alpha_idx.map(AlphaIdx::get) |
| } |
| } |
| |
| // We use `NonZeroU32` so that `Option<AlphaIdx>` still only needs 4 bytes. |
| #[derive(Debug, Clone, Copy)] |
| struct AlphaIdx(NonZeroU32); |
| |
| impl AlphaIdx { |
| fn new(alpha_idx: u32) -> Self { |
| Self(NonZeroU32::new(alpha_idx.checked_add(1).expect("alpha index overflow")).unwrap()) |
| } |
| |
| fn get(self) -> u32 { |
| self.0.get() - 1 |
| } |
| } |
| |
| #[doc(hidden)] |
| #[derive(Debug, Clone)] |
| pub struct PaintFillAttrs { |
| pub paint: Paint, |
| pub blend_mode: BlendMode, |
| pub mask: Option<Mask>, |
| pub draw_id: u32, |
| pub thread_idx: u8, |
| /// See the comment in `CommandBucketer::bucket_commands`. |
| pub origin: (u16, u16), |
| } |
| |
| #[derive(Debug, Clone)] |
| pub(crate) struct LayerFillAttrs { |
| pub(crate) blend_mode: BlendMode, |
| pub(crate) opacity: f32, |
| pub(crate) mask: Option<Mask>, |
| pub(crate) draw_id: u32, |
| /// In case there is any alpha associated with the layer command, this stores |
| /// the index of the thread that stores the alpha. |
| pub(crate) thread_idx: u8, |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::{AlphaIdx, RenderCmd}; |
| use core::mem::{needs_drop, size_of}; |
| |
| #[test] |
| fn alpha_idx_size() { |
| assert_eq!(size_of::<Option<AlphaIdx>>(), 4); |
| } |
| |
| #[test] |
| fn render_cmd_assertions() { |
| assert_eq!(size_of::<RenderCmd>(), 16); |
| assert!(!needs_drop::<RenderCmd>()); |
| } |
| } |