Skip to main content

vk_graph/driver/
image.rs

1//! Image resource types
2
3use {
4    super::{
5        DriverError, SharingMode, access_type_from_u8, access_type_into_u8, device::Device,
6        format_aspect_mask, pipeline_stage_access_flags,
7    },
8    ash::vk::{self, ImageCreateInfo},
9    derive_builder::Builder,
10    gpu_allocator::{
11        MemoryLocation,
12        vulkan::{Allocation, AllocationCreateDesc, AllocationScheme},
13    },
14    log::{trace, warn},
15    std::{
16        collections::{HashMap, hash_map::Entry},
17        fmt::{Debug, Formatter},
18        marker::PhantomData,
19        mem::{replace, take},
20        ops::{Deref, DerefMut},
21        sync::atomic::{AtomicU8, AtomicU16, AtomicU64, Ordering},
22        thread::panicking,
23    },
24    vk_sync::AccessType,
25};
26
27#[cfg(feature = "parking_lot")]
28use parking_lot::{Mutex, MutexGuard};
29
30#[cfg(not(feature = "parking_lot"))]
31use std::sync::{Mutex, MutexGuard};
32
33const fn access_type_to_layout(access: AccessType) -> Option<vk::ImageLayout> {
34    match access {
35        AccessType::Nothing => None,
36        AccessType::ColorAttachmentRead
37        | AccessType::ColorAttachmentReadWrite
38        | AccessType::ColorAttachmentWrite => Some(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL),
39        AccessType::DepthStencilAttachmentRead => {
40            Some(vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL)
41        }
42        AccessType::DepthStencilAttachmentReadWrite | AccessType::DepthStencilAttachmentWrite => {
43            Some(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
44        }
45        AccessType::DepthAttachmentWriteStencilReadOnly => {
46            Some(vk::ImageLayout::DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL)
47        }
48        AccessType::StencilAttachmentWriteDepthReadOnly => {
49            Some(vk::ImageLayout::DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL)
50        }
51        AccessType::TransferRead => Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
52        AccessType::TransferWrite => Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
53        AccessType::VertexShaderReadSampledImageOrUniformTexelBuffer
54        | AccessType::FragmentShaderReadSampledImageOrUniformTexelBuffer
55        | AccessType::FragmentShaderReadColorInputAttachment
56        | AccessType::ComputeShaderReadSampledImageOrUniformTexelBuffer
57        | AccessType::TessellationControlShaderReadSampledImageOrUniformTexelBuffer
58        | AccessType::TessellationEvaluationShaderReadSampledImageOrUniformTexelBuffer
59        | AccessType::GeometryShaderReadSampledImageOrUniformTexelBuffer
60        | AccessType::AnyShaderReadSampledImageOrUniformTexelBuffer
61        | AccessType::MeshShaderReadSampledImageOrUniformTexelBuffer
62        | AccessType::TaskShaderReadSampledImageOrUniformTexelBuffer => {
63            Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
64        }
65        AccessType::FragmentShaderReadDepthStencilInputAttachment => {
66            Some(vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL)
67        }
68        AccessType::Present => Some(vk::ImageLayout::PRESENT_SRC_KHR),
69        _ => Some(vk::ImageLayout::GENERAL),
70    }
71}
72
73const fn aspect_mask_at_ordinal(
74    aspect_mask: vk::ImageAspectFlags,
75    ordinal: u32,
76) -> vk::ImageAspectFlags {
77    // Common cases:
78    // - COLOR with ordinal 0 -> COLOR
79    // - DEPTH | STENCIL with ordinal 0 -> DEPTH
80    // - DEPTH | STENCIL with ordinal 1 -> STENCIL
81    let mut bits = aspect_mask.as_raw();
82    let mut idx = 0;
83
84    while bits != 0 {
85        let bit = bits.trailing_zeros();
86        if idx == ordinal {
87            return vk::ImageAspectFlags::from_raw(1 << bit);
88        }
89
90        bits &= !(1 << bit);
91        idx += 1;
92    }
93
94    vk::ImageAspectFlags::empty()
95}
96
97const fn aspect_ordinal(aspect_mask: vk::ImageAspectFlags, aspect: vk::ImageAspectFlags) -> u8 {
98    let mut bits = aspect_mask.as_raw();
99    let target = aspect.as_raw();
100    let mut idx = 0;
101
102    while bits != 0 {
103        let bit = bits.trailing_zeros();
104        if target == (1 << bit) {
105            return idx;
106        }
107
108        bits &= !(1 << bit);
109        idx += 1;
110    }
111
112    0
113}
114
115#[cfg(feature = "checked")]
116fn assert_aspect_mask_supported(aspect_mask: vk::ImageAspectFlags) {
117    use vk::ImageAspectFlags as A;
118
119    const COLOR: A = A::COLOR;
120    const DEPTH: A = A::DEPTH;
121    const DEPTH_STENCIL: A = A::from_raw(A::DEPTH.as_raw() | A::STENCIL.as_raw());
122    const STENCIL: A = A::STENCIL;
123
124    assert!(matches!(
125        aspect_mask,
126        COLOR | DEPTH | DEPTH_STENCIL | STENCIL
127    ));
128}
129
130pub(crate) fn image_subresource_range_contains(
131    lhs: vk::ImageSubresourceRange,
132    rhs: vk::ImageSubresourceRange,
133) -> bool {
134    lhs.aspect_mask.contains(rhs.aspect_mask)
135        && lhs.base_array_layer <= rhs.base_array_layer
136        && lhs.base_array_layer + lhs.layer_count >= rhs.base_array_layer + rhs.layer_count
137        && lhs.base_mip_level <= rhs.base_mip_level
138        && lhs.base_mip_level + lhs.level_count >= rhs.base_mip_level + rhs.level_count
139}
140
141pub(crate) fn image_subresource_range_intersection(
142    lhs: vk::ImageSubresourceRange,
143    rhs: vk::ImageSubresourceRange,
144) -> Option<vk::ImageSubresourceRange> {
145    if !image_subresource_range_intersects(lhs, rhs) {
146        return None;
147    }
148
149    let aspect_mask = lhs.aspect_mask & rhs.aspect_mask;
150    let base_array_layer = lhs.base_array_layer.max(rhs.base_array_layer);
151    let end_array_layer =
152        (lhs.base_array_layer + lhs.layer_count).min(rhs.base_array_layer + rhs.layer_count);
153    let base_mip_level = lhs.base_mip_level.max(rhs.base_mip_level);
154    let end_mip_level =
155        (lhs.base_mip_level + lhs.level_count).min(rhs.base_mip_level + rhs.level_count);
156
157    Some(vk::ImageSubresourceRange {
158        aspect_mask,
159        base_array_layer,
160        layer_count: end_array_layer - base_array_layer,
161        base_mip_level,
162        level_count: end_mip_level - base_mip_level,
163    })
164}
165
166pub(crate) fn image_subresource_range_intersects(
167    lhs: vk::ImageSubresourceRange,
168    rhs: vk::ImageSubresourceRange,
169) -> bool {
170    lhs.aspect_mask.intersects(rhs.aspect_mask)
171        && lhs.base_array_layer < rhs.base_array_layer + rhs.layer_count
172        && lhs.base_array_layer + lhs.layer_count > rhs.base_array_layer
173        && lhs.base_mip_level < rhs.base_mip_level + rhs.level_count
174        && lhs.base_mip_level + lhs.level_count > rhs.base_mip_level
175}
176
177#[derive(Debug)]
178enum Access {
179    Dense(DenseAccess),
180    DualAspect(DualAspectAccess),
181    Uniform(UniformAccess),
182}
183
184impl Access {
185    fn new(info: ImageInfo, access: AccessType) -> Self {
186        let aspect_count = format_aspect_mask(info.format).as_raw().count_ones() as u8;
187
188        if aspect_count == 1 && info.array_layer_count == 1 && info.mip_level_count == 1 {
189            Self::Uniform(UniformAccess::new(access))
190        } else if aspect_count == 2 && info.array_layer_count == 1 && info.mip_level_count == 1 {
191            Self::DualAspect(DualAspectAccess::new(access))
192        } else {
193            Self::Dense(DenseAccess::new(access))
194        }
195    }
196
197    fn swap<'a>(
198        &'a self,
199        dense: &'a Mutex<Option<DenseMap<AccessType>>>,
200        info: ImageInfo,
201        next_access: AccessType,
202        access_range: vk::ImageSubresourceRange,
203    ) -> AccessIter<'a> {
204        match self {
205            Self::Uniform(uniform) => {
206                AccessIter::Uniform(Some(uniform.swap(next_access, access_range)))
207            }
208            Self::DualAspect(dual) => AccessIter::DualAspect(DualAspectAccessIter::new(
209                dual,
210                info,
211                next_access,
212                access_range,
213            )),
214            Self::Dense(access) => {
215                if !access.uses_dense() && info.is_full_subresource_range(access_range) {
216                    return AccessIter::Uniform(Some(access.swap_range(next_access, access_range)));
217                }
218
219                let mut dense = dense.lock();
220
221                #[cfg(not(feature = "parking_lot"))]
222                let mut dense = dense.expect("poisoned image dense lock");
223
224                access.ensure_dense(&mut dense, info);
225
226                AccessIter::DenseMap(DenseMapIter::new(
227                    DenseAccessMapGuard { access, dense },
228                    next_access,
229                    access_range,
230                ))
231            }
232        }
233    }
234}
235
236enum AccessIter<'a> {
237    DenseMap(DenseMapIter<'a, DenseAccessMapGuard<'a>, AccessType>),
238    DualAspect(DualAspectAccessIter<'a>),
239    Uniform(Option<(AccessType, vk::ImageSubresourceRange)>),
240}
241
242impl Drop for AccessIter<'_> {
243    fn drop(&mut self) {
244        while self.next().is_some() {}
245    }
246}
247
248impl Iterator for AccessIter<'_> {
249    type Item = (AccessType, vk::ImageSubresourceRange);
250
251    fn next(&mut self) -> Option<Self::Item> {
252        match self {
253            Self::DenseMap(iter) => iter.next(),
254            Self::DualAspect(iter) => iter.next(),
255            Self::Uniform(item) => item.take(),
256        }
257    }
258}
259
260#[derive(Debug)]
261struct DenseAccess(AtomicU16);
262
263impl DenseAccess {
264    const ACCESS_MASK: u16 = 0x00_FF;
265    const STATE_MASK: u16 = 0xFF_00;
266    const STATE_SHIFT: u16 = 8;
267
268    fn new(access: AccessType) -> Self {
269        Self(AtomicU16::new(
270            (DenseAccessState::Uniform as u16) << Self::STATE_SHIFT
271                | access_type_into_u8(access) as u16,
272        ))
273    }
274
275    fn ensure_dense(&self, dense: &mut Option<DenseMap<AccessType>>, info: ImageInfo) {
276        if self.is_dense_active() {
277            debug_assert!(dense.is_some());
278            return;
279        }
280
281        self.set_promoting();
282        let current = self.load();
283        *dense = Some(DenseMap::new(info, current));
284        self.set_dense();
285    }
286
287    fn is_dense_active(&self) -> bool {
288        self.state() == DenseAccessState::Dense
289    }
290
291    fn load(&self) -> AccessType {
292        access_type_from_u8((self.0.load(Ordering::Acquire) & Self::ACCESS_MASK) as u8)
293    }
294
295    fn set_dense(&self) {
296        let current = self.0.load(Ordering::Acquire);
297        self.0.store(
298            (current & !Self::STATE_MASK) | (DenseAccessState::Dense as u16) << Self::STATE_SHIFT,
299            Ordering::Release,
300        );
301    }
302
303    fn set_promoting(&self) {
304        let current = self.0.load(Ordering::Acquire);
305        self.0.store(
306            (current & !Self::STATE_MASK)
307                | (DenseAccessState::Promoting as u16) << Self::STATE_SHIFT,
308            Ordering::Release,
309        );
310    }
311
312    fn set_uniform(&self, next_access: AccessType) {
313        self.0.store(
314            (DenseAccessState::Uniform as u16) << Self::STATE_SHIFT
315                | access_type_into_u8(next_access) as u16,
316            Ordering::Release,
317        );
318    }
319
320    fn state(&self) -> DenseAccessState {
321        match (self.0.load(Ordering::Acquire) >> Self::STATE_SHIFT) as u8 {
322            0 => DenseAccessState::Uniform,
323            1 => DenseAccessState::Promoting,
324            2 => DenseAccessState::Dense,
325            _ => unreachable!("invalid image dense access state"),
326        }
327    }
328
329    fn swap_range(
330        &self,
331        next_access: AccessType,
332        access_range: vk::ImageSubresourceRange,
333    ) -> (AccessType, vk::ImageSubresourceRange) {
334        let packed = (DenseAccessState::Uniform as u16) << Self::STATE_SHIFT
335            | access_type_into_u8(next_access) as u16;
336        let prev = self.0.swap(packed, Ordering::AcqRel);
337
338        (access_type_from_u8(prev as u8), access_range)
339    }
340
341    fn uses_dense(&self) -> bool {
342        self.state() != DenseAccessState::Uniform
343    }
344}
345
346struct DenseAccessMapGuard<'a> {
347    access: &'a DenseAccess,
348    dense: MutexGuard<'a, Option<DenseMap<AccessType>>>,
349}
350
351impl DenseAccessMapGuard<'_> {
352    fn try_demote_to_uniform(&mut self) {
353        let DenseAccessState::Dense = self.access.state() else {
354            return;
355        };
356
357        let dense_map = self.dense.as_ref().expect("missing dense access state");
358        let Some(access) = dense_map.uniform_value() else {
359            return;
360        };
361
362        *self.dense = None;
363        self.access.set_uniform(access);
364    }
365}
366
367impl Deref for DenseAccessMapGuard<'_> {
368    type Target = DenseMap<AccessType>;
369
370    fn deref(&self) -> &Self::Target {
371        self.dense.as_ref().expect("missing dense access state")
372    }
373}
374
375impl DerefMut for DenseAccessMapGuard<'_> {
376    fn deref_mut(&mut self) -> &mut Self::Target {
377        self.dense.as_mut().expect("missing dense access state")
378    }
379}
380
381impl Drop for DenseAccessMapGuard<'_> {
382    fn drop(&mut self) {
383        self.try_demote_to_uniform();
384    }
385}
386
387#[repr(u8)]
388#[derive(Clone, Copy, Debug, Eq, PartialEq)]
389enum DenseAccessState {
390    Uniform = 0,
391    Promoting = 1,
392    Dense = 2,
393}
394
395#[derive(Debug)]
396pub(crate) struct DenseMap<V> {
397    #[cfg(feature = "checked")]
398    array_layer_count: u32,
399
400    aspect_count: u8,
401    mip_level_count: u32,
402    values: Box<[V]>,
403}
404
405impl<V> DenseMap<V> {
406    fn base_aspect_ordinal(&self, base_aspect_bit: u8) -> u8 {
407        let stencil_bit = vk::ImageAspectFlags::STENCIL.as_raw().trailing_zeros() as u8;
408
409        // DenseMap stores depth/stencil aspects as compact ordinals: depth = 0, stencil = 1
410        (self.aspect_count == 2 && base_aspect_bit == stencil_bit) as u8
411    }
412
413    fn idx(&self, aspect: u8, array_layer: u32, mip_level: u32) -> usize {
414        let idx = (array_layer * self.aspect_count as u32 * self.mip_level_count
415            + mip_level * self.aspect_count as u32
416            + aspect as u32) as _;
417
418        #[cfg(feature = "checked")]
419        assert!(
420            idx < self.values.len(),
421            "idx={idx}, aspect={aspect}, layer={array_layer}, mip={mip_level}, aspect_count={}, mip_level_count={}, array_layer_count={}, len={}",
422            self.aspect_count,
423            self.mip_level_count,
424            self.array_layer_count,
425            self.values.len(),
426        );
427
428        idx
429    }
430}
431
432impl<V: Copy> DenseMap<V> {
433    pub(crate) fn new(info: ImageInfo, value: V) -> Self {
434        let aspect_mask = format_aspect_mask(info.format);
435
436        #[cfg(feature = "checked")]
437        assert_aspect_mask_supported(aspect_mask);
438
439        let aspect_count = aspect_mask.as_raw().count_ones() as u8;
440        let array_layer_count = info.array_layer_count;
441        let mip_level_count = info.mip_level_count;
442
443        Self {
444            aspect_count,
445            mip_level_count,
446            values: vec![value; (aspect_count as u32 * array_layer_count * mip_level_count) as _]
447                .into_boxed_slice(),
448
449            #[cfg(feature = "checked")]
450            array_layer_count,
451        }
452    }
453
454    fn subresource(&self, aspect: u8, array_layer: u32, mip_level: u32) -> V {
455        self.values[self.idx(aspect, array_layer, mip_level)]
456    }
457}
458
459impl<V: Copy + PartialEq> DenseMap<V> {
460    pub(crate) fn swap(
461        &mut self,
462        value: V,
463        range: vk::ImageSubresourceRange,
464    ) -> DenseMapIter<'_, &mut Self, V> {
465        DenseMapIter::new(self, value, range)
466    }
467
468    fn uniform_value(&self) -> Option<V> {
469        let mut iter = self.values.iter().copied();
470        let first = iter.next()?;
471
472        iter.all(|value| value == first).then_some(first)
473    }
474}
475
476struct DenseMapCursor {
477    range: DenseMapRange,
478    array_layer: u32,
479    aspect: u8,
480    mip_level: u32,
481}
482
483impl DenseMapCursor {
484    fn new<V>(map: &DenseMap<V>, range: vk::ImageSubresourceRange) -> Self {
485        #[cfg(feature = "checked")]
486        assert_aspect_mask_supported(range.aspect_mask);
487
488        #[cfg(feature = "checked")]
489        assert!(range.base_array_layer < map.array_layer_count);
490
491        debug_assert!(range.base_mip_level < map.mip_level_count);
492        debug_assert_ne!(range.layer_count, 0);
493        debug_assert_ne!(range.level_count, 0);
494
495        let aspect_count = range.aspect_mask.as_raw().count_ones() as _;
496
497        debug_assert!(aspect_count <= map.aspect_count);
498
499        let base_aspect_bit = range.aspect_mask.as_raw().trailing_zeros() as _;
500
501        Self {
502            array_layer: 0,
503            aspect: 0,
504            mip_level: 0,
505            range: DenseMapRange {
506                aspect_count,
507                base_array_layer: range.base_array_layer,
508                base_aspect_bit,
509                base_mip_level: range.base_mip_level,
510                layer_count: range.layer_count,
511                level_count: range.level_count,
512            },
513        }
514    }
515
516    fn next<V>(&mut self, map: &mut DenseMap<V>, value: V) -> Option<(V, vk::ImageSubresourceRange)>
517    where
518        V: Copy + PartialEq,
519    {
520        if self.aspect == self.range.aspect_count {
521            return None;
522        }
523
524        let mut range = vk::ImageSubresourceRange {
525            aspect_mask: vk::ImageAspectFlags::from_raw(
526                (1 << (self.range.base_aspect_bit + self.aspect)) as _,
527            ),
528            base_array_layer: self.range.base_array_layer + self.array_layer,
529            base_mip_level: self.range.base_mip_level + self.mip_level,
530            layer_count: 1,
531            level_count: 1,
532        };
533
534        let base_aspect_ordinal = map.base_aspect_ordinal(self.range.base_aspect_bit);
535        let prev_value = replace(
536            {
537                let idx = map.idx(
538                    base_aspect_ordinal + self.aspect,
539                    range.base_array_layer,
540                    range.base_mip_level,
541                );
542
543                unsafe { map.values.get_unchecked_mut(idx) }
544            },
545            value,
546        );
547
548        loop {
549            self.mip_level += 1;
550            self.mip_level %= self.range.level_count;
551            if self.mip_level == 0 {
552                break;
553            }
554
555            let idx = map.idx(
556                base_aspect_ordinal + self.aspect,
557                self.range.base_array_layer + self.array_layer,
558                self.range.base_mip_level + self.mip_level,
559            );
560            let next_value = unsafe { map.values.get_unchecked_mut(idx) };
561            if *next_value != prev_value {
562                return Some((prev_value, range));
563            }
564
565            *next_value = value;
566            range.level_count += 1;
567        }
568
569        loop {
570            self.array_layer += 1;
571            self.array_layer %= self.range.layer_count;
572            if self.array_layer == 0 {
573                break;
574            }
575
576            if range.base_mip_level != self.range.base_mip_level {
577                return Some((prev_value, range));
578            }
579
580            let array_layer = self.range.base_array_layer + self.array_layer;
581            let end_mip_level = self.range.base_mip_level + self.range.level_count;
582
583            for mip_level in self.range.base_mip_level..end_mip_level {
584                let idx = map.idx(base_aspect_ordinal + self.aspect, array_layer, mip_level);
585                let next_value = unsafe { *map.values.get_unchecked(idx) };
586                if next_value != prev_value {
587                    return Some((prev_value, range));
588                }
589            }
590
591            for mip_level in self.range.base_mip_level..end_mip_level {
592                let idx = map.idx(base_aspect_ordinal + self.aspect, array_layer, mip_level);
593                let next_value = unsafe { map.values.get_unchecked_mut(idx) };
594                *next_value = value;
595            }
596
597            range.layer_count += 1;
598        }
599
600        loop {
601            self.aspect += 1;
602            if self.aspect == self.range.aspect_count {
603                return Some((prev_value, range));
604            }
605
606            let end_array_layer = self.range.base_array_layer + self.range.layer_count;
607            let end_mip_level = self.range.base_mip_level + self.range.level_count;
608
609            for array_layer in self.range.base_array_layer..end_array_layer {
610                for mip_level in self.range.base_mip_level..end_mip_level {
611                    let idx = map.idx(base_aspect_ordinal + self.aspect, array_layer, mip_level);
612                    let next_value = unsafe { *map.values.get_unchecked(idx) };
613                    if next_value != prev_value {
614                        return Some((prev_value, range));
615                    }
616                }
617            }
618
619            for array_layer in self.range.base_array_layer..end_array_layer {
620                for mip_level in self.range.base_mip_level..end_mip_level {
621                    let idx = map.idx(base_aspect_ordinal + self.aspect, array_layer, mip_level);
622                    let next_value = unsafe { map.values.get_unchecked_mut(idx) };
623                    *next_value = value;
624                }
625            }
626
627            range.aspect_mask = vk::ImageAspectFlags::from_raw(
628                range.aspect_mask.as_raw() | (1 << (self.range.base_aspect_bit + self.aspect)),
629            );
630        }
631    }
632}
633
634pub(crate) struct DenseMapIter<'a, M, V>
635where
636    M: DerefMut<Target = DenseMap<V>>,
637    V: Copy + PartialEq,
638{
639    __: PhantomData<&'a mut DenseMap<V>>,
640    cursor: DenseMapCursor,
641    map: M,
642    value: V,
643}
644
645impl<M, V> Drop for DenseMapIter<'_, M, V>
646where
647    M: DerefMut<Target = DenseMap<V>>,
648    V: Copy + PartialEq,
649{
650    fn drop(&mut self) {
651        while self.next().is_some() {}
652    }
653}
654
655impl<'a, M, V: Copy + PartialEq> DenseMapIter<'a, M, V>
656where
657    M: DerefMut<Target = DenseMap<V>>,
658{
659    fn new(map: M, value: V, range: vk::ImageSubresourceRange) -> Self {
660        let cursor = DenseMapCursor::new(&map, range);
661
662        Self {
663            __: PhantomData,
664            cursor,
665            map,
666            value,
667        }
668    }
669}
670
671impl<'a, M, V: Copy + PartialEq> Iterator for DenseMapIter<'a, M, V>
672where
673    M: DerefMut<Target = DenseMap<V>>,
674{
675    type Item = (V, vk::ImageSubresourceRange);
676
677    fn next(&mut self) -> Option<Self::Item> {
678        self.cursor.next(&mut self.map, self.value)
679    }
680}
681
682#[derive(Copy, Clone)]
683struct DenseMapRange {
684    aspect_count: u8,
685    base_array_layer: u32,
686    base_aspect_bit: u8,
687    base_mip_level: u32,
688    layer_count: u32,
689    level_count: u32,
690}
691
692#[repr(u8)]
693#[derive(Clone, Copy, Debug, Eq, PartialEq)]
694enum DenseSharingState {
695    Idle = 0,
696    Promoting = 1,
697    Dense = 2,
698}
699
700#[derive(Debug)]
701struct DualAspectAccess([AtomicU8; 2]);
702
703impl DualAspectAccess {
704    fn new(access: AccessType) -> Self {
705        let access = access_type_into_u8(access);
706
707        Self([AtomicU8::new(access), AtomicU8::new(access)])
708    }
709
710    fn load(&self, aspect_idx: usize) -> AccessType {
711        access_type_from_u8(self.0[aspect_idx].load(Ordering::Acquire))
712    }
713}
714
715struct DualAspectAccessIter<'a> {
716    dual: &'a DualAspectAccess,
717    format_aspect_mask: vk::ImageAspectFlags,
718    next_access: AccessType,
719    ranges: ImageSubresourceRangeIter,
720}
721
722impl<'a> DualAspectAccessIter<'a> {
723    fn new(
724        dual: &'a DualAspectAccess,
725        info: ImageInfo,
726        next_access: AccessType,
727        access_range: vk::ImageSubresourceRange,
728    ) -> Self {
729        debug_assert_eq!(access_range.base_array_layer, 0);
730        debug_assert_eq!(access_range.base_mip_level, 0);
731        debug_assert_eq!(access_range.layer_count, 1);
732        debug_assert_eq!(access_range.level_count, 1);
733
734        Self {
735            dual,
736            format_aspect_mask: format_aspect_mask(info.format),
737            next_access,
738            ranges: ImageSubresourceRangeIter::new(access_range),
739        }
740    }
741}
742
743impl ExactSizeIterator for DualAspectAccessIter<'_> {
744    fn len(&self) -> usize {
745        self.ranges.len()
746    }
747}
748
749impl Iterator for DualAspectAccessIter<'_> {
750    type Item = (AccessType, vk::ImageSubresourceRange);
751
752    fn next(&mut self) -> Option<Self::Item> {
753        let range = self.ranges.next()?;
754        let aspect_idx = aspect_ordinal(self.format_aspect_mask, range.aspect_mask) as usize;
755        let prev_access = access_type_from_u8(
756            self.dual.0[aspect_idx].swap(access_type_into_u8(self.next_access), Ordering::AcqRel),
757        );
758
759        Some((prev_access, range))
760    }
761
762    fn size_hint(&self) -> (usize, Option<usize>) {
763        self.ranges.size_hint()
764    }
765}
766
767#[derive(Debug)]
768struct ExclusiveSharing {
769    // `promoting` keeps whole-image updates on the dense path while a partial update is
770    // converting uniform tracking into subresource tracking
771    dense_sharing_state: AtomicU8,
772    uniform: AtomicU64,
773}
774
775impl ExclusiveSharing {
776    fn new(_info: ImageInfo) -> Self {
777        let sharing = SharingMode::Exclusive(None);
778
779        Self {
780            uniform: AtomicU64::new(sharing.encode()),
781            dense_sharing_state: AtomicU8::new(0),
782        }
783    }
784
785    fn dense_sharing_state(&self) -> DenseSharingState {
786        match self.dense_sharing_state.load(Ordering::Acquire) {
787            0 => DenseSharingState::Idle,
788            1 => DenseSharingState::Promoting,
789            2 => DenseSharingState::Dense,
790            _ => unreachable!("invalid image dense sharing state"),
791        }
792    }
793
794    fn is_dense_sharing_active(&self) -> bool {
795        self.dense_sharing_state() == DenseSharingState::Dense
796    }
797
798    fn is_promoting_dense_sharing(&self) -> bool {
799        self.dense_sharing_state() == DenseSharingState::Promoting
800    }
801
802    fn uses_dense_sharing(&self) -> bool {
803        self.dense_sharing_state() != DenseSharingState::Idle
804    }
805
806    fn set_promoting_dense_sharing(&self) {
807        self.dense_sharing_state
808            .store(DenseSharingState::Promoting as _, Ordering::Release);
809    }
810
811    fn set_dense_sharing_active(&self) {
812        self.dense_sharing_state
813            .store(DenseSharingState::Dense as _, Ordering::Release);
814    }
815
816    fn set_ranges(
817        &self,
818        dense: &Mutex<Option<DenseMap<SharingMode>>>,
819        info: ImageInfo,
820        sharing: SharingMode,
821        sharing_ranges: &[vk::ImageSubresourceRange],
822    ) {
823        if sharing_ranges.is_empty() {
824            return;
825        }
826
827        if sharing_ranges.len() == 1 && info.is_full_subresource_range(sharing_ranges[0]) {
828            self.set_uniform_or_dense_sharing(dense, info, sharing, sharing_ranges[0]);
829
830            return;
831        }
832
833        self.promote_dense_sharing_and_set_ranges(dense, info, sharing, sharing_ranges);
834    }
835
836    fn set_uniform_or_dense_sharing(
837        &self,
838        dense: &Mutex<Option<DenseMap<SharingMode>>>,
839        _info: ImageInfo,
840        sharing: SharingMode,
841        sharing_range: vk::ImageSubresourceRange,
842    ) {
843        let encoded_sharing = sharing.encode();
844
845        loop {
846            if self.uses_dense_sharing() {
847                let mut dense = dense.lock();
848
849                #[cfg(not(feature = "parking_lot"))]
850                let mut dense = dense.expect("poisoned image dense lock");
851
852                dense
853                    .as_mut()
854                    .expect("missing dense sharing state")
855                    .swap(sharing, sharing_range);
856
857                return;
858            }
859
860            let current = self.uniform.load(Ordering::Acquire);
861            if self
862                .uniform
863                .compare_exchange(
864                    current,
865                    encoded_sharing,
866                    Ordering::AcqRel,
867                    Ordering::Acquire,
868                )
869                .is_ok()
870            {
871                if self.is_promoting_dense_sharing() {
872                    let mut dense = dense.lock();
873
874                    #[cfg(not(feature = "parking_lot"))]
875                    let mut dense = dense.expect("poisoned image dense lock");
876
877                    dense
878                        .as_mut()
879                        .expect("missing dense sharing state")
880                        .swap(sharing, sharing_range);
881                }
882
883                return;
884            }
885        }
886    }
887
888    fn promote_dense_sharing_and_set_ranges(
889        &self,
890        dense: &Mutex<Option<DenseMap<SharingMode>>>,
891        info: ImageInfo,
892        sharing: SharingMode,
893        sharing_ranges: &[vk::ImageSubresourceRange],
894    ) {
895        let mut dense = dense.lock();
896
897        #[cfg(not(feature = "parking_lot"))]
898        let mut dense = dense.expect("poisoned image dense lock");
899
900        if self.is_dense_sharing_active() {
901            let dense_sharing = dense.as_mut().expect("missing dense sharing state");
902            for &sharing_range in sharing_ranges {
903                dense_sharing.swap(sharing, info.resolve_subresource_counts(sharing_range));
904            }
905
906            return;
907        }
908
909        self.set_promoting_dense_sharing();
910
911        let current = SharingMode::decode(self.uniform.load(Ordering::Acquire));
912
913        *dense = Some(DenseMap::new(info, current));
914        let sharing_state = dense.as_mut().expect("missing dense sharing state");
915        for &sharing_range in sharing_ranges {
916            sharing_state.swap(sharing, info.resolve_subresource_counts(sharing_range));
917        }
918
919        self.set_dense_sharing_active();
920    }
921}
922
923/// Smart pointer handle to an [image] object.
924///
925/// Also contains information about the object.
926///
927/// ```no_run
928/// # use ash::vk;
929/// # use vk_sync::AccessType;
930/// # use vk_graph::driver::DriverError;
931/// # use vk_graph::driver::device::{Device, DeviceInfo};
932/// # use vk_graph::driver::image::{Image, ImageInfo};
933/// # fn main() -> Result<(), DriverError> {
934/// # let device = Device::create(DeviceInfo::default())?;
935/// let fmt = vk::Format::R8G8B8A8_UNORM;
936/// let usage = vk::ImageUsageFlags::SAMPLED;
937/// let info = ImageInfo::image_2d(320, 200, fmt, usage);
938/// let my_img = Image::create(&device, info)?;
939///
940/// assert_eq!(my_img.info, info);
941/// assert_ne!(my_img.handle, vk::Image::null());
942/// # Ok(()) }
943/// ```
944///
945/// [image]: https://registry.khronos.org/vulkan/specs/latest/man/html/VkImage.html
946#[read_only::cast]
947pub struct Image {
948    access: Access,
949    allocation: Option<Allocation>, // None when we don't own the image (Swapchain images)
950    dense_access: Mutex<Option<DenseMap<AccessType>>>,
951    dense_sharing: Mutex<Option<DenseMap<SharingMode>>>,
952
953    /// The device which owns this image resource.
954    ///
955    /// _Note:_ This field is read-only.
956    #[readonly]
957    pub device: Device,
958
959    /// The native Vulkan resource handle of this image.
960    ///
961    /// _Note:_ This field is read-only.
962    #[readonly]
963    pub handle: vk::Image,
964
965    #[allow(clippy::type_complexity)]
966    image_view_cache: Mutex<HashMap<ImageViewInfo, ImageView>>,
967
968    /// Information used to create this resource.
969    ///
970    /// _Note:_ This field is read-only.
971    #[readonly]
972    pub info: ImageInfo,
973
974    sharing: Sharing,
975}
976
977impl Image {
978    /// Creates a new image on the given device.
979    ///
980    /// # Examples
981    ///
982    /// Basic usage:
983    ///
984    /// ```no_run
985    /// # use std::sync::Arc;
986    /// # use ash::vk;
987    /// # use vk_graph::driver::DriverError;
988    /// # use vk_graph::driver::device::{Device, DeviceInfo};
989    /// # use vk_graph::driver::image::{Image, ImageInfo};
990    /// # fn main() -> Result<(), DriverError> {
991    /// # let device = Device::create(DeviceInfo::default())?;
992    /// let info = ImageInfo::image_2d(
993    ///     32,
994    ///     32,
995    ///     vk::Format::R8G8B8A8_UNORM,
996    ///     vk::ImageUsageFlags::SAMPLED,
997    /// );
998    /// let image = Image::create(&device, info)?;
999    ///
1000    /// assert_ne!(image.handle, vk::Image::null());
1001    /// assert_eq!(image.info.width, 32);
1002    /// assert_eq!(image.info.height, 32);
1003    /// # Ok(()) }
1004    /// ```
1005    #[profiling::function]
1006    pub fn create(device: &Device, info: impl Into<ImageInfo>) -> Result<Self, DriverError> {
1007        let info = info.into();
1008
1009        //trace!("create: {:?}", &info);
1010        trace!("create");
1011
1012        if info.usage.is_empty() {
1013            return Err(DriverError::InvalidData);
1014        }
1015
1016        let access = Access::new(info, AccessType::Nothing);
1017
1018        let device = device.clone();
1019        let create_info: ImageCreateInfo = info.into();
1020        let create_info = if info.sharing_mode == vk::SharingMode::CONCURRENT {
1021            create_info.queue_family_indices(&device.physical.queue_family_indices)
1022        } else {
1023            create_info
1024        };
1025        let handle = unsafe {
1026            device.create_image(&create_info, None).map_err(|err| {
1027                warn!("unable to create image: {err}");
1028
1029                DriverError::Unsupported
1030            })?
1031        };
1032        let requirements = unsafe { device.get_image_memory_requirements(handle) };
1033        let allocation_scheme = if info.alloc_dedicated {
1034            AllocationScheme::DedicatedImage(handle)
1035        } else {
1036            AllocationScheme::GpuAllocatorManaged
1037        };
1038        let allocation = {
1039            profiling::scope!("allocate");
1040
1041            Device::with_allocator(&device, |allocator| {
1042                allocator
1043                    .allocate(&AllocationCreateDesc {
1044                        name: "image",
1045                        requirements,
1046                        location: info.memory_location(),
1047                        linear: false,
1048                        allocation_scheme,
1049                    })
1050                    .map_err(|err| {
1051                        warn!("unable to allocate image memory: {err}");
1052
1053                        unsafe {
1054                            device.destroy_image(handle, None);
1055                        }
1056
1057                        DriverError::from_alloc_err(err)
1058                    })
1059                    .and_then(|allocation| {
1060                        if let Err(err) = unsafe {
1061                            device.bind_image_memory(
1062                                handle,
1063                                allocation.memory(),
1064                                allocation.offset(),
1065                            )
1066                        } {
1067                            warn!("unable to bind image memory: {err}");
1068
1069                            if let Err(err) = allocator.free(allocation) {
1070                                warn!("unable to free image allocation: {err}")
1071                            }
1072
1073                            unsafe {
1074                                device.destroy_image(handle, None);
1075                            }
1076
1077                            Err(DriverError::OutOfMemory)
1078                        } else {
1079                            Ok(allocation)
1080                        }
1081                    })
1082            })
1083        }?;
1084
1085        debug_assert_ne!(handle, vk::Image::null());
1086
1087        Ok(Self {
1088            access,
1089            allocation: Some(allocation),
1090            dense_access: Mutex::new(None),
1091            dense_sharing: Mutex::new(None),
1092            device,
1093            handle,
1094            image_view_cache: Mutex::new(Default::default()),
1095            info,
1096            sharing: Sharing::new(info, info.sharing_mode),
1097        })
1098    }
1099
1100    /// Drops the given allocation, all views, and the handle.
1101    #[profiling::function]
1102    fn drop_allocation(&self, allocation: Allocation) {
1103        {
1104            profiling::scope!("views");
1105
1106            self.with_image_view_cache(|cache| cache.clear());
1107        }
1108
1109        unsafe {
1110            self.device.destroy_image(self.handle, None);
1111        }
1112
1113        {
1114            profiling::scope!("deallocate");
1115
1116            Device::with_allocator(&self.device, |allocator| allocator.free(allocation))
1117        }
1118        .unwrap_or_else(|err| warn!("unable to free image allocation: {err}"));
1119    }
1120
1121    /// Consumes a Vulkan image created by some other library.
1122    ///
1123    /// The image is not destroyed automatically on drop, unlike images created through the
1124    /// [`Image::create`] function.
1125    ///
1126    /// # Safety
1127    ///
1128    /// `handle` must be a valid [`vk::Image`] created from `device`, and `info` must accurately
1129    /// describe the image's format, extent, usage, sharing mode, and subresource counts. The caller
1130    /// remains responsible for keeping the handle and its memory backing valid until all wrappers
1131    /// created from this function are no longer used.
1132    #[profiling::function]
1133    pub unsafe fn from_raw(device: &Device, handle: vk::Image, info: impl Into<ImageInfo>) -> Self {
1134        let device = device.clone();
1135        let info = info.into();
1136
1137        let access = Access::new(info, AccessType::Nothing);
1138
1139        Self {
1140            access,
1141            allocation: None,
1142            dense_access: Mutex::new(None),
1143            dense_sharing: Mutex::new(None),
1144            device,
1145            handle,
1146            image_view_cache: Mutex::new(Default::default()),
1147            info,
1148            sharing: Sharing::new(info, info.sharing_mode),
1149        }
1150    }
1151
1152    /// Sets the debugging name assigned to this image.
1153    pub fn set_debug_name(&self, name: impl AsRef<str>) {
1154        Device::try_set_debug_utils_object_name(&self.device, self.handle, &name);
1155        Device::try_set_private_data_object_name(
1156            &self.device,
1157            vk::ObjectType::IMAGE,
1158            self.handle,
1159            &name,
1160        );
1161    }
1162
1163    pub(crate) fn set_sharing_ranges(
1164        &self,
1165        sharing: SharingMode,
1166        sharing_ranges: &[vk::ImageSubresourceRange],
1167    ) {
1168        self.sharing
1169            .set_ranges(&self.dense_sharing, self.info, sharing, sharing_ranges);
1170    }
1171
1172    /// Keeps track of some next `access` which affects a `range` of this image.
1173    ///
1174    /// Returns the previous access for which a pipeline barrier should be used to prevent data
1175    /// corruption.
1176    #[profiling::function]
1177    pub(crate) fn swap_access(
1178        &self,
1179        next_access: AccessType,
1180        mut access_range: vk::ImageSubresourceRange,
1181    ) -> impl Iterator<Item = (AccessType, vk::ImageSubresourceRange)> + '_ {
1182        #[cfg(feature = "checked")]
1183        {
1184            assert_aspect_mask_supported(access_range.aspect_mask);
1185
1186            assert!(format_aspect_mask(self.info.format).contains(access_range.aspect_mask));
1187        }
1188
1189        if access_range.layer_count == vk::REMAINING_ARRAY_LAYERS {
1190            debug_assert!(access_range.base_array_layer < self.info.array_layer_count);
1191
1192            access_range.layer_count = self.info.array_layer_count - access_range.base_array_layer
1193        }
1194
1195        debug_assert!(
1196            access_range.base_array_layer + access_range.layer_count <= self.info.array_layer_count
1197        );
1198
1199        if access_range.level_count == vk::REMAINING_MIP_LEVELS {
1200            debug_assert!(access_range.base_mip_level < self.info.mip_level_count);
1201
1202            access_range.level_count = self.info.mip_level_count - access_range.base_mip_level
1203        }
1204
1205        debug_assert!(
1206            access_range.base_mip_level + access_range.level_count <= self.info.mip_level_count
1207        );
1208
1209        self.access
1210            .swap(&self.dense_access, self.info, next_access, access_range)
1211    }
1212
1213    pub(crate) fn swap_accesses<'a, I>(
1214        &'a self,
1215        accesses: I,
1216    ) -> impl Iterator<Item = (AccessType, AccessType, vk::ImageSubresourceRange)> + 'a
1217    where
1218        I: IntoIterator<Item = (AccessType, vk::ImageSubresourceRange)>,
1219        I::IntoIter: 'a,
1220    {
1221        let info = self.info;
1222        let format_aspect_mask = format_aspect_mask(info.format);
1223        let accesses = accesses
1224            .into_iter()
1225            .map(move |(next_access, access_range)| {
1226                #[cfg(feature = "checked")]
1227                {
1228                    assert_aspect_mask_supported(access_range.aspect_mask);
1229
1230                    assert!(format_aspect_mask.contains(access_range.aspect_mask));
1231                }
1232
1233                (next_access, info.resolve_subresource_counts(access_range))
1234            });
1235
1236        struct Iter<'a, I>
1237        where
1238            I: Iterator<Item = (AccessType, vk::ImageSubresourceRange)>,
1239        {
1240            access: &'a Access,
1241            accesses: I,
1242            dense_access: &'a Mutex<Option<DenseMap<AccessType>>>,
1243            info: ImageInfo,
1244            current: Option<(AccessType, AccessIter<'a>)>,
1245        }
1246
1247        impl<I> Iterator for Iter<'_, I>
1248        where
1249            I: Iterator<Item = (AccessType, vk::ImageSubresourceRange)>,
1250        {
1251            type Item = (AccessType, AccessType, vk::ImageSubresourceRange);
1252
1253            fn next(&mut self) -> Option<Self::Item> {
1254                loop {
1255                    if let Some((next_access, iter)) = self.current.as_mut() {
1256                        if let Some((prev_access, range)) = iter.next() {
1257                            return Some((*next_access, prev_access, range));
1258                        }
1259
1260                        self.current = None;
1261                    }
1262
1263                    let (next_access, access_range) = self.accesses.next()?;
1264                    self.current = Some((
1265                        next_access,
1266                        self.access
1267                            .swap(self.dense_access, self.info, next_access, access_range),
1268                    ));
1269                }
1270            }
1271        }
1272
1273        impl<I> Drop for Iter<'_, I>
1274        where
1275            I: Iterator<Item = (AccessType, vk::ImageSubresourceRange)>,
1276        {
1277            fn drop(&mut self) {
1278                while self.next().is_some() {}
1279            }
1280        }
1281
1282        Iter {
1283            access: &self.access,
1284            accesses,
1285            dense_access: &self.dense_access,
1286            info,
1287            current: None,
1288        }
1289    }
1290
1291    /// Returns compact synchronization information for the image's current subresource accesses.
1292    pub fn sync_info(&self) -> ImageSyncInfo {
1293        ImageSyncInfo {
1294            subresources: ImageSyncInfo::compact_subresources(
1295                self.sync_info_with_sharing()
1296                    .map(|(subresource, sharing)| subresource.into_public(sharing)),
1297            ),
1298        }
1299    }
1300
1301    pub(crate) fn sync_info_with_sharing(
1302        &self,
1303    ) -> impl Iterator<Item = (ImageSubresourceSyncInfo, SharingMode)> {
1304        self.sync_info_with_sharing_range(vk::ImageSubresourceRange {
1305            aspect_mask: format_aspect_mask(self.info.format),
1306            base_mip_level: 0,
1307            level_count: self.info.mip_level_count,
1308            base_array_layer: 0,
1309            layer_count: self.info.array_layer_count,
1310        })
1311    }
1312
1313    pub(crate) fn sync_info_with_sharing_range(
1314        &self,
1315        query_range: vk::ImageSubresourceRange,
1316    ) -> impl Iterator<Item = (ImageSubresourceSyncInfo, SharingMode)> {
1317        #[derive(Clone, Copy)]
1318        enum SharingSource {
1319            Concurrent,
1320            Uniform(SharingMode),
1321            Dense,
1322        }
1323
1324        let query_range = self.info.resolve_subresource_counts(query_range);
1325        let subresource_ranges = ImageSubresourceRangeIter::new(query_range);
1326        let format_aspect_mask = format_aspect_mask(self.info.format);
1327        #[derive(Clone, Copy)]
1328        enum AccessSource<'a> {
1329            Uniform(AccessType),
1330            DualAspect(&'a DualAspectAccess),
1331            Dense,
1332        }
1333
1334        let access_source = match &self.access {
1335            Access::Uniform(uniform) => AccessSource::Uniform(uniform.load()),
1336            Access::DualAspect(dual) => AccessSource::DualAspect(dual),
1337            Access::Dense(access) if access.uses_dense() => AccessSource::Dense,
1338            Access::Dense(access) => AccessSource::Uniform(access.load()),
1339        };
1340        let sharing_source = match &self.sharing {
1341            Sharing::Concurrent => SharingSource::Concurrent,
1342            Sharing::Exclusive(exclusive) if exclusive.uses_dense_sharing() => SharingSource::Dense,
1343            Sharing::Exclusive(exclusive) => SharingSource::Uniform(SharingMode::decode(
1344                exclusive.uniform.load(Ordering::Acquire),
1345            )),
1346        };
1347
1348        struct UniformSyncInfoIter {
1349            access: AccessType,
1350            sharing: SharingMode,
1351            subresource_ranges: ImageSubresourceRangeIter,
1352        }
1353
1354        impl Iterator for UniformSyncInfoIter {
1355            type Item = (ImageSubresourceSyncInfo, SharingMode);
1356
1357            fn next(&mut self) -> Option<Self::Item> {
1358                self.subresource_ranges.next().map(|range| {
1359                    (
1360                        ImageSubresourceSyncInfo::from_access(self.access, range),
1361                        self.sharing,
1362                    )
1363                })
1364            }
1365
1366            fn size_hint(&self) -> (usize, Option<usize>) {
1367                self.subresource_ranges.size_hint()
1368            }
1369        }
1370
1371        impl ExactSizeIterator for UniformSyncInfoIter {
1372            fn len(&self) -> usize {
1373                self.subresource_ranges.len()
1374            }
1375        }
1376
1377        struct DenseSyncInfoIter<'a> {
1378            access_source: AccessSource<'a>,
1379            format_aspect_mask: vk::ImageAspectFlags,
1380            access_dense: Option<MutexGuard<'a, Option<DenseMap<AccessType>>>>,
1381            sharing_dense: Option<MutexGuard<'a, Option<DenseMap<SharingMode>>>>,
1382            sharing_source: SharingSource,
1383            subresource_ranges: ImageSubresourceRangeIter,
1384        }
1385
1386        impl Iterator for DenseSyncInfoIter<'_> {
1387            type Item = (ImageSubresourceSyncInfo, SharingMode);
1388
1389            fn next(&mut self) -> Option<Self::Item> {
1390                let range = self.subresource_ranges.next()?;
1391                let aspect = aspect_ordinal(self.format_aspect_mask, range.aspect_mask);
1392                let access = match self.access_source {
1393                    AccessSource::Uniform(access) => access,
1394                    AccessSource::DualAspect(dual) => dual.load(aspect as usize),
1395                    AccessSource::Dense => self
1396                        .access_dense
1397                        .as_ref()
1398                        .expect("missing dense access state")
1399                        .as_ref()
1400                        .expect("missing dense access map")
1401                        .subresource(aspect, range.base_array_layer, range.base_mip_level),
1402                };
1403                let sharing = match self.sharing_source {
1404                    SharingSource::Concurrent => SharingMode::Concurrent,
1405                    SharingSource::Uniform(sharing) => sharing,
1406                    SharingSource::Dense => self
1407                        .sharing_dense
1408                        .as_ref()
1409                        .expect("missing dense sharing state")
1410                        .as_ref()
1411                        .expect("missing dense sharing map")
1412                        .subresource(aspect, range.base_array_layer, range.base_mip_level),
1413                };
1414
1415                Some((
1416                    ImageSubresourceSyncInfo::from_access(access, range),
1417                    sharing,
1418                ))
1419            }
1420
1421            fn size_hint(&self) -> (usize, Option<usize>) {
1422                self.subresource_ranges.size_hint()
1423            }
1424        }
1425
1426        impl ExactSizeIterator for DenseSyncInfoIter<'_> {
1427            fn len(&self) -> usize {
1428                self.subresource_ranges.len()
1429            }
1430        }
1431
1432        enum SyncInfoIter<'a> {
1433            Uniform(UniformSyncInfoIter),
1434            Dense(DenseSyncInfoIter<'a>),
1435        }
1436
1437        impl Iterator for SyncInfoIter<'_> {
1438            type Item = (ImageSubresourceSyncInfo, SharingMode);
1439
1440            fn next(&mut self) -> Option<Self::Item> {
1441                match self {
1442                    Self::Uniform(iter) => iter.next(),
1443                    Self::Dense(iter) => iter.next(),
1444                }
1445            }
1446
1447            fn size_hint(&self) -> (usize, Option<usize>) {
1448                let len = self.len();
1449
1450                (len, Some(len))
1451            }
1452        }
1453
1454        impl ExactSizeIterator for SyncInfoIter<'_> {
1455            fn len(&self) -> usize {
1456                match self {
1457                    Self::Uniform(iter) => iter.len(),
1458                    Self::Dense(iter) => iter.len(),
1459                }
1460            }
1461        }
1462
1463        let uniform_sharing = match sharing_source {
1464            SharingSource::Concurrent => Some(SharingMode::Concurrent),
1465            SharingSource::Uniform(sharing) => Some(sharing),
1466            SharingSource::Dense => None,
1467        };
1468
1469        let sync_infos = if let (AccessSource::Uniform(access), Some(sharing)) =
1470            (access_source, uniform_sharing)
1471        {
1472            SyncInfoIter::Uniform(UniformSyncInfoIter {
1473                access,
1474                sharing,
1475                subresource_ranges,
1476            })
1477        } else {
1478            let access_dense = if matches!(access_source, AccessSource::Dense) {
1479                let dense = self.dense_access.lock();
1480
1481                #[cfg(not(feature = "parking_lot"))]
1482                let dense = dense.expect("poisoned image dense access lock");
1483
1484                Some(dense)
1485            } else {
1486                None
1487            };
1488            let sharing_dense = if matches!(sharing_source, SharingSource::Dense) {
1489                let dense = self.dense_sharing.lock();
1490
1491                #[cfg(not(feature = "parking_lot"))]
1492                let dense = dense.expect("poisoned image dense sharing lock");
1493
1494                Some(dense)
1495            } else {
1496                None
1497            };
1498
1499            SyncInfoIter::Dense(DenseSyncInfoIter {
1500                access_source,
1501                format_aspect_mask,
1502                access_dense,
1503                sharing_dense,
1504                sharing_source,
1505                subresource_ranges,
1506            })
1507        };
1508
1509        struct CompactIter<I, P, M> {
1510            iter: I,
1511            pending: Option<(ImageSubresourceSyncInfo, SharingMode)>,
1512            can_merge: P,
1513            merge: M,
1514        }
1515
1516        /*
1517        Lazily compacts adjacent iterator entries. Each pass is linear in the number of source
1518        entries and keeps only one pending entry, so it uses `O(1)` extra memory. The image sync
1519        iterator applies this twice: first to merge mip levels, then to merge array layers.
1520        */
1521        impl<I, P, M> CompactIter<I, P, M>
1522        where
1523            I: Iterator<Item = (ImageSubresourceSyncInfo, SharingMode)>,
1524            P: Fn(
1525                (ImageSubresourceSyncInfo, SharingMode),
1526                (ImageSubresourceSyncInfo, SharingMode),
1527            ) -> bool,
1528            M: Fn(
1529                &mut (ImageSubresourceSyncInfo, SharingMode),
1530                (ImageSubresourceSyncInfo, SharingMode),
1531            ),
1532        {
1533            fn new(iter: I, can_merge: P, merge: M) -> Self {
1534                Self {
1535                    iter,
1536                    pending: None,
1537                    can_merge,
1538                    merge,
1539                }
1540            }
1541        }
1542
1543        impl<I, P, M> Iterator for CompactIter<I, P, M>
1544        where
1545            I: Iterator<Item = (ImageSubresourceSyncInfo, SharingMode)>,
1546            P: Fn(
1547                (ImageSubresourceSyncInfo, SharingMode),
1548                (ImageSubresourceSyncInfo, SharingMode),
1549            ) -> bool,
1550            M: Fn(
1551                &mut (ImageSubresourceSyncInfo, SharingMode),
1552                (ImageSubresourceSyncInfo, SharingMode),
1553            ),
1554        {
1555            type Item = (ImageSubresourceSyncInfo, SharingMode);
1556
1557            fn next(&mut self) -> Option<Self::Item> {
1558                let mut pending = self.pending.take().or_else(|| self.iter.next())?;
1559
1560                for next in self.iter.by_ref() {
1561                    if (self.can_merge)(pending, next) {
1562                        (self.merge)(&mut pending, next);
1563                    } else {
1564                        self.pending = Some(next);
1565                        return Some(pending);
1566                    }
1567                }
1568
1569                Some(pending)
1570            }
1571        }
1572
1573        let same_sync_and_sharing =
1574            |lhs: (ImageSubresourceSyncInfo, SharingMode),
1575             rhs: (ImageSubresourceSyncInfo, SharingMode)| {
1576                lhs.0.same_sync(rhs.0) && lhs.1 == rhs.1
1577            };
1578        let merge_array_layers =
1579            |lhs: &mut (ImageSubresourceSyncInfo, SharingMode),
1580             rhs: (ImageSubresourceSyncInfo, SharingMode)| {
1581                lhs.0.merge_array_layers(rhs.0);
1582            };
1583        let merge_mip_levels =
1584            |lhs: &mut (ImageSubresourceSyncInfo, SharingMode),
1585             rhs: (ImageSubresourceSyncInfo, SharingMode)| {
1586                lhs.0.merge_mip_levels(rhs.0);
1587            };
1588
1589        let mip_levels = CompactIter::new(sync_infos, same_sync_and_sharing, merge_mip_levels);
1590
1591        CompactIter::new(mip_levels, same_sync_and_sharing, merge_array_layers)
1592    }
1593
1594    /// Produces a new `Image` sharing the same Vulkan handle with independent access tracking.
1595    ///
1596    /// The returned image retains the handle, device, and debug name of `self` but starts with
1597    /// no prior access history (`AccessType::Nothing`) and does not claim ownership of the image's
1598    /// memory backing. Internal caches are moved out of `self` so they are not duplicated.
1599    ///
1600    /// This is used to create separate tracking instances for swapchain images that may be
1601    /// used concurrently across different graph executions.
1602    ///
1603    /// # Safety
1604    ///
1605    /// The caller must ensure the Vulkan image handle remains valid for the lifetime of the
1606    /// returned `Image`. This function should only be called on swapchain images or other
1607    /// platform or extension images.
1608    #[profiling::function]
1609    pub unsafe fn to_detached(&self) -> Self {
1610        debug_assert!(self.allocation.is_none());
1611
1612        let image_view_cache = self.with_image_view_cache(take);
1613
1614        let Self { handle, info, .. } = *self;
1615
1616        Self {
1617            access: Access::new(info, AccessType::Nothing),
1618            allocation: None,
1619            dense_access: Mutex::new(None),
1620            dense_sharing: Mutex::new(None),
1621            device: self.device.clone(),
1622            handle,
1623            image_view_cache: Mutex::new(image_view_cache),
1624            info,
1625            sharing: Sharing::new(info, info.sharing_mode),
1626        }
1627    }
1628
1629    #[profiling::function]
1630    pub(crate) fn view(&self, info: ImageViewInfo) -> Result<vk::ImageView, DriverError> {
1631        self.with_image_view_cache(|cache| {
1632            Ok(match cache.entry(info) {
1633                Entry::Occupied(entry) => entry.get().image_view,
1634                Entry::Vacant(entry) => {
1635                    entry
1636                        .insert(ImageView::create(&self.device, info, self.handle)?)
1637                        .image_view
1638                }
1639            })
1640        })
1641    }
1642
1643    /// Sets the debugging name assigned to this image.
1644    pub fn with_debug_name(self, name: impl AsRef<str>) -> Self {
1645        self.set_debug_name(name);
1646
1647        self
1648    }
1649
1650    fn with_image_view_cache<R>(
1651        &self,
1652        f: impl FnOnce(&mut HashMap<ImageViewInfo, ImageView>) -> R,
1653    ) -> R {
1654        let cache = self.image_view_cache.lock();
1655
1656        #[cfg(not(feature = "parking_lot"))]
1657        let cache = cache.expect("poisoned image view lock");
1658
1659        let mut cache = cache;
1660
1661        f(&mut cache)
1662    }
1663}
1664
1665impl Debug for Image {
1666    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1667        let mut res = f.debug_struct(stringify!(Image));
1668
1669        if let Some(debug_name) =
1670            &Device::private_data_object_name(&self.device, vk::ObjectType::IMAGE, self.handle)
1671        {
1672            res.field("debug_name", debug_name);
1673        }
1674
1675        res.field("handle", &self.handle).finish_non_exhaustive()
1676    }
1677}
1678
1679impl Drop for Image {
1680    // This function is not profiled because dropping the allocation may run during shutdown.
1681    fn drop(&mut self) {
1682        if panicking() {
1683            return;
1684        }
1685
1686        /*
1687        When allocation is Some, we allocated the image ourselves; otherwise somebody else owns this
1688        image and we should not destroy it. Usually it's the swapchain.
1689        */
1690        if let Some(allocation) = self.allocation.take() {
1691            Device::try_clear_private_data_object_name(
1692                &self.device,
1693                vk::ObjectType::IMAGE,
1694                self.handle,
1695            );
1696            Self::drop_allocation(self, allocation);
1697        } else {
1698            // Non-owned handles may already be invalid when their owner, such as a swapchain, has
1699            // been destroyed. Remove local metadata without issuing vkSetPrivateDataEXT.
1700            Device::forget_private_data_object_name(
1701                &self.device,
1702                vk::ObjectType::IMAGE,
1703                self.handle,
1704            );
1705        }
1706    }
1707}
1708
1709impl Eq for Image {}
1710
1711impl PartialEq for Image {
1712    fn eq(&self, other: &Self) -> bool {
1713        self.handle == other.handle
1714    }
1715}
1716
1717/// Information used to create an [`Image`] instance.
1718///
1719/// See [`VkImageCreateInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageCreateInfo.html).
1720#[derive(Builder, Clone, Copy, Debug, Hash, PartialEq, Eq)]
1721#[builder(
1722    build_fn(private, name = "fallible_build"),
1723    derive(Copy, Clone, Debug),
1724    pattern = "owned"
1725)]
1726pub struct ImageInfo {
1727    /// Specifies a dedicated memory allocation managed by the Vulkan driver and not by the
1728    /// internal memory allocation pool transient resources share.
1729    ///
1730    /// The driver may optimize access to dedicated images.
1731    #[builder(default)]
1732    pub alloc_dedicated: bool,
1733
1734    /// The number of layers in the image.
1735    #[builder(default = "1")]
1736    pub array_layer_count: u32,
1737
1738    /// Image extent of the Z axis, when describing a three dimensional image.
1739    #[builder(default)]
1740    pub depth: u32,
1741
1742    /// A bitmask describing additional parameters of the image.
1743    ///
1744    /// See [`VkImageCreateFlagBits`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageCreateFlagBits.html).
1745    #[builder(default)]
1746    pub flags: vk::ImageCreateFlags,
1747
1748    /// The format and type of the texel blocks that will be contained in the image.
1749    #[builder(default = "vk::Format::UNDEFINED")]
1750    pub format: vk::Format,
1751
1752    /// Image extent of the Y axis, when describing a two or three dimensional image.
1753    #[builder(default)]
1754    pub height: u32,
1755
1756    /// Specifies an image whose memory is host-visible and may be mapped for reads.
1757    ///
1758    /// Memory optimal for CPU readback of data may be used.
1759    ///
1760    #[builder(default)]
1761    pub host_readable: bool,
1762
1763    /// Specifies an image whose memory is host-visible and may be mapped for writes.
1764    ///
1765    /// Memory optimal for uploading data to the GPU may be used.
1766    ///
1767    #[builder(default)]
1768    pub host_writable: bool,
1769
1770    /// The number of levels of detail available for minified sampling of the image.
1771    #[builder(default = "1")]
1772    pub mip_level_count: u32,
1773
1774    /// Specifies the number of [samples per texel].
1775    ///
1776    /// See [`VkImageCreateInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageCreateInfo.html).
1777    #[builder(default = "SampleCount::Type1")]
1778    pub sample_count: SampleCount,
1779
1780    /// Controls whether the image is accessible from a single queue family (`EXCLUSIVE`) or from
1781    /// multiple queue families concurrently (`CONCURRENT`).
1782    ///
1783    /// `EXCLUSIVE` (the default) restricts the image to a single queue family. This may enable
1784    /// driver optimizations but requires ownership transfers to use the image on a different queue
1785    /// family.
1786    ///
1787    /// Set to `CONCURRENT` when the image will be accessed from multiple queue families (e.g.
1788    /// graphics and compute on separate queues).
1789    ///
1790    /// See
1791    /// [`VkSharingMode`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkSharingMode.html)
1792    /// in the Vulkan specification.
1793    #[builder(default = "vk::SharingMode::EXCLUSIVE")]
1794    pub sharing_mode: vk::SharingMode,
1795
1796    /// Specifies the tiling arrangement of the texel blocks in memory.
1797    ///
1798    /// The default value is [`vk::ImageTiling::OPTIMAL`].
1799    #[builder(default = "vk::ImageTiling::OPTIMAL")]
1800    pub tiling: vk::ImageTiling,
1801
1802    /// The basic dimensionality of the image.
1803    ///
1804    /// Layers in array textures do not count as a dimension for the purposes of the image type.
1805    #[builder(default = "vk::ImageType::TYPE_2D")]
1806    pub image_type: vk::ImageType,
1807
1808    /// A bitmask describing the intended usage of the image.
1809    ///
1810    /// See [`VkImageUsageFlagBits`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageUsageFlagBits.html).
1811    #[builder(default)]
1812    pub usage: vk::ImageUsageFlags,
1813
1814    /// Image extent of the X axis.
1815    #[builder(default)]
1816    pub width: u32,
1817}
1818
1819impl ImageInfo {
1820    /// Specifies a cube image.
1821    #[inline(always)]
1822    pub const fn cube(size: u32, format: vk::Format, usage: vk::ImageUsageFlags) -> ImageInfo {
1823        let mut res = Self::new(vk::ImageType::TYPE_2D, size, size, 1, 6, format, usage);
1824        res.flags = vk::ImageCreateFlags::from_raw(
1825            vk::ImageCreateFlags::CUBE_COMPATIBLE.as_raw() | res.flags.as_raw(),
1826        );
1827
1828        res
1829    }
1830
1831    /// Specifies a one-dimensional image.
1832    #[inline(always)]
1833    pub const fn image_1d(size: u32, format: vk::Format, usage: vk::ImageUsageFlags) -> ImageInfo {
1834        Self::new(vk::ImageType::TYPE_1D, size, 1, 1, 1, format, usage)
1835    }
1836
1837    /// Specifies a two-dimensional image.
1838    #[inline(always)]
1839    pub const fn image_2d(
1840        width: u32,
1841        height: u32,
1842        format: vk::Format,
1843        usage: vk::ImageUsageFlags,
1844    ) -> ImageInfo {
1845        Self::new(vk::ImageType::TYPE_2D, width, height, 1, 1, format, usage)
1846    }
1847
1848    /// Specifies a two-dimensional image array.
1849    #[inline(always)]
1850    pub const fn image_2d_array(
1851        width: u32,
1852        height: u32,
1853        array_layer_count: u32,
1854        format: vk::Format,
1855        usage: vk::ImageUsageFlags,
1856    ) -> ImageInfo {
1857        Self::new(
1858            vk::ImageType::TYPE_2D,
1859            width,
1860            height,
1861            1,
1862            array_layer_count,
1863            format,
1864            usage,
1865        )
1866    }
1867
1868    /// Specifies a three-dimensional image.
1869    #[inline(always)]
1870    pub const fn image_3d(
1871        width: u32,
1872        height: u32,
1873        depth: u32,
1874        format: vk::Format,
1875        usage: vk::ImageUsageFlags,
1876    ) -> ImageInfo {
1877        Self::new(
1878            vk::ImageType::TYPE_3D,
1879            width,
1880            height,
1881            depth,
1882            1,
1883            format,
1884            usage,
1885        )
1886    }
1887
1888    #[inline(always)]
1889    const fn new(
1890        image_type: vk::ImageType,
1891        width: u32,
1892        height: u32,
1893        depth: u32,
1894        array_layer_count: u32,
1895        format: vk::Format,
1896        usage: vk::ImageUsageFlags,
1897    ) -> Self {
1898        Self {
1899            alloc_dedicated: false,
1900            image_type,
1901            width,
1902            height,
1903            depth,
1904            array_layer_count,
1905            format,
1906            usage,
1907            flags: vk::ImageCreateFlags::empty(),
1908            host_readable: false,
1909            host_writable: false,
1910            sharing_mode: vk::SharingMode::EXCLUSIVE,
1911            tiling: vk::ImageTiling::OPTIMAL,
1912            mip_level_count: 1,
1913            sample_count: SampleCount::Type1,
1914        }
1915    }
1916
1917    /// Creates a default `ImageInfoBuilder`.
1918    pub fn builder() -> ImageInfoBuilder {
1919        Default::default()
1920    }
1921
1922    /// Provides an `ImageViewInfo` for this format, type, aspect, array elements, and mip levels.
1923    pub fn into_image_view(self) -> ImageViewInfo {
1924        self.into()
1925    }
1926
1927    pub(crate) fn resolve_subresource_counts(
1928        self,
1929        mut range: vk::ImageSubresourceRange,
1930    ) -> vk::ImageSubresourceRange {
1931        if range.layer_count == vk::REMAINING_ARRAY_LAYERS {
1932            range.layer_count = self.array_layer_count - range.base_array_layer;
1933        }
1934
1935        if range.level_count == vk::REMAINING_MIP_LEVELS {
1936            range.level_count = self.mip_level_count - range.base_mip_level;
1937        }
1938
1939        range
1940    }
1941
1942    fn is_full_subresource_range(self, range: vk::ImageSubresourceRange) -> bool {
1943        range.aspect_mask == format_aspect_mask(self.format)
1944            && range.base_array_layer == 0
1945            && range.layer_count == self.array_layer_count
1946            && range.base_mip_level == 0
1947            && range.level_count == self.mip_level_count
1948    }
1949
1950    /// Returns `true` if this image is an array.
1951    pub fn is_array(self) -> bool {
1952        self.array_layer_count > 1
1953    }
1954
1955    /// Returns `true` if this image is a cube or cube array.
1956    pub fn is_cube(self) -> bool {
1957        self.image_type == vk::ImageType::TYPE_2D
1958            && self.width == self.height
1959            && self.depth == 1
1960            && self.array_layer_count >= 6
1961            && self.flags.contains(vk::ImageCreateFlags::CUBE_COMPATIBLE)
1962    }
1963
1964    /// Returns `true` if this image is a cube array.
1965    pub fn is_cube_array(self) -> bool {
1966        self.is_cube() && self.array_layer_count > 6
1967    }
1968
1969    /// Returns `true` if this information specifies host-visible memory.
1970    pub fn is_host_visible(self) -> bool {
1971        self.host_readable | self.host_writable
1972    }
1973
1974    const fn memory_location(self) -> MemoryLocation {
1975        if self.host_writable {
1976            MemoryLocation::CpuToGpu
1977        } else if self.host_readable {
1978            MemoryLocation::GpuToCpu
1979        } else {
1980            MemoryLocation::GpuOnly
1981        }
1982    }
1983
1984    /// Converts an `ImageInfo` into an `ImageInfoBuilder`.
1985    pub fn into_builder(self) -> ImageInfoBuilder {
1986        ImageInfoBuilder {
1987            array_layer_count: Some(self.array_layer_count),
1988            alloc_dedicated: Some(self.alloc_dedicated),
1989            depth: Some(self.depth),
1990            flags: Some(self.flags),
1991            format: Some(self.format),
1992            height: Some(self.height),
1993            host_readable: Some(self.host_readable),
1994            host_writable: Some(self.host_writable),
1995            mip_level_count: Some(self.mip_level_count),
1996            sample_count: Some(self.sample_count),
1997            sharing_mode: Some(self.sharing_mode),
1998            tiling: Some(self.tiling),
1999            image_type: Some(self.image_type),
2000            usage: Some(self.usage),
2001            width: Some(self.width),
2002        }
2003    }
2004}
2005
2006impl From<ImageInfo> for vk::ImageCreateInfo<'_> {
2007    fn from(value: ImageInfo) -> Self {
2008        Self::default()
2009            .flags(value.flags)
2010            .image_type(value.image_type)
2011            .format(value.format)
2012            .extent(vk::Extent3D {
2013                width: value.width,
2014                height: value.height,
2015                depth: value.depth,
2016            })
2017            .mip_levels(value.mip_level_count)
2018            .array_layers(value.array_layer_count)
2019            .samples(value.sample_count.into())
2020            .tiling(value.tiling)
2021            .usage(value.usage)
2022            .sharing_mode(value.sharing_mode)
2023            .initial_layout(vk::ImageLayout::UNDEFINED)
2024    }
2025}
2026
2027impl From<ImageInfoBuilder> for ImageInfo {
2028    fn from(info: ImageInfoBuilder) -> Self {
2029        info.build()
2030    }
2031}
2032
2033impl From<ImageInfo> for vk::ImageSubresourceRange {
2034    fn from(info: ImageInfo) -> Self {
2035        let image_view_info: ImageViewInfo = info.into();
2036
2037        image_view_info.into()
2038    }
2039}
2040
2041impl ImageInfoBuilder {
2042    /// Builds a new `ImageInfo`.
2043    #[inline(always)]
2044    pub fn build(self) -> ImageInfo {
2045        self.fallible_build().expect("all fields have defaults")
2046    }
2047
2048    /// Provides an `ImageViewInfo` for this format, type, aspect, array elements, and mip levels.
2049    pub fn into_image_view(self) -> ImageViewInfoBuilder {
2050        self.build().into_image_view().into_builder()
2051    }
2052}
2053
2054struct ImageSubresourceRangeIter {
2055    aspect_mask: vk::ImageAspectFlags,
2056    aspect: u8,
2057    aspect_count: u8,
2058    array_layer: u32,
2059    end_array_layer: u32,
2060    base_array_layer: u32,
2061    base_mip_level: u32,
2062    mip_level: u32,
2063    end_mip_level: u32,
2064    remaining: usize,
2065}
2066
2067impl ImageSubresourceRangeIter {
2068    fn new(range: vk::ImageSubresourceRange) -> Self {
2069        let aspect_mask = range.aspect_mask;
2070        let aspect_count = aspect_mask.as_raw().count_ones() as u8;
2071
2072        Self {
2073            aspect_mask,
2074            aspect: 0,
2075            aspect_count,
2076            array_layer: range.base_array_layer,
2077            end_array_layer: range.base_array_layer + range.layer_count,
2078            base_array_layer: range.base_array_layer,
2079            base_mip_level: range.base_mip_level,
2080            mip_level: range.base_mip_level,
2081            end_mip_level: range.base_mip_level + range.level_count,
2082            remaining: aspect_count as usize
2083                * range.layer_count as usize
2084                * range.level_count as usize,
2085        }
2086    }
2087}
2088
2089impl ExactSizeIterator for ImageSubresourceRangeIter {
2090    fn len(&self) -> usize {
2091        self.remaining
2092    }
2093}
2094
2095impl Iterator for ImageSubresourceRangeIter {
2096    type Item = vk::ImageSubresourceRange;
2097
2098    fn next(&mut self) -> Option<Self::Item> {
2099        if self.aspect >= self.aspect_count {
2100            return None;
2101        }
2102
2103        let range = vk::ImageSubresourceRange {
2104            aspect_mask: aspect_mask_at_ordinal(self.aspect_mask, self.aspect as u32),
2105            base_array_layer: self.array_layer,
2106            layer_count: 1,
2107            base_mip_level: self.mip_level,
2108            level_count: 1,
2109        };
2110
2111        self.mip_level += 1;
2112        if self.mip_level >= self.end_mip_level {
2113            self.mip_level = self.base_mip_level;
2114            self.array_layer += 1;
2115            if self.array_layer >= self.end_array_layer {
2116                self.array_layer = self.base_array_layer;
2117                self.aspect += 1;
2118            }
2119        }
2120
2121        self.remaining -= 1;
2122
2123        Some(range)
2124    }
2125
2126    fn size_hint(&self) -> (usize, Option<usize>) {
2127        let len = self.len();
2128
2129        (len, Some(len))
2130    }
2131}
2132
2133/// Synchronization information for one accessed image subresource range.
2134#[derive(Clone, Copy, Debug)]
2135pub struct ImageSubresourceSyncInfo {
2136    /// Access types performed by `stage_mask`.
2137    pub access_mask: vk::AccessFlags,
2138
2139    /// Required image layout for the next external use, when one is defined.
2140    pub layout: Option<vk::ImageLayout>,
2141
2142    /// Queue-family ownership for this subresource, when exclusive ownership is known.
2143    pub queue_family_index: Option<u32>,
2144
2145    /// The tracked image subresource range.
2146    pub range: vk::ImageSubresourceRange,
2147
2148    /// Pipeline stages that access this `range`.
2149    pub stage_mask: vk::PipelineStageFlags,
2150}
2151
2152impl ImageSubresourceSyncInfo {
2153    fn can_merge_array_layers(self, other: Self) -> bool {
2154        self.same_sync(other)
2155            && self.range.aspect_mask == other.range.aspect_mask
2156            && self.range.base_mip_level == other.range.base_mip_level
2157            && self.range.level_count == other.range.level_count
2158            && self.range.base_array_layer + self.range.layer_count == other.range.base_array_layer
2159    }
2160
2161    fn can_merge_mip_levels(self, other: Self) -> bool {
2162        self.same_sync(other)
2163            && self.range.aspect_mask == other.range.aspect_mask
2164            && self.range.base_array_layer == other.range.base_array_layer
2165            && self.range.layer_count == other.range.layer_count
2166            && self.range.base_mip_level + self.range.level_count == other.range.base_mip_level
2167    }
2168
2169    fn from_access(access: AccessType, range: vk::ImageSubresourceRange) -> Self {
2170        let (stage_mask, access_mask) = pipeline_stage_access_flags(access);
2171
2172        Self {
2173            access_mask,
2174            layout: access_type_to_layout(access),
2175            queue_family_index: None,
2176            range,
2177            stage_mask,
2178        }
2179    }
2180
2181    fn into_public(self, sharing: SharingMode) -> Self {
2182        Self {
2183            queue_family_index: match sharing {
2184                SharingMode::Concurrent | SharingMode::Exclusive(None) => None,
2185                SharingMode::Exclusive(Some((queue_family_index, _))) => Some(queue_family_index),
2186            },
2187            ..self
2188        }
2189    }
2190
2191    fn merge_array_layers(&mut self, other: Self) {
2192        self.range.layer_count += other.range.layer_count;
2193    }
2194
2195    fn merge_mip_levels(&mut self, other: Self) {
2196        self.range.level_count += other.range.level_count;
2197    }
2198
2199    fn same_sync(self, other: Self) -> bool {
2200        self.access_mask == other.access_mask
2201            && self.layout == other.layout
2202            && self.queue_family_index == other.queue_family_index
2203            && self.stage_mask == other.stage_mask
2204    }
2205}
2206
2207/// Synchronization information for an image.
2208#[derive(Clone, Debug)]
2209pub struct ImageSyncInfo {
2210    /// Access state for the tracked image subresource ranges.
2211    pub subresources: Box<[ImageSubresourceSyncInfo]>,
2212}
2213
2214impl ImageSyncInfo {
2215    fn compact_subresources(
2216        subresources: impl IntoIterator<Item = ImageSubresourceSyncInfo>,
2217    ) -> Box<[ImageSubresourceSyncInfo]> {
2218        let mut mip_levels = Vec::new();
2219
2220        for sync_info in subresources {
2221            if let Some(prev) = mip_levels.last_mut()
2222                && ImageSubresourceSyncInfo::can_merge_mip_levels(*prev, sync_info)
2223            {
2224                prev.merge_mip_levels(sync_info);
2225            } else {
2226                mip_levels.push(sync_info);
2227            }
2228        }
2229
2230        let mut array_layers = Vec::with_capacity(mip_levels.len());
2231
2232        for sync_info in mip_levels {
2233            if let Some(prev) = array_layers.last_mut()
2234                && ImageSubresourceSyncInfo::can_merge_array_layers(*prev, sync_info)
2235            {
2236                prev.merge_array_layers(sync_info);
2237            } else {
2238                array_layers.push(sync_info);
2239            }
2240        }
2241
2242        array_layers.into_boxed_slice()
2243    }
2244
2245    /// Compacts adjacent subresource entries with identical synchronization requirements.
2246    ///
2247    /// This is opt-in because some callers may prefer the exact per-range snapshot produced by the
2248    /// internal access tracker.
2249    ///
2250    /// Runs in linear time over `subresources`. Image compaction performs two passes, first merging
2251    /// adjacent mip levels and then adjacent array layers, and uses temporary vector storage for
2252    /// each pass.
2253    pub fn compact(&mut self) {
2254        let subresources = take(&mut self.subresources);
2255        self.subresources = Self::compact_subresources(subresources);
2256    }
2257
2258    /// Returns a compacted copy of this synchronization snapshot.
2259    ///
2260    /// This has the same linear-time and temporary-storage characteristics as [`Self::compact`],
2261    /// but consumes and returns the snapshot for use in iterator chains or expression-oriented code.
2262    pub fn into_compacted(mut self) -> Self {
2263        self.compact();
2264        self
2265    }
2266}
2267
2268struct ImageView {
2269    device: Device,
2270    image_view: vk::ImageView,
2271}
2272
2273impl ImageView {
2274    #[profiling::function]
2275    fn create(
2276        device: &Device,
2277        info: impl Into<ImageViewInfo>,
2278        image: vk::Image,
2279    ) -> Result<Self, DriverError> {
2280        let info = info.into();
2281        let device = device.clone();
2282        let create_info = vk::ImageViewCreateInfo::default()
2283            .view_type(info.view_type)
2284            .format(info.format)
2285            .components(vk::ComponentMapping {
2286                r: vk::ComponentSwizzle::R,
2287                g: vk::ComponentSwizzle::G,
2288                b: vk::ComponentSwizzle::B,
2289                a: vk::ComponentSwizzle::A,
2290            })
2291            .image(image)
2292            .subresource_range(vk::ImageSubresourceRange {
2293                aspect_mask: info.aspect_mask,
2294                base_array_layer: info.base_array_layer,
2295                base_mip_level: info.base_mip_level,
2296                level_count: info.mip_level_count,
2297                layer_count: info.array_layer_count,
2298            });
2299
2300        let image_view =
2301            unsafe { device.create_image_view(&create_info, None) }.map_err(|err| {
2302                warn!("unable to create image view: {err}");
2303
2304                DriverError::Unsupported
2305            })?;
2306
2307        Ok(Self { device, image_view })
2308    }
2309}
2310
2311impl Drop for ImageView {
2312    #[profiling::function]
2313    fn drop(&mut self) {
2314        if panicking() {
2315            return;
2316        }
2317
2318        unsafe {
2319            self.device.destroy_image_view(self.image_view, None);
2320        }
2321    }
2322}
2323
2324/// Information used to reinterpret an existing [`Image`] instance.
2325///
2326/// See [`VkImageViewCreateInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageViewCreateInfo.html).
2327#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
2328#[builder(
2329    build_fn(private, name = "fallible_build"),
2330    derive(Clone, Copy, Debug),
2331    pattern = "owned"
2332)]
2333pub struct ImageViewInfo {
2334    /// The number of layers that will be contained in the view.
2335    ///
2336    /// The default value is `vk::REMAINING_ARRAY_LAYERS`.
2337    #[builder(default = "vk::REMAINING_ARRAY_LAYERS")]
2338    pub array_layer_count: u32,
2339
2340    /// The portion of the image that will be contained in the view.
2341    #[builder(default = "vk::ImageAspectFlags::COLOR")]
2342    pub aspect_mask: vk::ImageAspectFlags,
2343
2344    /// The first array layer that will be contained in the view.
2345    #[builder(default)]
2346    pub base_array_layer: u32,
2347
2348    /// The first mip level that will be contained in the view.
2349    #[builder(default)]
2350    pub base_mip_level: u32,
2351
2352    /// The format and type of the texel blocks that will be contained in the view.
2353    #[builder(default = "vk::Format::UNDEFINED")]
2354    pub format: vk::Format,
2355
2356    /// The number of mip levels that will be contained in the view.
2357    ///
2358    /// The default value is `vk::REMAINING_MIP_LEVELS`.
2359    #[builder(default = "vk::REMAINING_MIP_LEVELS")]
2360    pub mip_level_count: u32,
2361
2362    /// The basic dimensionality of the view.
2363    #[builder(default = "vk::ImageViewType::TYPE_2D")]
2364    pub view_type: vk::ImageViewType,
2365}
2366
2367impl ImageViewInfo {
2368    /// Specifies a default view with the given `format` and `view_type` values.
2369    ///
2370    /// # Note
2371    ///
2372    /// Automatically sets [`aspect_mask`](Self::aspect_mask) to a suggested value.
2373    #[inline(always)]
2374    pub const fn new(format: vk::Format, view_type: vk::ImageViewType) -> ImageViewInfo {
2375        Self {
2376            array_layer_count: vk::REMAINING_ARRAY_LAYERS,
2377            aspect_mask: format_aspect_mask(format),
2378            base_array_layer: 0,
2379            base_mip_level: 0,
2380            format,
2381            mip_level_count: vk::REMAINING_MIP_LEVELS,
2382            view_type,
2383        }
2384    }
2385
2386    /// Converts an `ImageViewInfo` into an `ImageViewInfoBuilder`.
2387    pub fn into_builder(self) -> ImageViewInfoBuilder {
2388        ImageViewInfoBuilder {
2389            array_layer_count: Some(self.array_layer_count),
2390            aspect_mask: Some(self.aspect_mask),
2391            base_array_layer: Some(self.base_array_layer),
2392            base_mip_level: Some(self.base_mip_level),
2393            format: Some(self.format),
2394            mip_level_count: Some(self.mip_level_count),
2395            view_type: Some(self.view_type),
2396        }
2397    }
2398}
2399
2400impl From<ImageInfo> for ImageViewInfo {
2401    fn from(info: ImageInfo) -> Self {
2402        Self::from_image_info(info).expect("unsupported image type for image view info")
2403    }
2404}
2405
2406impl ImageViewInfo {
2407    /// Creates an image view description from image creation info.
2408    pub fn from_image_info(info: ImageInfo) -> Result<Self, DriverError> {
2409        Ok(Self {
2410            array_layer_count: info.array_layer_count,
2411            aspect_mask: format_aspect_mask(info.format),
2412            base_array_layer: 0,
2413            base_mip_level: 0,
2414            format: info.format,
2415            mip_level_count: info.mip_level_count,
2416            view_type: match (info.image_type, info.array_layer_count) {
2417                (vk::ImageType::TYPE_1D, 1) => vk::ImageViewType::TYPE_1D,
2418                (vk::ImageType::TYPE_1D, _) => vk::ImageViewType::TYPE_1D_ARRAY,
2419                (vk::ImageType::TYPE_2D, 1) => vk::ImageViewType::TYPE_2D,
2420                (vk::ImageType::TYPE_2D, 6)
2421                    if info.flags.contains(vk::ImageCreateFlags::CUBE_COMPATIBLE) =>
2422                {
2423                    vk::ImageViewType::CUBE
2424                }
2425                (vk::ImageType::TYPE_2D, _)
2426                    if info.flags.contains(vk::ImageCreateFlags::CUBE_COMPATIBLE)
2427                        && info.array_layer_count > 6 =>
2428                {
2429                    vk::ImageViewType::CUBE_ARRAY
2430                }
2431                (vk::ImageType::TYPE_2D, _) => vk::ImageViewType::TYPE_2D_ARRAY,
2432                (vk::ImageType::TYPE_3D, _) => vk::ImageViewType::TYPE_3D,
2433                _ => {
2434                    warn!(
2435                        "invalid image view source info: image type {:?} with {} array layers",
2436                        info.image_type, info.array_layer_count
2437                    );
2438
2439                    return Err(DriverError::InvalidData);
2440                }
2441            },
2442        })
2443    }
2444}
2445
2446impl From<ImageViewInfoBuilder> for ImageViewInfo {
2447    fn from(info: ImageViewInfoBuilder) -> Self {
2448        info.build()
2449    }
2450}
2451
2452impl From<ImageViewInfo> for vk::ImageSubresourceRange {
2453    fn from(info: ImageViewInfo) -> Self {
2454        Self {
2455            aspect_mask: info.aspect_mask,
2456            base_mip_level: info.base_mip_level,
2457            base_array_layer: info.base_array_layer,
2458            layer_count: info.array_layer_count,
2459            level_count: info.mip_level_count,
2460        }
2461    }
2462}
2463
2464impl ImageViewInfoBuilder {
2465    /// Builds a new `ImageViewInfo`.
2466    #[inline(always)]
2467    pub fn build(self) -> ImageViewInfo {
2468        self.fallible_build().expect("all fields have defaults")
2469    }
2470}
2471
2472/// Specifies sample counts supported for an image used for storage operation.
2473///
2474/// Values must not exceed the device limits specified by the physical device properties.
2475///
2476/// See [`VkSampleCountFlagBits`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkSampleCountFlagBits.html).
2477#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
2478pub enum SampleCount {
2479    /// Single image sample. This is the usual mode.
2480    ///
2481    /// This is the default value.
2482    #[default]
2483    Type1,
2484
2485    /// Multiple image samples.
2486    Type2,
2487
2488    /// Multiple image samples.
2489    Type4,
2490
2491    /// Multiple image samples.
2492    Type8,
2493
2494    /// Multiple image samples.
2495    Type16,
2496
2497    /// Multiple image samples.
2498    Type32,
2499
2500    /// Multiple image samples.
2501    Type64,
2502}
2503
2504impl SampleCount {
2505    /// Returns `true` when the value represents a single sample mode.
2506    pub fn is_single(self) -> bool {
2507        matches!(self, Self::Type1)
2508    }
2509
2510    /// Returns `true` when the value represents a multiple sample mode.
2511    pub fn is_multiple(self) -> bool {
2512        matches!(
2513            self,
2514            Self::Type2 | Self::Type4 | Self::Type8 | Self::Type16 | Self::Type32 | Self::Type64
2515        )
2516    }
2517}
2518
2519impl From<SampleCount> for vk::SampleCountFlags {
2520    fn from(sample_count: SampleCount) -> Self {
2521        match sample_count {
2522            SampleCount::Type1 => Self::TYPE_1,
2523            SampleCount::Type2 => Self::TYPE_2,
2524            SampleCount::Type4 => Self::TYPE_4,
2525            SampleCount::Type8 => Self::TYPE_8,
2526            SampleCount::Type16 => Self::TYPE_16,
2527            SampleCount::Type32 => Self::TYPE_32,
2528            SampleCount::Type64 => Self::TYPE_64,
2529        }
2530    }
2531}
2532
2533#[derive(Debug)]
2534enum Sharing {
2535    Concurrent,
2536    Exclusive(ExclusiveSharing),
2537}
2538
2539impl Sharing {
2540    fn new(info: ImageInfo, sharing_mode: vk::SharingMode) -> Self {
2541        if sharing_mode == vk::SharingMode::CONCURRENT {
2542            Self::Concurrent
2543        } else {
2544            Self::Exclusive(ExclusiveSharing::new(info))
2545        }
2546    }
2547
2548    fn set_ranges(
2549        &self,
2550        dense: &Mutex<Option<DenseMap<SharingMode>>>,
2551        info: ImageInfo,
2552        sharing: SharingMode,
2553        sharing_ranges: &[vk::ImageSubresourceRange],
2554    ) {
2555        let Self::Exclusive(exclusive) = self else {
2556            return;
2557        };
2558
2559        exclusive.set_ranges(dense, info, sharing, sharing_ranges);
2560    }
2561}
2562
2563#[derive(Debug)]
2564struct UniformAccess(AtomicU8);
2565
2566impl UniformAccess {
2567    fn new(access: AccessType) -> Self {
2568        Self(AtomicU8::new(access_type_into_u8(access)))
2569    }
2570
2571    fn load(&self) -> AccessType {
2572        access_type_from_u8(self.0.load(Ordering::Acquire))
2573    }
2574
2575    fn swap(
2576        &self,
2577        next_access: AccessType,
2578        access_range: vk::ImageSubresourceRange,
2579    ) -> (AccessType, vk::ImageSubresourceRange) {
2580        debug_assert_eq!(access_range.base_array_layer, 0);
2581        debug_assert_eq!(access_range.base_mip_level, 0);
2582        debug_assert_eq!(access_range.layer_count, 1);
2583        debug_assert_eq!(access_range.level_count, 1);
2584        debug_assert_eq!(access_range.aspect_mask.as_raw().count_ones(), 1);
2585
2586        self.swap_range(next_access, access_range)
2587    }
2588
2589    fn swap_range(
2590        &self,
2591        next_access: AccessType,
2592        access_range: vk::ImageSubresourceRange,
2593    ) -> (AccessType, vk::ImageSubresourceRange) {
2594        let prev_access = access_type_from_u8(
2595            self.0
2596                .swap(access_type_into_u8(next_access), Ordering::AcqRel),
2597        );
2598
2599        (prev_access, access_range)
2600    }
2601}
2602
2603#[doc(hidden)]
2604pub mod bench {
2605    use super::*;
2606
2607    pub struct SwapAccessBenchHarness {
2608        access: Access,
2609        dense_access: Mutex<Option<DenseMap<AccessType>>>,
2610        info: ImageInfo,
2611    }
2612
2613    impl SwapAccessBenchHarness {
2614        pub fn new(layers: u32, mips: u32, format: vk::Format) -> Self {
2615            let info = ImageInfo::image_2d(1, 1, format, vk::ImageUsageFlags::empty())
2616                .into_builder()
2617                .array_layer_count(layers)
2618                .mip_level_count(mips)
2619                .build();
2620            Self {
2621                access: Access::new(info, AccessType::Nothing),
2622                dense_access: Mutex::new(None),
2623                info,
2624            }
2625        }
2626
2627        pub fn swap_access(
2628            &self,
2629            next_access: AccessType,
2630            mut access_range: vk::ImageSubresourceRange,
2631        ) -> Vec<(AccessType, vk::ImageSubresourceRange)> {
2632            #[cfg(feature = "checked")]
2633            {
2634                assert_aspect_mask_supported(access_range.aspect_mask);
2635                assert!(format_aspect_mask(self.info.format).contains(access_range.aspect_mask));
2636            }
2637
2638            if access_range.layer_count == vk::REMAINING_ARRAY_LAYERS {
2639                debug_assert!(access_range.base_array_layer < self.info.array_layer_count);
2640                access_range.layer_count =
2641                    self.info.array_layer_count - access_range.base_array_layer;
2642            }
2643
2644            debug_assert!(
2645                access_range.base_array_layer + access_range.layer_count
2646                    <= self.info.array_layer_count
2647            );
2648
2649            if access_range.level_count == vk::REMAINING_MIP_LEVELS {
2650                debug_assert!(access_range.base_mip_level < self.info.mip_level_count);
2651                access_range.level_count = self.info.mip_level_count - access_range.base_mip_level;
2652            }
2653
2654            debug_assert!(
2655                access_range.base_mip_level + access_range.level_count <= self.info.mip_level_count
2656            );
2657
2658            self.access
2659                .swap(&self.dense_access, self.info, next_access, access_range)
2660                .collect()
2661        }
2662    }
2663}
2664
2665#[cfg(test)]
2666mod test {
2667    use {
2668        super::*,
2669        rand::{Rng, SeedableRng, rngs::SmallRng},
2670        std::ops::Range,
2671    };
2672
2673    // ImageSubresourceRange does not implement PartialEq
2674    fn assert_access_ranges_eq(
2675        lhs: (AccessType, vk::ImageSubresourceRange),
2676        rhs: (AccessType, vk::ImageSubresourceRange),
2677    ) {
2678        assert_eq!(
2679            (
2680                lhs.0,
2681                lhs.1.aspect_mask,
2682                lhs.1.base_array_layer,
2683                lhs.1.layer_count,
2684                lhs.1.base_mip_level,
2685                lhs.1.level_count
2686            ),
2687            (
2688                rhs.0,
2689                rhs.1.aspect_mask,
2690                rhs.1.base_array_layer,
2691                rhs.1.layer_count,
2692                rhs.1.base_mip_level,
2693                rhs.1.level_count
2694            )
2695        );
2696    }
2697
2698    fn image_sync_subresource(
2699        aspect_mask: vk::ImageAspectFlags,
2700        array_layers: Range<u32>,
2701        mip_levels: Range<u32>,
2702    ) -> ImageSubresourceSyncInfo {
2703        ImageSubresourceSyncInfo {
2704            access_mask: vk::AccessFlags::SHADER_READ,
2705            layout: Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL),
2706            queue_family_index: None,
2707            range: image_subresource_range(aspect_mask, array_layers, mip_levels),
2708            stage_mask: vk::PipelineStageFlags::COMPUTE_SHADER,
2709        }
2710    }
2711
2712    #[test]
2713    pub fn image_access_basic() {
2714        use vk::ImageAspectFlags as A;
2715
2716        let mut image = DenseMap::new(
2717            image_subresource(vk::Format::R8G8B8A8_UNORM, 1, 1),
2718            AccessType::Nothing,
2719        );
2720
2721        {
2722            let mut accesses = DenseMapIter::new(
2723                &mut image,
2724                AccessType::AnyShaderWrite,
2725                image_subresource_range(A::COLOR, 0..1, 0..1),
2726            );
2727
2728            assert_access_ranges_eq(
2729                accesses.next().unwrap(),
2730                (
2731                    AccessType::Nothing,
2732                    image_subresource_range(A::COLOR, 0..1, 0..1),
2733                ),
2734            );
2735            assert!(accesses.next().is_none());
2736        }
2737
2738        {
2739            let mut accesses = DenseMapIter::new(
2740                &mut image,
2741                AccessType::AnyShaderReadOther,
2742                image_subresource_range(A::COLOR, 0..1, 0..1),
2743            );
2744
2745            assert_access_ranges_eq(
2746                accesses.next().unwrap(),
2747                (
2748                    AccessType::AnyShaderWrite,
2749                    image_subresource_range(A::COLOR, 0..1, 0..1),
2750                ),
2751            );
2752            assert!(accesses.next().is_none());
2753        }
2754    }
2755
2756    #[test]
2757    pub fn image_access_uniform() {
2758        use vk::ImageAspectFlags as A;
2759
2760        let info = image_subresource(vk::Format::R8G8B8A8_UNORM, 1, 1);
2761        let image = Access::new(info, AccessType::Nothing);
2762        let dense = Mutex::new(None);
2763
2764        let mut accesses = image.swap(
2765            &dense,
2766            info,
2767            AccessType::AnyShaderWrite,
2768            image_subresource_range(A::COLOR, 0..1, 0..1),
2769        );
2770
2771        assert_access_ranges_eq(
2772            accesses.next().unwrap(),
2773            (
2774                AccessType::Nothing,
2775                image_subresource_range(A::COLOR, 0..1, 0..1),
2776            ),
2777        );
2778        assert!(accesses.next().is_none());
2779    }
2780
2781    #[test]
2782    pub fn image_access_dual_aspect_tracks_aspects_independently() {
2783        use vk::ImageAspectFlags as A;
2784
2785        let info = image_subresource(vk::Format::D32_SFLOAT_S8_UINT, 1, 1);
2786        let image = Access::new(info, AccessType::Nothing);
2787        let dense = Mutex::new(None);
2788
2789        let mut accesses = image.swap(
2790            &dense,
2791            info,
2792            AccessType::DepthStencilAttachmentWrite,
2793            image_subresource_range(A::DEPTH, 0..1, 0..1),
2794        );
2795
2796        assert_access_ranges_eq(
2797            accesses.next().unwrap(),
2798            (
2799                AccessType::Nothing,
2800                image_subresource_range(A::DEPTH, 0..1, 0..1),
2801            ),
2802        );
2803        assert!(accesses.next().is_none());
2804
2805        let mut accesses = image.swap(
2806            &dense,
2807            info,
2808            AccessType::DepthStencilAttachmentRead,
2809            image_subresource_range(A::STENCIL, 0..1, 0..1),
2810        );
2811
2812        assert_access_ranges_eq(
2813            accesses.next().unwrap(),
2814            (
2815                AccessType::Nothing,
2816                image_subresource_range(A::STENCIL, 0..1, 0..1),
2817            ),
2818        );
2819        assert!(accesses.next().is_none());
2820
2821        let mut accesses = image.swap(
2822            &dense,
2823            info,
2824            AccessType::AnyShaderReadOther,
2825            image_subresource_range(A::DEPTH | A::STENCIL, 0..1, 0..1),
2826        );
2827
2828        assert_access_ranges_eq(
2829            accesses.next().unwrap(),
2830            (
2831                AccessType::DepthStencilAttachmentWrite,
2832                image_subresource_range(A::DEPTH, 0..1, 0..1),
2833            ),
2834        );
2835        assert_access_ranges_eq(
2836            accesses.next().unwrap(),
2837            (
2838                AccessType::DepthStencilAttachmentRead,
2839                image_subresource_range(A::STENCIL, 0..1, 0..1),
2840            ),
2841        );
2842        assert!(accesses.next().is_none());
2843    }
2844
2845    #[test]
2846    pub fn image_access_dense_promotes_only_on_partial_update() {
2847        use vk::ImageAspectFlags as A;
2848
2849        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
2850        let image = Access::new(info, AccessType::Nothing);
2851        let dense = Mutex::new(None);
2852
2853        let Access::Dense(access) = &image else {
2854            panic!("expected dense-capable access tracking");
2855        };
2856
2857        let mut accesses = image.swap(
2858            &dense,
2859            info,
2860            AccessType::AnyShaderReadOther,
2861            image_subresource_range(A::COLOR, 0..2, 0..2),
2862        );
2863
2864        assert_access_ranges_eq(
2865            accesses.next().unwrap(),
2866            (
2867                AccessType::Nothing,
2868                image_subresource_range(A::COLOR, 0..2, 0..2),
2869            ),
2870        );
2871        assert!(accesses.next().is_none());
2872        assert!(!access.is_dense_active());
2873
2874        let mut accesses = image.swap(
2875            &dense,
2876            info,
2877            AccessType::AnyShaderWrite,
2878            image_subresource_range(A::COLOR, 0..1, 0..1),
2879        );
2880
2881        assert_access_ranges_eq(
2882            accesses.next().unwrap(),
2883            (
2884                AccessType::AnyShaderReadOther,
2885                image_subresource_range(A::COLOR, 0..1, 0..1),
2886            ),
2887        );
2888        assert!(accesses.next().is_none());
2889        assert!(access.is_dense_active());
2890    }
2891
2892    #[test]
2893    pub fn image_access_dense_collapses_to_uniform_after_equalizing_updates() {
2894        use vk::ImageAspectFlags as A;
2895
2896        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
2897        let image = Access::new(info, AccessType::Nothing);
2898        let dense = Mutex::new(None);
2899
2900        let Access::Dense(access) = &image else {
2901            panic!("expected dense-capable access tracking");
2902        };
2903
2904        {
2905            let mut accesses = image.swap(
2906                &dense,
2907                info,
2908                AccessType::AnyShaderReadOther,
2909                image_subresource_range(A::COLOR, 0..1, 0..1),
2910            );
2911
2912            assert_access_ranges_eq(
2913                accesses.next().unwrap(),
2914                (
2915                    AccessType::Nothing,
2916                    image_subresource_range(A::COLOR, 0..1, 0..1),
2917                ),
2918            );
2919            assert!(accesses.next().is_none());
2920        }
2921
2922        assert!(access.is_dense_active());
2923
2924        {
2925            let mut accesses = image.swap(
2926                &dense,
2927                info,
2928                AccessType::AnyShaderReadOther,
2929                image_subresource_range(A::COLOR, 0..2, 0..2),
2930            );
2931
2932            assert!(accesses.next().is_some());
2933            while accesses.next().is_some() {}
2934        }
2935
2936        assert!(!access.is_dense_active());
2937        assert_eq!(access.load(), AccessType::AnyShaderReadOther);
2938
2939        let dense = dense.lock();
2940        #[cfg(not(feature = "parking_lot"))]
2941        let dense = dense.expect("poisoned image dense lock");
2942
2943        assert!(dense.is_none());
2944    }
2945
2946    #[test]
2947    pub fn image_access_dense_stays_active_for_mixed_updates() {
2948        use vk::ImageAspectFlags as A;
2949
2950        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
2951        let image = Access::new(info, AccessType::Nothing);
2952        let dense = Mutex::new(None);
2953
2954        let Access::Dense(access) = &image else {
2955            panic!("expected dense-capable access tracking");
2956        };
2957
2958        {
2959            let mut accesses = image.swap(
2960                &dense,
2961                info,
2962                AccessType::AnyShaderReadOther,
2963                image_subresource_range(A::COLOR, 0..1, 0..1),
2964            );
2965
2966            assert_access_ranges_eq(
2967                accesses.next().unwrap(),
2968                (
2969                    AccessType::Nothing,
2970                    image_subresource_range(A::COLOR, 0..1, 0..1),
2971                ),
2972            );
2973            assert!(accesses.next().is_none());
2974        }
2975
2976        {
2977            let mut accesses = image.swap(
2978                &dense,
2979                info,
2980                AccessType::AnyShaderWrite,
2981                image_subresource_range(A::COLOR, 1..2, 0..1),
2982            );
2983
2984            assert_access_ranges_eq(
2985                accesses.next().unwrap(),
2986                (
2987                    AccessType::Nothing,
2988                    image_subresource_range(A::COLOR, 1..2, 0..1),
2989                ),
2990            );
2991            assert!(accesses.next().is_none());
2992        }
2993
2994        assert!(access.is_dense_active());
2995
2996        let dense = dense.lock();
2997        #[cfg(not(feature = "parking_lot"))]
2998        let dense = dense.expect("poisoned image dense lock");
2999
3000        let dense_map = dense.as_ref().expect("missing dense access map");
3001        assert_eq!(
3002            dense_map.subresource(0, 0, 0),
3003            AccessType::AnyShaderReadOther
3004        );
3005        assert_eq!(dense_map.subresource(0, 1, 0), AccessType::AnyShaderWrite);
3006        assert_eq!(dense_map.subresource(0, 0, 1), AccessType::Nothing);
3007        assert_eq!(dense_map.subresource(0, 1, 1), AccessType::Nothing);
3008    }
3009
3010    #[test]
3011    pub fn image_access_dense_iter_drains_on_drop() {
3012        use vk::ImageAspectFlags as A;
3013
3014        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
3015        let image = Access::new(info, AccessType::Nothing);
3016        let dense = Mutex::new(None);
3017
3018        let Access::Dense(access) = &image else {
3019            panic!("expected dense-capable access tracking");
3020        };
3021
3022        {
3023            let mut accesses = image.swap(
3024                &dense,
3025                info,
3026                AccessType::AnyShaderReadOther,
3027                image_subresource_range(A::COLOR, 0..1, 0..1),
3028            );
3029
3030            assert_access_ranges_eq(
3031                accesses.next().unwrap(),
3032                (
3033                    AccessType::Nothing,
3034                    image_subresource_range(A::COLOR, 0..1, 0..1),
3035                ),
3036            );
3037            assert!(accesses.next().is_none());
3038        }
3039
3040        {
3041            let mut accesses = image.swap(
3042                &dense,
3043                info,
3044                AccessType::AnyShaderWrite,
3045                image_subresource_range(A::COLOR, 1..2, 0..1),
3046            );
3047
3048            assert_access_ranges_eq(
3049                accesses.next().unwrap(),
3050                (
3051                    AccessType::Nothing,
3052                    image_subresource_range(A::COLOR, 1..2, 0..1),
3053                ),
3054            );
3055            assert!(accesses.next().is_none());
3056        }
3057
3058        let mut accesses = image.swap(
3059            &dense,
3060            info,
3061            AccessType::HostRead,
3062            image_subresource_range(A::COLOR, 0..2, 0..2),
3063        );
3064
3065        assert!(accesses.next().is_some());
3066        drop(accesses);
3067
3068        assert!(!access.is_dense_active());
3069        assert_eq!(access.load(), AccessType::HostRead);
3070
3071        let dense = dense.lock();
3072        #[cfg(not(feature = "parking_lot"))]
3073        let dense = dense.expect("poisoned image dense lock");
3074
3075        assert!(dense.is_none());
3076    }
3077
3078    #[test]
3079    pub fn image_access_color() {
3080        use vk::ImageAspectFlags as A;
3081
3082        let mut image = DenseMap::new(
3083            image_subresource(vk::Format::R8G8B8A8_UNORM, 3, 3),
3084            AccessType::Nothing,
3085        );
3086
3087        {
3088            let mut accesses = DenseMapIter::new(
3089                &mut image,
3090                AccessType::AnyShaderWrite,
3091                image_subresource_range(A::COLOR, 0..3, 0..3),
3092            );
3093
3094            assert_access_ranges_eq(
3095                accesses.next().unwrap(),
3096                (
3097                    AccessType::Nothing,
3098                    image_subresource_range(A::COLOR, 0..3, 0..3),
3099                ),
3100            );
3101            assert!(accesses.next().is_none());
3102        }
3103
3104        {
3105            let mut accesses = DenseMapIter::new(
3106                &mut image,
3107                AccessType::AnyShaderReadOther,
3108                image_subresource_range(A::COLOR, 0..1, 0..1),
3109            );
3110
3111            assert_access_ranges_eq(
3112                accesses.next().unwrap(),
3113                (
3114                    AccessType::AnyShaderWrite,
3115                    image_subresource_range(A::COLOR, 0..1, 0..1),
3116                ),
3117            );
3118            assert!(accesses.next().is_none());
3119        }
3120
3121        {
3122            let mut accesses = DenseMapIter::new(
3123                &mut image,
3124                AccessType::ComputeShaderWrite,
3125                image_subresource_range(A::COLOR, 0..3, 0..3),
3126            );
3127
3128            assert_access_ranges_eq(
3129                accesses.next().unwrap(),
3130                (
3131                    AccessType::AnyShaderReadOther,
3132                    image_subresource_range(A::COLOR, 0..1, 0..1),
3133                ),
3134            );
3135            assert_access_ranges_eq(
3136                accesses.next().unwrap(),
3137                (
3138                    AccessType::AnyShaderWrite,
3139                    image_subresource_range(A::COLOR, 0..1, 1..3),
3140                ),
3141            );
3142            assert_access_ranges_eq(
3143                accesses.next().unwrap(),
3144                (
3145                    AccessType::AnyShaderWrite,
3146                    image_subresource_range(A::COLOR, 1..3, 0..3),
3147                ),
3148            );
3149            assert!(accesses.next().is_none());
3150        }
3151
3152        {
3153            let mut accesses = DenseMapIter::new(
3154                &mut image,
3155                AccessType::HostRead,
3156                image_subresource_range(A::COLOR, 0..3, 0..3),
3157            );
3158
3159            assert_access_ranges_eq(
3160                accesses.next().unwrap(),
3161                (
3162                    AccessType::ComputeShaderWrite,
3163                    image_subresource_range(A::COLOR, 0..3, 0..3),
3164                ),
3165            );
3166            assert!(accesses.next().is_none());
3167        }
3168
3169        {
3170            let mut accesses = DenseMapIter::new(
3171                &mut image,
3172                AccessType::HostWrite,
3173                image_subresource_range(A::COLOR, 1..2, 1..2),
3174            );
3175
3176            assert_access_ranges_eq(
3177                accesses.next().unwrap(),
3178                (
3179                    AccessType::HostRead,
3180                    image_subresource_range(A::COLOR, 1..2, 1..2),
3181                ),
3182            );
3183            assert!(accesses.next().is_none());
3184        }
3185
3186        {
3187            let mut accesses = DenseMapIter::new(
3188                &mut image,
3189                AccessType::GeometryShaderReadOther,
3190                image_subresource_range(A::COLOR, 0..3, 0..3),
3191            );
3192
3193            assert_access_ranges_eq(
3194                accesses.next().unwrap(),
3195                (
3196                    AccessType::HostRead,
3197                    image_subresource_range(A::COLOR, 0..1, 0..3),
3198                ),
3199            );
3200            assert_access_ranges_eq(
3201                accesses.next().unwrap(),
3202                (
3203                    AccessType::HostRead,
3204                    image_subresource_range(A::COLOR, 1..2, 0..1),
3205                ),
3206            );
3207            assert_access_ranges_eq(
3208                accesses.next().unwrap(),
3209                (
3210                    AccessType::HostWrite,
3211                    image_subresource_range(A::COLOR, 1..2, 1..2),
3212                ),
3213            );
3214            assert_access_ranges_eq(
3215                accesses.next().unwrap(),
3216                (
3217                    AccessType::HostRead,
3218                    image_subresource_range(A::COLOR, 1..2, 2..3),
3219                ),
3220            );
3221            assert_access_ranges_eq(
3222                accesses.next().unwrap(),
3223                (
3224                    AccessType::HostRead,
3225                    image_subresource_range(A::COLOR, 2..3, 0..3),
3226                ),
3227            );
3228            assert!(accesses.next().is_none());
3229        }
3230
3231        {
3232            let mut accesses = DenseMapIter::new(
3233                &mut image,
3234                AccessType::VertexBuffer,
3235                image_subresource_range(A::COLOR, 0..3, 1..2),
3236            );
3237
3238            assert_access_ranges_eq(
3239                accesses.next().unwrap(),
3240                (
3241                    AccessType::GeometryShaderReadOther,
3242                    image_subresource_range(A::COLOR, 0..3, 1..2),
3243                ),
3244            );
3245            assert!(accesses.next().is_none());
3246        }
3247
3248        {
3249            let mut accesses = DenseMapIter::new(
3250                &mut image,
3251                AccessType::ColorAttachmentRead,
3252                image_subresource_range(A::COLOR, 0..3, 0..3),
3253            );
3254
3255            assert_access_ranges_eq(
3256                accesses.next().unwrap(),
3257                (
3258                    AccessType::GeometryShaderReadOther,
3259                    image_subresource_range(A::COLOR, 0..1, 0..1),
3260                ),
3261            );
3262            assert_access_ranges_eq(
3263                accesses.next().unwrap(),
3264                (
3265                    AccessType::VertexBuffer,
3266                    image_subresource_range(A::COLOR, 0..1, 1..2),
3267                ),
3268            );
3269            assert_access_ranges_eq(
3270                accesses.next().unwrap(),
3271                (
3272                    AccessType::GeometryShaderReadOther,
3273                    image_subresource_range(A::COLOR, 0..1, 2..3),
3274                ),
3275            );
3276            assert_access_ranges_eq(
3277                accesses.next().unwrap(),
3278                (
3279                    AccessType::GeometryShaderReadOther,
3280                    image_subresource_range(A::COLOR, 1..2, 0..1),
3281                ),
3282            );
3283            assert_access_ranges_eq(
3284                accesses.next().unwrap(),
3285                (
3286                    AccessType::VertexBuffer,
3287                    image_subresource_range(A::COLOR, 1..2, 1..2),
3288                ),
3289            );
3290            assert_access_ranges_eq(
3291                accesses.next().unwrap(),
3292                (
3293                    AccessType::GeometryShaderReadOther,
3294                    image_subresource_range(A::COLOR, 1..2, 2..3),
3295                ),
3296            );
3297            assert_access_ranges_eq(
3298                accesses.next().unwrap(),
3299                (
3300                    AccessType::GeometryShaderReadOther,
3301                    image_subresource_range(A::COLOR, 2..3, 0..1),
3302                ),
3303            );
3304            assert_access_ranges_eq(
3305                accesses.next().unwrap(),
3306                (
3307                    AccessType::VertexBuffer,
3308                    image_subresource_range(A::COLOR, 2..3, 1..2),
3309                ),
3310            );
3311            assert_access_ranges_eq(
3312                accesses.next().unwrap(),
3313                (
3314                    AccessType::GeometryShaderReadOther,
3315                    image_subresource_range(A::COLOR, 2..3, 2..3),
3316                ),
3317            );
3318            assert!(accesses.next().is_none());
3319        }
3320    }
3321
3322    #[test]
3323    pub fn image_access_layers() {
3324        use vk::ImageAspectFlags as A;
3325
3326        let mut image = DenseMap::new(
3327            image_subresource(vk::Format::R8G8B8A8_UNORM, 3, 1),
3328            AccessType::Nothing,
3329        );
3330
3331        {
3332            let mut accesses = DenseMapIter::new(
3333                &mut image,
3334                AccessType::AnyShaderWrite,
3335                image_subresource_range(A::COLOR, 0..3, 0..1),
3336            );
3337
3338            assert_access_ranges_eq(
3339                accesses.next().unwrap(),
3340                (
3341                    AccessType::Nothing,
3342                    image_subresource_range(A::COLOR, 0..3, 0..1),
3343                ),
3344            );
3345            assert!(accesses.next().is_none());
3346        }
3347
3348        {
3349            let mut accesses = DenseMapIter::new(
3350                &mut image,
3351                AccessType::AnyShaderReadOther,
3352                image_subresource_range(A::COLOR, 2..3, 0..1),
3353            );
3354
3355            assert_access_ranges_eq(
3356                accesses.next().unwrap(),
3357                (
3358                    AccessType::AnyShaderWrite,
3359                    image_subresource_range(A::COLOR, 2..3, 0..1),
3360                ),
3361            );
3362            assert!(accesses.next().is_none());
3363        }
3364
3365        {
3366            let mut accesses = DenseMapIter::new(
3367                &mut image,
3368                AccessType::HostRead,
3369                image_subresource_range(A::COLOR, 0..2, 0..1),
3370            );
3371
3372            assert_access_ranges_eq(
3373                accesses.next().unwrap(),
3374                (
3375                    AccessType::AnyShaderWrite,
3376                    image_subresource_range(A::COLOR, 0..2, 0..1),
3377                ),
3378            );
3379            assert!(accesses.next().is_none());
3380        }
3381
3382        {
3383            let mut accesses = DenseMapIter::new(
3384                &mut image,
3385                AccessType::AnyShaderReadOther,
3386                image_subresource_range(A::COLOR, 0..1, 0..1),
3387            );
3388
3389            assert_access_ranges_eq(
3390                accesses.next().unwrap(),
3391                (
3392                    AccessType::HostRead,
3393                    image_subresource_range(A::COLOR, 0..1, 0..1),
3394                ),
3395            );
3396            assert!(accesses.next().is_none());
3397        }
3398
3399        {
3400            let mut accesses = DenseMapIter::new(
3401                &mut image,
3402                AccessType::AnyShaderReadOther,
3403                image_subresource_range(A::COLOR, 1..2, 0..1),
3404            );
3405
3406            assert_access_ranges_eq(
3407                accesses.next().unwrap(),
3408                (
3409                    AccessType::HostRead,
3410                    image_subresource_range(A::COLOR, 1..2, 0..1),
3411                ),
3412            );
3413            assert!(accesses.next().is_none());
3414        }
3415
3416        {
3417            let mut accesses = DenseMapIter::new(
3418                &mut image,
3419                AccessType::HostWrite,
3420                image_subresource_range(A::COLOR, 0..3, 0..1),
3421            );
3422
3423            assert_access_ranges_eq(
3424                accesses.next().unwrap(),
3425                (
3426                    AccessType::AnyShaderReadOther,
3427                    image_subresource_range(A::COLOR, 0..3, 0..1),
3428                ),
3429            );
3430            assert!(accesses.next().is_none());
3431        }
3432    }
3433
3434    #[test]
3435    pub fn image_access_levels() {
3436        use vk::ImageAspectFlags as A;
3437
3438        let mut image = DenseMap::new(
3439            image_subresource(vk::Format::R8G8B8A8_UNORM, 1, 3),
3440            AccessType::Nothing,
3441        );
3442
3443        {
3444            let mut accesses = DenseMapIter::new(
3445                &mut image,
3446                AccessType::AnyShaderWrite,
3447                image_subresource_range(A::COLOR, 0..1, 0..3),
3448            );
3449
3450            assert_access_ranges_eq(
3451                accesses.next().unwrap(),
3452                (
3453                    AccessType::Nothing,
3454                    image_subresource_range(A::COLOR, 0..1, 0..3),
3455                ),
3456            );
3457            assert!(accesses.next().is_none());
3458        }
3459
3460        {
3461            let mut accesses = DenseMapIter::new(
3462                &mut image,
3463                AccessType::AnyShaderReadOther,
3464                image_subresource_range(A::COLOR, 0..1, 2..3),
3465            );
3466
3467            assert_access_ranges_eq(
3468                accesses.next().unwrap(),
3469                (
3470                    AccessType::AnyShaderWrite,
3471                    image_subresource_range(A::COLOR, 0..1, 2..3),
3472                ),
3473            );
3474            assert!(accesses.next().is_none());
3475        }
3476
3477        {
3478            let mut accesses = DenseMapIter::new(
3479                &mut image,
3480                AccessType::HostRead,
3481                image_subresource_range(A::COLOR, 0..1, 0..2),
3482            );
3483
3484            assert_access_ranges_eq(
3485                accesses.next().unwrap(),
3486                (
3487                    AccessType::AnyShaderWrite,
3488                    image_subresource_range(A::COLOR, 0..1, 0..2),
3489                ),
3490            );
3491            assert!(accesses.next().is_none());
3492        }
3493
3494        {
3495            let mut accesses = DenseMapIter::new(
3496                &mut image,
3497                AccessType::AnyShaderReadOther,
3498                image_subresource_range(A::COLOR, 0..1, 0..1),
3499            );
3500
3501            assert_access_ranges_eq(
3502                accesses.next().unwrap(),
3503                (
3504                    AccessType::HostRead,
3505                    image_subresource_range(A::COLOR, 0..1, 0..1),
3506                ),
3507            );
3508            assert!(accesses.next().is_none());
3509        }
3510
3511        {
3512            let mut accesses = DenseMapIter::new(
3513                &mut image,
3514                AccessType::AnyShaderReadOther,
3515                image_subresource_range(A::COLOR, 0..1, 1..2),
3516            );
3517
3518            assert_access_ranges_eq(
3519                accesses.next().unwrap(),
3520                (
3521                    AccessType::HostRead,
3522                    image_subresource_range(A::COLOR, 0..1, 1..2),
3523                ),
3524            );
3525            assert!(accesses.next().is_none());
3526        }
3527
3528        {
3529            let mut accesses = DenseMapIter::new(
3530                &mut image,
3531                AccessType::HostWrite,
3532                image_subresource_range(A::COLOR, 0..1, 0..3),
3533            );
3534
3535            assert_access_ranges_eq(
3536                accesses.next().unwrap(),
3537                (
3538                    AccessType::AnyShaderReadOther,
3539                    image_subresource_range(A::COLOR, 0..1, 0..3),
3540                ),
3541            );
3542            assert!(accesses.next().is_none());
3543        }
3544    }
3545
3546    #[test]
3547    pub fn image_access_depth_stencil() {
3548        use vk::ImageAspectFlags as A;
3549
3550        let mut image = DenseMap::new(
3551            image_subresource(vk::Format::D24_UNORM_S8_UINT, 4, 3),
3552            AccessType::Nothing,
3553        );
3554
3555        {
3556            let mut accesses = DenseMapIter::new(
3557                &mut image,
3558                AccessType::AnyShaderWrite,
3559                image_subresource_range(A::DEPTH, 0..4, 0..1),
3560            );
3561
3562            assert_access_ranges_eq(
3563                accesses.next().unwrap(),
3564                (
3565                    AccessType::Nothing,
3566                    image_subresource_range(A::DEPTH, 0..4, 0..1),
3567                ),
3568            );
3569            assert!(accesses.next().is_none());
3570        }
3571
3572        {
3573            let mut accesses = DenseMapIter::new(
3574                &mut image,
3575                AccessType::AnyShaderWrite,
3576                image_subresource_range(A::STENCIL, 0..4, 1..2),
3577            );
3578
3579            assert_access_ranges_eq(
3580                accesses.next().unwrap(),
3581                (
3582                    AccessType::Nothing,
3583                    image_subresource_range(A::STENCIL, 0..4, 1..2),
3584                ),
3585            );
3586            assert!(accesses.next().is_none());
3587        }
3588
3589        {
3590            let mut accesses = DenseMapIter::new(
3591                &mut image,
3592                AccessType::AnyShaderReadOther,
3593                image_subresource_range(A::DEPTH | A::STENCIL, 0..4, 0..2),
3594            );
3595
3596            assert_access_ranges_eq(
3597                accesses.next().unwrap(),
3598                (
3599                    AccessType::AnyShaderWrite,
3600                    image_subresource_range(A::DEPTH, 0..1, 0..1),
3601                ),
3602            );
3603            assert_access_ranges_eq(
3604                accesses.next().unwrap(),
3605                (
3606                    AccessType::Nothing,
3607                    image_subresource_range(A::DEPTH, 0..1, 1..2),
3608                ),
3609            );
3610            assert_access_ranges_eq(
3611                accesses.next().unwrap(),
3612                (
3613                    AccessType::AnyShaderWrite,
3614                    image_subresource_range(A::DEPTH, 1..2, 0..1),
3615                ),
3616            );
3617            assert_access_ranges_eq(
3618                accesses.next().unwrap(),
3619                (
3620                    AccessType::Nothing,
3621                    image_subresource_range(A::DEPTH, 1..2, 1..2),
3622                ),
3623            );
3624            assert_access_ranges_eq(
3625                accesses.next().unwrap(),
3626                (
3627                    AccessType::AnyShaderWrite,
3628                    image_subresource_range(A::DEPTH, 2..3, 0..1),
3629                ),
3630            );
3631            assert_access_ranges_eq(
3632                accesses.next().unwrap(),
3633                (
3634                    AccessType::Nothing,
3635                    image_subresource_range(A::DEPTH, 2..3, 1..2),
3636                ),
3637            );
3638            assert_access_ranges_eq(
3639                accesses.next().unwrap(),
3640                (
3641                    AccessType::AnyShaderWrite,
3642                    image_subresource_range(A::DEPTH, 3..4, 0..1),
3643                ),
3644            );
3645            assert_access_ranges_eq(
3646                accesses.next().unwrap(),
3647                (
3648                    AccessType::Nothing,
3649                    image_subresource_range(A::DEPTH, 3..4, 1..2),
3650                ),
3651            );
3652            assert_access_ranges_eq(
3653                accesses.next().unwrap(),
3654                (
3655                    AccessType::Nothing,
3656                    image_subresource_range(A::STENCIL, 0..1, 0..1),
3657                ),
3658            );
3659            assert_access_ranges_eq(
3660                accesses.next().unwrap(),
3661                (
3662                    AccessType::AnyShaderWrite,
3663                    image_subresource_range(A::STENCIL, 0..1, 1..2),
3664                ),
3665            );
3666            assert_access_ranges_eq(
3667                accesses.next().unwrap(),
3668                (
3669                    AccessType::Nothing,
3670                    image_subresource_range(A::STENCIL, 1..2, 0..1),
3671                ),
3672            );
3673            assert_access_ranges_eq(
3674                accesses.next().unwrap(),
3675                (
3676                    AccessType::AnyShaderWrite,
3677                    image_subresource_range(A::STENCIL, 1..2, 1..2),
3678                ),
3679            );
3680            assert_access_ranges_eq(
3681                accesses.next().unwrap(),
3682                (
3683                    AccessType::Nothing,
3684                    image_subresource_range(A::STENCIL, 2..3, 0..1),
3685                ),
3686            );
3687            assert_access_ranges_eq(
3688                accesses.next().unwrap(),
3689                (
3690                    AccessType::AnyShaderWrite,
3691                    image_subresource_range(A::STENCIL, 2..3, 1..2),
3692                ),
3693            );
3694            assert_access_ranges_eq(
3695                accesses.next().unwrap(),
3696                (
3697                    AccessType::Nothing,
3698                    image_subresource_range(A::STENCIL, 3..4, 0..1),
3699                ),
3700            );
3701            assert_access_ranges_eq(
3702                accesses.next().unwrap(),
3703                (
3704                    AccessType::AnyShaderWrite,
3705                    image_subresource_range(A::STENCIL, 3..4, 1..2),
3706                ),
3707            );
3708            assert!(accesses.next().is_none());
3709        }
3710
3711        {
3712            let mut accesses = DenseMapIter::new(
3713                &mut image,
3714                AccessType::AccelerationStructureBuildWrite,
3715                image_subresource_range(A::DEPTH | A::STENCIL, 0..4, 0..2),
3716            );
3717
3718            assert_access_ranges_eq(
3719                accesses.next().unwrap(),
3720                (
3721                    AccessType::AnyShaderReadOther,
3722                    image_subresource_range(A::DEPTH | A::STENCIL, 0..4, 0..2),
3723                ),
3724            );
3725            assert!(accesses.next().is_none());
3726        }
3727
3728        {
3729            let mut accesses = DenseMapIter::new(
3730                &mut image,
3731                AccessType::AccelerationStructureBuildRead,
3732                image_subresource_range(A::DEPTH, 1..3, 0..2),
3733            );
3734
3735            assert_access_ranges_eq(
3736                accesses.next().unwrap(),
3737                (
3738                    AccessType::AccelerationStructureBuildWrite,
3739                    image_subresource_range(A::DEPTH, 1..3, 0..2),
3740                ),
3741            );
3742            assert!(accesses.next().is_none());
3743        }
3744    }
3745
3746    #[test]
3747    pub fn image_access_stencil() {
3748        use vk::ImageAspectFlags as A;
3749
3750        let mut image = DenseMap::new(
3751            image_subresource(vk::Format::S8_UINT, 2, 2),
3752            AccessType::Nothing,
3753        );
3754
3755        {
3756            let mut accesses = DenseMapIter::new(
3757                &mut image,
3758                AccessType::AnyShaderWrite,
3759                image_subresource_range(A::STENCIL, 0..2, 0..1),
3760            );
3761
3762            assert_access_ranges_eq(
3763                accesses.next().unwrap(),
3764                (
3765                    AccessType::Nothing,
3766                    image_subresource_range(A::STENCIL, 0..2, 0..1),
3767                ),
3768            );
3769            assert!(accesses.next().is_none());
3770        }
3771
3772        {
3773            let mut accesses = DenseMapIter::new(
3774                &mut image,
3775                AccessType::AnyShaderReadOther,
3776                image_subresource_range(A::STENCIL, 0..2, 1..2),
3777            );
3778
3779            assert_access_ranges_eq(
3780                accesses.next().unwrap(),
3781                (
3782                    AccessType::Nothing,
3783                    image_subresource_range(A::STENCIL, 0..2, 1..2),
3784                ),
3785            );
3786            assert!(accesses.next().is_none());
3787        }
3788
3789        {
3790            let mut accesses = DenseMapIter::new(
3791                &mut image,
3792                AccessType::HostRead,
3793                image_subresource_range(A::STENCIL, 0..2, 0..2),
3794            );
3795
3796            assert_access_ranges_eq(
3797                accesses.next().unwrap(),
3798                (
3799                    AccessType::AnyShaderWrite,
3800                    image_subresource_range(A::STENCIL, 0..1, 0..1),
3801                ),
3802            );
3803            assert_access_ranges_eq(
3804                accesses.next().unwrap(),
3805                (
3806                    AccessType::AnyShaderReadOther,
3807                    image_subresource_range(A::STENCIL, 0..1, 1..2),
3808                ),
3809            );
3810            assert_access_ranges_eq(
3811                accesses.next().unwrap(),
3812                (
3813                    AccessType::AnyShaderWrite,
3814                    image_subresource_range(A::STENCIL, 1..2, 0..1),
3815                ),
3816            );
3817            assert_access_ranges_eq(
3818                accesses.next().unwrap(),
3819                (
3820                    AccessType::AnyShaderReadOther,
3821                    image_subresource_range(A::STENCIL, 1..2, 1..2),
3822                ),
3823            );
3824            assert!(accesses.next().is_none());
3825        }
3826    }
3827
3828    #[test]
3829    pub fn image_info_cube() {
3830        let info = ImageInfo::cube(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3831        let builder = info.into_builder().build();
3832
3833        assert_eq!(info, builder);
3834    }
3835
3836    #[test]
3837    pub fn image_info_cube_builder() {
3838        let info = ImageInfo::cube(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3839        let builder = ImageInfoBuilder::default()
3840            .image_type(vk::ImageType::TYPE_2D)
3841            .format(vk::Format::R32_SFLOAT)
3842            .width(42)
3843            .height(42)
3844            .depth(1)
3845            .array_layer_count(6)
3846            .flags(vk::ImageCreateFlags::CUBE_COMPATIBLE)
3847            .build();
3848
3849        assert_eq!(info, builder);
3850    }
3851
3852    #[test]
3853    pub fn image_info_image_1d() {
3854        let info = ImageInfo::image_1d(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3855        let builder = info.into_builder().build();
3856
3857        assert_eq!(info, builder);
3858    }
3859
3860    #[test]
3861    pub fn image_info_image_1d_builder() {
3862        let info = ImageInfo::image_1d(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3863        let builder = ImageInfoBuilder::default()
3864            .image_type(vk::ImageType::TYPE_1D)
3865            .format(vk::Format::R32_SFLOAT)
3866            .width(42)
3867            .height(1)
3868            .depth(1)
3869            .build();
3870
3871        assert_eq!(info, builder);
3872    }
3873
3874    #[test]
3875    pub fn image_info_image_2d() {
3876        let info =
3877            ImageInfo::image_2d(42, 84, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3878        let builder = info.into_builder().build();
3879
3880        assert_eq!(info, builder);
3881    }
3882
3883    #[test]
3884    pub fn image_info_image_2d_builder() {
3885        let info =
3886            ImageInfo::image_2d(42, 84, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3887        let builder = ImageInfoBuilder::default()
3888            .image_type(vk::ImageType::TYPE_2D)
3889            .format(vk::Format::R32_SFLOAT)
3890            .width(42)
3891            .height(84)
3892            .depth(1)
3893            .build();
3894
3895        assert_eq!(info, builder);
3896    }
3897
3898    #[test]
3899    pub fn image_info_image_2d_array() {
3900        let info = ImageInfo::image_2d_array(
3901            42,
3902            84,
3903            100,
3904            vk::Format::default(),
3905            vk::ImageUsageFlags::empty(),
3906        );
3907        let builder = info.into_builder().build();
3908
3909        assert_eq!(info, builder);
3910    }
3911
3912    #[test]
3913    pub fn image_info_image_2d_array_builder() {
3914        let info = ImageInfo::image_2d_array(
3915            42,
3916            84,
3917            100,
3918            vk::Format::R32_SFLOAT,
3919            vk::ImageUsageFlags::empty(),
3920        );
3921        let builder = ImageInfoBuilder::default()
3922            .image_type(vk::ImageType::TYPE_2D)
3923            .format(vk::Format::R32_SFLOAT)
3924            .width(42)
3925            .height(84)
3926            .depth(1)
3927            .array_layer_count(100)
3928            .build();
3929
3930        assert_eq!(info, builder);
3931    }
3932
3933    #[test]
3934    pub fn image_info_image_3d() {
3935        let info = ImageInfo::image_3d(
3936            42,
3937            84,
3938            100,
3939            vk::Format::R32_SFLOAT,
3940            vk::ImageUsageFlags::empty(),
3941        );
3942        let builder = info.into_builder().build();
3943
3944        assert_eq!(info, builder);
3945    }
3946
3947    #[test]
3948    pub fn image_info_image_3d_builder() {
3949        let info = ImageInfo::image_3d(
3950            42,
3951            84,
3952            100,
3953            vk::Format::R32_SFLOAT,
3954            vk::ImageUsageFlags::empty(),
3955        );
3956        let builder = ImageInfoBuilder::default()
3957            .image_type(vk::ImageType::TYPE_3D)
3958            .format(vk::Format::R32_SFLOAT)
3959            .width(42)
3960            .height(84)
3961            .depth(100)
3962            .build();
3963
3964        assert_eq!(info, builder);
3965    }
3966
3967    #[test]
3968    pub fn image_info_builder_defaults() {
3969        let info = ImageInfo {
3970            array_layer_count: 1,
3971            alloc_dedicated: false,
3972            depth: 0,
3973            flags: vk::ImageCreateFlags::empty(),
3974            format: vk::Format::UNDEFINED,
3975            height: 0,
3976            host_readable: false,
3977            host_writable: false,
3978            mip_level_count: 1,
3979            sample_count: SampleCount::Type1,
3980            sharing_mode: vk::SharingMode::EXCLUSIVE,
3981            tiling: vk::ImageTiling::OPTIMAL,
3982            image_type: vk::ImageType::TYPE_2D,
3983            usage: vk::ImageUsageFlags::empty(),
3984            width: 0,
3985        };
3986
3987        assert_eq!(ImageInfoBuilder::default().build(), info);
3988    }
3989
3990    fn image_access_fuzz(aspect_count: u8, array_layer_count: u32, mip_level_count: u32) {
3991        const FUZZ_COUNT: usize = 100_000;
3992        static ACCESS_TYPES: &[AccessType] = &[
3993            AccessType::AnyShaderReadOther,
3994            AccessType::AnyShaderWrite,
3995            AccessType::ColorAttachmentRead,
3996            AccessType::ColorAttachmentWrite,
3997            AccessType::HostRead,
3998            AccessType::HostWrite,
3999            AccessType::Nothing,
4000        ];
4001
4002        let fmt = match aspect_count {
4003            1 => vk::Format::R8G8B8A8_UNORM,
4004            2 => vk::Format::D24_UNORM_S8_UINT,
4005            _ => unreachable!(),
4006        };
4007
4008        let mut rng = SmallRng::seed_from_u64(42);
4009        let total = (aspect_count as u32 * array_layer_count * mip_level_count) as usize;
4010        let mut access_map = DenseMap::new(
4011            image_subresource(fmt, array_layer_count, mip_level_count),
4012            AccessType::Nothing,
4013        );
4014        let mut data = vec![AccessType::Nothing; total];
4015
4016        let aspect_bits = format_aspect_mask(fmt);
4017
4018        for _ in 0..FUZZ_COUNT {
4019            let new_access = ACCESS_TYPES[rng.random_range(..ACCESS_TYPES.len())];
4020
4021            // Pick a valid aspect mask from the format's supported aspects
4022            let aspect_mask = if aspect_count == 2 && rng.random_bool(0.5) {
4023                aspect_bits
4024            } else {
4025                let bit_index =
4026                    rng.random_range(..aspect_count) + aspect_bits.as_raw().trailing_zeros() as u8;
4027                vk::ImageAspectFlags::from_raw(1 << bit_index)
4028            };
4029
4030            let layer_start = rng.random_range(..array_layer_count);
4031            let layer_end = rng.random_range(layer_start + 1..=array_layer_count);
4032            let mip_start = rng.random_range(..mip_level_count);
4033            let mip_end = rng.random_range(mip_start + 1..=mip_level_count);
4034
4035            let range =
4036                image_subresource_range(aspect_mask, layer_start..layer_end, mip_start..mip_end);
4037
4038            for (prev, range) in access_map.swap(new_access, range) {
4039                let range_mask = range.aspect_mask.as_raw();
4040                for ai in 0..range_mask.count_ones() as u8 {
4041                    let bit = range_mask.trailing_zeros() + ai as u32;
4042                    let a = (aspect_bits.as_raw() & ((1 << bit) - 1)).count_ones() as u8;
4043                    for l in range.base_array_layer..range.base_array_layer + range.layer_count {
4044                        for m in range.base_mip_level..range.base_mip_level + range.level_count {
4045                            let idx = (l * aspect_count as u32 * mip_level_count
4046                                + m * aspect_count as u32
4047                                + a as u32) as usize;
4048                            assert_eq!(
4049                                data[idx], prev,
4050                                "prev mismatch at aspect={a} layer={l} mip={m} idx={idx}: expected {prev:?}, got {:?}",
4051                                data[idx],
4052                            );
4053                        }
4054                    }
4055                }
4056            }
4057
4058            for a in 0..aspect_count {
4059                let bit = aspect_bits.as_raw().trailing_zeros() as u8 + a;
4060                if aspect_mask.as_raw() & (1 << bit) == 0 {
4061                    continue;
4062                }
4063                for l in layer_start..layer_end {
4064                    for m in mip_start..mip_end {
4065                        let idx = access_map.idx(a, l, m);
4066                        data[idx] = new_access;
4067                    }
4068                }
4069            }
4070        }
4071    }
4072
4073    #[test]
4074    pub fn image_access_fuzz_small() {
4075        image_access_fuzz(1, 3, 3);
4076    }
4077
4078    #[test]
4079    pub fn image_access_fuzz_medium() {
4080        image_access_fuzz(2, 4, 3);
4081    }
4082
4083    #[test]
4084    pub fn image_access_fuzz_large() {
4085        image_access_fuzz(1, 10, 10);
4086    }
4087
4088    fn image_access_fuzz_through_access(
4089        aspect_count: u8,
4090        array_layer_count: u32,
4091        mip_level_count: u32,
4092    ) {
4093        const FUZZ_COUNT: usize = 10_000;
4094        static ACCESS_TYPES: &[AccessType] = &[
4095            AccessType::AnyShaderReadOther,
4096            AccessType::AnyShaderWrite,
4097            AccessType::ColorAttachmentRead,
4098            AccessType::ColorAttachmentWrite,
4099            AccessType::HostRead,
4100            AccessType::HostWrite,
4101            AccessType::Nothing,
4102        ];
4103
4104        let fmt = match aspect_count {
4105            1 => vk::Format::R8G8B8A8_UNORM,
4106            2 => vk::Format::D24_UNORM_S8_UINT,
4107            _ => unreachable!(),
4108        };
4109
4110        let mut rng = SmallRng::seed_from_u64(42);
4111        let info = image_subresource(fmt, array_layer_count, mip_level_count);
4112        let total = (aspect_count as u32 * array_layer_count * mip_level_count) as usize;
4113        let access = Access::new(info, AccessType::Nothing);
4114        let dense = Mutex::new(None);
4115        let mut data = vec![AccessType::Nothing; total];
4116
4117        let aspect_bits = format_aspect_mask(fmt);
4118
4119        for _ in 0..FUZZ_COUNT {
4120            let new_access = ACCESS_TYPES[rng.random_range(..ACCESS_TYPES.len())];
4121
4122            let aspect_mask = if aspect_count == 2 && rng.random_bool(0.5) {
4123                aspect_bits
4124            } else {
4125                let bit_index =
4126                    rng.random_range(..aspect_count) + aspect_bits.as_raw().trailing_zeros() as u8;
4127                vk::ImageAspectFlags::from_raw(1 << bit_index)
4128            };
4129
4130            let layer_start = rng.random_range(..array_layer_count);
4131            let layer_end = rng.random_range(layer_start + 1..=array_layer_count);
4132            let mip_start = rng.random_range(..mip_level_count);
4133            let mip_end = rng.random_range(mip_start + 1..=mip_level_count);
4134
4135            let range =
4136                image_subresource_range(aspect_mask, layer_start..layer_end, mip_start..mip_end);
4137            let resolved = info.resolve_subresource_counts(range);
4138
4139            for (prev, returned_range) in access.swap(&dense, info, new_access, resolved) {
4140                let range_mask = returned_range.aspect_mask.as_raw();
4141                for ai in 0..range_mask.count_ones() as u8 {
4142                    let bit = range_mask.trailing_zeros() + ai as u32;
4143                    let a = (aspect_bits.as_raw() & ((1 << bit) - 1)).count_ones() as u8;
4144                    for l in returned_range.base_array_layer
4145                        ..returned_range.base_array_layer + returned_range.layer_count
4146                    {
4147                        for m in returned_range.base_mip_level
4148                            ..returned_range.base_mip_level + returned_range.level_count
4149                        {
4150                            let idx = (l * aspect_count as u32 * mip_level_count
4151                                + m * aspect_count as u32
4152                                + a as u32) as usize;
4153                            assert_eq!(
4154                                data[idx], prev,
4155                                "prev mismatch at aspect={a} layer={l} mip={m} idx={idx}: expected {prev:?}, got {:?}",
4156                                data[idx],
4157                            );
4158                        }
4159                    }
4160                }
4161            }
4162
4163            for a in 0..aspect_count {
4164                let bit = aspect_bits.as_raw().trailing_zeros() as u8 + a;
4165                if aspect_mask.as_raw() & (1 << bit) == 0 {
4166                    continue;
4167                }
4168                for l in layer_start..layer_end {
4169                    for m in mip_start..mip_end {
4170                        let idx = (l * aspect_count as u32 * mip_level_count
4171                            + m * aspect_count as u32
4172                            + a as u32) as usize;
4173                        data[idx] = new_access;
4174                    }
4175                }
4176            }
4177        }
4178    }
4179
4180    #[test]
4181    pub fn image_access_fuzz_access_uniform() {
4182        image_access_fuzz_through_access(1, 1, 1);
4183    }
4184
4185    #[test]
4186    pub fn image_access_fuzz_access_dual_aspect() {
4187        image_access_fuzz_through_access(2, 1, 1);
4188    }
4189
4190    #[test]
4191    pub fn image_access_fuzz_access_dense_small() {
4192        image_access_fuzz_through_access(1, 4, 4);
4193    }
4194
4195    #[test]
4196    pub fn image_access_fuzz_access_dense_large() {
4197        image_access_fuzz_through_access(1, 8, 8);
4198    }
4199
4200    #[test]
4201    pub fn image_access_fuzz_access_dense_dual_aspect() {
4202        image_access_fuzz_through_access(2, 3, 3);
4203    }
4204
4205    #[test]
4206    pub fn image_sync_info_compact_merges_mips_then_layers() {
4207        use vk::ImageAspectFlags as A;
4208
4209        let mut sync_info = ImageSyncInfo {
4210            subresources: vec![
4211                image_sync_subresource(A::COLOR, 0..1, 0..1),
4212                image_sync_subresource(A::COLOR, 0..1, 1..2),
4213                image_sync_subresource(A::COLOR, 1..2, 0..1),
4214                image_sync_subresource(A::COLOR, 1..2, 1..2),
4215            ]
4216            .into_boxed_slice(),
4217        };
4218
4219        sync_info.compact();
4220
4221        assert_eq!(sync_info.subresources.len(), 1);
4222        let subresource = &sync_info.subresources[0];
4223        let range = image_subresource_range(A::COLOR, 0..2, 0..2);
4224        assert_eq!(subresource.access_mask, vk::AccessFlags::SHADER_READ);
4225        assert_eq!(
4226            subresource.layout,
4227            Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
4228        );
4229        assert_eq!(subresource.range.aspect_mask, range.aspect_mask);
4230        assert_eq!(subresource.range.base_array_layer, range.base_array_layer);
4231        assert_eq!(subresource.range.layer_count, range.layer_count);
4232        assert_eq!(subresource.range.base_mip_level, range.base_mip_level);
4233        assert_eq!(subresource.range.level_count, range.level_count);
4234        assert_eq!(
4235            subresource.stage_mask,
4236            vk::PipelineStageFlags::COMPUTE_SHADER
4237        );
4238    }
4239
4240    #[test]
4241    pub fn image_sync_info_compact_keeps_different_sync_separate() {
4242        use vk::ImageAspectFlags as A;
4243
4244        let sync_info = ImageSyncInfo {
4245            subresources: vec![
4246                image_sync_subresource(A::COLOR, 0..1, 0..1),
4247                ImageSubresourceSyncInfo {
4248                    access_mask: vk::AccessFlags::SHADER_WRITE,
4249                    layout: Some(vk::ImageLayout::GENERAL),
4250                    queue_family_index: None,
4251                    range: image_subresource_range(A::COLOR, 0..1, 1..2),
4252                    stage_mask: vk::PipelineStageFlags::COMPUTE_SHADER,
4253                },
4254            ]
4255            .into_boxed_slice(),
4256        };
4257
4258        let sync_info = sync_info.into_compacted();
4259
4260        assert_eq!(sync_info.subresources.len(), 2);
4261        let subresource = &sync_info.subresources[0];
4262        let range = image_subresource_range(A::COLOR, 0..1, 0..1);
4263        assert_eq!(subresource.access_mask, vk::AccessFlags::SHADER_READ);
4264        assert_eq!(
4265            subresource.layout,
4266            Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
4267        );
4268        assert_eq!(subresource.range.aspect_mask, range.aspect_mask);
4269        assert_eq!(subresource.range.base_array_layer, range.base_array_layer);
4270        assert_eq!(subresource.range.layer_count, range.layer_count);
4271        assert_eq!(subresource.range.base_mip_level, range.base_mip_level);
4272        assert_eq!(subresource.range.level_count, range.level_count);
4273        assert_eq!(
4274            subresource.stage_mask,
4275            vk::PipelineStageFlags::COMPUTE_SHADER
4276        );
4277        assert_eq!(
4278            sync_info.subresources[1].access_mask,
4279            vk::AccessFlags::SHADER_WRITE
4280        );
4281        assert_eq!(
4282            sync_info.subresources[1].layout,
4283            Some(vk::ImageLayout::GENERAL)
4284        );
4285    }
4286
4287    #[test]
4288    pub fn image_sync_info_compact_keeps_different_queue_families_separate() {
4289        use vk::ImageAspectFlags as A;
4290
4291        let sync_info = ImageSyncInfo {
4292            subresources: vec![
4293                ImageSubresourceSyncInfo {
4294                    access_mask: vk::AccessFlags::SHADER_READ,
4295                    layout: Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL),
4296                    queue_family_index: Some(1),
4297                    range: image_subresource_range(A::COLOR, 0..1, 0..1),
4298                    stage_mask: vk::PipelineStageFlags::COMPUTE_SHADER,
4299                },
4300                ImageSubresourceSyncInfo {
4301                    access_mask: vk::AccessFlags::SHADER_READ,
4302                    layout: Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL),
4303                    queue_family_index: Some(2),
4304                    range: image_subresource_range(A::COLOR, 0..1, 1..2),
4305                    stage_mask: vk::PipelineStageFlags::COMPUTE_SHADER,
4306                },
4307            ]
4308            .into_boxed_slice(),
4309        };
4310
4311        let sync_info = sync_info.into_compacted();
4312
4313        assert_eq!(sync_info.subresources.len(), 2);
4314        assert_eq!(sync_info.subresources[0].queue_family_index, Some(1));
4315        assert_eq!(sync_info.subresources[1].queue_family_index, Some(2));
4316    }
4317
4318    #[test]
4319    pub fn image_ownership_set_promotes_dense_on_partial_update() {
4320        use vk::ImageAspectFlags as A;
4321
4322        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
4323        let sharing = Sharing::new(info, vk::SharingMode::EXCLUSIVE);
4324        let dense = Mutex::new(None);
4325
4326        sharing.set_ranges(
4327            &dense,
4328            info,
4329            SharingMode::Exclusive(Some((7, 3))),
4330            &[image_subresource_range(A::COLOR, 0..1, 0..1)],
4331        );
4332
4333        match &sharing {
4334            Sharing::Exclusive(exclusive) => {
4335                assert!(exclusive.is_dense_sharing_active());
4336            }
4337            Sharing::Concurrent => panic!("expected exclusive ownership"),
4338        }
4339
4340        let dense = dense.lock();
4341
4342        #[cfg(not(feature = "parking_lot"))]
4343        let dense = dense.expect("poisoned image dense lock");
4344
4345        let dense = dense.as_ref().expect("missing dense sharing state");
4346        assert_eq!(
4347            dense.subresource(0, 0, 0),
4348            SharingMode::Exclusive(Some((7, 3)))
4349        );
4350        assert_eq!(dense.subresource(0, 1, 0), SharingMode::Exclusive(None));
4351        assert_eq!(dense.subresource(0, 0, 1), SharingMode::Exclusive(None));
4352        assert_eq!(dense.subresource(0, 1, 1), SharingMode::Exclusive(None));
4353    }
4354
4355    #[test]
4356    pub fn image_ownership_set_whole_image_stays_uniform() {
4357        use vk::ImageAspectFlags as A;
4358
4359        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
4360        let sharing = Sharing::new(info, vk::SharingMode::EXCLUSIVE);
4361        let dense = Mutex::new(None);
4362
4363        sharing.set_ranges(
4364            &dense,
4365            info,
4366            SharingMode::Exclusive(Some((1, 2))),
4367            &[image_subresource_range(A::COLOR, 0..2, 0..2)],
4368        );
4369
4370        match &sharing {
4371            Sharing::Exclusive(exclusive) => {
4372                assert!(!exclusive.is_dense_sharing_active());
4373                assert_eq!(
4374                    SharingMode::decode(exclusive.uniform.load(Ordering::Acquire)),
4375                    SharingMode::Exclusive(Some((1, 2)))
4376                );
4377            }
4378            Sharing::Concurrent => panic!("expected exclusive ownership"),
4379        }
4380    }
4381
4382    fn image_subresource(
4383        format: vk::Format,
4384        array_layer_count: u32,
4385        mip_level_count: u32,
4386    ) -> ImageInfo {
4387        ImageInfo::image_2d(1, 1, format, vk::ImageUsageFlags::empty())
4388            .into_builder()
4389            .array_layer_count(array_layer_count)
4390            .mip_level_count(mip_level_count)
4391            .build()
4392    }
4393
4394    fn image_subresource_range(
4395        aspect_mask: vk::ImageAspectFlags,
4396        array_layers: Range<u32>,
4397        mip_levels: Range<u32>,
4398    ) -> vk::ImageSubresourceRange {
4399        vk::ImageSubresourceRange {
4400            aspect_mask,
4401            base_array_layer: array_layers.start,
4402            base_mip_level: mip_levels.start,
4403            layer_count: array_layers.len() as _,
4404            level_count: mip_levels.len() as _,
4405        }
4406    }
4407
4408    #[test]
4409    pub fn image_subresource_range_contains() {
4410        use {
4411            super::image_subresource_range_contains as f, image_subresource_range as i,
4412            vk::ImageAspectFlags as A,
4413        };
4414
4415        assert!(f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 0..1, 0..1)));
4416        assert!(f(i(A::COLOR, 0..2, 0..1), i(A::COLOR, 0..1, 0..1)));
4417        assert!(f(i(A::COLOR, 0..1, 0..2), i(A::COLOR, 0..1, 0..1)));
4418        assert!(f(i(A::COLOR, 0..2, 0..2), i(A::COLOR, 0..1, 0..1)));
4419        assert!(!f(i(A::COLOR, 0..1, 1..3), i(A::COLOR, 0..1, 0..1)));
4420        assert!(!f(i(A::COLOR, 1..3, 0..1), i(A::COLOR, 0..1, 0..1)));
4421        assert!(!f(i(A::COLOR, 0..1, 1..3), i(A::COLOR, 0..1, 0..2)));
4422        assert!(!f(i(A::COLOR, 1..3, 0..1), i(A::COLOR, 0..2, 0..1)));
4423    }
4424
4425    #[test]
4426    pub fn image_subresource_range_intersects() {
4427        use {
4428            super::image_subresource_range_intersects as f, image_subresource_range as i,
4429            vk::ImageAspectFlags as A,
4430        };
4431
4432        assert!(f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 0..1, 0..1)));
4433        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::DEPTH, 0..1, 0..1)));
4434
4435        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 1..2, 0..1)));
4436        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 0..1, 1..2)));
4437        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::DEPTH, 1..2, 0..1)));
4438        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::DEPTH, 0..1, 1..2)));
4439        assert!(!f(i(A::COLOR, 1..2, 1..2), i(A::COLOR, 0..1, 0..1)));
4440
4441        assert!(f(
4442            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
4443            i(A::DEPTH, 2..3, 2..4)
4444        ));
4445        assert!(f(
4446            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
4447            i(A::DEPTH, 2..3, 4..6)
4448        ));
4449        assert!(!f(
4450            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
4451            i(A::DEPTH, 2..3, 2..3)
4452        ));
4453        assert!(!f(
4454            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
4455            i(A::DEPTH, 2..3, 5..6)
4456        ));
4457    }
4458
4459    #[test]
4460    pub fn image_subresource_range_normalize_remaining_counts() {
4461        let info = image_subresource(vk::Format::R8_UINT, 4, 6);
4462        let range = vk::ImageSubresourceRange {
4463            aspect_mask: vk::ImageAspectFlags::COLOR,
4464            base_array_layer: 1,
4465            layer_count: vk::REMAINING_ARRAY_LAYERS,
4466            base_mip_level: 2,
4467            level_count: vk::REMAINING_MIP_LEVELS,
4468        };
4469
4470        let range = info.resolve_subresource_counts(range);
4471
4472        assert_eq!(range.base_array_layer, 1);
4473        assert_eq!(range.layer_count, 3);
4474        assert_eq!(range.base_mip_level, 2);
4475        assert_eq!(range.level_count, 4);
4476    }
4477
4478    #[test]
4479    pub fn image_view_info() {
4480        let info = ImageViewInfo::new(vk::Format::default(), vk::ImageViewType::TYPE_1D);
4481        let builder = info.into_builder().build();
4482
4483        assert_eq!(info, builder);
4484    }
4485
4486    #[test]
4487    pub fn image_view_info_builder() {
4488        let info = ImageViewInfo::new(vk::Format::default(), vk::ImageViewType::TYPE_1D);
4489        let builder = ImageViewInfoBuilder::default()
4490            .format(vk::Format::default())
4491            .view_type(vk::ImageViewType::TYPE_1D)
4492            .aspect_mask(vk::ImageAspectFlags::COLOR)
4493            .build();
4494
4495        assert_eq!(info, builder);
4496    }
4497
4498    #[test]
4499    pub fn image_view_info_builder_defaults() {
4500        assert_eq!(
4501            ImageViewInfoBuilder::default().build(),
4502            ImageViewInfo::new(vk::Format::UNDEFINED, vk::ImageViewType::TYPE_2D)
4503        );
4504    }
4505}