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    /// Returns a cached Vulkan image view matching `info`.
1630    ///
1631    /// The returned handle remains valid until this image is dropped. Repeated calls with the same
1632    /// information return the same handle. Calling [`Self::to_detached`] transfers the view cache
1633    /// to the detached image, so callers must not retain handles across that unsafe operation.
1634    #[profiling::function]
1635    pub fn view(&self, info: ImageViewInfo) -> Result<vk::ImageView, DriverError> {
1636        self.with_image_view_cache(|cache| {
1637            Ok(match cache.entry(info) {
1638                Entry::Occupied(entry) => entry.get().image_view,
1639                Entry::Vacant(entry) => {
1640                    entry
1641                        .insert(ImageView::create(&self.device, info, self.handle)?)
1642                        .image_view
1643                }
1644            })
1645        })
1646    }
1647
1648    /// Sets the debugging name assigned to this image.
1649    pub fn with_debug_name(self, name: impl AsRef<str>) -> Self {
1650        self.set_debug_name(name);
1651
1652        self
1653    }
1654
1655    fn with_image_view_cache<R>(
1656        &self,
1657        f: impl FnOnce(&mut HashMap<ImageViewInfo, ImageView>) -> R,
1658    ) -> R {
1659        let cache = self.image_view_cache.lock();
1660
1661        #[cfg(not(feature = "parking_lot"))]
1662        let cache = cache.expect("poisoned image view lock");
1663
1664        let mut cache = cache;
1665
1666        f(&mut cache)
1667    }
1668}
1669
1670impl Debug for Image {
1671    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1672        let mut res = f.debug_struct(stringify!(Image));
1673
1674        if let Some(debug_name) =
1675            &Device::private_data_object_name(&self.device, vk::ObjectType::IMAGE, self.handle)
1676        {
1677            res.field("debug_name", debug_name);
1678        }
1679
1680        res.field("handle", &self.handle).finish_non_exhaustive()
1681    }
1682}
1683
1684impl Drop for Image {
1685    // This function is not profiled because dropping the allocation may run during shutdown.
1686    fn drop(&mut self) {
1687        if panicking() {
1688            return;
1689        }
1690
1691        /*
1692        When allocation is Some, we allocated the image ourselves; otherwise somebody else owns this
1693        image and we should not destroy it. Usually it's the swapchain.
1694        */
1695        if let Some(allocation) = self.allocation.take() {
1696            Device::try_clear_private_data_object_name(
1697                &self.device,
1698                vk::ObjectType::IMAGE,
1699                self.handle,
1700            );
1701            Self::drop_allocation(self, allocation);
1702        } else {
1703            // Non-owned handles may already be invalid when their owner, such as a swapchain, has
1704            // been destroyed. Remove local metadata without issuing vkSetPrivateDataEXT.
1705            Device::forget_private_data_object_name(
1706                &self.device,
1707                vk::ObjectType::IMAGE,
1708                self.handle,
1709            );
1710        }
1711    }
1712}
1713
1714impl Eq for Image {}
1715
1716impl PartialEq for Image {
1717    fn eq(&self, other: &Self) -> bool {
1718        self.handle == other.handle
1719    }
1720}
1721
1722/// Information used to create an [`Image`] instance.
1723///
1724/// See [`VkImageCreateInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageCreateInfo.html).
1725#[derive(Builder, Clone, Copy, Debug, Hash, PartialEq, Eq)]
1726#[builder(
1727    build_fn(private, name = "fallible_build"),
1728    derive(Copy, Clone, Debug),
1729    pattern = "owned"
1730)]
1731pub struct ImageInfo {
1732    /// Specifies a dedicated memory allocation managed by the Vulkan driver and not by the
1733    /// internal memory allocation pool transient resources share.
1734    ///
1735    /// The driver may optimize access to dedicated images.
1736    #[builder(default)]
1737    pub alloc_dedicated: bool,
1738
1739    /// The number of layers in the image.
1740    #[builder(default = "1")]
1741    pub array_layer_count: u32,
1742
1743    /// Image extent of the Z axis, when describing a three dimensional image.
1744    #[builder(default)]
1745    pub depth: u32,
1746
1747    /// A bitmask describing additional parameters of the image.
1748    ///
1749    /// See [`VkImageCreateFlagBits`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageCreateFlagBits.html).
1750    #[builder(default)]
1751    pub flags: vk::ImageCreateFlags,
1752
1753    /// The format and type of the texel blocks that will be contained in the image.
1754    #[builder(default = "vk::Format::UNDEFINED")]
1755    pub format: vk::Format,
1756
1757    /// Image extent of the Y axis, when describing a two or three dimensional image.
1758    #[builder(default)]
1759    pub height: u32,
1760
1761    /// Specifies an image whose memory is host-visible and may be mapped for reads.
1762    ///
1763    /// Memory optimal for CPU readback of data may be used.
1764    ///
1765    #[builder(default)]
1766    pub host_readable: bool,
1767
1768    /// Specifies an image whose memory is host-visible and may be mapped for writes.
1769    ///
1770    /// Memory optimal for uploading data to the GPU may be used.
1771    ///
1772    #[builder(default)]
1773    pub host_writable: bool,
1774
1775    /// The number of levels of detail available for minified sampling of the image.
1776    #[builder(default = "1")]
1777    pub mip_level_count: u32,
1778
1779    /// Specifies the number of [samples per texel].
1780    ///
1781    /// See [`VkImageCreateInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageCreateInfo.html).
1782    #[builder(default = "SampleCount::Type1")]
1783    pub sample_count: SampleCount,
1784
1785    /// Controls whether the image is accessible from a single queue family (`EXCLUSIVE`) or from
1786    /// multiple queue families concurrently (`CONCURRENT`).
1787    ///
1788    /// `EXCLUSIVE` (the default) restricts the image to a single queue family. This may enable
1789    /// driver optimizations but requires ownership transfers to use the image on a different queue
1790    /// family.
1791    ///
1792    /// Set to `CONCURRENT` when the image will be accessed from multiple queue families (e.g.
1793    /// graphics and compute on separate queues).
1794    ///
1795    /// See
1796    /// [`VkSharingMode`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkSharingMode.html)
1797    /// in the Vulkan specification.
1798    #[builder(default = "vk::SharingMode::EXCLUSIVE")]
1799    pub sharing_mode: vk::SharingMode,
1800
1801    /// Specifies the tiling arrangement of the texel blocks in memory.
1802    ///
1803    /// The default value is [`vk::ImageTiling::OPTIMAL`].
1804    #[builder(default = "vk::ImageTiling::OPTIMAL")]
1805    pub tiling: vk::ImageTiling,
1806
1807    /// The basic dimensionality of the image.
1808    ///
1809    /// Layers in array textures do not count as a dimension for the purposes of the image type.
1810    #[builder(default = "vk::ImageType::TYPE_2D")]
1811    pub image_type: vk::ImageType,
1812
1813    /// A bitmask describing the intended usage of the image.
1814    ///
1815    /// See [`VkImageUsageFlagBits`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageUsageFlagBits.html).
1816    #[builder(default)]
1817    pub usage: vk::ImageUsageFlags,
1818
1819    /// Image extent of the X axis.
1820    #[builder(default)]
1821    pub width: u32,
1822}
1823
1824impl ImageInfo {
1825    /// Specifies a cube image.
1826    #[inline(always)]
1827    pub const fn cube(size: u32, format: vk::Format, usage: vk::ImageUsageFlags) -> ImageInfo {
1828        let mut res = Self::new(vk::ImageType::TYPE_2D, size, size, 1, 6, format, usage);
1829        res.flags = vk::ImageCreateFlags::from_raw(
1830            vk::ImageCreateFlags::CUBE_COMPATIBLE.as_raw() | res.flags.as_raw(),
1831        );
1832
1833        res
1834    }
1835
1836    /// Specifies a one-dimensional image.
1837    #[inline(always)]
1838    pub const fn image_1d(size: u32, format: vk::Format, usage: vk::ImageUsageFlags) -> ImageInfo {
1839        Self::new(vk::ImageType::TYPE_1D, size, 1, 1, 1, format, usage)
1840    }
1841
1842    /// Specifies a two-dimensional image.
1843    #[inline(always)]
1844    pub const fn image_2d(
1845        width: u32,
1846        height: u32,
1847        format: vk::Format,
1848        usage: vk::ImageUsageFlags,
1849    ) -> ImageInfo {
1850        Self::new(vk::ImageType::TYPE_2D, width, height, 1, 1, format, usage)
1851    }
1852
1853    /// Specifies a two-dimensional image array.
1854    #[inline(always)]
1855    pub const fn image_2d_array(
1856        width: u32,
1857        height: u32,
1858        array_layer_count: u32,
1859        format: vk::Format,
1860        usage: vk::ImageUsageFlags,
1861    ) -> ImageInfo {
1862        Self::new(
1863            vk::ImageType::TYPE_2D,
1864            width,
1865            height,
1866            1,
1867            array_layer_count,
1868            format,
1869            usage,
1870        )
1871    }
1872
1873    /// Specifies a three-dimensional image.
1874    #[inline(always)]
1875    pub const fn image_3d(
1876        width: u32,
1877        height: u32,
1878        depth: u32,
1879        format: vk::Format,
1880        usage: vk::ImageUsageFlags,
1881    ) -> ImageInfo {
1882        Self::new(
1883            vk::ImageType::TYPE_3D,
1884            width,
1885            height,
1886            depth,
1887            1,
1888            format,
1889            usage,
1890        )
1891    }
1892
1893    #[inline(always)]
1894    const fn new(
1895        image_type: vk::ImageType,
1896        width: u32,
1897        height: u32,
1898        depth: u32,
1899        array_layer_count: u32,
1900        format: vk::Format,
1901        usage: vk::ImageUsageFlags,
1902    ) -> Self {
1903        Self {
1904            alloc_dedicated: false,
1905            image_type,
1906            width,
1907            height,
1908            depth,
1909            array_layer_count,
1910            format,
1911            usage,
1912            flags: vk::ImageCreateFlags::empty(),
1913            host_readable: false,
1914            host_writable: false,
1915            sharing_mode: vk::SharingMode::EXCLUSIVE,
1916            tiling: vk::ImageTiling::OPTIMAL,
1917            mip_level_count: 1,
1918            sample_count: SampleCount::Type1,
1919        }
1920    }
1921
1922    /// Creates a default `ImageInfoBuilder`.
1923    pub fn builder() -> ImageInfoBuilder {
1924        Default::default()
1925    }
1926
1927    /// Provides an `ImageViewInfo` for this format, type, aspect, array elements, and mip levels.
1928    pub fn into_image_view(self) -> ImageViewInfo {
1929        self.into()
1930    }
1931
1932    pub(crate) fn resolve_subresource_counts(
1933        self,
1934        mut range: vk::ImageSubresourceRange,
1935    ) -> vk::ImageSubresourceRange {
1936        if range.layer_count == vk::REMAINING_ARRAY_LAYERS {
1937            range.layer_count = self.array_layer_count - range.base_array_layer;
1938        }
1939
1940        if range.level_count == vk::REMAINING_MIP_LEVELS {
1941            range.level_count = self.mip_level_count - range.base_mip_level;
1942        }
1943
1944        range
1945    }
1946
1947    fn is_full_subresource_range(self, range: vk::ImageSubresourceRange) -> bool {
1948        range.aspect_mask == format_aspect_mask(self.format)
1949            && range.base_array_layer == 0
1950            && range.layer_count == self.array_layer_count
1951            && range.base_mip_level == 0
1952            && range.level_count == self.mip_level_count
1953    }
1954
1955    /// Returns `true` if this image is an array.
1956    pub fn is_array(self) -> bool {
1957        self.array_layer_count > 1
1958    }
1959
1960    /// Returns `true` if this image is a cube or cube array.
1961    pub fn is_cube(self) -> bool {
1962        self.image_type == vk::ImageType::TYPE_2D
1963            && self.width == self.height
1964            && self.depth == 1
1965            && self.array_layer_count >= 6
1966            && self.flags.contains(vk::ImageCreateFlags::CUBE_COMPATIBLE)
1967    }
1968
1969    /// Returns `true` if this image is a cube array.
1970    pub fn is_cube_array(self) -> bool {
1971        self.is_cube() && self.array_layer_count > 6
1972    }
1973
1974    /// Returns `true` if this information specifies host-visible memory.
1975    pub fn is_host_visible(self) -> bool {
1976        self.host_readable | self.host_writable
1977    }
1978
1979    const fn memory_location(self) -> MemoryLocation {
1980        if self.host_writable {
1981            MemoryLocation::CpuToGpu
1982        } else if self.host_readable {
1983            MemoryLocation::GpuToCpu
1984        } else {
1985            MemoryLocation::GpuOnly
1986        }
1987    }
1988
1989    /// Converts an `ImageInfo` into an `ImageInfoBuilder`.
1990    pub fn into_builder(self) -> ImageInfoBuilder {
1991        ImageInfoBuilder {
1992            array_layer_count: Some(self.array_layer_count),
1993            alloc_dedicated: Some(self.alloc_dedicated),
1994            depth: Some(self.depth),
1995            flags: Some(self.flags),
1996            format: Some(self.format),
1997            height: Some(self.height),
1998            host_readable: Some(self.host_readable),
1999            host_writable: Some(self.host_writable),
2000            mip_level_count: Some(self.mip_level_count),
2001            sample_count: Some(self.sample_count),
2002            sharing_mode: Some(self.sharing_mode),
2003            tiling: Some(self.tiling),
2004            image_type: Some(self.image_type),
2005            usage: Some(self.usage),
2006            width: Some(self.width),
2007        }
2008    }
2009}
2010
2011impl From<ImageInfo> for vk::ImageCreateInfo<'_> {
2012    fn from(value: ImageInfo) -> Self {
2013        Self::default()
2014            .flags(value.flags)
2015            .image_type(value.image_type)
2016            .format(value.format)
2017            .extent(vk::Extent3D {
2018                width: value.width,
2019                height: value.height,
2020                depth: value.depth,
2021            })
2022            .mip_levels(value.mip_level_count)
2023            .array_layers(value.array_layer_count)
2024            .samples(value.sample_count.into())
2025            .tiling(value.tiling)
2026            .usage(value.usage)
2027            .sharing_mode(value.sharing_mode)
2028            .initial_layout(vk::ImageLayout::UNDEFINED)
2029    }
2030}
2031
2032impl From<ImageInfoBuilder> for ImageInfo {
2033    fn from(info: ImageInfoBuilder) -> Self {
2034        info.build()
2035    }
2036}
2037
2038impl From<ImageInfo> for vk::ImageSubresourceRange {
2039    fn from(info: ImageInfo) -> Self {
2040        let image_view_info: ImageViewInfo = info.into();
2041
2042        image_view_info.into()
2043    }
2044}
2045
2046impl ImageInfoBuilder {
2047    /// Builds a new `ImageInfo`.
2048    #[inline(always)]
2049    pub fn build(self) -> ImageInfo {
2050        self.fallible_build().expect("all fields have defaults")
2051    }
2052
2053    /// Provides an `ImageViewInfo` for this format, type, aspect, array elements, and mip levels.
2054    pub fn into_image_view(self) -> ImageViewInfoBuilder {
2055        self.build().into_image_view().into_builder()
2056    }
2057}
2058
2059struct ImageSubresourceRangeIter {
2060    aspect_mask: vk::ImageAspectFlags,
2061    aspect: u8,
2062    aspect_count: u8,
2063    array_layer: u32,
2064    end_array_layer: u32,
2065    base_array_layer: u32,
2066    base_mip_level: u32,
2067    mip_level: u32,
2068    end_mip_level: u32,
2069    remaining: usize,
2070}
2071
2072impl ImageSubresourceRangeIter {
2073    fn new(range: vk::ImageSubresourceRange) -> Self {
2074        let aspect_mask = range.aspect_mask;
2075        let aspect_count = aspect_mask.as_raw().count_ones() as u8;
2076
2077        Self {
2078            aspect_mask,
2079            aspect: 0,
2080            aspect_count,
2081            array_layer: range.base_array_layer,
2082            end_array_layer: range.base_array_layer + range.layer_count,
2083            base_array_layer: range.base_array_layer,
2084            base_mip_level: range.base_mip_level,
2085            mip_level: range.base_mip_level,
2086            end_mip_level: range.base_mip_level + range.level_count,
2087            remaining: aspect_count as usize
2088                * range.layer_count as usize
2089                * range.level_count as usize,
2090        }
2091    }
2092}
2093
2094impl ExactSizeIterator for ImageSubresourceRangeIter {
2095    fn len(&self) -> usize {
2096        self.remaining
2097    }
2098}
2099
2100impl Iterator for ImageSubresourceRangeIter {
2101    type Item = vk::ImageSubresourceRange;
2102
2103    fn next(&mut self) -> Option<Self::Item> {
2104        if self.aspect >= self.aspect_count {
2105            return None;
2106        }
2107
2108        let range = vk::ImageSubresourceRange {
2109            aspect_mask: aspect_mask_at_ordinal(self.aspect_mask, self.aspect as u32),
2110            base_array_layer: self.array_layer,
2111            layer_count: 1,
2112            base_mip_level: self.mip_level,
2113            level_count: 1,
2114        };
2115
2116        self.mip_level += 1;
2117        if self.mip_level >= self.end_mip_level {
2118            self.mip_level = self.base_mip_level;
2119            self.array_layer += 1;
2120            if self.array_layer >= self.end_array_layer {
2121                self.array_layer = self.base_array_layer;
2122                self.aspect += 1;
2123            }
2124        }
2125
2126        self.remaining -= 1;
2127
2128        Some(range)
2129    }
2130
2131    fn size_hint(&self) -> (usize, Option<usize>) {
2132        let len = self.len();
2133
2134        (len, Some(len))
2135    }
2136}
2137
2138/// Synchronization information for one accessed image subresource range.
2139#[derive(Clone, Copy, Debug)]
2140pub struct ImageSubresourceSyncInfo {
2141    /// Access types performed by `stage_mask`.
2142    pub access_mask: vk::AccessFlags,
2143
2144    /// Required image layout for the next external use, when one is defined.
2145    pub layout: Option<vk::ImageLayout>,
2146
2147    /// Queue-family ownership for this subresource, when exclusive ownership is known.
2148    pub queue_family_index: Option<u32>,
2149
2150    /// The tracked image subresource range.
2151    pub range: vk::ImageSubresourceRange,
2152
2153    /// Pipeline stages that access this `range`.
2154    pub stage_mask: vk::PipelineStageFlags,
2155}
2156
2157impl ImageSubresourceSyncInfo {
2158    fn can_merge_array_layers(self, other: Self) -> bool {
2159        self.same_sync(other)
2160            && self.range.aspect_mask == other.range.aspect_mask
2161            && self.range.base_mip_level == other.range.base_mip_level
2162            && self.range.level_count == other.range.level_count
2163            && self.range.base_array_layer + self.range.layer_count == other.range.base_array_layer
2164    }
2165
2166    fn can_merge_mip_levels(self, other: Self) -> bool {
2167        self.same_sync(other)
2168            && self.range.aspect_mask == other.range.aspect_mask
2169            && self.range.base_array_layer == other.range.base_array_layer
2170            && self.range.layer_count == other.range.layer_count
2171            && self.range.base_mip_level + self.range.level_count == other.range.base_mip_level
2172    }
2173
2174    fn from_access(access: AccessType, range: vk::ImageSubresourceRange) -> Self {
2175        let (stage_mask, access_mask) = pipeline_stage_access_flags(access);
2176
2177        Self {
2178            access_mask,
2179            layout: access_type_to_layout(access),
2180            queue_family_index: None,
2181            range,
2182            stage_mask,
2183        }
2184    }
2185
2186    fn into_public(self, sharing: SharingMode) -> Self {
2187        Self {
2188            queue_family_index: match sharing {
2189                SharingMode::Concurrent | SharingMode::Exclusive(None) => None,
2190                SharingMode::Exclusive(Some((queue_family_index, _))) => Some(queue_family_index),
2191            },
2192            ..self
2193        }
2194    }
2195
2196    fn merge_array_layers(&mut self, other: Self) {
2197        self.range.layer_count += other.range.layer_count;
2198    }
2199
2200    fn merge_mip_levels(&mut self, other: Self) {
2201        self.range.level_count += other.range.level_count;
2202    }
2203
2204    fn same_sync(self, other: Self) -> bool {
2205        self.access_mask == other.access_mask
2206            && self.layout == other.layout
2207            && self.queue_family_index == other.queue_family_index
2208            && self.stage_mask == other.stage_mask
2209    }
2210}
2211
2212/// Synchronization information for an image.
2213#[derive(Clone, Debug)]
2214pub struct ImageSyncInfo {
2215    /// Access state for the tracked image subresource ranges.
2216    pub subresources: Box<[ImageSubresourceSyncInfo]>,
2217}
2218
2219impl ImageSyncInfo {
2220    fn compact_subresources(
2221        subresources: impl IntoIterator<Item = ImageSubresourceSyncInfo>,
2222    ) -> Box<[ImageSubresourceSyncInfo]> {
2223        let mut mip_levels = Vec::new();
2224
2225        for sync_info in subresources {
2226            if let Some(prev) = mip_levels.last_mut()
2227                && ImageSubresourceSyncInfo::can_merge_mip_levels(*prev, sync_info)
2228            {
2229                prev.merge_mip_levels(sync_info);
2230            } else {
2231                mip_levels.push(sync_info);
2232            }
2233        }
2234
2235        let mut array_layers = Vec::with_capacity(mip_levels.len());
2236
2237        for sync_info in mip_levels {
2238            if let Some(prev) = array_layers.last_mut()
2239                && ImageSubresourceSyncInfo::can_merge_array_layers(*prev, sync_info)
2240            {
2241                prev.merge_array_layers(sync_info);
2242            } else {
2243                array_layers.push(sync_info);
2244            }
2245        }
2246
2247        array_layers.into_boxed_slice()
2248    }
2249
2250    /// Compacts adjacent subresource entries with identical synchronization requirements.
2251    ///
2252    /// This is opt-in because some callers may prefer the exact per-range snapshot produced by the
2253    /// internal access tracker.
2254    ///
2255    /// Runs in linear time over `subresources`. Image compaction performs two passes, first merging
2256    /// adjacent mip levels and then adjacent array layers, and uses temporary vector storage for
2257    /// each pass.
2258    pub fn compact(&mut self) {
2259        let subresources = take(&mut self.subresources);
2260        self.subresources = Self::compact_subresources(subresources);
2261    }
2262
2263    /// Returns a compacted copy of this synchronization snapshot.
2264    ///
2265    /// This has the same linear-time and temporary-storage characteristics as [`Self::compact`],
2266    /// but consumes and returns the snapshot for use in iterator chains or expression-oriented code.
2267    pub fn into_compacted(mut self) -> Self {
2268        self.compact();
2269        self
2270    }
2271}
2272
2273struct ImageView {
2274    device: Device,
2275    image_view: vk::ImageView,
2276}
2277
2278impl ImageView {
2279    #[profiling::function]
2280    fn create(
2281        device: &Device,
2282        info: impl Into<ImageViewInfo>,
2283        image: vk::Image,
2284    ) -> Result<Self, DriverError> {
2285        let info = info.into();
2286        let device = device.clone();
2287        let create_info = vk::ImageViewCreateInfo::default()
2288            .view_type(info.view_type)
2289            .format(info.format)
2290            .components(vk::ComponentMapping {
2291                r: vk::ComponentSwizzle::R,
2292                g: vk::ComponentSwizzle::G,
2293                b: vk::ComponentSwizzle::B,
2294                a: vk::ComponentSwizzle::A,
2295            })
2296            .image(image)
2297            .subresource_range(vk::ImageSubresourceRange {
2298                aspect_mask: info.aspect_mask,
2299                base_array_layer: info.base_array_layer,
2300                base_mip_level: info.base_mip_level,
2301                level_count: info.mip_level_count,
2302                layer_count: info.array_layer_count,
2303            });
2304
2305        let image_view =
2306            unsafe { device.create_image_view(&create_info, None) }.map_err(|err| {
2307                warn!("unable to create image view: {err}");
2308
2309                DriverError::Unsupported
2310            })?;
2311
2312        Ok(Self { device, image_view })
2313    }
2314}
2315
2316impl Drop for ImageView {
2317    #[profiling::function]
2318    fn drop(&mut self) {
2319        if panicking() {
2320            return;
2321        }
2322
2323        unsafe {
2324            self.device.destroy_image_view(self.image_view, None);
2325        }
2326    }
2327}
2328
2329/// Information used to reinterpret an existing [`Image`] instance.
2330///
2331/// See [`VkImageViewCreateInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkImageViewCreateInfo.html).
2332#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
2333#[builder(
2334    build_fn(private, name = "fallible_build"),
2335    derive(Clone, Copy, Debug),
2336    pattern = "owned"
2337)]
2338pub struct ImageViewInfo {
2339    /// The number of layers that will be contained in the view.
2340    ///
2341    /// The default value is `vk::REMAINING_ARRAY_LAYERS`.
2342    #[builder(default = "vk::REMAINING_ARRAY_LAYERS")]
2343    pub array_layer_count: u32,
2344
2345    /// The portion of the image that will be contained in the view.
2346    #[builder(default = "vk::ImageAspectFlags::COLOR")]
2347    pub aspect_mask: vk::ImageAspectFlags,
2348
2349    /// The first array layer that will be contained in the view.
2350    #[builder(default)]
2351    pub base_array_layer: u32,
2352
2353    /// The first mip level that will be contained in the view.
2354    #[builder(default)]
2355    pub base_mip_level: u32,
2356
2357    /// The format and type of the texel blocks that will be contained in the view.
2358    #[builder(default = "vk::Format::UNDEFINED")]
2359    pub format: vk::Format,
2360
2361    /// The number of mip levels that will be contained in the view.
2362    ///
2363    /// The default value is `vk::REMAINING_MIP_LEVELS`.
2364    #[builder(default = "vk::REMAINING_MIP_LEVELS")]
2365    pub mip_level_count: u32,
2366
2367    /// The basic dimensionality of the view.
2368    #[builder(default = "vk::ImageViewType::TYPE_2D")]
2369    pub view_type: vk::ImageViewType,
2370}
2371
2372impl ImageViewInfo {
2373    /// Specifies a default view with the given `format` and `view_type` values.
2374    ///
2375    /// # Note
2376    ///
2377    /// Automatically sets [`aspect_mask`](Self::aspect_mask) to a suggested value.
2378    #[inline(always)]
2379    pub const fn new(format: vk::Format, view_type: vk::ImageViewType) -> ImageViewInfo {
2380        Self {
2381            array_layer_count: vk::REMAINING_ARRAY_LAYERS,
2382            aspect_mask: format_aspect_mask(format),
2383            base_array_layer: 0,
2384            base_mip_level: 0,
2385            format,
2386            mip_level_count: vk::REMAINING_MIP_LEVELS,
2387            view_type,
2388        }
2389    }
2390
2391    /// Converts an `ImageViewInfo` into an `ImageViewInfoBuilder`.
2392    pub fn into_builder(self) -> ImageViewInfoBuilder {
2393        ImageViewInfoBuilder {
2394            array_layer_count: Some(self.array_layer_count),
2395            aspect_mask: Some(self.aspect_mask),
2396            base_array_layer: Some(self.base_array_layer),
2397            base_mip_level: Some(self.base_mip_level),
2398            format: Some(self.format),
2399            mip_level_count: Some(self.mip_level_count),
2400            view_type: Some(self.view_type),
2401        }
2402    }
2403}
2404
2405impl From<ImageInfo> for ImageViewInfo {
2406    fn from(info: ImageInfo) -> Self {
2407        Self::from_image_info(info).expect("unsupported image type for image view info")
2408    }
2409}
2410
2411impl ImageViewInfo {
2412    /// Creates an image view description from image creation info.
2413    pub fn from_image_info(info: ImageInfo) -> Result<Self, DriverError> {
2414        Ok(Self {
2415            array_layer_count: info.array_layer_count,
2416            aspect_mask: format_aspect_mask(info.format),
2417            base_array_layer: 0,
2418            base_mip_level: 0,
2419            format: info.format,
2420            mip_level_count: info.mip_level_count,
2421            view_type: match (info.image_type, info.array_layer_count) {
2422                (vk::ImageType::TYPE_1D, 1) => vk::ImageViewType::TYPE_1D,
2423                (vk::ImageType::TYPE_1D, _) => vk::ImageViewType::TYPE_1D_ARRAY,
2424                (vk::ImageType::TYPE_2D, 1) => vk::ImageViewType::TYPE_2D,
2425                (vk::ImageType::TYPE_2D, 6)
2426                    if info.flags.contains(vk::ImageCreateFlags::CUBE_COMPATIBLE) =>
2427                {
2428                    vk::ImageViewType::CUBE
2429                }
2430                (vk::ImageType::TYPE_2D, _)
2431                    if info.flags.contains(vk::ImageCreateFlags::CUBE_COMPATIBLE)
2432                        && info.array_layer_count > 6 =>
2433                {
2434                    vk::ImageViewType::CUBE_ARRAY
2435                }
2436                (vk::ImageType::TYPE_2D, _) => vk::ImageViewType::TYPE_2D_ARRAY,
2437                (vk::ImageType::TYPE_3D, _) => vk::ImageViewType::TYPE_3D,
2438                _ => {
2439                    warn!(
2440                        "invalid image view source info: image type {:?} with {} array layers",
2441                        info.image_type, info.array_layer_count
2442                    );
2443
2444                    return Err(DriverError::InvalidData);
2445                }
2446            },
2447        })
2448    }
2449}
2450
2451impl From<ImageViewInfoBuilder> for ImageViewInfo {
2452    fn from(info: ImageViewInfoBuilder) -> Self {
2453        info.build()
2454    }
2455}
2456
2457impl From<ImageViewInfo> for vk::ImageSubresourceRange {
2458    fn from(info: ImageViewInfo) -> Self {
2459        Self {
2460            aspect_mask: info.aspect_mask,
2461            base_mip_level: info.base_mip_level,
2462            base_array_layer: info.base_array_layer,
2463            layer_count: info.array_layer_count,
2464            level_count: info.mip_level_count,
2465        }
2466    }
2467}
2468
2469impl ImageViewInfoBuilder {
2470    /// Builds a new `ImageViewInfo`.
2471    #[inline(always)]
2472    pub fn build(self) -> ImageViewInfo {
2473        self.fallible_build().expect("all fields have defaults")
2474    }
2475}
2476
2477/// Specifies sample counts supported for an image used for storage operation.
2478///
2479/// Values must not exceed the device limits specified by the physical device properties.
2480///
2481/// See [`VkSampleCountFlagBits`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkSampleCountFlagBits.html).
2482#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
2483pub enum SampleCount {
2484    /// Single image sample. This is the usual mode.
2485    ///
2486    /// This is the default value.
2487    #[default]
2488    Type1,
2489
2490    /// Multiple image samples.
2491    Type2,
2492
2493    /// Multiple image samples.
2494    Type4,
2495
2496    /// Multiple image samples.
2497    Type8,
2498
2499    /// Multiple image samples.
2500    Type16,
2501
2502    /// Multiple image samples.
2503    Type32,
2504
2505    /// Multiple image samples.
2506    Type64,
2507}
2508
2509impl SampleCount {
2510    /// Returns `true` when the value represents a single sample mode.
2511    pub fn is_single(self) -> bool {
2512        matches!(self, Self::Type1)
2513    }
2514
2515    /// Returns `true` when the value represents a multiple sample mode.
2516    pub fn is_multiple(self) -> bool {
2517        matches!(
2518            self,
2519            Self::Type2 | Self::Type4 | Self::Type8 | Self::Type16 | Self::Type32 | Self::Type64
2520        )
2521    }
2522}
2523
2524impl From<SampleCount> for vk::SampleCountFlags {
2525    fn from(sample_count: SampleCount) -> Self {
2526        match sample_count {
2527            SampleCount::Type1 => Self::TYPE_1,
2528            SampleCount::Type2 => Self::TYPE_2,
2529            SampleCount::Type4 => Self::TYPE_4,
2530            SampleCount::Type8 => Self::TYPE_8,
2531            SampleCount::Type16 => Self::TYPE_16,
2532            SampleCount::Type32 => Self::TYPE_32,
2533            SampleCount::Type64 => Self::TYPE_64,
2534        }
2535    }
2536}
2537
2538#[derive(Debug)]
2539enum Sharing {
2540    Concurrent,
2541    Exclusive(ExclusiveSharing),
2542}
2543
2544impl Sharing {
2545    fn new(info: ImageInfo, sharing_mode: vk::SharingMode) -> Self {
2546        if sharing_mode == vk::SharingMode::CONCURRENT {
2547            Self::Concurrent
2548        } else {
2549            Self::Exclusive(ExclusiveSharing::new(info))
2550        }
2551    }
2552
2553    fn set_ranges(
2554        &self,
2555        dense: &Mutex<Option<DenseMap<SharingMode>>>,
2556        info: ImageInfo,
2557        sharing: SharingMode,
2558        sharing_ranges: &[vk::ImageSubresourceRange],
2559    ) {
2560        let Self::Exclusive(exclusive) = self else {
2561            return;
2562        };
2563
2564        exclusive.set_ranges(dense, info, sharing, sharing_ranges);
2565    }
2566}
2567
2568#[derive(Debug)]
2569struct UniformAccess(AtomicU8);
2570
2571impl UniformAccess {
2572    fn new(access: AccessType) -> Self {
2573        Self(AtomicU8::new(access_type_into_u8(access)))
2574    }
2575
2576    fn load(&self) -> AccessType {
2577        access_type_from_u8(self.0.load(Ordering::Acquire))
2578    }
2579
2580    fn swap(
2581        &self,
2582        next_access: AccessType,
2583        access_range: vk::ImageSubresourceRange,
2584    ) -> (AccessType, vk::ImageSubresourceRange) {
2585        debug_assert_eq!(access_range.base_array_layer, 0);
2586        debug_assert_eq!(access_range.base_mip_level, 0);
2587        debug_assert_eq!(access_range.layer_count, 1);
2588        debug_assert_eq!(access_range.level_count, 1);
2589        debug_assert_eq!(access_range.aspect_mask.as_raw().count_ones(), 1);
2590
2591        self.swap_range(next_access, access_range)
2592    }
2593
2594    fn swap_range(
2595        &self,
2596        next_access: AccessType,
2597        access_range: vk::ImageSubresourceRange,
2598    ) -> (AccessType, vk::ImageSubresourceRange) {
2599        let prev_access = access_type_from_u8(
2600            self.0
2601                .swap(access_type_into_u8(next_access), Ordering::AcqRel),
2602        );
2603
2604        (prev_access, access_range)
2605    }
2606}
2607
2608#[doc(hidden)]
2609pub mod bench {
2610    use super::*;
2611
2612    pub struct SwapAccessBenchHarness {
2613        access: Access,
2614        dense_access: Mutex<Option<DenseMap<AccessType>>>,
2615        info: ImageInfo,
2616    }
2617
2618    impl SwapAccessBenchHarness {
2619        pub fn new(layers: u32, mips: u32, format: vk::Format) -> Self {
2620            let info = ImageInfo::image_2d(1, 1, format, vk::ImageUsageFlags::empty())
2621                .into_builder()
2622                .array_layer_count(layers)
2623                .mip_level_count(mips)
2624                .build();
2625            Self {
2626                access: Access::new(info, AccessType::Nothing),
2627                dense_access: Mutex::new(None),
2628                info,
2629            }
2630        }
2631
2632        pub fn swap_access(
2633            &self,
2634            next_access: AccessType,
2635            mut access_range: vk::ImageSubresourceRange,
2636        ) -> Vec<(AccessType, vk::ImageSubresourceRange)> {
2637            #[cfg(feature = "checked")]
2638            {
2639                assert_aspect_mask_supported(access_range.aspect_mask);
2640                assert!(format_aspect_mask(self.info.format).contains(access_range.aspect_mask));
2641            }
2642
2643            if access_range.layer_count == vk::REMAINING_ARRAY_LAYERS {
2644                debug_assert!(access_range.base_array_layer < self.info.array_layer_count);
2645                access_range.layer_count =
2646                    self.info.array_layer_count - access_range.base_array_layer;
2647            }
2648
2649            debug_assert!(
2650                access_range.base_array_layer + access_range.layer_count
2651                    <= self.info.array_layer_count
2652            );
2653
2654            if access_range.level_count == vk::REMAINING_MIP_LEVELS {
2655                debug_assert!(access_range.base_mip_level < self.info.mip_level_count);
2656                access_range.level_count = self.info.mip_level_count - access_range.base_mip_level;
2657            }
2658
2659            debug_assert!(
2660                access_range.base_mip_level + access_range.level_count <= self.info.mip_level_count
2661            );
2662
2663            self.access
2664                .swap(&self.dense_access, self.info, next_access, access_range)
2665                .collect()
2666        }
2667    }
2668}
2669
2670#[cfg(test)]
2671mod test {
2672    use {
2673        super::*,
2674        rand::{Rng, SeedableRng, rngs::SmallRng},
2675        std::ops::Range,
2676    };
2677
2678    // ImageSubresourceRange does not implement PartialEq
2679    fn assert_access_ranges_eq(
2680        lhs: (AccessType, vk::ImageSubresourceRange),
2681        rhs: (AccessType, vk::ImageSubresourceRange),
2682    ) {
2683        assert_eq!(
2684            (
2685                lhs.0,
2686                lhs.1.aspect_mask,
2687                lhs.1.base_array_layer,
2688                lhs.1.layer_count,
2689                lhs.1.base_mip_level,
2690                lhs.1.level_count
2691            ),
2692            (
2693                rhs.0,
2694                rhs.1.aspect_mask,
2695                rhs.1.base_array_layer,
2696                rhs.1.layer_count,
2697                rhs.1.base_mip_level,
2698                rhs.1.level_count
2699            )
2700        );
2701    }
2702
2703    fn image_sync_subresource(
2704        aspect_mask: vk::ImageAspectFlags,
2705        array_layers: Range<u32>,
2706        mip_levels: Range<u32>,
2707    ) -> ImageSubresourceSyncInfo {
2708        ImageSubresourceSyncInfo {
2709            access_mask: vk::AccessFlags::SHADER_READ,
2710            layout: Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL),
2711            queue_family_index: None,
2712            range: image_subresource_range(aspect_mask, array_layers, mip_levels),
2713            stage_mask: vk::PipelineStageFlags::COMPUTE_SHADER,
2714        }
2715    }
2716
2717    #[test]
2718    pub fn image_access_basic() {
2719        use vk::ImageAspectFlags as A;
2720
2721        let mut image = DenseMap::new(
2722            image_subresource(vk::Format::R8G8B8A8_UNORM, 1, 1),
2723            AccessType::Nothing,
2724        );
2725
2726        {
2727            let mut accesses = DenseMapIter::new(
2728                &mut image,
2729                AccessType::AnyShaderWrite,
2730                image_subresource_range(A::COLOR, 0..1, 0..1),
2731            );
2732
2733            assert_access_ranges_eq(
2734                accesses.next().unwrap(),
2735                (
2736                    AccessType::Nothing,
2737                    image_subresource_range(A::COLOR, 0..1, 0..1),
2738                ),
2739            );
2740            assert!(accesses.next().is_none());
2741        }
2742
2743        {
2744            let mut accesses = DenseMapIter::new(
2745                &mut image,
2746                AccessType::AnyShaderReadOther,
2747                image_subresource_range(A::COLOR, 0..1, 0..1),
2748            );
2749
2750            assert_access_ranges_eq(
2751                accesses.next().unwrap(),
2752                (
2753                    AccessType::AnyShaderWrite,
2754                    image_subresource_range(A::COLOR, 0..1, 0..1),
2755                ),
2756            );
2757            assert!(accesses.next().is_none());
2758        }
2759    }
2760
2761    #[test]
2762    pub fn image_access_uniform() {
2763        use vk::ImageAspectFlags as A;
2764
2765        let info = image_subresource(vk::Format::R8G8B8A8_UNORM, 1, 1);
2766        let image = Access::new(info, AccessType::Nothing);
2767        let dense = Mutex::new(None);
2768
2769        let mut accesses = image.swap(
2770            &dense,
2771            info,
2772            AccessType::AnyShaderWrite,
2773            image_subresource_range(A::COLOR, 0..1, 0..1),
2774        );
2775
2776        assert_access_ranges_eq(
2777            accesses.next().unwrap(),
2778            (
2779                AccessType::Nothing,
2780                image_subresource_range(A::COLOR, 0..1, 0..1),
2781            ),
2782        );
2783        assert!(accesses.next().is_none());
2784    }
2785
2786    #[test]
2787    pub fn image_access_dual_aspect_tracks_aspects_independently() {
2788        use vk::ImageAspectFlags as A;
2789
2790        let info = image_subresource(vk::Format::D32_SFLOAT_S8_UINT, 1, 1);
2791        let image = Access::new(info, AccessType::Nothing);
2792        let dense = Mutex::new(None);
2793
2794        let mut accesses = image.swap(
2795            &dense,
2796            info,
2797            AccessType::DepthStencilAttachmentWrite,
2798            image_subresource_range(A::DEPTH, 0..1, 0..1),
2799        );
2800
2801        assert_access_ranges_eq(
2802            accesses.next().unwrap(),
2803            (
2804                AccessType::Nothing,
2805                image_subresource_range(A::DEPTH, 0..1, 0..1),
2806            ),
2807        );
2808        assert!(accesses.next().is_none());
2809
2810        let mut accesses = image.swap(
2811            &dense,
2812            info,
2813            AccessType::DepthStencilAttachmentRead,
2814            image_subresource_range(A::STENCIL, 0..1, 0..1),
2815        );
2816
2817        assert_access_ranges_eq(
2818            accesses.next().unwrap(),
2819            (
2820                AccessType::Nothing,
2821                image_subresource_range(A::STENCIL, 0..1, 0..1),
2822            ),
2823        );
2824        assert!(accesses.next().is_none());
2825
2826        let mut accesses = image.swap(
2827            &dense,
2828            info,
2829            AccessType::AnyShaderReadOther,
2830            image_subresource_range(A::DEPTH | A::STENCIL, 0..1, 0..1),
2831        );
2832
2833        assert_access_ranges_eq(
2834            accesses.next().unwrap(),
2835            (
2836                AccessType::DepthStencilAttachmentWrite,
2837                image_subresource_range(A::DEPTH, 0..1, 0..1),
2838            ),
2839        );
2840        assert_access_ranges_eq(
2841            accesses.next().unwrap(),
2842            (
2843                AccessType::DepthStencilAttachmentRead,
2844                image_subresource_range(A::STENCIL, 0..1, 0..1),
2845            ),
2846        );
2847        assert!(accesses.next().is_none());
2848    }
2849
2850    #[test]
2851    pub fn image_access_dense_promotes_only_on_partial_update() {
2852        use vk::ImageAspectFlags as A;
2853
2854        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
2855        let image = Access::new(info, AccessType::Nothing);
2856        let dense = Mutex::new(None);
2857
2858        let Access::Dense(access) = &image else {
2859            panic!("expected dense-capable access tracking");
2860        };
2861
2862        let mut accesses = image.swap(
2863            &dense,
2864            info,
2865            AccessType::AnyShaderReadOther,
2866            image_subresource_range(A::COLOR, 0..2, 0..2),
2867        );
2868
2869        assert_access_ranges_eq(
2870            accesses.next().unwrap(),
2871            (
2872                AccessType::Nothing,
2873                image_subresource_range(A::COLOR, 0..2, 0..2),
2874            ),
2875        );
2876        assert!(accesses.next().is_none());
2877        assert!(!access.is_dense_active());
2878
2879        let mut accesses = image.swap(
2880            &dense,
2881            info,
2882            AccessType::AnyShaderWrite,
2883            image_subresource_range(A::COLOR, 0..1, 0..1),
2884        );
2885
2886        assert_access_ranges_eq(
2887            accesses.next().unwrap(),
2888            (
2889                AccessType::AnyShaderReadOther,
2890                image_subresource_range(A::COLOR, 0..1, 0..1),
2891            ),
2892        );
2893        assert!(accesses.next().is_none());
2894        assert!(access.is_dense_active());
2895    }
2896
2897    #[test]
2898    pub fn image_access_dense_collapses_to_uniform_after_equalizing_updates() {
2899        use vk::ImageAspectFlags as A;
2900
2901        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
2902        let image = Access::new(info, AccessType::Nothing);
2903        let dense = Mutex::new(None);
2904
2905        let Access::Dense(access) = &image else {
2906            panic!("expected dense-capable access tracking");
2907        };
2908
2909        {
2910            let mut accesses = image.swap(
2911                &dense,
2912                info,
2913                AccessType::AnyShaderReadOther,
2914                image_subresource_range(A::COLOR, 0..1, 0..1),
2915            );
2916
2917            assert_access_ranges_eq(
2918                accesses.next().unwrap(),
2919                (
2920                    AccessType::Nothing,
2921                    image_subresource_range(A::COLOR, 0..1, 0..1),
2922                ),
2923            );
2924            assert!(accesses.next().is_none());
2925        }
2926
2927        assert!(access.is_dense_active());
2928
2929        {
2930            let mut accesses = image.swap(
2931                &dense,
2932                info,
2933                AccessType::AnyShaderReadOther,
2934                image_subresource_range(A::COLOR, 0..2, 0..2),
2935            );
2936
2937            assert!(accesses.next().is_some());
2938            while accesses.next().is_some() {}
2939        }
2940
2941        assert!(!access.is_dense_active());
2942        assert_eq!(access.load(), AccessType::AnyShaderReadOther);
2943
2944        let dense = dense.lock();
2945        #[cfg(not(feature = "parking_lot"))]
2946        let dense = dense.expect("poisoned image dense lock");
2947
2948        assert!(dense.is_none());
2949    }
2950
2951    #[test]
2952    pub fn image_access_dense_stays_active_for_mixed_updates() {
2953        use vk::ImageAspectFlags as A;
2954
2955        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
2956        let image = Access::new(info, AccessType::Nothing);
2957        let dense = Mutex::new(None);
2958
2959        let Access::Dense(access) = &image else {
2960            panic!("expected dense-capable access tracking");
2961        };
2962
2963        {
2964            let mut accesses = image.swap(
2965                &dense,
2966                info,
2967                AccessType::AnyShaderReadOther,
2968                image_subresource_range(A::COLOR, 0..1, 0..1),
2969            );
2970
2971            assert_access_ranges_eq(
2972                accesses.next().unwrap(),
2973                (
2974                    AccessType::Nothing,
2975                    image_subresource_range(A::COLOR, 0..1, 0..1),
2976                ),
2977            );
2978            assert!(accesses.next().is_none());
2979        }
2980
2981        {
2982            let mut accesses = image.swap(
2983                &dense,
2984                info,
2985                AccessType::AnyShaderWrite,
2986                image_subresource_range(A::COLOR, 1..2, 0..1),
2987            );
2988
2989            assert_access_ranges_eq(
2990                accesses.next().unwrap(),
2991                (
2992                    AccessType::Nothing,
2993                    image_subresource_range(A::COLOR, 1..2, 0..1),
2994                ),
2995            );
2996            assert!(accesses.next().is_none());
2997        }
2998
2999        assert!(access.is_dense_active());
3000
3001        let dense = dense.lock();
3002        #[cfg(not(feature = "parking_lot"))]
3003        let dense = dense.expect("poisoned image dense lock");
3004
3005        let dense_map = dense.as_ref().expect("missing dense access map");
3006        assert_eq!(
3007            dense_map.subresource(0, 0, 0),
3008            AccessType::AnyShaderReadOther
3009        );
3010        assert_eq!(dense_map.subresource(0, 1, 0), AccessType::AnyShaderWrite);
3011        assert_eq!(dense_map.subresource(0, 0, 1), AccessType::Nothing);
3012        assert_eq!(dense_map.subresource(0, 1, 1), AccessType::Nothing);
3013    }
3014
3015    #[test]
3016    pub fn image_access_dense_iter_drains_on_drop() {
3017        use vk::ImageAspectFlags as A;
3018
3019        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
3020        let image = Access::new(info, AccessType::Nothing);
3021        let dense = Mutex::new(None);
3022
3023        let Access::Dense(access) = &image else {
3024            panic!("expected dense-capable access tracking");
3025        };
3026
3027        {
3028            let mut accesses = image.swap(
3029                &dense,
3030                info,
3031                AccessType::AnyShaderReadOther,
3032                image_subresource_range(A::COLOR, 0..1, 0..1),
3033            );
3034
3035            assert_access_ranges_eq(
3036                accesses.next().unwrap(),
3037                (
3038                    AccessType::Nothing,
3039                    image_subresource_range(A::COLOR, 0..1, 0..1),
3040                ),
3041            );
3042            assert!(accesses.next().is_none());
3043        }
3044
3045        {
3046            let mut accesses = image.swap(
3047                &dense,
3048                info,
3049                AccessType::AnyShaderWrite,
3050                image_subresource_range(A::COLOR, 1..2, 0..1),
3051            );
3052
3053            assert_access_ranges_eq(
3054                accesses.next().unwrap(),
3055                (
3056                    AccessType::Nothing,
3057                    image_subresource_range(A::COLOR, 1..2, 0..1),
3058                ),
3059            );
3060            assert!(accesses.next().is_none());
3061        }
3062
3063        let mut accesses = image.swap(
3064            &dense,
3065            info,
3066            AccessType::HostRead,
3067            image_subresource_range(A::COLOR, 0..2, 0..2),
3068        );
3069
3070        assert!(accesses.next().is_some());
3071        drop(accesses);
3072
3073        assert!(!access.is_dense_active());
3074        assert_eq!(access.load(), AccessType::HostRead);
3075
3076        let dense = dense.lock();
3077        #[cfg(not(feature = "parking_lot"))]
3078        let dense = dense.expect("poisoned image dense lock");
3079
3080        assert!(dense.is_none());
3081    }
3082
3083    #[test]
3084    pub fn image_access_color() {
3085        use vk::ImageAspectFlags as A;
3086
3087        let mut image = DenseMap::new(
3088            image_subresource(vk::Format::R8G8B8A8_UNORM, 3, 3),
3089            AccessType::Nothing,
3090        );
3091
3092        {
3093            let mut accesses = DenseMapIter::new(
3094                &mut image,
3095                AccessType::AnyShaderWrite,
3096                image_subresource_range(A::COLOR, 0..3, 0..3),
3097            );
3098
3099            assert_access_ranges_eq(
3100                accesses.next().unwrap(),
3101                (
3102                    AccessType::Nothing,
3103                    image_subresource_range(A::COLOR, 0..3, 0..3),
3104                ),
3105            );
3106            assert!(accesses.next().is_none());
3107        }
3108
3109        {
3110            let mut accesses = DenseMapIter::new(
3111                &mut image,
3112                AccessType::AnyShaderReadOther,
3113                image_subresource_range(A::COLOR, 0..1, 0..1),
3114            );
3115
3116            assert_access_ranges_eq(
3117                accesses.next().unwrap(),
3118                (
3119                    AccessType::AnyShaderWrite,
3120                    image_subresource_range(A::COLOR, 0..1, 0..1),
3121                ),
3122            );
3123            assert!(accesses.next().is_none());
3124        }
3125
3126        {
3127            let mut accesses = DenseMapIter::new(
3128                &mut image,
3129                AccessType::ComputeShaderWrite,
3130                image_subresource_range(A::COLOR, 0..3, 0..3),
3131            );
3132
3133            assert_access_ranges_eq(
3134                accesses.next().unwrap(),
3135                (
3136                    AccessType::AnyShaderReadOther,
3137                    image_subresource_range(A::COLOR, 0..1, 0..1),
3138                ),
3139            );
3140            assert_access_ranges_eq(
3141                accesses.next().unwrap(),
3142                (
3143                    AccessType::AnyShaderWrite,
3144                    image_subresource_range(A::COLOR, 0..1, 1..3),
3145                ),
3146            );
3147            assert_access_ranges_eq(
3148                accesses.next().unwrap(),
3149                (
3150                    AccessType::AnyShaderWrite,
3151                    image_subresource_range(A::COLOR, 1..3, 0..3),
3152                ),
3153            );
3154            assert!(accesses.next().is_none());
3155        }
3156
3157        {
3158            let mut accesses = DenseMapIter::new(
3159                &mut image,
3160                AccessType::HostRead,
3161                image_subresource_range(A::COLOR, 0..3, 0..3),
3162            );
3163
3164            assert_access_ranges_eq(
3165                accesses.next().unwrap(),
3166                (
3167                    AccessType::ComputeShaderWrite,
3168                    image_subresource_range(A::COLOR, 0..3, 0..3),
3169                ),
3170            );
3171            assert!(accesses.next().is_none());
3172        }
3173
3174        {
3175            let mut accesses = DenseMapIter::new(
3176                &mut image,
3177                AccessType::HostWrite,
3178                image_subresource_range(A::COLOR, 1..2, 1..2),
3179            );
3180
3181            assert_access_ranges_eq(
3182                accesses.next().unwrap(),
3183                (
3184                    AccessType::HostRead,
3185                    image_subresource_range(A::COLOR, 1..2, 1..2),
3186                ),
3187            );
3188            assert!(accesses.next().is_none());
3189        }
3190
3191        {
3192            let mut accesses = DenseMapIter::new(
3193                &mut image,
3194                AccessType::GeometryShaderReadOther,
3195                image_subresource_range(A::COLOR, 0..3, 0..3),
3196            );
3197
3198            assert_access_ranges_eq(
3199                accesses.next().unwrap(),
3200                (
3201                    AccessType::HostRead,
3202                    image_subresource_range(A::COLOR, 0..1, 0..3),
3203                ),
3204            );
3205            assert_access_ranges_eq(
3206                accesses.next().unwrap(),
3207                (
3208                    AccessType::HostRead,
3209                    image_subresource_range(A::COLOR, 1..2, 0..1),
3210                ),
3211            );
3212            assert_access_ranges_eq(
3213                accesses.next().unwrap(),
3214                (
3215                    AccessType::HostWrite,
3216                    image_subresource_range(A::COLOR, 1..2, 1..2),
3217                ),
3218            );
3219            assert_access_ranges_eq(
3220                accesses.next().unwrap(),
3221                (
3222                    AccessType::HostRead,
3223                    image_subresource_range(A::COLOR, 1..2, 2..3),
3224                ),
3225            );
3226            assert_access_ranges_eq(
3227                accesses.next().unwrap(),
3228                (
3229                    AccessType::HostRead,
3230                    image_subresource_range(A::COLOR, 2..3, 0..3),
3231                ),
3232            );
3233            assert!(accesses.next().is_none());
3234        }
3235
3236        {
3237            let mut accesses = DenseMapIter::new(
3238                &mut image,
3239                AccessType::VertexBuffer,
3240                image_subresource_range(A::COLOR, 0..3, 1..2),
3241            );
3242
3243            assert_access_ranges_eq(
3244                accesses.next().unwrap(),
3245                (
3246                    AccessType::GeometryShaderReadOther,
3247                    image_subresource_range(A::COLOR, 0..3, 1..2),
3248                ),
3249            );
3250            assert!(accesses.next().is_none());
3251        }
3252
3253        {
3254            let mut accesses = DenseMapIter::new(
3255                &mut image,
3256                AccessType::ColorAttachmentRead,
3257                image_subresource_range(A::COLOR, 0..3, 0..3),
3258            );
3259
3260            assert_access_ranges_eq(
3261                accesses.next().unwrap(),
3262                (
3263                    AccessType::GeometryShaderReadOther,
3264                    image_subresource_range(A::COLOR, 0..1, 0..1),
3265                ),
3266            );
3267            assert_access_ranges_eq(
3268                accesses.next().unwrap(),
3269                (
3270                    AccessType::VertexBuffer,
3271                    image_subresource_range(A::COLOR, 0..1, 1..2),
3272                ),
3273            );
3274            assert_access_ranges_eq(
3275                accesses.next().unwrap(),
3276                (
3277                    AccessType::GeometryShaderReadOther,
3278                    image_subresource_range(A::COLOR, 0..1, 2..3),
3279                ),
3280            );
3281            assert_access_ranges_eq(
3282                accesses.next().unwrap(),
3283                (
3284                    AccessType::GeometryShaderReadOther,
3285                    image_subresource_range(A::COLOR, 1..2, 0..1),
3286                ),
3287            );
3288            assert_access_ranges_eq(
3289                accesses.next().unwrap(),
3290                (
3291                    AccessType::VertexBuffer,
3292                    image_subresource_range(A::COLOR, 1..2, 1..2),
3293                ),
3294            );
3295            assert_access_ranges_eq(
3296                accesses.next().unwrap(),
3297                (
3298                    AccessType::GeometryShaderReadOther,
3299                    image_subresource_range(A::COLOR, 1..2, 2..3),
3300                ),
3301            );
3302            assert_access_ranges_eq(
3303                accesses.next().unwrap(),
3304                (
3305                    AccessType::GeometryShaderReadOther,
3306                    image_subresource_range(A::COLOR, 2..3, 0..1),
3307                ),
3308            );
3309            assert_access_ranges_eq(
3310                accesses.next().unwrap(),
3311                (
3312                    AccessType::VertexBuffer,
3313                    image_subresource_range(A::COLOR, 2..3, 1..2),
3314                ),
3315            );
3316            assert_access_ranges_eq(
3317                accesses.next().unwrap(),
3318                (
3319                    AccessType::GeometryShaderReadOther,
3320                    image_subresource_range(A::COLOR, 2..3, 2..3),
3321                ),
3322            );
3323            assert!(accesses.next().is_none());
3324        }
3325    }
3326
3327    #[test]
3328    pub fn image_access_layers() {
3329        use vk::ImageAspectFlags as A;
3330
3331        let mut image = DenseMap::new(
3332            image_subresource(vk::Format::R8G8B8A8_UNORM, 3, 1),
3333            AccessType::Nothing,
3334        );
3335
3336        {
3337            let mut accesses = DenseMapIter::new(
3338                &mut image,
3339                AccessType::AnyShaderWrite,
3340                image_subresource_range(A::COLOR, 0..3, 0..1),
3341            );
3342
3343            assert_access_ranges_eq(
3344                accesses.next().unwrap(),
3345                (
3346                    AccessType::Nothing,
3347                    image_subresource_range(A::COLOR, 0..3, 0..1),
3348                ),
3349            );
3350            assert!(accesses.next().is_none());
3351        }
3352
3353        {
3354            let mut accesses = DenseMapIter::new(
3355                &mut image,
3356                AccessType::AnyShaderReadOther,
3357                image_subresource_range(A::COLOR, 2..3, 0..1),
3358            );
3359
3360            assert_access_ranges_eq(
3361                accesses.next().unwrap(),
3362                (
3363                    AccessType::AnyShaderWrite,
3364                    image_subresource_range(A::COLOR, 2..3, 0..1),
3365                ),
3366            );
3367            assert!(accesses.next().is_none());
3368        }
3369
3370        {
3371            let mut accesses = DenseMapIter::new(
3372                &mut image,
3373                AccessType::HostRead,
3374                image_subresource_range(A::COLOR, 0..2, 0..1),
3375            );
3376
3377            assert_access_ranges_eq(
3378                accesses.next().unwrap(),
3379                (
3380                    AccessType::AnyShaderWrite,
3381                    image_subresource_range(A::COLOR, 0..2, 0..1),
3382                ),
3383            );
3384            assert!(accesses.next().is_none());
3385        }
3386
3387        {
3388            let mut accesses = DenseMapIter::new(
3389                &mut image,
3390                AccessType::AnyShaderReadOther,
3391                image_subresource_range(A::COLOR, 0..1, 0..1),
3392            );
3393
3394            assert_access_ranges_eq(
3395                accesses.next().unwrap(),
3396                (
3397                    AccessType::HostRead,
3398                    image_subresource_range(A::COLOR, 0..1, 0..1),
3399                ),
3400            );
3401            assert!(accesses.next().is_none());
3402        }
3403
3404        {
3405            let mut accesses = DenseMapIter::new(
3406                &mut image,
3407                AccessType::AnyShaderReadOther,
3408                image_subresource_range(A::COLOR, 1..2, 0..1),
3409            );
3410
3411            assert_access_ranges_eq(
3412                accesses.next().unwrap(),
3413                (
3414                    AccessType::HostRead,
3415                    image_subresource_range(A::COLOR, 1..2, 0..1),
3416                ),
3417            );
3418            assert!(accesses.next().is_none());
3419        }
3420
3421        {
3422            let mut accesses = DenseMapIter::new(
3423                &mut image,
3424                AccessType::HostWrite,
3425                image_subresource_range(A::COLOR, 0..3, 0..1),
3426            );
3427
3428            assert_access_ranges_eq(
3429                accesses.next().unwrap(),
3430                (
3431                    AccessType::AnyShaderReadOther,
3432                    image_subresource_range(A::COLOR, 0..3, 0..1),
3433                ),
3434            );
3435            assert!(accesses.next().is_none());
3436        }
3437    }
3438
3439    #[test]
3440    pub fn image_access_levels() {
3441        use vk::ImageAspectFlags as A;
3442
3443        let mut image = DenseMap::new(
3444            image_subresource(vk::Format::R8G8B8A8_UNORM, 1, 3),
3445            AccessType::Nothing,
3446        );
3447
3448        {
3449            let mut accesses = DenseMapIter::new(
3450                &mut image,
3451                AccessType::AnyShaderWrite,
3452                image_subresource_range(A::COLOR, 0..1, 0..3),
3453            );
3454
3455            assert_access_ranges_eq(
3456                accesses.next().unwrap(),
3457                (
3458                    AccessType::Nothing,
3459                    image_subresource_range(A::COLOR, 0..1, 0..3),
3460                ),
3461            );
3462            assert!(accesses.next().is_none());
3463        }
3464
3465        {
3466            let mut accesses = DenseMapIter::new(
3467                &mut image,
3468                AccessType::AnyShaderReadOther,
3469                image_subresource_range(A::COLOR, 0..1, 2..3),
3470            );
3471
3472            assert_access_ranges_eq(
3473                accesses.next().unwrap(),
3474                (
3475                    AccessType::AnyShaderWrite,
3476                    image_subresource_range(A::COLOR, 0..1, 2..3),
3477                ),
3478            );
3479            assert!(accesses.next().is_none());
3480        }
3481
3482        {
3483            let mut accesses = DenseMapIter::new(
3484                &mut image,
3485                AccessType::HostRead,
3486                image_subresource_range(A::COLOR, 0..1, 0..2),
3487            );
3488
3489            assert_access_ranges_eq(
3490                accesses.next().unwrap(),
3491                (
3492                    AccessType::AnyShaderWrite,
3493                    image_subresource_range(A::COLOR, 0..1, 0..2),
3494                ),
3495            );
3496            assert!(accesses.next().is_none());
3497        }
3498
3499        {
3500            let mut accesses = DenseMapIter::new(
3501                &mut image,
3502                AccessType::AnyShaderReadOther,
3503                image_subresource_range(A::COLOR, 0..1, 0..1),
3504            );
3505
3506            assert_access_ranges_eq(
3507                accesses.next().unwrap(),
3508                (
3509                    AccessType::HostRead,
3510                    image_subresource_range(A::COLOR, 0..1, 0..1),
3511                ),
3512            );
3513            assert!(accesses.next().is_none());
3514        }
3515
3516        {
3517            let mut accesses = DenseMapIter::new(
3518                &mut image,
3519                AccessType::AnyShaderReadOther,
3520                image_subresource_range(A::COLOR, 0..1, 1..2),
3521            );
3522
3523            assert_access_ranges_eq(
3524                accesses.next().unwrap(),
3525                (
3526                    AccessType::HostRead,
3527                    image_subresource_range(A::COLOR, 0..1, 1..2),
3528                ),
3529            );
3530            assert!(accesses.next().is_none());
3531        }
3532
3533        {
3534            let mut accesses = DenseMapIter::new(
3535                &mut image,
3536                AccessType::HostWrite,
3537                image_subresource_range(A::COLOR, 0..1, 0..3),
3538            );
3539
3540            assert_access_ranges_eq(
3541                accesses.next().unwrap(),
3542                (
3543                    AccessType::AnyShaderReadOther,
3544                    image_subresource_range(A::COLOR, 0..1, 0..3),
3545                ),
3546            );
3547            assert!(accesses.next().is_none());
3548        }
3549    }
3550
3551    #[test]
3552    pub fn image_access_depth_stencil() {
3553        use vk::ImageAspectFlags as A;
3554
3555        let mut image = DenseMap::new(
3556            image_subresource(vk::Format::D24_UNORM_S8_UINT, 4, 3),
3557            AccessType::Nothing,
3558        );
3559
3560        {
3561            let mut accesses = DenseMapIter::new(
3562                &mut image,
3563                AccessType::AnyShaderWrite,
3564                image_subresource_range(A::DEPTH, 0..4, 0..1),
3565            );
3566
3567            assert_access_ranges_eq(
3568                accesses.next().unwrap(),
3569                (
3570                    AccessType::Nothing,
3571                    image_subresource_range(A::DEPTH, 0..4, 0..1),
3572                ),
3573            );
3574            assert!(accesses.next().is_none());
3575        }
3576
3577        {
3578            let mut accesses = DenseMapIter::new(
3579                &mut image,
3580                AccessType::AnyShaderWrite,
3581                image_subresource_range(A::STENCIL, 0..4, 1..2),
3582            );
3583
3584            assert_access_ranges_eq(
3585                accesses.next().unwrap(),
3586                (
3587                    AccessType::Nothing,
3588                    image_subresource_range(A::STENCIL, 0..4, 1..2),
3589                ),
3590            );
3591            assert!(accesses.next().is_none());
3592        }
3593
3594        {
3595            let mut accesses = DenseMapIter::new(
3596                &mut image,
3597                AccessType::AnyShaderReadOther,
3598                image_subresource_range(A::DEPTH | A::STENCIL, 0..4, 0..2),
3599            );
3600
3601            assert_access_ranges_eq(
3602                accesses.next().unwrap(),
3603                (
3604                    AccessType::AnyShaderWrite,
3605                    image_subresource_range(A::DEPTH, 0..1, 0..1),
3606                ),
3607            );
3608            assert_access_ranges_eq(
3609                accesses.next().unwrap(),
3610                (
3611                    AccessType::Nothing,
3612                    image_subresource_range(A::DEPTH, 0..1, 1..2),
3613                ),
3614            );
3615            assert_access_ranges_eq(
3616                accesses.next().unwrap(),
3617                (
3618                    AccessType::AnyShaderWrite,
3619                    image_subresource_range(A::DEPTH, 1..2, 0..1),
3620                ),
3621            );
3622            assert_access_ranges_eq(
3623                accesses.next().unwrap(),
3624                (
3625                    AccessType::Nothing,
3626                    image_subresource_range(A::DEPTH, 1..2, 1..2),
3627                ),
3628            );
3629            assert_access_ranges_eq(
3630                accesses.next().unwrap(),
3631                (
3632                    AccessType::AnyShaderWrite,
3633                    image_subresource_range(A::DEPTH, 2..3, 0..1),
3634                ),
3635            );
3636            assert_access_ranges_eq(
3637                accesses.next().unwrap(),
3638                (
3639                    AccessType::Nothing,
3640                    image_subresource_range(A::DEPTH, 2..3, 1..2),
3641                ),
3642            );
3643            assert_access_ranges_eq(
3644                accesses.next().unwrap(),
3645                (
3646                    AccessType::AnyShaderWrite,
3647                    image_subresource_range(A::DEPTH, 3..4, 0..1),
3648                ),
3649            );
3650            assert_access_ranges_eq(
3651                accesses.next().unwrap(),
3652                (
3653                    AccessType::Nothing,
3654                    image_subresource_range(A::DEPTH, 3..4, 1..2),
3655                ),
3656            );
3657            assert_access_ranges_eq(
3658                accesses.next().unwrap(),
3659                (
3660                    AccessType::Nothing,
3661                    image_subresource_range(A::STENCIL, 0..1, 0..1),
3662                ),
3663            );
3664            assert_access_ranges_eq(
3665                accesses.next().unwrap(),
3666                (
3667                    AccessType::AnyShaderWrite,
3668                    image_subresource_range(A::STENCIL, 0..1, 1..2),
3669                ),
3670            );
3671            assert_access_ranges_eq(
3672                accesses.next().unwrap(),
3673                (
3674                    AccessType::Nothing,
3675                    image_subresource_range(A::STENCIL, 1..2, 0..1),
3676                ),
3677            );
3678            assert_access_ranges_eq(
3679                accesses.next().unwrap(),
3680                (
3681                    AccessType::AnyShaderWrite,
3682                    image_subresource_range(A::STENCIL, 1..2, 1..2),
3683                ),
3684            );
3685            assert_access_ranges_eq(
3686                accesses.next().unwrap(),
3687                (
3688                    AccessType::Nothing,
3689                    image_subresource_range(A::STENCIL, 2..3, 0..1),
3690                ),
3691            );
3692            assert_access_ranges_eq(
3693                accesses.next().unwrap(),
3694                (
3695                    AccessType::AnyShaderWrite,
3696                    image_subresource_range(A::STENCIL, 2..3, 1..2),
3697                ),
3698            );
3699            assert_access_ranges_eq(
3700                accesses.next().unwrap(),
3701                (
3702                    AccessType::Nothing,
3703                    image_subresource_range(A::STENCIL, 3..4, 0..1),
3704                ),
3705            );
3706            assert_access_ranges_eq(
3707                accesses.next().unwrap(),
3708                (
3709                    AccessType::AnyShaderWrite,
3710                    image_subresource_range(A::STENCIL, 3..4, 1..2),
3711                ),
3712            );
3713            assert!(accesses.next().is_none());
3714        }
3715
3716        {
3717            let mut accesses = DenseMapIter::new(
3718                &mut image,
3719                AccessType::AccelerationStructureBuildWrite,
3720                image_subresource_range(A::DEPTH | A::STENCIL, 0..4, 0..2),
3721            );
3722
3723            assert_access_ranges_eq(
3724                accesses.next().unwrap(),
3725                (
3726                    AccessType::AnyShaderReadOther,
3727                    image_subresource_range(A::DEPTH | A::STENCIL, 0..4, 0..2),
3728                ),
3729            );
3730            assert!(accesses.next().is_none());
3731        }
3732
3733        {
3734            let mut accesses = DenseMapIter::new(
3735                &mut image,
3736                AccessType::AccelerationStructureBuildRead,
3737                image_subresource_range(A::DEPTH, 1..3, 0..2),
3738            );
3739
3740            assert_access_ranges_eq(
3741                accesses.next().unwrap(),
3742                (
3743                    AccessType::AccelerationStructureBuildWrite,
3744                    image_subresource_range(A::DEPTH, 1..3, 0..2),
3745                ),
3746            );
3747            assert!(accesses.next().is_none());
3748        }
3749    }
3750
3751    #[test]
3752    pub fn image_access_stencil() {
3753        use vk::ImageAspectFlags as A;
3754
3755        let mut image = DenseMap::new(
3756            image_subresource(vk::Format::S8_UINT, 2, 2),
3757            AccessType::Nothing,
3758        );
3759
3760        {
3761            let mut accesses = DenseMapIter::new(
3762                &mut image,
3763                AccessType::AnyShaderWrite,
3764                image_subresource_range(A::STENCIL, 0..2, 0..1),
3765            );
3766
3767            assert_access_ranges_eq(
3768                accesses.next().unwrap(),
3769                (
3770                    AccessType::Nothing,
3771                    image_subresource_range(A::STENCIL, 0..2, 0..1),
3772                ),
3773            );
3774            assert!(accesses.next().is_none());
3775        }
3776
3777        {
3778            let mut accesses = DenseMapIter::new(
3779                &mut image,
3780                AccessType::AnyShaderReadOther,
3781                image_subresource_range(A::STENCIL, 0..2, 1..2),
3782            );
3783
3784            assert_access_ranges_eq(
3785                accesses.next().unwrap(),
3786                (
3787                    AccessType::Nothing,
3788                    image_subresource_range(A::STENCIL, 0..2, 1..2),
3789                ),
3790            );
3791            assert!(accesses.next().is_none());
3792        }
3793
3794        {
3795            let mut accesses = DenseMapIter::new(
3796                &mut image,
3797                AccessType::HostRead,
3798                image_subresource_range(A::STENCIL, 0..2, 0..2),
3799            );
3800
3801            assert_access_ranges_eq(
3802                accesses.next().unwrap(),
3803                (
3804                    AccessType::AnyShaderWrite,
3805                    image_subresource_range(A::STENCIL, 0..1, 0..1),
3806                ),
3807            );
3808            assert_access_ranges_eq(
3809                accesses.next().unwrap(),
3810                (
3811                    AccessType::AnyShaderReadOther,
3812                    image_subresource_range(A::STENCIL, 0..1, 1..2),
3813                ),
3814            );
3815            assert_access_ranges_eq(
3816                accesses.next().unwrap(),
3817                (
3818                    AccessType::AnyShaderWrite,
3819                    image_subresource_range(A::STENCIL, 1..2, 0..1),
3820                ),
3821            );
3822            assert_access_ranges_eq(
3823                accesses.next().unwrap(),
3824                (
3825                    AccessType::AnyShaderReadOther,
3826                    image_subresource_range(A::STENCIL, 1..2, 1..2),
3827                ),
3828            );
3829            assert!(accesses.next().is_none());
3830        }
3831    }
3832
3833    #[test]
3834    pub fn image_info_cube() {
3835        let info = ImageInfo::cube(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3836        let builder = info.into_builder().build();
3837
3838        assert_eq!(info, builder);
3839    }
3840
3841    #[test]
3842    pub fn image_info_cube_builder() {
3843        let info = ImageInfo::cube(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3844        let builder = ImageInfoBuilder::default()
3845            .image_type(vk::ImageType::TYPE_2D)
3846            .format(vk::Format::R32_SFLOAT)
3847            .width(42)
3848            .height(42)
3849            .depth(1)
3850            .array_layer_count(6)
3851            .flags(vk::ImageCreateFlags::CUBE_COMPATIBLE)
3852            .build();
3853
3854        assert_eq!(info, builder);
3855    }
3856
3857    #[test]
3858    pub fn image_info_image_1d() {
3859        let info = ImageInfo::image_1d(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3860        let builder = info.into_builder().build();
3861
3862        assert_eq!(info, builder);
3863    }
3864
3865    #[test]
3866    pub fn image_info_image_1d_builder() {
3867        let info = ImageInfo::image_1d(42, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3868        let builder = ImageInfoBuilder::default()
3869            .image_type(vk::ImageType::TYPE_1D)
3870            .format(vk::Format::R32_SFLOAT)
3871            .width(42)
3872            .height(1)
3873            .depth(1)
3874            .build();
3875
3876        assert_eq!(info, builder);
3877    }
3878
3879    #[test]
3880    pub fn image_info_image_2d() {
3881        let info =
3882            ImageInfo::image_2d(42, 84, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3883        let builder = info.into_builder().build();
3884
3885        assert_eq!(info, builder);
3886    }
3887
3888    #[test]
3889    pub fn image_info_image_2d_builder() {
3890        let info =
3891            ImageInfo::image_2d(42, 84, vk::Format::R32_SFLOAT, vk::ImageUsageFlags::empty());
3892        let builder = ImageInfoBuilder::default()
3893            .image_type(vk::ImageType::TYPE_2D)
3894            .format(vk::Format::R32_SFLOAT)
3895            .width(42)
3896            .height(84)
3897            .depth(1)
3898            .build();
3899
3900        assert_eq!(info, builder);
3901    }
3902
3903    #[test]
3904    pub fn image_info_image_2d_array() {
3905        let info = ImageInfo::image_2d_array(
3906            42,
3907            84,
3908            100,
3909            vk::Format::default(),
3910            vk::ImageUsageFlags::empty(),
3911        );
3912        let builder = info.into_builder().build();
3913
3914        assert_eq!(info, builder);
3915    }
3916
3917    #[test]
3918    pub fn image_info_image_2d_array_builder() {
3919        let info = ImageInfo::image_2d_array(
3920            42,
3921            84,
3922            100,
3923            vk::Format::R32_SFLOAT,
3924            vk::ImageUsageFlags::empty(),
3925        );
3926        let builder = ImageInfoBuilder::default()
3927            .image_type(vk::ImageType::TYPE_2D)
3928            .format(vk::Format::R32_SFLOAT)
3929            .width(42)
3930            .height(84)
3931            .depth(1)
3932            .array_layer_count(100)
3933            .build();
3934
3935        assert_eq!(info, builder);
3936    }
3937
3938    #[test]
3939    pub fn image_info_image_3d() {
3940        let info = ImageInfo::image_3d(
3941            42,
3942            84,
3943            100,
3944            vk::Format::R32_SFLOAT,
3945            vk::ImageUsageFlags::empty(),
3946        );
3947        let builder = info.into_builder().build();
3948
3949        assert_eq!(info, builder);
3950    }
3951
3952    #[test]
3953    pub fn image_info_image_3d_builder() {
3954        let info = ImageInfo::image_3d(
3955            42,
3956            84,
3957            100,
3958            vk::Format::R32_SFLOAT,
3959            vk::ImageUsageFlags::empty(),
3960        );
3961        let builder = ImageInfoBuilder::default()
3962            .image_type(vk::ImageType::TYPE_3D)
3963            .format(vk::Format::R32_SFLOAT)
3964            .width(42)
3965            .height(84)
3966            .depth(100)
3967            .build();
3968
3969        assert_eq!(info, builder);
3970    }
3971
3972    #[test]
3973    pub fn image_info_builder_defaults() {
3974        let info = ImageInfo {
3975            array_layer_count: 1,
3976            alloc_dedicated: false,
3977            depth: 0,
3978            flags: vk::ImageCreateFlags::empty(),
3979            format: vk::Format::UNDEFINED,
3980            height: 0,
3981            host_readable: false,
3982            host_writable: false,
3983            mip_level_count: 1,
3984            sample_count: SampleCount::Type1,
3985            sharing_mode: vk::SharingMode::EXCLUSIVE,
3986            tiling: vk::ImageTiling::OPTIMAL,
3987            image_type: vk::ImageType::TYPE_2D,
3988            usage: vk::ImageUsageFlags::empty(),
3989            width: 0,
3990        };
3991
3992        assert_eq!(ImageInfoBuilder::default().build(), info);
3993    }
3994
3995    fn image_access_fuzz(aspect_count: u8, array_layer_count: u32, mip_level_count: u32) {
3996        const FUZZ_COUNT: usize = 100_000;
3997        static ACCESS_TYPES: &[AccessType] = &[
3998            AccessType::AnyShaderReadOther,
3999            AccessType::AnyShaderWrite,
4000            AccessType::ColorAttachmentRead,
4001            AccessType::ColorAttachmentWrite,
4002            AccessType::HostRead,
4003            AccessType::HostWrite,
4004            AccessType::Nothing,
4005        ];
4006
4007        let fmt = match aspect_count {
4008            1 => vk::Format::R8G8B8A8_UNORM,
4009            2 => vk::Format::D24_UNORM_S8_UINT,
4010            _ => unreachable!(),
4011        };
4012
4013        let mut rng = SmallRng::seed_from_u64(42);
4014        let total = (aspect_count as u32 * array_layer_count * mip_level_count) as usize;
4015        let mut access_map = DenseMap::new(
4016            image_subresource(fmt, array_layer_count, mip_level_count),
4017            AccessType::Nothing,
4018        );
4019        let mut data = vec![AccessType::Nothing; total];
4020
4021        let aspect_bits = format_aspect_mask(fmt);
4022
4023        for _ in 0..FUZZ_COUNT {
4024            let new_access = ACCESS_TYPES[rng.random_range(..ACCESS_TYPES.len())];
4025
4026            // Pick a valid aspect mask from the format's supported aspects
4027            let aspect_mask = if aspect_count == 2 && rng.random_bool(0.5) {
4028                aspect_bits
4029            } else {
4030                let bit_index =
4031                    rng.random_range(..aspect_count) + aspect_bits.as_raw().trailing_zeros() as u8;
4032                vk::ImageAspectFlags::from_raw(1 << bit_index)
4033            };
4034
4035            let layer_start = rng.random_range(..array_layer_count);
4036            let layer_end = rng.random_range(layer_start + 1..=array_layer_count);
4037            let mip_start = rng.random_range(..mip_level_count);
4038            let mip_end = rng.random_range(mip_start + 1..=mip_level_count);
4039
4040            let range =
4041                image_subresource_range(aspect_mask, layer_start..layer_end, mip_start..mip_end);
4042
4043            for (prev, range) in access_map.swap(new_access, range) {
4044                let range_mask = range.aspect_mask.as_raw();
4045                for ai in 0..range_mask.count_ones() as u8 {
4046                    let bit = range_mask.trailing_zeros() + ai as u32;
4047                    let a = (aspect_bits.as_raw() & ((1 << bit) - 1)).count_ones() as u8;
4048                    for l in range.base_array_layer..range.base_array_layer + range.layer_count {
4049                        for m in range.base_mip_level..range.base_mip_level + range.level_count {
4050                            let idx = (l * aspect_count as u32 * mip_level_count
4051                                + m * aspect_count as u32
4052                                + a as u32) as usize;
4053                            assert_eq!(
4054                                data[idx], prev,
4055                                "prev mismatch at aspect={a} layer={l} mip={m} idx={idx}: expected {prev:?}, got {:?}",
4056                                data[idx],
4057                            );
4058                        }
4059                    }
4060                }
4061            }
4062
4063            for a in 0..aspect_count {
4064                let bit = aspect_bits.as_raw().trailing_zeros() as u8 + a;
4065                if aspect_mask.as_raw() & (1 << bit) == 0 {
4066                    continue;
4067                }
4068                for l in layer_start..layer_end {
4069                    for m in mip_start..mip_end {
4070                        let idx = access_map.idx(a, l, m);
4071                        data[idx] = new_access;
4072                    }
4073                }
4074            }
4075        }
4076    }
4077
4078    #[test]
4079    pub fn image_access_fuzz_small() {
4080        image_access_fuzz(1, 3, 3);
4081    }
4082
4083    #[test]
4084    pub fn image_access_fuzz_medium() {
4085        image_access_fuzz(2, 4, 3);
4086    }
4087
4088    #[test]
4089    pub fn image_access_fuzz_large() {
4090        image_access_fuzz(1, 10, 10);
4091    }
4092
4093    fn image_access_fuzz_through_access(
4094        aspect_count: u8,
4095        array_layer_count: u32,
4096        mip_level_count: u32,
4097    ) {
4098        const FUZZ_COUNT: usize = 10_000;
4099        static ACCESS_TYPES: &[AccessType] = &[
4100            AccessType::AnyShaderReadOther,
4101            AccessType::AnyShaderWrite,
4102            AccessType::ColorAttachmentRead,
4103            AccessType::ColorAttachmentWrite,
4104            AccessType::HostRead,
4105            AccessType::HostWrite,
4106            AccessType::Nothing,
4107        ];
4108
4109        let fmt = match aspect_count {
4110            1 => vk::Format::R8G8B8A8_UNORM,
4111            2 => vk::Format::D24_UNORM_S8_UINT,
4112            _ => unreachable!(),
4113        };
4114
4115        let mut rng = SmallRng::seed_from_u64(42);
4116        let info = image_subresource(fmt, array_layer_count, mip_level_count);
4117        let total = (aspect_count as u32 * array_layer_count * mip_level_count) as usize;
4118        let access = Access::new(info, AccessType::Nothing);
4119        let dense = Mutex::new(None);
4120        let mut data = vec![AccessType::Nothing; total];
4121
4122        let aspect_bits = format_aspect_mask(fmt);
4123
4124        for _ in 0..FUZZ_COUNT {
4125            let new_access = ACCESS_TYPES[rng.random_range(..ACCESS_TYPES.len())];
4126
4127            let aspect_mask = if aspect_count == 2 && rng.random_bool(0.5) {
4128                aspect_bits
4129            } else {
4130                let bit_index =
4131                    rng.random_range(..aspect_count) + aspect_bits.as_raw().trailing_zeros() as u8;
4132                vk::ImageAspectFlags::from_raw(1 << bit_index)
4133            };
4134
4135            let layer_start = rng.random_range(..array_layer_count);
4136            let layer_end = rng.random_range(layer_start + 1..=array_layer_count);
4137            let mip_start = rng.random_range(..mip_level_count);
4138            let mip_end = rng.random_range(mip_start + 1..=mip_level_count);
4139
4140            let range =
4141                image_subresource_range(aspect_mask, layer_start..layer_end, mip_start..mip_end);
4142            let resolved = info.resolve_subresource_counts(range);
4143
4144            for (prev, returned_range) in access.swap(&dense, info, new_access, resolved) {
4145                let range_mask = returned_range.aspect_mask.as_raw();
4146                for ai in 0..range_mask.count_ones() as u8 {
4147                    let bit = range_mask.trailing_zeros() + ai as u32;
4148                    let a = (aspect_bits.as_raw() & ((1 << bit) - 1)).count_ones() as u8;
4149                    for l in returned_range.base_array_layer
4150                        ..returned_range.base_array_layer + returned_range.layer_count
4151                    {
4152                        for m in returned_range.base_mip_level
4153                            ..returned_range.base_mip_level + returned_range.level_count
4154                        {
4155                            let idx = (l * aspect_count as u32 * mip_level_count
4156                                + m * aspect_count as u32
4157                                + a as u32) as usize;
4158                            assert_eq!(
4159                                data[idx], prev,
4160                                "prev mismatch at aspect={a} layer={l} mip={m} idx={idx}: expected {prev:?}, got {:?}",
4161                                data[idx],
4162                            );
4163                        }
4164                    }
4165                }
4166            }
4167
4168            for a in 0..aspect_count {
4169                let bit = aspect_bits.as_raw().trailing_zeros() as u8 + a;
4170                if aspect_mask.as_raw() & (1 << bit) == 0 {
4171                    continue;
4172                }
4173                for l in layer_start..layer_end {
4174                    for m in mip_start..mip_end {
4175                        let idx = (l * aspect_count as u32 * mip_level_count
4176                            + m * aspect_count as u32
4177                            + a as u32) as usize;
4178                        data[idx] = new_access;
4179                    }
4180                }
4181            }
4182        }
4183    }
4184
4185    #[test]
4186    pub fn image_access_fuzz_access_uniform() {
4187        image_access_fuzz_through_access(1, 1, 1);
4188    }
4189
4190    #[test]
4191    pub fn image_access_fuzz_access_dual_aspect() {
4192        image_access_fuzz_through_access(2, 1, 1);
4193    }
4194
4195    #[test]
4196    pub fn image_access_fuzz_access_dense_small() {
4197        image_access_fuzz_through_access(1, 4, 4);
4198    }
4199
4200    #[test]
4201    pub fn image_access_fuzz_access_dense_large() {
4202        image_access_fuzz_through_access(1, 8, 8);
4203    }
4204
4205    #[test]
4206    pub fn image_access_fuzz_access_dense_dual_aspect() {
4207        image_access_fuzz_through_access(2, 3, 3);
4208    }
4209
4210    #[test]
4211    pub fn image_sync_info_compact_merges_mips_then_layers() {
4212        use vk::ImageAspectFlags as A;
4213
4214        let mut sync_info = ImageSyncInfo {
4215            subresources: vec![
4216                image_sync_subresource(A::COLOR, 0..1, 0..1),
4217                image_sync_subresource(A::COLOR, 0..1, 1..2),
4218                image_sync_subresource(A::COLOR, 1..2, 0..1),
4219                image_sync_subresource(A::COLOR, 1..2, 1..2),
4220            ]
4221            .into_boxed_slice(),
4222        };
4223
4224        sync_info.compact();
4225
4226        assert_eq!(sync_info.subresources.len(), 1);
4227        let subresource = &sync_info.subresources[0];
4228        let range = image_subresource_range(A::COLOR, 0..2, 0..2);
4229        assert_eq!(subresource.access_mask, vk::AccessFlags::SHADER_READ);
4230        assert_eq!(
4231            subresource.layout,
4232            Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
4233        );
4234        assert_eq!(subresource.range.aspect_mask, range.aspect_mask);
4235        assert_eq!(subresource.range.base_array_layer, range.base_array_layer);
4236        assert_eq!(subresource.range.layer_count, range.layer_count);
4237        assert_eq!(subresource.range.base_mip_level, range.base_mip_level);
4238        assert_eq!(subresource.range.level_count, range.level_count);
4239        assert_eq!(
4240            subresource.stage_mask,
4241            vk::PipelineStageFlags::COMPUTE_SHADER
4242        );
4243    }
4244
4245    #[test]
4246    pub fn image_sync_info_compact_keeps_different_sync_separate() {
4247        use vk::ImageAspectFlags as A;
4248
4249        let sync_info = ImageSyncInfo {
4250            subresources: vec![
4251                image_sync_subresource(A::COLOR, 0..1, 0..1),
4252                ImageSubresourceSyncInfo {
4253                    access_mask: vk::AccessFlags::SHADER_WRITE,
4254                    layout: Some(vk::ImageLayout::GENERAL),
4255                    queue_family_index: None,
4256                    range: image_subresource_range(A::COLOR, 0..1, 1..2),
4257                    stage_mask: vk::PipelineStageFlags::COMPUTE_SHADER,
4258                },
4259            ]
4260            .into_boxed_slice(),
4261        };
4262
4263        let sync_info = sync_info.into_compacted();
4264
4265        assert_eq!(sync_info.subresources.len(), 2);
4266        let subresource = &sync_info.subresources[0];
4267        let range = image_subresource_range(A::COLOR, 0..1, 0..1);
4268        assert_eq!(subresource.access_mask, vk::AccessFlags::SHADER_READ);
4269        assert_eq!(
4270            subresource.layout,
4271            Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
4272        );
4273        assert_eq!(subresource.range.aspect_mask, range.aspect_mask);
4274        assert_eq!(subresource.range.base_array_layer, range.base_array_layer);
4275        assert_eq!(subresource.range.layer_count, range.layer_count);
4276        assert_eq!(subresource.range.base_mip_level, range.base_mip_level);
4277        assert_eq!(subresource.range.level_count, range.level_count);
4278        assert_eq!(
4279            subresource.stage_mask,
4280            vk::PipelineStageFlags::COMPUTE_SHADER
4281        );
4282        assert_eq!(
4283            sync_info.subresources[1].access_mask,
4284            vk::AccessFlags::SHADER_WRITE
4285        );
4286        assert_eq!(
4287            sync_info.subresources[1].layout,
4288            Some(vk::ImageLayout::GENERAL)
4289        );
4290    }
4291
4292    #[test]
4293    pub fn image_sync_info_compact_keeps_different_queue_families_separate() {
4294        use vk::ImageAspectFlags as A;
4295
4296        let sync_info = ImageSyncInfo {
4297            subresources: vec![
4298                ImageSubresourceSyncInfo {
4299                    access_mask: vk::AccessFlags::SHADER_READ,
4300                    layout: Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL),
4301                    queue_family_index: Some(1),
4302                    range: image_subresource_range(A::COLOR, 0..1, 0..1),
4303                    stage_mask: vk::PipelineStageFlags::COMPUTE_SHADER,
4304                },
4305                ImageSubresourceSyncInfo {
4306                    access_mask: vk::AccessFlags::SHADER_READ,
4307                    layout: Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL),
4308                    queue_family_index: Some(2),
4309                    range: image_subresource_range(A::COLOR, 0..1, 1..2),
4310                    stage_mask: vk::PipelineStageFlags::COMPUTE_SHADER,
4311                },
4312            ]
4313            .into_boxed_slice(),
4314        };
4315
4316        let sync_info = sync_info.into_compacted();
4317
4318        assert_eq!(sync_info.subresources.len(), 2);
4319        assert_eq!(sync_info.subresources[0].queue_family_index, Some(1));
4320        assert_eq!(sync_info.subresources[1].queue_family_index, Some(2));
4321    }
4322
4323    #[test]
4324    pub fn image_ownership_set_promotes_dense_on_partial_update() {
4325        use vk::ImageAspectFlags as A;
4326
4327        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
4328        let sharing = Sharing::new(info, vk::SharingMode::EXCLUSIVE);
4329        let dense = Mutex::new(None);
4330
4331        sharing.set_ranges(
4332            &dense,
4333            info,
4334            SharingMode::Exclusive(Some((7, 3))),
4335            &[image_subresource_range(A::COLOR, 0..1, 0..1)],
4336        );
4337
4338        match &sharing {
4339            Sharing::Exclusive(exclusive) => {
4340                assert!(exclusive.is_dense_sharing_active());
4341            }
4342            Sharing::Concurrent => panic!("expected exclusive ownership"),
4343        }
4344
4345        let dense = dense.lock();
4346
4347        #[cfg(not(feature = "parking_lot"))]
4348        let dense = dense.expect("poisoned image dense lock");
4349
4350        let dense = dense.as_ref().expect("missing dense sharing state");
4351        assert_eq!(
4352            dense.subresource(0, 0, 0),
4353            SharingMode::Exclusive(Some((7, 3)))
4354        );
4355        assert_eq!(dense.subresource(0, 1, 0), SharingMode::Exclusive(None));
4356        assert_eq!(dense.subresource(0, 0, 1), SharingMode::Exclusive(None));
4357        assert_eq!(dense.subresource(0, 1, 1), SharingMode::Exclusive(None));
4358    }
4359
4360    #[test]
4361    pub fn image_ownership_set_whole_image_stays_uniform() {
4362        use vk::ImageAspectFlags as A;
4363
4364        let info = image_subresource(vk::Format::R8_UINT, 2, 2);
4365        let sharing = Sharing::new(info, vk::SharingMode::EXCLUSIVE);
4366        let dense = Mutex::new(None);
4367
4368        sharing.set_ranges(
4369            &dense,
4370            info,
4371            SharingMode::Exclusive(Some((1, 2))),
4372            &[image_subresource_range(A::COLOR, 0..2, 0..2)],
4373        );
4374
4375        match &sharing {
4376            Sharing::Exclusive(exclusive) => {
4377                assert!(!exclusive.is_dense_sharing_active());
4378                assert_eq!(
4379                    SharingMode::decode(exclusive.uniform.load(Ordering::Acquire)),
4380                    SharingMode::Exclusive(Some((1, 2)))
4381                );
4382            }
4383            Sharing::Concurrent => panic!("expected exclusive ownership"),
4384        }
4385    }
4386
4387    fn image_subresource(
4388        format: vk::Format,
4389        array_layer_count: u32,
4390        mip_level_count: u32,
4391    ) -> ImageInfo {
4392        ImageInfo::image_2d(1, 1, format, vk::ImageUsageFlags::empty())
4393            .into_builder()
4394            .array_layer_count(array_layer_count)
4395            .mip_level_count(mip_level_count)
4396            .build()
4397    }
4398
4399    fn image_subresource_range(
4400        aspect_mask: vk::ImageAspectFlags,
4401        array_layers: Range<u32>,
4402        mip_levels: Range<u32>,
4403    ) -> vk::ImageSubresourceRange {
4404        vk::ImageSubresourceRange {
4405            aspect_mask,
4406            base_array_layer: array_layers.start,
4407            base_mip_level: mip_levels.start,
4408            layer_count: array_layers.len() as _,
4409            level_count: mip_levels.len() as _,
4410        }
4411    }
4412
4413    #[test]
4414    pub fn image_subresource_range_contains() {
4415        use {
4416            super::image_subresource_range_contains as f, image_subresource_range as i,
4417            vk::ImageAspectFlags as A,
4418        };
4419
4420        assert!(f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 0..1, 0..1)));
4421        assert!(f(i(A::COLOR, 0..2, 0..1), i(A::COLOR, 0..1, 0..1)));
4422        assert!(f(i(A::COLOR, 0..1, 0..2), i(A::COLOR, 0..1, 0..1)));
4423        assert!(f(i(A::COLOR, 0..2, 0..2), i(A::COLOR, 0..1, 0..1)));
4424        assert!(!f(i(A::COLOR, 0..1, 1..3), i(A::COLOR, 0..1, 0..1)));
4425        assert!(!f(i(A::COLOR, 1..3, 0..1), i(A::COLOR, 0..1, 0..1)));
4426        assert!(!f(i(A::COLOR, 0..1, 1..3), i(A::COLOR, 0..1, 0..2)));
4427        assert!(!f(i(A::COLOR, 1..3, 0..1), i(A::COLOR, 0..2, 0..1)));
4428    }
4429
4430    #[test]
4431    pub fn image_subresource_range_intersects() {
4432        use {
4433            super::image_subresource_range_intersects as f, image_subresource_range as i,
4434            vk::ImageAspectFlags as A,
4435        };
4436
4437        assert!(f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 0..1, 0..1)));
4438        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::DEPTH, 0..1, 0..1)));
4439
4440        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 1..2, 0..1)));
4441        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::COLOR, 0..1, 1..2)));
4442        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::DEPTH, 1..2, 0..1)));
4443        assert!(!f(i(A::COLOR, 0..1, 0..1), i(A::DEPTH, 0..1, 1..2)));
4444        assert!(!f(i(A::COLOR, 1..2, 1..2), i(A::COLOR, 0..1, 0..1)));
4445
4446        assert!(f(
4447            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
4448            i(A::DEPTH, 2..3, 2..4)
4449        ));
4450        assert!(f(
4451            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
4452            i(A::DEPTH, 2..3, 4..6)
4453        ));
4454        assert!(!f(
4455            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
4456            i(A::DEPTH, 2..3, 2..3)
4457        ));
4458        assert!(!f(
4459            i(A::DEPTH | A::STENCIL, 2..3, 3..5),
4460            i(A::DEPTH, 2..3, 5..6)
4461        ));
4462    }
4463
4464    #[test]
4465    pub fn image_subresource_range_normalize_remaining_counts() {
4466        let info = image_subresource(vk::Format::R8_UINT, 4, 6);
4467        let range = vk::ImageSubresourceRange {
4468            aspect_mask: vk::ImageAspectFlags::COLOR,
4469            base_array_layer: 1,
4470            layer_count: vk::REMAINING_ARRAY_LAYERS,
4471            base_mip_level: 2,
4472            level_count: vk::REMAINING_MIP_LEVELS,
4473        };
4474
4475        let range = info.resolve_subresource_counts(range);
4476
4477        assert_eq!(range.base_array_layer, 1);
4478        assert_eq!(range.layer_count, 3);
4479        assert_eq!(range.base_mip_level, 2);
4480        assert_eq!(range.level_count, 4);
4481    }
4482
4483    #[test]
4484    pub fn image_view_info() {
4485        let info = ImageViewInfo::new(vk::Format::default(), vk::ImageViewType::TYPE_1D);
4486        let builder = info.into_builder().build();
4487
4488        assert_eq!(info, builder);
4489    }
4490
4491    #[test]
4492    pub fn image_view_info_builder() {
4493        let info = ImageViewInfo::new(vk::Format::default(), vk::ImageViewType::TYPE_1D);
4494        let builder = ImageViewInfoBuilder::default()
4495            .format(vk::Format::default())
4496            .view_type(vk::ImageViewType::TYPE_1D)
4497            .aspect_mask(vk::ImageAspectFlags::COLOR)
4498            .build();
4499
4500        assert_eq!(info, builder);
4501    }
4502
4503    #[test]
4504    pub fn image_view_info_builder_defaults() {
4505        assert_eq!(
4506            ImageViewInfoBuilder::default().build(),
4507            ImageViewInfo::new(vk::Format::UNDEFINED, vk::ImageViewType::TYPE_2D)
4508        );
4509    }
4510}