maia/
render_pass.rs

1// Copyright 2022 Google LLC
2
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::device::Device;
10use crate::enums::*;
11use crate::error::{Error, Result};
12use crate::types::*;
13
14/// A
15#[doc = crate::spec_link!("render pass", "8", "renderpass")]
16#[derive(Debug)]
17pub struct RenderPass {
18    handle: Handle<VkRenderPass>,
19    compat: RenderPassCompat,
20    pub(crate) device: Arc<Device>,
21}
22
23impl RenderPass {
24    #[doc = crate::man_link!(vkCreateRenderPass)]
25    pub fn new(
26        device: &Arc<Device>, info: &RenderPassCreateInfo,
27    ) -> Result<Arc<Self>> {
28        for subpass in info.subpasses {
29            if subpass.color_attachments.len()
30                > device.limits().max_color_attachments
31            {
32                return Err(Error::LimitExceeded);
33            }
34        }
35        let compat = RenderPassCompat::new(info)?;
36        let mut handle = None;
37        unsafe {
38            (device.fun.create_render_pass)(
39                device.handle(),
40                info,
41                None,
42                &mut handle,
43            )?;
44        }
45        let handle = handle.unwrap();
46        Ok(Arc::new(Self { handle, compat, device: device.clone() }))
47    }
48
49    /// Borrows the inner Vulkan handle.
50    pub fn handle(&self) -> Ref<VkRenderPass> {
51        self.handle.borrow()
52    }
53    /// Returns the number of subpasses.
54    pub fn num_subpasses(&self) -> u32 {
55        self.compat.subpasses.len() as u32
56    }
57    /// Returns the associated device.
58    pub fn device(&self) -> &Arc<Device> {
59        &self.device
60    }
61    /// Returns true if this render pass is compatible with `other`
62    pub fn compatible(&self, other: &Self) -> bool {
63        std::ptr::eq(self, other) || self.compat == other.compat
64    }
65}
66
67impl Drop for RenderPass {
68    fn drop(&mut self) {
69        unsafe {
70            (self.device.fun.destroy_render_pass)(
71                self.device.handle(),
72                self.handle.borrow_mut(),
73                None,
74            )
75        }
76    }
77}
78
79#[derive(Debug, PartialEq, Eq)]
80struct AttachmentRefCompat {
81    format: Format,
82    samples: SampleCount,
83}
84
85#[derive(Debug, Eq)]
86struct SubpassCompat {
87    input_attachments: Vec<Option<AttachmentRefCompat>>,
88    color_attachments: Vec<Option<AttachmentRefCompat>>,
89    resolve_attachments: Vec<Option<AttachmentRefCompat>>,
90    depth_stencil_attachments: Vec<Option<AttachmentRefCompat>>,
91    preserve_attachments: Vec<Option<AttachmentRefCompat>>,
92}
93
94#[derive(Debug, PartialEq, Eq)]
95struct RenderPassCompat {
96    subpasses: Vec<SubpassCompat>,
97    dependencies: Vec<SubpassDependency>,
98}
99
100fn flatten_ref<T>(opt: Option<&Option<T>>) -> Option<&T> {
101    match opt {
102        Some(Some(v)) => Some(v),
103        _ => None,
104    }
105}
106
107fn att_ref_array_compat(
108    a: &[Option<AttachmentRefCompat>], b: &[Option<AttachmentRefCompat>],
109) -> bool {
110    for i in 0..a.len().max(b.len()) {
111        if flatten_ref(a.get(i)) != flatten_ref(b.get(i)) {
112            return false;
113        }
114    }
115    true
116}
117
118impl PartialEq for SubpassCompat {
119    fn eq(&self, other: &Self) -> bool {
120        att_ref_array_compat(&self.input_attachments, &other.input_attachments)
121            && att_ref_array_compat(
122                &self.color_attachments,
123                &other.color_attachments,
124            )
125            && att_ref_array_compat(
126                &self.resolve_attachments,
127                &other.resolve_attachments,
128            )
129            && att_ref_array_compat(
130                &self.depth_stencil_attachments,
131                &other.depth_stencil_attachments,
132            )
133            && att_ref_array_compat(
134                &self.preserve_attachments,
135                &other.preserve_attachments,
136            )
137    }
138}
139
140impl RenderPassCompat {
141    fn new(info: &RenderPassCreateInfo) -> Result<Self> {
142        let att_ref = |att: &AttachmentReference| {
143            if att.attachment == u32::MAX {
144                Ok(None)
145            } else if let Some(desc) =
146                info.attachments.as_slice().get(att.attachment as usize)
147            {
148                Ok(Some(AttachmentRefCompat {
149                    format: desc.format,
150                    samples: desc.samples,
151                }))
152            } else {
153                Err(Error::OutOfBounds)
154            }
155        };
156        let mut subpasses = vec![];
157        for subpass in info.subpasses {
158            subpasses.push(SubpassCompat {
159                input_attachments: subpass
160                    .input_attachments
161                    .into_iter()
162                    .map(att_ref)
163                    .collect::<Result<_>>()?,
164                preserve_attachments: subpass
165                    .color_attachments
166                    .into_iter()
167                    .map(att_ref)
168                    .collect::<Result<_>>()?,
169                color_attachments: subpass
170                    .color_attachments
171                    .into_iter()
172                    .map(att_ref)
173                    .collect::<Result<_>>()?,
174                resolve_attachments: subpass
175                    .resolve_attachments
176                    .map_or(Default::default(), |a| unsafe {
177                        a.as_slice(subpass.color_attachments.len())
178                    })
179                    .iter()
180                    .map(att_ref)
181                    .collect::<Result<_>>()?,
182                depth_stencil_attachments: subpass
183                    .depth_stencil_attachments
184                    .map_or(Default::default(), |a| unsafe {
185                        a.as_slice(subpass.color_attachments.len())
186                    })
187                    .iter()
188                    .map(att_ref)
189                    .collect::<Result<_>>()?,
190            });
191        }
192
193        Ok(Self {
194            subpasses,
195            dependencies: info.dependencies.into_iter().cloned().collect(),
196        })
197    }
198}