1 // Copyright (c) 2021 The vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 //! Image views. 11 //! 12 //! This module contains types related to image views. An image view wraps around 13 //! an image and describes how the GPU should interpret the data. It is needed when an image is 14 //! to be used in a shader descriptor or as a framebuffer attachment. 15 16 use super::{ 17 sys::Image, ImageAccess, ImageDimensions, ImageFormatInfo, ImageSubresourceRange, ImageUsage, 18 }; 19 use crate::{ 20 device::{Device, DeviceOwned}, 21 format::{ChromaSampling, Format, FormatFeatures}, 22 image::{ImageAspects, ImageCreateFlags, ImageTiling, ImageType, SampleCount}, 23 macros::{impl_id_counter, vulkan_enum}, 24 sampler::{ycbcr::SamplerYcbcrConversion, ComponentMapping}, 25 OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, 26 }; 27 use std::{ 28 error::Error, 29 fmt::{Debug, Display, Error as FmtError, Formatter}, 30 hash::{Hash, Hasher}, 31 mem::MaybeUninit, 32 num::NonZeroU64, 33 ptr, 34 sync::Arc, 35 }; 36 37 /// A wrapper around an image that makes it available to shaders or framebuffers. 38 #[derive(Debug)] 39 pub struct ImageView<I> 40 where 41 I: ImageAccess + ?Sized, 42 { 43 handle: ash::vk::ImageView, 44 image: Arc<I>, 45 id: NonZeroU64, 46 47 component_mapping: ComponentMapping, 48 format: Option<Format>, 49 format_features: FormatFeatures, 50 sampler_ycbcr_conversion: Option<Arc<SamplerYcbcrConversion>>, 51 subresource_range: ImageSubresourceRange, 52 usage: ImageUsage, 53 view_type: ImageViewType, 54 55 filter_cubic: bool, 56 filter_cubic_minmax: bool, 57 } 58 59 impl<I> ImageView<I> 60 where 61 I: ImageAccess + ?Sized, 62 { 63 /// Creates a new `ImageView`. 64 /// 65 /// # Panics 66 /// 67 /// - Panics if `create_info.array_layers` is empty. 68 /// - Panics if `create_info.mip_levels` is empty. 69 /// - Panics if `create_info.aspects` contains any aspects other than `color`, `depth`, 70 /// `stencil`, `plane0`, `plane1` or `plane2`. 71 /// - Panics if `create_info.aspects` contains more more than one aspect, unless `depth` and 72 /// `stencil` are the only aspects selected. new( image: Arc<I>, create_info: ImageViewCreateInfo, ) -> Result<Arc<ImageView<I>>, ImageViewCreationError>73 pub fn new( 74 image: Arc<I>, 75 create_info: ImageViewCreateInfo, 76 ) -> Result<Arc<ImageView<I>>, ImageViewCreationError> { 77 let format_features = Self::validate_new(&image, &create_info)?; 78 79 unsafe { 80 Ok(Self::new_unchecked_with_format_features( 81 image, 82 create_info, 83 format_features, 84 )?) 85 } 86 } 87 validate_new( image: &I, create_info: &ImageViewCreateInfo, ) -> Result<FormatFeatures, ImageViewCreationError>88 fn validate_new( 89 image: &I, 90 create_info: &ImageViewCreateInfo, 91 ) -> Result<FormatFeatures, ImageViewCreationError> { 92 let &ImageViewCreateInfo { 93 view_type, 94 format, 95 component_mapping, 96 ref subresource_range, 97 mut usage, 98 ref sampler_ycbcr_conversion, 99 _ne: _, 100 } = create_info; 101 102 let image_inner = image.inner().image; 103 let device = image_inner.device(); 104 let format = format.unwrap(); 105 106 let level_count = subresource_range.mip_levels.end - subresource_range.mip_levels.start; 107 let layer_count = subresource_range.array_layers.end - subresource_range.array_layers.start; 108 109 // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask 110 assert!(!subresource_range.aspects.is_empty()); 111 112 // VUID-VkImageSubresourceRange-levelCount-01720 113 assert!(level_count != 0); 114 115 // VUID-VkImageSubresourceRange-layerCount-01721 116 assert!(layer_count != 0); 117 118 let default_usage = Self::get_default_usage(subresource_range.aspects, image_inner); 119 120 let has_non_default_usage = if usage.is_empty() { 121 usage = default_usage; 122 false 123 } else { 124 usage == default_usage 125 }; 126 127 // VUID-VkImageViewCreateInfo-viewType-parameter 128 view_type.validate_device(device)?; 129 130 // VUID-VkImageViewCreateInfo-format-parameter 131 format.validate_device(device)?; 132 133 // VUID-VkComponentMapping-r-parameter 134 component_mapping.r.validate_device(device)?; 135 136 // VUID-VkComponentMapping-g-parameter 137 component_mapping.g.validate_device(device)?; 138 139 // VUID-VkComponentMapping-b-parameter 140 component_mapping.b.validate_device(device)?; 141 142 // VUID-VkComponentMapping-a-parameter 143 component_mapping.a.validate_device(device)?; 144 145 // VUID-VkImageSubresourceRange-aspectMask-parameter 146 subresource_range.aspects.validate_device(device)?; 147 148 assert!(!subresource_range.aspects.intersects( 149 ImageAspects::METADATA 150 | ImageAspects::MEMORY_PLANE_0 151 | ImageAspects::MEMORY_PLANE_1 152 | ImageAspects::MEMORY_PLANE_2 153 )); 154 assert!({ 155 subresource_range.aspects.count() == 1 156 || subresource_range 157 .aspects 158 .contains(ImageAspects::DEPTH | ImageAspects::STENCIL) 159 && !subresource_range.aspects.intersects( 160 ImageAspects::COLOR 161 | ImageAspects::PLANE_0 162 | ImageAspects::PLANE_1 163 | ImageAspects::PLANE_2, 164 ) 165 }); 166 167 // Get format features 168 let format_features = unsafe { Self::get_format_features(format, image_inner) }; 169 170 // No VUID apparently, but this seems like something we want to check? 171 if !image_inner 172 .format() 173 .unwrap() 174 .aspects() 175 .contains(subresource_range.aspects) 176 { 177 return Err(ImageViewCreationError::ImageAspectsNotCompatible { 178 aspects: subresource_range.aspects, 179 image_aspects: image_inner.format().unwrap().aspects(), 180 }); 181 } 182 183 // VUID-VkImageViewCreateInfo-None-02273 184 if format_features == FormatFeatures::default() { 185 return Err(ImageViewCreationError::FormatNotSupported); 186 } 187 188 // Check for compatibility with the image 189 let image_type = image.dimensions().image_type(); 190 191 // VUID-VkImageViewCreateInfo-subResourceRange-01021 192 if !view_type.is_compatible_with(image_type) { 193 return Err(ImageViewCreationError::ImageTypeNotCompatible); 194 } 195 196 // VUID-VkImageViewCreateInfo-image-01003 197 if (view_type == ImageViewType::Cube || view_type == ImageViewType::CubeArray) 198 && !image_inner 199 .flags() 200 .intersects(ImageCreateFlags::CUBE_COMPATIBLE) 201 { 202 return Err(ImageViewCreationError::ImageNotCubeCompatible); 203 } 204 205 // VUID-VkImageViewCreateInfo-viewType-01004 206 if view_type == ImageViewType::CubeArray && !device.enabled_features().image_cube_array { 207 return Err(ImageViewCreationError::RequirementNotMet { 208 required_for: "`create_info.viewtype` is `ImageViewType::CubeArray`", 209 requires_one_of: RequiresOneOf { 210 features: &["image_cube_array"], 211 ..Default::default() 212 }, 213 }); 214 } 215 216 // VUID-VkImageViewCreateInfo-subresourceRange-01718 217 if subresource_range.mip_levels.end > image_inner.mip_levels() { 218 return Err(ImageViewCreationError::MipLevelsOutOfRange { 219 range_end: subresource_range.mip_levels.end, 220 max: image_inner.mip_levels(), 221 }); 222 } 223 224 if image_type == ImageType::Dim3d 225 && (view_type == ImageViewType::Dim2d || view_type == ImageViewType::Dim2dArray) 226 { 227 // VUID-VkImageViewCreateInfo-image-01005 228 if !image_inner 229 .flags() 230 .intersects(ImageCreateFlags::ARRAY_2D_COMPATIBLE) 231 { 232 return Err(ImageViewCreationError::ImageNotArray2dCompatible); 233 } 234 235 // VUID-VkImageViewCreateInfo-image-04970 236 if level_count != 1 { 237 return Err(ImageViewCreationError::Array2dCompatibleMultipleMipLevels); 238 } 239 240 // VUID-VkImageViewCreateInfo-image-02724 241 // VUID-VkImageViewCreateInfo-subresourceRange-02725 242 // We're using the depth dimension as array layers, but because of mip scaling, the 243 // depth, and therefore number of layers available, shrinks as the mip level gets 244 // higher. 245 let max = image_inner 246 .dimensions() 247 .mip_level_dimensions(subresource_range.mip_levels.start) 248 .unwrap() 249 .depth(); 250 if subresource_range.array_layers.end > max { 251 return Err(ImageViewCreationError::ArrayLayersOutOfRange { 252 range_end: subresource_range.array_layers.end, 253 max, 254 }); 255 } 256 } else { 257 // VUID-VkImageViewCreateInfo-image-01482 258 // VUID-VkImageViewCreateInfo-subresourceRange-01483 259 if subresource_range.array_layers.end > image_inner.dimensions().array_layers() { 260 return Err(ImageViewCreationError::ArrayLayersOutOfRange { 261 range_end: subresource_range.array_layers.end, 262 max: image_inner.dimensions().array_layers(), 263 }); 264 } 265 } 266 267 // VUID-VkImageViewCreateInfo-image-04972 268 if image_inner.samples() != SampleCount::Sample1 269 && !(view_type == ImageViewType::Dim2d || view_type == ImageViewType::Dim2dArray) 270 { 271 return Err(ImageViewCreationError::MultisamplingNot2d); 272 } 273 274 /* Check usage requirements */ 275 276 if has_non_default_usage { 277 if !(device.api_version() >= Version::V1_1 278 || device.enabled_extensions().khr_maintenance2) 279 { 280 return Err(ImageViewCreationError::RequirementNotMet { 281 required_for: "`create_info.usage` is not the default value", 282 requires_one_of: RequiresOneOf { 283 api_version: Some(Version::V1_1), 284 device_extensions: &["khr_maintenance2"], 285 ..Default::default() 286 }, 287 }); 288 } 289 290 // VUID-VkImageViewUsageCreateInfo-usage-parameter 291 usage.validate_device(device)?; 292 293 // VUID-VkImageViewUsageCreateInfo-usage-requiredbitmask 294 assert!(!usage.is_empty()); 295 296 // VUID-VkImageViewCreateInfo-pNext-02662 297 // VUID-VkImageViewCreateInfo-pNext-02663 298 // VUID-VkImageViewCreateInfo-pNext-02664 299 if !default_usage.contains(usage) { 300 return Err(ImageViewCreationError::UsageNotSupportedByImage { 301 usage, 302 supported_usage: default_usage, 303 }); 304 } 305 } 306 307 // VUID-VkImageViewCreateInfo-image-04441 308 if !image_inner.usage().intersects( 309 ImageUsage::SAMPLED 310 | ImageUsage::STORAGE 311 | ImageUsage::COLOR_ATTACHMENT 312 | ImageUsage::DEPTH_STENCIL_ATTACHMENT 313 | ImageUsage::INPUT_ATTACHMENT 314 | ImageUsage::TRANSIENT_ATTACHMENT, 315 ) { 316 return Err(ImageViewCreationError::ImageMissingUsage); 317 } 318 319 // VUID-VkImageViewCreateInfo-usage-02274 320 if usage.intersects(ImageUsage::SAMPLED) 321 && !format_features.intersects(FormatFeatures::SAMPLED_IMAGE) 322 { 323 return Err(ImageViewCreationError::FormatUsageNotSupported { usage: "sampled" }); 324 } 325 326 // VUID-VkImageViewCreateInfo-usage-02275 327 if usage.intersects(ImageUsage::STORAGE) 328 && !format_features.intersects(FormatFeatures::STORAGE_IMAGE) 329 { 330 return Err(ImageViewCreationError::FormatUsageNotSupported { usage: "storage" }); 331 } 332 333 // VUID-VkImageViewCreateInfo-usage-02276 334 if usage.intersects(ImageUsage::COLOR_ATTACHMENT) 335 && !format_features.intersects(FormatFeatures::COLOR_ATTACHMENT) 336 { 337 return Err(ImageViewCreationError::FormatUsageNotSupported { 338 usage: "color_attachment", 339 }); 340 } 341 342 // VUID-VkImageViewCreateInfo-usage-02277 343 if usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT) 344 && !format_features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) 345 { 346 return Err(ImageViewCreationError::FormatUsageNotSupported { 347 usage: "depth_stencil_attachment", 348 }); 349 } 350 351 // VUID-VkImageViewCreateInfo-usage-02652 352 if usage.intersects(ImageUsage::INPUT_ATTACHMENT) 353 && !format_features.intersects( 354 FormatFeatures::COLOR_ATTACHMENT | FormatFeatures::DEPTH_STENCIL_ATTACHMENT, 355 ) 356 { 357 return Err(ImageViewCreationError::FormatUsageNotSupported { 358 usage: "input_attachment", 359 }); 360 } 361 362 /* Check flags requirements */ 363 364 if Some(format) != image_inner.format() { 365 // VUID-VkImageViewCreateInfo-image-01762 366 if !image_inner 367 .flags() 368 .intersects(ImageCreateFlags::MUTABLE_FORMAT) 369 || !image_inner.format().unwrap().planes().is_empty() 370 && subresource_range.aspects.intersects(ImageAspects::COLOR) 371 { 372 return Err(ImageViewCreationError::FormatNotCompatible); 373 } 374 375 // VUID-VkImageViewCreateInfo-imageViewFormatReinterpretation-04466 376 // TODO: it is unclear what the number of bits is for compressed formats. 377 // See https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2361 378 if device.enabled_extensions().khr_portability_subset 379 && !device.enabled_features().image_view_format_reinterpretation 380 && format.components() != image_inner.format().unwrap().components() 381 { 382 return Err(ImageViewCreationError::RequirementNotMet { 383 required_for: "this device is a portability subset device, and the format of \ 384 the image view does not have the same components and number of bits per \ 385 component as the parent image", 386 requires_one_of: RequiresOneOf { 387 features: &["image_view_format_reinterpretation"], 388 ..Default::default() 389 }, 390 }); 391 } 392 393 if image_inner 394 .flags() 395 .intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE) 396 { 397 // VUID-VkImageViewCreateInfo-image-01583 398 if !(format.compatibility() == image_inner.format().unwrap().compatibility() 399 || format.block_size() == image_inner.format().unwrap().block_size()) 400 { 401 return Err(ImageViewCreationError::FormatNotCompatible); 402 } 403 404 if format.compression().is_none() { 405 // VUID-VkImageViewCreateInfo-image-01584 406 if layer_count != 1 { 407 return Err( 408 ImageViewCreationError::BlockTexelViewCompatibleMultipleArrayLayers, 409 ); 410 } 411 412 // VUID-VkImageViewCreateInfo-image-01584 413 if level_count != 1 { 414 return Err( 415 ImageViewCreationError::BlockTexelViewCompatibleMultipleMipLevels, 416 ); 417 } 418 } 419 } else { 420 if image_inner.format().unwrap().planes().is_empty() { 421 // VUID-VkImageViewCreateInfo-image-01761 422 if format.compatibility() != image_inner.format().unwrap().compatibility() { 423 return Err(ImageViewCreationError::FormatNotCompatible); 424 } 425 } else { 426 let plane = if subresource_range.aspects.intersects(ImageAspects::PLANE_0) { 427 0 428 } else if subresource_range.aspects.intersects(ImageAspects::PLANE_1) { 429 1 430 } else if subresource_range.aspects.intersects(ImageAspects::PLANE_2) { 431 2 432 } else { 433 unreachable!() 434 }; 435 let plane_format = image_inner.format().unwrap().planes()[plane]; 436 437 // VUID-VkImageViewCreateInfo-image-01586 438 if format.compatibility() != plane_format.compatibility() { 439 return Err(ImageViewCreationError::FormatNotCompatible); 440 } 441 } 442 } 443 } 444 445 // VUID-VkImageViewCreateInfo-imageViewType-04973 446 if (view_type == ImageViewType::Dim1d 447 || view_type == ImageViewType::Dim2d 448 || view_type == ImageViewType::Dim3d) 449 && layer_count != 1 450 { 451 return Err(ImageViewCreationError::TypeNonArrayedMultipleArrayLayers); 452 } 453 // VUID-VkImageViewCreateInfo-viewType-02960 454 else if view_type == ImageViewType::Cube && layer_count != 6 { 455 return Err(ImageViewCreationError::TypeCubeNot6ArrayLayers); 456 } 457 // VUID-VkImageViewCreateInfo-viewType-02961 458 else if view_type == ImageViewType::CubeArray && layer_count % 6 != 0 { 459 return Err(ImageViewCreationError::TypeCubeArrayNotMultipleOf6ArrayLayers); 460 } 461 462 // VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465 463 if device.enabled_extensions().khr_portability_subset 464 && !device.enabled_features().image_view_format_swizzle 465 && !component_mapping.is_identity() 466 { 467 return Err(ImageViewCreationError::RequirementNotMet { 468 required_for: "this device is a portability subset device, and \ 469 `create_info.component_mapping` is not the identity mapping", 470 requires_one_of: RequiresOneOf { 471 features: &["image_view_format_swizzle"], 472 ..Default::default() 473 }, 474 }); 475 } 476 477 // VUID-VkImageViewCreateInfo-format-04714 478 // VUID-VkImageViewCreateInfo-format-04715 479 match format.ycbcr_chroma_sampling() { 480 Some(ChromaSampling::Mode422) => { 481 if image_inner.dimensions().width() % 2 != 0 { 482 return Err( 483 ImageViewCreationError::FormatChromaSubsamplingInvalidImageDimensions, 484 ); 485 } 486 } 487 Some(ChromaSampling::Mode420) => { 488 if image_inner.dimensions().width() % 2 != 0 489 || image_inner.dimensions().height() % 2 != 0 490 { 491 return Err( 492 ImageViewCreationError::FormatChromaSubsamplingInvalidImageDimensions, 493 ); 494 } 495 } 496 _ => (), 497 } 498 499 // Don't need to check features because you can't create a conversion object without the 500 // feature anyway. 501 if let Some(conversion) = &sampler_ycbcr_conversion { 502 assert_eq!(device, conversion.device()); 503 504 // VUID-VkImageViewCreateInfo-pNext-01970 505 if !component_mapping.is_identity() { 506 return Err( 507 ImageViewCreationError::SamplerYcbcrConversionComponentMappingNotIdentity { 508 component_mapping, 509 }, 510 ); 511 } 512 } else { 513 // VUID-VkImageViewCreateInfo-format-06415 514 if format.ycbcr_chroma_sampling().is_some() { 515 return Err( 516 ImageViewCreationError::FormatRequiresSamplerYcbcrConversion { format }, 517 ); 518 } 519 } 520 521 Ok(format_features) 522 } 523 524 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] new_unchecked( image: Arc<I>, create_info: ImageViewCreateInfo, ) -> Result<Arc<Self>, VulkanError>525 pub unsafe fn new_unchecked( 526 image: Arc<I>, 527 create_info: ImageViewCreateInfo, 528 ) -> Result<Arc<Self>, VulkanError> { 529 let format_features = 530 Self::get_format_features(create_info.format.unwrap(), image.inner().image); 531 Self::new_unchecked_with_format_features(image, create_info, format_features) 532 } 533 new_unchecked_with_format_features( image: Arc<I>, create_info: ImageViewCreateInfo, format_features: FormatFeatures, ) -> Result<Arc<Self>, VulkanError>534 unsafe fn new_unchecked_with_format_features( 535 image: Arc<I>, 536 create_info: ImageViewCreateInfo, 537 format_features: FormatFeatures, 538 ) -> Result<Arc<Self>, VulkanError> { 539 let &ImageViewCreateInfo { 540 view_type, 541 format, 542 component_mapping, 543 ref subresource_range, 544 mut usage, 545 ref sampler_ycbcr_conversion, 546 _ne: _, 547 } = &create_info; 548 549 let image_inner = image.inner().image; 550 let device = image_inner.device(); 551 552 let default_usage = Self::get_default_usage(subresource_range.aspects, image_inner); 553 554 let has_non_default_usage = if usage.is_empty() { 555 usage = default_usage; 556 false 557 } else { 558 usage == default_usage 559 }; 560 561 let mut info_vk = ash::vk::ImageViewCreateInfo { 562 flags: ash::vk::ImageViewCreateFlags::empty(), 563 image: image_inner.handle(), 564 view_type: view_type.into(), 565 format: format.unwrap().into(), 566 components: component_mapping.into(), 567 subresource_range: subresource_range.clone().into(), 568 ..Default::default() 569 }; 570 let mut image_view_usage_info_vk = None; 571 let mut sampler_ycbcr_conversion_info_vk = None; 572 573 if has_non_default_usage { 574 let next = image_view_usage_info_vk.insert(ash::vk::ImageViewUsageCreateInfo { 575 usage: usage.into(), 576 ..Default::default() 577 }); 578 579 next.p_next = info_vk.p_next; 580 info_vk.p_next = next as *const _ as *const _; 581 } 582 583 if let Some(conversion) = sampler_ycbcr_conversion { 584 let next = 585 sampler_ycbcr_conversion_info_vk.insert(ash::vk::SamplerYcbcrConversionInfo { 586 conversion: conversion.handle(), 587 ..Default::default() 588 }); 589 590 next.p_next = info_vk.p_next; 591 info_vk.p_next = next as *const _ as *const _; 592 } 593 594 let handle = { 595 let fns = device.fns(); 596 let mut output = MaybeUninit::uninit(); 597 (fns.v1_0.create_image_view)( 598 device.handle(), 599 &info_vk, 600 ptr::null(), 601 output.as_mut_ptr(), 602 ) 603 .result() 604 .map_err(VulkanError::from)?; 605 output.assume_init() 606 }; 607 608 Self::from_handle_with_format_features(image, handle, create_info, format_features) 609 } 610 611 /// Creates a default `ImageView`. Equivalent to 612 /// `ImageView::new(image, ImageViewCreateInfo::from_image(image))`. new_default(image: Arc<I>) -> Result<Arc<ImageView<I>>, ImageViewCreationError>613 pub fn new_default(image: Arc<I>) -> Result<Arc<ImageView<I>>, ImageViewCreationError> { 614 let create_info = ImageViewCreateInfo::from_image(&image); 615 Self::new(image, create_info) 616 } 617 618 /// Creates a new `ImageView` from a raw object handle. 619 /// 620 /// # Safety 621 /// 622 /// - `handle` must be a valid Vulkan object handle created from `image`. 623 /// - `create_info` must match the info used to create the object. from_handle( image: Arc<I>, handle: ash::vk::ImageView, create_info: ImageViewCreateInfo, ) -> Result<Arc<Self>, VulkanError>624 pub unsafe fn from_handle( 625 image: Arc<I>, 626 handle: ash::vk::ImageView, 627 create_info: ImageViewCreateInfo, 628 ) -> Result<Arc<Self>, VulkanError> { 629 let format_features = 630 Self::get_format_features(create_info.format.unwrap(), image.inner().image); 631 Self::from_handle_with_format_features(image, handle, create_info, format_features) 632 } 633 from_handle_with_format_features( image: Arc<I>, handle: ash::vk::ImageView, create_info: ImageViewCreateInfo, format_features: FormatFeatures, ) -> Result<Arc<Self>, VulkanError>634 unsafe fn from_handle_with_format_features( 635 image: Arc<I>, 636 handle: ash::vk::ImageView, 637 create_info: ImageViewCreateInfo, 638 format_features: FormatFeatures, 639 ) -> Result<Arc<Self>, VulkanError> { 640 let ImageViewCreateInfo { 641 view_type, 642 format, 643 component_mapping, 644 subresource_range, 645 mut usage, 646 sampler_ycbcr_conversion, 647 _ne: _, 648 } = create_info; 649 650 let image_inner = image.inner().image; 651 let device = image_inner.device(); 652 653 if usage.is_empty() { 654 usage = Self::get_default_usage(subresource_range.aspects, image_inner); 655 } 656 657 let mut filter_cubic = false; 658 let mut filter_cubic_minmax = false; 659 660 if device 661 .physical_device() 662 .supported_extensions() 663 .ext_filter_cubic 664 { 665 // Use unchecked, because all validation has been done above or is validated by the 666 // image. 667 let properties = 668 device 669 .physical_device() 670 .image_format_properties_unchecked(ImageFormatInfo { 671 flags: image_inner.flags(), 672 format: image_inner.format(), 673 image_type: image.dimensions().image_type(), 674 tiling: image_inner.tiling(), 675 usage: image_inner.usage(), 676 image_view_type: Some(view_type), 677 ..Default::default() 678 })?; 679 680 if let Some(properties) = properties { 681 filter_cubic = properties.filter_cubic; 682 filter_cubic_minmax = properties.filter_cubic_minmax; 683 } 684 } 685 686 Ok(Arc::new(ImageView { 687 handle, 688 image, 689 id: Self::next_id(), 690 view_type, 691 format, 692 format_features, 693 component_mapping, 694 subresource_range, 695 usage, 696 sampler_ycbcr_conversion, 697 filter_cubic, 698 filter_cubic_minmax, 699 })) 700 } 701 702 // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkImageViewCreateInfo.html#_description get_default_usage(aspects: ImageAspects, image: &Image) -> ImageUsage703 fn get_default_usage(aspects: ImageAspects, image: &Image) -> ImageUsage { 704 let has_stencil_aspect = aspects.intersects(ImageAspects::STENCIL); 705 let has_non_stencil_aspect = !(aspects - ImageAspects::STENCIL).is_empty(); 706 707 if has_stencil_aspect && has_non_stencil_aspect { 708 image.usage() & image.stencil_usage() 709 } else if has_stencil_aspect { 710 image.stencil_usage() 711 } else if has_non_stencil_aspect { 712 image.usage() 713 } else { 714 unreachable!() 715 } 716 } 717 718 // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/chap12.html#resources-image-view-format-features get_format_features(format: Format, image: &Image) -> FormatFeatures719 unsafe fn get_format_features(format: Format, image: &Image) -> FormatFeatures { 720 let device = image.device(); 721 722 let mut format_features = if Some(format) != image.format() { 723 // Use unchecked, because all validation should have been done before calling. 724 let format_properties = device.physical_device().format_properties_unchecked(format); 725 726 match image.tiling() { 727 ImageTiling::Optimal => format_properties.optimal_tiling_features, 728 ImageTiling::Linear => format_properties.linear_tiling_features, 729 ImageTiling::DrmFormatModifier => format_properties.linear_tiling_features, 730 } 731 } else { 732 image.format_features() 733 }; 734 735 if !device.enabled_extensions().khr_format_feature_flags2 { 736 if format.type_color().is_none() 737 && format_features.intersects(FormatFeatures::SAMPLED_IMAGE) 738 { 739 format_features |= FormatFeatures::SAMPLED_IMAGE_DEPTH_COMPARISON; 740 } 741 742 if format.shader_storage_image_without_format() { 743 if device 744 .enabled_features() 745 .shader_storage_image_read_without_format 746 { 747 format_features |= FormatFeatures::STORAGE_READ_WITHOUT_FORMAT; 748 } 749 750 if device 751 .enabled_features() 752 .shader_storage_image_write_without_format 753 { 754 format_features |= FormatFeatures::STORAGE_WRITE_WITHOUT_FORMAT; 755 } 756 } 757 } 758 759 format_features 760 } 761 762 /// Returns the wrapped image that this image view was created from. image(&self) -> &Arc<I>763 pub fn image(&self) -> &Arc<I> { 764 &self.image 765 } 766 } 767 768 impl<I> Drop for ImageView<I> 769 where 770 I: ImageAccess + ?Sized, 771 { drop(&mut self)772 fn drop(&mut self) { 773 unsafe { 774 let device = self.device(); 775 let fns = device.fns(); 776 (fns.v1_0.destroy_image_view)(device.handle(), self.handle, ptr::null()); 777 } 778 } 779 } 780 781 unsafe impl<I> VulkanObject for ImageView<I> 782 where 783 I: ImageAccess + ?Sized, 784 { 785 type Handle = ash::vk::ImageView; 786 handle(&self) -> Self::Handle787 fn handle(&self) -> Self::Handle { 788 self.handle 789 } 790 } 791 792 unsafe impl<I> DeviceOwned for ImageView<I> 793 where 794 I: ImageAccess + ?Sized, 795 { device(&self) -> &Arc<Device>796 fn device(&self) -> &Arc<Device> { 797 self.image.inner().image.device() 798 } 799 } 800 801 impl_id_counter!(ImageView<I: ImageAccess + ?Sized>); 802 803 /// Parameters to create a new `ImageView`. 804 #[derive(Debug)] 805 pub struct ImageViewCreateInfo { 806 /// The image view type. 807 /// 808 /// The view type must be compatible with the dimensions of the image and the selected array 809 /// layers. 810 /// 811 /// The default value is [`ImageViewType::Dim2d`]. 812 pub view_type: ImageViewType, 813 814 /// The format of the image view. 815 /// 816 /// If this is set to a format that is different from the image, the image must be created with 817 /// the `mutable_format` flag. 818 /// 819 /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag) 820 /// devices, if `format` does not have the same number of components and bits per component as 821 /// the parent image's format, the 822 /// [`image_view_format_reinterpretation`](crate::device::Features::image_view_format_reinterpretation) 823 /// feature must be enabled on the device. 824 /// 825 /// The default value is `None`, which must be overridden. 826 pub format: Option<Format>, 827 828 /// How to map components of each pixel. 829 /// 830 /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag) 831 /// devices, if `component_mapping` is not the identity mapping, the 832 /// [`image_view_format_swizzle`](crate::device::Features::image_view_format_swizzle) 833 /// feature must be enabled on the device. 834 /// 835 /// The default value is [`ComponentMapping::identity()`]. 836 pub component_mapping: ComponentMapping, 837 838 /// The subresource range of the image that the view should cover. 839 /// 840 /// The default value is empty, which must be overridden. 841 pub subresource_range: ImageSubresourceRange, 842 843 /// How the image view is going to be used. 844 /// 845 /// If `usage` is empty, then a default value is used based on the parent image's usages. 846 /// Depending on the image aspects selected in `subresource_range`, 847 /// the default `usage` will be equal to the parent image's `usage`, its `stencil_usage`, 848 /// or the intersection of the two. 849 /// 850 /// If you set `usage` to a different value from the default, then the device API version must 851 /// be at least 1.1, or the [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2) 852 /// extension must be enabled on the device. The specified `usage` must be a subset of the 853 /// default value; usages that are not set for the parent image are not allowed. 854 /// 855 /// The default value is [`ImageUsage::empty()`]. 856 pub usage: ImageUsage, 857 858 /// The sampler YCbCr conversion to be used with the image view. 859 /// 860 /// If set to `Some`, several restrictions apply: 861 /// - The `component_mapping` must be the identity swizzle for all components. 862 /// - If the image view is to be used in a shader, it must be in a combined image sampler 863 /// descriptor, a separate sampled image descriptor is not allowed. 864 /// - The corresponding sampler must have the same sampler YCbCr object or an identically 865 /// created one, and must be used as an immutable sampler within a descriptor set layout. 866 /// 867 /// The default value is `None`. 868 pub sampler_ycbcr_conversion: Option<Arc<SamplerYcbcrConversion>>, 869 870 pub _ne: crate::NonExhaustive, 871 } 872 873 impl Default for ImageViewCreateInfo { 874 #[inline] default() -> Self875 fn default() -> Self { 876 Self { 877 view_type: ImageViewType::Dim2d, 878 format: None, 879 component_mapping: ComponentMapping::identity(), 880 subresource_range: ImageSubresourceRange { 881 aspects: ImageAspects::empty(), 882 array_layers: 0..0, 883 mip_levels: 0..0, 884 }, 885 usage: ImageUsage::empty(), 886 sampler_ycbcr_conversion: None, 887 _ne: crate::NonExhaustive(()), 888 } 889 } 890 } 891 892 impl ImageViewCreateInfo { 893 /// Returns an `ImageViewCreateInfo` with the `view_type` determined from the image type and 894 /// array layers, and `subresource_range` determined from the image format and covering the 895 /// whole image. from_image(image: &(impl ImageAccess + ?Sized)) -> Self896 pub fn from_image(image: &(impl ImageAccess + ?Sized)) -> Self { 897 Self { 898 view_type: match image.dimensions() { 899 ImageDimensions::Dim1d { 900 array_layers: 1, .. 901 } => ImageViewType::Dim1d, 902 ImageDimensions::Dim1d { .. } => ImageViewType::Dim1dArray, 903 ImageDimensions::Dim2d { 904 array_layers: 1, .. 905 } => ImageViewType::Dim2d, 906 ImageDimensions::Dim2d { .. } => ImageViewType::Dim2dArray, 907 ImageDimensions::Dim3d { .. } => ImageViewType::Dim3d, 908 }, 909 format: Some(image.format()), 910 subresource_range: image.subresource_range(), 911 ..Default::default() 912 } 913 } 914 } 915 916 /// Error that can happen when creating an image view. 917 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 918 pub enum ImageViewCreationError { 919 /// Allocating memory failed. 920 OomError(OomError), 921 922 RequirementNotMet { 923 required_for: &'static str, 924 requires_one_of: RequiresOneOf, 925 }, 926 927 /// A 2D image view was requested from a 3D image, but a range of multiple mip levels was 928 /// specified. 929 Array2dCompatibleMultipleMipLevels, 930 931 /// The specified range of array layers was not a subset of those in the image. 932 ArrayLayersOutOfRange { range_end: u32, max: u32 }, 933 934 /// The image has the `block_texel_view_compatible` flag, but a range of multiple array layers 935 /// was specified. 936 BlockTexelViewCompatibleMultipleArrayLayers, 937 938 /// The image has the `block_texel_view_compatible` flag, but a range of multiple mip levels 939 /// was specified. 940 BlockTexelViewCompatibleMultipleMipLevels, 941 942 /// The requested format has chroma subsampling, but the width and/or height of the image was 943 /// not a multiple of 2. 944 FormatChromaSubsamplingInvalidImageDimensions, 945 946 /// The requested format was not compatible with the image. 947 FormatNotCompatible, 948 949 /// The given format was not supported by the device. 950 FormatNotSupported, 951 952 /// The format requires a sampler YCbCr conversion, but none was provided. 953 FormatRequiresSamplerYcbcrConversion { format: Format }, 954 955 /// A requested usage flag was not supported by the given format. 956 FormatUsageNotSupported { usage: &'static str }, 957 958 /// An aspect was selected that was not present in the image. 959 ImageAspectsNotCompatible { 960 aspects: ImageAspects, 961 image_aspects: ImageAspects, 962 }, 963 964 /// The image was not created with 965 /// [one of the required usages](https://registry.khronos.org/vulkan/specs/1.2-extensions/html/vkspec.html#valid-imageview-imageusage) 966 /// for image views. 967 ImageMissingUsage, 968 969 /// A 2D image view was requested from a 3D image, but the image was not created with the 970 /// `array_2d_compatible` flag. 971 ImageNotArray2dCompatible, 972 973 /// A cube image view type was requested, but the image was not created with the 974 /// `cube_compatible` flag. 975 ImageNotCubeCompatible, 976 977 /// The given image view type was not compatible with the type of the image. 978 ImageTypeNotCompatible, 979 980 /// The requested [`ImageViewType`] was not compatible with the image, or with the specified 981 /// ranges of array layers and mipmap levels. 982 IncompatibleType, 983 984 /// The specified range of mip levels was not a subset of those in the image. 985 MipLevelsOutOfRange { range_end: u32, max: u32 }, 986 987 /// The image has multisampling enabled, but the image view type was not `Dim2d` or 988 /// `Dim2dArray`. 989 MultisamplingNot2d, 990 991 /// Sampler YCbCr conversion was enabled, but `component_mapping` was not the identity mapping. 992 SamplerYcbcrConversionComponentMappingNotIdentity { component_mapping: ComponentMapping }, 993 994 /// The `CubeArray` image view type was specified, but the range of array layers did not have a 995 /// size that is a multiple 6. 996 TypeCubeArrayNotMultipleOf6ArrayLayers, 997 998 /// The `Cube` image view type was specified, but the range of array layers did not have a size 999 /// of 6. 1000 TypeCubeNot6ArrayLayers, 1001 1002 /// A non-arrayed image view type was specified, but a range of multiple array layers was 1003 /// specified. 1004 TypeNonArrayedMultipleArrayLayers, 1005 1006 /// The provided `usage` is not supported by the parent image. 1007 UsageNotSupportedByImage { 1008 usage: ImageUsage, 1009 supported_usage: ImageUsage, 1010 }, 1011 } 1012 1013 impl Error for ImageViewCreationError { source(&self) -> Option<&(dyn Error + 'static)>1014 fn source(&self) -> Option<&(dyn Error + 'static)> { 1015 match self { 1016 ImageViewCreationError::OomError(err) => Some(err), 1017 _ => None, 1018 } 1019 } 1020 } 1021 1022 impl Display for ImageViewCreationError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1023 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 1024 match self { 1025 Self::OomError(_) => write!(f, "allocating memory failed",), 1026 Self::RequirementNotMet { 1027 required_for, 1028 requires_one_of, 1029 } => write!( 1030 f, 1031 "a requirement was not met for: {}; requires one of: {}", 1032 required_for, requires_one_of, 1033 ), 1034 Self::Array2dCompatibleMultipleMipLevels => write!( 1035 f, 1036 "a 2D image view was requested from a 3D image, but a range of multiple mip levels \ 1037 was specified", 1038 ), 1039 Self::ArrayLayersOutOfRange { .. } => write!( 1040 f, 1041 "the specified range of array layers was not a subset of those in the image", 1042 ), 1043 Self::BlockTexelViewCompatibleMultipleArrayLayers => write!( 1044 f, 1045 "the image has the `block_texel_view_compatible` flag, but a range of multiple \ 1046 array layers was specified", 1047 ), 1048 Self::BlockTexelViewCompatibleMultipleMipLevels => write!( 1049 f, 1050 "the image has the `block_texel_view_compatible` flag, but a range of multiple mip \ 1051 levels was specified", 1052 ), 1053 Self::FormatChromaSubsamplingInvalidImageDimensions => write!( 1054 f, 1055 "the requested format has chroma subsampling, but the width and/or height of the \ 1056 image was not a multiple of 2", 1057 ), 1058 Self::FormatNotCompatible => { 1059 write!(f, "the requested format was not compatible with the image") 1060 } 1061 Self::FormatNotSupported => { 1062 write!(f, "the given format was not supported by the device") 1063 } 1064 Self::FormatRequiresSamplerYcbcrConversion { .. } => write!( 1065 f, 1066 "the format requires a sampler YCbCr conversion, but none was provided", 1067 ), 1068 Self::FormatUsageNotSupported { .. } => write!( 1069 f, 1070 "a requested usage flag was not supported by the given format", 1071 ), 1072 Self::ImageAspectsNotCompatible { .. } => write!( 1073 f, 1074 "an aspect was selected that was not present in the image", 1075 ), 1076 Self::ImageMissingUsage => write!( 1077 f, 1078 "the image was not created with one of the required usages for image views", 1079 ), 1080 Self::ImageNotArray2dCompatible => write!( 1081 f, 1082 "a 2D image view was requested from a 3D image, but the image was not created with \ 1083 the `array_2d_compatible` flag", 1084 ), 1085 Self::ImageNotCubeCompatible => write!( 1086 f, 1087 "a cube image view type was requested, but the image was not created with the \ 1088 `cube_compatible` flag", 1089 ), 1090 Self::ImageTypeNotCompatible => write!( 1091 f, 1092 "the given image view type was not compatible with the type of the image", 1093 ), 1094 Self::IncompatibleType => write!( 1095 f, 1096 "image view type is not compatible with image, array layers or mipmap levels", 1097 ), 1098 Self::MipLevelsOutOfRange { .. } => write!( 1099 f, 1100 "the specified range of mip levels was not a subset of those in the image", 1101 ), 1102 Self::MultisamplingNot2d => write!( 1103 f, 1104 "the image has multisampling enabled, but the image view type was not `Dim2d` or \ 1105 `Dim2dArray`", 1106 ), 1107 Self::SamplerYcbcrConversionComponentMappingNotIdentity { .. } => write!( 1108 f, 1109 "sampler YCbCr conversion was enabled, but `component_mapping` was not the \ 1110 identity mapping", 1111 ), 1112 Self::TypeCubeArrayNotMultipleOf6ArrayLayers => write!( 1113 f, 1114 "the `CubeArray` image view type was specified, but the range of array layers did \ 1115 not have a size that is a multiple 6", 1116 ), 1117 Self::TypeCubeNot6ArrayLayers => write!( 1118 f, 1119 "the `Cube` image view type was specified, but the range of array layers did not \ 1120 have a size of 6", 1121 ), 1122 Self::TypeNonArrayedMultipleArrayLayers => write!( 1123 f, 1124 "a non-arrayed image view type was specified, but a range of multiple array layers \ 1125 was specified", 1126 ), 1127 Self::UsageNotSupportedByImage { 1128 usage: _, 1129 supported_usage: _, 1130 } => write!( 1131 f, 1132 "the provided `usage` is not supported by the parent image", 1133 ), 1134 } 1135 } 1136 } 1137 1138 impl From<OomError> for ImageViewCreationError { from(err: OomError) -> ImageViewCreationError1139 fn from(err: OomError) -> ImageViewCreationError { 1140 ImageViewCreationError::OomError(err) 1141 } 1142 } 1143 1144 impl From<VulkanError> for ImageViewCreationError { from(err: VulkanError) -> ImageViewCreationError1145 fn from(err: VulkanError) -> ImageViewCreationError { 1146 match err { 1147 err @ VulkanError::OutOfHostMemory => OomError::from(err).into(), 1148 err @ VulkanError::OutOfDeviceMemory => OomError::from(err).into(), 1149 _ => panic!("unexpected error: {:?}", err), 1150 } 1151 } 1152 } 1153 1154 impl From<RequirementNotMet> for ImageViewCreationError { from(err: RequirementNotMet) -> Self1155 fn from(err: RequirementNotMet) -> Self { 1156 Self::RequirementNotMet { 1157 required_for: err.required_for, 1158 requires_one_of: err.requires_one_of, 1159 } 1160 } 1161 } 1162 1163 vulkan_enum! { 1164 #[non_exhaustive] 1165 1166 /// The geometry type of an image view. 1167 ImageViewType impl { 1168 /// Returns whether the type is arrayed. 1169 #[inline] 1170 pub fn is_arrayed(self) -> bool { 1171 match self { 1172 Self::Dim1d | Self::Dim2d | Self::Dim3d | Self::Cube => false, 1173 Self::Dim1dArray | Self::Dim2dArray | Self::CubeArray => true, 1174 } 1175 } 1176 1177 /// Returns whether `self` is compatible with the given `image_type`. 1178 #[inline] 1179 pub fn is_compatible_with(self, image_type: ImageType) -> bool { 1180 matches!( 1181 (self, image_type,), 1182 ( 1183 ImageViewType::Dim1d | ImageViewType::Dim1dArray, 1184 ImageType::Dim1d 1185 ) | ( 1186 ImageViewType::Dim2d | ImageViewType::Dim2dArray, 1187 ImageType::Dim2d | ImageType::Dim3d 1188 ) | ( 1189 ImageViewType::Cube | ImageViewType::CubeArray, 1190 ImageType::Dim2d 1191 ) | (ImageViewType::Dim3d, ImageType::Dim3d) 1192 ) 1193 } 1194 } 1195 = ImageViewType(i32); 1196 1197 // TODO: document 1198 Dim1d = TYPE_1D, 1199 1200 // TODO: document 1201 Dim2d = TYPE_2D, 1202 1203 // TODO: document 1204 Dim3d = TYPE_3D, 1205 1206 // TODO: document 1207 Cube = CUBE, 1208 1209 // TODO: document 1210 Dim1dArray = TYPE_1D_ARRAY, 1211 1212 // TODO: document 1213 Dim2dArray = TYPE_2D_ARRAY, 1214 1215 // TODO: document 1216 CubeArray = CUBE_ARRAY, 1217 } 1218 1219 /// Trait for types that represent the GPU can access an image view. 1220 pub unsafe trait ImageViewAbstract: 1221 VulkanObject<Handle = ash::vk::ImageView> + DeviceOwned + Debug + Send + Sync 1222 { 1223 /// Returns the wrapped image that this image view was created from. image(&self) -> Arc<dyn ImageAccess>1224 fn image(&self) -> Arc<dyn ImageAccess>; 1225 1226 /// Returns the component mapping of this view. component_mapping(&self) -> ComponentMapping1227 fn component_mapping(&self) -> ComponentMapping; 1228 1229 /// Returns the dimensions of this view. 1230 #[inline] dimensions(&self) -> ImageDimensions1231 fn dimensions(&self) -> ImageDimensions { 1232 let subresource_range = self.subresource_range(); 1233 let array_layers = 1234 subresource_range.array_layers.end - subresource_range.array_layers.start; 1235 1236 match self.image().dimensions() { 1237 ImageDimensions::Dim1d { width, .. } => ImageDimensions::Dim1d { 1238 width, 1239 array_layers, 1240 }, 1241 ImageDimensions::Dim2d { width, height, .. } => ImageDimensions::Dim2d { 1242 width, 1243 height, 1244 array_layers, 1245 }, 1246 ImageDimensions::Dim3d { 1247 width, 1248 height, 1249 depth, 1250 } => ImageDimensions::Dim3d { 1251 width, 1252 height, 1253 depth, 1254 }, 1255 } 1256 } 1257 1258 /// Returns whether the image view supports sampling with a 1259 /// [`Cubic`](crate::sampler::Filter::Cubic) `mag_filter` or `min_filter`. filter_cubic(&self) -> bool1260 fn filter_cubic(&self) -> bool; 1261 1262 /// Returns whether the image view supports sampling with a 1263 /// [`Cubic`](crate::sampler::Filter::Cubic) `mag_filter` or `min_filter`, and with a 1264 /// [`Min`](crate::sampler::SamplerReductionMode::Min) or 1265 /// [`Max`](crate::sampler::SamplerReductionMode::Max) `reduction_mode`. filter_cubic_minmax(&self) -> bool1266 fn filter_cubic_minmax(&self) -> bool; 1267 1268 /// Returns the format of this view. This can be different from the parent's format. format(&self) -> Option<Format>1269 fn format(&self) -> Option<Format>; 1270 1271 /// Returns the features supported by the image view's format. format_features(&self) -> FormatFeatures1272 fn format_features(&self) -> FormatFeatures; 1273 1274 /// Returns the sampler YCbCr conversion that this image view was created with, if any. sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>>1275 fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>>; 1276 1277 /// Returns the subresource range of the wrapped image that this view exposes. subresource_range(&self) -> &ImageSubresourceRange1278 fn subresource_range(&self) -> &ImageSubresourceRange; 1279 1280 /// Returns the usage of the image view. usage(&self) -> ImageUsage1281 fn usage(&self) -> ImageUsage; 1282 1283 /// Returns the [`ImageViewType`] of this image view. view_type(&self) -> ImageViewType1284 fn view_type(&self) -> ImageViewType; 1285 } 1286 1287 unsafe impl<I> ImageViewAbstract for ImageView<I> 1288 where 1289 I: ImageAccess + Debug + 'static, 1290 { image(&self) -> Arc<dyn ImageAccess>1291 fn image(&self) -> Arc<dyn ImageAccess> { 1292 self.image.clone() 1293 } 1294 component_mapping(&self) -> ComponentMapping1295 fn component_mapping(&self) -> ComponentMapping { 1296 self.component_mapping 1297 } 1298 filter_cubic(&self) -> bool1299 fn filter_cubic(&self) -> bool { 1300 self.filter_cubic 1301 } 1302 filter_cubic_minmax(&self) -> bool1303 fn filter_cubic_minmax(&self) -> bool { 1304 self.filter_cubic_minmax 1305 } 1306 format(&self) -> Option<Format>1307 fn format(&self) -> Option<Format> { 1308 self.format 1309 } 1310 format_features(&self) -> FormatFeatures1311 fn format_features(&self) -> FormatFeatures { 1312 self.format_features 1313 } 1314 sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>>1315 fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> { 1316 self.sampler_ycbcr_conversion.as_ref() 1317 } 1318 subresource_range(&self) -> &ImageSubresourceRange1319 fn subresource_range(&self) -> &ImageSubresourceRange { 1320 &self.subresource_range 1321 } 1322 usage(&self) -> ImageUsage1323 fn usage(&self) -> ImageUsage { 1324 self.usage 1325 } 1326 view_type(&self) -> ImageViewType1327 fn view_type(&self) -> ImageViewType { 1328 self.view_type 1329 } 1330 } 1331 1332 unsafe impl ImageViewAbstract for ImageView<dyn ImageAccess> { 1333 #[inline] image(&self) -> Arc<dyn ImageAccess>1334 fn image(&self) -> Arc<dyn ImageAccess> { 1335 self.image.clone() 1336 } 1337 1338 #[inline] component_mapping(&self) -> ComponentMapping1339 fn component_mapping(&self) -> ComponentMapping { 1340 self.component_mapping 1341 } 1342 1343 #[inline] filter_cubic(&self) -> bool1344 fn filter_cubic(&self) -> bool { 1345 self.filter_cubic 1346 } 1347 1348 #[inline] filter_cubic_minmax(&self) -> bool1349 fn filter_cubic_minmax(&self) -> bool { 1350 self.filter_cubic_minmax 1351 } 1352 1353 #[inline] format(&self) -> Option<Format>1354 fn format(&self) -> Option<Format> { 1355 self.format 1356 } 1357 1358 #[inline] format_features(&self) -> FormatFeatures1359 fn format_features(&self) -> FormatFeatures { 1360 self.format_features 1361 } 1362 1363 #[inline] sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>>1364 fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> { 1365 self.sampler_ycbcr_conversion.as_ref() 1366 } 1367 1368 #[inline] subresource_range(&self) -> &ImageSubresourceRange1369 fn subresource_range(&self) -> &ImageSubresourceRange { 1370 &self.subresource_range 1371 } 1372 1373 #[inline] usage(&self) -> ImageUsage1374 fn usage(&self) -> ImageUsage { 1375 self.usage 1376 } 1377 1378 #[inline] view_type(&self) -> ImageViewType1379 fn view_type(&self) -> ImageViewType { 1380 self.view_type 1381 } 1382 } 1383 1384 impl PartialEq for dyn ImageViewAbstract { 1385 #[inline] eq(&self, other: &Self) -> bool1386 fn eq(&self, other: &Self) -> bool { 1387 self.handle() == other.handle() && self.device() == other.device() 1388 } 1389 } 1390 1391 impl Eq for dyn ImageViewAbstract {} 1392 1393 impl Hash for dyn ImageViewAbstract { hash<H: Hasher>(&self, state: &mut H)1394 fn hash<H: Hasher>(&self, state: &mut H) { 1395 self.handle().hash(state); 1396 self.device().hash(state); 1397 } 1398 } 1399