vulkano/render_pass/
framebuffer.rs

1// Copyright (c) 2016 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
10use super::RenderPass;
11use crate::{
12    device::{Device, DeviceOwned, DeviceOwnedDebugWrapper},
13    image::{
14        view::{ImageView, ImageViewType},
15        ImageAspects, ImageType, ImageUsage,
16    },
17    macros::{impl_id_counter, vulkan_bitflags},
18    Validated, ValidationError, VulkanError, VulkanObject,
19};
20use smallvec::SmallVec;
21use std::{mem::MaybeUninit, num::NonZeroU64, ops::Range, ptr, sync::Arc};
22
23/// The image views that are attached to a render pass during drawing.
24///
25/// A framebuffer is a collection of images, and supplies the actual inputs and outputs of each
26/// attachment within a render pass. Each attachment point in the render pass must have a matching
27/// image in the framebuffer.
28///
29/// ```
30/// # use std::sync::Arc;
31/// # use vulkano::render_pass::RenderPass;
32/// # use vulkano::image::view::ImageView;
33/// use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo};
34///
35/// # let render_pass: Arc<RenderPass> = return;
36/// # let view: Arc<ImageView> = return;
37/// // let render_pass: Arc<_> = ...;
38/// let framebuffer = Framebuffer::new(
39///     render_pass.clone(),
40///     FramebufferCreateInfo {
41///         attachments: vec![view],
42///         ..Default::default()
43///     },
44/// )
45/// .unwrap();
46/// ```
47#[derive(Debug)]
48pub struct Framebuffer {
49    handle: ash::vk::Framebuffer,
50    render_pass: DeviceOwnedDebugWrapper<Arc<RenderPass>>,
51    id: NonZeroU64,
52
53    flags: FramebufferCreateFlags,
54    attachments: Vec<DeviceOwnedDebugWrapper<Arc<ImageView>>>,
55    extent: [u32; 2],
56    layers: u32,
57}
58
59impl Framebuffer {
60    /// Creates a new `Framebuffer`.
61    pub fn new(
62        render_pass: Arc<RenderPass>,
63        mut create_info: FramebufferCreateInfo,
64    ) -> Result<Arc<Framebuffer>, Validated<VulkanError>> {
65        create_info.set_auto_extent_layers(&render_pass);
66        Self::validate_new(&render_pass, &create_info)?;
67
68        unsafe { Ok(Self::new_unchecked(render_pass, create_info)?) }
69    }
70
71    fn validate_new(
72        render_pass: &RenderPass,
73        create_info: &FramebufferCreateInfo,
74    ) -> Result<(), Box<ValidationError>> {
75        // VUID-vkCreateFramebuffer-pCreateInfo-parameter
76        create_info
77            .validate(render_pass.device())
78            .map_err(|err| err.add_context("create_info"))?;
79
80        let &FramebufferCreateInfo {
81            flags: _,
82            ref attachments,
83            extent,
84            layers,
85            _ne,
86        } = create_info;
87
88        if attachments.len() != render_pass.attachments().len() {
89            return Err(Box::new(ValidationError {
90                problem: "`create_info.attachments` does not have the same length as \
91                    `render_pass.attachments()`"
92                    .into(),
93                vuids: &["VUID-VkFramebufferCreateInfo-attachmentCount-00876"],
94                ..Default::default()
95            }));
96        }
97
98        for (index, ((image_view, attachment_desc), attachment_use)) in attachments
99            .iter()
100            .zip(render_pass.attachments())
101            .zip(&render_pass.attachment_use)
102            .enumerate()
103        {
104            if attachment_use.color_attachment
105                && !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT)
106            {
107                return Err(Box::new(ValidationError {
108                    problem: format!(
109                        "`render_pass` uses `create_info.attachments[{}]` as \
110                        a color attachment, but it was not created with the \
111                        `ImageUsage::COLOR_ATTACHMENT` usage",
112                        index
113                    )
114                    .into(),
115                    vuids: &["VUID-VkFramebufferCreateInfo-pAttachments-00877"],
116                    ..Default::default()
117                }));
118            }
119
120            if attachment_use.depth_stencil_attachment
121                && !image_view
122                    .usage()
123                    .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
124            {
125                return Err(Box::new(ValidationError {
126                    problem: format!(
127                        "`render_pass` uses `create_info.attachments[{}]` as \
128                        a depth or stencil attachment, but it was not created with the \
129                        `ImageUsage::DEPTH_STENCIL_ATTACHMENT` usage",
130                        index,
131                    )
132                    .into(),
133                    vuids: &[
134                        "VUID-VkFramebufferCreateInfo-pAttachments-02633",
135                        "VUID-VkFramebufferCreateInfo-pAttachments-02634",
136                    ],
137                    ..Default::default()
138                }));
139            }
140
141            if attachment_use.input_attachment
142                && !image_view.usage().intersects(ImageUsage::INPUT_ATTACHMENT)
143            {
144                return Err(Box::new(ValidationError {
145                    problem: format!(
146                        "`render_pass` uses `create_info.attachments[{}]` as \
147                        an input attachment, but it was not created with the \
148                        `ImageUsage::INPUT_ATTACHMENT` usage",
149                        index,
150                    )
151                    .into(),
152                    vuids: &["VUID-VkFramebufferCreateInfo-pAttachments-02633"],
153                    ..Default::default()
154                }));
155            }
156
157            if image_view.format() != attachment_desc.format {
158                return Err(Box::new(ValidationError {
159                    problem: format!(
160                        "the format of `create_info.attachments[{}]` does not equal \
161                        `render_pass.attachments()[{0}].format`",
162                        index,
163                    )
164                    .into(),
165                    vuids: &["VUID-VkFramebufferCreateInfo-pAttachments-00880"],
166                    ..Default::default()
167                }));
168            }
169
170            if image_view.image().samples() != attachment_desc.samples {
171                return Err(Box::new(ValidationError {
172                    problem: format!(
173                        "the samples of `create_info.attachments[{}]` does not equal \
174                        `render_pass.attachments()[{0}].samples`",
175                        index,
176                    )
177                    .into(),
178                    vuids: &["VUID-VkFramebufferCreateInfo-pAttachments-00881"],
179                    ..Default::default()
180                }));
181            }
182
183            let image_view_extent = image_view.image().extent();
184            let image_view_array_layers = image_view.subresource_range().array_layers.end
185                - image_view.subresource_range().array_layers.start;
186
187            if attachment_use.input_attachment
188                || attachment_use.color_attachment
189                || attachment_use.depth_stencil_attachment
190            {
191                if image_view_extent[0] < extent[0] || image_view_extent[1] < extent[1] {
192                    return Err(Box::new(ValidationError {
193                        problem: format!(
194                            "`render_pass` uses `create_info.attachments[{}]` as an input, color, \
195                            depth or stencil attachment, but \
196                            its width and height are less than `create_info.extent`",
197                            index,
198                        )
199                        .into(),
200                        vuids: &[
201                            "VUID-VkFramebufferCreateInfo-flags-04533",
202                            "VUID-VkFramebufferCreateInfo-flags-04534",
203                        ],
204                        ..Default::default()
205                    }));
206                }
207
208                if image_view_array_layers < layers {
209                    return Err(Box::new(ValidationError {
210                        problem: format!(
211                            "`render_pass` uses `create_info.attachments[{}]` as an input, color, \
212                            depth or stencil attachment, but \
213                            its layer count is less than `create_info.layers`",
214                            index,
215                        )
216                        .into(),
217                        vuids: &["VUID-VkFramebufferCreateInfo-flags-04535"],
218                        ..Default::default()
219                    }));
220                }
221
222                if image_view_array_layers < render_pass.views_used() {
223                    return Err(Box::new(ValidationError {
224                        problem: format!(
225                            "`render_pass` has multiview enabled, and uses \
226                            `create_info.attachments[{}]` as an input, color, depth or stencil \
227                            attachment, but its layer count is less than the number of views used \
228                            by `render_pass`",
229                            index
230                        )
231                        .into(),
232                        vuids: &["VUID-VkFramebufferCreateInfo-renderPass-04536"],
233                        ..Default::default()
234                    }));
235                }
236            }
237
238            if render_pass.views_used() != 0 && layers != 1 {
239                return Err(Box::new(ValidationError {
240                    problem: "`render_pass` has multiview enabled, but \
241                        `create_info.layers` is not 1"
242                        .into(),
243                    vuids: &["VUID-VkFramebufferCreateInfo-renderPass-02531"],
244                    ..Default::default()
245                }));
246            }
247        }
248
249        Ok(())
250    }
251
252    #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
253    pub unsafe fn new_unchecked(
254        render_pass: Arc<RenderPass>,
255        mut create_info: FramebufferCreateInfo,
256    ) -> Result<Arc<Framebuffer>, VulkanError> {
257        create_info.set_auto_extent_layers(&render_pass);
258
259        let &FramebufferCreateInfo {
260            flags,
261            ref attachments,
262            extent,
263            layers,
264            _ne: _,
265        } = &create_info;
266
267        let attachments_vk: SmallVec<[_; 4]> =
268            attachments.iter().map(VulkanObject::handle).collect();
269
270        let create_info_vk = ash::vk::FramebufferCreateInfo {
271            flags: flags.into(),
272            render_pass: render_pass.handle(),
273            attachment_count: attachments_vk.len() as u32,
274            p_attachments: attachments_vk.as_ptr(),
275            width: extent[0],
276            height: extent[1],
277            layers,
278            ..Default::default()
279        };
280
281        let handle = unsafe {
282            let fns = render_pass.device().fns();
283            let mut output = MaybeUninit::uninit();
284            (fns.v1_0.create_framebuffer)(
285                render_pass.device().handle(),
286                &create_info_vk,
287                ptr::null(),
288                output.as_mut_ptr(),
289            )
290            .result()
291            .map_err(VulkanError::from)?;
292            output.assume_init()
293        };
294
295        Ok(Self::from_handle(render_pass, handle, create_info))
296    }
297
298    /// Creates a new `Framebuffer` from a raw object handle.
299    ///
300    /// # Safety
301    ///
302    /// - `handle` must be a valid Vulkan object handle created from `render_pass`.
303    /// - `create_info` must match the info used to create the object.
304    #[inline]
305    pub unsafe fn from_handle(
306        render_pass: Arc<RenderPass>,
307        handle: ash::vk::Framebuffer,
308        mut create_info: FramebufferCreateInfo,
309    ) -> Arc<Framebuffer> {
310        create_info.set_auto_extent_layers(&render_pass);
311
312        let FramebufferCreateInfo {
313            flags,
314            attachments,
315            extent,
316            layers,
317            _ne: _,
318        } = create_info;
319
320        Arc::new(Framebuffer {
321            handle,
322            render_pass: DeviceOwnedDebugWrapper(render_pass),
323            id: Self::next_id(),
324
325            flags,
326            attachments: attachments
327                .into_iter()
328                .map(DeviceOwnedDebugWrapper)
329                .collect(),
330            extent,
331            layers,
332        })
333    }
334
335    /// Returns the renderpass that was used to create this framebuffer.
336    #[inline]
337    pub fn render_pass(&self) -> &Arc<RenderPass> {
338        &self.render_pass
339    }
340
341    /// Returns the flags that the framebuffer was created with.
342    #[inline]
343    pub fn flags(&self) -> FramebufferCreateFlags {
344        self.flags
345    }
346
347    /// Returns the attachments of the framebuffer.
348    #[inline]
349    pub fn attachments(&self) -> &[Arc<ImageView>] {
350        DeviceOwnedDebugWrapper::cast_slice_inner(&self.attachments)
351    }
352
353    /// Returns the extent (width and height) of the framebuffer.
354    #[inline]
355    pub fn extent(&self) -> [u32; 2] {
356        self.extent
357    }
358
359    /// Returns the number of layers of the framebuffer.
360    #[inline]
361    pub fn layers(&self) -> u32 {
362        self.layers
363    }
364
365    /// Returns the layer ranges for all attachments.
366    #[inline]
367    pub fn attached_layers_ranges(&self) -> SmallVec<[Range<u32>; 4]> {
368        self.attachments
369            .iter()
370            .map(|img| img.subresource_range().array_layers.clone())
371            .collect()
372    }
373}
374
375impl Drop for Framebuffer {
376    #[inline]
377    fn drop(&mut self) {
378        unsafe {
379            let fns = self.device().fns();
380            (fns.v1_0.destroy_framebuffer)(self.device().handle(), self.handle, ptr::null());
381        }
382    }
383}
384
385unsafe impl VulkanObject for Framebuffer {
386    type Handle = ash::vk::Framebuffer;
387
388    #[inline]
389    fn handle(&self) -> Self::Handle {
390        self.handle
391    }
392}
393
394unsafe impl DeviceOwned for Framebuffer {
395    #[inline]
396    fn device(&self) -> &Arc<Device> {
397        self.render_pass.device()
398    }
399}
400
401impl_id_counter!(Framebuffer);
402
403/// Parameters to create a new `Framebuffer`.
404#[derive(Clone, Debug)]
405pub struct FramebufferCreateInfo {
406    /// Additional properties of the framebuffer.
407    ///
408    /// The default value is empty.
409    pub flags: FramebufferCreateFlags,
410
411    /// The attachment images that are to be used in the framebuffer.
412    ///
413    /// Attachments are specified in the same order as they are defined in the render pass, and
414    /// there must be exactly as many. This implies that the list must be empty if the render pass
415    /// specifies no attachments. Each image must have the correct usages set to be used for the
416    /// types of attachment that the render pass will use it as.
417    ///
418    /// The attachment images must not be smaller than `extent` and `layers`, but can be larger and
419    /// have different sizes from each other. Any leftover parts of an image will be left untouched
420    /// during rendering.
421    ///
422    /// If the render pass has multiview enabled (`views_used` does not return 0), then each
423    /// image must have at least `views_used` array layers.
424    ///
425    /// The default value is empty.
426    pub attachments: Vec<Arc<ImageView>>,
427
428    /// The extent (width and height) of the framebuffer.
429    ///
430    /// This must be no larger than the smallest width and height of the images in `attachments`.
431    /// If one of the elements is set to 0, the extent will be calculated automatically from the
432    /// extents of the attachment images to be the largest allowed. At least one attachment image
433    /// must be specified in that case.
434    ///
435    /// The extent, whether automatically calculated or specified explicitly, must not be larger
436    /// than the [`max_framebuffer_width`](crate::device::Properties::max_framebuffer_width) and
437    /// [`max_framebuffer_height`](crate::device::Properties::max_framebuffer_height) limits.
438    ///
439    /// The default value is `[0, 0]`.
440    pub extent: [u32; 2],
441
442    /// The number of layers of the framebuffer.
443    ///
444    /// This must be no larger than the smallest number of array layers of the images in
445    /// `attachments`. If set to 0, the number of layers will be calculated automatically from the
446    /// layer ranges of the attachment images to be the largest allowed. At least one attachment
447    /// image must be specified in that case.
448    ///
449    /// The number of layers, whether automatically calculated or specified explicitly, must not be
450    /// larger than the
451    /// [`max_framebuffer_layers`](crate::device::Properties::max_framebuffer_layers) limit.
452    ///
453    /// If the render pass has multiview enabled (`views_used` does not return 0), then this value
454    /// must be 0 or 1.
455    ///
456    /// The default value is `0`.
457    pub layers: u32,
458
459    pub _ne: crate::NonExhaustive,
460}
461
462impl Default for FramebufferCreateInfo {
463    #[inline]
464    fn default() -> Self {
465        Self {
466            flags: FramebufferCreateFlags::empty(),
467            attachments: Vec::new(),
468            extent: [0, 0],
469            layers: 0,
470            _ne: crate::NonExhaustive(()),
471        }
472    }
473}
474
475impl FramebufferCreateInfo {
476    fn set_auto_extent_layers(&mut self, render_pass: &RenderPass) {
477        let Self {
478            flags: _,
479            attachments,
480            extent,
481            layers,
482            _ne: _,
483        } = self;
484
485        let is_auto_extent = extent[0] == 0 || extent[1] == 0;
486        let is_auto_layers = *layers == 0;
487
488        if (is_auto_extent || is_auto_layers) && !attachments.is_empty() {
489            let mut auto_extent = [u32::MAX, u32::MAX];
490            let mut auto_layers = if render_pass.views_used() != 0 {
491                // VUID-VkFramebufferCreateInfo-renderPass-02531
492                1
493            } else {
494                u32::MAX
495            };
496
497            for image_view in attachments.iter() {
498                let image_view_extent = image_view.image().extent();
499                let image_view_array_layers =
500                    image_view.subresource_range().array_layers.len() as u32;
501
502                auto_extent[0] = auto_extent[0].min(image_view_extent[0]);
503                auto_extent[1] = auto_extent[1].min(image_view_extent[1]);
504                auto_layers = auto_layers.min(image_view_array_layers);
505            }
506
507            if is_auto_extent {
508                *extent = auto_extent;
509            }
510
511            if is_auto_layers {
512                *layers = auto_layers;
513            }
514        }
515    }
516
517    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
518        let &Self {
519            flags,
520            ref attachments,
521            extent,
522            layers,
523            _ne: _,
524        } = self;
525
526        flags.validate_device(device).map_err(|err| {
527            err.add_context("flags")
528                .set_vuids(&["VUID-VkFramebufferCreateInfo-flags-parameter"])
529        })?;
530
531        for (index, image_view) in attachments.iter().enumerate() {
532            assert_eq!(device, image_view.device().as_ref());
533
534            let image_view_mip_levels = image_view.subresource_range().mip_levels.end
535                - image_view.subresource_range().mip_levels.start;
536
537            if image_view_mip_levels != 1 {
538                return Err(Box::new(ValidationError {
539                    context: format!("attachments[{}]", index).into(),
540                    problem: "has more than one mip level".into(),
541                    vuids: &["VUID-VkFramebufferCreateInfo-pAttachments-00883"],
542                    ..Default::default()
543                }));
544            }
545
546            if !image_view.component_mapping().is_identity() {
547                return Err(Box::new(ValidationError {
548                    context: format!("attachments[{}]", index).into(),
549                    problem: "is not identity swizzled".into(),
550                    vuids: &["VUID-VkFramebufferCreateInfo-pAttachments-00884"],
551                    ..Default::default()
552                }));
553            }
554
555            match image_view.view_type() {
556                ImageViewType::Dim2d | ImageViewType::Dim2dArray => {
557                    if image_view.image().image_type() == ImageType::Dim3d
558                        && (image_view.format().aspects())
559                            .intersects(ImageAspects::DEPTH | ImageAspects::STENCIL)
560                    {
561                        return Err(Box::new(ValidationError {
562                            context: format!("attachments[{}]", index).into(),
563                            problem: "is a 2D or 2D array image view, but its format is a \
564                                depth/stencil format"
565                                .into(),
566                            vuids: &["VUID-VkFramebufferCreateInfo-pAttachments-00891"],
567                            ..Default::default()
568                        }));
569                    }
570                }
571                ImageViewType::Dim3d => {
572                    return Err(Box::new(ValidationError {
573                        context: format!("attachments[{}]", index).into(),
574                        problem: "is a 3D image view".into(),
575                        vuids: &["VUID-VkFramebufferCreateInfo-flags-04113"],
576                        ..Default::default()
577                    }));
578                }
579                _ => (),
580            }
581        }
582
583        let properties = device.physical_device().properties();
584
585        if extent[0] == 0 {
586            return Err(Box::new(ValidationError {
587                context: "extent[0]".into(),
588                problem: "is zero".into(),
589                vuids: &["VUID-VkFramebufferCreateInfo-width-00885"],
590                ..Default::default()
591            }));
592        }
593
594        if extent[0] > properties.max_framebuffer_width {
595            return Err(Box::new(ValidationError {
596                context: "extent[0]".into(),
597                problem: "exceeds the `max_framebuffer_width` limit".into(),
598                vuids: &["VUID-VkFramebufferCreateInfo-width-00886"],
599                ..Default::default()
600            }));
601        }
602
603        if extent[1] == 0 {
604            return Err(Box::new(ValidationError {
605                context: "extent[1]".into(),
606                problem: "is zero".into(),
607                vuids: &["VUID-VkFramebufferCreateInfo-height-00887"],
608                ..Default::default()
609            }));
610        }
611
612        if extent[1] > properties.max_framebuffer_height {
613            return Err(Box::new(ValidationError {
614                context: "extent[1]".into(),
615                problem: "exceeds the `max_framebuffer_height` limit".into(),
616                vuids: &["VUID-VkFramebufferCreateInfo-height-00888"],
617                ..Default::default()
618            }));
619        }
620
621        if layers == 0 {
622            return Err(Box::new(ValidationError {
623                context: "layers".into(),
624                problem: "is zero".into(),
625                vuids: &["VUID-VkFramebufferCreateInfo-layers-00889"],
626                ..Default::default()
627            }));
628        }
629
630        if layers > properties.max_framebuffer_layers {
631            return Err(Box::new(ValidationError {
632                context: "layers".into(),
633                problem: "exceeds the `max_framebuffer_layers` limit".into(),
634                vuids: &["VUID-VkFramebufferCreateInfo-layers-00890"],
635                ..Default::default()
636            }));
637        }
638
639        Ok(())
640    }
641}
642
643vulkan_bitflags! {
644    #[non_exhaustive]
645
646    /// Flags specifying additional properties of a framebuffer.
647    FramebufferCreateFlags = FramebufferCreateFlags(u32);
648
649    /* TODO: enable
650    // TODO: document
651    IMAGELESS = IMAGELESS {
652        api_version: V1_2,
653        device_extensions: [khr_imageless_framebuffer],
654    }, */
655}
656
657#[cfg(test)]
658mod tests {
659    use crate::{
660        format::Format,
661        image::{view::ImageView, Image, ImageCreateInfo, ImageType, ImageUsage},
662        memory::allocator::{AllocationCreateInfo, StandardMemoryAllocator},
663        render_pass::{
664            Framebuffer, FramebufferCreateInfo, RenderPass, RenderPassCreateInfo,
665            SubpassDescription,
666        },
667    };
668    use std::sync::Arc;
669
670    #[test]
671    fn simple_create() {
672        let (device, _) = gfx_dev_and_queue!();
673
674        let render_pass = single_pass_renderpass!(
675            device.clone(),
676            attachments: {
677                color: {
678                    format: Format::R8G8B8A8_UNORM,
679                    samples: 1,
680                    load_op: Clear,
681                    store_op: DontCare,
682                },
683            },
684            pass: {
685                color: [color],
686                depth_stencil: {},
687            },
688        )
689        .unwrap();
690
691        let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
692        let view = ImageView::new_default(
693            Image::new(
694                memory_allocator,
695                ImageCreateInfo {
696                    image_type: ImageType::Dim2d,
697                    format: Format::R8G8B8A8_UNORM,
698                    extent: [1024, 768, 1],
699                    usage: ImageUsage::COLOR_ATTACHMENT,
700                    ..Default::default()
701                },
702                AllocationCreateInfo::default(),
703            )
704            .unwrap(),
705        )
706        .unwrap();
707        let _ = Framebuffer::new(
708            render_pass,
709            FramebufferCreateInfo {
710                attachments: vec![view],
711                ..Default::default()
712            },
713        )
714        .unwrap();
715    }
716
717    #[test]
718    fn check_device_limits() {
719        let (device, _) = gfx_dev_and_queue!();
720
721        let render_pass = RenderPass::new(
722            device,
723            RenderPassCreateInfo {
724                subpasses: vec![SubpassDescription::default()],
725                ..Default::default()
726            },
727        )
728        .unwrap();
729
730        assert!(Framebuffer::new(
731            render_pass.clone(),
732            FramebufferCreateInfo {
733                extent: [0xffffffff, 0xffffffff],
734                layers: 1,
735                ..Default::default()
736            },
737        )
738        .is_err());
739
740        assert!(Framebuffer::new(
741            render_pass,
742            FramebufferCreateInfo {
743                extent: [1, 1],
744                layers: 0xffffffff,
745                ..Default::default()
746            },
747        )
748        .is_err());
749    }
750
751    #[test]
752    fn attachment_format_mismatch() {
753        let (device, _) = gfx_dev_and_queue!();
754
755        let render_pass = single_pass_renderpass!(
756            device.clone(),
757            attachments: {
758                color: {
759                    format: Format::R8G8B8A8_UNORM,
760                    samples: 1,
761                    load_op: Clear,
762                    store_op: DontCare,
763                },
764            },
765            pass: {
766                color: [color],
767                depth_stencil: {},
768            },
769        )
770        .unwrap();
771
772        let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
773        let view = ImageView::new_default(
774            Image::new(
775                memory_allocator,
776                ImageCreateInfo {
777                    image_type: ImageType::Dim2d,
778                    format: Format::R8_UNORM,
779                    extent: [1024, 768, 1],
780                    usage: ImageUsage::COLOR_ATTACHMENT,
781                    ..Default::default()
782                },
783                AllocationCreateInfo::default(),
784            )
785            .unwrap(),
786        )
787        .unwrap();
788
789        assert!(Framebuffer::new(
790            render_pass,
791            FramebufferCreateInfo {
792                attachments: vec![view],
793                ..Default::default()
794            },
795        )
796        .is_err());
797    }
798
799    // TODO: check samples mismatch
800
801    #[test]
802    fn attachment_dims_larger_than_specified_valid() {
803        let (device, _) = gfx_dev_and_queue!();
804
805        let render_pass = single_pass_renderpass!(
806            device.clone(),
807            attachments: {
808                color: {
809                    format: Format::R8G8B8A8_UNORM,
810                    samples: 1,
811                    load_op: Clear,
812                    store_op: DontCare,
813                },
814            },
815            pass: {
816                color: [color],
817                depth_stencil: {},
818            },
819        )
820        .unwrap();
821
822        let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
823        let view = ImageView::new_default(
824            Image::new(
825                memory_allocator,
826                ImageCreateInfo {
827                    image_type: ImageType::Dim2d,
828                    format: Format::R8G8B8A8_UNORM,
829                    extent: [600, 600, 1],
830                    usage: ImageUsage::COLOR_ATTACHMENT,
831                    ..Default::default()
832                },
833                AllocationCreateInfo::default(),
834            )
835            .unwrap(),
836        )
837        .unwrap();
838
839        let _ = Framebuffer::new(
840            render_pass,
841            FramebufferCreateInfo {
842                attachments: vec![view],
843                extent: [512, 512],
844                layers: 1,
845                ..Default::default()
846            },
847        )
848        .unwrap();
849    }
850
851    #[test]
852    fn attachment_dims_smaller_than_specified() {
853        let (device, _) = gfx_dev_and_queue!();
854
855        let render_pass = single_pass_renderpass!(
856            device.clone(),
857            attachments: {
858                color: {
859                    format: Format::R8G8B8A8_UNORM,
860                    samples: 1,
861                    load_op: Clear,
862                    store_op: DontCare,
863                },
864            },
865            pass: {
866                color: [color],
867                depth_stencil: {},
868            },
869        )
870        .unwrap();
871
872        let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
873        let view = ImageView::new_default(
874            Image::new(
875                memory_allocator,
876                ImageCreateInfo {
877                    image_type: ImageType::Dim2d,
878                    format: Format::R8G8B8A8_UNORM,
879                    extent: [512, 700, 1],
880                    usage: ImageUsage::COLOR_ATTACHMENT,
881                    ..Default::default()
882                },
883                AllocationCreateInfo::default(),
884            )
885            .unwrap(),
886        )
887        .unwrap();
888
889        assert!(Framebuffer::new(
890            render_pass,
891            FramebufferCreateInfo {
892                attachments: vec![view],
893                extent: [600, 600],
894                layers: 1,
895                ..Default::default()
896            },
897        )
898        .is_err());
899    }
900
901    #[test]
902    fn multi_attachments_auto_smaller() {
903        let (device, _) = gfx_dev_and_queue!();
904
905        let render_pass = single_pass_renderpass!(
906            device.clone(),
907            attachments: {
908                a: {
909                    format: Format::R8G8B8A8_UNORM,
910                    samples: 1,
911                    load_op: Clear,
912                    store_op: DontCare,
913                },
914                b: {
915                    format: Format::R8G8B8A8_UNORM,
916                    samples: 1,
917                    load_op: Clear,
918                    store_op: DontCare,
919                },
920            },
921            pass: {
922                color: [a, b],
923                depth_stencil: {},
924            },
925        )
926        .unwrap();
927
928        let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
929        let a = ImageView::new_default(
930            Image::new(
931                memory_allocator.clone(),
932                ImageCreateInfo {
933                    image_type: ImageType::Dim2d,
934                    format: Format::R8G8B8A8_UNORM,
935                    extent: [256, 512, 1],
936                    usage: ImageUsage::COLOR_ATTACHMENT,
937                    ..Default::default()
938                },
939                AllocationCreateInfo::default(),
940            )
941            .unwrap(),
942        )
943        .unwrap();
944        let b = ImageView::new_default(
945            Image::new(
946                memory_allocator,
947                ImageCreateInfo {
948                    image_type: ImageType::Dim2d,
949                    format: Format::R8G8B8A8_UNORM,
950                    extent: [512, 128, 1],
951                    usage: ImageUsage::COLOR_ATTACHMENT,
952                    ..Default::default()
953                },
954                AllocationCreateInfo::default(),
955            )
956            .unwrap(),
957        )
958        .unwrap();
959
960        let framebuffer = Framebuffer::new(
961            render_pass,
962            FramebufferCreateInfo {
963                attachments: vec![a, b],
964                ..Default::default()
965            },
966        )
967        .unwrap();
968
969        match (framebuffer.extent(), framebuffer.layers()) {
970            ([256, 128], 1) => (),
971            _ => panic!(),
972        }
973    }
974
975    #[test]
976    fn not_enough_attachments() {
977        let (device, _) = gfx_dev_and_queue!();
978
979        let render_pass = single_pass_renderpass!(
980            device.clone(),
981            attachments: {
982                a: {
983                    format: Format::R8G8B8A8_UNORM,
984                    samples: 1,
985                    load_op: Clear,
986                    store_op: DontCare,
987                },
988                b: {
989                    format: Format::R8G8B8A8_UNORM,
990                    samples: 1,
991                    load_op: Clear,
992                    store_op: DontCare,
993                },
994            },
995            pass: {
996                color: [a, b],
997                depth_stencil: {},
998            },
999        )
1000        .unwrap();
1001
1002        let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
1003        let view = ImageView::new_default(
1004            Image::new(
1005                memory_allocator,
1006                ImageCreateInfo {
1007                    image_type: ImageType::Dim2d,
1008                    format: Format::R8G8B8A8_UNORM,
1009                    extent: [256, 512, 1],
1010                    usage: ImageUsage::COLOR_ATTACHMENT,
1011                    ..Default::default()
1012                },
1013                AllocationCreateInfo::default(),
1014            )
1015            .unwrap(),
1016        )
1017        .unwrap();
1018
1019        assert!(Framebuffer::new(
1020            render_pass,
1021            FramebufferCreateInfo {
1022                attachments: vec![view],
1023                ..Default::default()
1024            },
1025        )
1026        .is_err());
1027    }
1028
1029    #[test]
1030    fn too_many_attachments() {
1031        let (device, _) = gfx_dev_and_queue!();
1032
1033        let render_pass = single_pass_renderpass!(
1034            device.clone(),
1035            attachments: {
1036                a: {
1037                    format: Format::R8G8B8A8_UNORM,
1038                    samples: 1,
1039                    load_op: Clear,
1040                    store_op: DontCare,
1041                },
1042            },
1043            pass: {
1044                color: [a],
1045                depth_stencil: {},
1046            },
1047        )
1048        .unwrap();
1049
1050        let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
1051        let a = ImageView::new_default(
1052            Image::new(
1053                memory_allocator.clone(),
1054                ImageCreateInfo {
1055                    image_type: ImageType::Dim2d,
1056                    format: Format::R8G8B8A8_UNORM,
1057                    extent: [256, 512, 1],
1058                    usage: ImageUsage::COLOR_ATTACHMENT,
1059                    ..Default::default()
1060                },
1061                AllocationCreateInfo::default(),
1062            )
1063            .unwrap(),
1064        )
1065        .unwrap();
1066        let b = ImageView::new_default(
1067            Image::new(
1068                memory_allocator,
1069                ImageCreateInfo {
1070                    image_type: ImageType::Dim2d,
1071                    format: Format::R8G8B8A8_UNORM,
1072                    extent: [256, 512, 1],
1073                    usage: ImageUsage::COLOR_ATTACHMENT,
1074                    ..Default::default()
1075                },
1076                AllocationCreateInfo::default(),
1077            )
1078            .unwrap(),
1079        )
1080        .unwrap();
1081
1082        assert!(Framebuffer::new(
1083            render_pass,
1084            FramebufferCreateInfo {
1085                attachments: vec![a, b],
1086                ..Default::default()
1087            },
1088        )
1089        .is_err());
1090    }
1091
1092    #[test]
1093    fn empty_working() {
1094        let (device, _) = gfx_dev_and_queue!();
1095
1096        let render_pass = RenderPass::new(
1097            device,
1098            RenderPassCreateInfo {
1099                subpasses: vec![SubpassDescription::default()],
1100                ..Default::default()
1101            },
1102        )
1103        .unwrap();
1104        let _ = Framebuffer::new(
1105            render_pass,
1106            FramebufferCreateInfo {
1107                extent: [512, 512],
1108                layers: 1,
1109                ..Default::default()
1110            },
1111        )
1112        .unwrap();
1113    }
1114
1115    #[test]
1116    fn cant_determine_dimensions_auto() {
1117        let (device, _) = gfx_dev_and_queue!();
1118
1119        let render_pass = RenderPass::new(
1120            device,
1121            RenderPassCreateInfo {
1122                subpasses: vec![SubpassDescription::default()],
1123                ..Default::default()
1124            },
1125        )
1126        .unwrap();
1127
1128        assert!(Framebuffer::new(render_pass, FramebufferCreateInfo::default()).is_err());
1129    }
1130}