tessera_ui/renderer/
command.rs

1//! Unified command system for rendering and computation.
2//!
3//! This module defines the `Command` enum that unifies draw and compute
4//! operations into a single type, enabling seamless integration of graphics and
5//! compute pipelines in the rendering workflow.
6
7use std::any::Any;
8
9use crate::{
10    ComputeCommand, DrawCommand,
11    px::{Px, PxRect},
12};
13
14/// Defines the sampling requirements for a rendering command that needs a
15/// barrier.
16#[derive(Debug, Clone, Copy, PartialEq)]
17pub enum SampleRegion {
18    /// The command needs to sample from the entire previously rendered scene.
19    /// This will cause a full-screen texture copy.
20    Global,
21    /// The command needs to sample from a region relative to its own bounding
22    /// box.
23    PaddedLocal(PaddingRect),
24    /// The command needs to sample from a specific, absolute region of the
25    /// screen.
26    Absolute(PxRect),
27}
28
29/// Defines the drawing region for a rendering command.
30#[derive(Debug, Clone, Copy, PartialEq)]
31pub enum DrawRegion {
32    /// The command draws to the entire surface.
33    Global,
34    /// The command draws to a region relative to its own bounding box.
35    PaddedLocal(PaddingRect),
36    /// The command draws to a specific, absolute region of the screen.
37    Absolute(PxRect),
38}
39
40/// Padding values for all four sides of a rectangle.
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub struct PaddingRect {
43    /// Padding applied to the top edge.
44    pub top: Px,
45    /// Padding applied to the right edge.
46    pub right: Px,
47    /// Padding applied to the bottom edge.
48    pub bottom: Px,
49    /// Padding applied to the left edge.
50    pub left: Px,
51}
52
53impl PaddingRect {
54    /// A zero padding rectangle that leaves the sampling region unchanged.
55    pub const ZERO: Self = Self {
56        top: Px::ZERO,
57        right: Px::ZERO,
58        bottom: Px::ZERO,
59        left: Px::ZERO,
60    };
61
62    /// Creates a uniform padding rectangle with the same padding on all sides.
63    #[must_use]
64    pub const fn uniform(padding: Px) -> Self {
65        Self {
66            top: padding,
67            right: padding,
68            bottom: padding,
69            left: padding,
70        }
71    }
72}
73
74impl SampleRegion {
75    /// A zero-padding local barrier requirement for commands that only sample
76    /// within their bounds.
77    pub const ZERO_PADDING_LOCAL: Self = Self::PaddedLocal(PaddingRect::ZERO);
78
79    /// Creates a `PaddedLocal` barrier requirement with uniform sampling
80    /// padding on all sides.
81    #[must_use]
82    pub const fn uniform_padding_local(padding: Px) -> Self {
83        Self::PaddedLocal(PaddingRect::uniform(padding))
84    }
85}
86
87/// Trait providing type erasure capabilities for command objects.
88///
89/// This trait allows commands to be stored and passed around as trait objects
90/// while still providing access to their concrete types when needed for
91/// pipeline dispatch.
92pub trait AsAny {
93    /// Returns a reference to the concrete type as `&dyn Any`.
94    fn as_any(&self) -> &dyn Any;
95}
96
97/// Blanket implementation of `AsAny` for all types that implement `Any`.
98impl<T: Any> AsAny for T {
99    fn as_any(&self) -> &dyn Any {
100        self
101    }
102}
103
104/// Unified command enum that can represent either a draw or compute operation.
105///
106/// This enum enables the rendering system to process both graphics and compute
107/// commands in a unified pipeline, with proper barrier handling for multi-pass
108/// rendering scenarios.
109pub enum Command {
110    /// A graphics rendering command processed by draw pipelines
111    Draw(Box<dyn DrawCommand>),
112    /// A GPU computation command processed by compute pipelines
113    Compute(Box<dyn ComputeCommand>),
114    /// A command to push a clipping rectangle onto the stack
115    ClipPush(PxRect),
116    /// A command to pop the most recent clipping rectangle from the stack
117    ClipPop,
118}
119
120impl Command {
121    /// Returns the barrier requirement for this command.
122    ///
123    /// Commands that need to sample from previously rendered content
124    /// should return a barrier requirement to ensure proper synchronization.
125    #[must_use]
126    pub fn barrier(&self) -> Option<SampleRegion> {
127        match self {
128            Self::Draw(command) => command.sample_region(),
129            // Currently, compute can only be used for after effects,
130            Self::Compute(command) => Some(command.barrier()),
131            Self::ClipPush(_) | Self::ClipPop => None, // Clipping commands do not require barriers
132        }
133    }
134}
135
136impl Clone for Command {
137    fn clone(&self) -> Self {
138        match self {
139            Self::Draw(cmd) => Self::Draw(cmd.clone_box()),
140            Self::Compute(cmd) => Self::Compute(cmd.clone_box()),
141            Self::ClipPush(rect) => Self::ClipPush(*rect),
142            Self::ClipPop => Self::ClipPop,
143        }
144    }
145}
146
147/// Automatic conversion from boxed draw commands to unified commands
148impl From<Box<dyn DrawCommand>> for Command {
149    fn from(val: Box<dyn DrawCommand>) -> Self {
150        Self::Draw(val)
151    }
152}
153
154/// Automatic conversion from boxed compute commands to unified commands
155impl From<Box<dyn ComputeCommand>> for Command {
156    fn from(val: Box<dyn ComputeCommand>) -> Self {
157        Self::Compute(val)
158    }
159}