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