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    pub top: Px,
63    pub right: Px,
64    pub bottom: Px,
65    pub left: Px,
66}
67
68impl PaddingRect {
69    pub const ZERO: Self = Self {
70        top: Px::ZERO,
71        right: Px::ZERO,
72        bottom: Px::ZERO,
73        left: Px::ZERO,
74    };
75
76    /// Creates a uniform padding rectangle with the same padding on all sides.
77    #[must_use]
78    pub const fn uniform(padding: Px) -> Self {
79        Self {
80            top: padding,
81            right: padding,
82            bottom: padding,
83            left: padding,
84        }
85    }
86}
87
88impl BarrierRequirement {
89    pub const ZERO_PADDING_LOCAL: Self = Self::PaddedLocal(PaddingRect::ZERO);
90
91    /// Creates a `PaddedLocal` barrier requirement with uniform sampling padding on all sides.
92    #[must_use]
93    pub const fn uniform_padding_local(padding: Px) -> Self {
94        Self::PaddedLocal(PaddingRect::uniform(padding))
95    }
96}
97
98/// Trait providing type erasure capabilities for command objects.
99///
100/// This trait allows commands to be stored and passed around as trait objects
101/// while still providing access to their concrete types when needed for
102/// pipeline dispatch.
103pub trait AsAny {
104    /// Returns a reference to the concrete type as `&dyn Any`.
105    fn as_any(&self) -> &dyn Any;
106}
107
108/// Blanket implementation of `AsAny` for all types that implement `Any`.
109impl<T: Any> AsAny for T {
110    fn as_any(&self) -> &dyn Any {
111        self
112    }
113}
114
115/// Unified command enum that can represent either a draw or compute operation.
116///
117/// This enum enables the rendering system to process both graphics and compute
118/// commands in a unified pipeline, with proper barrier handling for multi-pass
119/// rendering scenarios.
120pub enum Command {
121    /// A graphics rendering command processed by draw pipelines
122    Draw(Box<dyn DrawCommand>),
123    /// A GPU computation command processed by compute pipelines
124    Compute(Box<dyn ComputeCommand>),
125    /// A command to push a clipping rectangle onto the stack
126    ClipPush(PxRect),
127    /// A command to pop the most recent clipping rectangle from the stack
128    ClipPop,
129}
130
131impl Command {
132    /// Returns the barrier requirement for this command.
133    ///
134    /// Commands that need to sample from previously rendered content
135    /// should return a barrier requirement to ensure proper synchronization.
136    #[must_use]
137    pub fn barrier(&self) -> Option<BarrierRequirement> {
138        match self {
139            Self::Draw(command) => command.barrier(),
140            // Currently, compute can only be used for after effects,
141            Self::Compute(command) => Some(command.barrier()),
142            Self::ClipPush(_) | Self::ClipPop => None, // Clipping commands do not require barriers
143        }
144    }
145}
146
147impl Clone for Command {
148    fn clone(&self) -> Self {
149        match self {
150            Self::Draw(cmd) => Self::Draw(cmd.clone_box()),
151            Self::Compute(cmd) => Self::Compute(cmd.clone_box()),
152            Self::ClipPush(rect) => Self::ClipPush(*rect),
153            Self::ClipPop => Self::ClipPop,
154        }
155    }
156}
157
158/// Automatic conversion from boxed draw commands to unified commands
159impl From<Box<dyn DrawCommand>> for Command {
160    fn from(val: Box<dyn DrawCommand>) -> Self {
161        Self::Draw(val)
162    }
163}
164
165/// Automatic conversion from boxed compute commands to unified commands
166impl From<Box<dyn ComputeCommand>> for Command {
167    fn from(val: Box<dyn ComputeCommand>) -> Self {
168        Self::Compute(val)
169    }
170}