• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! This module contains the `ensure_image_view_compatible` function, which verifies whether
11 //! an image view can be used as a render pass attachment.
12 
13 use crate::image::view::ImageViewAbstract;
14 use crate::render_pass::RenderPassDesc;
15 use crate::{format::Format, image::SampleCount};
16 use std::error;
17 use std::fmt;
18 
19 /// Checks whether the given image view is allowed to be the nth attachment of the given render
20 /// pass.
21 ///
22 /// # Panic
23 ///
24 /// Panics if the attachment number is out of range.
25 // TODO: add a specializable trait instead, that uses this function
26 // TODO: ImageView instead of ImageViewAbstract?
ensure_image_view_compatible<I>( render_pass_desc: &RenderPassDesc, attachment_num: usize, image_view: &I, ) -> Result<(), IncompatibleRenderPassAttachmentError> where I: ?Sized + ImageViewAbstract,27 pub fn ensure_image_view_compatible<I>(
28     render_pass_desc: &RenderPassDesc,
29     attachment_num: usize,
30     image_view: &I,
31 ) -> Result<(), IncompatibleRenderPassAttachmentError>
32 where
33     I: ?Sized + ImageViewAbstract,
34 {
35     let attachment_desc = render_pass_desc
36         .attachments()
37         .get(attachment_num)
38         .expect("Attachment num out of range");
39 
40     if image_view.format() != attachment_desc.format {
41         return Err(IncompatibleRenderPassAttachmentError::FormatMismatch {
42             expected: attachment_desc.format,
43             obtained: image_view.format(),
44         });
45     }
46 
47     if image_view.image().samples() != attachment_desc.samples {
48         return Err(IncompatibleRenderPassAttachmentError::SamplesMismatch {
49             expected: attachment_desc.samples,
50             obtained: image_view.image().samples(),
51         });
52     }
53 
54     if !image_view.component_mapping().is_identity() {
55         return Err(IncompatibleRenderPassAttachmentError::NotIdentitySwizzled);
56     }
57 
58     for subpass in render_pass_desc.subpasses() {
59         if subpass
60             .color_attachments
61             .iter()
62             .any(|&(n, _)| n == attachment_num)
63         {
64             debug_assert!(image_view.image().has_color()); // Was normally checked by the render pass.
65             if !image_view.image().inner().image.usage().color_attachment {
66                 return Err(IncompatibleRenderPassAttachmentError::MissingColorAttachmentUsage);
67             }
68         }
69 
70         if let Some((ds, _)) = subpass.depth_stencil {
71             if ds == attachment_num {
72                 // Was normally checked by the render pass.
73                 debug_assert!(image_view.image().has_depth() || image_view.image().has_stencil());
74                 if !image_view
75                     .image()
76                     .inner()
77                     .image
78                     .usage()
79                     .depth_stencil_attachment
80                 {
81                     return Err(
82                         IncompatibleRenderPassAttachmentError::MissingDepthStencilAttachmentUsage,
83                     );
84                 }
85             }
86         }
87 
88         if subpass
89             .input_attachments
90             .iter()
91             .any(|&(n, _)| n == attachment_num)
92         {
93             if !image_view.image().inner().image.usage().input_attachment {
94                 return Err(IncompatibleRenderPassAttachmentError::MissingInputAttachmentUsage);
95             }
96         }
97     }
98 
99     // TODO: consider forbidding LoadOp::Load if image is transient
100 
101     // TODO: are all image layouts allowed? check this
102 
103     Ok(())
104 }
105 
106 /// Error that can happen when an image is not compatible with a render pass attachment slot.
107 #[derive(Copy, Clone, Debug)]
108 pub enum IncompatibleRenderPassAttachmentError {
109     /// The image format expected by the render pass doesn't match the actual format of
110     /// the image.
111     FormatMismatch {
112         /// Format expected by the render pass.
113         expected: Format,
114         /// Format of the image.
115         obtained: Format,
116     },
117 
118     /// The number of samples expected by the render pass doesn't match the number of samples of
119     /// the image.
120     SamplesMismatch {
121         /// Number of samples expected by the render pass.
122         expected: SampleCount,
123         /// Number of samples of the image.
124         obtained: SampleCount,
125     },
126 
127     /// The image view has a component swizzle that is different from identity.
128     NotIdentitySwizzled,
129 
130     /// The image is used as a color attachment but is missing the color attachment usage.
131     MissingColorAttachmentUsage,
132 
133     /// The image is used as a depth/stencil attachment but is missing the depth-stencil attachment
134     /// usage.
135     MissingDepthStencilAttachmentUsage,
136 
137     /// The image is used as an input attachment but is missing the input attachment usage.
138     MissingInputAttachmentUsage,
139 }
140 
141 impl error::Error for IncompatibleRenderPassAttachmentError {}
142 
143 impl fmt::Display for IncompatibleRenderPassAttachmentError {
144     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>145     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
146         write!(
147             fmt,
148             "{}",
149             match *self {
150                 IncompatibleRenderPassAttachmentError::FormatMismatch { .. } => {
151                     "mismatch between the format expected by the render pass and the actual format"
152                 }
153                 IncompatibleRenderPassAttachmentError::SamplesMismatch { .. } => {
154                     "mismatch between the number of samples expected by the render pass and the actual \
155                  number of samples"
156                 }
157                 IncompatibleRenderPassAttachmentError::NotIdentitySwizzled => {
158                     "the image view's component mapping is not identity swizzled"
159                 }
160                 IncompatibleRenderPassAttachmentError::MissingColorAttachmentUsage => {
161                     "the image is used as a color attachment but is missing the color attachment usage"
162                 }
163                 IncompatibleRenderPassAttachmentError::MissingDepthStencilAttachmentUsage => {
164                     "the image is used as a depth/stencil attachment but is missing the depth-stencil \
165                  attachment usage"
166                 }
167                 IncompatibleRenderPassAttachmentError::MissingInputAttachmentUsage => {
168                     "the image is used as an input attachment but is missing the input \
169                  attachment usage"
170                 }
171             }
172         )
173     }
174 }
175 
176 #[cfg(test)]
177 mod tests {
178     use super::ensure_image_view_compatible;
179     use super::IncompatibleRenderPassAttachmentError;
180     use crate::format::Format;
181     use crate::image::view::ImageView;
182     use crate::image::AttachmentImage;
183     use crate::render_pass::RenderPassDesc;
184 
185     #[test]
basic_ok()186     fn basic_ok() {
187         let (device, _) = gfx_dev_and_queue!();
188 
189         let rp = single_pass_renderpass!(device.clone(),
190             attachments: {
191                 color: {
192                     load: Clear,
193                     store: Store,
194                     format: Format::R8G8B8A8Unorm,
195                     samples: 1,
196                 }
197             },
198             pass: {
199                 color: [color],
200                 depth_stencil: {}
201             }
202         )
203         .unwrap();
204 
205         let view = ImageView::new(
206             AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap(),
207         )
208         .unwrap();
209 
210         ensure_image_view_compatible(rp.desc(), 0, &view).unwrap();
211     }
212 
213     #[test]
format_mismatch()214     fn format_mismatch() {
215         let (device, _) = gfx_dev_and_queue!();
216 
217         let rp = single_pass_renderpass!(device.clone(),
218             attachments: {
219                 color: {
220                     load: Clear,
221                     store: Store,
222                     format: Format::R16G16Sfloat,
223                     samples: 1,
224                 }
225             },
226             pass: {
227                 color: [color],
228                 depth_stencil: {}
229             }
230         )
231         .unwrap();
232 
233         let view = ImageView::new(
234             AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap(),
235         )
236         .unwrap();
237 
238         match ensure_image_view_compatible(rp.desc(), 0, &view) {
239             Err(IncompatibleRenderPassAttachmentError::FormatMismatch {
240                 expected: Format::R16G16Sfloat,
241                 obtained: Format::R8G8B8A8Unorm,
242             }) => (),
243             e => panic!("{:?}", e),
244         }
245     }
246 
247     #[test]
attachment_out_of_range()248     fn attachment_out_of_range() {
249         let (device, _) = gfx_dev_and_queue!();
250 
251         let rp = RenderPassDesc::empty();
252         let view = ImageView::new(
253             AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap(),
254         )
255         .unwrap();
256 
257         assert_should_panic!("Attachment num out of range", {
258             let _ = ensure_image_view_compatible(&rp, 0, &view);
259         });
260     }
261 
262     // TODO: more tests
263 }
264