1use 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#[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 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 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 #[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 #[inline]
337 pub fn render_pass(&self) -> &Arc<RenderPass> {
338 &self.render_pass
339 }
340
341 #[inline]
343 pub fn flags(&self) -> FramebufferCreateFlags {
344 self.flags
345 }
346
347 #[inline]
349 pub fn attachments(&self) -> &[Arc<ImageView>] {
350 DeviceOwnedDebugWrapper::cast_slice_inner(&self.attachments)
351 }
352
353 #[inline]
355 pub fn extent(&self) -> [u32; 2] {
356 self.extent
357 }
358
359 #[inline]
361 pub fn layers(&self) -> u32 {
362 self.layers
363 }
364
365 #[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#[derive(Clone, Debug)]
405pub struct FramebufferCreateInfo {
406 pub flags: FramebufferCreateFlags,
410
411 pub attachments: Vec<Arc<ImageView>>,
427
428 pub extent: [u32; 2],
441
442 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 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 FramebufferCreateFlags = FramebufferCreateFlags(u32);
648
649 }
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 #[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}