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 operations
4//! into a single type, enabling seamless integration of graphics and compute pipelines
5//! 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 barrier.
15#[derive(Debug, Clone, Copy, PartialEq)]
16pub enum BarrierRequirement {
17    /// The command needs to sample from the entire previously rendered scene.
18    /// This will cause a full-screen texture copy.
19    Global,
20
21    /// The command needs to sample from a region relative to its own bounding box.
22    ///
23    /// - Sampling padding: The region from which pixels are read (e.g., blur needs to read
24    ///   pixels outside the target area). This determines the texture region captured before
25    ///   the command executes, while the write target remains the component's measured size.
26    ///
27    /// For most cases without special batching requirements, set a uniform padding value.
28    /// For effects like blur that need large sampling areas but have small target areas,
29    /// use large sampling padding so enough source pixels are available while batching still
30    /// relies on the component's bounds.
31    ///
32    /// # Examples
33    ///
34    /// Simple case (uniform sampling padding):
35    ///
36    /// ```
37    /// use tessera_ui::renderer::command::{BarrierRequirement, PaddingRect};
38    /// use tessera_ui::Px;
39    ///
40    /// let req = BarrierRequirement::PaddedLocal(PaddingRect::uniform(Px(10)));
41    /// let _ = req;
42    /// ```
43    ///
44    /// Blur optimization (large sampling area):
45    ///
46    /// ```
47    /// use tessera_ui::renderer::command::{BarrierRequirement, PaddingRect};
48    /// use tessera_ui::Px;
49    ///
50    /// let req = BarrierRequirement::PaddedLocal(PaddingRect::uniform(Px(75)));
51    /// let _ = req;
52    /// ```
53    PaddedLocal(PaddingRect),
54
55    /// The command needs to sample from a specific, absolute region of the screen.
56    Absolute(PxRect),
57}
58
59/// Padding values for all four sides of a rectangle.
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct PaddingRect {
62    /// Padding applied to the top edge.
63    pub top: Px,
64    /// Padding applied to the right edge.
65    pub right: Px,
66    /// Padding applied to the bottom edge.
67    pub bottom: Px,
68    /// Padding applied to the left edge.
69    pub left: Px,
70}
71
72impl PaddingRect {
73    /// A zero padding rectangle that leaves the sampling region unchanged.
74    pub const ZERO: Self = Self {
75        top: Px::ZERO,
76        right: Px::ZERO,
77        bottom: Px::ZERO,
78        left: Px::ZERO,
79    };
80
81    /// Creates a uniform padding rectangle with the same padding on all sides.
82    #[must_use]
83    pub const fn uniform(padding: Px) -> Self {
84        Self {
85            top: padding,
86            right: padding,
87            bottom: padding,
88            left: padding,
89        }
90    }
91}
92
93impl BarrierRequirement {
94    /// A zero-padding local barrier requirement for commands that only sample within their bounds.
95    pub const ZERO_PADDING_LOCAL: Self = Self::PaddedLocal(PaddingRect::ZERO);
96
97    /// Creates a `PaddedLocal` barrier requirement with uniform sampling padding on all sides.
98    #[must_use]
99    pub const fn uniform_padding_local(padding: Px) -> Self {
100        Self::PaddedLocal(PaddingRect::uniform(padding))
101    }
102}
103
104/// Trait providing type erasure capabilities for command objects.
105///
106/// This trait allows commands to be stored and passed around as trait objects
107/// while still providing access to their concrete types when needed for
108/// pipeline dispatch.
109pub trait AsAny {
110    /// Returns a reference to the concrete type as `&dyn Any`.
111    fn as_any(&self) -> &dyn Any;
112}
113
114/// Blanket implementation of `AsAny` for all types that implement `Any`.
115impl<T: Any> AsAny for T {
116    fn as_any(&self) -> &dyn Any {
117        self
118    }
119}
120
121/// Unified command enum that can represent either a draw or compute operation.
122///
123/// This enum enables the rendering system to process both graphics and compute
124/// commands in a unified pipeline, with proper barrier handling for multi-pass
125/// rendering scenarios.
126pub enum Command {
127    /// A graphics rendering command processed by draw pipelines
128    Draw(Box<dyn DrawCommand>),
129    /// A GPU computation command processed by compute pipelines
130    Compute(Box<dyn ComputeCommand>),
131    /// A command to push a clipping rectangle onto the stack
132    ClipPush(PxRect),
133    /// A command to pop the most recent clipping rectangle from the stack
134    ClipPop,
135}
136
137impl Command {
138    /// Returns the barrier requirement for this command.
139    ///
140    /// Commands that need to sample from previously rendered content
141    /// should return a barrier requirement to ensure proper synchronization.
142    #[must_use]
143    pub fn barrier(&self) -> Option<BarrierRequirement> {
144        match self {
145            Self::Draw(command) => command.barrier(),
146            // Currently, compute can only be used for after effects,
147            Self::Compute(command) => Some(command.barrier()),
148            Self::ClipPush(_) | Self::ClipPop => None, // Clipping commands do not require barriers
149        }
150    }
151}
152
153impl Clone for Command {
154    fn clone(&self) -> Self {
155        match self {
156            Self::Draw(cmd) => Self::Draw(cmd.clone_box()),
157            Self::Compute(cmd) => Self::Compute(cmd.clone_box()),
158            Self::ClipPush(rect) => Self::ClipPush(*rect),
159            Self::ClipPop => Self::ClipPop,
160        }
161    }
162}
163
164/// Automatic conversion from boxed draw commands to unified commands
165impl From<Box<dyn DrawCommand>> for Command {
166    fn from(val: Box<dyn DrawCommand>) -> Self {
167        Self::Draw(val)
168    }
169}
170
171/// Automatic conversion from boxed compute commands to unified commands
172impl From<Box<dyn ComputeCommand>> for Command {
173    fn from(val: Box<dyn ComputeCommand>) -> Self {
174        Self::Compute(val)
175    }
176}