1use super::{
12 Image, ImageAspect, ImageAspects, ImageCreateFlags, ImageLayout, ImageMemory,
13 ImageSubresourceLayers, ImageSubresourceRange, ImageTiling, ImageUsage, SampleCount,
14 SparseImageMemoryRequirements, SubresourceLayout,
15};
16#[cfg(doc)]
17use crate::format::DrmFormatModifierProperties;
18use crate::{
19 cache::OnceCache,
20 device::{Device, DeviceOwned},
21 format::{ChromaSampling, Format, FormatFeatures},
22 image::{
23 max_mip_levels, ImageDrmFormatModifierInfo, ImageFormatInfo, ImageFormatProperties,
24 ImageType,
25 },
26 instance::InstanceOwnedDebugWrapper,
27 macros::impl_id_counter,
28 memory::{
29 allocator::AllocationType, is_aligned, DedicatedTo, ExternalMemoryHandleTypes,
30 MemoryPropertyFlags, MemoryRequirements, ResourceMemory,
31 },
32 sync::Sharing,
33 Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
34 VulkanObject,
35};
36use smallvec::{smallvec, SmallVec};
37use std::{marker::PhantomData, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc};
38
39#[derive(Debug)]
49pub struct RawImage {
50 handle: ash::vk::Image,
51 device: InstanceOwnedDebugWrapper<Arc<Device>>,
52 id: NonZeroU64,
53
54 flags: ImageCreateFlags,
55 image_type: ImageType,
56 format: Format,
57 format_features: FormatFeatures,
58 view_formats: Vec<Format>,
59 extent: [u32; 3],
60 array_layers: u32,
61 mip_levels: u32,
62 samples: SampleCount,
63 tiling: ImageTiling,
64 usage: ImageUsage,
65 stencil_usage: Option<ImageUsage>,
66 sharing: Sharing<SmallVec<[u32; 4]>>,
67 initial_layout: ImageLayout,
68 drm_format_modifier: Option<(u64, u32)>,
69 external_memory_handle_types: ExternalMemoryHandleTypes,
70
71 memory_requirements: SmallVec<[MemoryRequirements; 4]>,
72 sparse_memory_requirements: Vec<SparseImageMemoryRequirements>,
73 needs_destruction: bool, subresource_layout: OnceCache<(ImageAspect, u32, u32), SubresourceLayout>,
75}
76
77impl RawImage {
78 #[inline]
80 pub fn new(
81 device: Arc<Device>,
82 create_info: ImageCreateInfo,
83 ) -> Result<RawImage, Validated<VulkanError>> {
84 Self::validate_new(&device, &create_info)?;
85
86 Ok(unsafe { RawImage::new_unchecked(device, create_info) }?)
87 }
88
89 fn validate_new(
90 device: &Device,
91 create_info: &ImageCreateInfo,
92 ) -> Result<(), Box<ValidationError>> {
93 create_info
94 .validate(device)
95 .map_err(|err| err.add_context("create_info"))?;
96
97 Ok(())
103 }
104
105 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
106 #[inline]
107 pub unsafe fn new_unchecked(
108 device: Arc<Device>,
109 create_info: ImageCreateInfo,
110 ) -> Result<Self, VulkanError> {
111 let create_info_fields1_vk = create_info.to_vk_fields1();
112 let mut create_info_extensions_vk = create_info.to_vk_extensions(&create_info_fields1_vk);
113 let create_info_vk = create_info.to_vk(&mut create_info_extensions_vk);
114
115 let handle = {
116 let fns = device.fns();
117 let mut output = MaybeUninit::uninit();
118 unsafe {
119 (fns.v1_0.create_image)(
120 device.handle(),
121 &create_info_vk,
122 ptr::null(),
123 output.as_mut_ptr(),
124 )
125 }
126 .result()
127 .map_err(VulkanError::from)?;
128 unsafe { output.assume_init() }
129 };
130
131 unsafe { Self::from_handle(device, handle, create_info) }
132 }
133
134 #[inline]
143 pub unsafe fn from_handle(
144 device: Arc<Device>,
145 handle: ash::vk::Image,
146 create_info: ImageCreateInfo,
147 ) -> Result<Self, VulkanError> {
148 unsafe { Self::from_handle_with_destruction(device, handle, create_info, true) }
149 }
150
151 #[inline]
163 pub unsafe fn from_handle_borrowed(
164 device: Arc<Device>,
165 handle: ash::vk::Image,
166 create_info: ImageCreateInfo,
167 ) -> Result<Self, VulkanError> {
168 unsafe { Self::from_handle_with_destruction(device, handle, create_info, false) }
169 }
170
171 pub(super) unsafe fn from_handle_with_destruction(
172 device: Arc<Device>,
173 handle: ash::vk::Image,
174 create_info: ImageCreateInfo,
175 needs_destruction: bool,
176 ) -> Result<Self, VulkanError> {
177 let ImageCreateInfo {
178 flags,
179 image_type,
180 format,
181 view_formats,
182 extent,
183 array_layers,
184 mip_levels,
185 samples,
186 tiling,
187 usage,
188 stencil_usage,
189 sharing,
190 initial_layout,
191 drm_format_modifiers: _,
192 drm_format_modifier_plane_layouts: _,
193 external_memory_handle_types,
194 _ne: _,
195 } = create_info;
196
197 let format_properties =
198 unsafe { device.physical_device().format_properties_unchecked(format) };
199
200 let drm_format_modifier = if tiling == ImageTiling::DrmFormatModifier {
201 let drm_format_modifier =
202 unsafe { Self::get_drm_format_modifier_properties(&device, handle) }?;
203 let drm_format_modifier_plane_count = format_properties
204 .drm_format_modifier_properties
205 .iter()
206 .find(|properties| properties.drm_format_modifier == drm_format_modifier)
207 .expect("couldn't get the DRM format modifier plane count for the image")
208 .drm_format_modifier_plane_count;
209 Some((drm_format_modifier, drm_format_modifier_plane_count))
210 } else {
211 None
212 };
213
214 let format_features = {
215 let drm_format_modifiers: SmallVec<[_; 1]> =
216 drm_format_modifier.map_or_else(Default::default, |(m, _)| smallvec![m]);
217 format_properties.format_features(tiling, &drm_format_modifiers)
218 };
219
220 let memory_requirements = if needs_destruction {
221 if flags.intersects(ImageCreateFlags::DISJOINT) {
222 let plane_count = drm_format_modifier.map_or_else(
225 || format.planes().len(),
226 |(_, plane_count)| plane_count as usize,
227 );
228
229 (0..plane_count)
230 .map(|plane| unsafe {
231 Self::get_memory_requirements(&device, handle, Some((plane, tiling)))
232 })
233 .collect()
234 } else {
235 smallvec![unsafe { Self::get_memory_requirements(&device, handle, None) }]
237 }
238 } else {
239 smallvec![]
240 };
241
242 let sparse_memory_requirements = if flags
243 .contains(ImageCreateFlags::SPARSE_BINDING | ImageCreateFlags::SPARSE_RESIDENCY)
244 {
245 unsafe { Self::get_sparse_memory_requirements(&device, handle) }
246 } else {
247 Vec::new()
248 };
249
250 Ok(RawImage {
251 handle,
252 device: InstanceOwnedDebugWrapper(device),
253 id: Self::next_id(),
254
255 flags,
256 image_type,
257 format,
258 format_features,
259 view_formats,
260 extent,
261 array_layers,
262 mip_levels,
263 initial_layout,
264 samples,
265 tiling,
266 usage,
267 stencil_usage,
268 sharing,
269 drm_format_modifier,
270 external_memory_handle_types,
271
272 memory_requirements,
273 sparse_memory_requirements,
274 needs_destruction,
275 subresource_layout: OnceCache::new(),
276 })
277 }
278
279 unsafe fn get_memory_requirements(
280 device: &Device,
281 handle: ash::vk::Image,
282 plane_tiling: Option<(usize, ImageTiling)>,
283 ) -> MemoryRequirements {
284 let mut info_vk = ash::vk::ImageMemoryRequirementsInfo2::default().image(handle);
285 let mut plane_info_vk = None;
286
287 if let Some((plane, tiling)) = plane_tiling {
288 debug_assert!(
289 device.api_version() >= Version::V1_1
290 || device.enabled_extensions().khr_get_memory_requirements2
291 );
292
293 let plane_aspect = match tiling {
294 ImageTiling::Optimal | ImageTiling::Linear => {
296 debug_assert!(
297 device.api_version() >= Version::V1_1
298 || device.enabled_extensions().khr_sampler_ycbcr_conversion
299 );
300 match plane {
301 0 => ash::vk::ImageAspectFlags::PLANE_0,
302 1 => ash::vk::ImageAspectFlags::PLANE_1,
303 2 => ash::vk::ImageAspectFlags::PLANE_2,
304 _ => unreachable!(),
305 }
306 }
307 ImageTiling::DrmFormatModifier => {
309 debug_assert!(device.enabled_extensions().ext_image_drm_format_modifier);
310 match plane {
311 0 => ash::vk::ImageAspectFlags::MEMORY_PLANE_0_EXT,
312 1 => ash::vk::ImageAspectFlags::MEMORY_PLANE_1_EXT,
313 2 => ash::vk::ImageAspectFlags::MEMORY_PLANE_2_EXT,
314 3 => ash::vk::ImageAspectFlags::MEMORY_PLANE_3_EXT,
315 _ => unreachable!(),
316 }
317 }
318 };
319
320 let next = plane_info_vk.insert(
321 ash::vk::ImagePlaneMemoryRequirementsInfo::default().plane_aspect(plane_aspect),
322 );
323 info_vk = info_vk.push_next(next);
324 }
325
326 let mut memory_requirements2_extensions_vk =
327 MemoryRequirements::to_mut_vk2_extensions(device);
328 let mut memory_requirements2_vk =
329 MemoryRequirements::to_mut_vk2(&mut memory_requirements2_extensions_vk);
330
331 let fns = device.fns();
332
333 if device.api_version() >= Version::V1_1
334 || device.enabled_extensions().khr_get_memory_requirements2
335 {
336 if device.api_version() >= Version::V1_1 {
337 unsafe {
338 (fns.v1_1.get_image_memory_requirements2)(
339 device.handle(),
340 &info_vk,
341 &mut memory_requirements2_vk,
342 )
343 };
344 } else {
345 unsafe {
346 (fns.khr_get_memory_requirements2
347 .get_image_memory_requirements2_khr)(
348 device.handle(),
349 &info_vk,
350 &mut memory_requirements2_vk,
351 )
352 };
353 }
354 } else {
355 unsafe {
356 (fns.v1_0.get_image_memory_requirements)(
357 device.handle(),
358 handle,
359 &mut memory_requirements2_vk.memory_requirements,
360 )
361 };
362 }
363
364 let memory_requirements2_vk = ash::vk::MemoryRequirements2 {
366 _marker: PhantomData,
367 ..memory_requirements2_vk
368 };
369
370 MemoryRequirements::from_vk2(
371 &memory_requirements2_vk,
372 &memory_requirements2_extensions_vk,
373 )
374 }
375
376 unsafe fn get_sparse_memory_requirements(
377 device: &Device,
378 handle: ash::vk::Image,
379 ) -> Vec<SparseImageMemoryRequirements> {
380 let fns = device.fns();
381
382 if device.api_version() >= Version::V1_1
383 || device.enabled_extensions().khr_get_memory_requirements2
384 {
385 let info2_vk = ash::vk::ImageSparseMemoryRequirementsInfo2::default().image(handle);
386
387 let mut count = 0;
388
389 if device.api_version() >= Version::V1_1 {
390 unsafe {
391 (fns.v1_1.get_image_sparse_memory_requirements2)(
392 device.handle(),
393 &info2_vk,
394 &mut count,
395 ptr::null_mut(),
396 )
397 };
398 } else {
399 unsafe {
400 (fns.khr_get_memory_requirements2
401 .get_image_sparse_memory_requirements2_khr)(
402 device.handle(),
403 &info2_vk,
404 &mut count,
405 ptr::null_mut(),
406 )
407 };
408 }
409
410 let mut requirements2_vk =
411 vec![SparseImageMemoryRequirements::to_mut_vk2(); count as usize];
412
413 if device.api_version() >= Version::V1_1 {
414 unsafe {
415 (fns.v1_1.get_image_sparse_memory_requirements2)(
416 device.handle(),
417 &info2_vk,
418 &mut count,
419 requirements2_vk.as_mut_ptr(),
420 )
421 };
422 } else {
423 unsafe {
424 (fns.khr_get_memory_requirements2
425 .get_image_sparse_memory_requirements2_khr)(
426 device.handle(),
427 &info2_vk,
428 &mut count,
429 requirements2_vk.as_mut_ptr(),
430 )
431 };
432 }
433
434 unsafe { requirements2_vk.set_len(count as usize) };
435 requirements2_vk
436 .iter()
437 .map(SparseImageMemoryRequirements::from_vk2)
438 .collect()
439 } else {
440 let mut count = 0;
441
442 unsafe {
443 (fns.v1_0.get_image_sparse_memory_requirements)(
444 device.handle(),
445 handle,
446 &mut count,
447 ptr::null_mut(),
448 )
449 };
450
451 let mut requirements_vk =
452 vec![SparseImageMemoryRequirements::to_mut_vk(); count as usize];
453
454 unsafe {
455 (fns.v1_0.get_image_sparse_memory_requirements)(
456 device.handle(),
457 handle,
458 &mut count,
459 requirements_vk.as_mut_ptr(),
460 )
461 };
462
463 unsafe { requirements_vk.set_len(count as usize) };
464 requirements_vk
465 .iter()
466 .map(SparseImageMemoryRequirements::from_vk)
467 .collect()
468 }
469 }
470
471 unsafe fn get_drm_format_modifier_properties(
472 device: &Device,
473 handle: ash::vk::Image,
474 ) -> Result<u64, VulkanError> {
475 let mut properties_vk = ash::vk::ImageDrmFormatModifierPropertiesEXT::default();
476
477 let fns = device.fns();
478 unsafe {
479 (fns.ext_image_drm_format_modifier
480 .get_image_drm_format_modifier_properties_ext)(
481 device.handle(),
482 handle,
483 &mut properties_vk,
484 )
485 }
486 .result()
487 .map_err(VulkanError::from)?;
488
489 Ok(properties_vk.drm_format_modifier)
490 }
491
492 pub fn bind_memory(
503 self,
504 allocations: impl IntoIterator<Item = ResourceMemory>,
505 ) -> Result<
506 Image,
507 (
508 Validated<VulkanError>,
509 RawImage,
510 impl ExactSizeIterator<Item = ResourceMemory>,
511 ),
512 > {
513 let allocations: SmallVec<[_; 4]> = allocations.into_iter().collect();
514
515 if let Err(err) = self.validate_bind_memory(&allocations) {
516 return Err((err.into(), self, allocations.into_iter()));
517 }
518
519 unsafe { self.bind_memory_unchecked(allocations) }.map_err(|(err, image, allocations)| {
520 (
521 err.into(),
522 image,
523 allocations
524 .into_iter()
525 .collect::<SmallVec<[_; 4]>>()
526 .into_iter(),
527 )
528 })
529 }
530
531 fn validate_bind_memory(
532 &self,
533 allocations: &[ResourceMemory],
534 ) -> Result<(), Box<ValidationError>> {
535 if self.flags().intersects(ImageCreateFlags::SPARSE_BINDING) {
536 return Err(Box::new(ValidationError {
537 context: "self.flags()".into(),
538 problem: "contains `ImageCreateFlags::SPARSE_BINDING`".into(),
539 vuids: &["VUID-VkBindImageMemoryInfo-image-01045"],
540 ..Default::default()
541 }));
542 }
543
544 let physical_device = self.device().physical_device();
545
546 if self.flags.intersects(ImageCreateFlags::DISJOINT) {
547 match self.tiling {
548 ImageTiling::Optimal | ImageTiling::Linear => {
549 if allocations.len() != self.format.planes().len() {
550 return Err(Box::new(ValidationError {
551 problem: "`self.flags()` contains `ImageCreateFlags::DISJOINT`, and \
552 `self.tiling()` is `ImageTiling::Optimal` or \
553 `ImageTiling::Linear`, but the length of `allocations` does not \
554 equal the number of planes in the format of the image"
555 .into(),
556 ..Default::default()
557 }));
558 }
559 }
560 ImageTiling::DrmFormatModifier => {
561 if allocations.len() != self.drm_format_modifier.unwrap().1 as usize {
562 return Err(Box::new(ValidationError {
563 problem: "`self.flags()` contains `ImageCreateFlags::DISJOINT`, and \
564 `self.tiling()` is `ImageTiling::DrmFormatModifier`, but the \
565 length of `allocations` does not equal the number of memory planes \
566 of the DRM format modifier of the image"
567 .into(),
568 ..Default::default()
569 }));
570 }
571 }
572 }
573 } else {
574 if allocations.len() != 1 {
575 return Err(Box::new(ValidationError {
576 problem: "`self.flags()` does not contain `ImageCreateFlags::DISJOINT`, but \
577 the length of `allocations` is not 1"
578 .into(),
579 ..Default::default()
580 }));
581 }
582 }
583
584 for (index, (allocation, memory_requirements)) in allocations
585 .iter()
586 .zip(self.memory_requirements.iter())
587 .enumerate()
588 {
589 match allocation.allocation_type() {
590 AllocationType::Unknown => {
591 }
593 AllocationType::Linear => {
594 if self.tiling() != ImageTiling::Linear {
595 return Err(Box::new(ValidationError {
596 problem: format!(
597 "`allocations[{}].allocation_type()` is `AllocationType::Linear`, \
598 but `self.tiling()` is not `ImageTiling::Linear`",
599 index
600 )
601 .into(),
602 ..Default::default()
603 }));
604 }
605 }
606 AllocationType::NonLinear => {
607 if self.tiling() != ImageTiling::Optimal {
608 return Err(Box::new(ValidationError {
609 problem: format!(
610 "`allocations[{}].allocation_type()` is \
611 `AllocationType::NonLinear`, but `self.tiling()` is not \
612 `ImageTiling::Optimal`",
613 index
614 )
615 .into(),
616 ..Default::default()
617 }));
618 }
619 }
620 }
621
622 let memory = allocation.device_memory();
623 let memory_offset = allocation.offset();
624 let memory_type = &physical_device.memory_properties().memory_types
625 [memory.memory_type_index() as usize];
626
627 assert_eq!(self.device(), memory.device());
629
630 if memory_requirements.memory_type_bits & (1 << memory.memory_type_index()) == 0 {
637 return Err(Box::new(ValidationError {
638 problem: format!(
639 "`allocation[{}].device_memory().memory_type_index()` is not a bit set in \
640 `self.memory_requirements().memory_type_bits`",
641 index
642 )
643 .into(),
644 vuids: &[
645 "VUID-VkBindImageMemoryInfo-pNext-01615",
646 "VUID-VkBindImageMemoryInfo-pNext-01619",
647 ],
648 ..Default::default()
649 }));
650 }
651
652 if !is_aligned(memory_offset, memory_requirements.layout.alignment()) {
653 return Err(Box::new(ValidationError {
654 problem: format!(
655 "`allocations[{}].offset()` is not aligned according to \
656 `self.memory_requirements().layout.alignment()`",
657 index
658 )
659 .into(),
660 vuids: &[
661 "VUID-VkBindImageMemoryInfo-pNext-01616",
662 "VUID-VkBindImageMemoryInfo-pNext-01620",
663 ],
664 ..Default::default()
665 }));
666 }
667
668 if allocation.size() < memory_requirements.layout.size() {
669 return Err(Box::new(ValidationError {
670 problem: format!(
671 "`allocations[{}].size()` is less than \
672 `self.memory_requirements().layout.size()`",
673 index
674 )
675 .into(),
676 vuids: &[
677 "VUID-VkBindImageMemoryInfo-pNext-01617",
678 "VUID-VkBindImageMemoryInfo-pNext-01621",
679 ],
680 ..Default::default()
681 }));
682 }
683
684 if let Some(dedicated_to) = memory.dedicated_to() {
685 match dedicated_to {
686 DedicatedTo::Image(id) if id == self.id => {}
687 _ => {
688 return Err(Box::new(ValidationError {
689 problem: format!(
690 "`allocations[{}].device_memory()` is a dedicated allocation, but \
691 it is not dedicated to this image",
692 index
693 )
694 .into(),
695 vuids: &["VUID-VkBindImageMemoryInfo-memory-02628"],
696 ..Default::default()
697 }));
698 }
699 }
700 debug_assert!(memory_offset == 0); } else {
702 if memory_requirements.requires_dedicated_allocation {
703 return Err(Box::new(ValidationError {
704 problem: format!(
705 "`self.memory_requirements().requires_dedicated_allocation` is \
706 `true`, but `allocations[{}].device_memory()` is not a \
707 dedicated allocation",
708 index
709 )
710 .into(),
711 vuids: &["VUID-VkBindImageMemoryInfo-image-01445"],
712 ..Default::default()
713 }));
714 }
715 }
716
717 if memory_type
718 .property_flags
719 .intersects(MemoryPropertyFlags::PROTECTED)
720 {
721 return Err(Box::new(ValidationError {
722 problem: format!(
723 "the `property_flags` of the memory type of \
724 `allocations[{}].device_memory()` contains \
725 `MemoryPropertyFlags::PROTECTED`",
726 index
727 )
728 .into(),
729 vuids: &["VUID-VkBindImageMemoryInfo-None-01901"],
730 ..Default::default()
731 }));
732 }
733
734 if !memory.export_handle_types().is_empty() {
735 if !self
736 .external_memory_handle_types
737 .intersects(memory.export_handle_types())
738 {
739 return Err(Box::new(ValidationError {
740 problem: format!(
741 "`allocations[{}].device_memory().export_handle_types()` is not empty, \
742 but it does not share at least one memory type with \
743 `self.external_memory_handle_types()`",
744 index
745 )
746 .into(),
747 vuids: &["VUID-VkBindImageMemoryInfo-memory-02728"],
748 ..Default::default()
749 }));
750 }
751
752 for handle_type in memory.export_handle_types() {
753 let image_format_properties = unsafe {
754 physical_device.image_format_properties_unchecked(ImageFormatInfo {
755 flags: self.flags,
756 format: self.format,
757 view_formats: self.view_formats.clone(),
758 image_type: self.image_type,
759 tiling: self.tiling,
760 usage: self.usage,
761 stencil_usage: self.stencil_usage,
762 drm_format_modifier_info: self.drm_format_modifier().map(
763 |(drm_format_modifier, _)| ImageDrmFormatModifierInfo {
764 drm_format_modifier,
765 sharing: self.sharing.clone(),
766 _ne: crate::NonExhaustive(()),
767 },
768 ),
769 external_memory_handle_type: Some(handle_type),
770 image_view_type: None,
771 _ne: crate::NonExhaustive(()),
772 })
773 }
774 .map_err(|_| {
775 Box::new(ValidationError {
776 problem: "`PhysicalDevice::image_format_properties` returned an error"
777 .into(),
778 ..Default::default()
779 })
780 })?
781 .unwrap();
782
783 if image_format_properties
784 .external_memory_properties
785 .dedicated_only
786 && !memory.is_dedicated()
787 {
788 return Err(Box::new(ValidationError {
789 problem: format!(
790 "`allocations[{}].device_memory().export_handle_types()` has the \
791 `{:?}` flag set, which requires a dedicated allocation as returned \
792 by `PhysicalDevice::image_format_properties`, but \
793 `allocations[{}].device_memory()` is not a dedicated allocation",
794 index, handle_type, index,
795 )
796 .into(),
797 vuids: &["VUID-VkMemoryAllocateInfo-pNext-00639"],
798 ..Default::default()
799 }));
800 }
801
802 if !image_format_properties
803 .external_memory_properties
804 .exportable
805 {
806 return Err(Box::new(ValidationError {
807 problem: format!(
808 "`allocations[{}].device_memory().export_handle_types()` has the \
809 `{:?}` flag set, but the flag is not supported for exporting, as \
810 returned by `PhysicalDevice::image_format_properties`",
811 index, handle_type,
812 )
813 .into(),
814 vuids: &["VUID-VkExportMemoryAllocateInfo-handleTypes-00656"],
815 ..Default::default()
816 }));
817 }
818
819 if !image_format_properties
820 .external_memory_properties
821 .compatible_handle_types
822 .contains(memory.export_handle_types())
823 {
824 return Err(Box::new(ValidationError {
825 problem: format!(
826 "`allocation.device_memory().export_handle_types()` has the `{:?}` \
827 flag set, but the flag is not compatible with the other flags set, \
828 as returned by `PhysicalDevice::image_format_properties`",
829 handle_type,
830 )
831 .into(),
832 vuids: &["VUID-VkExportMemoryAllocateInfo-handleTypes-00656"],
833 ..Default::default()
834 }));
835 }
836 }
837 }
838
839 if let Some(handle_type) = memory.imported_handle_type() {
840 if !ExternalMemoryHandleTypes::from(handle_type)
841 .intersects(self.external_memory_handle_types)
842 {
843 return Err(Box::new(ValidationError {
844 problem: format!(
845 "`allocations[{}].device_memory()` is imported, but \
846 `self.external_memory_handle_types()` does not contain the imported \
847 handle type",
848 index
849 )
850 .into(),
851 vuids: &["VUID-VkBindImageMemoryInfo-memory-02989"],
852 ..Default::default()
853 }));
854 }
855 }
856 }
857
858 Ok(())
859 }
860
861 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
872 pub unsafe fn bind_memory_unchecked(
873 self,
874 allocations: impl IntoIterator<Item = ResourceMemory>,
875 ) -> Result<
876 Image,
877 (
878 VulkanError,
879 RawImage,
880 impl ExactSizeIterator<Item = ResourceMemory>,
881 ),
882 > {
883 let allocations: SmallVec<[_; 4]> = allocations.into_iter().collect();
884
885 const PLANE_ASPECTS_VK_NORMAL: &[ash::vk::ImageAspectFlags] = &[
886 ash::vk::ImageAspectFlags::PLANE_0,
887 ash::vk::ImageAspectFlags::PLANE_1,
888 ash::vk::ImageAspectFlags::PLANE_2,
889 ];
890 const PLANE_ASPECTS_VK_DRM_FORMAT_MODIFIER: &[ash::vk::ImageAspectFlags] = &[
891 ash::vk::ImageAspectFlags::MEMORY_PLANE_0_EXT,
892 ash::vk::ImageAspectFlags::MEMORY_PLANE_1_EXT,
893 ash::vk::ImageAspectFlags::MEMORY_PLANE_2_EXT,
894 ash::vk::ImageAspectFlags::MEMORY_PLANE_3_EXT,
895 ];
896 let needs_plane = (self.device.api_version() >= Version::V1_1
897 || self.device.enabled_extensions().khr_bind_memory2)
898 && self.flags.intersects(ImageCreateFlags::DISJOINT);
899
900 let plane_aspects_vk = if needs_plane {
901 Some(match self.tiling {
902 ImageTiling::Optimal | ImageTiling::Linear => {
904 let plane_count = self.format.planes().len();
905 &PLANE_ASPECTS_VK_NORMAL[..plane_count]
906 }
907 ImageTiling::DrmFormatModifier => {
909 let plane_count = self.drm_format_modifier.unwrap().1 as usize;
910 &PLANE_ASPECTS_VK_DRM_FORMAT_MODIFIER[..plane_count]
911 }
912 })
913 } else {
914 debug_assert_eq!(allocations.len(), 1);
915 None
916 };
917
918 let mut plane_infos_vk: SmallVec<[_; 4]> = (0..allocations.len())
919 .map(|plane_num| {
920 plane_aspects_vk.map(|plane_aspects_vk| {
921 let plane_aspect_vk = plane_aspects_vk[plane_num];
922 ash::vk::BindImagePlaneMemoryInfo::default().plane_aspect(plane_aspect_vk)
923 })
924 })
925 .collect();
926
927 let infos_vk: SmallVec<[_; 4]> = allocations
928 .iter()
929 .zip(&mut plane_infos_vk)
930 .map(|(allocation, plane_info_vk)| {
931 let mut info_vk = allocation.to_vk_bind_image_memory_info(self.handle);
932
933 if let Some(next) = plane_info_vk {
934 info_vk = info_vk.push_next(next);
935 }
936
937 info_vk
938 })
939 .collect();
940
941 let fns = self.device.fns();
942
943 let result = if self.device.api_version() >= Version::V1_1
944 || self.device.enabled_extensions().khr_bind_memory2
945 {
946 if self.device.api_version() >= Version::V1_1 {
947 unsafe {
948 (fns.v1_1.bind_image_memory2)(
949 self.device.handle(),
950 infos_vk.len() as u32,
951 infos_vk.as_ptr(),
952 )
953 }
954 } else {
955 unsafe {
956 (fns.khr_bind_memory2.bind_image_memory2_khr)(
957 self.device.handle(),
958 infos_vk.len() as u32,
959 infos_vk.as_ptr(),
960 )
961 }
962 }
963 } else {
964 let info_vk = &infos_vk[0];
965
966 unsafe {
967 (fns.v1_0.bind_image_memory)(
968 self.device.handle(),
969 info_vk.image,
970 info_vk.memory,
971 info_vk.memory_offset,
972 )
973 }
974 }
975 .result();
976
977 if let Err(err) = result {
978 return Err((VulkanError::from(err), self, allocations.into_iter()));
979 }
980
981 let layout = self.default_layout();
982
983 Ok(unsafe { Image::from_raw(self, ImageMemory::Normal(allocations), layout) })
984 }
985
986 pub unsafe fn assume_bound(self) -> Image {
1007 let memory = if self.flags().intersects(ImageCreateFlags::SPARSE_BINDING) {
1008 ImageMemory::Sparse
1009 } else {
1010 ImageMemory::External
1011 };
1012 let layout = self.default_layout();
1013
1014 unsafe { Image::from_raw(self, memory, layout) }
1015 }
1016
1017 fn default_layout(&self) -> ImageLayout {
1018 let usage = self
1019 .usage
1020 .difference(ImageUsage::TRANSFER_SRC | ImageUsage::TRANSFER_DST);
1021
1022 if usage.intersects(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
1023 && usage
1024 .difference(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
1025 .is_empty()
1026 {
1027 ImageLayout::ShaderReadOnlyOptimal
1028 } else if usage.intersects(ImageUsage::COLOR_ATTACHMENT)
1029 && usage.difference(ImageUsage::COLOR_ATTACHMENT).is_empty()
1030 {
1031 ImageLayout::ColorAttachmentOptimal
1032 } else if usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
1033 && usage
1034 .difference(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
1035 .is_empty()
1036 {
1037 ImageLayout::DepthStencilAttachmentOptimal
1038 } else {
1039 ImageLayout::General
1040 }
1041 }
1042
1043 #[inline]
1051 pub fn memory_requirements(&self) -> &[MemoryRequirements] {
1052 &self.memory_requirements
1053 }
1054
1055 #[inline]
1060 pub fn sparse_memory_requirements(&self) -> &[SparseImageMemoryRequirements] {
1061 &self.sparse_memory_requirements
1062 }
1063
1064 #[inline]
1066 pub fn flags(&self) -> ImageCreateFlags {
1067 self.flags
1068 }
1069
1070 #[inline]
1072 pub fn image_type(&self) -> ImageType {
1073 self.image_type
1074 }
1075
1076 #[inline]
1078 pub fn format(&self) -> Format {
1079 self.format
1080 }
1081
1082 #[inline]
1084 pub fn format_features(&self) -> FormatFeatures {
1085 self.format_features
1086 }
1087
1088 #[inline]
1090 pub fn view_formats(&self) -> &[Format] {
1091 &self.view_formats
1092 }
1093
1094 #[inline]
1096 pub fn extent(&self) -> [u32; 3] {
1097 self.extent
1098 }
1099
1100 #[inline]
1102 pub fn array_layers(&self) -> u32 {
1103 self.array_layers
1104 }
1105
1106 #[inline]
1108 pub fn mip_levels(&self) -> u32 {
1109 self.mip_levels
1110 }
1111
1112 #[inline]
1114 pub fn initial_layout(&self) -> ImageLayout {
1115 self.initial_layout
1116 }
1117
1118 #[inline]
1120 pub fn samples(&self) -> SampleCount {
1121 self.samples
1122 }
1123
1124 #[inline]
1126 pub fn tiling(&self) -> ImageTiling {
1127 self.tiling
1128 }
1129
1130 #[inline]
1132 pub fn usage(&self) -> ImageUsage {
1133 self.usage
1134 }
1135
1136 #[inline]
1138 pub fn stencil_usage(&self) -> Option<ImageUsage> {
1139 self.stencil_usage
1140 }
1141
1142 #[inline]
1144 pub fn sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> {
1145 &self.sharing
1146 }
1147
1148 #[inline]
1153 pub fn drm_format_modifier(&self) -> Option<(u64, u32)> {
1154 self.drm_format_modifier
1155 }
1156
1157 #[inline]
1159 pub fn external_memory_handle_types(&self) -> ExternalMemoryHandleTypes {
1160 self.external_memory_handle_types
1161 }
1162
1163 #[inline]
1166 pub fn subresource_layers(&self) -> ImageSubresourceLayers {
1167 ImageSubresourceLayers {
1168 aspects: {
1169 let aspects = self.format.aspects();
1170
1171 if aspects.intersects(ImageAspects::PLANE_0) {
1172 ImageAspects::PLANE_0
1173 } else {
1174 aspects
1175 }
1176 },
1177 mip_level: 0,
1178 array_layers: 0..self.array_layers,
1179 }
1180 }
1181
1182 #[inline]
1185 pub fn subresource_range(&self) -> ImageSubresourceRange {
1186 ImageSubresourceRange {
1187 aspects: self.format.aspects()
1188 - (ImageAspects::PLANE_0 | ImageAspects::PLANE_1 | ImageAspects::PLANE_2),
1189 mip_levels: 0..self.mip_levels,
1190 array_layers: 0..self.array_layers,
1191 }
1192 }
1193
1194 pub fn subresource_layout(
1205 &self,
1206 aspect: ImageAspect,
1207 mip_level: u32,
1208 array_layer: u32,
1209 ) -> Result<SubresourceLayout, Box<ValidationError>> {
1210 self.validate_subresource_layout(aspect, mip_level, array_layer)?;
1211
1212 Ok(unsafe { self.subresource_layout_unchecked(aspect, mip_level, array_layer) })
1213 }
1214
1215 fn validate_subresource_layout(
1216 &self,
1217 aspect: ImageAspect,
1218 mip_level: u32,
1219 array_layer: u32,
1220 ) -> Result<(), Box<ValidationError>> {
1221 aspect.validate_device(&self.device).map_err(|err| {
1222 err.add_context("aspect")
1223 .set_vuids(&["VUID-VkImageSubresource-aspectMask-parameter"])
1224 })?;
1225
1226 if !matches!(
1231 self.tiling,
1232 ImageTiling::Linear | ImageTiling::DrmFormatModifier
1233 ) {
1234 return Err(Box::new(ValidationError {
1235 context: "self.tiling()".into(),
1236 problem: "is not `ImageTiling::Linear` or `ImageTiling::DrmFormatModifier`".into(),
1237 vuids: &["VUID-vkGetImageSubresourceLayout-image-02270"],
1238 ..Default::default()
1239 }));
1240 }
1241
1242 if mip_level >= self.mip_levels {
1243 return Err(Box::new(ValidationError {
1244 context: "mip_level".into(),
1245 problem: "is greater than the number of mip levels in the image".into(),
1246 vuids: &["VUID-vkGetImageSubresourceLayout-mipLevel-01716"],
1247 ..Default::default()
1248 }));
1249 }
1250
1251 if array_layer >= self.array_layers {
1252 return Err(Box::new(ValidationError {
1253 context: "array_layer".into(),
1254 problem: "is greater than the number of array layers in the image".into(),
1255 vuids: &["VUID-vkGetImageSubresourceLayout-arrayLayer-01717"],
1256 ..Default::default()
1257 }));
1258 }
1259
1260 let format = self.format;
1261 let format_aspects = format.aspects();
1262
1263 if let Some((_, drm_format_modifier_plane_count)) = self.drm_format_modifier {
1264 match drm_format_modifier_plane_count {
1265 1 => {
1266 if !matches!(aspect, ImageAspect::MemoryPlane0) {
1267 return Err(Box::new(ValidationError {
1268 problem: "the image has a DRM format modifier with 1 memory plane, \
1269 but `aspect` is not `ImageAspect::MemoryPlane0`"
1270 .into(),
1271 vuids: &["VUID-vkGetImageSubresourceLayout-tiling-02271"],
1272 ..Default::default()
1273 }));
1274 }
1275 }
1276 2 => {
1277 if !matches!(
1278 aspect,
1279 ImageAspect::MemoryPlane0 | ImageAspect::MemoryPlane1
1280 ) {
1281 return Err(Box::new(ValidationError {
1282 problem: "the image has a DRM format modifier with 2 memory planes, \
1283 but `aspect` is not `ImageAspect::MemoryPlane0` or \
1284 `ImageAspect::MemoryPlane1`"
1285 .into(),
1286 vuids: &["VUID-vkGetImageSubresourceLayout-tiling-02271"],
1287 ..Default::default()
1288 }));
1289 }
1290 }
1291 3 => {
1292 if !matches!(
1293 aspect,
1294 ImageAspect::MemoryPlane0
1295 | ImageAspect::MemoryPlane1
1296 | ImageAspect::MemoryPlane2
1297 ) {
1298 return Err(Box::new(ValidationError {
1299 problem: "the image has a DRM format modifier with 3 memory planes, \
1300 but `aspect` is not `ImageAspect::MemoryPlane0`, \
1301 `ImageAspect::MemoryPlane1` or `ImageAspect::MemoryPlane2`"
1302 .into(),
1303 vuids: &["VUID-vkGetImageSubresourceLayout-tiling-02271"],
1304 ..Default::default()
1305 }));
1306 }
1307 }
1308 4 => {
1309 if !matches!(
1310 aspect,
1311 ImageAspect::MemoryPlane0
1312 | ImageAspect::MemoryPlane1
1313 | ImageAspect::MemoryPlane2
1314 | ImageAspect::MemoryPlane3
1315 ) {
1316 return Err(Box::new(ValidationError {
1317 problem: "the image has a DRM format modifier with 4 memory planes, \
1318 but `aspect` is not `ImageAspect::MemoryPlane0`, \
1319 `ImageAspect::MemoryPlane1`, `ImageAspect::MemoryPlane2` or \
1320 `ImageAspect::MemoryPlane3`"
1321 .into(),
1322 vuids: &["VUID-vkGetImageSubresourceLayout-tiling-02271"],
1323 ..Default::default()
1324 }));
1325 }
1326 }
1327 _ => unreachable!("image has more than 4 memory planes??"),
1328 }
1329 } else if format_aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL) {
1330 return Err(Box::new(ValidationError {
1333 context: "self.format()".into(),
1334 problem: "has both a depth and a stencil aspect".into(),
1335 vuids: &[
1336 "VUID-vkGetImageSubresourceLayout-aspectMask-00997",
1337 "VUID-vkGetImageSubresourceLayout-format-04462",
1338 "VUID-vkGetImageSubresourceLayout-format-04463",
1339 ],
1340 ..Default::default()
1341 }));
1342 } else if format_aspects.intersects(ImageAspects::DEPTH) {
1343 if aspect != ImageAspect::Depth {
1344 return Err(Box::new(ValidationError {
1345 problem: "`self.format()` is a depth format, but \
1346 `aspect` is not `ImageAspect::Depth`"
1347 .into(),
1348 vuids: &["VUID-vkGetImageSubresourceLayout-format-04462"],
1349 ..Default::default()
1350 }));
1351 }
1352 } else if format_aspects.intersects(ImageAspects::STENCIL) {
1353 if aspect != ImageAspect::Stencil {
1354 return Err(Box::new(ValidationError {
1355 problem: "`self.format()` is a stencil format, but \
1356 `aspect` is not `ImageAspect::Stencil`"
1357 .into(),
1358 vuids: &["VUID-vkGetImageSubresourceLayout-format-04463"],
1359 ..Default::default()
1360 }));
1361 }
1362 } else if format_aspects.intersects(ImageAspects::COLOR) {
1363 if format.planes().is_empty() {
1364 if aspect != ImageAspect::Color {
1365 return Err(Box::new(ValidationError {
1366 problem: "`self.format()` is a color format with a single plane, but \
1367 `aspect` is not `ImageAspect::Color`"
1368 .into(),
1369 vuids: &["VUID-vkGetImageSubresourceLayout-format-08886"],
1370 ..Default::default()
1371 }));
1372 }
1373 } else if format.planes().len() == 2 {
1374 if !matches!(aspect, ImageAspect::Plane0 | ImageAspect::Plane1) {
1375 return Err(Box::new(ValidationError {
1376 problem: "`self.format()` is a color format with two planes, but \
1377 `aspect` is not `ImageAspect::Plane0` or `ImageAspect::Plane1`"
1378 .into(),
1379 vuids: &["VUID-vkGetImageSubresourceLayout-tiling-08717"],
1380 ..Default::default()
1381 }));
1382 }
1383 } else if format.planes().len() == 3 {
1384 if !matches!(
1385 aspect,
1386 ImageAspect::Plane0 | ImageAspect::Plane1 | ImageAspect::Plane2
1387 ) {
1388 return Err(Box::new(ValidationError {
1389 problem: "`self.format()` is a color format with three planes, but \
1390 `aspect` is not `ImageAspect::Plane0`, `ImageAspect::Plane1` or \
1391 `ImageAspect::Plane2`"
1392 .into(),
1393 vuids: &["VUID-vkGetImageSubresourceLayout-tiling-08717"],
1394 ..Default::default()
1395 }));
1396 }
1397 }
1398 }
1399
1400 if !format_aspects.contains(aspect.into()) {
1412 return Err(Box::new(ValidationError {
1413 context: "array_layer".into(),
1414 problem: "is greater than the number of array layers in the image".into(),
1415 vuids: &["VUID-vkGetImageSubresourceLayout-arrayLayer-01717"],
1416 ..Default::default()
1417 }));
1418 }
1419
1420 Ok(())
1421 }
1422
1423 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1424 pub unsafe fn subresource_layout_unchecked(
1425 &self,
1426 aspect: ImageAspect,
1427 mip_level: u32,
1428 array_layer: u32,
1429 ) -> SubresourceLayout {
1430 self.subresource_layout.get_or_insert(
1431 (aspect, mip_level, array_layer),
1432 |&(aspect, mip_level, array_layer)| {
1433 let subresource_vk = ash::vk::ImageSubresource {
1434 aspect_mask: aspect.into(),
1435 mip_level,
1436 array_layer,
1437 };
1438
1439 let ash::vk::SubresourceLayout {
1440 offset,
1441 size,
1442 row_pitch,
1443 array_pitch,
1444 depth_pitch,
1445 } = {
1446 let fns = self.device.fns();
1447 let mut output = MaybeUninit::uninit();
1448 unsafe {
1449 (fns.v1_0.get_image_subresource_layout)(
1450 self.device.handle(),
1451 self.handle,
1452 &subresource_vk,
1453 output.as_mut_ptr(),
1454 )
1455 };
1456 unsafe { output.assume_init() }
1457 };
1458
1459 SubresourceLayout {
1460 offset,
1461 size,
1462 row_pitch,
1463 array_pitch: (self.array_layers > 1).then_some(array_pitch),
1464 depth_pitch: matches!(self.image_type, ImageType::Dim3d).then_some(depth_pitch),
1465 }
1466 },
1467 )
1468 }
1469}
1470
1471impl Drop for RawImage {
1472 #[inline]
1473 fn drop(&mut self) {
1474 if !self.needs_destruction {
1475 return;
1476 }
1477
1478 let fns = self.device.fns();
1479 unsafe { (fns.v1_0.destroy_image)(self.device.handle(), self.handle, ptr::null()) };
1480 }
1481}
1482
1483unsafe impl VulkanObject for RawImage {
1484 type Handle = ash::vk::Image;
1485
1486 #[inline]
1487 fn handle(&self) -> Self::Handle {
1488 self.handle
1489 }
1490}
1491
1492unsafe impl DeviceOwned for RawImage {
1493 #[inline]
1494 fn device(&self) -> &Arc<Device> {
1495 &self.device
1496 }
1497}
1498
1499impl_id_counter!(RawImage);
1500
1501#[derive(Clone, Debug)]
1503pub struct ImageCreateInfo {
1504 pub flags: ImageCreateFlags,
1508
1509 pub image_type: ImageType,
1513
1514 pub format: Format,
1518
1519 pub view_formats: Vec<Format>,
1540
1541 pub extent: [u32; 3],
1548
1549 pub array_layers: u32,
1559
1560 pub mip_levels: u32,
1564
1565 pub samples: SampleCount,
1575
1576 pub tiling: ImageTiling,
1580
1581 pub usage: ImageUsage,
1585
1586 pub stencil_usage: Option<ImageUsage>,
1595
1596 pub sharing: Sharing<SmallVec<[u32; 4]>>,
1600
1601 pub initial_layout: ImageLayout,
1605
1606 pub drm_format_modifiers: Vec<u64>,
1620
1621 pub drm_format_modifier_plane_layouts: Vec<SubresourceLayout>,
1637
1638 pub external_memory_handle_types: ExternalMemoryHandleTypes,
1647
1648 pub _ne: crate::NonExhaustive,
1649}
1650
1651impl Default for ImageCreateInfo {
1652 #[inline]
1653 fn default() -> Self {
1654 Self {
1655 flags: ImageCreateFlags::empty(),
1656 image_type: ImageType::Dim2d,
1657 format: Format::UNDEFINED,
1658 view_formats: Vec::new(),
1659 extent: [0; 3],
1660 array_layers: 1,
1661 mip_levels: 1,
1662 samples: SampleCount::Sample1,
1663 tiling: ImageTiling::Optimal,
1664 usage: ImageUsage::empty(),
1665 stencil_usage: None,
1666 sharing: Sharing::Exclusive,
1667 initial_layout: ImageLayout::Undefined,
1668 external_memory_handle_types: ExternalMemoryHandleTypes::empty(),
1669 drm_format_modifiers: Vec::new(),
1670 drm_format_modifier_plane_layouts: Vec::new(),
1671 _ne: crate::NonExhaustive(()),
1672 }
1673 }
1674}
1675
1676impl ImageCreateInfo {
1677 pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1678 let &Self {
1679 flags,
1680 image_type,
1681 format,
1682 ref view_formats,
1683 extent,
1684 array_layers,
1685 mip_levels,
1686 samples,
1687 tiling,
1688 usage,
1689 stencil_usage,
1690 ref sharing,
1691 initial_layout,
1692 ref drm_format_modifiers,
1693 ref drm_format_modifier_plane_layouts,
1694 external_memory_handle_types,
1695 _ne: _,
1696 } = self;
1697
1698 let physical_device = device.physical_device();
1699 let device_properties = physical_device.properties();
1700
1701 flags.validate_device(device).map_err(|err| {
1702 err.add_context("flags")
1703 .set_vuids(&["VUID-VkImageCreateInfo-flags-parameter"])
1704 })?;
1705
1706 format.validate_device(device).map_err(|err| {
1707 err.add_context("format")
1708 .set_vuids(&["VUID-VkImageCreateInfo-format-parameter"])
1709 })?;
1710
1711 samples.validate_device(device).map_err(|err| {
1712 err.add_context("samples")
1713 .set_vuids(&["VUID-VkImageCreateInfo-samples-parameter"])
1714 })?;
1715
1716 tiling.validate_device(device).map_err(|err| {
1717 err.add_context("tiling")
1718 .set_vuids(&["VUID-VkImageCreateInfo-tiling-parameter"])
1719 })?;
1720
1721 usage.validate_device(device).map_err(|err| {
1722 err.add_context("usage")
1723 .set_vuids(&["VUID-VkImageCreateInfo-usage-parameter"])
1724 })?;
1725
1726 if usage.is_empty() {
1727 return Err(Box::new(ValidationError {
1728 context: "usage".into(),
1729 problem: "is empty".into(),
1730 vuids: &["VUID-VkImageCreateInfo-usage-requiredbitmask"],
1731 ..Default::default()
1732 }));
1733 }
1734
1735 if format == Format::UNDEFINED {
1736 return Err(Box::new(ValidationError {
1737 context: "format".into(),
1738 problem: "is `Format::UNDEFINED`".into(),
1739 vuids: &["VUID-VkImageCreateInfo-pNext-01975"],
1740 ..Default::default()
1741 }));
1742 }
1743
1744 let format_properties = unsafe { physical_device.format_properties_unchecked(format) };
1745 let image_create_drm_format_modifiers = &drm_format_modifiers;
1746 let image_create_maybe_linear = match tiling {
1747 ImageTiling::Linear => true,
1748 ImageTiling::Optimal => false,
1749 ImageTiling::DrmFormatModifier => {
1750 const DRM_FORMAT_MOD_LINEAR: u64 = 0;
1751 image_create_drm_format_modifiers.contains(&DRM_FORMAT_MOD_LINEAR)
1752 }
1753 };
1754 let image_create_format_features =
1755 format_properties.format_features(tiling, drm_format_modifiers);
1756
1757 initial_layout.validate_device(device).map_err(|err| {
1758 err.add_context("initial_layout")
1759 .set_vuids(&["VUID-VkImageCreateInfo-initialLayout-parameter"])
1760 })?;
1761
1762 if !matches!(
1763 initial_layout,
1764 ImageLayout::Undefined | ImageLayout::Preinitialized
1765 ) {
1766 return Err(Box::new(ValidationError {
1767 context: "initial_layout".into(),
1768 problem: "is not `ImageLayout::Undefined` or `ImageLayout::Preinitialized`".into(),
1769 vuids: &["VUID-VkImageCreateInfo-initialLayout-00993"],
1770 ..Default::default()
1771 }));
1772 }
1773
1774 if flags.intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE)
1775 && !flags.intersects(ImageCreateFlags::MUTABLE_FORMAT)
1776 {
1777 return Err(Box::new(ValidationError {
1778 context: "flags".into(),
1779 problem: "contains `ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, but does not \
1780 contain `ImageCreateFlags::MUTABLE_FORMAT`"
1781 .into(),
1782 vuids: &["VUID-VkImageCreateInfo-flags-01573"],
1783 ..Default::default()
1784 }));
1785 }
1786
1787 if !view_formats.is_empty() {
1788 if !(device.api_version() >= Version::V1_2
1789 || device.enabled_extensions().khr_image_format_list)
1790 {
1791 return Err(Box::new(ValidationError {
1792 context: "view_formats".into(),
1793 problem: "is not empty".into(),
1794 requires_one_of: RequiresOneOf(&[
1795 RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]),
1796 RequiresAllOf(&[Requires::DeviceExtension("khr_image_format_list")]),
1797 ]),
1798 ..Default::default()
1799 }));
1800 }
1801
1802 if !flags.intersects(ImageCreateFlags::MUTABLE_FORMAT) && view_formats.len() != 1 {
1803 return Err(Box::new(ValidationError {
1804 problem: "`flags` does not contain `ImageCreateFlags::MUTABLE_FORMAT`, but \
1805 `view_formats` contains more than one element"
1806 .into(),
1807 vuids: &["VUID-VkImageCreateInfo-flags-04738"],
1808 ..Default::default()
1809 }));
1810 }
1811
1812 for (index, &view_format) in view_formats.iter().enumerate() {
1813 view_format.validate_device(device).map_err(|err| {
1814 err.add_context(format!("view_formats[{}]", index))
1815 .set_vuids(&["VUID-VkImageFormatListCreateInfo-pViewFormats-parameter"])
1816 })?;
1817
1818 if flags.intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE)
1819 && view_format.compression().is_none()
1820 {
1821 if !(view_format.compatibility() == format.compatibility()
1822 || view_format.block_size() == format.block_size())
1823 {
1824 return Err(Box::new(ValidationError {
1825 problem: format!(
1826 "`flags` contains \
1827 `ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, and \
1828 `view_formats[{}]` is an uncompressed format, but \
1829 it is not compatible with `format`, and \
1830 does not have an equal block size",
1831 index
1832 )
1833 .into(),
1834 vuids: &["VUID-VkImageCreateInfo-pNext-06722"],
1835 ..Default::default()
1836 }));
1837 }
1838 } else {
1839 if view_format.compatibility() != format.compatibility() {
1840 return Err(Box::new(ValidationError {
1841 problem: format!(
1842 "`flags` does not contain \
1843 `ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, or \
1844 `view_format[{}]` is a compressed format, but \
1845 it is not compatible with `create_info.format`",
1846 index
1847 )
1848 .into(),
1849 vuids: &["VUID-VkImageCreateInfo-pNext-06722"],
1850 ..Default::default()
1851 }));
1852 }
1853 }
1854 }
1855 }
1856
1857 match image_type {
1858 ImageType::Dim1d => {
1859 if extent[1] != 1 {
1860 return Err(Box::new(ValidationError {
1861 problem: "`image_type` is `ImageType::Dim1d`, but `extent[1]` is not 1"
1862 .into(),
1863 vuids: &["VUID-VkImageCreateInfo-imageType-00956"],
1864 ..Default::default()
1865 }));
1866 }
1867
1868 if extent[2] != 1 {
1869 return Err(Box::new(ValidationError {
1870 problem: "`image_type` is `ImageType::Dim1d`, but `extent[2]` is not 1"
1871 .into(),
1872 vuids: &["VUID-VkImageCreateInfo-imageType-00956"],
1873 ..Default::default()
1874 }));
1875 }
1876
1877 if flags.intersects(ImageCreateFlags::SPARSE_RESIDENCY) {
1878 return Err(Box::new(ValidationError {
1879 problem: "`image_type` is `ImageType::Dim1d`, but `flags` contains \
1880 `ImageCreateFlags::SPARSE_RESIDENCY`"
1881 .into(),
1882 vuids: &["VUID-VkImageCreateInfo-imageType-00970"],
1883 ..Default::default()
1884 }));
1885 }
1886 }
1887 ImageType::Dim2d => {
1888 if extent[2] != 1 {
1889 return Err(Box::new(ValidationError {
1890 problem: "`image_type` is `ImageType::Dim2d`, but `extent[2]` is not 1"
1891 .into(),
1892 vuids: &["VUID-VkImageCreateInfo-imageType-00957"],
1893 ..Default::default()
1894 }));
1895 }
1896
1897 if flags.intersects(ImageCreateFlags::SPARSE_RESIDENCY)
1898 && !device.enabled_features().sparse_residency_image2_d
1899 {
1900 return Err(Box::new(ValidationError {
1901 problem: "`image_type` is `ImageType::Dim2d`, and `flags` contains \
1902 `ImageCreateFlags::SPARSE_RESIDENCY`"
1903 .into(),
1904 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
1905 Requires::DeviceFeature("sparse_residency_image2_d"),
1906 ])]),
1907 vuids: &["VUID-VkImageCreateInfo-imageType-00971"],
1908 ..Default::default()
1909 }));
1910 }
1911 }
1912 ImageType::Dim3d => {
1913 if array_layers != 1 {
1914 return Err(Box::new(ValidationError {
1915 problem: "`image_type` is `ImageType::Dim3d`, but `array_layers` is not 1"
1916 .into(),
1917 vuids: &["VUID-VkImageCreateInfo-imageType-00961"],
1918 ..Default::default()
1919 }));
1920 }
1921
1922 if flags.intersects(ImageCreateFlags::SPARSE_RESIDENCY)
1923 && !device.enabled_features().sparse_residency_image3_d
1924 {
1925 return Err(Box::new(ValidationError {
1926 problem: "`image_type` is `ImageType::Dim3d`, and `flags` contains \
1927 `ImageCreateFlags::SPARSE_RESIDENCY`"
1928 .into(),
1929 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
1930 Requires::DeviceFeature("sparse_residency_image3_d"),
1931 ])]),
1932 vuids: &["VUID-VkImageCreateInfo-imageType-00972"],
1933 ..Default::default()
1934 }));
1935 }
1936 }
1937 }
1938
1939 if extent[0] == 0 {
1940 return Err(Box::new(ValidationError {
1941 context: "extent[0]".into(),
1942 problem: "is zero".into(),
1943 vuids: &["VUID-VkImageCreateInfo-extent-00944"],
1944 ..Default::default()
1945 }));
1946 }
1947
1948 if extent[1] == 0 {
1949 return Err(Box::new(ValidationError {
1950 context: "extent[1]".into(),
1951 problem: "is zero".into(),
1952 vuids: &["VUID-VkImageCreateInfo-extent-00945"],
1953 ..Default::default()
1954 }));
1955 }
1956
1957 if extent[2] == 0 {
1958 return Err(Box::new(ValidationError {
1959 context: "extent[2]".into(),
1960 problem: "is zero".into(),
1961 vuids: &["VUID-VkImageCreateInfo-extent-00946"],
1962 ..Default::default()
1963 }));
1964 }
1965
1966 if array_layers == 0 {
1967 return Err(Box::new(ValidationError {
1968 context: "array_layers".into(),
1969 problem: "is zero".into(),
1970 vuids: &["VUID-VkImageCreateInfo-arrayLayers-00948"],
1971 ..Default::default()
1972 }));
1973 }
1974
1975 if mip_levels == 0 {
1976 return Err(Box::new(ValidationError {
1977 context: "mip_levels".into(),
1978 problem: "is zero".into(),
1979 vuids: &["VUID-VkImageCreateInfo-mipLevels-00947"],
1980 ..Default::default()
1981 }));
1982 }
1983
1984 let max_mip_levels = max_mip_levels(extent);
1985 debug_assert!(max_mip_levels >= 1);
1986
1987 if mip_levels > max_mip_levels {
1988 return Err(Box::new(ValidationError {
1989 problem: "`mip_levels` is greater than the maximum allowed number of mip levels \
1990 for `dimensions`"
1991 .into(),
1992 vuids: &["VUID-VkImageCreateInfo-mipLevels-00958"],
1993 ..Default::default()
1994 }));
1995 }
1996
1997 if samples != SampleCount::Sample1 {
1998 if image_type != ImageType::Dim2d {
1999 return Err(Box::new(ValidationError {
2000 problem: "`samples` is not `samples != SampleCount::Sample1`, but \
2001 `image_type` is not `ImageType::Dim2d`"
2002 .into(),
2003 vuids: &["VUID-VkImageCreateInfo-samples-02257"],
2004 ..Default::default()
2005 }));
2006 }
2007
2008 if flags.intersects(ImageCreateFlags::CUBE_COMPATIBLE) {
2009 return Err(Box::new(ValidationError {
2010 problem: "`samples` is not `samples != SampleCount::Sample1`, but \
2011 `flags` contains `ImageCreateFlags::CUBE_COMPATIBLE`"
2012 .into(),
2013 vuids: &["VUID-VkImageCreateInfo-samples-02257"],
2014 ..Default::default()
2015 }));
2016 }
2017
2018 if mip_levels != 1 {
2019 return Err(Box::new(ValidationError {
2020 problem: "`samples` is not `samples != SampleCount::Sample1`, but \
2021 `mip_levels` is not 1"
2022 .into(),
2023 vuids: &["VUID-VkImageCreateInfo-samples-02257"],
2024 ..Default::default()
2025 }));
2026 }
2027
2028 if image_create_maybe_linear {
2029 return Err(Box::new(ValidationError {
2030 problem: "`samples` is not `samples != SampleCount::Sample1`, but \
2031 the image may have linear tiling"
2032 .into(),
2033 vuids: &["VUID-VkImageCreateInfo-samples-02257"],
2034 ..Default::default()
2035 }));
2036 }
2037
2038 if device.enabled_extensions().khr_portability_subset
2039 && !device.enabled_features().multisample_array_image
2040 && array_layers != 1
2041 {
2042 return Err(Box::new(ValidationError {
2043 problem: "this device is a portability subset device, \
2044 `samples` is not `SampleCount::Sample1`, and \
2045 `array_layers` is greater than 1"
2046 .into(),
2047 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
2048 "multisample_array_image",
2049 )])]),
2050 vuids: &["VUID-VkImageCreateInfo-multisampleArrayImage-04460"],
2051 ..Default::default()
2052 }));
2053 }
2054 }
2055
2056 if let Some(chroma_sampling) = format.ycbcr_chroma_sampling() {
2058 if mip_levels != 1 {
2059 return Err(Box::new(ValidationError {
2060 problem: "`format` is a YCbCr format, but \
2061 `mip_levels` is not 1"
2062 .into(),
2063 vuids: &["VUID-VkImageCreateInfo-format-06410"],
2064 ..Default::default()
2065 }));
2066 }
2067
2068 if samples != SampleCount::Sample1 {
2069 return Err(Box::new(ValidationError {
2070 problem: "`format` is a YCbCr format, but \
2071 `samples` is not `SampleCount::Sample1`"
2072 .into(),
2073 vuids: &["VUID-VkImageCreateInfo-format-06411"],
2074 ..Default::default()
2075 }));
2076 }
2077
2078 if image_type != ImageType::Dim2d {
2079 return Err(Box::new(ValidationError {
2080 problem: "`format` is a YCbCr format, but \
2081 `image_type` is not `ImageType::Dim2d`"
2082 .into(),
2083 vuids: &["VUID-VkImageCreateInfo-format-06412"],
2084 ..Default::default()
2085 }));
2086 }
2087
2088 if array_layers > 1 && !device.enabled_features().ycbcr_image_arrays {
2089 return Err(Box::new(ValidationError {
2090 problem: "`format` is is a YCbCr format, and \
2091 `array_layers` is greater than 1"
2092 .into(),
2093 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
2094 "ycbcr_image_arrays",
2095 )])]),
2096 vuids: &["VUID-VkImageCreateInfo-format-06413"],
2097 ..Default::default()
2098 }));
2099 }
2100
2101 match chroma_sampling {
2102 ChromaSampling::Mode444 => (),
2103 ChromaSampling::Mode422 => {
2104 if extent[0] % 2 != 0 {
2105 return Err(Box::new(ValidationError {
2106 problem: "`format` is a YCbCr format with horizontal \
2107 chroma subsampling, but \
2108 `extent[0]` is not \
2109 a multiple of 2"
2110 .into(),
2111 vuids: &["VUID-VkImageCreateInfo-format-04712"],
2112 ..Default::default()
2113 }));
2114 }
2115 }
2116 ChromaSampling::Mode420 => {
2117 if !(extent[0] % 2 == 0 && extent[1] % 2 == 0) {
2118 return Err(Box::new(ValidationError {
2119 problem: "`format` is a YCbCr format with horizontal and vertical \
2120 chroma subsampling, but \
2121 `extent[0]` and `extent[1]` are not both \
2122 a multiple of 2"
2123 .into(),
2124 vuids: &[
2125 "VUID-VkImageCreateInfo-format-04712",
2126 "VUID-VkImageCreateInfo-format-04713",
2127 ],
2128 ..Default::default()
2129 }));
2130 }
2131 }
2132 }
2133 }
2134
2135 if usage.intersects(ImageUsage::STORAGE)
2138 && samples != SampleCount::Sample1
2139 && !device.enabled_features().shader_storage_image_multisample
2140 {
2141 return Err(Box::new(ValidationError {
2142 problem: "`usage` contains `ImageUsage::STORAGE`, but \
2143 `samples` is not `SampleCount::Sample1`"
2144 .into(),
2145 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
2146 "shader_storage_image_multisample",
2147 )])]),
2148 vuids: &["VUID-VkImageCreateInfo-usage-00968"],
2149 ..Default::default()
2150 }));
2151 }
2152
2153 if usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT) {
2154 if !usage.intersects(
2155 ImageUsage::COLOR_ATTACHMENT
2156 | ImageUsage::DEPTH_STENCIL_ATTACHMENT
2157 | ImageUsage::INPUT_ATTACHMENT,
2158 ) {
2159 return Err(Box::new(ValidationError {
2160 context: "usage".into(),
2161 problem: "contains `ImageUsage::TRANSIENT_ATTACHMENT`, but does not also \
2162 contain one of `ImageUsage::COLOR_ATTACHMENT`, \
2163 `ImageUsage::DEPTH_STENCIL_ATTACHMENT` or `ImageUsage::INPUT_ATTACHMENT`"
2164 .into(),
2165 vuids: &["VUID-VkImageCreateInfo-usage-00966"],
2166 ..Default::default()
2167 }));
2168 }
2169
2170 if !(usage
2171 - (ImageUsage::TRANSIENT_ATTACHMENT
2172 | ImageUsage::COLOR_ATTACHMENT
2173 | ImageUsage::DEPTH_STENCIL_ATTACHMENT
2174 | ImageUsage::INPUT_ATTACHMENT))
2175 .is_empty()
2176 {
2177 return Err(Box::new(ValidationError {
2178 context: "usage".into(),
2179 problem: "contains `ImageUsage::TRANSIENT_ATTACHMENT`, but also contains \
2180 usages other than `ImageUsage::COLOR_ATTACHMENT`, \
2181 `ImageUsage::DEPTH_STENCIL_ATTACHMENT` or `ImageUsage::INPUT_ATTACHMENT`"
2182 .into(),
2183 vuids: &["VUID-VkImageCreateInfo-usage-00963"],
2184 ..Default::default()
2185 }));
2186 }
2187 }
2188
2189 if usage.intersects(
2190 ImageUsage::COLOR_ATTACHMENT
2191 | ImageUsage::DEPTH_STENCIL_ATTACHMENT
2192 | ImageUsage::INPUT_ATTACHMENT
2193 | ImageUsage::TRANSIENT_ATTACHMENT,
2194 ) {
2195 if extent[0] > device_properties.max_framebuffer_width {
2196 return Err(Box::new(ValidationError {
2197 problem: "`usage` contains \
2198 `ImageUsage::COLOR_ATTACHMENT`, \
2199 `ImageUsage::DEPTH_STENCIL_ATTACHMENT`, \
2200 `ImageUsage::INPUT_ATTACHMENT`, or \
2201 `ImageUsage::TRANSIENT_ATTACHMENT`, but \
2202 `extent[0]` exceeds the `max_framebuffer_width` limit"
2203 .into(),
2204 vuids: &[
2205 "VUID-VkImageCreateInfo-usage-00964",
2206 "VUID-VkImageCreateInfo-Format-02536",
2207 ],
2208 ..Default::default()
2209 }));
2210 }
2211
2212 if extent[1] > device_properties.max_framebuffer_height {
2213 return Err(Box::new(ValidationError {
2214 problem: "`usage` contains \
2215 `ImageUsage::COLOR_ATTACHMENT`, \
2216 `ImageUsage::DEPTH_STENCIL_ATTACHMENT`, \
2217 `ImageUsage::INPUT_ATTACHMENT`, or \
2218 `ImageUsage::TRANSIENT_ATTACHMENT`, but \
2219 `extent[1]` exceeds the `max_framebuffer_height` limit"
2220 .into(),
2221 vuids: &["VUID-VkImageCreateInfo-usage-00965"],
2222 ..Default::default()
2223 }));
2224 }
2225 }
2226
2227 if let Some(stencil_usage) = stencil_usage {
2228 if !(device.api_version() >= Version::V1_2
2229 || device.enabled_extensions().ext_separate_stencil_usage)
2230 {
2231 return Err(Box::new(ValidationError {
2232 context: "stencil_usage".into(),
2233 problem: "is `Some`".into(),
2234 requires_one_of: RequiresOneOf(&[
2235 RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]),
2236 RequiresAllOf(&[Requires::DeviceExtension("ext_separate_stencil_usage")]),
2237 ]),
2238 ..Default::default()
2239 }));
2240 }
2241
2242 stencil_usage.validate_device(device).map_err(|err| {
2243 err.add_context("stencil_usage")
2244 .set_vuids(&["VUID-VkImageStencilUsageCreateInfo-stencilUsage-parameter"])
2245 })?;
2246
2247 if stencil_usage.is_empty() {
2248 return Err(Box::new(ValidationError {
2249 context: "stencil_usage".into(),
2250 problem: "is empty".into(),
2251 vuids: &["VUID-VkImageStencilUsageCreateInfo-usage-requiredbitmask"],
2252 ..Default::default()
2253 }));
2254 }
2255
2256 if stencil_usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT)
2257 && !(stencil_usage
2258 - (ImageUsage::TRANSIENT_ATTACHMENT
2259 | ImageUsage::DEPTH_STENCIL_ATTACHMENT
2260 | ImageUsage::INPUT_ATTACHMENT))
2261 .is_empty()
2262 {
2263 return Err(Box::new(ValidationError {
2264 context: "stencil_usage".into(),
2265 problem: "contains `ImageUsage::TRANSIENT_ATTACHMENT`, but also contains \
2266 usages other than `ImageUsage::DEPTH_STENCIL_ATTACHMENT` or \
2267 `ImageUsage::INPUT_ATTACHMENT`"
2268 .into(),
2269 vuids: &["VUID-VkImageStencilUsageCreateInfo-stencilUsage-02539"],
2270 ..Default::default()
2271 }));
2272 }
2273
2274 if format
2275 .aspects()
2276 .intersects(ImageAspects::DEPTH | ImageAspects::STENCIL)
2277 {
2278 if usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
2279 && !stencil_usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
2280 {
2281 return Err(Box::new(ValidationError {
2282 problem: "`format` is a depth/stencil format, and \
2283 `usage` contains `ImageUsage::DEPTH_STENCIL_ATTACHMENT`, but \
2284 `stencil_usage` does not also contain \
2285 `ImageUsage::DEPTH_STENCIL_ATTACHMENT`"
2286 .into(),
2287 vuids: &["VUID-VkImageCreateInfo-format-02795"],
2288 ..Default::default()
2289 }));
2290 }
2291
2292 if !usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
2293 && stencil_usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
2294 {
2295 return Err(Box::new(ValidationError {
2296 problem: "`format` is a depth/stencil format, and \
2297 `usage` does not contain `ImageUsage::DEPTH_STENCIL_ATTACHMENT`, but \
2298 `stencil_usage` does contain `ImageUsage::DEPTH_STENCIL_ATTACHMENT`"
2299 .into(),
2300 vuids: &["VUID-VkImageCreateInfo-format-02796"],
2301 ..Default::default()
2302 }));
2303 }
2304
2305 if usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT)
2306 && !stencil_usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT)
2307 {
2308 return Err(Box::new(ValidationError {
2309 problem: "`format` is a depth/stencil format, and \
2310 `usage` contains `ImageUsage::TRANSIENT_ATTACHMENT`, but \
2311 `stencil_usage` does not also contain \
2312 `ImageUsage::TRANSIENT_ATTACHMENT`"
2313 .into(),
2314 vuids: &["VUID-VkImageCreateInfo-format-02797"],
2315 ..Default::default()
2316 }));
2317 }
2318
2319 if !usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT)
2320 && stencil_usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT)
2321 {
2322 return Err(Box::new(ValidationError {
2323 problem: "`format` is a depth/stencil format, and \
2324 `usage` does not contain `ImageUsage::TRANSIENT_ATTACHMENT`, but \
2325 `stencil_usage` does contain \
2326 `ImageUsage::TRANSIENT_ATTACHMENT`"
2327 .into(),
2328 vuids: &["VUID-VkImageCreateInfo-format-02798"],
2329 ..Default::default()
2330 }));
2331 }
2332
2333 if stencil_usage.intersects(ImageUsage::INPUT_ATTACHMENT) {
2334 if extent[0] > device_properties.max_framebuffer_width {
2335 return Err(Box::new(ValidationError {
2336 problem: "`stencil_usage` contains \
2337 `ImageUsage::INPUT_ATTACHMENT`, but \
2338 `extent[0]` exceeds the `max_framebuffer_width` limit"
2339 .into(),
2340 vuids: &["VUID-VkImageCreateInfo-Format-02536"],
2341 ..Default::default()
2342 }));
2343 }
2344
2345 if extent[1] > device_properties.max_framebuffer_height {
2346 return Err(Box::new(ValidationError {
2347 problem: "`stencil_usage` contains \
2348 `ImageUsage::INPUT_ATTACHMENT`, but \
2349 `extent[1]` exceeds the `max_framebuffer_height` limit"
2350 .into(),
2351 vuids: &["VUID-VkImageCreateInfo-format-02537"],
2352 ..Default::default()
2353 }));
2354 }
2355 }
2356
2357 if stencil_usage.intersects(ImageUsage::STORAGE)
2358 && samples != SampleCount::Sample1
2359 && !device.enabled_features().shader_storage_image_multisample
2360 {
2361 return Err(Box::new(ValidationError {
2362 problem: "`stencil_usage` contains `ImageUsage::STORAGE`, but \
2363 `samples` is not `SampleCount::Sample1`"
2364 .into(),
2365 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
2366 Requires::DeviceFeature("shader_storage_image_multisample"),
2367 ])]),
2368 vuids: &["VUID-VkImageCreateInfo-format-02538"],
2369 ..Default::default()
2370 }));
2371 }
2372 }
2373 }
2374
2375 if flags.intersects(ImageCreateFlags::SPARSE_BINDING) {
2378 if !device.enabled_features().sparse_binding {
2379 return Err(Box::new(ValidationError {
2380 context: "flags".into(),
2381 problem: "contains `ImageCreateFlags::SPARSE_BINDING`".into(),
2382 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
2383 "sparse_binding",
2384 )])]),
2385 vuids: &["VUID-VkImageCreateInfo-flags-00969"],
2386 }));
2387 }
2388
2389 if usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT) {
2390 return Err(Box::new(ValidationError {
2391 problem: "`flags` contains `ImageCreateFlags::SPARSE_BINDING`, but \
2392 `usage` contains `ImageUsage::TRANSIENT_ATTACHMENT`"
2393 .into(),
2394 vuids: &["VUID-VkImageCreateInfo-None-01925"],
2395 ..Default::default()
2396 }));
2397 }
2398 }
2399
2400 if flags.intersects(ImageCreateFlags::SPARSE_RESIDENCY) {
2401 if !flags.intersects(ImageCreateFlags::SPARSE_BINDING) {
2402 return Err(Box::new(ValidationError {
2403 context: "flags".into(),
2404 problem: "contains `ImageCreateFlags::SPARSE_RESIDENCY`, but does not also \
2405 contain `ImageCreateFlags::SPARSE_BINDING`"
2406 .into(),
2407 vuids: &["VUID-VkImageCreateInfo-flags-00987"],
2408 ..Default::default()
2409 }));
2410 }
2411
2412 if tiling == ImageTiling::Linear {
2413 return Err(Box::new(ValidationError {
2414 context: "flags".into(),
2415 problem: "contains `ImageCreateFlags::SPARSE_RESIDENCY`, but `tiling` is \
2416 `ImageTiling::Linear`"
2417 .into(),
2418 vuids: &["VUID-VkImageCreateInfo-tiling-04121"],
2419 ..Default::default()
2420 }));
2421 }
2422
2423 match samples {
2424 SampleCount::Sample2 => {
2425 if !device.enabled_features().sparse_residency2_samples {
2426 return Err(Box::new(ValidationError {
2427 problem: "`flags` contains `ImageCreateFlags::SPARSE_RESIDENCY`, and \
2428 `samples` is `SampleCount::Sample2`"
2429 .into(),
2430 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
2431 Requires::DeviceFeature("sparse_residency2_samples"),
2432 ])]),
2433 vuids: &["VUID-VkImageCreateInfo-imageType-00973"],
2434 ..Default::default()
2435 }));
2436 }
2437 }
2438 SampleCount::Sample4 => {
2439 if !device.enabled_features().sparse_residency4_samples {
2440 return Err(Box::new(ValidationError {
2441 problem: "`flags` contains `ImageCreateFlags::SPARSE_RESIDENCY`, and \
2442 `samples` is `SampleCount::Sample4`"
2443 .into(),
2444 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
2445 Requires::DeviceFeature("sparse_residency4_samples"),
2446 ])]),
2447 vuids: &["VUID-VkImageCreateInfo-imageType-00974"],
2448 ..Default::default()
2449 }));
2450 }
2451 }
2452 SampleCount::Sample8 => {
2453 if !device.enabled_features().sparse_residency8_samples {
2454 return Err(Box::new(ValidationError {
2455 problem: "`flags` contains `ImageCreateFlags::SPARSE_RESIDENCY`, and \
2456 `samples` is `SampleCount::Sample8`"
2457 .into(),
2458 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
2459 Requires::DeviceFeature("sparse_residency8_samples"),
2460 ])]),
2461 vuids: &["VUID-VkImageCreateInfo-imageType-00975"],
2462 ..Default::default()
2463 }));
2464 }
2465 }
2466 SampleCount::Sample16 => {
2467 if !device.enabled_features().sparse_residency16_samples {
2468 return Err(Box::new(ValidationError {
2469 problem: "`flags` contains `ImageCreateFlags::SPARSE_RESIDENCY`, and \
2470 `samples` is `SampleCount::Sample16`"
2471 .into(),
2472 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
2473 Requires::DeviceFeature("sparse_residency16_samples"),
2474 ])]),
2475 vuids: &["VUID-VkImageCreateInfo-imageType-00976"],
2476 ..Default::default()
2477 }));
2478 }
2479 }
2480 SampleCount::Sample1 | SampleCount::Sample32 | SampleCount::Sample64 => (),
2481 }
2482 }
2483
2484 if flags.intersects(ImageCreateFlags::CUBE_COMPATIBLE) {
2485 if image_type != ImageType::Dim2d {
2486 return Err(Box::new(ValidationError {
2487 problem: "`flags` contains `ImageCreateFlags::CUBE_COMPATIBLE`, but \
2488 `image_type` is not `ImageType::Dim2d`"
2489 .into(),
2490 vuids: &["VUID-VkImageCreateInfo-flags-00949"],
2491 ..Default::default()
2492 }));
2493 }
2494
2495 if extent[0] != extent[1] {
2496 return Err(Box::new(ValidationError {
2497 problem: "`flags` contains `ImageCreateFlags::CUBE_COMPATIBLE`, but \
2498 `extent[0]` does not equal `extent[1]`"
2499 .into(),
2500 vuids: &["VUID-VkImageCreateInfo-imageType-00954"],
2501 ..Default::default()
2502 }));
2503 }
2504
2505 if array_layers < 6 {
2506 return Err(Box::new(ValidationError {
2507 problem: "`flags` contains `ImageCreateFlags::CUBE_COMPATIBLE`, but \
2508 `array_layers` is less than 6"
2509 .into(),
2510 vuids: &["VUID-VkImageCreateInfo-imageType-00954"],
2511 ..Default::default()
2512 }));
2513 }
2514 }
2515
2516 if flags.intersects(ImageCreateFlags::DIM2D_ARRAY_COMPATIBLE) {
2517 if flags.intersects(ImageCreateFlags::SPARSE_BINDING) {
2518 return Err(Box::new(ValidationError {
2519 context: "flags".into(),
2520 problem: "contains `ImageCreateFlags::DIM2D_ARRAY_COMPATIBLE`, but \
2521 also contains `ImageCreateFlags::SPARSE_BINDING`"
2522 .into(),
2523 vuids: &["VUID-VkImageCreateInfo-flags-09403"],
2524 ..Default::default()
2525 }));
2526 }
2527
2528 if image_type != ImageType::Dim3d {
2529 return Err(Box::new(ValidationError {
2530 problem: "`flags` contains `ImageCreateFlags::DIM2D_ARRAY_COMPATIBLE`, but \
2531 `image_type` is not `ImageType::Dim3d`"
2532 .into(),
2533 vuids: &["VUID-VkImageCreateInfo-flags-00950"],
2534 ..Default::default()
2535 }));
2536 }
2537
2538 if device.enabled_extensions().khr_portability_subset
2539 && !device.enabled_features().image_view2_d_on3_d_image
2540 {
2541 return Err(Box::new(ValidationError {
2542 problem: "this device is a portability subset device, and \
2543 `flags` contains `ImageCreateFlags::DIM2D_ARRAY_COMPATIBLE`"
2544 .into(),
2545 requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
2546 "image_view2_d_on3_d_image",
2547 )])]),
2548 vuids: &["VUID-VkImageCreateInfo-imageView2DOn3DImage-04459"],
2549 ..Default::default()
2550 }));
2551 }
2552 }
2553
2554 if flags.intersects(ImageCreateFlags::DIM2D_VIEW_COMPATIBLE) {
2555 if image_type != ImageType::Dim3d {
2556 return Err(Box::new(ValidationError {
2557 problem: "`flags` contains `ImageCreateFlags::DIM2D_VIEW_COMPATIBLE`, but \
2558 `image_type` is not `ImageType::Dim3d`"
2559 .into(),
2560 vuids: &["VUID-VkImageCreateInfo-flags-07755"],
2561 ..Default::default()
2562 }));
2563 }
2564 }
2565
2566 if flags.intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE)
2567 && format.compression().is_none()
2568 {
2569 return Err(Box::new(ValidationError {
2570 problem: "`flags` contains `ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, \
2571 but `format` is not a compressed format"
2572 .into(),
2573 vuids: &["VUID-VkImageCreateInfo-flags-01572"],
2574 ..Default::default()
2575 }));
2576 }
2577
2578 if flags.intersects(ImageCreateFlags::DISJOINT) {
2579 if format.planes().len() < 2 {
2580 return Err(Box::new(ValidationError {
2581 problem: "`flags` contains `ImageCreateFlags::DISJOINT`, but `format` \
2582 is not a multi-planar format"
2583 .into(),
2584 vuids: &["VUID-VkImageCreateInfo-format-01577"],
2585 ..Default::default()
2586 }));
2587 }
2588
2589 if !image_create_format_features.intersects(FormatFeatures::DISJOINT) {
2590 return Err(Box::new(ValidationError {
2591 problem: "`flags` contains `ImageCreateFlags::DISJOINT`, but the \
2592 format features of `format` do not include \
2593 `FormatFeatures::DISJOINT`"
2594 .into(),
2595 vuids: &["VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260"],
2596 ..Default::default()
2597 }));
2598 }
2599 }
2600
2601 match sharing {
2604 Sharing::Exclusive => (),
2605 Sharing::Concurrent(queue_family_indices) => {
2606 if queue_family_indices.len() < 2 {
2607 return Err(Box::new(ValidationError {
2608 context: "sharing".into(),
2609 problem: "is `Sharing::Concurrent`, but contains less than 2 elements"
2610 .into(),
2611 vuids: &["VUID-VkImageCreateInfo-sharingMode-00942"],
2612 ..Default::default()
2613 }));
2614 }
2615
2616 let queue_family_count = physical_device.queue_family_properties().len() as u32;
2617
2618 for (index, &queue_family_index) in queue_family_indices.iter().enumerate() {
2619 if queue_family_indices[..index].contains(&queue_family_index) {
2620 return Err(Box::new(ValidationError {
2621 context: "queue_family_indices".into(),
2622 problem: format!(
2623 "the queue family index in the list at index {} is contained in \
2624 the list more than once",
2625 index,
2626 )
2627 .into(),
2628 vuids: &["VUID-VkImageCreateInfo-sharingMode-01420"],
2629 ..Default::default()
2630 }));
2631 }
2632
2633 if queue_family_index >= queue_family_count {
2634 return Err(Box::new(ValidationError {
2635 context: format!("sharing[{}]", index).into(),
2636 problem: "is not less than the number of queue families in the device"
2637 .into(),
2638 vuids: &["VUID-VkImageCreateInfo-sharingMode-01420"],
2639 ..Default::default()
2640 }));
2641 }
2642 }
2643 }
2644 }
2645
2646 if !(drm_format_modifier_plane_layouts.is_empty() || drm_format_modifiers.len() == 1) {
2647 return Err(Box::new(ValidationError {
2648 problem: "`drm_format_modifier_plane_layouts` is not empty, but \
2649 `drm_format_modifiers` does not contain exactly one element"
2650 .into(),
2651 ..Default::default()
2652 }));
2653 }
2654
2655 match (tiling, !drm_format_modifiers.is_empty()) {
2656 (ImageTiling::DrmFormatModifier, true) => {
2657 if flags.intersects(ImageCreateFlags::MUTABLE_FORMAT) && view_formats.is_empty() {
2658 return Err(Box::new(ValidationError {
2659 problem: "`tiling` is `ImageTiling::DrmFormatModifier`, and \
2660 `flags` contains `ImageCreateFlags::MUTABLE_FORMAT`, but \
2661 `view_formats` is empty"
2662 .into(),
2663 vuids: &["VUID-VkImageCreateInfo-tiling-02353"],
2664 ..Default::default()
2665 }));
2666 }
2667
2668 if !drm_format_modifier_plane_layouts.is_empty() {
2669 let drm_format_modifier = drm_format_modifiers[0];
2670 let drm_format_modifier_properties = format_properties
2671 .drm_format_modifier_properties
2672 .iter()
2673 .find(|properties| properties.drm_format_modifier == drm_format_modifier)
2674 .ok_or_else(|| Box::new(ValidationError {
2675 problem: "`drm_format_modifier_plane_layouts` is not empty, but \
2676 `drm_format_modifiers[0]` is not one of the modifiers in \
2677 `FormatProperties::drm_format_properties`, as returned by \
2678 `PhysicalDevice::format_properties` for `format`".into(),
2679 vuids: &["VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-drmFormatModifierPlaneCount-02265"],
2680 ..Default::default()
2681 }))?;
2682
2683 if drm_format_modifier_plane_layouts.len()
2684 != drm_format_modifier_properties.drm_format_modifier_plane_count as usize
2685 {
2686 return Err(Box::new(ValidationError {
2687 problem: "`drm_format_modifier_plane_layouts` is not empty, but the \
2688 number of provided subresource layouts does not equal the number \
2689 of memory planes for `drm_format_modifiers[0]`, specified in \
2690 `DrmFormatModifierProperties::drm_format_modifier_plane_count`, \
2691 as returned by `PhysicalDevice::format_properties` for `format`"
2692 .into(),
2693 vuids: &["VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-drmFormatModifierPlaneCount-02265"],
2694 ..Default::default()
2695 }));
2696 }
2697
2698 for (index, subresource_layout) in
2699 drm_format_modifier_plane_layouts.iter().enumerate()
2700 {
2701 let &SubresourceLayout {
2702 offset: _,
2703 size,
2704 row_pitch: _,
2705 array_pitch,
2706 depth_pitch,
2707 } = subresource_layout;
2708
2709 if size != 0 {
2710 return Err(Box::new(ValidationError {
2711 context: format!(
2712 "drm_format_modifier_plane_layouts[{}].size",
2713 index
2714 )
2715 .into(),
2716 problem: "is not zero".into(),
2717 vuids: &[
2718 "VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-size-02267",
2719 ],
2720 ..Default::default()
2721 }));
2722 }
2723
2724 if array_layers == 1 && array_pitch.is_some() {
2725 return Err(Box::new(ValidationError {
2726 problem: format!(
2727 "`array_layers` is 1, but \
2728 `drm_format_modifier_plane_layouts[{}].array_pitch` is `Some`",
2729 index
2730 )
2731 .into(),
2732 vuids: &["VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-arrayPitch-02268"],
2733 ..Default::default()
2734 }));
2735 }
2736
2737 if extent[2] == 1 && depth_pitch.is_some() {
2738 return Err(Box::new(ValidationError {
2739 problem: format!(
2740 "`extent[2]` is 1, but \
2741 `drm_format_modifier_plane_layouts[{}].depth_pitch` is `Some`",
2742 index
2743 )
2744 .into(),
2745 vuids: &["VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-depthPitch-02269"],
2746 ..Default::default()
2747 }));
2748 }
2749 }
2750 }
2751 }
2752 (ImageTiling::DrmFormatModifier, false) => {
2753 return Err(Box::new(ValidationError {
2754 problem: "`tiling` is `ImageTiling::DrmFormatModifier`, but \
2755 `drm_format_modifiers` is empty"
2756 .into(),
2757 vuids: &["VUID-VkImageCreateInfo-tiling-02261"],
2758 ..Default::default()
2759 }));
2760 }
2761 (_, true) => {
2762 if tiling != ImageTiling::DrmFormatModifier {
2763 return Err(Box::new(ValidationError {
2764 problem: "`drm_format_modifiers` is not empty, but \
2765 `tiling` is not `ImageTiling::DrmFormatModifier`"
2766 .into(),
2767 vuids: &["VUID-VkImageCreateInfo-pNext-02262"],
2768 ..Default::default()
2769 }));
2770 }
2771 }
2772 (_, false) => (),
2773 }
2774
2775 if !external_memory_handle_types.is_empty() {
2776 if !(device.api_version() >= Version::V1_1
2777 || device.enabled_extensions().khr_external_memory)
2778 {
2779 return Err(Box::new(ValidationError {
2780 context: "external_memory_handle_types".into(),
2781 problem: "is not empty".into(),
2782 requires_one_of: RequiresOneOf(&[
2783 RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]),
2784 RequiresAllOf(&[Requires::DeviceExtension("khr_external_memory")]),
2785 ]),
2786 ..Default::default()
2787 }));
2788 }
2789
2790 external_memory_handle_types
2791 .validate_device(device)
2792 .map_err(|err| {
2793 err.add_context("external_memory_handle_types")
2794 .set_vuids(&["VUID-VkExternalMemoryImageCreateInfo-handleTypes-parameter"])
2795 })?;
2796
2797 if initial_layout != ImageLayout::Undefined {
2798 return Err(Box::new(ValidationError {
2799 problem: "`external_memory_handle_types` is not empty, but \
2800 `initial_layout` is not `ImageLayout::Undefined`"
2801 .into(),
2802 vuids: &["VUID-VkImageCreateInfo-pNext-01443"],
2803 ..Default::default()
2804 }));
2805 }
2806 }
2807
2808 fn iter_or_none<T>(iter: impl IntoIterator<Item = T>) -> impl Iterator<Item = Option<T>> {
2816 let mut iter = iter.into_iter();
2817 [iter.next()].into_iter().chain(iter.map(Some))
2818 }
2819
2820 for drm_format_modifier in iter_or_none(drm_format_modifiers.iter().copied()) {
2821 for external_memory_handle_type in iter_or_none(external_memory_handle_types) {
2822 let image_format_properties = unsafe {
2823 physical_device.image_format_properties_unchecked(ImageFormatInfo {
2824 flags,
2825 format,
2826 image_type,
2827 tiling,
2828 usage,
2829 stencil_usage,
2830 external_memory_handle_type,
2831 drm_format_modifier_info: drm_format_modifier.map(|drm_format_modifier| {
2832 ImageDrmFormatModifierInfo {
2833 drm_format_modifier,
2834 sharing: sharing.clone(),
2835 ..Default::default()
2836 }
2837 }),
2838 ..Default::default()
2839 })
2840 }
2841 .map_err(|_err| {
2842 Box::new(ValidationError {
2843 problem: "`PhysicalDevice::image_format_properties` \
2844 returned an error"
2845 .into(),
2846 ..Default::default()
2847 })
2848 })?;
2849
2850 let image_format_properties = image_format_properties.ok_or_else(|| Box::new(ValidationError {
2851 problem: "the combination of parameters of this image is not \
2852 supported by the physical device, as returned by \
2853 `PhysicalDevice::image_format_properties`"
2854 .into(),
2855 vuids: &[
2856 "VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-drmFormatModifier-02264",
2857 "VUID-VkImageDrmFormatModifierListCreateInfoEXT-pDrmFormatModifiers-02263",
2858 ],
2859 ..Default::default()
2860 }))?;
2861
2862 let ImageFormatProperties {
2863 max_extent,
2864 max_mip_levels,
2865 max_array_layers,
2866 sample_counts,
2867 max_resource_size: _,
2868 external_memory_properties,
2869 filter_cubic: _,
2870 filter_cubic_minmax: _,
2871 } = image_format_properties;
2872
2873 if extent[0] > max_extent[0] {
2874 return Err(Box::new(ValidationError {
2875 problem: "`extent[0]` exceeds `max_extent[0]` for \
2876 the combination of parameters of this image, as returned by \
2877 `PhysicalDevice::image_format_properties`"
2878 .into(),
2879 vuids: &["VUID-VkImageCreateInfo-extent-02252"],
2880 ..Default::default()
2881 }));
2882 }
2883
2884 if extent[1] > max_extent[1] {
2885 return Err(Box::new(ValidationError {
2886 problem: "`extent[1]` exceeds `max_extent[1]` for \
2887 the combination of parameters of this image, as returned by \
2888 `PhysicalDevice::image_format_properties`"
2889 .into(),
2890 vuids: &["VUID-VkImageCreateInfo-extent-02253"],
2891 ..Default::default()
2892 }));
2893 }
2894
2895 if extent[2] > max_extent[2] {
2896 return Err(Box::new(ValidationError {
2897 problem: "`extent[2]` exceeds `max_extent[2]` for \
2898 the combination of parameters of this image, as returned by \
2899 `PhysicalDevice::image_format_properties`"
2900 .into(),
2901 vuids: &["VUID-VkImageCreateInfo-extent-02254"],
2902 ..Default::default()
2903 }));
2904 }
2905
2906 if mip_levels > max_mip_levels {
2907 return Err(Box::new(ValidationError {
2908 problem: "`mip_levels` exceeds `max_mip_levels` for \
2909 the combination of parameters of this image, as returned by \
2910 `PhysicalDevice::image_format_properties`"
2911 .into(),
2912 vuids: &["VUID-VkImageCreateInfo-mipLevels-02255"],
2913 ..Default::default()
2914 }));
2915 }
2916
2917 if array_layers > max_array_layers {
2918 return Err(Box::new(ValidationError {
2919 problem: "`array_layers` exceeds `max_array_layers` for \
2920 the combination of parameters of this image, as returned by \
2921 `PhysicalDevice::image_format_properties`"
2922 .into(),
2923 vuids: &["VUID-VkImageCreateInfo-arrayLayers-02256"],
2924 ..Default::default()
2925 }));
2926 }
2927
2928 if !sample_counts.contains_enum(samples) {
2929 return Err(Box::new(ValidationError {
2930 problem: "`samples` is not present in the `sample_counts` value for \
2931 the combination of parameters of this image, as returned by \
2932 `PhysicalDevice::image_format_properties`"
2933 .into(),
2934 vuids: &["VUID-VkImageCreateInfo-samples-02258"],
2935 ..Default::default()
2936 }));
2937 }
2938
2939 if !external_memory_properties
2940 .compatible_handle_types
2941 .contains(external_memory_handle_types)
2942 {
2943 return Err(Box::new(ValidationError {
2944 problem: "`external_memory_handle_types` is not a subset of the \
2945 `external_memory_properties.compatible_handle_types` value for \
2946 the combination of parameters of this image, as returned by \
2947 `PhysicalDevice::image_format_properties`"
2948 .into(),
2949 vuids: &["VUID-VkImageCreateInfo-pNext-00990"],
2950 ..Default::default()
2951 }));
2952 }
2953 }
2954 }
2955
2956 Ok(())
2957 }
2958
2959 pub(crate) fn to_vk<'a>(
2960 &'a self,
2961 extensions_vk: &'a mut ImageCreateInfoExtensionsVk<'_>,
2962 ) -> ash::vk::ImageCreateInfo<'a> {
2963 let &Self {
2964 flags,
2965 image_type,
2966 format,
2967 view_formats: _,
2968 extent,
2969 array_layers,
2970 mip_levels,
2971 samples,
2972 tiling,
2973 usage,
2974 stencil_usage: _,
2975 ref sharing,
2976 initial_layout,
2977 drm_format_modifiers: _,
2978 drm_format_modifier_plane_layouts: _,
2979 external_memory_handle_types: _,
2980 _ne: _,
2981 } = self;
2982
2983 let (sharing_mode, queue_family_indices_vk) = match sharing {
2984 Sharing::Exclusive => (ash::vk::SharingMode::EXCLUSIVE, [].as_slice()),
2985 Sharing::Concurrent(queue_family_indices) => (
2986 ash::vk::SharingMode::CONCURRENT,
2987 queue_family_indices.as_slice(),
2988 ),
2989 };
2990
2991 let mut val_vk = ash::vk::ImageCreateInfo::default()
2992 .flags(flags.into())
2993 .image_type(image_type.into())
2994 .format(format.into())
2995 .extent(ash::vk::Extent3D {
2996 width: extent[0],
2997 height: extent[1],
2998 depth: extent[2],
2999 })
3000 .mip_levels(mip_levels)
3001 .array_layers(array_layers)
3002 .samples(samples.into())
3003 .tiling(tiling.into())
3004 .usage(usage.into())
3005 .sharing_mode(sharing_mode)
3006 .queue_family_indices(queue_family_indices_vk)
3007 .initial_layout(initial_layout.into());
3008
3009 let ImageCreateInfoExtensionsVk {
3010 drm_format_modifier_explicit_vk,
3011 drm_format_modifier_list_vk,
3012 external_memory_vk,
3013 format_list_vk,
3014 stencil_usage_vk,
3015 } = extensions_vk;
3016
3017 if let Some(next) = drm_format_modifier_explicit_vk {
3018 val_vk = val_vk.push_next(next);
3019 }
3020
3021 if let Some(next) = drm_format_modifier_list_vk {
3022 val_vk = val_vk.push_next(next);
3023 }
3024
3025 if let Some(next) = external_memory_vk {
3026 val_vk = val_vk.push_next(next);
3027 }
3028
3029 if let Some(next) = format_list_vk {
3030 val_vk = val_vk.push_next(next);
3031 }
3032
3033 if let Some(next) = stencil_usage_vk {
3034 val_vk = val_vk.push_next(next);
3035 }
3036
3037 val_vk
3038 }
3039
3040 pub(crate) fn to_vk_extensions<'a>(
3041 &'a self,
3042 fields1_vk: &'a ImageCreateInfoFields1Vk,
3043 ) -> ImageCreateInfoExtensionsVk<'a> {
3044 let ImageCreateInfoFields1Vk {
3045 plane_layouts_vk,
3046 view_formats_vk,
3047 } = fields1_vk;
3048
3049 let drm_format_modifier_explicit_vk = (!plane_layouts_vk.is_empty()).then(|| {
3050 ash::vk::ImageDrmFormatModifierExplicitCreateInfoEXT::default()
3051 .drm_format_modifier(self.drm_format_modifiers[0])
3052 .plane_layouts(plane_layouts_vk)
3053 });
3054
3055 let drm_format_modifier_list_vk = (!self.drm_format_modifier_plane_layouts.is_empty())
3056 .then(|| {
3057 ash::vk::ImageDrmFormatModifierListCreateInfoEXT::default()
3058 .drm_format_modifiers(&self.drm_format_modifiers)
3059 });
3060
3061 let external_memory_vk = (!self.external_memory_handle_types.is_empty()).then(|| {
3062 ash::vk::ExternalMemoryImageCreateInfo::default()
3063 .handle_types(self.external_memory_handle_types.into())
3064 });
3065
3066 let format_list_vk = (!view_formats_vk.is_empty())
3067 .then(|| ash::vk::ImageFormatListCreateInfo::default().view_formats(view_formats_vk));
3068
3069 let stencil_usage_vk = self.stencil_usage.map(|stencil_usage| {
3070 ash::vk::ImageStencilUsageCreateInfo::default().stencil_usage(stencil_usage.into())
3071 });
3072
3073 ImageCreateInfoExtensionsVk {
3074 drm_format_modifier_explicit_vk,
3075 drm_format_modifier_list_vk,
3076 external_memory_vk,
3077 format_list_vk,
3078 stencil_usage_vk,
3079 }
3080 }
3081
3082 pub(crate) fn to_vk_fields1(&self) -> ImageCreateInfoFields1Vk {
3083 let plane_layouts_vk = self
3084 .drm_format_modifier_plane_layouts
3085 .iter()
3086 .map(SubresourceLayout::to_vk)
3087 .collect();
3088
3089 let view_formats_vk = self
3090 .view_formats
3091 .iter()
3092 .copied()
3093 .map(ash::vk::Format::from)
3094 .collect();
3095
3096 ImageCreateInfoFields1Vk {
3097 plane_layouts_vk,
3098 view_formats_vk,
3099 }
3100 }
3101}
3102
3103pub(crate) struct ImageCreateInfoExtensionsVk<'a> {
3104 pub(crate) drm_format_modifier_explicit_vk:
3105 Option<ash::vk::ImageDrmFormatModifierExplicitCreateInfoEXT<'a>>,
3106 pub(crate) drm_format_modifier_list_vk:
3107 Option<ash::vk::ImageDrmFormatModifierListCreateInfoEXT<'a>>,
3108 pub(crate) external_memory_vk: Option<ash::vk::ExternalMemoryImageCreateInfo<'static>>,
3109 pub(crate) format_list_vk: Option<ash::vk::ImageFormatListCreateInfo<'a>>,
3110 pub(crate) stencil_usage_vk: Option<ash::vk::ImageStencilUsageCreateInfo<'static>>,
3111}
3112
3113pub(crate) struct ImageCreateInfoFields1Vk {
3114 plane_layouts_vk: SmallVec<[ash::vk::SubresourceLayout; 4]>,
3115 view_formats_vk: Vec<ash::vk::Format>,
3116}
3117
3118#[cfg(test)]
3119mod tests {
3120 use super::{ImageCreateInfo, ImageUsage, RawImage};
3121 use crate::{
3122 format::Format,
3123 image::{
3124 ImageAspect, ImageAspects, ImageCreateFlags, ImageSubresourceRange, ImageType,
3125 SampleCount, SubresourceRangeIterator,
3126 },
3127 DeviceSize, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError,
3128 };
3129 use smallvec::SmallVec;
3130
3131 #[test]
3132 fn create_sampled() {
3133 let (device, _) = gfx_dev_and_queue!();
3134
3135 let _ = RawImage::new(
3136 device,
3137 ImageCreateInfo {
3138 image_type: ImageType::Dim2d,
3139 format: Format::R8G8B8A8_UNORM,
3140 extent: [32, 32, 1],
3141 usage: ImageUsage::SAMPLED,
3142 ..Default::default()
3143 },
3144 )
3145 .unwrap();
3146 }
3147
3148 #[test]
3149 fn create_transient() {
3150 let (device, _) = gfx_dev_and_queue!();
3151
3152 let _ = RawImage::new(
3153 device,
3154 ImageCreateInfo {
3155 image_type: ImageType::Dim2d,
3156 format: Format::R8G8B8A8_UNORM,
3157 extent: [32, 32, 1],
3158 usage: ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::COLOR_ATTACHMENT,
3159 ..Default::default()
3160 },
3161 )
3162 .unwrap();
3163 }
3164
3165 #[test]
3166 fn zero_mipmap() {
3167 let (device, _) = gfx_dev_and_queue!();
3168
3169 assert!(matches!(
3170 RawImage::new(
3171 device,
3172 ImageCreateInfo {
3173 image_type: ImageType::Dim2d,
3174 format: Format::R8G8B8A8_UNORM,
3175 extent: [32, 32, 1],
3176 mip_levels: 0,
3177 usage: ImageUsage::SAMPLED,
3178 ..Default::default()
3179 },
3180 ),
3181 Err(Validated::ValidationError(_))
3182 ),);
3183 }
3184
3185 #[test]
3186 fn mipmaps_too_high() {
3187 let (device, _) = gfx_dev_and_queue!();
3188
3189 let res = RawImage::new(
3190 device,
3191 ImageCreateInfo {
3192 image_type: ImageType::Dim2d,
3193 format: Format::R8G8B8A8_UNORM,
3194 extent: [32, 32, 1],
3195 mip_levels: u32::MAX,
3196 usage: ImageUsage::SAMPLED,
3197 ..Default::default()
3198 },
3199 );
3200
3201 match res {
3202 Err(Validated::ValidationError(_)) => (),
3203 _ => panic!(),
3204 };
3205 }
3206
3207 #[test]
3208 fn shader_storage_image_multisample() {
3209 let (device, _) = gfx_dev_and_queue!();
3210
3211 let res = RawImage::new(
3212 device,
3213 ImageCreateInfo {
3214 image_type: ImageType::Dim2d,
3215 format: Format::R8G8B8A8_UNORM,
3216 extent: [32, 32, 1],
3217 samples: SampleCount::Sample2,
3218 usage: ImageUsage::STORAGE,
3219 ..Default::default()
3220 },
3221 );
3222
3223 match res {
3224 Err(Validated::ValidationError(err))
3225 if matches!(
3226 *err,
3227 ValidationError {
3228 requires_one_of: RequiresOneOf([RequiresAllOf([Requires::DeviceFeature(
3229 "shader_storage_image_multisample"
3230 )])],),
3231 ..
3232 }
3233 ) => {}
3234 Err(Validated::ValidationError(_)) => (), _ => panic!(),
3236 };
3237 }
3238
3239 #[test]
3240 fn compressed_not_color_attachment() {
3241 let (device, _) = gfx_dev_and_queue!();
3242
3243 let res = RawImage::new(
3244 device,
3245 ImageCreateInfo {
3246 image_type: ImageType::Dim2d,
3247 format: Format::ASTC_5x4_UNORM_BLOCK,
3248 extent: [32, 32, 1],
3249 usage: ImageUsage::COLOR_ATTACHMENT,
3250 ..Default::default()
3251 },
3252 );
3253
3254 match res {
3255 Err(Validated::ValidationError(_)) => (),
3256 _ => panic!(),
3257 };
3258 }
3259
3260 #[test]
3261 fn transient_forbidden_with_some_usages() {
3262 let (device, _) = gfx_dev_and_queue!();
3263
3264 assert!(matches!(
3265 RawImage::new(
3266 device,
3267 ImageCreateInfo {
3268 image_type: ImageType::Dim2d,
3269 format: Format::R8G8B8A8_UNORM,
3270 extent: [32, 32, 1],
3271 usage: ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::SAMPLED,
3272 ..Default::default()
3273 },
3274 ),
3275 Err(Validated::ValidationError(_))
3276 ))
3277 }
3278
3279 #[test]
3280 fn cubecompatible_dims_mismatch() {
3281 let (device, _) = gfx_dev_and_queue!();
3282
3283 let res = RawImage::new(
3284 device,
3285 ImageCreateInfo {
3286 flags: ImageCreateFlags::CUBE_COMPATIBLE,
3287 image_type: ImageType::Dim2d,
3288 format: Format::R8G8B8A8_UNORM,
3289 extent: [32, 64, 1],
3290 usage: ImageUsage::SAMPLED,
3291 ..Default::default()
3292 },
3293 );
3294
3295 match res {
3296 Err(Validated::ValidationError(_)) => (),
3297 _ => panic!(),
3298 };
3299 }
3300
3301 #[test]
3302 #[allow(clippy::erasing_op, clippy::identity_op)]
3303 fn subresource_range_iterator() {
3304 let image_aspect_list: SmallVec<[ImageAspect; 4]> = (ImageAspects::COLOR
3306 | ImageAspects::DEPTH
3307 | ImageAspects::STENCIL
3308 | ImageAspects::PLANE_0)
3309 .into_iter()
3310 .collect();
3311 let image_mip_levels = 6;
3312 let image_array_layers = 8;
3313
3314 let mip = image_array_layers as DeviceSize;
3315 let asp = mip * image_mip_levels as DeviceSize;
3316
3317 let mut iter = SubresourceRangeIterator::new(
3319 ImageSubresourceRange {
3320 aspects: ImageAspects::COLOR
3321 | ImageAspects::DEPTH
3322 | ImageAspects::STENCIL
3323 | ImageAspects::PLANE_0,
3324 mip_levels: 0..6,
3325 array_layers: 0..8,
3326 },
3327 &image_aspect_list,
3328 asp,
3329 image_mip_levels,
3330 mip,
3331 image_array_layers,
3332 );
3333
3334 assert_eq!(iter.next(), Some(0 * asp..4 * asp));
3335 assert_eq!(iter.next(), None);
3336
3337 let mut iter = SubresourceRangeIterator::new(
3339 ImageSubresourceRange {
3340 aspects: ImageAspects::COLOR | ImageAspects::DEPTH | ImageAspects::PLANE_0,
3341 mip_levels: 0..6,
3342 array_layers: 0..8,
3343 },
3344 &image_aspect_list,
3345 asp,
3346 image_mip_levels,
3347 mip,
3348 image_array_layers,
3349 );
3350
3351 assert_eq!(iter.next(), Some(0 * asp..2 * asp));
3352 assert_eq!(iter.next(), Some(3 * asp..4 * asp));
3353 assert_eq!(iter.next(), None);
3354
3355 let mut iter = SubresourceRangeIterator::new(
3357 ImageSubresourceRange {
3358 aspects: ImageAspects::DEPTH | ImageAspects::STENCIL,
3359 mip_levels: 2..4,
3360 array_layers: 0..8,
3361 },
3362 &image_aspect_list,
3363 asp,
3364 image_mip_levels,
3365 mip,
3366 image_array_layers,
3367 );
3368 assert_eq!(iter.next(), Some(1 * asp + 2 * mip..1 * asp + 4 * mip));
3369 assert_eq!(iter.next(), Some(2 * asp + 2 * mip..2 * asp + 4 * mip));
3370 assert_eq!(iter.next(), None);
3371
3372 let mut iter = SubresourceRangeIterator::new(
3374 ImageSubresourceRange {
3375 aspects: ImageAspects::COLOR,
3376
3377 mip_levels: 0..1,
3378 array_layers: 2..4,
3379 },
3380 &image_aspect_list,
3381 asp,
3382 image_mip_levels,
3383 mip,
3384 image_array_layers,
3385 );
3386
3387 assert_eq!(
3388 iter.next(),
3389 Some(0 * asp + 0 * mip + 2..0 * asp + 0 * mip + 4)
3390 );
3391 assert_eq!(iter.next(), None);
3392
3393 let mut iter = SubresourceRangeIterator::new(
3395 ImageSubresourceRange {
3396 aspects: ImageAspects::DEPTH | ImageAspects::STENCIL,
3397 mip_levels: 2..4,
3398 array_layers: 6..8,
3399 },
3400 &image_aspect_list,
3401 asp,
3402 image_mip_levels,
3403 mip,
3404 image_array_layers,
3405 );
3406 assert_eq!(
3407 iter.next(),
3408 Some(1 * asp + 2 * mip + 6..1 * asp + 2 * mip + 8)
3409 );
3410 assert_eq!(
3411 iter.next(),
3412 Some(1 * asp + 3 * mip + 6..1 * asp + 3 * mip + 8)
3413 );
3414 assert_eq!(
3415 iter.next(),
3416 Some(2 * asp + 2 * mip + 6..2 * asp + 2 * mip + 8)
3417 );
3418 assert_eq!(
3419 iter.next(),
3420 Some(2 * asp + 3 * mip + 6..2 * asp + 3 * mip + 8)
3421 );
3422 assert_eq!(iter.next(), None);
3423 }
3424}