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