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}