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 //! Low-level implementation of images. 11 //! 12 //! This module contains low-level wrappers around the Vulkan image types. All 13 //! other image types of this library, and all custom image types 14 //! that you create must wrap around the types in this module. 15 16 use super::{ 17 ImageAspect, ImageAspects, ImageCreateFlags, ImageDimensions, ImageLayout, 18 ImageSubresourceLayers, ImageSubresourceRange, ImageTiling, ImageUsage, SampleCount, 19 SampleCounts, SparseImageMemoryRequirements, 20 }; 21 use crate::{ 22 buffer::subbuffer::{ReadLockError, WriteLockError}, 23 cache::OnceCache, 24 device::{Device, DeviceOwned}, 25 format::{ChromaSampling, Format, FormatFeatures, NumericType}, 26 image::{ 27 view::ImageViewCreationError, ImageFormatInfo, ImageFormatProperties, ImageType, 28 SparseImageFormatProperties, 29 }, 30 macros::impl_id_counter, 31 memory::{ 32 allocator::{AllocationCreationError, AllocationType, DeviceLayout, MemoryAlloc}, 33 is_aligned, DedicatedTo, DeviceAlignment, ExternalMemoryHandleType, 34 ExternalMemoryHandleTypes, MemoryPropertyFlags, MemoryRequirements, 35 }, 36 range_map::RangeMap, 37 swapchain::Swapchain, 38 sync::{future::AccessError, CurrentAccess, Sharing}, 39 DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, 40 }; 41 use ash::vk::ImageDrmFormatModifierExplicitCreateInfoEXT; 42 use parking_lot::{Mutex, MutexGuard}; 43 use smallvec::{smallvec, SmallVec}; 44 use std::{ 45 error::Error, 46 fmt::{Display, Error as FmtError, Formatter}, 47 hash::{Hash, Hasher}, 48 iter::{FusedIterator, Peekable}, 49 mem::{size_of_val, MaybeUninit}, 50 num::NonZeroU64, 51 ops::Range, 52 ptr, 53 sync::Arc, 54 }; 55 56 /// A raw image, with no memory backing it. 57 /// 58 /// This is the basic image type, a direct translation of a `VkImage` object, but it is mostly 59 /// useless in this form. After creating a raw image, you must call `bind_memory` to make a 60 /// complete image object. 61 #[derive(Debug)] 62 pub struct RawImage { 63 handle: ash::vk::Image, 64 device: Arc<Device>, 65 id: NonZeroU64, 66 67 flags: ImageCreateFlags, 68 dimensions: ImageDimensions, 69 format: Option<Format>, 70 format_features: FormatFeatures, 71 initial_layout: ImageLayout, 72 mip_levels: u32, 73 samples: SampleCount, 74 tiling: ImageTiling, 75 usage: ImageUsage, 76 sharing: Sharing<SmallVec<[u32; 4]>>, 77 stencil_usage: ImageUsage, 78 external_memory_handle_types: ExternalMemoryHandleTypes, 79 80 memory_requirements: SmallVec<[MemoryRequirements; 3]>, 81 needs_destruction: bool, // `vkDestroyImage` is called only if true. 82 subresource_layout: OnceCache<(ImageAspect, u32, u32), SubresourceLayout>, 83 } 84 85 impl RawImage { 86 /// Creates a new `RawImage`. 87 /// 88 /// # Panics 89 /// 90 /// - Panics if one of the values in `create_info.dimensions` is zero. 91 /// - Panics if `create_info.format` is `None`. 92 /// - Panics if `create_info.block_texel_view_compatible` is set but not 93 /// `create_info.mutable_format`. 94 /// - Panics if `create_info.mip_levels` is `0`. 95 /// - Panics if `create_info.sharing` is [`Sharing::Concurrent`] with less than 2 items. 96 /// - Panics if `create_info.initial_layout` is something other than 97 /// [`ImageLayout::Undefined`] or [`ImageLayout::Preinitialized`]. 98 /// - Panics if `create_info.usage` is empty. 99 /// - Panics if `create_info.usage` contains `transient_attachment`, but does not also contain 100 /// at least one of `color_attachment`, `depth_stencil_attachment`, `input_attachment`, or 101 /// if it contains values other than these. 102 #[inline] new( device: Arc<Device>, mut create_info: ImageCreateInfo, ) -> Result<RawImage, ImageError>103 pub fn new( 104 device: Arc<Device>, 105 mut create_info: ImageCreateInfo, 106 ) -> Result<RawImage, ImageError> { 107 match &mut create_info.sharing { 108 Sharing::Exclusive => (), 109 Sharing::Concurrent(queue_family_indices) => { 110 // VUID-VkImageCreateInfo-sharingMode-01420 111 queue_family_indices.sort_unstable(); 112 queue_family_indices.dedup(); 113 } 114 } 115 116 Self::validate_new(&device, &create_info)?; 117 118 unsafe { Ok(RawImage::new_unchecked(device, create_info)?) } 119 } 120 validate_new( device: &Device, create_info: &ImageCreateInfo, ) -> Result<FormatFeatures, ImageError>121 fn validate_new( 122 device: &Device, 123 create_info: &ImageCreateInfo, 124 ) -> Result<FormatFeatures, ImageError> { 125 let &ImageCreateInfo { 126 flags, 127 dimensions, 128 format, 129 mip_levels, 130 samples, 131 tiling, 132 usage, 133 mut stencil_usage, 134 ref sharing, 135 initial_layout, 136 external_memory_handle_types, 137 _ne: _, 138 image_drm_format_modifier_create_info, 139 } = create_info; 140 141 let physical_device = device.physical_device(); 142 let device_properties = physical_device.properties(); 143 144 let format = format.unwrap(); // Can be None for "external formats" but Vulkano doesn't support that yet 145 let aspects = format.aspects(); 146 147 let has_separate_stencil_usage = if stencil_usage.is_empty() 148 || !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL) 149 { 150 stencil_usage = usage; 151 false 152 } else { 153 stencil_usage == usage 154 }; 155 156 // VUID-VkImageCreateInfo-flags-parameter 157 flags.validate_device(device)?; 158 159 // VUID-VkImageCreateInfo-format-parameter 160 format.validate_device(device)?; 161 162 // VUID-VkImageCreateInfo-samples-parameter 163 samples.validate_device(device)?; 164 165 // VUID-VkImageCreateInfo-tiling-parameter 166 tiling.validate_device(device)?; 167 168 // VUID-VkImageCreateInfo-usage-parameter 169 usage.validate_device(device)?; 170 171 // VUID-VkImageCreateInfo-usage-requiredbitmask 172 assert!(!usage.is_empty()); 173 174 if has_separate_stencil_usage { 175 if !(device.api_version() >= Version::V1_2 176 || device.enabled_extensions().ext_separate_stencil_usage) 177 { 178 return Err(ImageError::RequirementNotMet { 179 required_for: "`create_info.stencil_usage` is `Some` and `create_info.format` \ 180 has both a depth and a stencil aspect", 181 requires_one_of: RequiresOneOf { 182 api_version: Some(Version::V1_2), 183 device_extensions: &["ext_separate_stencil_usage"], 184 ..Default::default() 185 }, 186 }); 187 } 188 189 // VUID-VkImageStencilUsageCreateInfo-stencilUsage-parameter 190 stencil_usage.validate_device(device)?; 191 192 // VUID-VkImageStencilUsageCreateInfo-usage-requiredbitmask 193 assert!(!stencil_usage.is_empty()); 194 } 195 196 // VUID-VkImageCreateInfo-initialLayout-parameter 197 initial_layout.validate_device(device)?; 198 199 // VUID-VkImageCreateInfo-initialLayout-00993 200 assert!(matches!( 201 initial_layout, 202 ImageLayout::Undefined | ImageLayout::Preinitialized 203 )); 204 205 // VUID-VkImageCreateInfo-flags-01573 206 assert!( 207 !flags.intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE) 208 || flags.intersects(ImageCreateFlags::MUTABLE_FORMAT) 209 ); 210 211 // VUID-VkImageCreateInfo-tiling-02261 212 // VUID-VkImageCreateInfo-pNext-02262 213 if (tiling == ImageTiling::DrmFormatModifier) 214 != image_drm_format_modifier_create_info.is_some() 215 { 216 return Err(ImageError::DrmFormatModifierRequiresCreateInfo); 217 } 218 219 // Get format features 220 let format_features = { 221 // Use unchecked, because all validation has been done above. 222 let format_properties = unsafe { physical_device.format_properties_unchecked(format) }; 223 match tiling { 224 ImageTiling::Linear => format_properties.linear_tiling_features, 225 ImageTiling::Optimal => format_properties.optimal_tiling_features, 226 ImageTiling::DrmFormatModifier => format_properties.linear_tiling_features, // TODO: Improve 227 } 228 }; 229 230 // TODO: VUID-VkImageCreateInfo-tiling-02353 231 // Vulkano currently has no high-level way to add or check for VkImageFormatListCreateInfo. 232 233 // Format isn't supported at all? 234 if format_features.is_empty() { 235 return Err(ImageError::FormatNotSupported); 236 } 237 238 // Decode the dimensions 239 let (image_type, extent, array_layers) = match dimensions { 240 ImageDimensions::Dim1d { 241 width, 242 array_layers, 243 } => (ImageType::Dim1d, [width, 1, 1], array_layers), 244 ImageDimensions::Dim2d { 245 width, 246 height, 247 array_layers, 248 } => (ImageType::Dim2d, [width, height, 1], array_layers), 249 ImageDimensions::Dim3d { 250 width, 251 height, 252 depth, 253 } => (ImageType::Dim3d, [width, height, depth], 1), 254 }; 255 256 // VUID-VkImageCreateInfo-extent-00944 257 assert!(extent[0] != 0); 258 259 // VUID-VkImageCreateInfo-extent-00945 260 assert!(extent[1] != 0); 261 262 // VUID-VkImageCreateInfo-extent-00946 263 assert!(extent[2] != 0); 264 265 // VUID-VkImageCreateInfo-arrayLayers-00948 266 assert!(array_layers != 0); 267 268 // VUID-VkImageCreateInfo-mipLevels-00947 269 assert!(mip_levels != 0); 270 271 // Check mip levels 272 273 let max_mip_levels = dimensions.max_mip_levels(); 274 debug_assert!(max_mip_levels >= 1); 275 276 // VUID-VkImageCreateInfo-mipLevels-00958 277 if mip_levels > max_mip_levels { 278 return Err(ImageError::MaxMipLevelsExceeded { 279 mip_levels, 280 max: max_mip_levels, 281 }); 282 } 283 284 // VUID-VkImageCreateInfo-samples-02257 285 if samples != SampleCount::Sample1 { 286 if image_type != ImageType::Dim2d { 287 return Err(ImageError::MultisampleNot2d); 288 } 289 290 if flags.intersects(ImageCreateFlags::CUBE_COMPATIBLE) { 291 return Err(ImageError::MultisampleCubeCompatible); 292 } 293 294 if mip_levels != 1 { 295 return Err(ImageError::MultisampleMultipleMipLevels); 296 } 297 298 if tiling == ImageTiling::Linear { 299 return Err(ImageError::MultisampleLinearTiling); 300 } 301 302 // VUID-VkImageCreateInfo-multisampleArrayImage-04460 303 if device.enabled_extensions().khr_portability_subset 304 && !device.enabled_features().multisample_array_image 305 && array_layers != 1 306 { 307 return Err(ImageError::RequirementNotMet { 308 required_for: "this device is a portability subset device, \ 309 `create_info.samples` is not `SampleCount::Sample1` and \ 310 `create_info.dimensions.array_layers()` is greater than `1`", 311 requires_one_of: RequiresOneOf { 312 features: &["multisample_array_image"], 313 ..Default::default() 314 }, 315 }); 316 } 317 } 318 319 // Check limits for YCbCr formats 320 if let Some(chroma_sampling) = format.ycbcr_chroma_sampling() { 321 // VUID-VkImageCreateInfo-format-06410 322 if mip_levels != 1 { 323 return Err(ImageError::YcbcrFormatMultipleMipLevels); 324 } 325 326 // VUID-VkImageCreateInfo-format-06411 327 if samples != SampleCount::Sample1 { 328 return Err(ImageError::YcbcrFormatMultisampling); 329 } 330 331 // VUID-VkImageCreateInfo-format-06412 332 if image_type != ImageType::Dim2d { 333 return Err(ImageError::YcbcrFormatNot2d); 334 } 335 336 // VUID-VkImageCreateInfo-format-06413 337 if array_layers > 1 && !device.enabled_features().ycbcr_image_arrays { 338 return Err(ImageError::RequirementNotMet { 339 required_for: "`create_info.format.ycbcr_chroma_sampling()` is `Some` and \ 340 `create_info.dimensions.array_layers()` is greater than `1`", 341 requires_one_of: RequiresOneOf { 342 features: &["ycbcr_image_arrays"], 343 ..Default::default() 344 }, 345 }); 346 } 347 348 match chroma_sampling { 349 ChromaSampling::Mode444 => (), 350 ChromaSampling::Mode422 => { 351 // VUID-VkImageCreateInfo-format-04712 352 if extent[0] % 2 != 0 { 353 return Err(ImageError::YcbcrFormatInvalidDimensions); 354 } 355 } 356 ChromaSampling::Mode420 => { 357 // VUID-VkImageCreateInfo-format-04712 358 // VUID-VkImageCreateInfo-format-04713 359 if !(extent[0] % 2 == 0 && extent[1] % 2 == 0) { 360 return Err(ImageError::YcbcrFormatInvalidDimensions); 361 } 362 } 363 } 364 } 365 366 /* Check usage requirements */ 367 368 let combined_usage = usage | stencil_usage; 369 370 if combined_usage.intersects(ImageUsage::SAMPLED) 371 && !format_features.intersects(FormatFeatures::SAMPLED_IMAGE) 372 { 373 return Err(ImageError::FormatUsageNotSupported { usage: "sampled" }); 374 } 375 376 if combined_usage.intersects(ImageUsage::COLOR_ATTACHMENT) 377 && !format_features.intersects(FormatFeatures::COLOR_ATTACHMENT) 378 { 379 return Err(ImageError::FormatUsageNotSupported { 380 usage: "color_attachment", 381 }); 382 } 383 384 if combined_usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT) 385 && !format_features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) 386 { 387 return Err(ImageError::FormatUsageNotSupported { 388 usage: "depth_stencil_attachment", 389 }); 390 } 391 392 if combined_usage.intersects(ImageUsage::INPUT_ATTACHMENT) 393 && !format_features.intersects( 394 FormatFeatures::COLOR_ATTACHMENT | FormatFeatures::DEPTH_STENCIL_ATTACHMENT, 395 ) 396 { 397 return Err(ImageError::FormatUsageNotSupported { 398 usage: "input_attachment", 399 }); 400 } 401 402 if combined_usage.intersects( 403 ImageUsage::COLOR_ATTACHMENT 404 | ImageUsage::DEPTH_STENCIL_ATTACHMENT 405 | ImageUsage::INPUT_ATTACHMENT 406 | ImageUsage::TRANSIENT_ATTACHMENT, 407 ) { 408 // VUID-VkImageCreateInfo-usage-00964 409 // VUID-VkImageCreateInfo-usage-00965 410 // VUID-VkImageCreateInfo-Format-02536 411 // VUID-VkImageCreateInfo-format-02537 412 if extent[0] > device_properties.max_framebuffer_width 413 || extent[1] > device_properties.max_framebuffer_height 414 { 415 return Err(ImageError::MaxFramebufferDimensionsExceeded { 416 extent: [extent[0], extent[1]], 417 max: [ 418 device_properties.max_framebuffer_width, 419 device_properties.max_framebuffer_height, 420 ], 421 }); 422 } 423 } 424 425 if combined_usage.intersects(ImageUsage::STORAGE) { 426 if !format_features.intersects(FormatFeatures::STORAGE_IMAGE) { 427 return Err(ImageError::FormatUsageNotSupported { usage: "storage" }); 428 } 429 430 // VUID-VkImageCreateInfo-usage-00968 431 // VUID-VkImageCreateInfo-format-02538 432 if !device.enabled_features().shader_storage_image_multisample 433 && samples != SampleCount::Sample1 434 { 435 return Err(ImageError::RequirementNotMet { 436 required_for: "`create_info.usage` or `create_info.stencil_usage` contains \ 437 `ImageUsage::STORAGE`, and `create_info.samples` is not \ 438 `SampleCount::Sample1`", 439 requires_one_of: RequiresOneOf { 440 features: &["shader_storage_image_multisample"], 441 ..Default::default() 442 }, 443 }); 444 } 445 } 446 447 // These flags only exist in later versions, ignore them otherwise 448 if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 { 449 if combined_usage.intersects(ImageUsage::TRANSFER_SRC) 450 && !format_features.intersects(FormatFeatures::TRANSFER_SRC) 451 { 452 return Err(ImageError::FormatUsageNotSupported { 453 usage: "transfer_src", 454 }); 455 } 456 457 if combined_usage.intersects(ImageUsage::TRANSFER_DST) 458 && !format_features.intersects(FormatFeatures::TRANSFER_DST) 459 { 460 return Err(ImageError::FormatUsageNotSupported { 461 usage: "transfer_dst", 462 }); 463 } 464 } 465 466 if usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT) { 467 // VUID-VkImageCreateInfo-usage-00966 468 assert!(usage.intersects( 469 ImageUsage::COLOR_ATTACHMENT 470 | ImageUsage::DEPTH_STENCIL_ATTACHMENT 471 | ImageUsage::INPUT_ATTACHMENT 472 )); 473 474 // VUID-VkImageCreateInfo-usage-00963 475 assert!((usage 476 - (ImageUsage::TRANSIENT_ATTACHMENT 477 | ImageUsage::COLOR_ATTACHMENT 478 | ImageUsage::DEPTH_STENCIL_ATTACHMENT 479 | ImageUsage::INPUT_ATTACHMENT)) 480 .is_empty()) 481 } 482 483 if has_separate_stencil_usage { 484 // VUID-VkImageCreateInfo-format-02795 485 // VUID-VkImageCreateInfo-format-02796 486 if usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT) 487 != stencil_usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT) 488 { 489 return Err(ImageError::StencilUsageMismatch { 490 usage, 491 stencil_usage, 492 }); 493 } 494 495 // VUID-VkImageCreateInfo-format-02797 496 // VUID-VkImageCreateInfo-format-02798 497 if usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT) 498 != stencil_usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT) 499 { 500 return Err(ImageError::StencilUsageMismatch { 501 usage, 502 stencil_usage, 503 }); 504 } 505 506 if stencil_usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT) { 507 // VUID-VkImageStencilUsageCreateInfo-stencilUsage-02539 508 assert!((stencil_usage 509 - (ImageUsage::TRANSIENT_ATTACHMENT 510 | ImageUsage::DEPTH_STENCIL_ATTACHMENT 511 | ImageUsage::INPUT_ATTACHMENT)) 512 .is_empty()) 513 } 514 } 515 516 /* Check flags requirements */ 517 518 if flags.intersects(ImageCreateFlags::CUBE_COMPATIBLE) { 519 // VUID-VkImageCreateInfo-flags-00949 520 if image_type != ImageType::Dim2d { 521 return Err(ImageError::CubeCompatibleNot2d); 522 } 523 524 // VUID-VkImageCreateInfo-imageType-00954 525 if extent[0] != extent[1] { 526 return Err(ImageError::CubeCompatibleNotSquare); 527 } 528 529 // VUID-VkImageCreateInfo-imageType-00954 530 if array_layers < 6 { 531 return Err(ImageError::CubeCompatibleNotEnoughArrayLayers); 532 } 533 } 534 535 if flags.intersects(ImageCreateFlags::ARRAY_2D_COMPATIBLE) { 536 // VUID-VkImageCreateInfo-flags-00950 537 if image_type != ImageType::Dim3d { 538 return Err(ImageError::Array2dCompatibleNot3d); 539 } 540 541 // VUID-VkImageCreateInfo-imageView2DOn3DImage-04459 542 if device.enabled_extensions().khr_portability_subset 543 && !device.enabled_features().image_view2_d_on3_d_image 544 { 545 return Err(ImageError::RequirementNotMet { 546 required_for: "this device is a portability subset device, and \ 547 `create_info.flags` contains `ImageCreateFlags::ARRAY_2D_COMPATIBLE`", 548 requires_one_of: RequiresOneOf { 549 features: &["image_view2_d_on3_d_image"], 550 ..Default::default() 551 }, 552 }); 553 } 554 } 555 556 if flags.intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE) { 557 // VUID-VkImageCreateInfo-flags-01572 558 if format.compression().is_none() { 559 return Err(ImageError::BlockTexelViewCompatibleNotCompressed); 560 } 561 } 562 563 if flags.intersects(ImageCreateFlags::DISJOINT) { 564 // VUID-VkImageCreateInfo-format-01577 565 if format.planes().len() < 2 { 566 return Err(ImageError::DisjointFormatNotSupported); 567 } 568 569 // VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260 570 if !format_features.intersects(FormatFeatures::DISJOINT) { 571 return Err(ImageError::DisjointFormatNotSupported); 572 } 573 } 574 575 /* Check sharing mode and queue families */ 576 577 match sharing { 578 Sharing::Exclusive => (), 579 Sharing::Concurrent(queue_family_indices) => { 580 // VUID-VkImageCreateInfo-sharingMode-00942 581 assert!(queue_family_indices.len() >= 2); 582 583 for &queue_family_index in queue_family_indices { 584 // VUID-VkImageCreateInfo-sharingMode-01420 585 if queue_family_index 586 >= device.physical_device().queue_family_properties().len() as u32 587 { 588 return Err(ImageError::SharingQueueFamilyIndexOutOfRange { 589 queue_family_index, 590 queue_family_count: device 591 .physical_device() 592 .queue_family_properties() 593 .len() as u32, 594 }); 595 } 596 } 597 } 598 } 599 600 /* External memory handles */ 601 602 if !external_memory_handle_types.is_empty() { 603 if !(device.api_version() >= Version::V1_1 604 || device.enabled_extensions().khr_external_memory) 605 { 606 return Err(ImageError::RequirementNotMet { 607 required_for: "`create_info.external_memory_handle_types` is not empty", 608 requires_one_of: RequiresOneOf { 609 api_version: Some(Version::V1_1), 610 device_extensions: &["khr_external_memory"], 611 ..Default::default() 612 }, 613 }); 614 } 615 616 // VUID-VkExternalMemoryImageCreateInfo-handleTypes-parameter 617 external_memory_handle_types.validate_device(device)?; 618 619 // VUID-VkImageCreateInfo-pNext-01443 620 if initial_layout != ImageLayout::Undefined { 621 return Err(ImageError::ExternalMemoryInvalidInitialLayout); 622 } 623 } 624 625 /* 626 Some device limits can be exceeded, but only for particular image configurations, which 627 must be queried with `image_format_properties`. See: 628 https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap44.html#capabilities-image 629 First, we check if this is the case, then query the device if so. 630 */ 631 632 // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap44.html#features-extentperimagetype 633 let extent_must_query = || match image_type { 634 ImageType::Dim1d => { 635 let limit = device.physical_device().properties().max_image_dimension1_d; 636 extent[0] > limit 637 } 638 ImageType::Dim2d if flags.intersects(ImageCreateFlags::CUBE_COMPATIBLE) => { 639 let limit = device 640 .physical_device() 641 .properties() 642 .max_image_dimension_cube; 643 extent[0] > limit 644 } 645 ImageType::Dim2d => { 646 let limit = device.physical_device().properties().max_image_dimension2_d; 647 extent[0] > limit || extent[1] > limit 648 } 649 ImageType::Dim3d => { 650 let limit = device.physical_device().properties().max_image_dimension3_d; 651 extent[0] > limit || extent[1] > limit || extent[2] > limit 652 } 653 }; 654 // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImageFormatProperties.html 655 let mip_levels_must_query = || { 656 if mip_levels > 1 { 657 // TODO: for external memory, the spec says: 658 // "handle type included in the handleTypes member for which mipmap image support is 659 // not required". But which handle types are those? 660 !external_memory_handle_types.is_empty() 661 } else { 662 false 663 } 664 }; 665 // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImageFormatProperties.html 666 let array_layers_must_query = || { 667 if array_layers > device.physical_device().properties().max_image_array_layers { 668 true 669 } else if array_layers > 1 { 670 image_type == ImageType::Dim3d 671 } else { 672 false 673 } 674 }; 675 // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap44.html#features-supported-sample-counts 676 let samples_must_query = || { 677 if samples == SampleCount::Sample1 { 678 return false; 679 } 680 681 if combined_usage.intersects(ImageUsage::COLOR_ATTACHMENT) 682 && !device_properties 683 .framebuffer_color_sample_counts 684 .contains_enum(samples) 685 { 686 // TODO: how to handle framebuffer_integer_color_sample_counts limit, which only 687 // exists >= Vulkan 1.2 688 return true; 689 } 690 691 if combined_usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT) { 692 if aspects.intersects(ImageAspects::DEPTH) 693 && !device_properties 694 .framebuffer_depth_sample_counts 695 .contains_enum(samples) 696 { 697 return true; 698 } 699 700 if aspects.intersects(ImageAspects::STENCIL) 701 && !device_properties 702 .framebuffer_stencil_sample_counts 703 .contains_enum(samples) 704 { 705 return true; 706 } 707 } 708 709 if combined_usage.intersects(ImageUsage::SAMPLED) { 710 if let Some(numeric_type) = format.type_color() { 711 match numeric_type { 712 NumericType::UINT | NumericType::SINT => { 713 if !device_properties 714 .sampled_image_integer_sample_counts 715 .contains_enum(samples) 716 { 717 return true; 718 } 719 } 720 NumericType::SFLOAT 721 | NumericType::UFLOAT 722 | NumericType::SNORM 723 | NumericType::UNORM 724 | NumericType::SSCALED 725 | NumericType::USCALED 726 | NumericType::SRGB => { 727 if !device_properties 728 .sampled_image_color_sample_counts 729 .contains_enum(samples) 730 { 731 return true; 732 } 733 } 734 } 735 } else { 736 if aspects.intersects(ImageAspects::DEPTH) 737 && !device_properties 738 .sampled_image_depth_sample_counts 739 .contains_enum(samples) 740 { 741 return true; 742 } 743 744 if aspects.intersects(ImageAspects::STENCIL) 745 && device_properties 746 .sampled_image_stencil_sample_counts 747 .contains_enum(samples) 748 { 749 return true; 750 } 751 } 752 } 753 754 if combined_usage.intersects(ImageUsage::STORAGE) 755 && !device_properties 756 .storage_image_sample_counts 757 .contains_enum(samples) 758 { 759 return true; 760 } 761 762 false 763 }; 764 // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImageCreateInfo.html#_description 765 let linear_must_query = || { 766 if tiling == ImageTiling::Linear { 767 !(image_type == ImageType::Dim2d 768 && format.type_color().is_some() 769 && mip_levels == 1 770 && array_layers == 1 771 // VUID-VkImageCreateInfo-samples-02257 already states that multisampling+linear 772 // is invalid so no need to check for that here. 773 && (usage - (ImageUsage::TRANSFER_SRC | ImageUsage::TRANSFER_DST)).is_empty()) 774 } else { 775 false 776 } 777 }; 778 779 let must_query_device = extent_must_query() 780 || mip_levels_must_query() 781 || array_layers_must_query() 782 || samples_must_query() 783 || linear_must_query(); 784 785 // We determined that we must query the device in order to be sure that the image 786 // configuration is supported. 787 if must_query_device { 788 let external_memory_handle_types: SmallVec<[Option<ExternalMemoryHandleType>; 4]> = 789 if !external_memory_handle_types.is_empty() { 790 // If external memory handles are used, the properties need to be queried 791 // individually for each handle type. 792 external_memory_handle_types.into_iter().map(Some).collect() 793 } else { 794 smallvec![None] 795 }; 796 797 for external_memory_handle_type in external_memory_handle_types { 798 // Use unchecked, because all validation has been done above. 799 let image_format_properties = unsafe { 800 device 801 .physical_device() 802 .image_format_properties_unchecked(ImageFormatInfo { 803 flags, 804 format: Some(format), 805 image_type, 806 tiling, 807 usage, 808 external_memory_handle_type, 809 ..Default::default() 810 })? 811 }; 812 813 let ImageFormatProperties { 814 max_extent, 815 max_mip_levels, 816 max_array_layers, 817 sample_counts, 818 max_resource_size: _, 819 .. 820 } = match image_format_properties { 821 Some(x) => x, 822 None => return Err(ImageError::ImageFormatPropertiesNotSupported), 823 }; 824 825 // VUID-VkImageCreateInfo-extent-02252 826 // VUID-VkImageCreateInfo-extent-02253 827 // VUID-VkImageCreateInfo-extent-02254 828 if extent[0] > max_extent[0] 829 || extent[1] > max_extent[1] 830 || extent[2] > max_extent[2] 831 { 832 return Err(ImageError::MaxDimensionsExceeded { 833 extent, 834 max: max_extent, 835 }); 836 } 837 838 // VUID-VkImageCreateInfo-mipLevels-02255 839 if mip_levels > max_mip_levels { 840 return Err(ImageError::MaxMipLevelsExceeded { 841 mip_levels, 842 max: max_mip_levels, 843 }); 844 } 845 846 // VUID-VkImageCreateInfo-arrayLayers-02256 847 if array_layers > max_array_layers { 848 return Err(ImageError::MaxArrayLayersExceeded { 849 array_layers, 850 max: max_array_layers, 851 }); 852 } 853 854 // VUID-VkImageCreateInfo-samples-02258 855 if !sample_counts.contains_enum(samples) { 856 return Err(ImageError::SampleCountNotSupported { 857 samples, 858 supported: sample_counts, 859 }); 860 } 861 862 // TODO: check resource size? 863 } 864 } 865 866 Ok(format_features) 867 } 868 869 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] 870 #[inline] new_unchecked( device: Arc<Device>, create_info: ImageCreateInfo, ) -> Result<Self, VulkanError>871 pub unsafe fn new_unchecked( 872 device: Arc<Device>, 873 create_info: ImageCreateInfo, 874 ) -> Result<Self, VulkanError> { 875 let &ImageCreateInfo { 876 flags, 877 dimensions, 878 format, 879 mip_levels, 880 samples, 881 tiling, 882 usage, 883 mut stencil_usage, 884 ref sharing, 885 initial_layout, 886 external_memory_handle_types, 887 _ne: _, 888 mut image_drm_format_modifier_create_info, 889 } = &create_info; 890 891 let aspects = format.map_or_else(Default::default, |format| format.aspects()); 892 893 let has_separate_stencil_usage = if stencil_usage.is_empty() 894 || !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL) 895 { 896 stencil_usage = usage; 897 false 898 } else { 899 stencil_usage == usage 900 }; 901 902 let (image_type, extent, array_layers) = match dimensions { 903 ImageDimensions::Dim1d { 904 width, 905 array_layers, 906 } => (ImageType::Dim1d, [width, 1, 1], array_layers), 907 ImageDimensions::Dim2d { 908 width, 909 height, 910 array_layers, 911 } => (ImageType::Dim2d, [width, height, 1], array_layers), 912 ImageDimensions::Dim3d { 913 width, 914 height, 915 depth, 916 } => (ImageType::Dim3d, [width, height, depth], 1), 917 }; 918 919 let (sharing_mode, queue_family_index_count, p_queue_family_indices) = match sharing { 920 Sharing::Exclusive => (ash::vk::SharingMode::EXCLUSIVE, 0, &[] as _), 921 Sharing::Concurrent(queue_family_indices) => ( 922 ash::vk::SharingMode::CONCURRENT, 923 queue_family_indices.len() as u32, 924 queue_family_indices.as_ptr(), 925 ), 926 }; 927 928 let mut info_vk = ash::vk::ImageCreateInfo { 929 flags: flags.into(), 930 image_type: image_type.into(), 931 format: format.map(Into::into).unwrap_or_default(), 932 extent: ash::vk::Extent3D { 933 width: extent[0], 934 height: extent[1], 935 depth: extent[2], 936 }, 937 mip_levels, 938 array_layers, 939 samples: samples.into(), 940 tiling: tiling.into(), 941 usage: usage.into(), 942 sharing_mode, 943 queue_family_index_count, 944 p_queue_family_indices, 945 initial_layout: initial_layout.into(), 946 ..Default::default() 947 }; 948 let mut external_memory_info_vk = None; 949 let mut stencil_usage_info_vk = None; 950 951 if !external_memory_handle_types.is_empty() { 952 let next = external_memory_info_vk.insert(ash::vk::ExternalMemoryImageCreateInfo { 953 handle_types: external_memory_handle_types.into(), 954 ..Default::default() 955 }); 956 957 next.p_next = info_vk.p_next; 958 info_vk.p_next = next as *const _ as *const _; 959 } 960 961 if has_separate_stencil_usage { 962 let next = stencil_usage_info_vk.insert(ash::vk::ImageStencilUsageCreateInfo { 963 stencil_usage: stencil_usage.into(), 964 ..Default::default() 965 }); 966 967 next.p_next = info_vk.p_next; 968 info_vk.p_next = next as *const _ as *const _; 969 } 970 971 if external_memory_handle_types.intersects(ExternalMemoryHandleTypes::DMA_BUF) { 972 let next = image_drm_format_modifier_create_info.as_mut().unwrap(); 973 974 next.p_next = info_vk.p_next; 975 info_vk.p_next = next as *const _ as *const _; 976 } 977 978 let handle = { 979 let fns = device.fns(); 980 let mut output = MaybeUninit::uninit(); 981 (fns.v1_0.create_image)(device.handle(), &info_vk, ptr::null(), output.as_mut_ptr()) 982 .result() 983 .map_err(VulkanError::from)?; 984 output.assume_init() 985 }; 986 987 Ok(Self::from_handle(device, handle, create_info)) 988 } 989 990 /// Creates a new `RawImage` from a raw object handle. 991 /// 992 /// # Safety 993 /// 994 /// - `handle` must be a valid Vulkan object handle created from `device`. 995 /// - `handle` must refer to an image that has not yet had memory bound to it. 996 /// - `create_info` must match the info used to create the object. 997 #[inline] from_handle( device: Arc<Device>, handle: ash::vk::Image, create_info: ImageCreateInfo, ) -> Self998 pub unsafe fn from_handle( 999 device: Arc<Device>, 1000 handle: ash::vk::Image, 1001 create_info: ImageCreateInfo, 1002 ) -> Self { 1003 Self::from_handle_with_destruction(device, handle, create_info, true) 1004 } 1005 from_handle_with_destruction( device: Arc<Device>, handle: ash::vk::Image, create_info: ImageCreateInfo, needs_destruction: bool, ) -> Self1006 unsafe fn from_handle_with_destruction( 1007 device: Arc<Device>, 1008 handle: ash::vk::Image, 1009 create_info: ImageCreateInfo, 1010 needs_destruction: bool, 1011 ) -> Self { 1012 let ImageCreateInfo { 1013 flags, 1014 dimensions, 1015 format, 1016 mip_levels, 1017 samples, 1018 tiling, 1019 usage, 1020 mut stencil_usage, 1021 sharing, 1022 initial_layout, 1023 external_memory_handle_types, 1024 _ne: _, 1025 image_drm_format_modifier_create_info: _, 1026 } = create_info; 1027 1028 let aspects = format.map_or_else(Default::default, |format| format.aspects()); 1029 1030 if stencil_usage.is_empty() 1031 || !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL) 1032 { 1033 stencil_usage = usage; 1034 } 1035 1036 // Get format features 1037 let format_features = { 1038 // Use unchecked, because `create_info` is assumed to match the info of the handle, and 1039 // therefore already valid. 1040 let format_properties = device 1041 .physical_device() 1042 .format_properties_unchecked(format.unwrap()); 1043 match tiling { 1044 ImageTiling::Linear => format_properties.linear_tiling_features, 1045 ImageTiling::Optimal => format_properties.optimal_tiling_features, 1046 ImageTiling::DrmFormatModifier => format_properties.linear_tiling_features, // TODO: improve 1047 } 1048 }; 1049 1050 let memory_requirements = if needs_destruction { 1051 if flags.intersects(ImageCreateFlags::DISJOINT) { 1052 (0..format.unwrap().planes().len()) 1053 .map(|plane| Self::get_memory_requirements(&device, handle, Some(plane))) 1054 .collect() 1055 } else { 1056 smallvec![Self::get_memory_requirements(&device, handle, None)] 1057 } 1058 } else { 1059 smallvec![] 1060 }; 1061 1062 RawImage { 1063 handle, 1064 device, 1065 id: Self::next_id(), 1066 flags, 1067 dimensions, 1068 format, 1069 format_features, 1070 mip_levels, 1071 initial_layout, 1072 samples, 1073 tiling, 1074 usage, 1075 stencil_usage, 1076 sharing, 1077 external_memory_handle_types, 1078 memory_requirements, 1079 needs_destruction, 1080 subresource_layout: OnceCache::new(), 1081 } 1082 } 1083 get_memory_requirements( device: &Device, handle: ash::vk::Image, plane: Option<usize>, ) -> MemoryRequirements1084 fn get_memory_requirements( 1085 device: &Device, 1086 handle: ash::vk::Image, 1087 plane: Option<usize>, 1088 ) -> MemoryRequirements { 1089 let mut info_vk = ash::vk::ImageMemoryRequirementsInfo2 { 1090 image: handle, 1091 ..Default::default() 1092 }; 1093 let mut plane_info_vk = None; 1094 1095 if let Some(plane) = plane { 1096 debug_assert!( 1097 device.api_version() >= Version::V1_1 1098 || device.enabled_extensions().khr_get_memory_requirements2 1099 && device.enabled_extensions().khr_sampler_ycbcr_conversion 1100 ); 1101 1102 let next = plane_info_vk.insert(ash::vk::ImagePlaneMemoryRequirementsInfo { 1103 plane_aspect: match plane { 1104 0 => ash::vk::ImageAspectFlags::PLANE_0, 1105 1 => ash::vk::ImageAspectFlags::PLANE_1, 1106 2 => ash::vk::ImageAspectFlags::PLANE_2, 1107 _ => unreachable!(), 1108 }, 1109 ..Default::default() 1110 }); 1111 1112 next.p_next = info_vk.p_next; 1113 info_vk.p_next = next as *mut _ as *mut _; 1114 } 1115 1116 let mut memory_requirements2_vk = ash::vk::MemoryRequirements2::default(); 1117 let mut memory_dedicated_requirements_vk = None; 1118 1119 if device.api_version() >= Version::V1_1 1120 || device.enabled_extensions().khr_dedicated_allocation 1121 { 1122 debug_assert!( 1123 device.api_version() >= Version::V1_1 1124 || device.enabled_extensions().khr_get_memory_requirements2 1125 ); 1126 1127 let next = memory_dedicated_requirements_vk 1128 .insert(ash::vk::MemoryDedicatedRequirements::default()); 1129 1130 next.p_next = memory_requirements2_vk.p_next; 1131 memory_requirements2_vk.p_next = next as *mut _ as *mut _; 1132 } 1133 1134 unsafe { 1135 let fns = device.fns(); 1136 1137 if device.api_version() >= Version::V1_1 1138 || device.enabled_extensions().khr_get_memory_requirements2 1139 { 1140 if device.api_version() >= Version::V1_1 { 1141 (fns.v1_1.get_image_memory_requirements2)( 1142 device.handle(), 1143 &info_vk, 1144 &mut memory_requirements2_vk, 1145 ); 1146 } else { 1147 (fns.khr_get_memory_requirements2 1148 .get_image_memory_requirements2_khr)( 1149 device.handle(), 1150 &info_vk, 1151 &mut memory_requirements2_vk, 1152 ); 1153 } 1154 } else { 1155 (fns.v1_0.get_image_memory_requirements)( 1156 device.handle(), 1157 handle, 1158 &mut memory_requirements2_vk.memory_requirements, 1159 ); 1160 } 1161 } 1162 1163 MemoryRequirements { 1164 layout: DeviceLayout::from_size_alignment( 1165 memory_requirements2_vk.memory_requirements.size, 1166 memory_requirements2_vk.memory_requirements.alignment, 1167 ) 1168 .unwrap(), 1169 memory_type_bits: memory_requirements2_vk.memory_requirements.memory_type_bits, 1170 prefers_dedicated_allocation: memory_dedicated_requirements_vk 1171 .map_or(false, |dreqs| dreqs.prefers_dedicated_allocation != 0), 1172 requires_dedicated_allocation: memory_dedicated_requirements_vk 1173 .map_or(false, |dreqs| dreqs.requires_dedicated_allocation != 0), 1174 } 1175 } 1176 1177 #[inline] 1178 #[allow(dead_code)] // Remove when sparse memory is implemented get_sparse_memory_requirements(&self) -> Vec<SparseImageMemoryRequirements>1179 fn get_sparse_memory_requirements(&self) -> Vec<SparseImageMemoryRequirements> { 1180 let device = &self.device; 1181 1182 unsafe { 1183 let fns = self.device.fns(); 1184 1185 if device.api_version() >= Version::V1_1 1186 || device.enabled_extensions().khr_get_memory_requirements2 1187 { 1188 let info2 = ash::vk::ImageSparseMemoryRequirementsInfo2 { 1189 image: self.handle, 1190 ..Default::default() 1191 }; 1192 1193 let mut count = 0; 1194 1195 if device.api_version() >= Version::V1_1 { 1196 (fns.v1_1.get_image_sparse_memory_requirements2)( 1197 device.handle(), 1198 &info2, 1199 &mut count, 1200 ptr::null_mut(), 1201 ); 1202 } else { 1203 (fns.khr_get_memory_requirements2 1204 .get_image_sparse_memory_requirements2_khr)( 1205 device.handle(), 1206 &info2, 1207 &mut count, 1208 ptr::null_mut(), 1209 ); 1210 } 1211 1212 let mut sparse_image_memory_requirements2 = 1213 vec![ash::vk::SparseImageMemoryRequirements2::default(); count as usize]; 1214 1215 if device.api_version() >= Version::V1_1 { 1216 (fns.v1_1.get_image_sparse_memory_requirements2)( 1217 self.device.handle(), 1218 &info2, 1219 &mut count, 1220 sparse_image_memory_requirements2.as_mut_ptr(), 1221 ); 1222 } else { 1223 (fns.khr_get_memory_requirements2 1224 .get_image_sparse_memory_requirements2_khr)( 1225 self.device.handle(), 1226 &info2, 1227 &mut count, 1228 sparse_image_memory_requirements2.as_mut_ptr(), 1229 ); 1230 } 1231 1232 sparse_image_memory_requirements2.set_len(count as usize); 1233 1234 sparse_image_memory_requirements2 1235 .into_iter() 1236 .map( 1237 |sparse_image_memory_requirements2| SparseImageMemoryRequirements { 1238 format_properties: SparseImageFormatProperties { 1239 aspects: sparse_image_memory_requirements2 1240 .memory_requirements 1241 .format_properties 1242 .aspect_mask 1243 .into(), 1244 image_granularity: [ 1245 sparse_image_memory_requirements2 1246 .memory_requirements 1247 .format_properties 1248 .image_granularity 1249 .width, 1250 sparse_image_memory_requirements2 1251 .memory_requirements 1252 .format_properties 1253 .image_granularity 1254 .height, 1255 sparse_image_memory_requirements2 1256 .memory_requirements 1257 .format_properties 1258 .image_granularity 1259 .depth, 1260 ], 1261 flags: sparse_image_memory_requirements2 1262 .memory_requirements 1263 .format_properties 1264 .flags 1265 .into(), 1266 }, 1267 image_mip_tail_first_lod: sparse_image_memory_requirements2 1268 .memory_requirements 1269 .image_mip_tail_first_lod, 1270 image_mip_tail_size: sparse_image_memory_requirements2 1271 .memory_requirements 1272 .image_mip_tail_size, 1273 image_mip_tail_offset: sparse_image_memory_requirements2 1274 .memory_requirements 1275 .image_mip_tail_offset, 1276 image_mip_tail_stride: (!sparse_image_memory_requirements2 1277 .memory_requirements 1278 .format_properties 1279 .flags 1280 .intersects(ash::vk::SparseImageFormatFlags::SINGLE_MIPTAIL)) 1281 .then_some( 1282 sparse_image_memory_requirements2 1283 .memory_requirements 1284 .image_mip_tail_stride, 1285 ), 1286 }, 1287 ) 1288 .collect() 1289 } else { 1290 let mut count = 0; 1291 1292 (fns.v1_0.get_image_sparse_memory_requirements)( 1293 device.handle(), 1294 self.handle, 1295 &mut count, 1296 ptr::null_mut(), 1297 ); 1298 1299 let mut sparse_image_memory_requirements = 1300 vec![ash::vk::SparseImageMemoryRequirements::default(); count as usize]; 1301 1302 (fns.v1_0.get_image_sparse_memory_requirements)( 1303 device.handle(), 1304 self.handle, 1305 &mut count, 1306 sparse_image_memory_requirements.as_mut_ptr(), 1307 ); 1308 1309 sparse_image_memory_requirements.set_len(count as usize); 1310 1311 sparse_image_memory_requirements 1312 .into_iter() 1313 .map( 1314 |sparse_image_memory_requirements| SparseImageMemoryRequirements { 1315 format_properties: SparseImageFormatProperties { 1316 aspects: sparse_image_memory_requirements 1317 .format_properties 1318 .aspect_mask 1319 .into(), 1320 image_granularity: [ 1321 sparse_image_memory_requirements 1322 .format_properties 1323 .image_granularity 1324 .width, 1325 sparse_image_memory_requirements 1326 .format_properties 1327 .image_granularity 1328 .height, 1329 sparse_image_memory_requirements 1330 .format_properties 1331 .image_granularity 1332 .depth, 1333 ], 1334 flags: sparse_image_memory_requirements 1335 .format_properties 1336 .flags 1337 .into(), 1338 }, 1339 image_mip_tail_first_lod: sparse_image_memory_requirements 1340 .image_mip_tail_first_lod, 1341 image_mip_tail_size: sparse_image_memory_requirements 1342 .image_mip_tail_size, 1343 image_mip_tail_offset: sparse_image_memory_requirements 1344 .image_mip_tail_offset, 1345 image_mip_tail_stride: (!sparse_image_memory_requirements 1346 .format_properties 1347 .flags 1348 .intersects(ash::vk::SparseImageFormatFlags::SINGLE_MIPTAIL)) 1349 .then_some(sparse_image_memory_requirements.image_mip_tail_stride), 1350 }, 1351 ) 1352 .collect() 1353 } 1354 } 1355 } 1356 id(&self) -> NonZeroU641357 pub(crate) fn id(&self) -> NonZeroU64 { 1358 self.id 1359 } 1360 1361 /// Binds device memory to this image. 1362 /// 1363 /// - If `self.flags().disjoint` is not set, then `allocations` must contain exactly one 1364 /// element. This element may be a dedicated allocation. 1365 /// - If `self.flags().disjoint` is set, then `allocations` must contain exactly 1366 /// `self.format().unwrap().planes().len()` elements. These elements must not be dedicated 1367 /// allocations. bind_memory( self, allocations: impl IntoIterator<Item = MemoryAlloc>, ) -> Result< Image, ( ImageError, RawImage, impl ExactSizeIterator<Item = MemoryAlloc>, ), >1368 pub fn bind_memory( 1369 self, 1370 allocations: impl IntoIterator<Item = MemoryAlloc>, 1371 ) -> Result< 1372 Image, 1373 ( 1374 ImageError, 1375 RawImage, 1376 impl ExactSizeIterator<Item = MemoryAlloc>, 1377 ), 1378 > { 1379 let allocations: SmallVec<[_; 3]> = allocations.into_iter().collect(); 1380 1381 if let Err(err) = self.validate_bind_memory(&allocations) { 1382 return Err((err, self, allocations.into_iter())); 1383 } 1384 1385 unsafe { self.bind_memory_unchecked(allocations) }.map_err(|(err, image, allocations)| { 1386 ( 1387 err.into(), 1388 image, 1389 allocations 1390 .into_iter() 1391 .collect::<SmallVec<[_; 3]>>() 1392 .into_iter(), 1393 ) 1394 }) 1395 } 1396 validate_bind_memory(&self, allocations: &[MemoryAlloc]) -> Result<(), ImageError>1397 fn validate_bind_memory(&self, allocations: &[MemoryAlloc]) -> Result<(), ImageError> { 1398 if self.flags.intersects(ImageCreateFlags::DISJOINT) { 1399 if allocations.len() != self.format.unwrap().planes().len() { 1400 return Err(ImageError::AllocationsWrongNumberOfElements { 1401 provided: allocations.len(), 1402 required: self.format.unwrap().planes().len(), 1403 }); 1404 } 1405 } else { 1406 if allocations.len() != 1 { 1407 return Err(ImageError::AllocationsWrongNumberOfElements { 1408 provided: allocations.len(), 1409 required: 1, 1410 }); 1411 } 1412 } 1413 1414 for (allocations_index, (allocation, memory_requirements)) in (allocations.iter()) 1415 .zip(self.memory_requirements.iter()) 1416 .enumerate() 1417 { 1418 assert_ne!(allocation.allocation_type(), AllocationType::Linear); 1419 1420 let memory = allocation.device_memory(); 1421 let memory_offset = allocation.offset(); 1422 let memory_type = &self 1423 .device 1424 .physical_device() 1425 .memory_properties() 1426 .memory_types[memory.memory_type_index() as usize]; 1427 1428 // VUID-VkBindImageMemoryInfo-commonparent 1429 assert_eq!(self.device(), memory.device()); 1430 1431 // VUID-VkBindImageMemoryInfo-image-07460 1432 // Ensured by taking ownership of `RawImage`. 1433 1434 // VUID-VkBindImageMemoryInfo-image-01045 1435 // Currently ensured by not having sparse binding flags, but this needs to be checked 1436 // once those are enabled. 1437 1438 // VUID-VkBindImageMemoryInfo-memoryOffset-01046 1439 // Assume that `allocation` was created correctly. 1440 1441 if let Some(dedicated_to) = memory.dedicated_to() { 1442 // VUID-VkBindImageMemoryInfo-memory-02628 1443 match dedicated_to { 1444 DedicatedTo::Image(id) if id == self.id => {} 1445 _ => return Err(ImageError::DedicatedAllocationMismatch), 1446 } 1447 debug_assert!(memory_offset == 0); // This should be ensured by the allocator 1448 } else { 1449 // VUID-VkBindImageMemoryInfo-image-01445 1450 if memory_requirements.requires_dedicated_allocation { 1451 return Err(ImageError::DedicatedAllocationRequired); 1452 } 1453 } 1454 1455 // VUID-VkBindImageMemoryInfo-None-01901 1456 if memory_type 1457 .property_flags 1458 .intersects(MemoryPropertyFlags::PROTECTED) 1459 { 1460 return Err(ImageError::MemoryProtectedMismatch { 1461 allocations_index, 1462 image_protected: false, 1463 memory_protected: true, 1464 }); 1465 } 1466 1467 // VUID-VkBindImageMemoryInfo-memory-02728 1468 if !memory.export_handle_types().is_empty() 1469 && !memory 1470 .export_handle_types() 1471 .intersects(self.external_memory_handle_types) 1472 { 1473 return Err(ImageError::MemoryExternalHandleTypesDisjoint { 1474 allocations_index, 1475 image_handle_types: self.external_memory_handle_types, 1476 memory_export_handle_types: memory.export_handle_types(), 1477 }); 1478 } 1479 1480 if let Some(handle_type) = memory.imported_handle_type() { 1481 // VUID-VkBindImageMemoryInfo-memory-02989 1482 if !ExternalMemoryHandleTypes::from(handle_type) 1483 .intersects(self.external_memory_handle_types) 1484 { 1485 return Err(ImageError::MemoryImportedHandleTypeNotEnabled { 1486 allocations_index, 1487 image_handle_types: self.external_memory_handle_types, 1488 memory_imported_handle_type: handle_type, 1489 }); 1490 } 1491 } 1492 1493 // VUID-VkBindImageMemoryInfo-pNext-01615 1494 // VUID-VkBindImageMemoryInfo-pNext-01619 1495 if memory_requirements.memory_type_bits & (1 << memory.memory_type_index()) == 0 { 1496 return Err(ImageError::MemoryTypeNotAllowed { 1497 allocations_index, 1498 provided_memory_type_index: memory.memory_type_index(), 1499 allowed_memory_type_bits: memory_requirements.memory_type_bits, 1500 }); 1501 } 1502 1503 // VUID-VkBindImageMemoryInfo-pNext-01616 1504 // VUID-VkBindImageMemoryInfo-pNext-01620 1505 if !is_aligned(memory_offset, memory_requirements.layout.alignment()) { 1506 return Err(ImageError::MemoryAllocationNotAligned { 1507 allocations_index, 1508 allocation_offset: memory_offset, 1509 required_alignment: memory_requirements.layout.alignment(), 1510 }); 1511 } 1512 1513 // VUID-VkBindImageMemoryInfo-pNext-01617 1514 // VUID-VkBindImageMemoryInfo-pNext-01621 1515 if allocation.size() < memory_requirements.layout.size() { 1516 return Err(ImageError::MemoryAllocationTooSmall { 1517 allocations_index, 1518 allocation_size: allocation.size(), 1519 required_size: memory_requirements.layout.size(), 1520 }); 1521 } 1522 } 1523 1524 Ok(()) 1525 } 1526 1527 /// # Safety 1528 /// 1529 /// - If `self.flags().disjoint` is not set, then `allocations` must contain exactly one 1530 /// element. 1531 /// - If `self.flags().disjoint` is set, then `allocations` must contain exactly 1532 /// `self.format().unwrap().planes().len()` elements. 1533 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] bind_memory_unchecked( self, allocations: impl IntoIterator<Item = MemoryAlloc>, ) -> Result< Image, ( VulkanError, RawImage, impl ExactSizeIterator<Item = MemoryAlloc>, ), >1534 pub unsafe fn bind_memory_unchecked( 1535 self, 1536 allocations: impl IntoIterator<Item = MemoryAlloc>, 1537 ) -> Result< 1538 Image, 1539 ( 1540 VulkanError, 1541 RawImage, 1542 impl ExactSizeIterator<Item = MemoryAlloc>, 1543 ), 1544 > { 1545 let allocations: SmallVec<[_; 3]> = allocations.into_iter().collect(); 1546 let fns = self.device.fns(); 1547 1548 let result = if self.device.api_version() >= Version::V1_1 1549 || self.device.enabled_extensions().khr_bind_memory2 1550 { 1551 let mut infos_vk: SmallVec<[_; 3]> = SmallVec::with_capacity(3); 1552 let mut plane_infos_vk: SmallVec<[_; 3]> = SmallVec::with_capacity(3); 1553 1554 if self.flags.intersects(ImageCreateFlags::DISJOINT) { 1555 debug_assert_eq!(allocations.len(), self.format.unwrap().planes().len()); 1556 1557 for (plane, allocation) in allocations.iter().enumerate() { 1558 let memory = allocation.device_memory(); 1559 let memory_offset = allocation.offset(); 1560 1561 infos_vk.push(ash::vk::BindImageMemoryInfo { 1562 image: self.handle, 1563 memory: memory.handle(), 1564 memory_offset, 1565 ..Default::default() 1566 }); 1567 // VUID-VkBindImageMemoryInfo-pNext-01618 1568 plane_infos_vk.push(ash::vk::BindImagePlaneMemoryInfo { 1569 plane_aspect: match plane { 1570 0 => ash::vk::ImageAspectFlags::PLANE_0, 1571 1 => ash::vk::ImageAspectFlags::PLANE_1, 1572 2 => ash::vk::ImageAspectFlags::PLANE_2, 1573 _ => unreachable!(), 1574 }, 1575 ..Default::default() 1576 }); 1577 } 1578 } else { 1579 debug_assert_eq!(allocations.len(), 1); 1580 1581 let allocation = &allocations[0]; 1582 let memory = allocation.device_memory(); 1583 let memory_offset = allocation.offset(); 1584 1585 infos_vk.push(ash::vk::BindImageMemoryInfo { 1586 image: self.handle, 1587 memory: memory.handle(), 1588 memory_offset, 1589 ..Default::default() 1590 }); 1591 }; 1592 1593 for (info_vk, plane_info_vk) in (infos_vk.iter_mut()).zip(plane_infos_vk.iter_mut()) { 1594 info_vk.p_next = plane_info_vk as *mut _ as *mut _; 1595 } 1596 1597 if self.device.api_version() >= Version::V1_1 { 1598 (fns.v1_1.bind_image_memory2)( 1599 self.device.handle(), 1600 infos_vk.len() as u32, 1601 infos_vk.as_ptr(), 1602 ) 1603 } else { 1604 (fns.khr_bind_memory2.bind_image_memory2_khr)( 1605 self.device.handle(), 1606 infos_vk.len() as u32, 1607 infos_vk.as_ptr(), 1608 ) 1609 } 1610 } else { 1611 debug_assert_eq!(allocations.len(), 1); 1612 1613 let allocation = &allocations[0]; 1614 let memory = allocation.device_memory(); 1615 let memory_offset = allocation.offset(); 1616 1617 (fns.v1_0.bind_image_memory)( 1618 self.device.handle(), 1619 self.handle, 1620 memory.handle(), 1621 memory_offset, 1622 ) 1623 } 1624 .result(); 1625 1626 if let Err(err) = result { 1627 return Err((VulkanError::from(err), self, allocations.into_iter())); 1628 } 1629 1630 Ok(Image::from_raw(self, ImageMemory::Normal(allocations))) 1631 } 1632 1633 /// Returns the memory requirements for this image. 1634 /// 1635 /// - If the image is a swapchain image, this returns a slice with a length of 0. 1636 /// - If `self.flags().disjoint` is not set, this returns a slice with a length of 1. 1637 /// - If `self.flags().disjoint` is set, this returns a slice with a length equal to 1638 /// `self.format().unwrap().planes().len()`. 1639 #[inline] memory_requirements(&self) -> &[MemoryRequirements]1640 pub fn memory_requirements(&self) -> &[MemoryRequirements] { 1641 &self.memory_requirements 1642 } 1643 1644 /// Returns the flags the image was created with. 1645 #[inline] flags(&self) -> ImageCreateFlags1646 pub fn flags(&self) -> ImageCreateFlags { 1647 self.flags 1648 } 1649 1650 /// Returns the dimensions of the image. 1651 #[inline] dimensions(&self) -> ImageDimensions1652 pub fn dimensions(&self) -> ImageDimensions { 1653 self.dimensions 1654 } 1655 1656 /// Returns the image's format. 1657 #[inline] format(&self) -> Option<Format>1658 pub fn format(&self) -> Option<Format> { 1659 self.format 1660 } 1661 1662 /// Returns the features supported by the image's format. 1663 #[inline] format_features(&self) -> FormatFeatures1664 pub fn format_features(&self) -> FormatFeatures { 1665 self.format_features 1666 } 1667 1668 /// Returns the number of mipmap levels in the image. 1669 #[inline] mip_levels(&self) -> u321670 pub fn mip_levels(&self) -> u32 { 1671 self.mip_levels 1672 } 1673 1674 /// Returns the initial layout of the image. 1675 #[inline] initial_layout(&self) -> ImageLayout1676 pub fn initial_layout(&self) -> ImageLayout { 1677 self.initial_layout 1678 } 1679 1680 /// Returns the number of samples for the image. 1681 #[inline] samples(&self) -> SampleCount1682 pub fn samples(&self) -> SampleCount { 1683 self.samples 1684 } 1685 1686 /// Returns the tiling of the image. 1687 #[inline] tiling(&self) -> ImageTiling1688 pub fn tiling(&self) -> ImageTiling { 1689 self.tiling 1690 } 1691 1692 /// Returns the usage the image was created with. 1693 #[inline] usage(&self) -> ImageUsage1694 pub fn usage(&self) -> ImageUsage { 1695 self.usage 1696 } 1697 1698 /// Returns the stencil usage the image was created with. 1699 #[inline] stencil_usage(&self) -> ImageUsage1700 pub fn stencil_usage(&self) -> ImageUsage { 1701 self.stencil_usage 1702 } 1703 1704 /// Returns the sharing the image was created with. 1705 #[inline] sharing(&self) -> &Sharing<SmallVec<[u32; 4]>>1706 pub fn sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> { 1707 &self.sharing 1708 } 1709 1710 /// Returns the external memory handle types that are supported with this image. 1711 #[inline] external_memory_handle_types(&self) -> ExternalMemoryHandleTypes1712 pub fn external_memory_handle_types(&self) -> ExternalMemoryHandleTypes { 1713 self.external_memory_handle_types 1714 } 1715 1716 /// Returns an `ImageSubresourceLayers` covering the first mip level of the image. All aspects 1717 /// of the image are selected, or `plane0` if the image is multi-planar. 1718 #[inline] subresource_layers(&self) -> ImageSubresourceLayers1719 pub fn subresource_layers(&self) -> ImageSubresourceLayers { 1720 ImageSubresourceLayers { 1721 aspects: { 1722 let aspects = self.format.unwrap().aspects(); 1723 1724 if aspects.intersects(ImageAspects::PLANE_0) { 1725 ImageAspects::PLANE_0 1726 } else { 1727 aspects 1728 } 1729 }, 1730 mip_level: 0, 1731 array_layers: 0..self.dimensions.array_layers(), 1732 } 1733 } 1734 1735 /// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar, 1736 /// only the `color` aspect is selected. 1737 #[inline] subresource_range(&self) -> ImageSubresourceRange1738 pub fn subresource_range(&self) -> ImageSubresourceRange { 1739 ImageSubresourceRange { 1740 aspects: self.format.unwrap().aspects() 1741 - (ImageAspects::PLANE_0 | ImageAspects::PLANE_1 | ImageAspects::PLANE_2), 1742 mip_levels: 0..self.mip_levels, 1743 array_layers: 0..self.dimensions.array_layers(), 1744 } 1745 } 1746 1747 /// Queries the memory layout of a single subresource of the image. 1748 /// 1749 /// Only images with linear tiling are supported, if they do not have a format with both a 1750 /// depth and a stencil format. Images with optimal tiling have an opaque image layout that is 1751 /// not suitable for direct memory accesses, and likewise for combined depth/stencil formats. 1752 /// Multi-planar formats are supported, but you must specify one of the planes as the `aspect`, 1753 /// not [`ImageAspect::Color`]. 1754 /// 1755 /// The results of this function are cached, so that future calls with the same arguments 1756 /// do not need to make a call to the Vulkan API again. subresource_layout( &self, aspect: ImageAspect, mip_level: u32, array_layer: u32, ) -> Result<SubresourceLayout, ImageError>1757 pub fn subresource_layout( 1758 &self, 1759 aspect: ImageAspect, 1760 mip_level: u32, 1761 array_layer: u32, 1762 ) -> Result<SubresourceLayout, ImageError> { 1763 self.validate_subresource_layout(aspect, mip_level, array_layer)?; 1764 1765 unsafe { Ok(self.subresource_layout_unchecked(aspect, mip_level, array_layer)) } 1766 } 1767 validate_subresource_layout( &self, aspect: ImageAspect, mip_level: u32, array_layer: u32, ) -> Result<(), ImageError>1768 fn validate_subresource_layout( 1769 &self, 1770 aspect: ImageAspect, 1771 mip_level: u32, 1772 array_layer: u32, 1773 ) -> Result<(), ImageError> { 1774 // VUID-VkImageSubresource-aspectMask-parameter 1775 aspect.validate_device(&self.device)?; 1776 1777 // VUID-VkImageSubresource-aspectMask-requiredbitmask 1778 // VUID-vkGetImageSubresourceLayout-aspectMask-00997 1779 // Ensured by use of enum `ImageAspect`. 1780 1781 // VUID-vkGetImageSubresourceLayout-image-02270 1782 if !matches!( 1783 self.tiling, 1784 ImageTiling::DrmFormatModifier | ImageTiling::Linear 1785 ) { 1786 return Err(ImageError::OptimalTilingNotSupported); 1787 } 1788 1789 // VUID-vkGetImageSubresourceLayout-mipLevel-01716 1790 if mip_level >= self.mip_levels { 1791 return Err(ImageError::MipLevelOutOfRange { 1792 provided_mip_level: mip_level, 1793 image_mip_levels: self.mip_levels, 1794 }); 1795 } 1796 1797 // VUID-vkGetImageSubresourceLayout-arrayLayer-01717 1798 if array_layer >= self.dimensions.array_layers() { 1799 return Err(ImageError::ArrayLayerOutOfRange { 1800 provided_array_layer: array_layer, 1801 image_array_layers: self.dimensions.array_layers(), 1802 }); 1803 } 1804 1805 let mut allowed_aspects = self.format.unwrap().aspects(); 1806 1807 // Follows from the combination of these three VUIDs. See: 1808 // https://github.com/KhronosGroup/Vulkan-Docs/issues/1942 1809 // VUID-vkGetImageSubresourceLayout-aspectMask-00997 1810 // VUID-vkGetImageSubresourceLayout-format-04462 1811 // VUID-vkGetImageSubresourceLayout-format-04463 1812 if allowed_aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL) { 1813 return Err(ImageError::DepthStencilFormatsNotSupported); 1814 } 1815 1816 if allowed_aspects 1817 .intersects(ImageAspects::PLANE_0 | ImageAspects::PLANE_1 | ImageAspects::PLANE_2) 1818 { 1819 allowed_aspects -= ImageAspects::COLOR; 1820 } 1821 1822 // TODO: VUID-vkGetImageSubresourceLayout-tiling-02271 1823 //if self.tiling == ImageTiling::DrmFormatModifier { 1824 // Only one-plane image importing is possible for now. 1825 //} 1826 1827 // VUID-vkGetImageSubresourceLayout-format-04461 1828 // VUID-vkGetImageSubresourceLayout-format-04462 1829 // VUID-vkGetImageSubresourceLayout-format-04463 1830 // VUID-vkGetImageSubresourceLayout-format-04464 1831 // VUID-vkGetImageSubresourceLayout-format-01581 1832 // VUID-vkGetImageSubresourceLayout-format-01582 1833 if !allowed_aspects.contains(aspect.into()) { 1834 return Err(ImageError::AspectNotAllowed { 1835 provided_aspect: aspect, 1836 allowed_aspects, 1837 }); 1838 } 1839 1840 Ok(()) 1841 } 1842 1843 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] subresource_layout_unchecked( &self, aspect: ImageAspect, mip_level: u32, array_layer: u32, ) -> SubresourceLayout1844 pub unsafe fn subresource_layout_unchecked( 1845 &self, 1846 aspect: ImageAspect, 1847 mip_level: u32, 1848 array_layer: u32, 1849 ) -> SubresourceLayout { 1850 self.subresource_layout.get_or_insert( 1851 (aspect, mip_level, array_layer), 1852 |&(aspect, mip_level, array_layer)| { 1853 let fns = self.device.fns(); 1854 1855 let subresource = ash::vk::ImageSubresource { 1856 aspect_mask: aspect.into(), 1857 mip_level, 1858 array_layer, 1859 }; 1860 1861 let mut output = MaybeUninit::uninit(); 1862 (fns.v1_0.get_image_subresource_layout)( 1863 self.device.handle(), 1864 self.handle, 1865 &subresource, 1866 output.as_mut_ptr(), 1867 ); 1868 let output = output.assume_init(); 1869 1870 SubresourceLayout { 1871 offset: output.offset, 1872 size: output.size, 1873 row_pitch: output.row_pitch, 1874 array_pitch: (self.dimensions.array_layers() > 1).then_some(output.array_pitch), 1875 depth_pitch: matches!(self.dimensions, ImageDimensions::Dim3d { .. }) 1876 .then_some(output.depth_pitch), 1877 } 1878 }, 1879 ) 1880 } 1881 } 1882 1883 impl Drop for RawImage { 1884 #[inline] drop(&mut self)1885 fn drop(&mut self) { 1886 if !self.needs_destruction { 1887 return; 1888 } 1889 1890 unsafe { 1891 let fns = self.device.fns(); 1892 (fns.v1_0.destroy_image)(self.device.handle(), self.handle, ptr::null()); 1893 } 1894 } 1895 } 1896 1897 unsafe impl VulkanObject for RawImage { 1898 type Handle = ash::vk::Image; 1899 1900 #[inline] handle(&self) -> Self::Handle1901 fn handle(&self) -> Self::Handle { 1902 self.handle 1903 } 1904 } 1905 1906 unsafe impl DeviceOwned for RawImage { 1907 #[inline] device(&self) -> &Arc<Device>1908 fn device(&self) -> &Arc<Device> { 1909 &self.device 1910 } 1911 } 1912 1913 impl_id_counter!(RawImage); 1914 1915 /// Parameters to create a new `Image`. 1916 #[derive(Clone, Debug)] 1917 pub struct ImageCreateInfo { 1918 /// Flags to enable. 1919 /// 1920 /// The default value is [`ImageCreateFlags::empty()`]. 1921 pub flags: ImageCreateFlags, 1922 1923 /// The type, extent and number of array layers to create the image with. 1924 /// 1925 /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag) 1926 /// devices, if `samples` is not [`SampleCount::Sample1`] and `dimensions.array_layers()` is 1927 /// not 1, the [`multisample_array_image`](crate::device::Features::multisample_array_image) 1928 /// feature must be enabled on the device. 1929 /// 1930 /// The default value is `ImageDimensions::Dim2d { width: 0, height: 0, array_layers: 1 }`, 1931 /// which must be overridden. 1932 pub dimensions: ImageDimensions, 1933 1934 /// The format used to store the image data. 1935 /// 1936 /// The default value is `None`, which must be overridden. 1937 pub format: Option<Format>, 1938 1939 /// The number of mip levels to create the image with. 1940 /// 1941 /// The default value is `1`. 1942 pub mip_levels: u32, 1943 1944 /// The number of samples per texel that the image should use. 1945 /// 1946 /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag) 1947 /// devices, if `samples` is not [`SampleCount::Sample1`] and `dimensions.array_layers()` is 1948 /// not 1, the [`multisample_array_image`](crate::device::Features::multisample_array_image) 1949 /// feature must be enabled on the device. 1950 /// 1951 /// The default value is [`SampleCount::Sample1`]. 1952 pub samples: SampleCount, 1953 1954 /// The memory arrangement of the texel blocks. 1955 /// 1956 /// The default value is [`ImageTiling::Optimal`]. 1957 pub tiling: ImageTiling, 1958 1959 /// How the image is going to be used. 1960 /// 1961 /// The default value is [`ImageUsage::empty()`], which must be overridden. 1962 pub usage: ImageUsage, 1963 1964 /// How the stencil aspect of the image is going to be used, if any. 1965 /// 1966 /// If `stencil_usage` is empty or if `format` does not have both a depth and a stencil aspect, 1967 /// then it is automatically set to equal `usage`. 1968 /// 1969 /// If after this, `stencil_usage` does not equal `usage`, 1970 /// then the device API version must be at least 1.2, or the 1971 /// [`ext_separate_stencil_usage`](crate::device::DeviceExtensions::ext_separate_stencil_usage) 1972 /// extension must be enabled on the device. 1973 /// 1974 /// The default value is [`ImageUsage::empty()`]. 1975 pub stencil_usage: ImageUsage, 1976 1977 /// Whether the image can be shared across multiple queues, or is limited to a single queue. 1978 /// 1979 /// The default value is [`Sharing::Exclusive`]. 1980 pub sharing: Sharing<SmallVec<[u32; 4]>>, 1981 1982 /// The image layout that the image will have when it is created. 1983 /// 1984 /// The default value is [`ImageLayout::Undefined`]. 1985 pub initial_layout: ImageLayout, 1986 1987 /// The external memory handle types that are going to be used with the image. 1988 /// 1989 /// If any of the fields in this value are set, the device must either support API version 1.1 1990 /// or the [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory) 1991 /// extension must be enabled, and `initial_layout` must be set to 1992 /// [`ImageLayout::Undefined`]. 1993 /// 1994 /// The default value is [`ExternalMemoryHandleTypes::empty()`]. 1995 pub external_memory_handle_types: ExternalMemoryHandleTypes, 1996 1997 /// Specify that an image be created with the provided DRM format modifier and explicit memory layout 1998 pub image_drm_format_modifier_create_info: Option<ImageDrmFormatModifierExplicitCreateInfoEXT>, 1999 2000 pub _ne: crate::NonExhaustive, 2001 } 2002 2003 impl Default for ImageCreateInfo { 2004 #[inline] default() -> Self2005 fn default() -> Self { 2006 Self { 2007 flags: ImageCreateFlags::empty(), 2008 dimensions: ImageDimensions::Dim2d { 2009 width: 0, 2010 height: 0, 2011 array_layers: 1, 2012 }, 2013 format: None, 2014 mip_levels: 1, 2015 samples: SampleCount::Sample1, 2016 tiling: ImageTiling::Optimal, 2017 usage: ImageUsage::empty(), 2018 stencil_usage: ImageUsage::empty(), 2019 sharing: Sharing::Exclusive, 2020 initial_layout: ImageLayout::Undefined, 2021 external_memory_handle_types: ExternalMemoryHandleTypes::empty(), 2022 image_drm_format_modifier_create_info: None, 2023 _ne: crate::NonExhaustive(()), 2024 } 2025 } 2026 } 2027 2028 /// A multi-dimensioned storage for texel data. 2029 /// 2030 /// Unlike [`RawImage`], an `Image` has memory backing it, and can be used normally. 2031 #[derive(Debug)] 2032 pub struct Image { 2033 inner: RawImage, 2034 memory: ImageMemory, 2035 2036 aspect_list: SmallVec<[ImageAspect; 4]>, 2037 aspect_size: DeviceSize, 2038 mip_level_size: DeviceSize, 2039 range_size: DeviceSize, 2040 state: Mutex<ImageState>, 2041 } 2042 2043 /// The type of backing memory that an image can have. 2044 #[derive(Debug)] 2045 pub enum ImageMemory { 2046 /// The image is backed by normal memory, bound with [`bind_memory`]. 2047 /// 2048 /// [`bind_memory`]: RawImage::bind_memory 2049 Normal(SmallVec<[MemoryAlloc; 3]>), 2050 2051 /// The image is backed by sparse memory, bound with [`bind_sparse`]. 2052 /// 2053 /// [`bind_sparse`]: crate::device::QueueGuard::bind_sparse 2054 Sparse(Vec<SparseImageMemoryRequirements>), 2055 2056 /// The image is backed by memory owned by a [`Swapchain`]. 2057 Swapchain { 2058 swapchain: Arc<Swapchain>, 2059 image_index: u32, 2060 }, 2061 } 2062 2063 impl Image { from_raw(inner: RawImage, memory: ImageMemory) -> Self2064 fn from_raw(inner: RawImage, memory: ImageMemory) -> Self { 2065 let aspects = inner.format.unwrap().aspects(); 2066 let aspect_list: SmallVec<[ImageAspect; 4]> = aspects.into_iter().collect(); 2067 let mip_level_size = inner.dimensions.array_layers() as DeviceSize; 2068 let aspect_size = mip_level_size * inner.mip_levels as DeviceSize; 2069 let range_size = aspect_list.len() as DeviceSize * aspect_size; 2070 let state = Mutex::new(ImageState::new(range_size, inner.initial_layout)); 2071 2072 Image { 2073 inner, 2074 memory, 2075 2076 aspect_list, 2077 aspect_size, 2078 mip_level_size, 2079 range_size, 2080 state, 2081 } 2082 } 2083 from_swapchain( handle: ash::vk::Image, swapchain: Arc<Swapchain>, image_index: u32, ) -> Self2084 pub(crate) unsafe fn from_swapchain( 2085 handle: ash::vk::Image, 2086 swapchain: Arc<Swapchain>, 2087 image_index: u32, 2088 ) -> Self { 2089 let create_info = ImageCreateInfo { 2090 flags: ImageCreateFlags::empty(), 2091 dimensions: ImageDimensions::Dim2d { 2092 width: swapchain.image_extent()[0], 2093 height: swapchain.image_extent()[1], 2094 array_layers: swapchain.image_array_layers(), 2095 }, 2096 format: Some(swapchain.image_format()), 2097 initial_layout: ImageLayout::Undefined, 2098 mip_levels: 1, 2099 samples: SampleCount::Sample1, 2100 tiling: ImageTiling::Optimal, 2101 usage: swapchain.image_usage(), 2102 stencil_usage: swapchain.image_usage(), 2103 sharing: swapchain.image_sharing().clone(), 2104 ..Default::default() 2105 }; 2106 2107 Self::from_raw( 2108 RawImage::from_handle_with_destruction( 2109 swapchain.device().clone(), 2110 handle, 2111 create_info, 2112 false, 2113 ), 2114 ImageMemory::Swapchain { 2115 swapchain, 2116 image_index, 2117 }, 2118 ) 2119 } 2120 2121 /// Returns the type of memory that is backing this image. 2122 #[inline] memory(&self) -> &ImageMemory2123 pub fn memory(&self) -> &ImageMemory { 2124 &self.memory 2125 } 2126 2127 /// Returns the memory requirements for this image. 2128 /// 2129 /// - If the image is a swapchain image, this returns a slice with a length of 0. 2130 /// - If `self.flags().disjoint` is not set, this returns a slice with a length of 1. 2131 /// - If `self.flags().disjoint` is set, this returns a slice with a length equal to 2132 /// `self.format().unwrap().planes().len()`. 2133 #[inline] memory_requirements(&self) -> &[MemoryRequirements]2134 pub fn memory_requirements(&self) -> &[MemoryRequirements] { 2135 &self.inner.memory_requirements 2136 } 2137 2138 /// Returns the flags the image was created with. 2139 #[inline] flags(&self) -> ImageCreateFlags2140 pub fn flags(&self) -> ImageCreateFlags { 2141 self.inner.flags 2142 } 2143 2144 /// Returns the dimensions of the image. 2145 #[inline] dimensions(&self) -> ImageDimensions2146 pub fn dimensions(&self) -> ImageDimensions { 2147 self.inner.dimensions 2148 } 2149 2150 /// Returns the image's format. 2151 #[inline] format(&self) -> Option<Format>2152 pub fn format(&self) -> Option<Format> { 2153 self.inner.format 2154 } 2155 2156 /// Returns the features supported by the image's format. 2157 #[inline] format_features(&self) -> FormatFeatures2158 pub fn format_features(&self) -> FormatFeatures { 2159 self.inner.format_features 2160 } 2161 2162 /// Returns the number of mipmap levels in the image. 2163 #[inline] mip_levels(&self) -> u322164 pub fn mip_levels(&self) -> u32 { 2165 self.inner.mip_levels 2166 } 2167 2168 /// Returns the initial layout of the image. 2169 #[inline] initial_layout(&self) -> ImageLayout2170 pub fn initial_layout(&self) -> ImageLayout { 2171 self.inner.initial_layout 2172 } 2173 2174 /// Returns the number of samples for the image. 2175 #[inline] samples(&self) -> SampleCount2176 pub fn samples(&self) -> SampleCount { 2177 self.inner.samples 2178 } 2179 2180 /// Returns the tiling of the image. 2181 #[inline] tiling(&self) -> ImageTiling2182 pub fn tiling(&self) -> ImageTiling { 2183 self.inner.tiling 2184 } 2185 2186 /// Returns the usage the image was created with. 2187 #[inline] usage(&self) -> ImageUsage2188 pub fn usage(&self) -> ImageUsage { 2189 self.inner.usage 2190 } 2191 2192 /// Returns the stencil usage the image was created with. 2193 #[inline] stencil_usage(&self) -> ImageUsage2194 pub fn stencil_usage(&self) -> ImageUsage { 2195 self.inner.stencil_usage 2196 } 2197 2198 /// Returns the sharing the image was created with. 2199 #[inline] sharing(&self) -> &Sharing<SmallVec<[u32; 4]>>2200 pub fn sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> { 2201 &self.inner.sharing 2202 } 2203 2204 /// Returns the external memory handle types that are supported with this image. 2205 #[inline] external_memory_handle_types(&self) -> ExternalMemoryHandleTypes2206 pub fn external_memory_handle_types(&self) -> ExternalMemoryHandleTypes { 2207 self.inner.external_memory_handle_types 2208 } 2209 2210 /// Returns an `ImageSubresourceLayers` covering the first mip level of the image. All aspects 2211 /// of the image are selected, or `plane0` if the image is multi-planar. 2212 #[inline] subresource_layers(&self) -> ImageSubresourceLayers2213 pub fn subresource_layers(&self) -> ImageSubresourceLayers { 2214 self.inner.subresource_layers() 2215 } 2216 2217 /// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar, 2218 /// only the `color` aspect is selected. 2219 #[inline] subresource_range(&self) -> ImageSubresourceRange2220 pub fn subresource_range(&self) -> ImageSubresourceRange { 2221 self.inner.subresource_range() 2222 } 2223 2224 /// Queries the memory layout of a single subresource of the image. 2225 /// 2226 /// Only images with linear tiling are supported, if they do not have a format with both a 2227 /// depth and a stencil format. Images with optimal tiling have an opaque image layout that is 2228 /// not suitable for direct memory accesses, and likewise for combined depth/stencil formats. 2229 /// Multi-planar formats are supported, but you must specify one of the planes as the `aspect`, 2230 /// not [`ImageAspect::Color`]. 2231 /// 2232 /// The layout is invariant for each image. However it is not cached, as this would waste 2233 /// memory in the case of non-linear-tiling images. You are encouraged to store the layout 2234 /// somewhere in order to avoid calling this semi-expensive function at every single memory 2235 /// access. 2236 #[inline] subresource_layout( &self, aspect: ImageAspect, mip_level: u32, array_layer: u32, ) -> Result<SubresourceLayout, ImageError>2237 pub fn subresource_layout( 2238 &self, 2239 aspect: ImageAspect, 2240 mip_level: u32, 2241 array_layer: u32, 2242 ) -> Result<SubresourceLayout, ImageError> { 2243 self.inner 2244 .subresource_layout(aspect, mip_level, array_layer) 2245 } 2246 2247 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] 2248 #[inline] subresource_layout_unchecked( &self, aspect: ImageAspect, mip_level: u32, array_layer: u32, ) -> SubresourceLayout2249 pub unsafe fn subresource_layout_unchecked( 2250 &self, 2251 aspect: ImageAspect, 2252 mip_level: u32, 2253 array_layer: u32, 2254 ) -> SubresourceLayout { 2255 self.inner 2256 .subresource_layout_unchecked(aspect, mip_level, array_layer) 2257 } 2258 range_size(&self) -> DeviceSize2259 pub(crate) fn range_size(&self) -> DeviceSize { 2260 self.range_size 2261 } 2262 2263 /// Returns an iterator over subresource ranges. 2264 /// 2265 /// In ranges, the subresources are "flattened" to `DeviceSize`, where each index in the range 2266 /// is a single array layer. The layers are arranged hierarchically: aspects at the top level, 2267 /// with the mip levels in that aspect, and the array layers in that mip level. iter_ranges( &self, subresource_range: ImageSubresourceRange, ) -> SubresourceRangeIterator2268 pub(crate) fn iter_ranges( 2269 &self, 2270 subresource_range: ImageSubresourceRange, 2271 ) -> SubresourceRangeIterator { 2272 assert!(self 2273 .format() 2274 .unwrap() 2275 .aspects() 2276 .contains(subresource_range.aspects)); 2277 assert!(subresource_range.mip_levels.end <= self.inner.mip_levels); 2278 assert!(subresource_range.array_layers.end <= self.inner.dimensions.array_layers()); 2279 2280 SubresourceRangeIterator::new( 2281 subresource_range, 2282 &self.aspect_list, 2283 self.aspect_size, 2284 self.inner.mip_levels, 2285 self.mip_level_size, 2286 self.inner.dimensions.array_layers(), 2287 ) 2288 } 2289 range_to_subresources( &self, mut range: Range<DeviceSize>, ) -> ImageSubresourceRange2290 pub(crate) fn range_to_subresources( 2291 &self, 2292 mut range: Range<DeviceSize>, 2293 ) -> ImageSubresourceRange { 2294 debug_assert!(!range.is_empty()); 2295 debug_assert!(range.end <= self.range_size); 2296 2297 if range.end - range.start > self.aspect_size { 2298 debug_assert!(range.start % self.aspect_size == 0); 2299 debug_assert!(range.end % self.aspect_size == 0); 2300 2301 let start_aspect_num = (range.start / self.aspect_size) as usize; 2302 let end_aspect_num = (range.end / self.aspect_size) as usize; 2303 2304 ImageSubresourceRange { 2305 aspects: self.aspect_list[start_aspect_num..end_aspect_num] 2306 .iter() 2307 .copied() 2308 .collect(), 2309 mip_levels: 0..self.inner.mip_levels, 2310 array_layers: 0..self.inner.dimensions.array_layers(), 2311 } 2312 } else { 2313 let aspect_num = (range.start / self.aspect_size) as usize; 2314 range.start %= self.aspect_size; 2315 range.end %= self.aspect_size; 2316 2317 // Wraparound 2318 if range.end == 0 { 2319 range.end = self.aspect_size; 2320 } 2321 2322 if range.end - range.start > self.mip_level_size { 2323 debug_assert!(range.start % self.mip_level_size == 0); 2324 debug_assert!(range.end % self.mip_level_size == 0); 2325 2326 let start_mip_level = (range.start / self.mip_level_size) as u32; 2327 let end_mip_level = (range.end / self.mip_level_size) as u32; 2328 2329 ImageSubresourceRange { 2330 aspects: self.aspect_list[aspect_num].into(), 2331 mip_levels: start_mip_level..end_mip_level, 2332 array_layers: 0..self.inner.dimensions.array_layers(), 2333 } 2334 } else { 2335 let mip_level = (range.start / self.mip_level_size) as u32; 2336 range.start %= self.mip_level_size; 2337 range.end %= self.mip_level_size; 2338 2339 // Wraparound 2340 if range.end == 0 { 2341 range.end = self.mip_level_size; 2342 } 2343 2344 let start_array_layer = range.start as u32; 2345 let end_array_layer = range.end as u32; 2346 2347 ImageSubresourceRange { 2348 aspects: self.aspect_list[aspect_num].into(), 2349 mip_levels: mip_level..mip_level + 1, 2350 array_layers: start_array_layer..end_array_layer, 2351 } 2352 } 2353 } 2354 } 2355 state(&self) -> MutexGuard<'_, ImageState>2356 pub(crate) fn state(&self) -> MutexGuard<'_, ImageState> { 2357 self.state.lock() 2358 } 2359 } 2360 2361 unsafe impl VulkanObject for Image { 2362 type Handle = ash::vk::Image; 2363 2364 #[inline] handle(&self) -> Self::Handle2365 fn handle(&self) -> Self::Handle { 2366 self.inner.handle 2367 } 2368 } 2369 2370 unsafe impl DeviceOwned for Image { 2371 #[inline] device(&self) -> &Arc<Device>2372 fn device(&self) -> &Arc<Device> { 2373 &self.inner.device 2374 } 2375 } 2376 2377 impl PartialEq for Image { 2378 #[inline] eq(&self, other: &Self) -> bool2379 fn eq(&self, other: &Self) -> bool { 2380 self.inner == other.inner 2381 } 2382 } 2383 2384 impl Eq for Image {} 2385 2386 impl Hash for Image { hash<H: Hasher>(&self, state: &mut H)2387 fn hash<H: Hasher>(&self, state: &mut H) { 2388 self.inner.hash(state); 2389 } 2390 } 2391 2392 /// The current state of an image. 2393 #[derive(Debug)] 2394 pub(crate) struct ImageState { 2395 ranges: RangeMap<DeviceSize, ImageRangeState>, 2396 } 2397 2398 impl ImageState { new(size: DeviceSize, initial_layout: ImageLayout) -> Self2399 fn new(size: DeviceSize, initial_layout: ImageLayout) -> Self { 2400 ImageState { 2401 ranges: [( 2402 0..size, 2403 ImageRangeState { 2404 current_access: CurrentAccess::Shared { 2405 cpu_reads: 0, 2406 gpu_reads: 0, 2407 }, 2408 layout: initial_layout, 2409 }, 2410 )] 2411 .into_iter() 2412 .collect(), 2413 } 2414 } 2415 2416 #[allow(dead_code)] check_cpu_read(&self, range: Range<DeviceSize>) -> Result<(), ReadLockError>2417 pub(crate) fn check_cpu_read(&self, range: Range<DeviceSize>) -> Result<(), ReadLockError> { 2418 for (_range, state) in self.ranges.range(&range) { 2419 match &state.current_access { 2420 CurrentAccess::CpuExclusive { .. } => return Err(ReadLockError::CpuWriteLocked), 2421 CurrentAccess::GpuExclusive { .. } => return Err(ReadLockError::GpuWriteLocked), 2422 CurrentAccess::Shared { .. } => (), 2423 } 2424 } 2425 2426 Ok(()) 2427 } 2428 2429 #[allow(dead_code)] cpu_read_lock(&mut self, range: Range<DeviceSize>)2430 pub(crate) unsafe fn cpu_read_lock(&mut self, range: Range<DeviceSize>) { 2431 self.ranges.split_at(&range.start); 2432 self.ranges.split_at(&range.end); 2433 2434 for (_range, state) in self.ranges.range_mut(&range) { 2435 match &mut state.current_access { 2436 CurrentAccess::Shared { cpu_reads, .. } => { 2437 *cpu_reads += 1; 2438 } 2439 _ => unreachable!("Image is being written by the CPU or GPU"), 2440 } 2441 } 2442 } 2443 2444 #[allow(dead_code)] cpu_read_unlock(&mut self, range: Range<DeviceSize>)2445 pub(crate) unsafe fn cpu_read_unlock(&mut self, range: Range<DeviceSize>) { 2446 self.ranges.split_at(&range.start); 2447 self.ranges.split_at(&range.end); 2448 2449 for (_range, state) in self.ranges.range_mut(&range) { 2450 match &mut state.current_access { 2451 CurrentAccess::Shared { cpu_reads, .. } => *cpu_reads -= 1, 2452 _ => unreachable!("Image was not locked for CPU read"), 2453 } 2454 } 2455 } 2456 2457 #[allow(dead_code)] check_cpu_write(&self, range: Range<DeviceSize>) -> Result<(), WriteLockError>2458 pub(crate) fn check_cpu_write(&self, range: Range<DeviceSize>) -> Result<(), WriteLockError> { 2459 for (_range, state) in self.ranges.range(&range) { 2460 match &state.current_access { 2461 CurrentAccess::CpuExclusive => return Err(WriteLockError::CpuLocked), 2462 CurrentAccess::GpuExclusive { .. } => return Err(WriteLockError::GpuLocked), 2463 CurrentAccess::Shared { 2464 cpu_reads: 0, 2465 gpu_reads: 0, 2466 } => (), 2467 CurrentAccess::Shared { cpu_reads, .. } if *cpu_reads > 0 => { 2468 return Err(WriteLockError::CpuLocked) 2469 } 2470 CurrentAccess::Shared { .. } => return Err(WriteLockError::GpuLocked), 2471 } 2472 } 2473 2474 Ok(()) 2475 } 2476 2477 #[allow(dead_code)] cpu_write_lock(&mut self, range: Range<DeviceSize>)2478 pub(crate) unsafe fn cpu_write_lock(&mut self, range: Range<DeviceSize>) { 2479 self.ranges.split_at(&range.start); 2480 self.ranges.split_at(&range.end); 2481 2482 for (_range, state) in self.ranges.range_mut(&range) { 2483 state.current_access = CurrentAccess::CpuExclusive; 2484 } 2485 } 2486 2487 #[allow(dead_code)] cpu_write_unlock(&mut self, range: Range<DeviceSize>)2488 pub(crate) unsafe fn cpu_write_unlock(&mut self, range: Range<DeviceSize>) { 2489 self.ranges.split_at(&range.start); 2490 self.ranges.split_at(&range.end); 2491 2492 for (_range, state) in self.ranges.range_mut(&range) { 2493 match &mut state.current_access { 2494 CurrentAccess::CpuExclusive => { 2495 state.current_access = CurrentAccess::Shared { 2496 cpu_reads: 0, 2497 gpu_reads: 0, 2498 } 2499 } 2500 _ => unreachable!("Image was not locked for CPU write"), 2501 } 2502 } 2503 } 2504 check_gpu_read( &self, range: Range<DeviceSize>, expected_layout: ImageLayout, ) -> Result<(), AccessError>2505 pub(crate) fn check_gpu_read( 2506 &self, 2507 range: Range<DeviceSize>, 2508 expected_layout: ImageLayout, 2509 ) -> Result<(), AccessError> { 2510 for (_range, state) in self.ranges.range(&range) { 2511 match &state.current_access { 2512 CurrentAccess::Shared { .. } => (), 2513 _ => return Err(AccessError::AlreadyInUse), 2514 } 2515 2516 if expected_layout != ImageLayout::Undefined && state.layout != expected_layout { 2517 return Err(AccessError::UnexpectedImageLayout { 2518 allowed: state.layout, 2519 requested: expected_layout, 2520 }); 2521 } 2522 } 2523 2524 Ok(()) 2525 } 2526 gpu_read_lock(&mut self, range: Range<DeviceSize>)2527 pub(crate) unsafe fn gpu_read_lock(&mut self, range: Range<DeviceSize>) { 2528 self.ranges.split_at(&range.start); 2529 self.ranges.split_at(&range.end); 2530 2531 for (_range, state) in self.ranges.range_mut(&range) { 2532 match &mut state.current_access { 2533 CurrentAccess::GpuExclusive { gpu_reads, .. } 2534 | CurrentAccess::Shared { gpu_reads, .. } => *gpu_reads += 1, 2535 _ => unreachable!("Image is being written by the CPU"), 2536 } 2537 } 2538 } 2539 gpu_read_unlock(&mut self, range: Range<DeviceSize>)2540 pub(crate) unsafe fn gpu_read_unlock(&mut self, range: Range<DeviceSize>) { 2541 self.ranges.split_at(&range.start); 2542 self.ranges.split_at(&range.end); 2543 2544 for (_range, state) in self.ranges.range_mut(&range) { 2545 match &mut state.current_access { 2546 CurrentAccess::GpuExclusive { gpu_reads, .. } => *gpu_reads -= 1, 2547 CurrentAccess::Shared { gpu_reads, .. } => *gpu_reads -= 1, 2548 _ => unreachable!("Buffer was not locked for GPU read"), 2549 } 2550 } 2551 } 2552 check_gpu_write( &self, range: Range<DeviceSize>, expected_layout: ImageLayout, ) -> Result<(), AccessError>2553 pub(crate) fn check_gpu_write( 2554 &self, 2555 range: Range<DeviceSize>, 2556 expected_layout: ImageLayout, 2557 ) -> Result<(), AccessError> { 2558 for (_range, state) in self.ranges.range(&range) { 2559 match &state.current_access { 2560 CurrentAccess::Shared { 2561 cpu_reads: 0, 2562 gpu_reads: 0, 2563 } => (), 2564 _ => return Err(AccessError::AlreadyInUse), 2565 } 2566 2567 if expected_layout != ImageLayout::Undefined && state.layout != expected_layout { 2568 return Err(AccessError::UnexpectedImageLayout { 2569 allowed: state.layout, 2570 requested: expected_layout, 2571 }); 2572 } 2573 } 2574 2575 Ok(()) 2576 } 2577 gpu_write_lock( &mut self, range: Range<DeviceSize>, destination_layout: ImageLayout, )2578 pub(crate) unsafe fn gpu_write_lock( 2579 &mut self, 2580 range: Range<DeviceSize>, 2581 destination_layout: ImageLayout, 2582 ) { 2583 debug_assert!(!matches!( 2584 destination_layout, 2585 ImageLayout::Undefined | ImageLayout::Preinitialized 2586 )); 2587 2588 self.ranges.split_at(&range.start); 2589 self.ranges.split_at(&range.end); 2590 2591 for (_range, state) in self.ranges.range_mut(&range) { 2592 match &mut state.current_access { 2593 CurrentAccess::GpuExclusive { gpu_writes, .. } => *gpu_writes += 1, 2594 &mut CurrentAccess::Shared { 2595 cpu_reads: 0, 2596 gpu_reads, 2597 } => { 2598 state.current_access = CurrentAccess::GpuExclusive { 2599 gpu_reads, 2600 gpu_writes: 1, 2601 } 2602 } 2603 _ => unreachable!("Image is being accessed by the CPU"), 2604 } 2605 2606 state.layout = destination_layout; 2607 } 2608 } 2609 gpu_write_unlock(&mut self, range: Range<DeviceSize>)2610 pub(crate) unsafe fn gpu_write_unlock(&mut self, range: Range<DeviceSize>) { 2611 self.ranges.split_at(&range.start); 2612 self.ranges.split_at(&range.end); 2613 2614 for (_range, state) in self.ranges.range_mut(&range) { 2615 match &mut state.current_access { 2616 &mut CurrentAccess::GpuExclusive { 2617 gpu_reads, 2618 gpu_writes: 1, 2619 } => { 2620 state.current_access = CurrentAccess::Shared { 2621 cpu_reads: 0, 2622 gpu_reads, 2623 } 2624 } 2625 CurrentAccess::GpuExclusive { gpu_writes, .. } => *gpu_writes -= 1, 2626 _ => unreachable!("Image was not locked for GPU write"), 2627 } 2628 } 2629 } 2630 } 2631 2632 /// The current state of a specific subresource range in an image. 2633 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 2634 struct ImageRangeState { 2635 current_access: CurrentAccess, 2636 layout: ImageLayout, 2637 } 2638 2639 #[derive(Clone)] 2640 pub(crate) struct SubresourceRangeIterator { 2641 next_fn: fn(&mut Self) -> Option<Range<DeviceSize>>, 2642 image_aspect_size: DeviceSize, 2643 image_mip_level_size: DeviceSize, 2644 mip_levels: Range<u32>, 2645 array_layers: Range<u32>, 2646 2647 aspect_nums: Peekable<smallvec::IntoIter<[usize; 4]>>, 2648 current_aspect_num: Option<usize>, 2649 current_mip_level: u32, 2650 } 2651 2652 impl SubresourceRangeIterator { new( subresource_range: ImageSubresourceRange, image_aspect_list: &[ImageAspect], image_aspect_size: DeviceSize, image_mip_levels: u32, image_mip_level_size: DeviceSize, image_array_layers: u32, ) -> Self2653 fn new( 2654 subresource_range: ImageSubresourceRange, 2655 image_aspect_list: &[ImageAspect], 2656 image_aspect_size: DeviceSize, 2657 image_mip_levels: u32, 2658 image_mip_level_size: DeviceSize, 2659 image_array_layers: u32, 2660 ) -> Self { 2661 assert!(!subresource_range.mip_levels.is_empty()); 2662 assert!(!subresource_range.array_layers.is_empty()); 2663 2664 let next_fn = if subresource_range.array_layers.start != 0 2665 || subresource_range.array_layers.end != image_array_layers 2666 { 2667 Self::next_some_layers 2668 } else if subresource_range.mip_levels.start != 0 2669 || subresource_range.mip_levels.end != image_mip_levels 2670 { 2671 Self::next_some_levels_all_layers 2672 } else { 2673 Self::next_all_levels_all_layers 2674 }; 2675 2676 let mut aspect_nums = subresource_range 2677 .aspects 2678 .into_iter() 2679 .map(|aspect| image_aspect_list.iter().position(|&a| a == aspect).unwrap()) 2680 .collect::<SmallVec<[usize; 4]>>() 2681 .into_iter() 2682 .peekable(); 2683 assert!(aspect_nums.len() != 0); 2684 let current_aspect_num = aspect_nums.next(); 2685 let current_mip_level = subresource_range.mip_levels.start; 2686 2687 Self { 2688 next_fn, 2689 image_aspect_size, 2690 image_mip_level_size, 2691 mip_levels: subresource_range.mip_levels, 2692 array_layers: subresource_range.array_layers, 2693 2694 aspect_nums, 2695 current_aspect_num, 2696 current_mip_level, 2697 } 2698 } 2699 2700 /// Used when the requested range contains only a subset of the array layers in the image. 2701 /// The iterator returns one range for each mip level and aspect, each covering the range of 2702 /// array layers of that mip level and aspect. next_some_layers(&mut self) -> Option<Range<DeviceSize>>2703 fn next_some_layers(&mut self) -> Option<Range<DeviceSize>> { 2704 self.current_aspect_num.map(|aspect_num| { 2705 let mip_level_offset = aspect_num as DeviceSize * self.image_aspect_size 2706 + self.current_mip_level as DeviceSize * self.image_mip_level_size; 2707 self.current_mip_level += 1; 2708 2709 if self.current_mip_level >= self.mip_levels.end { 2710 self.current_mip_level = self.mip_levels.start; 2711 self.current_aspect_num = self.aspect_nums.next(); 2712 } 2713 2714 let start = mip_level_offset + self.array_layers.start as DeviceSize; 2715 let end = mip_level_offset + self.array_layers.end as DeviceSize; 2716 start..end 2717 }) 2718 } 2719 2720 /// Used when the requested range contains all array layers in the image, but not all mip 2721 /// levels. The iterator returns one range for each aspect, each covering all layers of the 2722 /// range of mip levels of that aspect. next_some_levels_all_layers(&mut self) -> Option<Range<DeviceSize>>2723 fn next_some_levels_all_layers(&mut self) -> Option<Range<DeviceSize>> { 2724 self.current_aspect_num.map(|aspect_num| { 2725 let aspect_offset = aspect_num as DeviceSize * self.image_aspect_size; 2726 self.current_aspect_num = self.aspect_nums.next(); 2727 2728 let start = 2729 aspect_offset + self.mip_levels.start as DeviceSize * self.image_mip_level_size; 2730 let end = aspect_offset + self.mip_levels.end as DeviceSize * self.image_mip_level_size; 2731 start..end 2732 }) 2733 } 2734 2735 /// Used when the requested range contains all array layers and mip levels in the image. 2736 /// The iterator returns one range for each series of adjacent aspect numbers, each covering 2737 /// all mip levels and all layers of those aspects. If the range contains the whole image, then 2738 /// exactly one range is returned since all aspect numbers will be adjacent. next_all_levels_all_layers(&mut self) -> Option<Range<DeviceSize>>2739 fn next_all_levels_all_layers(&mut self) -> Option<Range<DeviceSize>> { 2740 self.current_aspect_num.map(|aspect_num_start| { 2741 self.current_aspect_num = self.aspect_nums.next(); 2742 let mut aspect_num_end = aspect_num_start + 1; 2743 2744 while self.current_aspect_num == Some(aspect_num_end) { 2745 self.current_aspect_num = self.aspect_nums.next(); 2746 aspect_num_end += 1; 2747 } 2748 2749 let start = aspect_num_start as DeviceSize * self.image_aspect_size; 2750 let end = aspect_num_end as DeviceSize * self.image_aspect_size; 2751 start..end 2752 }) 2753 } 2754 } 2755 2756 impl Iterator for SubresourceRangeIterator { 2757 type Item = Range<DeviceSize>; 2758 next(&mut self) -> Option<Self::Item>2759 fn next(&mut self) -> Option<Self::Item> { 2760 (self.next_fn)(self) 2761 } 2762 } 2763 2764 impl FusedIterator for SubresourceRangeIterator {} 2765 2766 /// Describes the memory layout of a single subresource of an image. 2767 /// 2768 /// The address of a texel at `(x, y, z, layer)` is `layer * array_pitch + z * depth_pitch + 2769 /// y * row_pitch + x * size_of_each_texel + offset`. `size_of_each_texel` must be determined 2770 /// depending on the format. The same formula applies for compressed formats, except that the 2771 /// coordinates must be in number of blocks. 2772 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 2773 pub struct SubresourceLayout { 2774 /// The number of bytes from the start of the memory to the start of the queried subresource. 2775 pub offset: DeviceSize, 2776 2777 /// The total number of bytes for the queried subresource. 2778 pub size: DeviceSize, 2779 2780 /// The number of bytes between two texels or two blocks in adjacent rows. 2781 pub row_pitch: DeviceSize, 2782 2783 /// For images with more than one array layer, the number of bytes between two texels or two 2784 /// blocks in adjacent array layers. 2785 pub array_pitch: Option<DeviceSize>, 2786 2787 /// For 3D images, the number of bytes between two texels or two blocks in adjacent depth 2788 /// layers. 2789 pub depth_pitch: Option<DeviceSize>, 2790 } 2791 2792 /// Error that can happen in image functions. 2793 #[derive(Clone, Debug, PartialEq, Eq)] 2794 pub enum ImageError { 2795 VulkanError(VulkanError), 2796 2797 /// Allocating memory failed. 2798 AllocError(AllocationCreationError), 2799 2800 RequirementNotMet { 2801 required_for: &'static str, 2802 requires_one_of: RequiresOneOf, 2803 }, 2804 2805 /// The provided number of elements in `allocations` is not what is required for `image`. 2806 AllocationsWrongNumberOfElements { 2807 provided: usize, 2808 required: usize, 2809 }, 2810 2811 /// The `array_2d_compatible` flag was enabled, but the image type was not 3D. 2812 Array2dCompatibleNot3d, 2813 2814 /// The provided array layer is not less than the number of array layers in the image. 2815 ArrayLayerOutOfRange { 2816 provided_array_layer: u32, 2817 image_array_layers: u32, 2818 }, 2819 2820 /// The provided aspect is not present in the image, or is not allowed. 2821 AspectNotAllowed { 2822 provided_aspect: ImageAspect, 2823 allowed_aspects: ImageAspects, 2824 }, 2825 2826 /// The `block_texel_view_compatible` flag was enabled, but the given format was not compressed. 2827 BlockTexelViewCompatibleNotCompressed, 2828 2829 /// The `cube_compatible` flag was enabled, but the image type was not 2D. 2830 CubeCompatibleNot2d, 2831 2832 /// The `cube_compatible` flag was enabled, but the number of array layers was less than 6. 2833 CubeCompatibleNotEnoughArrayLayers, 2834 2835 /// The `cube_compatible` flag was enabled, but the image dimensions were not square. 2836 CubeCompatibleNotSquare, 2837 2838 /// The `cube_compatible` flag was enabled together with multisampling. 2839 CubeCompatibleMultisampling, 2840 2841 /// The memory was created dedicated to a resource, but not to this image. 2842 DedicatedAllocationMismatch, 2843 2844 /// A dedicated allocation is required for this image, but one was not provided. 2845 DedicatedAllocationRequired, 2846 2847 /// The image has a format with both a depth and a stencil aspect, which is not supported for 2848 /// this operation. 2849 DepthStencilFormatsNotSupported, 2850 2851 /// The `disjoint` flag was enabled, but the given format is either not multi-planar, or does 2852 /// not support disjoint images. 2853 DisjointFormatNotSupported, 2854 2855 /// One or more external memory handle types were provided, but the initial layout was not 2856 /// `Undefined`. 2857 ExternalMemoryInvalidInitialLayout, 2858 2859 /// The given format was not supported by the device. 2860 FormatNotSupported, 2861 2862 /// A requested usage flag was not supported by the given format. 2863 FormatUsageNotSupported { 2864 usage: &'static str, 2865 }, 2866 2867 /// The image configuration as queried through the `image_format_properties` function was not 2868 /// supported by the device. 2869 ImageFormatPropertiesNotSupported, 2870 2871 /// The number of array layers exceeds the maximum supported by the device for this image 2872 /// configuration. 2873 MaxArrayLayersExceeded { 2874 array_layers: u32, 2875 max: u32, 2876 }, 2877 2878 /// The specified dimensions exceed the maximum supported by the device for this image 2879 /// configuration. 2880 MaxDimensionsExceeded { 2881 extent: [u32; 3], 2882 max: [u32; 3], 2883 }, 2884 2885 /// The usage included one of the attachment types, and the specified width and height exceeded 2886 /// the `max_framebuffer_width` or `max_framebuffer_height` limits. 2887 MaxFramebufferDimensionsExceeded { 2888 extent: [u32; 2], 2889 max: [u32; 2], 2890 }, 2891 2892 /// The maximum number of mip levels for the given dimensions has been exceeded. 2893 MaxMipLevelsExceeded { 2894 mip_levels: u32, 2895 max: u32, 2896 }, 2897 2898 /// In an `allocations` element, the offset of the allocation does not have the required 2899 /// alignment. 2900 MemoryAllocationNotAligned { 2901 allocations_index: usize, 2902 allocation_offset: DeviceSize, 2903 required_alignment: DeviceAlignment, 2904 }, 2905 2906 /// In an `allocations` element, the size of the allocation is smaller than what is required. 2907 MemoryAllocationTooSmall { 2908 allocations_index: usize, 2909 allocation_size: DeviceSize, 2910 required_size: DeviceSize, 2911 }, 2912 2913 /// In an `allocations` element, the memory was created with export handle types, but none of 2914 /// these handle types were enabled on the image. 2915 MemoryExternalHandleTypesDisjoint { 2916 allocations_index: usize, 2917 image_handle_types: ExternalMemoryHandleTypes, 2918 memory_export_handle_types: ExternalMemoryHandleTypes, 2919 }, 2920 2921 /// In an `allocations` element, the memory was created with an import, but the import's handle 2922 /// type was not enabled on the image. 2923 MemoryImportedHandleTypeNotEnabled { 2924 allocations_index: usize, 2925 image_handle_types: ExternalMemoryHandleTypes, 2926 memory_imported_handle_type: ExternalMemoryHandleType, 2927 }, 2928 2929 /// In an `allocations` element, the protection of image and memory are not equal. 2930 MemoryProtectedMismatch { 2931 allocations_index: usize, 2932 image_protected: bool, 2933 memory_protected: bool, 2934 }, 2935 2936 /// In an `allocations` element, the provided memory type is not one of the allowed memory 2937 /// types that can be bound to this image or image plane. 2938 MemoryTypeNotAllowed { 2939 allocations_index: usize, 2940 provided_memory_type_index: u32, 2941 allowed_memory_type_bits: u32, 2942 }, 2943 2944 /// The provided mip level is not less than the number of mip levels in the image. 2945 MipLevelOutOfRange { 2946 provided_mip_level: u32, 2947 image_mip_levels: u32, 2948 }, 2949 2950 /// Multisampling was enabled, and the `cube_compatible` flag was set. 2951 MultisampleCubeCompatible, 2952 2953 /// Multisampling was enabled, and tiling was `Linear`. 2954 MultisampleLinearTiling, 2955 2956 /// Multisampling was enabled, and multiple mip levels were specified. 2957 MultisampleMultipleMipLevels, 2958 2959 /// Multisampling was enabled, but the image type was not 2D. 2960 MultisampleNot2d, 2961 2962 /// The image has optimal tiling, which is not supported for this operation. 2963 OptimalTilingNotSupported, 2964 2965 /// The sample count is not supported by the device for this image configuration. 2966 SampleCountNotSupported { 2967 samples: SampleCount, 2968 supported: SampleCounts, 2969 }, 2970 2971 /// The sharing mode was set to `Concurrent`, but one of the specified queue family indices was 2972 /// out of range. 2973 SharingQueueFamilyIndexOutOfRange { 2974 queue_family_index: u32, 2975 queue_family_count: u32, 2976 }, 2977 2978 /// The provided `usage` and `stencil_usage` have different values for 2979 /// `depth_stencil_attachment` or `transient_attachment`. 2980 StencilUsageMismatch { 2981 usage: ImageUsage, 2982 stencil_usage: ImageUsage, 2983 }, 2984 2985 /// A YCbCr format was given, but the specified width and/or height was not a multiple of 2 2986 /// as required by the format's chroma subsampling. 2987 YcbcrFormatInvalidDimensions, 2988 2989 /// A YCbCr format was given, and multiple mip levels were specified. 2990 YcbcrFormatMultipleMipLevels, 2991 2992 /// A YCbCr format was given, and multisampling was enabled. 2993 YcbcrFormatMultisampling, 2994 2995 /// A YCbCr format was given, but the image type was not 2D. 2996 YcbcrFormatNot2d, 2997 2998 DirectImageViewCreationFailed(ImageViewCreationError), 2999 3000 /// If and only if tiling is `DRMFormatModifier`, then `image_drm_format_modifier_create_info` must not be `None`. 3001 DrmFormatModifierRequiresCreateInfo, 3002 } 3003 3004 impl Error for ImageError { source(&self) -> Option<&(dyn Error + 'static)>3005 fn source(&self) -> Option<&(dyn Error + 'static)> { 3006 match self { 3007 ImageError::AllocError(err) => Some(err), 3008 _ => None, 3009 } 3010 } 3011 } 3012 3013 impl Display for ImageError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>3014 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 3015 match self { 3016 Self::VulkanError(_) => write!(f, "a runtime error occurred"), 3017 Self::AllocError(_) => write!(f, "allocating memory failed"), 3018 Self::RequirementNotMet { 3019 required_for, 3020 requires_one_of, 3021 } => write!( 3022 f, 3023 "a requirement was not met for: {}; requires one of: {}", 3024 required_for, requires_one_of, 3025 ), 3026 Self::AllocationsWrongNumberOfElements { provided, required } => write!( 3027 f, 3028 "the provided number of elements in `allocations` ({}) is not what is required for \ 3029 `image` ({})", 3030 provided, required, 3031 ), 3032 Self::Array2dCompatibleNot3d => write!( 3033 f, 3034 "the `array_2d_compatible` flag was enabled, but the image type was not 3D", 3035 ), 3036 Self::ArrayLayerOutOfRange { 3037 provided_array_layer, 3038 image_array_layers, 3039 } => write!( 3040 f, 3041 "the provided array layer ({}) is not less than the number of array layers in the image ({})", 3042 provided_array_layer, image_array_layers, 3043 ), 3044 Self::AspectNotAllowed { 3045 provided_aspect, 3046 allowed_aspects, 3047 } => write!( 3048 f, 3049 "the provided aspect ({:?}) is not present in the image, or is not allowed ({:?})", 3050 provided_aspect, allowed_aspects, 3051 ), 3052 Self::BlockTexelViewCompatibleNotCompressed => write!( 3053 f, 3054 "the `block_texel_view_compatible` flag was enabled, but the given format was not \ 3055 compressed", 3056 ), 3057 Self::CubeCompatibleNot2d => write!( 3058 f, 3059 "the `cube_compatible` flag was enabled, but the image type was not 2D", 3060 ), 3061 Self::CubeCompatibleNotEnoughArrayLayers => write!( 3062 f, 3063 "the `cube_compatible` flag was enabled, but the number of array layers was less \ 3064 than 6", 3065 ), 3066 Self::CubeCompatibleNotSquare => write!( 3067 f, 3068 "the `cube_compatible` flag was enabled, but the image dimensions were not square", 3069 ), 3070 Self::CubeCompatibleMultisampling => write!( 3071 f, 3072 "the `cube_compatible` flag was enabled together with multisampling", 3073 ), 3074 Self::DedicatedAllocationMismatch => write!( 3075 f, 3076 "the memory was created dedicated to a resource, but not to this image", 3077 ), 3078 Self::DedicatedAllocationRequired => write!( 3079 f, 3080 "a dedicated allocation is required for this image, but one was not provided" 3081 ), 3082 Self::DepthStencilFormatsNotSupported => write!( 3083 f, 3084 "the image has a format with both a depth and a stencil aspect, which is not \ 3085 supported for this operation", 3086 ), 3087 Self::DisjointFormatNotSupported => write!( 3088 f, 3089 "the `disjoint` flag was enabled, but the given format is either not multi-planar, \ 3090 or does not support disjoint images", 3091 ), 3092 Self::ExternalMemoryInvalidInitialLayout => write!( 3093 f, 3094 "one or more external memory handle types were provided, but the initial layout \ 3095 was not `Undefined`", 3096 ), 3097 Self::FormatNotSupported => { 3098 write!(f, "the given format was not supported by the device") 3099 } 3100 Self::FormatUsageNotSupported { .. } => write!( 3101 f, 3102 "a requested usage flag was not supported by the given format", 3103 ), 3104 Self::ImageFormatPropertiesNotSupported => write!( 3105 f, 3106 "the image configuration as queried through the `image_format_properties` function \ 3107 was not supported by the device", 3108 ), 3109 Self::MaxArrayLayersExceeded { .. } => write!( 3110 f, 3111 "the number of array layers exceeds the maximum supported by the device for this \ 3112 image configuration", 3113 ), 3114 Self::MaxDimensionsExceeded { .. } => write!( 3115 f, 3116 "the specified dimensions exceed the maximum supported by the device for this \ 3117 image configuration", 3118 ), 3119 Self::MaxFramebufferDimensionsExceeded { .. } => write!( 3120 f, 3121 "the usage included one of the attachment types, and the specified width and \ 3122 height exceeded the `max_framebuffer_width` or `max_framebuffer_height` limits", 3123 ), 3124 Self::MaxMipLevelsExceeded { .. } => write!( 3125 f, 3126 "the maximum number of mip levels for the given dimensions has been exceeded", 3127 ), 3128 Self::MemoryAllocationNotAligned { 3129 allocations_index, 3130 allocation_offset, 3131 required_alignment, 3132 } => write!( 3133 f, 3134 "in `allocations` element {}, the offset of the allocation ({}) does not have the \ 3135 required alignment ({:?})", 3136 allocations_index, allocation_offset, required_alignment, 3137 ), 3138 Self::MemoryAllocationTooSmall { 3139 allocations_index, 3140 allocation_size, 3141 required_size, 3142 } => write!( 3143 f, 3144 "in `allocations` element {}, the size of the allocation ({}) is smaller than what \ 3145 is required ({})", 3146 allocations_index, allocation_size, required_size, 3147 ), 3148 Self::MemoryExternalHandleTypesDisjoint { 3149 allocations_index, .. 3150 } => write!( 3151 f, 3152 "in `allocations` element {}, the memory was created with export handle types, but \ 3153 none of these handle types were enabled on the image", 3154 allocations_index, 3155 ), 3156 Self::MemoryImportedHandleTypeNotEnabled { 3157 allocations_index, .. 3158 } => write!( 3159 f, 3160 "in `allocations` element {}, the memory was created with an import, but the \ 3161 import's handle type was not enabled on the image", 3162 allocations_index, 3163 ), 3164 Self::MemoryProtectedMismatch { 3165 allocations_index, 3166 image_protected, 3167 memory_protected, 3168 } => write!( 3169 f, 3170 "in `allocations` element {}, the protection of image ({}) and memory ({}) are not \ 3171 equal", 3172 allocations_index, image_protected, memory_protected, 3173 ), 3174 Self::MemoryTypeNotAllowed { 3175 allocations_index, 3176 provided_memory_type_index, 3177 allowed_memory_type_bits, 3178 } => write!( 3179 f, 3180 "in `allocations` element {}, the provided memory type ({}) is not one of the \ 3181 allowed memory types (", 3182 allocations_index, provided_memory_type_index, 3183 ) 3184 .and_then(|_| { 3185 let mut first = true; 3186 3187 for i in (0..size_of_val(allowed_memory_type_bits)) 3188 .filter(|i| allowed_memory_type_bits & (1 << i) != 0) 3189 { 3190 if first { 3191 write!(f, "{}", i)?; 3192 first = false; 3193 } else { 3194 write!(f, ", {}", i)?; 3195 } 3196 } 3197 3198 Ok(()) 3199 }) 3200 .and_then(|_| write!(f, ") that can be bound to this buffer")), 3201 Self::MipLevelOutOfRange { 3202 provided_mip_level, 3203 image_mip_levels, 3204 } => write!( 3205 f, 3206 "the provided mip level ({}) is not less than the number of mip levels in the image ({})", 3207 provided_mip_level, image_mip_levels, 3208 ), 3209 Self::MultisampleCubeCompatible => write!( 3210 f, 3211 "multisampling was enabled, and the `cube_compatible` flag was set", 3212 ), 3213 Self::MultisampleLinearTiling => { 3214 write!(f, "multisampling was enabled, and tiling was `Linear`") 3215 } 3216 Self::MultisampleMultipleMipLevels => write!( 3217 f, 3218 "multisampling was enabled, and multiple mip levels were specified", 3219 ), 3220 Self::MultisampleNot2d => write!( 3221 f, 3222 "multisampling was enabled, but the image type was not 2D", 3223 ), 3224 Self::OptimalTilingNotSupported => write!( 3225 f, 3226 "the image has optimal tiling, which is not supported for this operation", 3227 ), 3228 Self::SampleCountNotSupported { .. } => write!( 3229 f, 3230 "the sample count is not supported by the device for this image configuration", 3231 ), 3232 Self::SharingQueueFamilyIndexOutOfRange { .. } => write!( 3233 f, 3234 "the sharing mode was set to `Concurrent`, but one of the specified queue family \ 3235 indices was out of range", 3236 ), 3237 Self::StencilUsageMismatch { 3238 usage: _, 3239 stencil_usage: _, 3240 } => write!( 3241 f, 3242 "the provided `usage` and `stencil_usage` have different values for \ 3243 `depth_stencil_attachment` or `transient_attachment`", 3244 ), 3245 Self::YcbcrFormatInvalidDimensions => write!( 3246 f, 3247 "a YCbCr format was given, but the specified width and/or height was not a \ 3248 multiple of 2 as required by the format's chroma subsampling", 3249 ), 3250 Self::YcbcrFormatMultipleMipLevels => write!( 3251 f, 3252 "a YCbCr format was given, and multiple mip levels were specified", 3253 ), 3254 Self::YcbcrFormatMultisampling => { 3255 write!(f, "a YCbCr format was given, and multisampling was enabled") 3256 } 3257 Self::YcbcrFormatNot2d => { 3258 write!(f, "a YCbCr format was given, but the image type was not 2D") 3259 } 3260 Self::DirectImageViewCreationFailed(e) => write!(f, "Image view creation failed {}", e), 3261 Self::DrmFormatModifierRequiresCreateInfo => write!(f, "If and only if tiling is `DRMFormatModifier`, then `image_drm_format_modifier_create_info` must be `Some`"), 3262 } 3263 } 3264 } 3265 3266 impl From<VulkanError> for ImageError { from(err: VulkanError) -> Self3267 fn from(err: VulkanError) -> Self { 3268 Self::VulkanError(err) 3269 } 3270 } 3271 3272 impl From<AllocationCreationError> for ImageError { from(err: AllocationCreationError) -> Self3273 fn from(err: AllocationCreationError) -> Self { 3274 Self::AllocError(err) 3275 } 3276 } 3277 3278 impl From<RequirementNotMet> for ImageError { from(err: RequirementNotMet) -> Self3279 fn from(err: RequirementNotMet) -> Self { 3280 Self::RequirementNotMet { 3281 required_for: err.required_for, 3282 requires_one_of: err.requires_one_of, 3283 } 3284 } 3285 } 3286 3287 #[cfg(test)] 3288 mod tests { 3289 use super::{ImageCreateInfo, ImageError, ImageUsage, RawImage}; 3290 use crate::{ 3291 format::Format, 3292 image::{ 3293 sys::SubresourceRangeIterator, ImageAspect, ImageAspects, ImageCreateFlags, 3294 ImageDimensions, ImageSubresourceRange, SampleCount, 3295 }, 3296 DeviceSize, RequiresOneOf, 3297 }; 3298 use smallvec::SmallVec; 3299 3300 #[test] create_sampled()3301 fn create_sampled() { 3302 let (device, _) = gfx_dev_and_queue!(); 3303 3304 let _ = RawImage::new( 3305 device, 3306 ImageCreateInfo { 3307 dimensions: ImageDimensions::Dim2d { 3308 width: 32, 3309 height: 32, 3310 array_layers: 1, 3311 }, 3312 format: Some(Format::R8G8B8A8_UNORM), 3313 usage: ImageUsage::SAMPLED, 3314 ..Default::default() 3315 }, 3316 ) 3317 .unwrap(); 3318 } 3319 3320 #[test] create_transient()3321 fn create_transient() { 3322 let (device, _) = gfx_dev_and_queue!(); 3323 3324 let _ = RawImage::new( 3325 device, 3326 ImageCreateInfo { 3327 dimensions: ImageDimensions::Dim2d { 3328 width: 32, 3329 height: 32, 3330 array_layers: 1, 3331 }, 3332 format: Some(Format::R8G8B8A8_UNORM), 3333 usage: ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::COLOR_ATTACHMENT, 3334 ..Default::default() 3335 }, 3336 ) 3337 .unwrap(); 3338 } 3339 3340 #[test] zero_mipmap()3341 fn zero_mipmap() { 3342 let (device, _) = gfx_dev_and_queue!(); 3343 3344 assert_should_panic!({ 3345 let _ = RawImage::new( 3346 device, 3347 ImageCreateInfo { 3348 dimensions: ImageDimensions::Dim2d { 3349 width: 32, 3350 height: 32, 3351 array_layers: 1, 3352 }, 3353 format: Some(Format::R8G8B8A8_UNORM), 3354 mip_levels: 0, 3355 usage: ImageUsage::SAMPLED, 3356 ..Default::default() 3357 }, 3358 ); 3359 }); 3360 } 3361 3362 #[test] mipmaps_too_high()3363 fn mipmaps_too_high() { 3364 let (device, _) = gfx_dev_and_queue!(); 3365 3366 let res = RawImage::new( 3367 device, 3368 ImageCreateInfo { 3369 dimensions: ImageDimensions::Dim2d { 3370 width: 32, 3371 height: 32, 3372 array_layers: 1, 3373 }, 3374 format: Some(Format::R8G8B8A8_UNORM), 3375 mip_levels: u32::MAX, 3376 usage: ImageUsage::SAMPLED, 3377 ..Default::default() 3378 }, 3379 ); 3380 3381 match res { 3382 Err(ImageError::MaxMipLevelsExceeded { .. }) => (), 3383 _ => panic!(), 3384 }; 3385 } 3386 3387 #[test] shader_storage_image_multisample()3388 fn shader_storage_image_multisample() { 3389 let (device, _) = gfx_dev_and_queue!(); 3390 3391 let res = RawImage::new( 3392 device, 3393 ImageCreateInfo { 3394 dimensions: ImageDimensions::Dim2d { 3395 width: 32, 3396 height: 32, 3397 array_layers: 1, 3398 }, 3399 format: Some(Format::R8G8B8A8_UNORM), 3400 samples: SampleCount::Sample2, 3401 usage: ImageUsage::STORAGE, 3402 ..Default::default() 3403 }, 3404 ); 3405 3406 match res { 3407 Err(ImageError::RequirementNotMet { 3408 requires_one_of: RequiresOneOf { features, .. }, 3409 .. 3410 }) if features.contains(&"shader_storage_image_multisample") => (), 3411 Err(ImageError::SampleCountNotSupported { .. }) => (), // unlikely but possible 3412 _ => panic!(), 3413 }; 3414 } 3415 3416 #[test] compressed_not_color_attachment()3417 fn compressed_not_color_attachment() { 3418 let (device, _) = gfx_dev_and_queue!(); 3419 3420 let res = RawImage::new( 3421 device, 3422 ImageCreateInfo { 3423 dimensions: ImageDimensions::Dim2d { 3424 width: 32, 3425 height: 32, 3426 array_layers: 1, 3427 }, 3428 format: Some(Format::ASTC_5x4_UNORM_BLOCK), 3429 usage: ImageUsage::COLOR_ATTACHMENT, 3430 ..Default::default() 3431 }, 3432 ); 3433 3434 match res { 3435 Err(ImageError::FormatNotSupported) => (), 3436 Err(ImageError::FormatUsageNotSupported { 3437 usage: "color_attachment", 3438 }) => (), 3439 _ => panic!(), 3440 }; 3441 } 3442 3443 #[test] transient_forbidden_with_some_usages()3444 fn transient_forbidden_with_some_usages() { 3445 let (device, _) = gfx_dev_and_queue!(); 3446 3447 assert_should_panic!({ 3448 let _ = RawImage::new( 3449 device, 3450 ImageCreateInfo { 3451 dimensions: ImageDimensions::Dim2d { 3452 width: 32, 3453 height: 32, 3454 array_layers: 1, 3455 }, 3456 format: Some(Format::R8G8B8A8_UNORM), 3457 usage: ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::SAMPLED, 3458 ..Default::default() 3459 }, 3460 ); 3461 }) 3462 } 3463 3464 #[test] cubecompatible_dims_mismatch()3465 fn cubecompatible_dims_mismatch() { 3466 let (device, _) = gfx_dev_and_queue!(); 3467 3468 let res = RawImage::new( 3469 device, 3470 ImageCreateInfo { 3471 flags: ImageCreateFlags::CUBE_COMPATIBLE, 3472 dimensions: ImageDimensions::Dim2d { 3473 width: 32, 3474 height: 64, 3475 array_layers: 1, 3476 }, 3477 format: Some(Format::R8G8B8A8_UNORM), 3478 usage: ImageUsage::SAMPLED, 3479 ..Default::default() 3480 }, 3481 ); 3482 3483 match res { 3484 Err(ImageError::CubeCompatibleNotEnoughArrayLayers) => (), 3485 Err(ImageError::CubeCompatibleNotSquare) => (), 3486 _ => panic!(), 3487 }; 3488 } 3489 3490 #[test] 3491 #[allow(clippy::erasing_op, clippy::identity_op)] subresource_range_iterator()3492 fn subresource_range_iterator() { 3493 // A fictitious set of aspects that no real image would actually ever have. 3494 let image_aspect_list: SmallVec<[ImageAspect; 4]> = (ImageAspects::COLOR 3495 | ImageAspects::DEPTH 3496 | ImageAspects::STENCIL 3497 | ImageAspects::PLANE_0) 3498 .into_iter() 3499 .collect(); 3500 let image_mip_levels = 6; 3501 let image_array_layers = 8; 3502 3503 let mip = image_array_layers as DeviceSize; 3504 let asp = mip * image_mip_levels as DeviceSize; 3505 3506 // Whole image 3507 let mut iter = SubresourceRangeIterator::new( 3508 ImageSubresourceRange { 3509 aspects: ImageAspects::COLOR 3510 | ImageAspects::DEPTH 3511 | ImageAspects::STENCIL 3512 | ImageAspects::PLANE_0, 3513 mip_levels: 0..6, 3514 array_layers: 0..8, 3515 }, 3516 &image_aspect_list, 3517 asp, 3518 image_mip_levels, 3519 mip, 3520 image_array_layers, 3521 ); 3522 3523 assert_eq!(iter.next(), Some(0 * asp..4 * asp)); 3524 assert_eq!(iter.next(), None); 3525 3526 // Only some aspects 3527 let mut iter = SubresourceRangeIterator::new( 3528 ImageSubresourceRange { 3529 aspects: ImageAspects::COLOR | ImageAspects::DEPTH | ImageAspects::PLANE_0, 3530 mip_levels: 0..6, 3531 array_layers: 0..8, 3532 }, 3533 &image_aspect_list, 3534 asp, 3535 image_mip_levels, 3536 mip, 3537 image_array_layers, 3538 ); 3539 3540 assert_eq!(iter.next(), Some(0 * asp..2 * asp)); 3541 assert_eq!(iter.next(), Some(3 * asp..4 * asp)); 3542 assert_eq!(iter.next(), None); 3543 3544 // Two aspects, and only some of the mip levels 3545 let mut iter = SubresourceRangeIterator::new( 3546 ImageSubresourceRange { 3547 aspects: ImageAspects::DEPTH | ImageAspects::STENCIL, 3548 mip_levels: 2..4, 3549 array_layers: 0..8, 3550 }, 3551 &image_aspect_list, 3552 asp, 3553 image_mip_levels, 3554 mip, 3555 image_array_layers, 3556 ); 3557 assert_eq!(iter.next(), Some(1 * asp + 2 * mip..1 * asp + 4 * mip)); 3558 assert_eq!(iter.next(), Some(2 * asp + 2 * mip..2 * asp + 4 * mip)); 3559 assert_eq!(iter.next(), None); 3560 3561 // One aspect, one mip level, only some of the array layers 3562 let mut iter = SubresourceRangeIterator::new( 3563 ImageSubresourceRange { 3564 aspects: ImageAspects::COLOR, 3565 3566 mip_levels: 0..1, 3567 array_layers: 2..4, 3568 }, 3569 &image_aspect_list, 3570 asp, 3571 image_mip_levels, 3572 mip, 3573 image_array_layers, 3574 ); 3575 3576 assert_eq!( 3577 iter.next(), 3578 Some(0 * asp + 0 * mip + 2..0 * asp + 0 * mip + 4) 3579 ); 3580 assert_eq!(iter.next(), None); 3581 3582 // Two aspects, two mip levels, only some of the array layers 3583 let mut iter = SubresourceRangeIterator::new( 3584 ImageSubresourceRange { 3585 aspects: ImageAspects::DEPTH | ImageAspects::STENCIL, 3586 mip_levels: 2..4, 3587 array_layers: 6..8, 3588 }, 3589 &image_aspect_list, 3590 asp, 3591 image_mip_levels, 3592 mip, 3593 image_array_layers, 3594 ); 3595 assert_eq!( 3596 iter.next(), 3597 Some(1 * asp + 2 * mip + 6..1 * asp + 2 * mip + 8) 3598 ); 3599 assert_eq!( 3600 iter.next(), 3601 Some(1 * asp + 3 * mip + 6..1 * asp + 3 * mip + 8) 3602 ); 3603 assert_eq!( 3604 iter.next(), 3605 Some(2 * asp + 2 * mip + 6..2 * asp + 2 * mip + 8) 3606 ); 3607 assert_eq!( 3608 iter.next(), 3609 Some(2 * asp + 3 * mip + 6..2 * asp + 3 * mip + 8) 3610 ); 3611 assert_eq!(iter.next(), None); 3612 } 3613 } 3614