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 //! Image storage (1D, 2D, 3D, arrays, etc.) and image views.
11 //!
12 //! An *image* is a region of memory whose purpose is to store multi-dimensional data. Its
13 //! most common use is to store a 2D array of color pixels (in other words an *image* in
14 //! everyday language), but it can also be used to store arbitrary data.
15 //!
16 //! The advantage of using an image compared to a buffer is that the memory layout is optimized
17 //! for locality. When reading a specific pixel of an image, reading the nearby pixels is really
18 //! fast. Most implementations have hardware dedicated to reading from images if you access them
19 //! through a sampler.
20 //!
21 //! # Properties of an image
22 //!
23 //! # Images and image views
24 //!
25 //! There is a distinction between *images* and *image views*. As its name suggests, an image
26 //! view describes how the GPU must interpret the image.
27 //!
28 //! Transfer and memory operations operate on images themselves, while reading/writing an image
29 //! operates on image views. You can create multiple image views from the same image.
30 //!
31 //! # High-level wrappers
32 //!
33 //! In the vulkano library, an image is any object that implements the [`ImageAccess`] trait. You
34 //! can create a view by wrapping them in an [`ImageView`](crate::image::view::ImageView).
35 //!
36 //! Since the `ImageAccess` trait is low-level, you are encouraged to not implement it yourself but
37 //! instead use one of the provided implementations that are specialized depending on the way you
38 //! are going to use the image:
39 //!
40 //! - An `AttachmentImage` can be used when you want to draw to an image.
41 //! - An `ImmutableImage` stores data which never need be changed after the initial upload,
42 //!   like a texture.
43 //!
44 //! # Low-level information
45 //!
46 //! To be written.
47 //!
48 
49 pub use self::{
50     aspect::{ImageAspect, ImageAspects},
51     attachment::AttachmentImage,
52     immutable::ImmutableImage,
53     layout::{ImageDescriptorLayouts, ImageLayout},
54     storage::StorageImage,
55     swapchain::SwapchainImage,
56     sys::ImageError,
57     traits::{ImageAccess, ImageInner},
58     usage::ImageUsage,
59     view::{ImageViewAbstract, ImageViewType},
60 };
61 
62 #[cfg(target_os = "linux")]
63 pub use self::storage::SubresourceData;
64 
65 use crate::{
66     format::Format,
67     macros::{vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum},
68     memory::{ExternalMemoryHandleType, ExternalMemoryProperties},
69     DeviceSize,
70 };
71 use std::{cmp, ops::Range};
72 
73 mod aspect;
74 pub mod attachment; // TODO: make private
75 pub mod immutable; // TODO: make private
76 mod layout;
77 mod storage;
78 pub mod swapchain; // TODO: make private
79 pub mod sys;
80 pub mod traits;
81 mod usage;
82 pub mod view;
83 
84 vulkan_bitflags! {
85     #[non_exhaustive]
86 
87     /// Flags that can be set when creating a new image.
88     ImageCreateFlags = ImageCreateFlags(u32);
89 
90     /* TODO: enable
91     /// The image will be backed by sparse memory binding (through queue commands) instead of
92     /// regular binding (through [`bind_memory`]).
93     ///
94     /// The [`sparse_binding`] feature must be enabled on the device.
95     ///
96     /// [`bind_memory`]: sys::RawImage::bind_memory
97     /// [`sparse_binding`]: crate::device::Features::sparse_binding
98     SPARSE_BINDING = SPARSE_BINDING,*/
99 
100     /* TODO: enable
101     /// The image can be used without being fully resident in memory at the time of use.
102     ///
103     /// This requires the `sparse_binding` flag as well.
104     ///
105     /// Depending on the image dimensions, either the [`sparse_residency_image2_d`] or the
106     /// [`sparse_residency_image3_d`] feature must be enabled on the device.
107     /// For a multisampled image, the one of the features [`sparse_residency2_samples`],
108     /// [`sparse_residency4_samples`], [`sparse_residency8_samples`] or
109     /// [`sparse_residency16_samples`], corresponding to the sample count of the image, must
110     /// be enabled on the device.
111     ///
112     /// [`sparse_binding`]: crate::device::Features::sparse_binding
113     /// [`sparse_residency_image2_d`]: crate::device::Features::sparse_residency_image2_d
114     /// [`sparse_residency_image2_3`]: crate::device::Features::sparse_residency_image3_d
115     /// [`sparse_residency2_samples`]: crate::device::Features::sparse_residency2_samples
116     /// [`sparse_residency4_samples`]: crate::device::Features::sparse_residency4_samples
117     /// [`sparse_residency8_samples`]: crate::device::Features::sparse_residency8_samples
118     /// [`sparse_residency16_samples`]: crate::device::Features::sparse_residency16_samples
119     SPARSE_RESIDENCY = SPARSE_RESIDENCY,*/
120 
121     /* TODO: enable
122     /// The buffer's memory can alias with another image or a different part of the same image.
123     ///
124     /// This requires the `sparse_binding` flag as well.
125     ///
126     /// The [`sparse_residency_aliased`] feature must be enabled on the device.
127     ///
128     /// [`sparse_residency_aliased`]: crate::device::Features::sparse_residency_aliased
129     SPARSE_ALIASED = SPARSE_ALIASED,*/
130 
131     /// For non-multi-planar formats, whether an image view wrapping the image can have a
132     /// different format.
133     ///
134     /// For multi-planar formats, whether an image view wrapping the image can be created from a
135     /// single plane of the image.
136     MUTABLE_FORMAT = MUTABLE_FORMAT,
137 
138     /// For 2D images, whether an image view of type [`ImageViewType::Cube`] or
139     /// [`ImageViewType::CubeArray`] can be created from the image.
140     ///
141     /// [`ImageViewType::Cube`]: crate::image::view::ImageViewType::Cube
142     /// [`ImageViewType::CubeArray`]: crate::image::view::ImageViewType::CubeArray
143     CUBE_COMPATIBLE = CUBE_COMPATIBLE,
144 
145     /* TODO: enable
146     // TODO: document
147     ALIAS = ALIAS {
148         api_version: V1_1,
149         device_extensions: [khr_bind_memory2],
150     },*/
151 
152     /* TODO: enable
153     // TODO: document
154     SPLIT_INSTANCE_BIND_REGIONS = SPLIT_INSTANCE_BIND_REGIONS {
155         api_version: V1_1,
156         device_extensions: [khr_device_group],
157     },*/
158 
159     /// For 3D images, whether an image view of type [`ImageViewType::Dim2d`] or
160     /// [`ImageViewType::Dim2dArray`] can be created from the image.
161     ///
162     /// On [portability subset] devices, the [`image_view2_d_on3_d_image`] feature must be enabled
163     /// on the device.
164     ///
165     /// [`ImageViewType::Dim2d`]: crate::image::view::ImageViewType::Dim2d
166     /// [`ImageViewType::Dim2dArray`]: crate::image::view::ImageViewType::Dim2dArray
167     /// [portability subset]: crate::instance#portability-subset-devices-and-the-enumerate_portability-flag
168     /// [`image_view2_d_on3_d_image`]: crate::device::Features::image_view2_d_on3_d_image
169     ARRAY_2D_COMPATIBLE = TYPE_2D_ARRAY_COMPATIBLE {
170         api_version: V1_1,
171         device_extensions: [khr_maintenance1],
172     },
173 
174     /// For images with a compressed format, whether an image view with an uncompressed
175     /// format can be created from the image, where each texel in the view will correspond to a
176     /// compressed texel block in the image.
177     ///
178     /// Requires `mutable_format`.
179     BLOCK_TEXEL_VIEW_COMPATIBLE = BLOCK_TEXEL_VIEW_COMPATIBLE {
180         api_version: V1_1,
181         device_extensions: [khr_maintenance2],
182     },
183 
184     /* TODO: enable
185     // TODO: document
186     EXTENDED_USAGE = EXTENDED_USAGE {
187         api_version: V1_1,
188         device_extensions: [khr_maintenance2],
189     },*/
190 
191     /* TODO: enable
192     // TODO: document
193     PROTECTED = PROTECTED {
194         api_version: V1_1,
195     },*/
196 
197     /// For images with a multi-planar format, whether each plane will have its memory bound
198     /// separately, rather than having a single memory binding for the whole image.
199     DISJOINT = DISJOINT {
200         api_version: V1_1,
201         device_extensions: [khr_sampler_ycbcr_conversion],
202     },
203 
204     /* TODO: enable
205     // TODO: document
206     CORNER_SAMPLED = CORNER_SAMPLED_NV {
207         device_extensions: [nv_corner_sampled_image],
208     },*/
209 
210     /* TODO: enable
211     // TODO: document
212     SAMPLE_LOCATIONS_COMPATIBLE_DEPTH = SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_EXT {
213         device_extensions: [ext_sample_locations],
214     },*/
215 
216     /* TODO: enable
217     // TODO: document
218     SUBSAMPLED = SUBSAMPLED_EXT {
219         device_extensions: [ext_fragment_density_map],
220     },*/
221 
222     /* TODO: enable
223     // TODO: document
224     MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED = MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXT {
225         device_extensions: [ext_multisampled_render_to_single_sampled],
226     },*/
227 
228     /* TODO: enable
229     // TODO: document
230     TYPE_2D_VIEW_COMPATIBLE = TYPE_2D_VIEW_COMPATIBLE_EXT {
231         device_extensions: [ext_image_2d_view_of_3d],
232     },*/
233 
234     /* TODO: enable
235     // TODO: document
236     FRAGMENT_DENSITY_MAP_OFFSET = FRAGMENT_DENSITY_MAP_OFFSET_QCOM {
237         device_extensions: [qcom_fragment_density_map_offset],
238     },*/
239 }
240 
241 vulkan_bitflags_enum! {
242     #[non_exhaustive]
243 
244     /// A set of [`SampleCount`] values.
245     SampleCounts impl {
246         /// Returns the maximum sample count in `self`.
247         #[inline]
248         pub const fn max_count(self) -> SampleCount {
249             if self.intersects(SampleCounts::SAMPLE_64) {
250                 SampleCount::Sample64
251             } else if self.intersects(SampleCounts::SAMPLE_32) {
252                 SampleCount::Sample32
253             } else if self.intersects(SampleCounts::SAMPLE_16) {
254                 SampleCount::Sample16
255             } else if self.intersects(SampleCounts::SAMPLE_8) {
256                 SampleCount::Sample8
257             } else if self.intersects(SampleCounts::SAMPLE_4) {
258                 SampleCount::Sample4
259             } else if self.intersects(SampleCounts::SAMPLE_2) {
260                 SampleCount::Sample2
261             } else {
262                 SampleCount::Sample1
263             }
264         }
265     },
266 
267     /// The number of samples per texel of an image.
268     SampleCount,
269 
270     = SampleCountFlags(u32);
271 
272     /// 1 sample per texel.
273     SAMPLE_1, Sample1 = TYPE_1,
274 
275     /// 2 samples per texel.
276     SAMPLE_2, Sample2 = TYPE_2,
277 
278     /// 4 samples per texel.
279     SAMPLE_4, Sample4 = TYPE_4,
280 
281     /// 8 samples per texel.
282     SAMPLE_8, Sample8 = TYPE_8,
283 
284     /// 16 samples per texel.
285     SAMPLE_16, Sample16 = TYPE_16,
286 
287     /// 32 samples per texel.
288     SAMPLE_32, Sample32 = TYPE_32,
289 
290     /// 64 samples per texel.
291     SAMPLE_64, Sample64 = TYPE_64,
292 }
293 
294 impl From<SampleCount> for u32 {
295     #[inline]
from(value: SampleCount) -> Self296     fn from(value: SampleCount) -> Self {
297         value as u32
298     }
299 }
300 
301 impl TryFrom<u32> for SampleCount {
302     type Error = ();
303 
304     #[inline]
try_from(val: u32) -> Result<Self, Self::Error>305     fn try_from(val: u32) -> Result<Self, Self::Error> {
306         match val {
307             1 => Ok(Self::Sample1),
308             2 => Ok(Self::Sample2),
309             4 => Ok(Self::Sample4),
310             8 => Ok(Self::Sample8),
311             16 => Ok(Self::Sample16),
312             32 => Ok(Self::Sample32),
313             64 => Ok(Self::Sample64),
314             _ => Err(()),
315         }
316     }
317 }
318 
319 /// Specifies how many mipmaps must be allocated.
320 ///
321 /// Note that at least one mipmap must be allocated, to store the main level of the image.
322 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
323 pub enum MipmapsCount {
324     /// Allocates the number of mipmaps required to store all the mipmaps of the image where each
325     /// mipmap is half the dimensions of the previous level. Guaranteed to be always supported.
326     ///
327     /// Note that this is not necessarily the maximum number of mipmaps, as the Vulkan
328     /// implementation may report that it supports a greater value.
329     Log2,
330 
331     /// Allocate one mipmap (ie. just the main level). Always supported.
332     One,
333 
334     /// Allocate the given number of mipmaps. May result in an error if the value is out of range
335     /// of what the implementation supports.
336     Specific(u32),
337 }
338 
339 impl From<u32> for MipmapsCount {
340     #[inline]
from(num: u32) -> MipmapsCount341     fn from(num: u32) -> MipmapsCount {
342         MipmapsCount::Specific(num)
343     }
344 }
345 
346 vulkan_enum! {
347     #[non_exhaustive]
348 
349     // TODO: document
350     ImageType = ImageType(i32);
351 
352     // TODO: document
353     Dim1d = TYPE_1D,
354 
355     // TODO: document
356     Dim2d = TYPE_2D,
357 
358     // TODO: document
359     Dim3d = TYPE_3D,
360 }
361 
362 vulkan_enum! {
363     #[non_exhaustive]
364 
365     // TODO: document
366     ImageTiling = ImageTiling(i32);
367 
368     // TODO: document
369     Optimal = OPTIMAL,
370 
371     // TODO: document
372     Linear = LINEAR,
373 
374     // TODO: document
375     DrmFormatModifier = DRM_FORMAT_MODIFIER_EXT {
376         device_extensions: [ext_image_drm_format_modifier],
377     },
378 }
379 
380 /// The dimensions of an image.
381 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
382 pub enum ImageDimensions {
383     Dim1d {
384         width: u32,
385         array_layers: u32,
386     },
387     Dim2d {
388         width: u32,
389         height: u32,
390         array_layers: u32,
391     },
392     Dim3d {
393         width: u32,
394         height: u32,
395         depth: u32,
396     },
397 }
398 
399 impl ImageDimensions {
400     #[inline]
width(&self) -> u32401     pub fn width(&self) -> u32 {
402         match *self {
403             ImageDimensions::Dim1d { width, .. } => width,
404             ImageDimensions::Dim2d { width, .. } => width,
405             ImageDimensions::Dim3d { width, .. } => width,
406         }
407     }
408 
409     #[inline]
height(&self) -> u32410     pub fn height(&self) -> u32 {
411         match *self {
412             ImageDimensions::Dim1d { .. } => 1,
413             ImageDimensions::Dim2d { height, .. } => height,
414             ImageDimensions::Dim3d { height, .. } => height,
415         }
416     }
417 
418     #[inline]
width_height(&self) -> [u32; 2]419     pub fn width_height(&self) -> [u32; 2] {
420         [self.width(), self.height()]
421     }
422 
423     #[inline]
depth(&self) -> u32424     pub fn depth(&self) -> u32 {
425         match *self {
426             ImageDimensions::Dim1d { .. } => 1,
427             ImageDimensions::Dim2d { .. } => 1,
428             ImageDimensions::Dim3d { depth, .. } => depth,
429         }
430     }
431 
432     #[inline]
width_height_depth(&self) -> [u32; 3]433     pub fn width_height_depth(&self) -> [u32; 3] {
434         [self.width(), self.height(), self.depth()]
435     }
436 
437     #[inline]
array_layers(&self) -> u32438     pub fn array_layers(&self) -> u32 {
439         match *self {
440             ImageDimensions::Dim1d { array_layers, .. } => array_layers,
441             ImageDimensions::Dim2d { array_layers, .. } => array_layers,
442             ImageDimensions::Dim3d { .. } => 1,
443         }
444     }
445 
446     /// Returns the total number of texels for an image of these dimensions.
447     #[inline]
num_texels(&self) -> u32448     pub fn num_texels(&self) -> u32 {
449         self.width() * self.height() * self.depth() * self.array_layers()
450     }
451 
452     #[inline]
image_type(&self) -> ImageType453     pub fn image_type(&self) -> ImageType {
454         match *self {
455             ImageDimensions::Dim1d { .. } => ImageType::Dim1d,
456             ImageDimensions::Dim2d { .. } => ImageType::Dim2d,
457             ImageDimensions::Dim3d { .. } => ImageType::Dim3d,
458         }
459     }
460 
461     /// Returns the maximum number of mipmap levels for these image dimensions.
462     ///
463     /// The returned value is always at least 1.
464     ///
465     /// # Examples
466     ///
467     /// ```
468     /// use vulkano::image::ImageDimensions;
469     ///
470     /// let dims = ImageDimensions::Dim2d {
471     ///     width: 32,
472     ///     height: 50,
473     ///     array_layers: 1,
474     /// };
475     ///
476     /// assert_eq!(dims.max_mip_levels(), 6);
477     /// ```
478     #[inline]
max_mip_levels(&self) -> u32479     pub fn max_mip_levels(&self) -> u32 {
480         // This calculates `log2(max(width, height, depth)) + 1` using fast integer operations.
481         let max = match *self {
482             ImageDimensions::Dim1d { width, .. } => width,
483             ImageDimensions::Dim2d { width, height, .. } => width | height,
484             ImageDimensions::Dim3d {
485                 width,
486                 height,
487                 depth,
488             } => width | height | depth,
489         };
490         32 - max.leading_zeros()
491     }
492 
493     /// Returns the dimensions of the `level`th mipmap level. If `level` is 0, then the dimensions
494     /// are left unchanged.
495     ///
496     /// Returns `None` if `level` is superior or equal to `max_mip_levels()`.
497     ///
498     /// # Examples
499     ///
500     /// ```
501     /// use vulkano::image::ImageDimensions;
502     ///
503     /// let dims = ImageDimensions::Dim2d {
504     ///     width: 963,
505     ///     height: 256,
506     ///     array_layers: 1,
507     /// };
508     ///
509     /// assert_eq!(dims.mip_level_dimensions(0), Some(dims));
510     /// assert_eq!(dims.mip_level_dimensions(1), Some(ImageDimensions::Dim2d {
511     ///     width: 481,
512     ///     height: 128,
513     ///     array_layers: 1,
514     /// }));
515     /// assert_eq!(dims.mip_level_dimensions(6), Some(ImageDimensions::Dim2d {
516     ///     width: 15,
517     ///     height: 4,
518     ///     array_layers: 1,
519     /// }));
520     /// assert_eq!(dims.mip_level_dimensions(9), Some(ImageDimensions::Dim2d {
521     ///     width: 1,
522     ///     height: 1,
523     ///     array_layers: 1,
524     /// }));
525     /// assert_eq!(dims.mip_level_dimensions(11), None);
526     /// ```
527     ///
528     /// # Panics
529     ///
530     /// - In debug mode, panics if `width`, `height` or `depth` is equal to 0. In release, returns
531     ///   an unspecified value.
532     #[inline]
mip_level_dimensions(&self, level: u32) -> Option<ImageDimensions>533     pub fn mip_level_dimensions(&self, level: u32) -> Option<ImageDimensions> {
534         if level == 0 {
535             return Some(*self);
536         }
537 
538         if level >= self.max_mip_levels() {
539             return None;
540         }
541 
542         Some(match *self {
543             ImageDimensions::Dim1d {
544                 width,
545                 array_layers,
546             } => {
547                 debug_assert_ne!(width, 0);
548                 ImageDimensions::Dim1d {
549                     array_layers,
550                     width: cmp::max(1, width >> level),
551                 }
552             }
553 
554             ImageDimensions::Dim2d {
555                 width,
556                 height,
557                 array_layers,
558             } => {
559                 debug_assert_ne!(width, 0);
560                 debug_assert_ne!(height, 0);
561                 ImageDimensions::Dim2d {
562                     width: cmp::max(1, width >> level),
563                     height: cmp::max(1, height >> level),
564                     array_layers,
565                 }
566             }
567 
568             ImageDimensions::Dim3d {
569                 width,
570                 height,
571                 depth,
572             } => {
573                 debug_assert_ne!(width, 0);
574                 debug_assert_ne!(height, 0);
575                 ImageDimensions::Dim3d {
576                     width: cmp::max(1, width >> level),
577                     height: cmp::max(1, height >> level),
578                     depth: cmp::max(1, depth >> level),
579                 }
580             }
581         })
582     }
583 }
584 
585 /// One or more subresources of an image, spanning a single mip level, that should be accessed by a
586 /// command.
587 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
588 pub struct ImageSubresourceLayers {
589     /// Selects the aspects that will be included.
590     ///
591     /// The value must not be empty, and must not include any of the `memory_plane` aspects.
592     /// The `color` aspect cannot be selected together any of with the `plane` aspects.
593     pub aspects: ImageAspects,
594 
595     /// Selects mip level that will be included.
596     pub mip_level: u32,
597 
598     /// Selects the range of array layers that will be included.
599     ///
600     /// The range must not be empty.
601     pub array_layers: Range<u32>,
602 }
603 
604 impl ImageSubresourceLayers {
605     /// Returns an `ImageSubresourceLayers` from the given image parameters, covering the first
606     /// mip level of the image. All aspects of the image are selected, or `plane0` if the image
607     /// is multi-planar.
608     #[inline]
from_parameters(format: Format, array_layers: u32) -> Self609     pub fn from_parameters(format: Format, array_layers: u32) -> Self {
610         Self {
611             aspects: {
612                 let aspects = format.aspects();
613 
614                 if aspects.intersects(ImageAspects::PLANE_0) {
615                     ImageAspects::PLANE_0
616                 } else {
617                     aspects
618                 }
619             },
620             mip_level: 0,
621             array_layers: 0..array_layers,
622         }
623     }
624 }
625 
626 impl From<ImageSubresourceLayers> for ash::vk::ImageSubresourceLayers {
627     #[inline]
from(val: ImageSubresourceLayers) -> Self628     fn from(val: ImageSubresourceLayers) -> Self {
629         Self {
630             aspect_mask: val.aspects.into(),
631             mip_level: val.mip_level,
632             base_array_layer: val.array_layers.start,
633             layer_count: val.array_layers.end - val.array_layers.start,
634         }
635     }
636 }
637 
638 /// One or more subresources of an image that should be accessed by a command.
639 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
640 pub struct ImageSubresourceRange {
641     /// Selects the aspects that will be included.
642     ///
643     /// The value must not be empty, and must not include any of the `memory_plane` aspects.
644     /// The `color` aspect cannot be selected together any of with the `plane` aspects.
645     pub aspects: ImageAspects,
646 
647     /// Selects the range of the mip levels that will be included.
648     ///
649     /// The range must not be empty.
650     pub mip_levels: Range<u32>,
651 
652     /// Selects the range of array layers that will be included.
653     ///
654     /// The range must not be empty.
655     pub array_layers: Range<u32>,
656 }
657 
658 impl ImageSubresourceRange {
659     /// Returns an `ImageSubresourceRange` from the given image parameters, covering the whole
660     /// image. If the image is multi-planar, only the `color` aspect is selected.
661     #[inline]
from_parameters(format: Format, mip_levels: u32, array_layers: u32) -> Self662     pub fn from_parameters(format: Format, mip_levels: u32, array_layers: u32) -> Self {
663         Self {
664             aspects: format.aspects()
665                 - (ImageAspects::PLANE_0 | ImageAspects::PLANE_1 | ImageAspects::PLANE_2),
666             mip_levels: 0..mip_levels,
667             array_layers: 0..array_layers,
668         }
669     }
670 }
671 
672 impl From<ImageSubresourceRange> for ash::vk::ImageSubresourceRange {
673     #[inline]
from(val: ImageSubresourceRange) -> Self674     fn from(val: ImageSubresourceRange) -> Self {
675         Self {
676             aspect_mask: val.aspects.into(),
677             base_mip_level: val.mip_levels.start,
678             level_count: val.mip_levels.end - val.mip_levels.start,
679             base_array_layer: val.array_layers.start,
680             layer_count: val.array_layers.end - val.array_layers.start,
681         }
682     }
683 }
684 
685 impl From<ImageSubresourceLayers> for ImageSubresourceRange {
686     #[inline]
from(val: ImageSubresourceLayers) -> Self687     fn from(val: ImageSubresourceLayers) -> Self {
688         Self {
689             aspects: val.aspects,
690             mip_levels: val.mip_level..val.mip_level + 1,
691             array_layers: val.array_layers,
692         }
693     }
694 }
695 
696 /// Describes the memory layout of an image.
697 ///
698 /// The address of a texel at `(x, y, z, layer)` is `layer * array_pitch + z * depth_pitch +
699 /// y * row_pitch + x * size_of_each_texel + offset`. `size_of_each_texel` must be determined
700 /// depending on the format. The same formula applies for compressed formats, except that the
701 /// coordinates must be in number of blocks.
702 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
703 pub struct SubresourceLayout {
704     /// The number of bytes from the start of the memory where the subresource begins.
705     pub offset: DeviceSize,
706 
707     /// The size in bytes in the subresource. It includes any extra memory that is required based on
708     /// `row_pitch`.
709     pub size: DeviceSize,
710 
711     /// The number of bytes between adjacent rows of texels.
712     pub row_pitch: DeviceSize,
713 
714     /// The number of bytes between adjacent array layers.
715     ///
716     /// This value is undefined for images with only one array layer.
717     pub array_pitch: DeviceSize,
718 
719     /// The number of bytes between adjacent depth slices.
720     ///
721     /// This value is undefined for images that are not three-dimensional.
722     pub depth_pitch: DeviceSize,
723 }
724 
725 /// The image configuration to query in
726 /// [`PhysicalDevice::image_format_properties`](crate::device::physical::PhysicalDevice::image_format_properties).
727 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
728 pub struct ImageFormatInfo {
729     /// The `flags` that the image will have.
730     ///
731     /// The default value is [`ImageCreateFlags::empty()`].
732     pub flags: ImageCreateFlags,
733 
734     /// The `format` that the image will have.
735     ///
736     /// The default value is `None`, which must be overridden.
737     pub format: Option<Format>,
738 
739     /// The dimension type that the image will have.
740     ///
741     /// The default value is [`ImageType::Dim2d`].
742     pub image_type: ImageType,
743 
744     /// The `tiling` that the image will have.
745     ///
746     /// The default value is [`ImageTiling::Optimal`].
747     pub tiling: ImageTiling,
748 
749     /// The `usage` that the image will have.
750     ///
751     /// The default value is [`ImageUsage::empty()`], which must be overridden.
752     pub usage: ImageUsage,
753 
754     /// The `stencil_usage` that the image will have.
755     ///
756     /// If `stencil_usage` is empty or if `format` does not have both a depth and a stencil aspect,
757     /// then it is automatically set to equal `usage`.
758     ///
759     /// If after this, `stencil_usage` does not equal `usage`,
760     /// then the physical device API version must be at least 1.2, or the
761     /// [`ext_separate_stencil_usage`](crate::device::DeviceExtensions::ext_separate_stencil_usage)
762     /// extension must be supported by the physical device.
763     ///
764     /// The default value is [`ImageUsage::empty()`].
765     pub stencil_usage: ImageUsage,
766 
767     /// An external memory handle type that will be imported to or exported from the image.
768     ///
769     /// This is needed to retrieve the
770     /// [`external_memory_properties`](ImageFormatProperties::external_memory_properties) value,
771     /// and the physical device API version must be at least 1.1 or the
772     /// [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)
773     /// extension must be enabled on the instance.
774     ///
775     /// The default value is `None`.
776     pub external_memory_handle_type: Option<ExternalMemoryHandleType>,
777 
778     /// The image view type that will be created from the image.
779     ///
780     /// This is needed to retrieve the
781     /// [`filter_cubic`](ImageFormatProperties::filter_cubic) and
782     /// [`filter_cubic_minmax`](ImageFormatProperties::filter_cubic_minmax) values, and the
783     /// [`ext_filter_cubic`](crate::device::DeviceExtensions::ext_filter_cubic) extension must be
784     /// supported on the physical device.
785     ///
786     /// The default value is `None`.
787     pub image_view_type: Option<ImageViewType>,
788 
789     pub _ne: crate::NonExhaustive,
790 }
791 
792 impl Default for ImageFormatInfo {
793     #[inline]
default() -> Self794     fn default() -> Self {
795         Self {
796             flags: ImageCreateFlags::empty(),
797             format: None,
798             image_type: ImageType::Dim2d,
799             tiling: ImageTiling::Optimal,
800             usage: ImageUsage::empty(),
801             stencil_usage: ImageUsage::empty(),
802             external_memory_handle_type: None,
803             image_view_type: None,
804             _ne: crate::NonExhaustive(()),
805         }
806     }
807 }
808 
809 /// The properties that are supported by a physical device for images of a certain type.
810 #[derive(Clone, Debug)]
811 #[non_exhaustive]
812 pub struct ImageFormatProperties {
813     /// The maximum dimensions.
814     pub max_extent: [u32; 3],
815 
816     /// The maximum number of mipmap levels.
817     pub max_mip_levels: u32,
818 
819     /// The maximum number of array layers.
820     pub max_array_layers: u32,
821 
822     /// The supported sample counts.
823     pub sample_counts: SampleCounts,
824 
825     /// The maximum total size of an image, in bytes. This is guaranteed to be at least
826     /// 0x80000000.
827     pub max_resource_size: DeviceSize,
828 
829     /// The properties for external memory.
830     /// This will be [`ExternalMemoryProperties::default()`] if `external_handle_type` was `None`.
831     pub external_memory_properties: ExternalMemoryProperties,
832 
833     /// When querying with an image view type, whether such image views support sampling with
834     /// a [`Cubic`](crate::sampler::Filter::Cubic) `mag_filter` or `min_filter`.
835     pub filter_cubic: bool,
836 
837     /// When querying with an image view type, whether such image views support sampling with
838     /// a [`Cubic`](crate::sampler::Filter::Cubic) `mag_filter` or `min_filter`, and with a
839     /// [`Min`](crate::sampler::SamplerReductionMode::Min) or
840     /// [`Max`](crate::sampler::SamplerReductionMode::Max) `reduction_mode`.
841     pub filter_cubic_minmax: bool,
842 }
843 
844 impl From<ash::vk::ImageFormatProperties> for ImageFormatProperties {
845     #[inline]
from(props: ash::vk::ImageFormatProperties) -> Self846     fn from(props: ash::vk::ImageFormatProperties) -> Self {
847         Self {
848             max_extent: [
849                 props.max_extent.width,
850                 props.max_extent.height,
851                 props.max_extent.depth,
852             ],
853             max_mip_levels: props.max_mip_levels,
854             max_array_layers: props.max_array_layers,
855             sample_counts: props.sample_counts.into(),
856             max_resource_size: props.max_resource_size,
857             external_memory_properties: Default::default(),
858             filter_cubic: false,
859             filter_cubic_minmax: false,
860         }
861     }
862 }
863 
864 /// The image configuration to query in
865 /// [`PhysicalDevice::sparse_image_format_properties`](crate::device::physical::PhysicalDevice::sparse_image_format_properties).
866 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
867 pub struct SparseImageFormatInfo {
868     /// The `format` that the image will have.
869     ///
870     /// The default value is `None`, which must be overridden.
871     pub format: Option<Format>,
872 
873     /// The dimension type that the image will have.
874     ///
875     /// The default value is [`ImageType::Dim2d`].
876     pub image_type: ImageType,
877 
878     /// The `samples` that the image will have.
879     ///
880     /// The default value is `SampleCount::Sample1`.
881     pub samples: SampleCount,
882 
883     /// The `usage` that the image will have.
884     ///
885     /// The default value is [`ImageUsage::empty()`], which must be overridden.
886     pub usage: ImageUsage,
887 
888     /// The `tiling` that the image will have.
889     ///
890     /// The default value is [`ImageTiling::Optimal`].
891     pub tiling: ImageTiling,
892 
893     pub _ne: crate::NonExhaustive,
894 }
895 
896 impl Default for SparseImageFormatInfo {
897     #[inline]
default() -> Self898     fn default() -> Self {
899         Self {
900             format: None,
901             image_type: ImageType::Dim2d,
902             samples: SampleCount::Sample1,
903             usage: ImageUsage::empty(),
904             tiling: ImageTiling::Optimal,
905             _ne: crate::NonExhaustive(()),
906         }
907     }
908 }
909 
910 /// The properties that are supported by a physical device for sparse images of a certain type.
911 #[derive(Clone, Debug)]
912 #[non_exhaustive]
913 pub struct SparseImageFormatProperties {
914     /// The aspects of the image that the properties apply to.
915     pub aspects: ImageAspects,
916 
917     /// The size of the sparse image block, in texels or compressed texel blocks.
918     ///
919     /// If `flags.nonstandard_block_size` is set, then these values do not match the standard
920     /// sparse block dimensions for the given format.
921     pub image_granularity: [u32; 3],
922 
923     /// Additional information about the sparse image.
924     pub flags: SparseImageFormatFlags,
925 }
926 
927 vulkan_bitflags! {
928     #[non_exhaustive]
929 
930     /// Flags specifying information about a sparse resource.
931     SparseImageFormatFlags = SparseImageFormatFlags(u32);
932 
933     /// The image uses a single mip tail region for all array layers, instead of one mip tail region
934     /// per array layer.
935     SINGLE_MIPTAIL = SINGLE_MIPTAIL,
936 
937     /// The image's mip tail region begins with the first mip level whose dimensions are not an
938     /// integer multiple of the corresponding sparse image block dimensions.
939     ALIGNED_MIP_SIZE = ALIGNED_MIP_SIZE,
940 
941     /// The image uses non-standard sparse image block dimensions.
942     NONSTANDARD_BLOCK_SIZE = NONSTANDARD_BLOCK_SIZE,
943 }
944 
945 /// Requirements for binding memory to a sparse image.
946 #[derive(Clone, Debug)]
947 #[non_exhaustive]
948 pub struct SparseImageMemoryRequirements {
949     /// The properties of the image format.
950     pub format_properties: SparseImageFormatProperties,
951 
952     /// The first mip level at which image subresources are included in the mip tail region.
953     pub image_mip_tail_first_lod: u32,
954 
955     /// The size in bytes of the mip tail region. This value is guaranteed to be a multiple of the
956     /// sparse block size in bytes.
957     ///
958     /// If `format_properties.flags.single_miptail` is set, then this is the size of the whole
959     /// mip tail. Otherwise it is the size of the mip tail of a single array layer.
960     pub image_mip_tail_size: DeviceSize,
961 
962     /// The memory offset that must be used to bind the mip tail region.
963     pub image_mip_tail_offset: DeviceSize,
964 
965     /// If `format_properties.flags.single_miptail` is not set, specifies the stride between
966     /// the mip tail regions of each array layer.
967     pub image_mip_tail_stride: Option<DeviceSize>,
968 }
969 
970 #[cfg(test)]
971 mod tests {
972     use crate::{
973         command_buffer::{
974             allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage,
975         },
976         format::Format,
977         image::{ImageAccess, ImageDimensions, ImmutableImage, MipmapsCount},
978         memory::allocator::StandardMemoryAllocator,
979     };
980 
981     #[test]
max_mip_levels()982     fn max_mip_levels() {
983         let dims = ImageDimensions::Dim2d {
984             width: 2,
985             height: 1,
986             array_layers: 1,
987         };
988         assert_eq!(dims.max_mip_levels(), 2);
989 
990         let dims = ImageDimensions::Dim2d {
991             width: 2,
992             height: 3,
993             array_layers: 1,
994         };
995         assert_eq!(dims.max_mip_levels(), 2);
996 
997         let dims = ImageDimensions::Dim2d {
998             width: 512,
999             height: 512,
1000             array_layers: 1,
1001         };
1002         assert_eq!(dims.max_mip_levels(), 10);
1003     }
1004 
1005     #[test]
mip_level_dimensions()1006     fn mip_level_dimensions() {
1007         let dims = ImageDimensions::Dim2d {
1008             width: 283,
1009             height: 175,
1010             array_layers: 1,
1011         };
1012         assert_eq!(dims.mip_level_dimensions(0), Some(dims));
1013         assert_eq!(
1014             dims.mip_level_dimensions(1),
1015             Some(ImageDimensions::Dim2d {
1016                 width: 141,
1017                 height: 87,
1018                 array_layers: 1,
1019             })
1020         );
1021         assert_eq!(
1022             dims.mip_level_dimensions(2),
1023             Some(ImageDimensions::Dim2d {
1024                 width: 70,
1025                 height: 43,
1026                 array_layers: 1,
1027             })
1028         );
1029         assert_eq!(
1030             dims.mip_level_dimensions(3),
1031             Some(ImageDimensions::Dim2d {
1032                 width: 35,
1033                 height: 21,
1034                 array_layers: 1,
1035             })
1036         );
1037 
1038         assert_eq!(
1039             dims.mip_level_dimensions(4),
1040             Some(ImageDimensions::Dim2d {
1041                 width: 17,
1042                 height: 10,
1043                 array_layers: 1,
1044             })
1045         );
1046         assert_eq!(
1047             dims.mip_level_dimensions(5),
1048             Some(ImageDimensions::Dim2d {
1049                 width: 8,
1050                 height: 5,
1051                 array_layers: 1,
1052             })
1053         );
1054         assert_eq!(
1055             dims.mip_level_dimensions(6),
1056             Some(ImageDimensions::Dim2d {
1057                 width: 4,
1058                 height: 2,
1059                 array_layers: 1,
1060             })
1061         );
1062         assert_eq!(
1063             dims.mip_level_dimensions(7),
1064             Some(ImageDimensions::Dim2d {
1065                 width: 2,
1066                 height: 1,
1067                 array_layers: 1,
1068             })
1069         );
1070         assert_eq!(
1071             dims.mip_level_dimensions(8),
1072             Some(ImageDimensions::Dim2d {
1073                 width: 1,
1074                 height: 1,
1075                 array_layers: 1,
1076             })
1077         );
1078         assert_eq!(dims.mip_level_dimensions(9), None);
1079     }
1080 
1081     #[test]
mipmap_working_immutable_image()1082     fn mipmap_working_immutable_image() {
1083         let (device, queue) = gfx_dev_and_queue!();
1084 
1085         let cb_allocator = StandardCommandBufferAllocator::new(device.clone(), Default::default());
1086         let mut cbb = AutoCommandBufferBuilder::primary(
1087             &cb_allocator,
1088             queue.queue_family_index(),
1089             CommandBufferUsage::OneTimeSubmit,
1090         )
1091         .unwrap();
1092 
1093         let memory_allocator = StandardMemoryAllocator::new_default(device);
1094         let dimensions = ImageDimensions::Dim2d {
1095             width: 512,
1096             height: 512,
1097             array_layers: 1,
1098         };
1099         {
1100             let mut vec = Vec::new();
1101 
1102             vec.resize(512 * 512, 0u8);
1103 
1104             let image = ImmutableImage::from_iter(
1105                 &memory_allocator,
1106                 vec.into_iter(),
1107                 dimensions,
1108                 MipmapsCount::One,
1109                 Format::R8_UNORM,
1110                 &mut cbb,
1111             )
1112             .unwrap();
1113             assert_eq!(image.mip_levels(), 1);
1114         }
1115         {
1116             let mut vec = Vec::new();
1117 
1118             vec.resize(512 * 512, 0u8);
1119 
1120             let image = ImmutableImage::from_iter(
1121                 &memory_allocator,
1122                 vec.into_iter(),
1123                 dimensions,
1124                 MipmapsCount::Log2,
1125                 Format::R8_UNORM,
1126                 &mut cbb,
1127             )
1128             .unwrap();
1129             assert_eq!(image.mip_levels(), 10);
1130         }
1131     }
1132 }
1133