tessera_ui/
render_scene.rs

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