blob: 63f14ffad2966ba6cc127f1b8e5b7a2266627951 [file]
//! 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>());
}
}