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