Skip to main content

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