1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9
10 use crate::buffer::BufferAccess;
11 use crate::buffer::BufferUsage;
12 use crate::buffer::CpuAccessibleBuffer;
13 use crate::buffer::TypedBufferAccess;
14 use crate::command_buffer::AutoCommandBufferBuilder;
15 use crate::command_buffer::CommandBufferExecFuture;
16 use crate::command_buffer::CommandBufferUsage;
17 use crate::command_buffer::PrimaryAutoCommandBuffer;
18 use crate::command_buffer::PrimaryCommandBuffer;
19 use crate::device::physical::QueueFamily;
20 use crate::device::Device;
21 use crate::device::Queue;
22 use crate::format::Format;
23 use crate::format::Pixel;
24 use crate::image::sys::ImageCreationError;
25 use crate::image::sys::UnsafeImage;
26 use crate::image::traits::ImageAccess;
27 use crate::image::traits::ImageContent;
28 use crate::image::ImageCreateFlags;
29 use crate::image::ImageDescriptorLayouts;
30 use crate::image::ImageDimensions;
31 use crate::image::ImageInner;
32 use crate::image::ImageLayout;
33 use crate::image::ImageUsage;
34 use crate::image::MipmapsCount;
35 use crate::image::SampleCount;
36 use crate::memory::pool::AllocFromRequirementsFilter;
37 use crate::memory::pool::AllocLayout;
38 use crate::memory::pool::MappingRequirement;
39 use crate::memory::pool::MemoryPool;
40 use crate::memory::pool::MemoryPoolAlloc;
41 use crate::memory::pool::PotentialDedicatedAllocation;
42 use crate::memory::pool::StdMemoryPoolAlloc;
43 use crate::memory::DedicatedAlloc;
44 use crate::sampler::Filter;
45 use crate::sync::AccessError;
46 use crate::sync::NowFuture;
47 use crate::sync::Sharing;
48 use smallvec::SmallVec;
49 use std::hash::Hash;
50 use std::hash::Hasher;
51 use std::sync::atomic::AtomicBool;
52 use std::sync::atomic::Ordering;
53 use std::sync::Arc;
54
55 /// Image whose purpose is to be used for read-only purposes. You can write to the image once,
56 /// but then you must only ever read from it.
57 // TODO: type (2D, 3D, array, etc.) as template parameter
58 #[derive(Debug)]
59 pub struct ImmutableImage<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
60 image: UnsafeImage,
61 dimensions: ImageDimensions,
62 memory: A,
63 format: Format,
64 initialized: AtomicBool,
65 layout: ImageLayout,
66 }
67
68 /// Image whose purpose is to access only a part of one image, for any kind of access
69 /// We define a part of one image here by a level of mipmap, or a layer of an array
70 /// The image attribute must be an implementation of ImageAccess
71 /// The mip_levels_access must be a range showing which mipmaps will be accessed
72 /// The layer_levels_access must be a range showing which layers will be accessed
73 /// The layout must be the layout of the image at the beginning and at the end of the command buffer
74 pub struct SubImage {
75 image: Arc<dyn ImageAccess + Sync + Send>,
76 mip_levels_access: std::ops::Range<u32>,
77 layer_levels_access: std::ops::Range<u32>,
78 layout: ImageLayout,
79 }
80
81 impl SubImage {
new( image: Arc<dyn ImageAccess + Sync + Send>, mip_level: u32, mip_level_count: u32, layer_level: u32, layer_level_count: u32, layout: ImageLayout, ) -> Arc<SubImage>82 pub fn new(
83 image: Arc<dyn ImageAccess + Sync + Send>,
84 mip_level: u32,
85 mip_level_count: u32,
86 layer_level: u32,
87 layer_level_count: u32,
88 layout: ImageLayout,
89 ) -> Arc<SubImage> {
90 debug_assert!(mip_level + mip_level_count <= image.mipmap_levels());
91 debug_assert!(layer_level + layer_level_count <= image.dimensions().array_layers());
92
93 let last_level = mip_level + mip_level_count;
94 let mip_levels_access = mip_level..last_level;
95
96 let last_level = layer_level + layer_level_count;
97 let layer_levels_access = layer_level..last_level;
98
99 Arc::new(SubImage {
100 image,
101 mip_levels_access,
102 layer_levels_access,
103 layout: ImageLayout::ShaderReadOnlyOptimal,
104 })
105 }
106 }
107
108 // Must not implement Clone, as that would lead to multiple `used` values.
109 pub struct ImmutableImageInitialization<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
110 image: Arc<ImmutableImage<A>>,
111 used: AtomicBool,
112 mip_levels_access: std::ops::Range<u32>,
113 layer_levels_access: std::ops::Range<u32>,
114 }
115
has_mipmaps(mipmaps: MipmapsCount) -> bool116 fn has_mipmaps(mipmaps: MipmapsCount) -> bool {
117 match mipmaps {
118 MipmapsCount::One => false,
119 MipmapsCount::Log2 => true,
120 MipmapsCount::Specific(x) => x > 1,
121 }
122 }
123
generate_mipmaps<L, Img>( cbb: &mut AutoCommandBufferBuilder<L>, image: Arc<Img>, dimensions: ImageDimensions, layout: ImageLayout, ) where Img: ImageAccess + Send + Sync + 'static,124 fn generate_mipmaps<L, Img>(
125 cbb: &mut AutoCommandBufferBuilder<L>,
126 image: Arc<Img>,
127 dimensions: ImageDimensions,
128 layout: ImageLayout,
129 ) where
130 Img: ImageAccess + Send + Sync + 'static,
131 {
132 for level in 1..image.mipmap_levels() {
133 let [xs, ys, ds] = dimensions
134 .mipmap_dimensions(level - 1)
135 .unwrap()
136 .width_height_depth();
137 let [xd, yd, dd] = dimensions
138 .mipmap_dimensions(level)
139 .unwrap()
140 .width_height_depth();
141
142 let src = SubImage::new(
143 image.clone(),
144 level - 1,
145 1,
146 0,
147 dimensions.array_layers(),
148 layout,
149 );
150
151 let dst = SubImage::new(
152 image.clone(),
153 level,
154 1,
155 0,
156 dimensions.array_layers(),
157 layout,
158 );
159
160 cbb.blit_image(
161 src, //source
162 [0, 0, 0], //source_top_left
163 [xs as i32, ys as i32, ds as i32], //source_bottom_right
164 0, //source_base_array_layer
165 level - 1, //source_mip_level
166 dst, //destination
167 [0, 0, 0], //destination_top_left
168 [xd as i32, yd as i32, dd as i32], //destination_bottom_right
169 0, //destination_base_array_layer
170 level, //destination_mip_level
171 1, //layer_count
172 Filter::Linear, //filter
173 )
174 .expect("failed to blit a mip map to image!");
175 }
176 }
177
178 impl ImmutableImage {
179 #[deprecated(note = "use ImmutableImage::uninitialized instead")]
180 #[inline]
new<'a, I>( device: Arc<Device>, dimensions: ImageDimensions, format: Format, queue_families: I, ) -> Result<Arc<ImmutableImage>, ImageCreationError> where I: IntoIterator<Item = QueueFamily<'a>>,181 pub fn new<'a, I>(
182 device: Arc<Device>,
183 dimensions: ImageDimensions,
184 format: Format,
185 queue_families: I,
186 ) -> Result<Arc<ImmutableImage>, ImageCreationError>
187 where
188 I: IntoIterator<Item = QueueFamily<'a>>,
189 {
190 #[allow(deprecated)]
191 ImmutableImage::with_mipmaps(
192 device,
193 dimensions,
194 format,
195 MipmapsCount::One,
196 queue_families,
197 )
198 }
199
200 #[deprecated(note = "use ImmutableImage::uninitialized instead")]
201 #[inline]
with_mipmaps<'a, I, M>( device: Arc<Device>, dimensions: ImageDimensions, format: Format, mipmaps: M, queue_families: I, ) -> Result<Arc<ImmutableImage>, ImageCreationError> where I: IntoIterator<Item = QueueFamily<'a>>, M: Into<MipmapsCount>,202 pub fn with_mipmaps<'a, I, M>(
203 device: Arc<Device>,
204 dimensions: ImageDimensions,
205 format: Format,
206 mipmaps: M,
207 queue_families: I,
208 ) -> Result<Arc<ImmutableImage>, ImageCreationError>
209 where
210 I: IntoIterator<Item = QueueFamily<'a>>,
211 M: Into<MipmapsCount>,
212 {
213 let usage = ImageUsage {
214 transfer_source: true, // for blits
215 transfer_destination: true,
216 sampled: true,
217 ..ImageUsage::none()
218 };
219
220 let flags = ImageCreateFlags::none();
221
222 let (image, _) = ImmutableImage::uninitialized(
223 device,
224 dimensions,
225 format,
226 mipmaps,
227 usage,
228 flags,
229 ImageLayout::ShaderReadOnlyOptimal,
230 queue_families,
231 )?;
232 image.initialized.store(true, Ordering::Relaxed); // Allow uninitialized access for backwards compatibility
233 Ok(image)
234 }
235
236 /// Builds an uninitialized immutable image.
237 ///
238 /// Returns two things: the image, and a special access that should be used for the initial upload to the image.
uninitialized<'a, I, M>( device: Arc<Device>, dimensions: ImageDimensions, format: Format, mipmaps: M, usage: ImageUsage, flags: ImageCreateFlags, layout: ImageLayout, queue_families: I, ) -> Result<(Arc<ImmutableImage>, ImmutableImageInitialization), ImageCreationError> where I: IntoIterator<Item = QueueFamily<'a>>, M: Into<MipmapsCount>,239 pub fn uninitialized<'a, I, M>(
240 device: Arc<Device>,
241 dimensions: ImageDimensions,
242 format: Format,
243 mipmaps: M,
244 usage: ImageUsage,
245 flags: ImageCreateFlags,
246 layout: ImageLayout,
247 queue_families: I,
248 ) -> Result<(Arc<ImmutableImage>, ImmutableImageInitialization), ImageCreationError>
249 where
250 I: IntoIterator<Item = QueueFamily<'a>>,
251 M: Into<MipmapsCount>,
252 {
253 let queue_families = queue_families
254 .into_iter()
255 .map(|f| f.id())
256 .collect::<SmallVec<[u32; 4]>>();
257
258 let (image, mem_reqs) = unsafe {
259 let sharing = if queue_families.len() >= 2 {
260 Sharing::Concurrent(queue_families.iter().cloned())
261 } else {
262 Sharing::Exclusive
263 };
264
265 UnsafeImage::new(
266 device.clone(),
267 usage,
268 format,
269 flags,
270 dimensions,
271 SampleCount::Sample1,
272 mipmaps,
273 sharing,
274 false,
275 false,
276 )?
277 };
278
279 let memory = MemoryPool::alloc_from_requirements(
280 &Device::standard_pool(&device),
281 &mem_reqs,
282 AllocLayout::Optimal,
283 MappingRequirement::DoNotMap,
284 DedicatedAlloc::Image(&image),
285 |t| {
286 if t.is_device_local() {
287 AllocFromRequirementsFilter::Preferred
288 } else {
289 AllocFromRequirementsFilter::Allowed
290 }
291 },
292 )?;
293 debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
294 unsafe {
295 image.bind_memory(memory.memory(), memory.offset())?;
296 }
297
298 let image = Arc::new(ImmutableImage {
299 image,
300 memory,
301 dimensions,
302 format,
303 initialized: AtomicBool::new(false),
304 layout,
305 });
306
307 let init = ImmutableImageInitialization {
308 image: image.clone(),
309 used: AtomicBool::new(false),
310 mip_levels_access: 0..image.mipmap_levels(),
311 layer_levels_access: 0..image.dimensions().array_layers(),
312 };
313
314 Ok((image, init))
315 }
316
317 /// Construct an ImmutableImage from the contents of `iter`.
318 #[inline]
from_iter<Px, I>( iter: I, dimensions: ImageDimensions, mipmaps: MipmapsCount, format: Format, queue: Arc<Queue>, ) -> Result< ( Arc<Self>, CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>, ), ImageCreationError, > where Px: Pixel + Send + Sync + Clone + 'static, I: ExactSizeIterator<Item = Px>,319 pub fn from_iter<Px, I>(
320 iter: I,
321 dimensions: ImageDimensions,
322 mipmaps: MipmapsCount,
323 format: Format,
324 queue: Arc<Queue>,
325 ) -> Result<
326 (
327 Arc<Self>,
328 CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>,
329 ),
330 ImageCreationError,
331 >
332 where
333 Px: Pixel + Send + Sync + Clone + 'static,
334 I: ExactSizeIterator<Item = Px>,
335 {
336 let source = CpuAccessibleBuffer::from_iter(
337 queue.device().clone(),
338 BufferUsage::transfer_source(),
339 false,
340 iter,
341 )?;
342 ImmutableImage::from_buffer(source, dimensions, mipmaps, format, queue)
343 }
344
345 /// Construct an ImmutableImage containing a copy of the data in `source`.
from_buffer<B, Px>( source: B, dimensions: ImageDimensions, mipmaps: MipmapsCount, format: Format, queue: Arc<Queue>, ) -> Result< ( Arc<Self>, CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>, ), ImageCreationError, > where B: BufferAccess + TypedBufferAccess<Content = [Px]> + 'static + Clone + Send + Sync, Px: Pixel + Send + Sync + Clone + 'static,346 pub fn from_buffer<B, Px>(
347 source: B,
348 dimensions: ImageDimensions,
349 mipmaps: MipmapsCount,
350 format: Format,
351 queue: Arc<Queue>,
352 ) -> Result<
353 (
354 Arc<Self>,
355 CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>,
356 ),
357 ImageCreationError,
358 >
359 where
360 B: BufferAccess + TypedBufferAccess<Content = [Px]> + 'static + Clone + Send + Sync,
361 Px: Pixel + Send + Sync + Clone + 'static,
362 {
363 let need_to_generate_mipmaps = has_mipmaps(mipmaps);
364 let usage = ImageUsage {
365 transfer_destination: true,
366 transfer_source: need_to_generate_mipmaps,
367 sampled: true,
368 ..ImageUsage::none()
369 };
370 let flags = ImageCreateFlags::none();
371 let layout = ImageLayout::ShaderReadOnlyOptimal;
372
373 let (image, initializer) = ImmutableImage::uninitialized(
374 source.device().clone(),
375 dimensions,
376 format,
377 mipmaps,
378 usage,
379 flags,
380 layout,
381 source.device().active_queue_families(),
382 )?;
383
384 let init = SubImage::new(
385 Arc::new(initializer),
386 0,
387 1,
388 0,
389 1,
390 ImageLayout::ShaderReadOnlyOptimal,
391 );
392
393 let mut cbb = AutoCommandBufferBuilder::primary(
394 source.device().clone(),
395 queue.family(),
396 CommandBufferUsage::MultipleSubmit,
397 )?;
398 cbb.copy_buffer_to_image_dimensions(
399 source,
400 init,
401 [0, 0, 0],
402 dimensions.width_height_depth(),
403 0,
404 dimensions.array_layers(),
405 0,
406 )
407 .unwrap();
408
409 if need_to_generate_mipmaps {
410 generate_mipmaps(
411 &mut cbb,
412 image.clone(),
413 image.dimensions,
414 ImageLayout::ShaderReadOnlyOptimal,
415 );
416 }
417
418 let cb = cbb.build().unwrap();
419
420 let future = match cb.execute(queue) {
421 Ok(f) => f,
422 Err(e) => unreachable!("{:?}", e),
423 };
424
425 image.initialized.store(true, Ordering::Relaxed);
426
427 Ok((image, future))
428 }
429 }
430
431 impl<A> ImmutableImage<A> {
432 /// Returns the dimensions of the image.
433 #[inline]
dimensions(&self) -> ImageDimensions434 pub fn dimensions(&self) -> ImageDimensions {
435 self.dimensions
436 }
437
438 /// Returns the number of mipmap levels of the image.
439 #[inline]
mipmap_levels(&self) -> u32440 pub fn mipmap_levels(&self) -> u32 {
441 self.image.mipmap_levels()
442 }
443 }
444
445 unsafe impl<A> ImageAccess for ImmutableImage<A> {
446 #[inline]
inner(&self) -> ImageInner447 fn inner(&self) -> ImageInner {
448 ImageInner {
449 image: &self.image,
450 first_layer: 0,
451 num_layers: self.image.dimensions().array_layers() as usize,
452 first_mipmap_level: 0,
453 num_mipmap_levels: self.image.mipmap_levels() as usize,
454 }
455 }
456
457 #[inline]
initial_layout_requirement(&self) -> ImageLayout458 fn initial_layout_requirement(&self) -> ImageLayout {
459 self.layout
460 }
461
462 #[inline]
final_layout_requirement(&self) -> ImageLayout463 fn final_layout_requirement(&self) -> ImageLayout {
464 self.layout
465 }
466
467 #[inline]
descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>468 fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
469 Some(ImageDescriptorLayouts {
470 storage_image: self.layout,
471 combined_image_sampler: self.layout,
472 sampled_image: self.layout,
473 input_attachment: self.layout,
474 })
475 }
476
477 #[inline]
conflict_key(&self) -> u64478 fn conflict_key(&self) -> u64 {
479 self.image.key()
480 }
481
482 #[inline]
try_gpu_lock( &self, exclusive_access: bool, uninitialized_safe: bool, expected_layout: ImageLayout, ) -> Result<(), AccessError>483 fn try_gpu_lock(
484 &self,
485 exclusive_access: bool,
486 uninitialized_safe: bool,
487 expected_layout: ImageLayout,
488 ) -> Result<(), AccessError> {
489 if expected_layout != self.layout && expected_layout != ImageLayout::Undefined {
490 return Err(AccessError::UnexpectedImageLayout {
491 requested: expected_layout,
492 allowed: self.layout,
493 });
494 }
495
496 if exclusive_access {
497 return Err(AccessError::ExclusiveDenied);
498 }
499
500 if !self.initialized.load(Ordering::Relaxed) {
501 return Err(AccessError::BufferNotInitialized);
502 }
503
504 Ok(())
505 }
506
507 #[inline]
increase_gpu_lock(&self)508 unsafe fn increase_gpu_lock(&self) {}
509
510 #[inline]
unlock(&self, new_layout: Option<ImageLayout>)511 unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
512 debug_assert!(new_layout.is_none());
513 }
514
515 #[inline]
current_miplevels_access(&self) -> std::ops::Range<u32>516 fn current_miplevels_access(&self) -> std::ops::Range<u32> {
517 0..self.mipmap_levels()
518 }
519
520 #[inline]
current_layer_levels_access(&self) -> std::ops::Range<u32>521 fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
522 0..self.dimensions().array_layers()
523 }
524 }
525
526 unsafe impl<P, A> ImageContent<P> for ImmutableImage<A> {
527 #[inline]
matches_format(&self) -> bool528 fn matches_format(&self) -> bool {
529 true // FIXME:
530 }
531 }
532
533 unsafe impl ImageAccess for SubImage {
534 #[inline]
inner(&self) -> ImageInner535 fn inner(&self) -> ImageInner {
536 self.image.inner()
537 }
538
539 #[inline]
initial_layout_requirement(&self) -> ImageLayout540 fn initial_layout_requirement(&self) -> ImageLayout {
541 self.image.initial_layout_requirement()
542 }
543
544 #[inline]
final_layout_requirement(&self) -> ImageLayout545 fn final_layout_requirement(&self) -> ImageLayout {
546 self.image.final_layout_requirement()
547 }
548
549 #[inline]
descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>550 fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
551 None
552 }
553
current_miplevels_access(&self) -> std::ops::Range<u32>554 fn current_miplevels_access(&self) -> std::ops::Range<u32> {
555 self.mip_levels_access.clone()
556 }
557
current_layer_levels_access(&self) -> std::ops::Range<u32>558 fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
559 self.layer_levels_access.clone()
560 }
561
562 #[inline]
conflict_key(&self) -> u64563 fn conflict_key(&self) -> u64 {
564 self.image.conflict_key()
565 }
566
567 #[inline]
try_gpu_lock( &self, exclusive_access: bool, uninitialized_safe: bool, expected_layout: ImageLayout, ) -> Result<(), AccessError>568 fn try_gpu_lock(
569 &self,
570 exclusive_access: bool,
571 uninitialized_safe: bool,
572 expected_layout: ImageLayout,
573 ) -> Result<(), AccessError> {
574 if expected_layout != self.layout && expected_layout != ImageLayout::Undefined {
575 return Err(AccessError::UnexpectedImageLayout {
576 requested: expected_layout,
577 allowed: self.layout,
578 });
579 }
580
581 Ok(())
582 }
583
584 #[inline]
increase_gpu_lock(&self)585 unsafe fn increase_gpu_lock(&self) {
586 self.image.increase_gpu_lock()
587 }
588
589 #[inline]
unlock(&self, new_layout: Option<ImageLayout>)590 unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
591 self.image.unlock(new_layout)
592 }
593 }
594
595 impl<A> PartialEq for ImmutableImage<A> {
596 #[inline]
eq(&self, other: &Self) -> bool597 fn eq(&self, other: &Self) -> bool {
598 ImageAccess::inner(self) == ImageAccess::inner(other)
599 }
600 }
601
602 impl<A> Eq for ImmutableImage<A> {}
603
604 impl<A> Hash for ImmutableImage<A> {
605 #[inline]
hash<H: Hasher>(&self, state: &mut H)606 fn hash<H: Hasher>(&self, state: &mut H) {
607 ImageAccess::inner(self).hash(state);
608 }
609 }
610
611 unsafe impl<A> ImageAccess for ImmutableImageInitialization<A> {
612 #[inline]
inner(&self) -> ImageInner613 fn inner(&self) -> ImageInner {
614 ImageAccess::inner(&self.image)
615 }
616
617 #[inline]
initial_layout_requirement(&self) -> ImageLayout618 fn initial_layout_requirement(&self) -> ImageLayout {
619 ImageLayout::Undefined
620 }
621
622 #[inline]
final_layout_requirement(&self) -> ImageLayout623 fn final_layout_requirement(&self) -> ImageLayout {
624 self.image.layout
625 }
626
627 #[inline]
descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>628 fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
629 None
630 }
631
632 #[inline]
conflict_key(&self) -> u64633 fn conflict_key(&self) -> u64 {
634 self.image.image.key()
635 }
636
637 #[inline]
try_gpu_lock( &self, _: bool, uninitialized_safe: bool, expected_layout: ImageLayout, ) -> Result<(), AccessError>638 fn try_gpu_lock(
639 &self,
640 _: bool,
641 uninitialized_safe: bool,
642 expected_layout: ImageLayout,
643 ) -> Result<(), AccessError> {
644 if expected_layout != ImageLayout::Undefined {
645 return Err(AccessError::UnexpectedImageLayout {
646 requested: expected_layout,
647 allowed: ImageLayout::Undefined,
648 });
649 }
650
651 if self.image.initialized.load(Ordering::Relaxed) {
652 return Err(AccessError::AlreadyInUse);
653 }
654
655 // FIXME: Mipmapped textures require multiple writes to initialize
656 if !self
657 .used
658 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
659 .unwrap_or_else(|e| e)
660 {
661 Ok(())
662 } else {
663 Err(AccessError::AlreadyInUse)
664 }
665 }
666
667 #[inline]
increase_gpu_lock(&self)668 unsafe fn increase_gpu_lock(&self) {
669 debug_assert!(self.used.load(Ordering::Relaxed));
670 }
671
672 #[inline]
unlock(&self, new_layout: Option<ImageLayout>)673 unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
674 assert_eq!(new_layout, Some(self.image.layout));
675 self.image.initialized.store(true, Ordering::Relaxed);
676 }
677
678 #[inline]
current_miplevels_access(&self) -> std::ops::Range<u32>679 fn current_miplevels_access(&self) -> std::ops::Range<u32> {
680 self.mip_levels_access.clone()
681 }
682
683 #[inline]
current_layer_levels_access(&self) -> std::ops::Range<u32>684 fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
685 self.layer_levels_access.clone()
686 }
687 }
688
689 impl<A> PartialEq for ImmutableImageInitialization<A> {
690 #[inline]
eq(&self, other: &Self) -> bool691 fn eq(&self, other: &Self) -> bool {
692 ImageAccess::inner(self) == ImageAccess::inner(other)
693 }
694 }
695
696 impl<A> Eq for ImmutableImageInitialization<A> {}
697
698 impl<A> Hash for ImmutableImageInitialization<A> {
699 #[inline]
hash<H: Hasher>(&self, state: &mut H)700 fn hash<H: Hasher>(&self, state: &mut H) {
701 ImageAccess::inner(self).hash(state);
702 }
703 }
704