screen_13/driver/
image.rs

1//! Image resource types
2
3use {
4    super::{DriverError, device::Device, format_aspect_mask},
5    ash::vk::{self, ImageCreateInfo},
6    derive_builder::{Builder, UninitializedFieldError},
7    gpu_allocator::{
8        MemoryLocation,
9        vulkan::{Allocation, AllocationCreateDesc, AllocationScheme},
10    },
11    log::{trace, warn},
12    std::{
13        collections::{HashMap, hash_map::Entry},
14        fmt::{Debug, Formatter},
15        mem::{replace, take},
16        ops::{Deref, DerefMut},
17        sync::Arc,
18        thread::panicking,
19    },
20    vk_sync::AccessType,
21};
22
23#[cfg(feature = "parking_lot")]
24use parking_lot::Mutex;
25
26#[cfg(not(feature = "parking_lot"))]
27use std::sync::Mutex;
28
29#[cfg(debug_assertions)]
30fn assert_aspect_mask_supported(aspect_mask: vk::ImageAspectFlags) {
31    use vk::ImageAspectFlags as A;
32
33    const COLOR: A = A::COLOR;
34    const DEPTH: A = A::DEPTH;
35    const DEPTH_STENCIL: A = A::from_raw(A::DEPTH.as_raw() | A::STENCIL.as_raw());
36    const STENCIL: A = A::STENCIL;
37
38    assert!(matches!(
39        aspect_mask,
40        COLOR | DEPTH | DEPTH_STENCIL | STENCIL
41    ));
42}
43
44pub(crate) fn image_subresource_range_contains(
45    lhs: vk::ImageSubresourceRange,
46    rhs: vk::ImageSubresourceRange,
47) -> bool {
48    lhs.aspect_mask.contains(rhs.aspect_mask)
49        && lhs.base_array_layer <= rhs.base_array_layer
50        && lhs.base_array_layer + lhs.layer_count >= rhs.base_array_layer + rhs.layer_count
51        && lhs.base_mip_level <= rhs.base_mip_level
52        && lhs.base_mip_level + lhs.level_count >= rhs.base_mip_level + rhs.level_count
53}
54
55pub(crate) fn image_subresource_range_intersects(
56    lhs: vk::ImageSubresourceRange,
57    rhs: vk::ImageSubresourceRange,
58) -> bool {
59    lhs.aspect_mask.intersects(rhs.aspect_mask)
60        && lhs.base_array_layer < rhs.base_array_layer + rhs.layer_count
61        && lhs.base_array_layer + lhs.layer_count > rhs.base_array_layer
62        && lhs.base_mip_level < rhs.base_mip_level + rhs.level_count
63        && lhs.base_mip_level + lhs.level_count > rhs.base_mip_level
64}
65
66/// Smart pointer handle to an [image] object.
67///
68/// Also contains information about the object.
69///
70/// ## `Deref` behavior
71///
72/// `Image` automatically dereferences to [`vk::Image`] (via the [`Deref`] trait), so you can
73/// call `vk::Image`'s methods on a value of type `Image`. To avoid name clashes with `vk::Image`'s
74/// methods, the methods of `Image` itself are associated functions, called using
75/// [fully qualified syntax]:
76///
77/// ```no_run
78/// # use std::sync::Arc;
79/// # use ash::vk;
80/// # use screen_13::driver::{AccessType, DriverError};
81/// # use screen_13::driver::device::{Device, DeviceInfo};
82/// # use screen_13::driver::image::{Image, ImageInfo};
83/// # fn main() -> Result<(), DriverError> {
84/// # let device = Arc::new(Device::create_headless(DeviceInfo::default())?);
85/// # let info = ImageInfo::image_1d(1, vk::Format::R8_UINT, vk::ImageUsageFlags::STORAGE);
86/// # let my_image = Image::create(&device, info)?;
87/// # let my_subresource_range = vk::ImageSubresourceRange::default();
88/// let prev = Image::access(&my_image, AccessType::AnyShaderWrite, my_subresource_range);
89/// # Ok(()) }
90/// ```
91///
92/// [image]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImage.html
93/// [deref]: core::ops::Deref
94/// [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name
95pub struct Image {
96    accesses: Mutex<ImageAccess<AccessType>>,
97    allocation: Option<Allocation>, // None when we don't own the image (Swapchain images)
98    pub(super) device: Arc<Device>,
99    image: vk::Image,
100    #[allow(clippy::type_complexity)]
101    image_view_cache: Mutex<HashMap<ImageViewInfo, ImageView>>,
102
103    /// Information used to create this object.
104    pub info: ImageInfo,
105
106    /// A name for debugging purposes.
107    pub name: Option<String>,
108}
109
110impl Image {
111    /// Creates a new image on the given device.
112    ///
113    /// # Examples
114    ///
115    /// Basic usage:
116    ///
117    /// ```no_run
118    /// # use std::sync::Arc;
119    /// # use ash::vk;
120    /// # use screen_13::driver::DriverError;
121    /// # use screen_13::driver::device::{Device, DeviceInfo};
122    /// # use screen_13::driver::image::{Image, ImageInfo};
123    /// # fn main() -> Result<(), DriverError> {
124    /// # let device = Arc::new(Device::create_headless(DeviceInfo::default())?);
125    /// let info = ImageInfo::image_2d(32, 32, vk::Format::R8G8B8A8_UNORM, vk::ImageUsageFlags::SAMPLED);
126    /// let image = Image::create(&device, info)?;
127    ///
128    /// assert_ne!(*image, vk::Image::null());
129    /// assert_eq!(image.info.width, 32);
130    /// assert_eq!(image.info.height, 32);
131    /// # Ok(()) }
132    /// ```
133    #[profiling::function]
134    pub fn create(device: &Arc<Device>, info: impl Into<ImageInfo>) -> Result<Self, DriverError> {
135        let info: ImageInfo = info.into();
136
137        //trace!("create: {:?}", &info);
138        trace!("create");
139
140        assert!(
141            !info.usage.is_empty(),
142            "Unspecified image usage {:?}",
143            info.usage
144        );
145
146        let accesses = Mutex::new(ImageAccess::new(info, AccessType::Nothing));
147
148        let device = Arc::clone(device);
149        let create_info: ImageCreateInfo = info.into();
150        let create_info =
151            create_info.queue_family_indices(&device.physical_device.queue_family_indices);
152        let image = unsafe {
153            device.create_image(&create_info, None).map_err(|err| {
154                warn!("unable to create image: {err}");
155
156                DriverError::Unsupported
157            })?
158        };
159        let requirements = unsafe { device.get_image_memory_requirements(image) };
160        let allocation = {
161            profiling::scope!("allocate");
162
163            #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
164            let mut allocator = device.allocator.lock();
165
166            #[cfg(not(feature = "parking_lot"))]
167            let mut allocator = allocator.unwrap();
168
169            allocator
170                .allocate(&AllocationCreateDesc {
171                    name: "image",
172                    requirements,
173                    location: MemoryLocation::GpuOnly,
174                    linear: false,
175                    allocation_scheme: AllocationScheme::GpuAllocatorManaged,
176                })
177                .map_err(|err| {
178                    warn!("unable to allocate image memory: {err}");
179
180                    unsafe {
181                        device.destroy_image(image, None);
182                    }
183
184                    DriverError::from_alloc_err(err)
185                })
186                .and_then(|allocation| {
187                    if let Err(err) = unsafe {
188                        device.bind_image_memory(image, allocation.memory(), allocation.offset())
189                    } {
190                        warn!("unable to bind image memory: {err}");
191
192                        if let Err(err) = allocator.free(allocation) {
193                            warn!("unable to free image allocation: {err}")
194                        }
195
196                        unsafe {
197                            device.destroy_image(image, None);
198                        }
199
200                        Err(DriverError::OutOfMemory)
201                    } else {
202                        Ok(allocation)
203                    }
204                })
205        }?;
206
207        debug_assert_ne!(image, vk::Image::null());
208
209        Ok(Self {
210            accesses,
211            allocation: Some(allocation),
212            device,
213            image,
214            image_view_cache: Mutex::new(Default::default()),
215            info,
216            name: None,
217        })
218    }
219
220    /// Keeps track of some next `access` which affects a `range` this image.
221    ///
222    /// Returns the previous access for which a pipeline barrier should be used to prevent data
223    /// corruption.
224    ///
225    /// # Note
226    ///
227    /// Used to maintain object state when passing a _Screen 13_-created `vk::Image` handle to
228    /// external code such as [_Ash_] or [_Erupt_] bindings.
229    ///
230    /// # Examples
231    ///
232    /// Basic usage:
233    ///
234    /// ```no_run
235    /// # use std::sync::Arc;
236    /// # use ash::vk;
237    /// # use screen_13::driver::{AccessType, DriverError};
238    /// # use screen_13::driver::device::{Device, DeviceInfo};
239    /// # use screen_13::driver::image::{Image, ImageInfo};
240    /// # fn main() -> Result<(), DriverError> {
241    /// # let device = Arc::new(Device::create_headless(DeviceInfo::default())?);
242    /// # let info = ImageInfo::image_1d(1, vk::Format::R8_UINT, vk::ImageUsageFlags::STORAGE);
243    /// # let my_image = Image::create(&device, info)?;
244    /// # let my_subresource_range = vk::ImageSubresourceRange::default();
245    /// // Initially we want to "Read Other"
246    /// let next = AccessType::AnyShaderReadOther;
247    /// let mut prev = Image::access(&my_image, next, my_subresource_range);
248    /// assert_eq!(prev.next().unwrap().0, AccessType::Nothing);
249    ///
250    /// // External code may now "Read Other"; no barrier required
251    ///
252    /// // Subsequently we want to "Write"
253    /// let next = AccessType::FragmentShaderWrite;
254    /// let mut prev = Image::access(&my_image, next, my_subresource_range);
255    /// assert_eq!(prev.next().unwrap().0, AccessType::AnyShaderReadOther);
256    ///
257    /// // A barrier on "Read Other" before "Write" is required!
258    /// # Ok(()) }
259    /// ```
260    ///
261    /// [_Ash_]: https://crates.io/crates/ash
262    /// [_Erupt_]: https://crates.io/crates/erupt
263    #[profiling::function]
264    pub fn access(
265        this: &Self,
266        access: AccessType,
267        mut access_range: vk::ImageSubresourceRange,
268    ) -> impl Iterator<Item = (AccessType, vk::ImageSubresourceRange)> + '_ {
269        #[cfg(debug_assertions)]
270        {
271            assert_aspect_mask_supported(access_range.aspect_mask);
272
273            assert!(format_aspect_mask(this.info.fmt).contains(access_range.aspect_mask));
274        }
275
276        if access_range.layer_count == vk::REMAINING_ARRAY_LAYERS {
277            debug_assert!(access_range.base_array_layer < this.info.array_layer_count);
278
279            access_range.layer_count = this.info.array_layer_count - access_range.base_array_layer
280        }
281
282        debug_assert!(
283            access_range.base_array_layer + access_range.layer_count <= this.info.array_layer_count
284        );
285
286        if access_range.level_count == vk::REMAINING_MIP_LEVELS {
287            debug_assert!(access_range.base_mip_level < this.info.mip_level_count);
288
289            access_range.level_count = this.info.mip_level_count - access_range.base_mip_level
290        }
291
292        debug_assert!(
293            access_range.base_mip_level + access_range.level_count <= this.info.mip_level_count
294        );
295
296        let accesses = this.accesses.lock();
297
298        #[cfg(not(feature = "parking_lot"))]
299        let accesses = accesses.unwrap();
300
301        ImageAccessIter::new(accesses, access, access_range)
302    }
303
304    #[profiling::function]
305    pub(super) fn clone_swapchain(this: &Self) -> Self {
306        // Moves the image view cache from the current instance to the clone!
307        #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
308        let mut image_view_cache = this.image_view_cache.lock();
309
310        #[cfg(not(feature = "parking_lot"))]
311        let mut image_view_cache = image_view_cache.unwrap();
312
313        let image_view_cache = take(&mut *image_view_cache);
314
315        // Does NOT copy over the image accesses!
316        // Force previous access to general to wait for presentation
317        let Self { image, info, .. } = *this;
318        let accesses = ImageAccess::new(info, AccessType::General);
319        let accesses = Mutex::new(accesses);
320
321        Self {
322            accesses,
323            allocation: None,
324            device: Arc::clone(&this.device),
325            image,
326            image_view_cache: Mutex::new(image_view_cache),
327            info,
328            name: this.name.clone(),
329        }
330    }
331
332    #[profiling::function]
333    fn drop_allocation(this: &Self, allocation: Allocation) {
334        {
335            profiling::scope!("views");
336
337            #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
338            let mut image_view_cache = this.image_view_cache.lock();
339
340            #[cfg(not(feature = "parking_lot"))]
341            let mut image_view_cache = image_view_cache.unwrap();
342
343            image_view_cache.clear();
344        }
345
346        unsafe {
347            this.device.destroy_image(this.image, None);
348        }
349
350        {
351            profiling::scope!("deallocate");
352
353            #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
354            let mut allocator = this.device.allocator.lock();
355
356            #[cfg(not(feature = "parking_lot"))]
357            let mut allocator = allocator.unwrap();
358
359            allocator.free(allocation)
360        }
361        .unwrap_or_else(|err| warn!("unable to free image allocation: {err}"));
362    }
363
364    /// Consumes a Vulkan image created by some other library.
365    ///
366    /// The image is not destroyed automatically on drop, unlike images created through the
367    /// [`Image::create`] function.
368    #[profiling::function]
369    pub fn from_raw(device: &Arc<Device>, image: vk::Image, info: impl Into<ImageInfo>) -> Self {
370        let device = Arc::clone(device);
371        let info = info.into();
372
373        // For now default all image access to general, but maybe make this configurable later.
374        // This helps make sure the first presentation of a swapchain image doesn't throw a
375        // validation error, but it could also be very useful for raw vulkan images from other
376        // sources.
377        let accesses = ImageAccess::new(info, AccessType::General);
378
379        Self {
380            accesses: Mutex::new(accesses),
381            allocation: None,
382            device,
383            image,
384            image_view_cache: Mutex::new(Default::default()),
385            info,
386            name: None,
387        }
388    }
389
390    #[profiling::function]
391    pub(crate) fn view(this: &Self, info: ImageViewInfo) -> Result<vk::ImageView, DriverError> {
392        #[cfg_attr(not(feature = "parking_lot"), allow(unused_mut))]
393        let mut image_view_cache = this.image_view_cache.lock();
394
395        #[cfg(not(feature = "parking_lot"))]
396        let mut image_view_cache = image_view_cache.unwrap();
397
398        Ok(match image_view_cache.entry(info) {
399            Entry::Occupied(entry) => entry.get().image_view,
400            Entry::Vacant(entry) => {
401                entry
402                    .insert(ImageView::create(&this.device, info, this.image)?)
403                    .image_view
404            }
405        })
406    }
407}
408
409impl Debug for Image {
410    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
411        if let Some(name) = &self.name {
412            write!(f, "{} ({:?})", name, self.image)
413        } else {
414            write!(f, "{:?}", self.image)
415        }
416    }
417}
418
419impl Deref for Image {
420    type Target = vk::Image;
421
422    fn deref(&self) -> &Self::Target {
423        &self.image
424    }
425}
426
427impl Drop for Image {
428    // This function is not profiled because drop_allocation is
429    fn drop(&mut self) {
430        if panicking() {
431            return;
432        }
433
434        // When our allocation is some we allocated ourself; otherwise somebody
435        // else owns this image and we should not destroy it. Usually it's the swapchain...
436        if let Some(allocation) = self.allocation.take() {
437            Self::drop_allocation(self, allocation);
438        }
439    }
440}
441
442#[derive(Debug)]
443pub(crate) struct ImageAccess<A> {
444    accesses: Box<[A]>,
445
446    #[cfg(debug_assertions)]
447    array_layer_count: u32,
448
449    aspect_count: u8,
450    mip_level_count: u32,
451}
452
453impl<A> ImageAccess<A> {
454    pub fn new(info: ImageInfo, access: A) -> Self
455    where
456        A: Copy,
457    {
458        let aspect_mask = format_aspect_mask(info.fmt);
459
460        #[cfg(debug_assertions)]
461        assert_aspect_mask_supported(aspect_mask);
462
463        let aspect_count = aspect_mask.as_raw().count_ones() as u8;
464        let array_layer_count = info.array_layer_count;
465        let mip_level_count = info.mip_level_count;
466
467        Self {
468            accesses: vec![
469                access;
470                (aspect_count as u32 * array_layer_count * mip_level_count) as _
471            ]
472            .into_boxed_slice(),
473
474            #[cfg(debug_assertions)]
475            array_layer_count,
476
477            aspect_count,
478            mip_level_count,
479        }
480    }
481
482    pub fn access(
483        &mut self,
484        access: A,
485        access_range: vk::ImageSubresourceRange,
486    ) -> impl Iterator<Item = (A, vk::ImageSubresourceRange)> + '_
487    where
488        A: Copy + PartialEq,
489    {
490        ImageAccessIter::new(self, access, access_range)
491    }
492
493    fn idx(&self, aspect: u8, array_layer: u32, mip_level: u32) -> usize {
494        // For a 3 Layer, 2 Mip, Depth/Stencil image:
495        // 0     1     2     3     4     5     6     7     8     9     10    11
496        // DL0M0 SL0M0 DL0M1 SL0M1 DL1M0 SL1M0 DL1M1 SL1M1 DL2M0 SL2M0 DL2M1 SL2M1
497        let idx = (array_layer * self.aspect_count as u32 * self.mip_level_count
498            + mip_level * self.aspect_count as u32
499            + aspect as u32) as _;
500
501        debug_assert!(idx < self.accesses.len());
502
503        idx
504    }
505}
506
507struct ImageAccessIter<I, A> {
508    access: A,
509    access_range: ImageAccessRange,
510    array_layer: u32,
511    aspect: u8,
512    image: I,
513    mip_level: u32,
514}
515
516impl<I, A> ImageAccessIter<I, A> {
517    fn new(image: I, access: A, access_range: vk::ImageSubresourceRange) -> Self
518    where
519        I: DerefMut<Target = ImageAccess<A>>,
520    {
521        #[cfg(debug_assertions)]
522        assert_aspect_mask_supported(access_range.aspect_mask);
523
524        #[cfg(debug_assertions)]
525        assert!(access_range.base_array_layer < image.array_layer_count);
526
527        debug_assert!(access_range.base_mip_level < image.mip_level_count);
528        debug_assert_ne!(access_range.layer_count, 0);
529        debug_assert_ne!(access_range.level_count, 0);
530
531        let aspect_count = access_range.aspect_mask.as_raw().count_ones() as _;
532
533        debug_assert!(aspect_count <= image.aspect_count);
534
535        let base_aspect = access_range.aspect_mask.as_raw().trailing_zeros() as _;
536
537        Self {
538            access,
539            array_layer: 0,
540            aspect: 0,
541            image,
542            mip_level: 0,
543            access_range: ImageAccessRange {
544                aspect_count,
545                base_array_layer: access_range.base_array_layer,
546                base_aspect,
547                base_mip_level: access_range.base_mip_level,
548                layer_count: access_range.layer_count,
549                level_count: access_range.level_count,
550            },
551        }
552    }
553}
554
555impl<I, A> Iterator for ImageAccessIter<I, A>
556where
557    I: DerefMut<Target = ImageAccess<A>>,
558    A: Copy + PartialEq,
559{
560    type Item = (A, vk::ImageSubresourceRange);
561
562    fn next(&mut self) -> Option<Self::Item> {
563        if self.aspect == self.access_range.aspect_count {
564            return None;
565        }
566
567        let mut res = vk::ImageSubresourceRange {
568            aspect_mask: vk::ImageAspectFlags::from_raw(
569                (1 << (self.access_range.base_aspect + self.aspect)) as _,
570            ),
571            base_array_layer: self.access_range.base_array_layer + self.array_layer,
572            base_mip_level: self.access_range.base_mip_level + self.mip_level,
573            layer_count: 1,
574            level_count: 1,
575        };
576
577        let base_aspect = (self.image.aspect_count << self.access_range.base_aspect == 8) as u8;
578        let prev_access = replace(
579            {
580                let idx = self.image.idx(
581                    base_aspect + self.aspect,
582                    res.base_array_layer,
583                    res.base_mip_level,
584                );
585
586                unsafe { self.image.accesses.get_unchecked_mut(idx) }
587            },
588            self.access,
589        );
590
591        loop {
592            self.mip_level += 1;
593            self.mip_level %= self.access_range.level_count;
594            if self.mip_level == 0 {
595                break;
596            }
597
598            let idx = self.image.idx(
599                base_aspect + self.aspect,
600                self.access_range.base_array_layer + self.array_layer,
601                self.access_range.base_mip_level + self.mip_level,
602            );
603            let access = unsafe { self.image.accesses.get_unchecked_mut(idx) };
604            if *access != prev_access {
605                return Some((prev_access, res));
606            }
607
608            *access = self.access;
609            res.level_count += 1;
610        }
611
612        loop {
613            self.array_layer += 1;
614            self.array_layer %= self.access_range.layer_count;
615            if self.array_layer == 0 {
616                break;
617            }
618
619            if res.base_mip_level != self.access_range.base_mip_level {
620                return Some((prev_access, res));
621            }
622
623            let array_layer = self.access_range.base_array_layer + self.array_layer;
624            let end_mip_level = self.access_range.base_mip_level + self.access_range.level_count;
625
626            for mip_level in self.access_range.base_mip_level..end_mip_level {
627                let idx = self
628                    .image
629                    .idx(base_aspect + self.aspect, array_layer, mip_level);
630                let access = unsafe { *self.image.accesses.get_unchecked(idx) };
631                if access != prev_access {
632                    return Some((prev_access, res));
633                }
634            }
635
636            for mip_level in self.access_range.base_mip_level..end_mip_level {
637                let idx = self
638                    .image
639                    .idx(base_aspect + self.aspect, array_layer, mip_level);
640                let access = unsafe { self.image.accesses.get_unchecked_mut(idx) };
641                *access = self.access;
642            }
643
644            res.layer_count += 1;
645        }
646
647        loop {
648            self.aspect += 1;
649            if self.aspect == self.access_range.aspect_count {
650                return Some((prev_access, res));
651            }
652
653            let end_array_layer =
654                self.access_range.base_array_layer + self.access_range.layer_count;
655            let end_mip_level = self.access_range.base_mip_level + self.access_range.level_count;
656
657            for array_layer in self.access_range.base_array_layer..end_array_layer {
658                for mip_level in self.access_range.base_mip_level..end_mip_level {
659                    let idx = self
660                        .image
661                        .idx(base_aspect + self.aspect, array_layer, mip_level);
662                    let access = unsafe { *self.image.accesses.get_unchecked(idx) };
663                    if access != prev_access {
664                        return Some((prev_access, res));
665                    }
666                }
667            }
668
669            for array_layer in self.access_range.base_array_layer..end_array_layer {
670                for mip_level in self.access_range.base_mip_level..end_mip_level {
671                    let idx = self
672                        .image
673                        .idx(base_aspect + self.aspect, array_layer, mip_level);
674                    let access = unsafe { self.image.accesses.get_unchecked_mut(idx) };
675                    *access = self.access;
676                }
677            }
678
679            res.aspect_mask |= vk::ImageAspectFlags::from_raw(
680                (1 << (self.access_range.base_aspect + self.aspect)) as _,
681            )
682        }
683    }
684}
685
686#[derive(Copy, Clone)]
687struct ImageAccessRange {
688    aspect_count: u8,
689    base_array_layer: u32,
690    base_aspect: u8,
691    base_mip_level: u32,
692    layer_count: u32,
693    level_count: u32,
694}
695
696/// Information used to create an [`Image`] instance.
697#[derive(Builder, Clone, Copy, Debug, Hash, PartialEq, Eq)]
698#[builder(
699    build_fn(private, name = "fallible_build", error = "ImageInfoBuilderError"),
700    derive(Copy, Clone, Debug),
701    pattern = "owned"
702)]
703#[non_exhaustive]
704pub struct ImageInfo {
705    /// The number of layers in the image.
706    #[builder(default = "1", setter(strip_option))]
707    pub array_layer_count: u32,
708
709    /// Image extent of the Z axis, when describing a three dimensional image.
710    #[builder(setter(strip_option))]
711    pub depth: u32,
712
713    /// A bitmask of describing additional parameters of the image.
714    #[builder(default, setter(strip_option))]
715    pub flags: vk::ImageCreateFlags,
716
717    /// The format and type of the texel blocks that will be contained in the image.
718    #[builder(setter(strip_option))]
719    pub fmt: vk::Format,
720
721    /// Image extent of the Y axis, when describing a two or three dimensional image.
722    #[builder(setter(strip_option))]
723    pub height: u32,
724
725    /// The number of levels of detail available for minified sampling of the image.
726    #[builder(default = "1", setter(strip_option))]
727    pub mip_level_count: u32,
728
729    /// Specifies the number of [samples per texel].
730    ///
731    /// [samples per texel]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#primsrast-multisampling
732    #[builder(default = "SampleCount::Type1", setter(strip_option))]
733    pub sample_count: SampleCount,
734
735    /// Specifies the tiling arrangement of the texel blocks in memory.
736    ///
737    /// The default value is [`vk::ImageTiling::OPTIMAL`].
738    #[builder(default = "vk::ImageTiling::OPTIMAL", setter(strip_option))]
739    pub tiling: vk::ImageTiling,
740
741    /// The basic dimensionality of the image.
742    ///
743    /// Layers in array textures do not count as a dimension for the purposes of the image type.
744    #[builder(setter(strip_option))]
745    pub ty: vk::ImageType,
746
747    /// A bitmask of describing the intended usage of the image.
748    #[builder(default, setter(strip_option))]
749    pub usage: vk::ImageUsageFlags,
750
751    /// Image extent of the X axis.
752    #[builder(setter(strip_option))]
753    pub width: u32,
754}
755
756impl ImageInfo {
757    /// Specifies a cube image.
758    #[inline(always)]
759    pub const fn cube(size: u32, fmt: vk::Format, usage: vk::ImageUsageFlags) -> ImageInfo {
760        let mut res = Self::new(vk::ImageType::TYPE_2D, size, size, 1, 6, fmt, usage);
761        res.flags = vk::ImageCreateFlags::from_raw(
762            vk::ImageCreateFlags::CUBE_COMPATIBLE.as_raw() | res.flags.as_raw(),
763        );
764
765        res
766    }
767
768    /// Specifies a one-dimensional image.
769    #[inline(always)]
770    pub const fn image_1d(size: u32, fmt: vk::Format, usage: vk::ImageUsageFlags) -> ImageInfo {
771        Self::new(vk::ImageType::TYPE_1D, size, 1, 1, 1, fmt, usage)
772    }
773
774    /// Specifies a two-dimensional image.
775    #[inline(always)]
776    pub const fn image_2d(
777        width: u32,
778        height: u32,
779        fmt: vk::Format,
780        usage: vk::ImageUsageFlags,
781    ) -> ImageInfo {
782        Self::new(vk::ImageType::TYPE_2D, width, height, 1, 1, fmt, usage)
783    }
784
785    /// Specifies a two-dimensional image array.
786    #[inline(always)]
787    pub const fn image_2d_array(
788        width: u32,
789        height: u32,
790        array_elements: u32,
791        fmt: vk::Format,
792        usage: vk::ImageUsageFlags,
793    ) -> ImageInfo {
794        Self::new(
795            vk::ImageType::TYPE_2D,
796            width,
797            height,
798            1,
799            array_elements,
800            fmt,
801            usage,
802        )
803    }
804
805    /// Specifies a three-dimensional image.
806    #[inline(always)]
807    pub const fn image_3d(
808        width: u32,
809        height: u32,
810        depth: u32,
811        fmt: vk::Format,
812        usage: vk::ImageUsageFlags,
813    ) -> ImageInfo {
814        Self::new(vk::ImageType::TYPE_3D, width, height, depth, 1, fmt, usage)
815    }
816
817    #[inline(always)]
818    const fn new(
819        ty: vk::ImageType,
820        width: u32,
821        height: u32,
822        depth: u32,
823        array_layer_count: u32,
824        fmt: vk::Format,
825        usage: vk::ImageUsageFlags,
826    ) -> Self {
827        Self {
828            ty,
829            width,
830            height,
831            depth,
832            array_layer_count,
833            fmt,
834            usage,
835            flags: vk::ImageCreateFlags::empty(),
836            tiling: vk::ImageTiling::OPTIMAL,
837            mip_level_count: 1,
838            sample_count: SampleCount::Type1,
839        }
840    }
841
842    /// Provides an `ImageViewInfo` for this format, type, aspect, array elements, and mip levels.
843    pub fn default_view_info(self) -> ImageViewInfo {
844        self.into()
845    }
846
847    /// Returns `true` if this image is an array
848    pub fn is_array(self) -> bool {
849        self.array_layer_count > 1
850    }
851
852    /// Returns `true` if this image is a cube or cube array
853    pub fn is_cube(self) -> bool {
854        self.ty == vk::ImageType::TYPE_2D
855            && self.width == self.height
856            && self.depth == 1
857            && self.array_layer_count >= 6
858            && self.flags.contains(vk::ImageCreateFlags::CUBE_COMPATIBLE)
859    }
860
861    /// Returns `true` if this image is a cube array
862    pub fn is_cube_array(self) -> bool {
863        self.is_cube() && self.array_layer_count > 6
864    }
865
866    /// Converts an `ImageInfo` into an `ImageInfoBuilder`.
867    #[inline(always)]
868    pub fn to_builder(self) -> ImageInfoBuilder {
869        ImageInfoBuilder {
870            array_layer_count: Some(self.array_layer_count),
871            depth: Some(self.depth),
872            flags: Some(self.flags),
873            fmt: Some(self.fmt),
874            height: Some(self.height),
875            mip_level_count: Some(self.mip_level_count),
876            sample_count: Some(self.sample_count),
877            tiling: Some(self.tiling),
878            ty: Some(self.ty),
879            usage: Some(self.usage),
880            width: Some(self.width),
881        }
882    }
883}
884
885impl From<ImageInfo> for vk::ImageCreateInfo<'_> {
886    fn from(value: ImageInfo) -> Self {
887        Self::default()
888            .flags(value.flags)
889            .image_type(value.ty)
890            .format(value.fmt)
891            .extent(vk::Extent3D {
892                width: value.width,
893                height: value.height,
894                depth: value.depth,
895            })
896            .mip_levels(value.mip_level_count)
897            .array_layers(value.array_layer_count)
898            .samples(value.sample_count.into())
899            .tiling(value.tiling)
900            .usage(value.usage)
901            .sharing_mode(vk::SharingMode::CONCURRENT)
902            .initial_layout(vk::ImageLayout::UNDEFINED)
903    }
904}
905
906impl From<ImageInfoBuilder> for ImageInfo {
907    fn from(info: ImageInfoBuilder) -> Self {
908        info.build()
909    }
910}
911
912impl ImageInfoBuilder {
913    /// Builds a new `ImageInfo`.
914    ///
915    /// # Panics
916    ///
917    /// If any of the following functions have not been called this function will panic:
918    ///
919    /// * `ty`
920    /// * `fmt`
921    /// * `width`
922    /// * `height`
923    /// * `depth`
924    #[inline(always)]
925    pub fn build(self) -> ImageInfo {
926        match self.fallible_build() {
927            Err(ImageInfoBuilderError(err)) => panic!("{err}"),
928            Ok(info) => info,
929        }
930    }
931}
932
933#[derive(Debug)]
934struct ImageInfoBuilderError(UninitializedFieldError);
935
936impl From<UninitializedFieldError> for ImageInfoBuilderError {
937    fn from(err: UninitializedFieldError) -> Self {
938        Self(err)
939    }
940}
941
942impl From<ImageViewInfo> for vk::ImageSubresourceRange {
943    fn from(info: ImageViewInfo) -> Self {
944        Self {
945            aspect_mask: info.aspect_mask,
946            base_mip_level: info.base_mip_level,
947            base_array_layer: info.base_array_layer,
948            layer_count: info.array_layer_count,
949            level_count: info.mip_level_count,
950        }
951    }
952}
953
954struct ImageView {
955    device: Arc<Device>,
956    image_view: vk::ImageView,
957}
958
959impl ImageView {
960    #[profiling::function]
961    fn create(
962        device: &Arc<Device>,
963        info: impl Into<ImageViewInfo>,
964        image: vk::Image,
965    ) -> Result<Self, DriverError> {
966        let info = info.into();
967        let device = Arc::clone(device);
968        let create_info = vk::ImageViewCreateInfo::default()
969            .view_type(info.ty)
970            .format(info.fmt)
971            .components(vk::ComponentMapping {
972                r: vk::ComponentSwizzle::R,
973                g: vk::ComponentSwizzle::G,
974                b: vk::ComponentSwizzle::B,
975                a: vk::ComponentSwizzle::A,
976            })
977            .image(image)
978            .subresource_range(vk::ImageSubresourceRange {
979                aspect_mask: info.aspect_mask,
980                base_array_layer: info.base_array_layer,
981                base_mip_level: info.base_mip_level,
982                level_count: info.mip_level_count,
983                layer_count: info.array_layer_count,
984            });
985
986        let image_view =
987            unsafe { device.create_image_view(&create_info, None) }.map_err(|err| {
988                warn!("{err}");
989
990                DriverError::Unsupported
991            })?;
992
993        Ok(Self { device, image_view })
994    }
995}
996
997impl Drop for ImageView {
998    #[profiling::function]
999    fn drop(&mut self) {
1000        if panicking() {
1001            return;
1002        }
1003
1004        unsafe {
1005            self.device.destroy_image_view(self.image_view, None);
1006        }
1007    }
1008}
1009
1010/// Information used to reinterpret an existing [`Image`] instance.
1011#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
1012#[builder(
1013    build_fn(private, name = "fallible_build", error = "ImageViewInfoBuilderError"),
1014    derive(Clone, Copy, Debug),
1015    pattern = "owned"
1016)]
1017#[non_exhaustive]
1018pub struct ImageViewInfo {
1019    /// The number of layers that will be contained in the view.
1020    ///
1021    /// The default value is `vk::REMAINING_ARRAY_LAYERS`.
1022    #[builder(default = "vk::REMAINING_ARRAY_LAYERS")]
1023    pub array_layer_count: u32,
1024
1025    /// The portion of the image that will be contained in the view.
1026    pub aspect_mask: vk::ImageAspectFlags,
1027
1028    /// The first array layer that will be contained in the view.
1029    #[builder(default)]
1030    pub base_array_layer: u32,
1031
1032    /// The first mip level that will be contained in the view.
1033    #[builder(default)]
1034    pub base_mip_level: u32,
1035
1036    /// The format and type of the texel blocks that will be contained in the view.
1037    pub fmt: vk::Format,
1038
1039    /// The number of mip levels that will be contained in the view.
1040    ///
1041    /// The default value is `vk::REMAINING_MIP_LEVELS`.
1042    #[builder(default = "vk::REMAINING_MIP_LEVELS")]
1043    pub mip_level_count: u32,
1044
1045    /// The basic dimensionality of the view.
1046    pub ty: vk::ImageViewType,
1047}
1048
1049impl ImageViewInfo {
1050    /// Specifies a default view with the given `fmt` and `ty` values.
1051    ///
1052    /// # Note
1053    ///
1054    /// Automatically sets [`aspect_mask`](Self::aspect_mask) to a suggested value.
1055    #[inline(always)]
1056    pub const fn new(fmt: vk::Format, ty: vk::ImageViewType) -> ImageViewInfo {
1057        Self {
1058            array_layer_count: vk::REMAINING_ARRAY_LAYERS,
1059            aspect_mask: format_aspect_mask(fmt),
1060            base_array_layer: 0,
1061            base_mip_level: 0,
1062            fmt,
1063            mip_level_count: vk::REMAINING_MIP_LEVELS,
1064            ty,
1065        }
1066    }
1067
1068    /// Converts a `ImageViewInfo` into a `ImageViewInfoBuilder`.
1069    #[inline(always)]
1070    pub fn to_builder(self) -> ImageViewInfoBuilder {
1071        ImageViewInfoBuilder {
1072            array_layer_count: Some(self.array_layer_count),
1073            aspect_mask: Some(self.aspect_mask),
1074            base_array_layer: Some(self.base_array_layer),
1075            base_mip_level: Some(self.base_mip_level),
1076            fmt: Some(self.fmt),
1077            mip_level_count: Some(self.mip_level_count),
1078            ty: Some(self.ty),
1079        }
1080    }
1081
1082    /// Takes this instance and returns it with a newly specified `ImageViewType`.
1083    pub fn with_type(mut self, ty: vk::ImageViewType) -> Self {
1084        self.ty = ty;
1085        self
1086    }
1087}
1088
1089impl From<ImageInfo> for ImageViewInfo {
1090    fn from(info: ImageInfo) -> Self {
1091        Self {
1092            array_layer_count: info.array_layer_count,
1093            aspect_mask: format_aspect_mask(info.fmt),
1094            base_array_layer: 0,
1095            base_mip_level: 0,
1096            fmt: info.fmt,
1097            mip_level_count: info.mip_level_count,
1098            ty: match (info.ty, info.array_layer_count) {
1099                (vk::ImageType::TYPE_1D, 1) => vk::ImageViewType::TYPE_1D,
1100                (vk::ImageType::TYPE_1D, _) => vk::ImageViewType::TYPE_1D_ARRAY,
1101                (vk::ImageType::TYPE_2D, 1) => vk::ImageViewType::TYPE_2D,
1102                (vk::ImageType::TYPE_2D, 6)
1103                    if info.flags.contains(vk::ImageCreateFlags::CUBE_COMPATIBLE) =>
1104                {
1105                    vk::ImageViewType::CUBE
1106                }
1107                (vk::ImageType::TYPE_2D, _)
1108                    if info.flags.contains(vk::ImageCreateFlags::CUBE_COMPATIBLE)
1109                        && info.array_layer_count > 6 =>
1110                {
1111                    vk::ImageViewType::CUBE_ARRAY
1112                }
1113                (vk::ImageType::TYPE_2D, _) => vk::ImageViewType::TYPE_2D_ARRAY,
1114                (vk::ImageType::TYPE_3D, _) => vk::ImageViewType::TYPE_3D,
1115                _ => unimplemented!(),
1116            },
1117        }
1118    }
1119}
1120
1121impl From<ImageViewInfoBuilder> for ImageViewInfo {
1122    fn from(info: ImageViewInfoBuilder) -> Self {
1123        info.build()
1124    }
1125}
1126
1127impl ImageViewInfoBuilder {
1128    /// Builds a new 'ImageViewInfo'.
1129    ///
1130    /// # Panics
1131    ///
1132    /// If any of the following values have not been set this function will panic:
1133    ///
1134    /// * `ty`
1135    /// * `fmt`
1136    /// * `aspect_mask`
1137    #[inline(always)]
1138    pub fn build(self) -> ImageViewInfo {
1139        match self.fallible_build() {
1140            Err(ImageViewInfoBuilderError(err)) => panic!("{err}"),
1141            Ok(info) => info,
1142        }
1143    }
1144}
1145
1146#[derive(Debug)]
1147struct ImageViewInfoBuilderError(UninitializedFieldError);
1148
1149impl From<UninitializedFieldError> for ImageViewInfoBuilderError {
1150    fn from(err: UninitializedFieldError) -> Self {
1151        Self(err)
1152    }
1153}
1154
1155/// Specifies sample counts supported for an image used for storage operation.
1156///
1157/// Values must not exceed the device limits specified by [Device.physical_device.props.limits].
1158#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
1159pub enum SampleCount {
1160    /// Single image sample. This is the usual mode.
1161    #[default]
1162    Type1,
1163
1164    /// Multiple image samples.
1165    Type2,
1166
1167    /// Multiple image samples.
1168    Type4,
1169
1170    /// Multiple image samples.
1171    Type8,
1172
1173    /// Multiple image samples.
1174    Type16,
1175
1176    /// Multiple image samples.
1177    Type32,
1178
1179    /// Multiple image samples.
1180    Type64,
1181}
1182
1183impl SampleCount {
1184    /// Returns `true` when the value represents a single sample mode.
1185    pub fn is_single(self) -> bool {
1186        matches!(self, Self::Type1)
1187    }
1188
1189    /// Returns `true` when the value represents a multiple sample mode.
1190    pub fn is_multiple(self) -> bool {
1191        matches!(
1192            self,
1193            Self::Type2 | Self::Type4 | Self::Type8 | Self::Type16 | Self::Type32 | Self::Type64
1194        )
1195    }
1196}
1197
1198impl From<SampleCount> for vk::SampleCountFlags {
1199    fn from(sample_count: SampleCount) -> Self {
1200        match sample_count {
1201            SampleCount::Type1 => Self::TYPE_1,
1202            SampleCount::Type2 => Self::TYPE_2,
1203            SampleCount::Type4 => Self::TYPE_4,
1204            SampleCount::Type8 => Self::TYPE_8,
1205            SampleCount::Type16 => Self::TYPE_16,
1206            SampleCount::Type32 => Self::TYPE_32,
1207            SampleCount::Type64 => Self::TYPE_64,
1208        }
1209    }
1210}
1211
1212#[cfg(test)]
1213mod tests {
1214    use {super::*, std::ops::Range};
1215
1216    // ImageSubresourceRange does not implement PartialEq
1217    fn assert_access_ranges_eq(
1218        lhs: (AccessType, vk::ImageSubresourceRange),
1219        rhs: (AccessType, vk::ImageSubresourceRange),
1220    ) {
1221        assert_eq!(
1222            (
1223                lhs.0,
1224                lhs.1.aspect_mask,
1225                lhs.1.base_array_layer,
1226                lhs.1.layer_count,
1227                lhs.1.base_mip_level,
1228                lhs.1.level_count
1229            ),
1230            (
1231                rhs.0,
1232                rhs.1.aspect_mask,
1233                rhs.1.base_array_layer,
1234                rhs.1.layer_count,
1235                rhs.1.base_mip_level,
1236                rhs.1.level_count
1237            )
1238        );
1239    }
1240
1241    #[test]
1242    pub fn image_access_basic() {
1243        use vk::ImageAspectFlags as A;
1244
1245        let mut image = ImageAccess::new(
1246            image_subresource(vk::Format::R8G8B8A8_UNORM, 1, 1),
1247            AccessType::Nothing,
1248        );
1249
1250        {
1251            let mut accesses = ImageAccessIter::new(
1252                &mut image,
1253                AccessType::AnyShaderWrite,
1254                image_subresource_range(A::COLOR, 0..1, 0..1),
1255            );
1256
1257            assert_access_ranges_eq(
1258                accesses.next().unwrap(),
1259                (
1260                    AccessType::Nothing,
1261                    image_subresource_range(A::COLOR, 0..1, 0..1),
1262                ),
1263            );
1264            assert!(accesses.next().is_none());
1265        }
1266
1267        {
1268            let mut accesses = ImageAccessIter::new(
1269                &mut image,
1270                AccessType::AnyShaderReadOther,
1271                image_subresource_range(A::COLOR, 0..1, 0..1),
1272            );
1273
1274            assert_access_ranges_eq(
1275                accesses.next().unwrap(),
1276                (
1277                    AccessType::AnyShaderWrite,
1278                    image_subresource_range(A::COLOR, 0..1, 0..1),
1279                ),
1280            );
1281            assert!(accesses.next().is_none());
1282        }
1283    }
1284
1285    #[test]
1286    pub fn image_access_color() {
1287        use vk::ImageAspectFlags as A;
1288
1289        let mut image = ImageAccess::new(
1290            image_subresource(vk::Format::R8G8B8A8_UNORM, 3, 3),
1291            AccessType::Nothing,
1292        );
1293
1294        {
1295            let mut accesses = ImageAccessIter::new(
1296                &mut image,
1297                AccessType::AnyShaderWrite,
1298                image_subresource_range(A::COLOR, 0..3, 0..3),
1299            );
1300
1301            assert_access_ranges_eq(
1302                accesses.next().unwrap(),
1303                (
1304                    AccessType::Nothing,
1305                    image_subresource_range(A::COLOR, 0..3, 0..3),
1306                ),
1307            );
1308            assert!(accesses.next().is_none());
1309        }
1310
1311        {
1312            let mut accesses = ImageAccessIter::new(
1313                &mut image,
1314                AccessType::AnyShaderReadOther,
1315                image_subresource_range(A::COLOR, 0..1, 0..1),
1316            );
1317
1318            assert_access_ranges_eq(
1319                accesses.next().unwrap(),
1320                (
1321                    AccessType::AnyShaderWrite,
1322                    image_subresource_range(A::COLOR, 0..1, 0..1),
1323                ),
1324            );
1325            assert!(accesses.next().is_none());
1326        }
1327
1328        {
1329            let mut accesses = ImageAccessIter::new(
1330                &mut image,
1331                AccessType::ComputeShaderWrite,
1332                image_subresource_range(A::COLOR, 0..3, 0..3),
1333            );
1334
1335            assert_access_ranges_eq(
1336                accesses.next().unwrap(),
1337                (
1338                    AccessType::AnyShaderReadOther,
1339                    image_subresource_range(A::COLOR, 0..1, 0..1),
1340                ),
1341            );
1342            assert_access_ranges_eq(
1343                accesses.next().unwrap(),
1344                (
1345                    AccessType::AnyShaderWrite,
1346                    image_subresource_range(A::COLOR, 0..1, 1..3),
1347                ),
1348            );
1349            assert_access_ranges_eq(
1350                accesses.next().unwrap(),
1351                (
1352                    AccessType::AnyShaderWrite,
1353                    image_subresource_range(A::COLOR, 1..3, 0..3),
1354                ),
1355            );
1356            assert!(accesses.next().is_none());
1357        }
1358
1359        {
1360            let mut accesses = ImageAccessIter::new(
1361                &mut image,
1362                AccessType::HostRead,
1363                image_subresource_range(A::COLOR, 0..3, 0..3),
1364            );
1365
1366            assert_access_ranges_eq(
1367                accesses.next().unwrap(),
1368                (
1369                    AccessType::ComputeShaderWrite,
1370                    image_subresource_range(A::COLOR, 0..3, 0..3),
1371                ),
1372            );
1373            assert!(accesses.next().is_none());
1374        }
1375
1376        {
1377            let mut accesses = ImageAccessIter::new(
1378                &mut image,
1379                AccessType::HostWrite,
1380                image_subresource_range(A::COLOR, 1..2, 1..2),
1381            );
1382
1383            assert_access_ranges_eq(
1384                accesses.next().unwrap(),
1385                (
1386                    AccessType::HostRead,
1387                    image_subresource_range(A::COLOR, 1..2, 1..2),
1388                ),
1389            );
1390            assert!(accesses.next().is_none());
1391        }
1392
1393        {
1394            let mut accesses = ImageAccessIter::new(
1395                &mut image,
1396                AccessType::GeometryShaderReadOther,
1397                image_subresource_range(A::COLOR, 0..3, 0..3),
1398            );
1399
1400            assert_access_ranges_eq(
1401                accesses.next().unwrap(),
1402                (
1403                    AccessType::HostRead,
1404                    image_subresource_range(A::COLOR, 0..1, 0..3),
1405                ),
1406            );
1407            assert_access_ranges_eq(
1408                accesses.next().unwrap(),
1409                (
1410                    AccessType::HostRead,
1411                    image_subresource_range(A::COLOR, 1..2, 0..1),
1412                ),
1413            );
1414            assert_access_ranges_eq(
1415                accesses.next().unwrap(),
1416                (
1417                    AccessType::HostWrite,
1418                    image_subresource_range(A::COLOR, 1..2, 1..2),
1419                ),
1420            );
1421            assert_access_ranges_eq(
1422                accesses.next().unwrap(),
1423                (
1424                    AccessType::HostRead,
1425                    image_subresource_range(A::COLOR, 1..2, 2..3),
1426                ),
1427            );
1428            assert_access_ranges_eq(
1429                accesses.next().unwrap(),
1430                (
1431                    AccessType::HostRead,
1432                    image_subresource_range(A::COLOR, 2..3, 0..3),
1433                ),
1434            );
1435            assert!(accesses.next().is_none());
1436        }
1437
1438        {
1439            let mut accesses = ImageAccessIter::new(
1440                &mut image,
1441                AccessType::VertexBuffer,
1442                image_subresource_range(A::COLOR, 0..3, 1..2),
1443            );
1444
1445            assert_access_ranges_eq(
1446                accesses.next().unwrap(),
1447                (
1448                    AccessType::GeometryShaderReadOther,
1449                    image_subresource_range(A::COLOR, 0..3, 1..2),
1450                ),
1451            );
1452            assert!(accesses.next().is_none());
1453        }
1454
1455        {
1456            let mut accesses = ImageAccessIter::new(
1457                &mut image,
1458                AccessType::ColorAttachmentRead,
1459                image_subresource_range(A::COLOR, 0..3, 0..3),
1460            );
1461
1462            assert_access_ranges_eq(
1463                accesses.next().unwrap(),
1464                (
1465                    AccessType::GeometryShaderReadOther,
1466                    image_subresource_range(A::COLOR, 0..1, 0..1),
1467                ),
1468            );
1469            assert_access_ranges_eq(
1470                accesses.next().unwrap(),
1471                (
1472                    AccessType::VertexBuffer,
1473                    image_subresource_range(A::COLOR, 0..1, 1..2),
1474                ),
1475            );
1476            assert_access_ranges_eq(
1477                accesses.next().unwrap(),
1478                (
1479                    AccessType::GeometryShaderReadOther,
1480                    image_subresource_range(A::COLOR, 0..1, 2..3),
1481                ),
1482            );
1483            assert_access_ranges_eq(
1484                accesses.next().unwrap(),
1485                (
1486                    AccessType::GeometryShaderReadOther,
1487                    image_subresource_range(A::COLOR, 1..2, 0..1),
1488                ),
1489            );
1490            assert_access_ranges_eq(
1491                accesses.next().unwrap(),
1492                (
1493                    AccessType::VertexBuffer,
1494                    image_subresource_range(A::COLOR, 1..2, 1..2),
1495                ),
1496            );
1497            assert_access_ranges_eq(
1498                accesses.next().unwrap(),
1499                (
1500                    AccessType::GeometryShaderReadOther,
1501                    image_subresource_range(A::COLOR, 1..2, 2..3),
1502                ),
1503            );
1504            assert_access_ranges_eq(
1505                accesses.next().unwrap(),
1506                (
1507                    AccessType::GeometryShaderReadOther,
1508                    image_subresource_range(A::COLOR, 2..3, 0..1),
1509                ),
1510            );
1511            assert_access_ranges_eq(
1512                accesses.next().unwrap(),
1513                (
1514                    AccessType::VertexBuffer,
1515                    image_subresource_range(A::COLOR, 2..3, 1..2),
1516                ),
1517            );
1518            assert_access_ranges_eq(
1519                accesses.next().unwrap(),
1520                (
1521                    AccessType::GeometryShaderReadOther,
1522                    image_subresource_range(A::COLOR, 2..3, 2..3),
1523                ),
1524            );
1525            assert!(accesses.next().is_none());
1526        }
1527    }
1528
1529    #[test]
1530    pub fn image_access_layers() {
1531        use vk::ImageAspectFlags as A;
1532
1533        let mut image = ImageAccess::new(
1534            image_subresource(vk::Format::R8G8B8A8_UNORM, 3, 1),
1535            AccessType::Nothing,
1536        );
1537
1538        {
1539            let mut accesses = ImageAccessIter::new(
1540                &mut image,
1541                AccessType::AnyShaderWrite,
1542                image_subresource_range(A::COLOR, 0..3, 0..1),
1543            );
1544
1545            assert_access_ranges_eq(
1546                accesses.next().unwrap(),
1547                (
1548                    AccessType::Nothing,
1549                    image_subresource_range(A::COLOR, 0..3, 0..1),
1550                ),
1551            );
1552            assert!(accesses.next().is_none());
1553        }
1554
1555        {
1556            let mut accesses = ImageAccessIter::new(
1557                &mut image,
1558                AccessType::AnyShaderReadOther,
1559                image_subresource_range(A::COLOR, 2..3, 0..1),
1560            );
1561
1562            assert_access_ranges_eq(
1563                accesses.next().unwrap(),
1564                (
1565                    AccessType::AnyShaderWrite,
1566                    image_subresource_range(A::COLOR, 2..3, 0..1),
1567                ),
1568            );
1569            assert!(accesses.next().is_none());
1570        }
1571
1572        {
1573            let mut accesses = ImageAccessIter::new(
1574                &mut image,
1575                AccessType::HostRead,
1576                image_subresource_range(A::COLOR, 0..2, 0..1),
1577            );
1578
1579            assert_access_ranges_eq(
1580                accesses.next().unwrap(),
1581                (
1582                    AccessType::AnyShaderWrite,
1583                    image_subresource_range(A::COLOR, 0..2, 0..1),
1584                ),
1585            );
1586            assert!(accesses.next().is_none());
1587        }
1588
1589        {
1590            let mut accesses = ImageAccessIter::new(
1591                &mut image,
1592                AccessType::AnyShaderReadOther,
1593                image_subresource_range(A::COLOR, 0..1, 0..1),
1594            );
1595
1596            assert_access_ranges_eq(
1597                accesses.next().unwrap(),
1598                (
1599                    AccessType::HostRead,
1600                    image_subresource_range(A::COLOR, 0..1, 0..1),
1601                ),
1602            );
1603            assert!(accesses.next().is_none());
1604        }
1605
1606        {
1607            let mut accesses = ImageAccessIter::new(
1608                &mut image,
1609                AccessType::AnyShaderReadOther,
1610                image_subresource_range(A::COLOR, 1..2, 0..1),
1611            );
1612
1613            assert_access_ranges_eq(
1614                accesses.next().unwrap(),
1615                (
1616                    AccessType::HostRead,
1617                    image_subresource_range(A::COLOR, 1..2, 0..1),
1618                ),
1619            );
1620            assert!(accesses.next().is_none());
1621        }
1622
1623        {
1624            let mut accesses = ImageAccessIter::new(
1625                &mut image,
1626                AccessType::HostWrite,
1627                image_subresource_range(A::COLOR, 0..3, 0..1),
1628            );
1629
1630            assert_access_ranges_eq(
1631                accesses.next().unwrap(),
1632                (
1633                    AccessType::AnyShaderReadOther,
1634                    image_subresource_range(A::COLOR, 0..3, 0..1),
1635                ),
1636            );
1637            assert!(accesses.next().is_none());
1638        }
1639    }
1640
1641    #[test]
1642    pub fn image_access_levels() {
1643        use vk::ImageAspectFlags as A;
1644
1645        let mut image = ImageAccess::new(
1646            image_subresource(vk::Format::R8G8B8A8_UNORM, 1, 3),
1647            AccessType::Nothing,
1648        );
1649
1650        {
1651            let mut accesses = ImageAccessIter::new(
1652                &mut image,
1653                AccessType::AnyShaderWrite,
1654                image_subresource_range(A::COLOR, 0..1, 0..3),
1655            );
1656
1657            assert_access_ranges_eq(
1658                accesses.next().unwrap(),
1659                (
1660                    AccessType::Nothing,
1661                    image_subresource_range(A::COLOR, 0..1, 0..3),
1662                ),
1663            );
1664            assert!(accesses.next().is_none());
1665        }
1666
1667        {
1668            let mut accesses = ImageAccessIter::new(
1669                &mut image,
1670                AccessType::AnyShaderReadOther,
1671                image_subresource_range(A::COLOR, 0..1, 2..3),
1672            );
1673
1674            assert_access_ranges_eq(
1675                accesses.next().unwrap(),
1676                (
1677                    AccessType::AnyShaderWrite,
1678                    image_subresource_range(A::COLOR, 0..1, 2..3),
1679                ),
1680            );
1681            assert!(accesses.next().is_none());
1682        }
1683
1684        {
1685            let mut accesses = ImageAccessIter::new(
1686                &mut image,
1687                AccessType::HostRead,
1688                image_subresource_range(A::COLOR, 0..1, 0..2),
1689            );
1690
1691            assert_access_ranges_eq(
1692                accesses.next().unwrap(),
1693                (
1694                    AccessType::AnyShaderWrite,
1695                    image_subresource_range(A::COLOR, 0..1, 0..2),
1696                ),
1697            );
1698            assert!(accesses.next().is_none());
1699        }
1700
1701        {
1702            let mut accesses = ImageAccessIter::new(
1703                &mut image,
1704                AccessType::AnyShaderReadOther,
1705                image_subresource_range(A::COLOR, 0..1, 0..1),
1706            );
1707
1708            assert_access_ranges_eq(
1709                accesses.next().unwrap(),
1710                (
1711                    AccessType::HostRead,
1712                    image_subresource_range(A::COLOR, 0..1, 0..1),
1713                ),
1714            );
1715            assert!(accesses.next().is_none());
1716        }
1717
1718        {
1719            let mut accesses = ImageAccessIter::new(
1720                &mut image,
1721                AccessType::AnyShaderReadOther,
1722                image_subresource_range(A::COLOR, 0..1, 1..2),
1723            );
1724
1725            assert_access_ranges_eq(
1726                accesses.next().unwrap(),
1727                (
1728                    AccessType::HostRead,
1729                    image_subresource_range(A::COLOR, 0..1, 1..2),
1730                ),
1731            );
1732            assert!(accesses.next().is_none());
1733        }
1734
1735        {
1736            let mut accesses = ImageAccessIter::new(
1737                &mut image,
1738                AccessType::HostWrite,
1739                image_subresource_range(A::COLOR, 0..1, 0..3),
1740            );
1741
1742            assert_access_ranges_eq(
1743                accesses.next().unwrap(),
1744                (
1745                    AccessType::AnyShaderReadOther,
1746                    image_subresource_range(A::COLOR, 0..1, 0..3),
1747                ),
1748            );
1749            assert!(accesses.next().is_none());
1750        }
1751    }
1752
1753    #[test]
1754    pub fn image_access_depth_stencil() {
1755        use vk::ImageAspectFlags as A;
1756
1757        let mut image = ImageAccess::new(
1758            image_subresource(vk::Format::D24_UNORM_S8_UINT, 4, 3),
1759            AccessType::Nothing,
1760        );
1761
1762        {
1763            let mut accesses = ImageAccessIter::new(
1764                &mut image,
1765                AccessType::AnyShaderWrite,
1766                image_subresource_range(A::DEPTH, 0..4, 0..1),
1767            );
1768
1769            assert_access_ranges_eq(
1770                accesses.next().unwrap(),
1771                (
1772                    AccessType::Nothing,
1773                    image_subresource_range(A::DEPTH, 0..4, 0..1),
1774                ),
1775            );
1776            assert!(accesses.next().is_none());
1777        }
1778
1779        {
1780            let mut accesses = ImageAccessIter::new(
1781                &mut image,
1782                AccessType::AnyShaderWrite,
1783                image_subresource_range(A::STENCIL, 0..4, 1..2),
1784            );
1785
1786            assert_access_ranges_eq(
1787                accesses.next().unwrap(),
1788                (
1789                    AccessType::Nothing,
1790                    image_subresource_range(A::STENCIL, 0..4, 1..2),
1791                ),
1792            );
1793            assert!(accesses.next().is_none());
1794        }
1795
1796        {
1797            let mut accesses = ImageAccessIter::new(
1798                &mut image,
1799                AccessType::AnyShaderReadOther,
1800                image_subresource_range(A::DEPTH | A::STENCIL, 0..4, 0..2),
1801            );
1802
1803            assert_access_ranges_eq(
1804                accesses.next().unwrap(),
1805                (
1806                    AccessType::AnyShaderWrite,
1807                    image_subresource_range(A::DEPTH, 0..1, 0..1),
1808                ),
1809            );
1810            assert_access_ranges_eq(
1811                accesses.next().unwrap(),
1812                (
1813                    AccessType::Nothing,
1814                    image_subresource_range(A::DEPTH, 0..1, 1..2),
1815                ),
1816            );
1817            assert_access_ranges_eq(
1818                accesses.next().unwrap(),
1819                (
1820                    AccessType::AnyShaderWrite,
1821                    image_subresource_range(A::DEPTH, 1..2, 0..1),
1822                ),
1823            );
1824            assert_access_ranges_eq(
1825                accesses.next().unwrap(),
1826                (
1827                    AccessType::Nothing,
1828                    image_subresource_range(A::DEPTH, 1..2, 1..2),
1829                ),
1830            );
1831            assert_access_ranges_eq(
1832                accesses.next().unwrap(),
1833                (
1834                    AccessType::AnyShaderWrite,
1835                    image_subresource_range(A::DEPTH, 2..3, 0..1),
1836                ),
1837            );
1838            assert_access_ranges_eq(
1839                accesses.next().unwrap(),
1840                (
1841                    AccessType::Nothing,
1842                    image_subresource_range(A::DEPTH, 2..3, 1..2),
1843                ),
1844            );
1845            assert_access_ranges_eq(
1846                accesses.next().unwrap(),
1847                (
1848                    AccessType::AnyShaderWrite,
1849                    image_subresource_range(A::DEPTH, 3..4, 0..1),
1850                ),
1851            );
1852            assert_access_ranges_eq(
1853                accesses.next().unwrap(),
1854                (
1855                    AccessType::Nothing,
1856                    image_subresource_range(A::DEPTH, 3..4, 1..2),
1857                ),
1858            );
1859            assert_access_ranges_eq(
1860                accesses.next().unwrap(),
1861                (
1862                    AccessType::Nothing,
1863                    image_subresource_range(A::STENCIL, 0..1, 0..1),
1864                ),
1865            );
1866            assert_access_ranges_eq(
1867                accesses.next().unwrap(),
1868                (
1869                    AccessType::AnyShaderWrite,
1870                    image_subresource_range(A::STENCIL, 0..1, 1..2),
1871                ),
1872            );
1873            assert_access_ranges_eq(
1874                accesses.next().unwrap(),
1875                (
1876                    AccessType::Nothing,
1877                    image_subresource_range(A::STENCIL, 1..2, 0..1),
1878                ),
1879            );
1880            assert_access_ranges_eq(
1881                accesses.next().unwrap(),
1882                (
1883                    AccessType::AnyShaderWrite,
1884                    image_subresource_range(A::STENCIL, 1..2, 1..2),
1885                ),
1886            );
1887            assert_access_ranges_eq(
1888                accesses.next().unwrap(),
1889                (
1890                    AccessType::Nothing,
1891                    image_subresource_range(A::STENCIL, 2..3, 0..1),
1892                ),
1893            );
1894            assert_access_ranges_eq(
1895                accesses.next().unwrap(),
1896                (
1897                    AccessType::AnyShaderWrite,
1898                    image_subresource_range(A::STENCIL, 2..3, 1..2),
1899                ),
1900            );
1901            assert_access_ranges_eq(
1902                accesses.next().unwrap(),
1903                (
1904                    AccessType::Nothing,
1905                    image_subresource_range(A::STENCIL, 3..4, 0..1),
1906                ),
1907            );
1908            assert_access_ranges_eq(
1909                accesses.next().unwrap(),
1910                (
1911                    AccessType::AnyShaderWrite,
1912                    image_subresource_range(A::STENCIL, 3..4, 1..2),
1913                ),
1914            );
1915            assert!(accesses.next().is_none());
1916        }
1917
1918        {
1919            let mut accesses = ImageAccessIter::new(
1920                &mut image,
1921                AccessType::AccelerationStructureBuildWrite,
1922                image_subresource_range(A::DEPTH | A::STENCIL, 0..4, 0..2),
1923            );
1924
1925            assert_access_ranges_eq(
1926                accesses.next().unwrap(),
1927                (
1928                    AccessType::AnyShaderReadOther,
1929                    image_subresource_range(A::DEPTH | A::STENCIL, 0..4, 0..2),
1930                ),
1931            );
1932            assert!(accesses.next().is_none());
1933        }
1934
1935        {
1936            let mut accesses = ImageAccessIter::new(
1937                &mut image,
1938                AccessType::AccelerationStructureBuildRead,
1939                image_subresource_range(A::DEPTH, 1..3, 0..2),
1940            );
1941
1942            assert_access_ranges_eq(
1943                accesses.next().unwrap(),
1944                (
1945                    AccessType::AccelerationStructureBuildWrite,
1946                    image_subresource_range(A::DEPTH, 1..3, 0..2),
1947                ),
1948            );
1949            assert!(accesses.next().is_none());
1950        }
1951    }
1952
1953    #[test]
1954    pub fn image_access_stencil() {
1955        use vk::ImageAspectFlags as A;
1956
1957        let mut image = ImageAccess::new(
1958            image_subresource(vk::Format::S8_UINT, 2, 2),
1959            AccessType::Nothing,
1960        );
1961
1962        {
1963            let mut accesses = ImageAccessIter::new(
1964                &mut image,
1965                AccessType::AnyShaderWrite,
1966                image_subresource_range(A::STENCIL, 0..2, 0..1),
1967            );
1968
1969            assert_access_ranges_eq(
1970                accesses.next().unwrap(),
1971                (
1972                    AccessType::Nothing,
1973                    image_subresource_range(A::STENCIL, 0..2, 0..1),
1974                ),
1975            );
1976            assert!(accesses.next().is_none());
1977        }
1978
1979        {
1980            let mut accesses = ImageAccessIter::new(
1981                &mut image,
1982                AccessType::AnyShaderReadOther,
1983                image_subresource_range(A::STENCIL, 0..2, 1..2),
1984            );
1985
1986            assert_access_ranges_eq(
1987                accesses.next().unwrap(),
1988                (
1989                    AccessType::Nothing,
1990                    image_subresource_range(A::STENCIL, 0..2, 1..2),
1991                ),
1992            );
1993            assert!(accesses.next().is_none());
1994        }
1995
1996        {
1997            let mut accesses = ImageAccessIter::new(
1998                &mut image,
1999                AccessType::HostRead,
2000                image_subresource_range(A::STENCIL, 0..2, 0..2),
2001            );
2002
2003            assert_access_ranges_eq(
2004                accesses.next().unwrap(),
2005                (
2006                    AccessType::AnyShaderWrite,
2007                    image_subresource_range(A::STENCIL, 0..1, 0..1),
2008                ),
2009            );
2010            assert_access_ranges_eq(
2011                accesses.next().unwrap(),
2012                (
2013                    AccessType::AnyShaderReadOther,
2014                    image_subresource_range(A::STENCIL, 0..1, 1..2),
2015                ),
2016            );
2017            assert_access_ranges_eq(
2018                accesses.next().unwrap(),
2019                (
2020                    AccessType::AnyShaderWrite,
2021                    image_subresource_range(A::STENCIL, 1..2, 0..1),
2022                ),
2023            );
2024            assert_access_ranges_eq(
2025                accesses.next().unwrap(),
2026                (
2027                    AccessType::AnyShaderReadOther,
2028                    image_subresource_range(A::STENCIL, 1..2, 1..2),
2029                ),
2030            );
2031            assert!(accesses.next().is_none());
2032        }
2033    }
2034
2035    #[test]
2036    pub fn image_info_cube() {
2037        let info = ImageInfo::cube(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
2038        let builder = info.to_builder().build();
2039
2040        assert_eq!(info, builder);
2041    }
2042
2043    #[test]
2044    pub fn image_info_cube_builder() {
2045        let info = ImageInfo::cube(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
2046        let builder = ImageInfoBuilder::default()
2047            .ty(vk::ImageType::TYPE_2D)
2048            .fmt(vk::Format::R32_SFLOAT)
2049            .width(42)
2050            .height(42)
2051            .depth(1)
2052            .array_layer_count(6)
2053            .flags(vk::ImageCreateFlags::CUBE_COMPATIBLE)
2054            .build();
2055
2056        assert_eq!(info, builder);
2057    }
2058
2059    #[test]
2060    pub fn image_info_image_1d() {
2061        let info = ImageInfo::image_1d(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
2062        let builder = info.to_builder().build();
2063
2064        assert_eq!(info, builder);
2065    }
2066
2067    #[test]
2068    pub fn image_info_image_1d_builder() {
2069        let info = ImageInfo::image_1d(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
2070        let builder = ImageInfoBuilder::default()
2071            .ty(vk::ImageType::TYPE_1D)
2072            .fmt(vk::Format::R32_SFLOAT)
2073            .width(42)
2074            .height(1)
2075            .depth(1)
2076            .build();
2077
2078        assert_eq!(info, builder);
2079    }
2080
2081    #[test]
2082    pub fn image_info_image_2d() {
2083        let info =
2084            ImageInfo::image_2d(42, 84, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
2085        let builder = info.to_builder().build();
2086
2087        assert_eq!(info, builder);
2088    }
2089
2090    #[test]
2091    pub fn image_info_image_2d_builder() {
2092        let info =
2093            ImageInfo::image_2d(42, 84, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
2094        let builder = ImageInfoBuilder::default()
2095            .ty(vk::ImageType::TYPE_2D)
2096            .fmt(vk::Format::R32_SFLOAT)
2097            .width(42)
2098            .height(84)
2099            .depth(1)
2100            .build();
2101
2102        assert_eq!(info, builder);
2103    }
2104
2105    #[test]
2106    pub fn image_info_image_2d_array() {
2107        let info = ImageInfo::image_2d_array(
2108            42,
2109            84,
2110            100,
2111            vk::Format::default(),
2112            vk::ImageUsageFlags::empty(),
2113        );
2114        let builder = info.to_builder().build();
2115
2116        assert_eq!(info, builder);
2117    }
2118
2119    #[test]
2120    pub fn image_info_image_2d_array_builder() {
2121        let info = ImageInfo::image_2d_array(
2122            42,
2123            84,
2124            100,
2125            vk::Format::R32_SFLOAT,
2126            vk::ImageUsageFlags::empty(),
2127        );
2128        let builder = ImageInfoBuilder::default()
2129            .ty(vk::ImageType::TYPE_2D)
2130            .fmt(vk::Format::R32_SFLOAT)
2131            .width(42)
2132            .height(84)
2133            .depth(1)
2134            .array_layer_count(100)
2135            .build();
2136
2137        assert_eq!(info, builder);
2138    }
2139
2140    #[test]
2141    pub fn image_info_image_3d() {
2142        let info = ImageInfo::image_3d(
2143            42,
2144            84,
2145            100,
2146            vk::Format::R32_SFLOAT,
2147            vk::ImageUsageFlags::empty(),
2148        );
2149        let builder = info.to_builder().build();
2150
2151        assert_eq!(info, builder);
2152    }
2153
2154    #[test]
2155    pub fn image_info_image_3d_builder() {
2156        let info = ImageInfo::image_3d(
2157            42,
2158            84,
2159            100,
2160            vk::Format::R32_SFLOAT,
2161            vk::ImageUsageFlags::empty(),
2162        );
2163        let builder = ImageInfoBuilder::default()
2164            .ty(vk::ImageType::TYPE_3D)
2165            .fmt(vk::Format::R32_SFLOAT)
2166            .width(42)
2167            .height(84)
2168            .depth(100)
2169            .build();
2170
2171        assert_eq!(info, builder);
2172    }
2173
2174    #[test]
2175    #[should_panic(expected = "Field not initialized: depth")]
2176    pub fn image_info_builder_uninit_depth() {
2177        ImageInfoBuilder::default().build();
2178    }
2179
2180    #[test]
2181    #[should_panic(expected = "Field not initialized: fmt")]
2182    pub fn image_info_builder_uninit_fmt() {
2183        ImageInfoBuilder::default().depth(1).build();
2184    }
2185
2186    #[test]
2187    #[should_panic(expected = "Field not initialized: height")]
2188    pub fn image_info_builder_uninit_height() {
2189        ImageInfoBuilder::default()
2190            .depth(1)
2191            .fmt(vk::Format::default())
2192            .build();
2193    }
2194
2195    #[test]
2196    #[should_panic(expected = "Field not initialized: ty")]
2197    pub fn image_info_builder_uninit_ty() {
2198        ImageInfoBuilder::default()
2199            .depth(1)
2200            .fmt(vk::Format::default())
2201            .height(2)
2202            .build();
2203    }
2204
2205    #[test]
2206    #[should_panic(expected = "Field not initialized: width")]
2207    pub fn image_info_builder_uninit_width() {
2208        ImageInfoBuilder::default()
2209            .depth(1)
2210            .fmt(vk::Format::default())
2211            .height(2)
2212            .ty(vk::ImageType::TYPE_2D)
2213            .build();
2214    }
2215
2216    fn image_subresource(
2217        fmt: vk::Format,
2218        array_layer_count: u32,
2219        mip_level_count: u32,
2220    ) -> ImageInfo {
2221        ImageInfo::image_2d(1, 1, fmt, vk::ImageUsageFlags::empty())
2222            .to_builder()
2223            .array_layer_count(array_layer_count)
2224            .mip_level_count(mip_level_count)
2225            .build()
2226    }
2227
2228    fn image_subresource_range(
2229        aspect_mask: vk::ImageAspectFlags,
2230        array_layers: Range<u32>,
2231        mip_levels: Range<u32>,
2232    ) -> vk::ImageSubresourceRange {
2233        vk::ImageSubresourceRange {
2234            aspect_mask,
2235            base_array_layer: array_layers.start,
2236            base_mip_level: mip_levels.start,
2237            layer_count: array_layers.len() as _,
2238            level_count: mip_levels.len() as _,
2239        }
2240    }
2241
2242    #[test]
2243    pub fn image_subresource_range_contains() {
2244        use {
2245            super::image_subresource_range_contains as f, image_subresource_range as i,
2246            vk::ImageAspectFlags as A,
2247        };
2248
2249        assert!(f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 0..1, 0..1)));
2250        assert!(f(i(A::COLOR, 0..2, 0..1), i(A::COLOR, 0..1, 0..1)));
2251        assert!(f(i(A::COLOR, 0..1, 0..2), i(A::COLOR, 0..1, 0..1)));
2252        assert!(f(i(A::COLOR, 0..2, 0..2), i(A::COLOR, 0..1, 0..1)));
2253        assert!(!f(i(A::COLOR, 0..1, 1..3), i(A::COLOR, 0..1, 0..1)));
2254        assert!(!f(i(A::COLOR, 1..3, 0..1), i(A::COLOR, 0..1, 0..1)));
2255        assert!(!f(i(A::COLOR, 0..1, 1..3), i(A::COLOR, 0..1, 0..2)));
2256        assert!(!f(i(A::COLOR, 1..3, 0..1), i(A::COLOR, 0..2, 0..1)));
2257    }
2258
2259    #[test]
2260    pub fn image_subresource_range_intersects() {
2261        use {
2262            super::image_subresource_range_intersects as f, image_subresource_range as i,
2263            vk::ImageAspectFlags as A,
2264        };
2265
2266        assert!(f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 0..1, 0..1)));
2267        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::DEPTH, 0..1, 0..1)));
2268
2269        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 1..2, 0..1)));
2270        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 0..1, 1..2)));
2271        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::DEPTH, 1..2, 0..1)));
2272        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::DEPTH, 0..1, 1..2)));
2273        assert!(!f(i(A::COLOR, 1..2, 1..2), i(A::COLOR, 0..1, 0..1)));
2274
2275        assert!(f(
2276            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
2277            i(A::DEPTH, 2..3, 2..4)
2278        ));
2279        assert!(f(
2280            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
2281            i(A::DEPTH, 2..3, 4..6)
2282        ));
2283        assert!(!f(
2284            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
2285            i(A::DEPTH, 2..3, 2..3)
2286        ));
2287        assert!(!f(
2288            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
2289            i(A::DEPTH, 2..3, 5..6)
2290        ));
2291    }
2292
2293    #[test]
2294    pub fn image_view_info() {
2295        let info = ImageViewInfo::new(vk::Format::default(), vk::ImageViewType::TYPE_1D);
2296        let builder = info.to_builder().build();
2297
2298        assert_eq!(info, builder);
2299    }
2300
2301    #[test]
2302    pub fn image_view_info_builder() {
2303        let info = ImageViewInfo::new(vk::Format::default(), vk::ImageViewType::TYPE_1D);
2304        let builder = ImageViewInfoBuilder::default()
2305            .fmt(vk::Format::default())
2306            .ty(vk::ImageViewType::TYPE_1D)
2307            .aspect_mask(vk::ImageAspectFlags::COLOR)
2308            .build();
2309
2310        assert_eq!(info, builder);
2311    }
2312
2313    #[test]
2314    #[should_panic(expected = "Field not initialized: aspect_mask")]
2315    pub fn image_view_info_builder_uninit_aspect_mask() {
2316        ImageViewInfoBuilder::default().build();
2317    }
2318
2319    #[test]
2320    #[should_panic(expected = "Field not initialized: fmt")]
2321    pub fn image_view_info_builder_unint_fmt() {
2322        ImageViewInfoBuilder::default()
2323            .aspect_mask(vk::ImageAspectFlags::empty())
2324            .build();
2325    }
2326
2327    #[test]
2328    #[should_panic(expected = "Field not initialized: ty")]
2329    pub fn image_view_info_builder_unint_ty() {
2330        ImageViewInfoBuilder::default()
2331            .aspect_mask(vk::ImageAspectFlags::empty())
2332            .fmt(vk::Format::default())
2333            .build();
2334    }
2335}