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 super::{
11     sys::{Image, ImageMemory, RawImage},
12     traits::ImageContent,
13     ImageAccess, ImageAspects, ImageDescriptorLayouts, ImageError, ImageInner, ImageLayout,
14     ImageUsage, SampleCount,
15 };
16 use crate::{
17     device::{Device, DeviceOwned},
18     format::Format,
19     image::{sys::ImageCreateInfo, ImageCreateFlags, ImageDimensions, ImageFormatInfo},
20     memory::{
21         allocator::{
22             AllocationCreateInfo, AllocationType, MemoryAllocatePreference, MemoryAllocator,
23             MemoryUsage,
24         },
25         is_aligned, DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType,
26         ExternalMemoryHandleTypes,
27     },
28     DeviceSize,
29 };
30 use std::{
31     fs::File,
32     hash::{Hash, Hasher},
33     sync::{
34         atomic::{AtomicBool, Ordering},
35         Arc,
36     },
37 };
38 
39 /// ImageAccess whose purpose is to be used as a framebuffer attachment.
40 ///
41 /// The image is always two-dimensional and has only one mipmap, but it can have any kind of
42 /// format. Trying to use a format that the backend doesn't support for rendering will result in
43 /// an error being returned when creating the image. Once you have an `AttachmentImage`, you are
44 /// guaranteed that you will be able to draw on it.
45 ///
46 /// The template parameter of `AttachmentImage` is a type that describes the format of the image.
47 ///
48 /// # Regular vs transient
49 ///
50 /// Calling `AttachmentImage::new` will create a regular image, while calling
51 /// `AttachmentImage::transient` will create a *transient* image. Transient image are only
52 /// relevant for images that serve as attachments, so `AttachmentImage` is the only type of
53 /// image in vulkano that provides a shortcut for this.
54 ///
55 /// A transient image is a special kind of image whose content is undefined outside of render
56 /// passes. Once you finish drawing, reading from it will returned undefined data (which can be
57 /// either valid or garbage, depending on the implementation).
58 ///
59 /// This gives a hint to the Vulkan implementation that it is possible for the image's content to
60 /// live exclusively in some cache memory, and that no real memory has to be allocated for it.
61 ///
62 /// In other words, if you are going to read from the image after drawing to it, use a regular
63 /// image. If you don't need to read from it (for example if it's some kind of intermediary color,
64 /// or a depth buffer that is only used once) then use a transient image as it may improve
65 /// performance.
66 ///
67 // TODO: forbid reading transient images outside render passes?
68 #[derive(Debug)]
69 pub struct AttachmentImage {
70     inner: Arc<Image>,
71 
72     // Layout to use when the image is used as a framebuffer attachment.
73     // Must be either "depth-stencil optimal" or "color optimal".
74     attachment_layout: ImageLayout,
75 
76     // If true, then the image is in the layout of `attachment_layout` (above). If false, then it
77     // is still `Undefined`.
78     layout_initialized: AtomicBool,
79 }
80 
81 impl AttachmentImage {
82     /// Creates a new image with the given dimensions and format.
83     ///
84     /// Returns an error if the dimensions are too large or if the backend doesn't support this
85     /// format as a framebuffer attachment.
86     #[inline]
new( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>87     pub fn new(
88         allocator: &(impl MemoryAllocator + ?Sized),
89         dimensions: [u32; 2],
90         format: Format,
91     ) -> Result<Arc<AttachmentImage>, ImageError> {
92         AttachmentImage::new_impl(
93             allocator,
94             dimensions,
95             1,
96             format,
97             ImageUsage::empty(),
98             SampleCount::Sample1,
99         )
100     }
101 
102     /// Same as `new`, but creates an image that can be used as an input attachment.
103     ///
104     /// > **Note**: This function is just a convenient shortcut for `with_usage`.
105     #[inline]
input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>106     pub fn input_attachment(
107         allocator: &(impl MemoryAllocator + ?Sized),
108         dimensions: [u32; 2],
109         format: Format,
110     ) -> Result<Arc<AttachmentImage>, ImageError> {
111         let base_usage = ImageUsage::INPUT_ATTACHMENT;
112 
113         AttachmentImage::new_impl(
114             allocator,
115             dimensions,
116             1,
117             format,
118             base_usage,
119             SampleCount::Sample1,
120         )
121     }
122 
123     /// Same as `new`, but creates a multisampled image.
124     ///
125     /// > **Note**: You can also use this function and pass `1` for the number of samples if you
126     /// > want a regular image.
127     #[inline]
multisampled( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>128     pub fn multisampled(
129         allocator: &(impl MemoryAllocator + ?Sized),
130         dimensions: [u32; 2],
131         samples: SampleCount,
132         format: Format,
133     ) -> Result<Arc<AttachmentImage>, ImageError> {
134         AttachmentImage::new_impl(
135             allocator,
136             dimensions,
137             1,
138             format,
139             ImageUsage::empty(),
140             samples,
141         )
142     }
143 
144     /// Same as `multisampled`, but creates an image that can be used as an input attachment.
145     ///
146     /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
147     #[inline]
multisampled_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>148     pub fn multisampled_input_attachment(
149         allocator: &(impl MemoryAllocator + ?Sized),
150         dimensions: [u32; 2],
151         samples: SampleCount,
152         format: Format,
153     ) -> Result<Arc<AttachmentImage>, ImageError> {
154         let base_usage = ImageUsage::INPUT_ATTACHMENT;
155 
156         AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
157     }
158 
159     /// Same as `new`, but lets you specify additional usages.
160     ///
161     /// The `color_attachment` or `depth_stencil_attachment` usages are automatically added based
162     /// on the format of the usage. Therefore the `usage` parameter allows you specify usages in
163     /// addition to these two.
164     #[inline]
with_usage( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, usage: ImageUsage, ) -> Result<Arc<AttachmentImage>, ImageError>165     pub fn with_usage(
166         allocator: &(impl MemoryAllocator + ?Sized),
167         dimensions: [u32; 2],
168         format: Format,
169         usage: ImageUsage,
170     ) -> Result<Arc<AttachmentImage>, ImageError> {
171         AttachmentImage::new_impl(
172             allocator,
173             dimensions,
174             1,
175             format,
176             usage,
177             SampleCount::Sample1,
178         )
179     }
180 
181     /// Same as `with_usage`, but creates a multisampled image.
182     ///
183     /// > **Note**: You can also use this function and pass `1` for the number of samples if you
184     /// > want a regular image.
185     #[inline]
multisampled_with_usage( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, usage: ImageUsage, ) -> Result<Arc<AttachmentImage>, ImageError>186     pub fn multisampled_with_usage(
187         allocator: &(impl MemoryAllocator + ?Sized),
188         dimensions: [u32; 2],
189         samples: SampleCount,
190         format: Format,
191         usage: ImageUsage,
192     ) -> Result<Arc<AttachmentImage>, ImageError> {
193         AttachmentImage::new_impl(allocator, dimensions, 1, format, usage, samples)
194     }
195 
196     /// Same as `multisampled_with_usage`, but creates an image with multiple layers.
197     ///
198     /// > **Note**: You can also use this function and pass `1` for the number of layers if you
199     /// > want a regular image.
200     #[inline]
multisampled_with_usage_with_layers( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], array_layers: u32, samples: SampleCount, format: Format, usage: ImageUsage, ) -> Result<Arc<AttachmentImage>, ImageError>201     pub fn multisampled_with_usage_with_layers(
202         allocator: &(impl MemoryAllocator + ?Sized),
203         dimensions: [u32; 2],
204         array_layers: u32,
205         samples: SampleCount,
206         format: Format,
207         usage: ImageUsage,
208     ) -> Result<Arc<AttachmentImage>, ImageError> {
209         AttachmentImage::new_impl(allocator, dimensions, array_layers, format, usage, samples)
210     }
211 
212     /// Same as `new`, except that the image can later be sampled.
213     ///
214     /// > **Note**: This function is just a convenient shortcut for `with_usage`.
215     #[inline]
sampled( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>216     pub fn sampled(
217         allocator: &(impl MemoryAllocator + ?Sized),
218         dimensions: [u32; 2],
219         format: Format,
220     ) -> Result<Arc<AttachmentImage>, ImageError> {
221         let base_usage = ImageUsage::SAMPLED;
222 
223         AttachmentImage::new_impl(
224             allocator,
225             dimensions,
226             1,
227             format,
228             base_usage,
229             SampleCount::Sample1,
230         )
231     }
232 
233     /// Same as `sampled`, except that the image can be used as an input attachment.
234     ///
235     /// > **Note**: This function is just a convenient shortcut for `with_usage`.
236     #[inline]
sampled_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>237     pub fn sampled_input_attachment(
238         allocator: &(impl MemoryAllocator + ?Sized),
239         dimensions: [u32; 2],
240         format: Format,
241     ) -> Result<Arc<AttachmentImage>, ImageError> {
242         let base_usage = ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT;
243 
244         AttachmentImage::new_impl(
245             allocator,
246             dimensions,
247             1,
248             format,
249             base_usage,
250             SampleCount::Sample1,
251         )
252     }
253 
254     /// Same as `sampled`, but creates a multisampled image.
255     ///
256     /// > **Note**: You can also use this function and pass `1` for the number of samples if you
257     /// > want a regular image.
258     ///
259     /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
260     #[inline]
sampled_multisampled( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>261     pub fn sampled_multisampled(
262         allocator: &(impl MemoryAllocator + ?Sized),
263         dimensions: [u32; 2],
264         samples: SampleCount,
265         format: Format,
266     ) -> Result<Arc<AttachmentImage>, ImageError> {
267         let base_usage = ImageUsage::SAMPLED;
268 
269         AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
270     }
271 
272     /// Same as `sampled_multisampled`, but creates an image that can be used as an input
273     /// attachment.
274     ///
275     /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
276     #[inline]
sampled_multisampled_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>277     pub fn sampled_multisampled_input_attachment(
278         allocator: &(impl MemoryAllocator + ?Sized),
279         dimensions: [u32; 2],
280         samples: SampleCount,
281         format: Format,
282     ) -> Result<Arc<AttachmentImage>, ImageError> {
283         let base_usage = ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT;
284 
285         AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
286     }
287 
288     /// Same as `new`, except that the image will be transient.
289     ///
290     /// A transient image is special because its content is undefined outside of a render pass.
291     /// This means that the implementation has the possibility to not allocate any memory for it.
292     ///
293     /// > **Note**: This function is just a convenient shortcut for `with_usage`.
294     #[inline]
transient( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>295     pub fn transient(
296         allocator: &(impl MemoryAllocator + ?Sized),
297         dimensions: [u32; 2],
298         format: Format,
299     ) -> Result<Arc<AttachmentImage>, ImageError> {
300         let base_usage = ImageUsage::TRANSIENT_ATTACHMENT;
301 
302         AttachmentImage::new_impl(
303             allocator,
304             dimensions,
305             1,
306             format,
307             base_usage,
308             SampleCount::Sample1,
309         )
310     }
311 
312     /// Same as `transient`, except that the image can be used as an input attachment.
313     ///
314     /// > **Note**: This function is just a convenient shortcut for `with_usage`.
315     #[inline]
transient_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>316     pub fn transient_input_attachment(
317         allocator: &(impl MemoryAllocator + ?Sized),
318         dimensions: [u32; 2],
319         format: Format,
320     ) -> Result<Arc<AttachmentImage>, ImageError> {
321         let base_usage = ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::INPUT_ATTACHMENT;
322 
323         AttachmentImage::new_impl(
324             allocator,
325             dimensions,
326             1,
327             format,
328             base_usage,
329             SampleCount::Sample1,
330         )
331     }
332 
333     /// Same as `transient`, but creates a multisampled image.
334     ///
335     /// > **Note**: You can also use this function and pass `1` for the number of samples if you
336     /// > want a regular image.
337     ///
338     /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
339     #[inline]
transient_multisampled( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>340     pub fn transient_multisampled(
341         allocator: &(impl MemoryAllocator + ?Sized),
342         dimensions: [u32; 2],
343         samples: SampleCount,
344         format: Format,
345     ) -> Result<Arc<AttachmentImage>, ImageError> {
346         let base_usage = ImageUsage::TRANSIENT_ATTACHMENT;
347 
348         AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
349     }
350 
351     /// Same as `transient_multisampled`, but creates an image that can be used as an input
352     /// attachment.
353     ///
354     /// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
355     #[inline]
transient_multisampled_input_attachment( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], samples: SampleCount, format: Format, ) -> Result<Arc<AttachmentImage>, ImageError>356     pub fn transient_multisampled_input_attachment(
357         allocator: &(impl MemoryAllocator + ?Sized),
358         dimensions: [u32; 2],
359         samples: SampleCount,
360         format: Format,
361     ) -> Result<Arc<AttachmentImage>, ImageError> {
362         let base_usage = ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::INPUT_ATTACHMENT;
363 
364         AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
365     }
366 
367     // All constructors dispatch to this one.
new_impl( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], array_layers: u32, format: Format, mut usage: ImageUsage, samples: SampleCount, ) -> Result<Arc<AttachmentImage>, ImageError>368     fn new_impl(
369         allocator: &(impl MemoryAllocator + ?Sized),
370         dimensions: [u32; 2],
371         array_layers: u32,
372         format: Format,
373         mut usage: ImageUsage,
374         samples: SampleCount,
375     ) -> Result<Arc<AttachmentImage>, ImageError> {
376         let physical_device = allocator.device().physical_device();
377         let device_properties = physical_device.properties();
378 
379         if dimensions[0] > device_properties.max_framebuffer_height {
380             panic!("AttachmentImage height exceeds physical device's max_framebuffer_height");
381         }
382         if dimensions[1] > device_properties.max_framebuffer_width {
383             panic!("AttachmentImage width exceeds physical device's max_framebuffer_width");
384         }
385         if array_layers > device_properties.max_framebuffer_layers {
386             panic!("AttachmentImage layer count exceeds physical device's max_framebuffer_layers");
387         }
388 
389         let aspects = format.aspects();
390         let is_depth_stencil = aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL);
391 
392         if is_depth_stencil {
393             usage -= ImageUsage::COLOR_ATTACHMENT;
394             usage |= ImageUsage::DEPTH_STENCIL_ATTACHMENT;
395         } else {
396             usage |= ImageUsage::COLOR_ATTACHMENT;
397             usage -= ImageUsage::DEPTH_STENCIL_ATTACHMENT;
398         }
399 
400         if format.compression().is_some() {
401             panic!() // TODO: message?
402         }
403 
404         let raw_image = RawImage::new(
405             allocator.device().clone(),
406             ImageCreateInfo {
407                 dimensions: ImageDimensions::Dim2d {
408                     width: dimensions[0],
409                     height: dimensions[1],
410                     array_layers,
411                 },
412                 format: Some(format),
413                 samples,
414                 usage,
415                 ..Default::default()
416             },
417         )?;
418         let requirements = raw_image.memory_requirements()[0];
419         let res = unsafe {
420             allocator.allocate_unchecked(
421                 requirements,
422                 AllocationType::NonLinear,
423                 AllocationCreateInfo {
424                     usage: MemoryUsage::DeviceOnly,
425                     allocate_preference: MemoryAllocatePreference::Unknown,
426                     _ne: crate::NonExhaustive(()),
427                 },
428                 Some(DedicatedAllocation::Image(&raw_image)),
429             )
430         };
431 
432         match res {
433             Ok(alloc) => {
434                 debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
435                 debug_assert!(alloc.size() == requirements.layout.size());
436 
437                 let inner = Arc::new(
438                     unsafe { raw_image.bind_memory_unchecked([alloc]) }
439                         .map_err(|(err, _, _)| err)?,
440                 );
441 
442                 Ok(Arc::new(AttachmentImage {
443                     inner,
444                     attachment_layout: if is_depth_stencil {
445                         ImageLayout::DepthStencilAttachmentOptimal
446                     } else {
447                         ImageLayout::ColorAttachmentOptimal
448                     },
449                     layout_initialized: AtomicBool::new(false),
450                 }))
451             }
452             Err(err) => Err(err.into()),
453         }
454     }
455 
new_with_exportable_fd( allocator: &(impl MemoryAllocator + ?Sized), dimensions: [u32; 2], array_layers: u32, format: Format, mut usage: ImageUsage, samples: SampleCount, ) -> Result<Arc<AttachmentImage>, ImageError>456     pub fn new_with_exportable_fd(
457         allocator: &(impl MemoryAllocator + ?Sized),
458         dimensions: [u32; 2],
459         array_layers: u32,
460         format: Format,
461         mut usage: ImageUsage,
462         samples: SampleCount,
463     ) -> Result<Arc<AttachmentImage>, ImageError> {
464         let physical_device = allocator.device().physical_device();
465         let device_properties = physical_device.properties();
466 
467         if dimensions[0] > device_properties.max_framebuffer_height {
468             panic!("AttachmentImage height exceeds physical device's max_framebuffer_height");
469         }
470         if dimensions[1] > device_properties.max_framebuffer_width {
471             panic!("AttachmentImage width exceeds physical device's max_framebuffer_width");
472         }
473         if array_layers > device_properties.max_framebuffer_layers {
474             panic!("AttachmentImage layer count exceeds physical device's max_framebuffer_layers");
475         }
476 
477         let aspects = format.aspects();
478         let is_depth_stencil = aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL);
479 
480         if is_depth_stencil {
481             usage -= ImageUsage::COLOR_ATTACHMENT;
482             usage |= ImageUsage::DEPTH_STENCIL_ATTACHMENT;
483         } else {
484             usage |= ImageUsage::COLOR_ATTACHMENT;
485             usage -= ImageUsage::DEPTH_STENCIL_ATTACHMENT;
486         }
487 
488         let external_memory_properties = allocator
489             .device()
490             .physical_device()
491             .image_format_properties(ImageFormatInfo {
492                 flags: ImageCreateFlags::MUTABLE_FORMAT,
493                 format: Some(format),
494                 usage,
495                 external_memory_handle_type: Some(ExternalMemoryHandleType::OpaqueFd),
496                 ..Default::default()
497             })
498             .unwrap()
499             .unwrap()
500             .external_memory_properties;
501         // VUID-VkExportMemoryAllocateInfo-handleTypes-00656
502         assert!(external_memory_properties.exportable);
503 
504         // VUID-VkMemoryAllocateInfo-pNext-00639
505         // Guaranteed because we always create a dedicated allocation
506 
507         let external_memory_handle_types = ExternalMemoryHandleTypes::OPAQUE_FD;
508         let raw_image = RawImage::new(
509             allocator.device().clone(),
510             ImageCreateInfo {
511                 flags: ImageCreateFlags::MUTABLE_FORMAT,
512                 dimensions: ImageDimensions::Dim2d {
513                     width: dimensions[0],
514                     height: dimensions[1],
515                     array_layers,
516                 },
517                 format: Some(format),
518                 samples,
519                 usage,
520                 external_memory_handle_types,
521                 ..Default::default()
522             },
523         )?;
524         let requirements = raw_image.memory_requirements()[0];
525         let memory_type_index = allocator
526             .find_memory_type_index(
527                 requirements.memory_type_bits,
528                 MemoryUsage::DeviceOnly.into(),
529             )
530             .expect("failed to find a suitable memory type");
531 
532         match unsafe {
533             allocator.allocate_dedicated_unchecked(
534                 memory_type_index,
535                 requirements.layout.size(),
536                 Some(DedicatedAllocation::Image(&raw_image)),
537                 external_memory_handle_types,
538             )
539         } {
540             Ok(alloc) => {
541                 debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
542                 debug_assert!(alloc.size() == requirements.layout.size());
543 
544                 let inner = Arc::new(unsafe {
545                     raw_image
546                         .bind_memory_unchecked([alloc])
547                         .map_err(|(err, _, _)| err)?
548                 });
549 
550                 Ok(Arc::new(AttachmentImage {
551                     inner,
552                     attachment_layout: if is_depth_stencil {
553                         ImageLayout::DepthStencilAttachmentOptimal
554                     } else {
555                         ImageLayout::ColorAttachmentOptimal
556                     },
557                     layout_initialized: AtomicBool::new(false),
558                 }))
559             }
560             Err(err) => Err(err.into()),
561         }
562     }
563 
564     /// Exports posix file descriptor for the allocated memory.
565     /// Requires `khr_external_memory_fd` and `khr_external_memory` extensions to be loaded.
566     #[inline]
export_posix_fd(&self) -> Result<File, DeviceMemoryError>567     pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
568         let allocation = match self.inner.memory() {
569             ImageMemory::Normal(a) => &a[0],
570             _ => unreachable!(),
571         };
572 
573         allocation
574             .device_memory()
575             .export_fd(ExternalMemoryHandleType::OpaqueFd)
576     }
577 
578     /// Return the size of the allocated memory (used e.g. with cuda).
579     #[inline]
mem_size(&self) -> DeviceSize580     pub fn mem_size(&self) -> DeviceSize {
581         let allocation = match self.inner.memory() {
582             ImageMemory::Normal(a) => &a[0],
583             _ => unreachable!(),
584         };
585 
586         allocation.device_memory().allocation_size()
587     }
588 }
589 
590 unsafe impl ImageAccess for AttachmentImage {
591     #[inline]
inner(&self) -> ImageInner<'_>592     fn inner(&self) -> ImageInner<'_> {
593         ImageInner {
594             image: &self.inner,
595             first_layer: 0,
596             num_layers: self.inner.dimensions().array_layers(),
597             first_mipmap_level: 0,
598             num_mipmap_levels: 1,
599         }
600     }
601 
602     #[inline]
initial_layout_requirement(&self) -> ImageLayout603     fn initial_layout_requirement(&self) -> ImageLayout {
604         self.attachment_layout
605     }
606 
607     #[inline]
final_layout_requirement(&self) -> ImageLayout608     fn final_layout_requirement(&self) -> ImageLayout {
609         self.attachment_layout
610     }
611 
612     #[inline]
descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>613     fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
614         Some(ImageDescriptorLayouts {
615             storage_image: ImageLayout::General,
616             combined_image_sampler: ImageLayout::ShaderReadOnlyOptimal,
617             sampled_image: ImageLayout::ShaderReadOnlyOptimal,
618             input_attachment: ImageLayout::ShaderReadOnlyOptimal,
619         })
620     }
621 
622     #[inline]
layout_initialized(&self)623     unsafe fn layout_initialized(&self) {
624         self.layout_initialized.store(true, Ordering::SeqCst);
625     }
626 
627     #[inline]
is_layout_initialized(&self) -> bool628     fn is_layout_initialized(&self) -> bool {
629         self.layout_initialized.load(Ordering::SeqCst)
630     }
631 }
632 
633 unsafe impl DeviceOwned for AttachmentImage {
634     #[inline]
device(&self) -> &Arc<Device>635     fn device(&self) -> &Arc<Device> {
636         self.inner.device()
637     }
638 }
639 
640 unsafe impl<P> ImageContent<P> for AttachmentImage {
matches_format(&self) -> bool641     fn matches_format(&self) -> bool {
642         true // FIXME:
643     }
644 }
645 
646 impl PartialEq for AttachmentImage {
647     #[inline]
eq(&self, other: &Self) -> bool648     fn eq(&self, other: &Self) -> bool {
649         self.inner() == other.inner()
650     }
651 }
652 
653 impl Eq for AttachmentImage {}
654 
655 impl Hash for AttachmentImage {
hash<H: Hasher>(&self, state: &mut H)656     fn hash<H: Hasher>(&self, state: &mut H) {
657         self.inner().hash(state);
658     }
659 }
660 
661 #[cfg(test)]
662 mod tests {
663     use super::*;
664     use crate::memory::allocator::StandardMemoryAllocator;
665 
666     #[test]
create_regular()667     fn create_regular() {
668         let (device, _) = gfx_dev_and_queue!();
669         let memory_allocator = StandardMemoryAllocator::new_default(device);
670         let _img =
671             AttachmentImage::new(&memory_allocator, [32, 32], Format::R8G8B8A8_UNORM).unwrap();
672     }
673 
674     #[test]
create_transient()675     fn create_transient() {
676         let (device, _) = gfx_dev_and_queue!();
677         let memory_allocator = StandardMemoryAllocator::new_default(device);
678         let _img = AttachmentImage::transient(&memory_allocator, [32, 32], Format::R8G8B8A8_UNORM)
679             .unwrap();
680     }
681 
682     #[test]
d16_unorm_always_supported()683     fn d16_unorm_always_supported() {
684         let (device, _) = gfx_dev_and_queue!();
685         let memory_allocator = StandardMemoryAllocator::new_default(device);
686         let _img = AttachmentImage::new(&memory_allocator, [32, 32], Format::D16_UNORM).unwrap();
687     }
688 }
689