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}