lambda_platform/gfx/
render_pass.rs1use gfx_hal::device::Device;
2
3use super::{
4 gpu::Gpu,
5 surface::ColorFormat,
6};
7
8#[derive(Debug)]
11pub enum Operations {
12 DontCare,
13 Load,
14 Clear,
15 Store,
16}
17
18impl Operations {
19 fn to_gfx_hal_load_operation(&self) -> gfx_hal::pass::AttachmentLoadOp {
20 match self {
21 Operations::DontCare => gfx_hal::pass::AttachmentLoadOp::DontCare,
22 Operations::Load => gfx_hal::pass::AttachmentLoadOp::Load,
23 Operations::Clear => gfx_hal::pass::AttachmentLoadOp::Clear,
24 _ => panic!("Cannot pass in {:?} as an operation for the attachment load operation!", self)
25 }
26 }
27
28 fn to_gfx_hal_store_operation(&self) -> gfx_hal::pass::AttachmentStoreOp {
29 return match self {
30 Operations::DontCare => gfx_hal::pass::AttachmentStoreOp::DontCare,
31 Operations::Store => gfx_hal::pass::AttachmentStoreOp::Store,
32 _ => panic!(
33 "Cannot pass in {:?} as an operation for the attachment store operation!",
34 self
35 ),
36 };
37 }
38}
39
40pub struct AttachmentBuilder {
44 samples: u8,
45 color_format: Option<ColorFormat>,
46 load_operation: gfx_hal::pass::AttachmentLoadOp,
47 store_operation: gfx_hal::pass::AttachmentStoreOp,
48}
49
50impl AttachmentBuilder {
52 pub fn new() -> Self {
53 return Self {
54 samples: 0,
55 color_format: None,
56 load_operation: gfx_hal::pass::AttachmentLoadOp::DontCare,
57 store_operation: gfx_hal::pass::AttachmentStoreOp::DontCare,
58 };
59 }
60
61 pub fn with_samples(mut self, samples: u8) -> Self {
63 self.samples = samples;
64 return self;
65 }
66
67 pub fn with_color_format(mut self, color_format: ColorFormat) -> Self {
69 self.color_format = Some(color_format);
70 return self;
71 }
72
73 pub fn on_load(mut self, operation: Operations) -> Self {
75 self.load_operation = operation.to_gfx_hal_load_operation();
76 return self;
77 }
78
79 pub fn on_store(mut self, operation: Operations) -> Self {
81 self.store_operation = operation.to_gfx_hal_store_operation();
82 return self;
83 }
84
85 pub fn build(self) -> Attachment {
87 return Attachment {
88 attachment: gfx_hal::pass::Attachment {
89 format: self.color_format,
90 samples: self.samples,
91 ops: gfx_hal::pass::AttachmentOps::new(
92 self.load_operation,
93 self.store_operation,
94 ),
95 stencil_ops: gfx_hal::pass::AttachmentOps::DONT_CARE,
96 layouts: gfx_hal::image::Layout::Undefined
97 ..gfx_hal::image::Layout::Present,
98 },
99 };
100 }
101}
102
103pub struct Attachment {
104 attachment: gfx_hal::pass::Attachment,
105}
106
107impl Attachment {
108 fn gfx_hal_attachment(&self) -> gfx_hal::pass::Attachment {
109 return self.attachment.clone();
110 }
111}
112
113pub use gfx_hal::image::Layout as ImageLayoutHint;
116
117pub struct SubpassBuilder {
118 color_attachment: Option<(usize, ImageLayoutHint)>,
119}
120
121impl SubpassBuilder {
122 pub fn new() -> Self {
123 return Self {
124 color_attachment: None,
125 };
126 }
127
128 pub fn with_color_attachment(
129 mut self,
130 attachment_index: usize,
131 layout: ImageLayoutHint,
132 ) -> Self {
133 self.color_attachment = Some((attachment_index, layout));
134 return self;
135 }
136 pub fn with_inputs() {
137 todo!("Implement input support for subpasses")
138 }
139 pub fn with_resolves() {
140 todo!("Implement resolving support for subpasses")
141 }
142 pub fn with_preserves() {
143 todo!("Implement preservation support for subpasses")
144 }
145
146 pub fn build<'a>(self) -> Subpass<'a> {
147 return Subpass {
148 subpass: gfx_hal::pass::SubpassDesc {
149 colors: &[(0, ImageLayoutHint::ColorAttachmentOptimal)],
150 depth_stencil: None,
151 inputs: &[],
152 resolves: &[],
153 preserves: &[],
154 },
155 };
156 }
157}
158
159pub struct Subpass<'a> {
160 subpass: gfx_hal::pass::SubpassDesc<'a>,
161}
162
163impl<'a> Subpass<'a> {
164 fn gfx_hal_subpass(self) -> gfx_hal::pass::SubpassDesc<'a> {
165 return self.subpass;
166 }
167}
168
169pub struct RenderPassBuilder<'builder> {
172 attachments: Vec<Attachment>,
173 subpasses: Vec<Subpass<'builder>>,
174}
175
176impl<'builder> RenderPassBuilder<'builder> {
177 pub fn new() -> Self {
178 return Self {
179 attachments: vec![],
180 subpasses: vec![],
181 };
182 }
183
184 pub fn add_attachment(mut self, attachment: Attachment) -> Self {
186 self.attachments.push(attachment);
187 return self;
188 }
189
190 pub fn add_subpass(mut self, subpass: Subpass<'builder>) -> Self {
191 self.subpasses.push(subpass);
192 return self;
193 }
194
195 pub fn build<RenderBackend: gfx_hal::Backend>(
196 self,
197 gpu: &Gpu<RenderBackend>,
198 ) -> RenderPass<RenderBackend> {
199 let attachments = match self.attachments.is_empty() {
202 true => vec![AttachmentBuilder::new()
203 .with_samples(1)
204 .on_load(Operations::Clear)
205 .on_store(Operations::Store)
206 .with_color_format(ColorFormat::Rgba8Srgb)
207 .build()
208 .gfx_hal_attachment()],
209 false => self
210 .attachments
211 .into_iter()
212 .map(|attachment| attachment.gfx_hal_attachment())
213 .collect(),
214 };
215
216 let subpasses = match self.subpasses.is_empty() {
218 true => vec![SubpassBuilder::new().build().gfx_hal_subpass()],
219 false => self
220 .subpasses
221 .into_iter()
222 .map(|subpass| subpass.gfx_hal_subpass())
223 .collect(),
224 };
225
226 let render_pass = unsafe {
227 gpu.internal_logical_device().create_render_pass(
228 attachments.into_iter(),
229 subpasses.into_iter(),
230 vec![].into_iter(),
231 )
232 }
233 .expect("The GPU does not have enough memory to allocate a render pass.");
234
235 return RenderPass { render_pass };
236 }
237}
238
239#[derive(Debug)]
240pub struct RenderPass<RenderBackend: gfx_hal::Backend> {
241 render_pass: RenderBackend::RenderPass,
242}
243
244impl<RenderBackend: gfx_hal::Backend> RenderPass<RenderBackend> {
245 pub fn destroy(self, gpu: &Gpu<RenderBackend>) {
246 unsafe {
247 gpu
248 .internal_logical_device()
249 .destroy_render_pass(self.render_pass);
250 }
251 }
252}
253
254impl<RenderBackend: gfx_hal::Backend> RenderPass<RenderBackend> {
255 pub(super) fn internal_render_pass(&self) -> &RenderBackend::RenderPass {
256 return &self.render_pass;
257 }
258}