Skip to main content

rotex_types/
frame.rs

1//! Frame and pass descriptors for multi-pass rendering and compute.
2//!
3//! Pass descriptors are **user-composed** inputs to `RhiCommand::BeginRenderPass`.
4//! The HAL does not interpret scene data or choose draw strategies — the user
5//! builds explicit command lists (`BindDescriptorSets`, `DrawIndexed`, etc.)
6//! between `BeginRenderPass` and `EndRenderPass`.
7//!
8//! Bind group layouts and set indices are user-defined via `BindGroupLayoutDescriptor`.
9//! ```rust
10//! use rotex_types::{ColorAttachmentLoad, FrameDescriptor, FramePass, PassDescriptor};
11//!
12//! let frame = FrameDescriptor::new(vec![
13//!     FramePass::Graphics(
14//!         PassDescriptor::new("scene")
15//!             .with_clear_color([0.02, 0.02, 0.04, 1.0])
16//!             .with_clear_depth(Some(1.0)),
17//!     ),
18//!     FramePass::Graphics(
19//!         PassDescriptor::new("ui").with_color_load(ColorAttachmentLoad::Load),
20//!     ),
21//! ]);
22//! ```
23
24use crate::resource::{BufferUsageIntent, ComputePipelineId, TextureId};
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27pub enum ColorAttachmentLoad {
28    Clear,
29    Load,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33pub enum DepthAttachmentLoad {
34    Clear,
35    Load,
36    None,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
40pub enum PassColorTarget {
41    Swapchain,
42    Texture(TextureId),
43}
44
45#[derive(Debug, Clone)]
46pub struct PassDescriptor {
47    pub name: String,
48    pub color_target: PassColorTarget,
49    pub color_load: ColorAttachmentLoad,
50    pub clear_color: [f32; 4],
51    pub depth_load: DepthAttachmentLoad,
52    pub clear_depth: f32,
53    pub instance_indices: Vec<usize>,
54    pub buffer_intents: Vec<BufferUsageIntent>,
55}
56
57impl PassDescriptor {
58    pub fn new(name: impl Into<String>) -> Self {
59        Self {
60            name: name.into(),
61            color_target: PassColorTarget::Swapchain,
62            color_load: ColorAttachmentLoad::Clear,
63            clear_color: [0.04, 0.05, 0.08, 1.0],
64            depth_load: DepthAttachmentLoad::None,
65            clear_depth: 1.0,
66            instance_indices: Vec::new(),
67            buffer_intents: Vec::new(),
68        }
69    }
70
71    pub fn uses_depth_attachment(&self) -> bool {
72        !matches!(self.depth_load, DepthAttachmentLoad::None)
73    }
74
75    pub fn with_clear_color(mut self, clear_color: [f32; 4]) -> Self {
76        self.clear_color = clear_color;
77        self.color_load = ColorAttachmentLoad::Clear;
78        self
79    }
80
81    pub fn with_clear_depth(mut self, clear_depth: Option<f32>) -> Self {
82        match clear_depth {
83            Some(depth) => {
84                self.depth_load = DepthAttachmentLoad::Clear;
85                self.clear_depth = depth;
86            }
87            None => {
88                self.depth_load = DepthAttachmentLoad::None;
89            }
90        }
91        self
92    }
93
94    pub fn with_color_load(mut self, color_load: ColorAttachmentLoad) -> Self {
95        self.color_load = color_load;
96        self
97    }
98
99    pub fn with_depth_load(mut self, depth_load: DepthAttachmentLoad) -> Self {
100        self.depth_load = depth_load;
101        self
102    }
103
104    pub fn with_color_target(mut self, color_target: PassColorTarget) -> Self {
105        self.color_target = color_target;
106        self
107    }
108
109    pub fn with_instance_indices(mut self, instance_indices: Vec<usize>) -> Self {
110        self.instance_indices = instance_indices;
111        self
112    }
113
114    pub fn with_buffer_intents(mut self, buffer_intents: Vec<BufferUsageIntent>) -> Self {
115        self.buffer_intents = buffer_intents;
116        self
117    }
118
119    pub fn into_frame_pass(self) -> FramePass {
120        FramePass::Graphics(self)
121    }
122}
123
124#[derive(Debug, Clone)]
125pub struct ComputePassDescriptor {
126    pub name: String,
127    pub pipeline: ComputePipelineId,
128    pub workgroup_count: [u32; 3],
129    pub buffer_intents: Vec<BufferUsageIntent>,
130}
131
132impl ComputePassDescriptor {
133    pub fn new(
134        name: impl Into<String>,
135        pipeline: ComputePipelineId,
136        workgroup_count: [u32; 3],
137    ) -> Self {
138        Self {
139            name: name.into(),
140            pipeline,
141            workgroup_count,
142            buffer_intents: Vec::new(),
143        }
144    }
145
146    pub fn with_buffer_intents(mut self, buffer_intents: Vec<BufferUsageIntent>) -> Self {
147        self.buffer_intents = buffer_intents;
148        self
149    }
150
151    pub fn into_frame_pass(self) -> FramePass {
152        FramePass::Compute(self)
153    }
154}
155
156#[derive(Debug, Clone)]
157pub enum FramePass {
158    Graphics(PassDescriptor),
159    Compute(ComputePassDescriptor),
160}
161
162#[derive(Debug, Clone)]
163pub struct FrameDescriptor {
164    pub passes: Vec<FramePass>,
165}
166
167impl FrameDescriptor {
168    pub fn new(passes: Vec<FramePass>) -> Self {
169        Self { passes }
170    }
171
172    pub fn new_graphics(passes: Vec<PassDescriptor>) -> Self {
173        Self {
174            passes: passes.into_iter().map(FramePass::Graphics).collect(),
175        }
176    }
177
178    pub fn single_pass(clear_color: [f32; 4], clear_depth: Option<f32>) -> Self {
179        Self::new_graphics(vec![
180            PassDescriptor::new("main")
181                .with_clear_color(clear_color)
182                .with_clear_depth(clear_depth),
183        ])
184    }
185}