Skip to main content

tessera_ui/
render_scene.rs

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