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 crate::check_errors; 17 use crate::device::Device; 18 use crate::format::Format; 19 use crate::format::FormatTy; 20 use crate::image::sys::UnsafeImage; 21 use crate::image::ImageAccess; 22 use crate::image::ImageDimensions; 23 use crate::memory::DeviceMemoryAllocError; 24 use crate::sampler::Sampler; 25 use crate::OomError; 26 use crate::SafeDeref; 27 use crate::VulkanObject; 28 use std::error; 29 use std::fmt; 30 use std::hash::Hash; 31 use std::hash::Hasher; 32 use std::mem::MaybeUninit; 33 use std::ops::Range; 34 use std::ptr; 35 use std::sync::Arc; 36 37 /// A safe image view that checks for validity and keeps its attached image alive. 38 pub struct ImageView<I> 39 where 40 I: ImageAccess, 41 { 42 image: I, 43 inner: UnsafeImageView, 44 format: Format, 45 46 ty: ImageViewType, 47 component_mapping: ComponentMapping, 48 array_layers: Range<u32>, 49 } 50 51 impl<I> ImageView<I> 52 where 53 I: ImageAccess, 54 { 55 /// Creates a default `ImageView`. Equivalent to `ImageView::start(image).build()`. 56 #[inline] new(image: I) -> Result<Arc<ImageView<I>>, ImageViewCreationError>57 pub fn new(image: I) -> Result<Arc<ImageView<I>>, ImageViewCreationError> { 58 Self::start(image).build() 59 } 60 61 /// Begins building an `ImageView`. start(image: I) -> ImageViewBuilder<I>62 pub fn start(image: I) -> ImageViewBuilder<I> { 63 let ty = match image.dimensions() { 64 ImageDimensions::Dim1d { 65 array_layers: 1, .. 66 } => ImageViewType::Dim1d, 67 ImageDimensions::Dim1d { .. } => ImageViewType::Dim1dArray, 68 ImageDimensions::Dim2d { 69 array_layers: 1, .. 70 } => ImageViewType::Dim2d, 71 ImageDimensions::Dim2d { .. } => ImageViewType::Dim2dArray, 72 ImageDimensions::Dim3d { .. } => ImageViewType::Dim3d, 73 }; 74 let mipmap_levels = 0..image.mipmap_levels(); 75 let array_layers = 0..image.dimensions().array_layers(); 76 77 ImageViewBuilder { 78 image, 79 ty, 80 component_mapping: ComponentMapping::default(), 81 mipmap_levels, 82 array_layers, 83 } 84 } 85 86 /// Returns the wrapped image that this image view was created from. image(&self) -> &I87 pub fn image(&self) -> &I { 88 &self.image 89 } 90 } 91 92 #[derive(Debug)] 93 pub struct ImageViewBuilder<I> { 94 image: I, 95 ty: ImageViewType, 96 component_mapping: ComponentMapping, 97 mipmap_levels: Range<u32>, 98 array_layers: Range<u32>, 99 } 100 101 impl<I> ImageViewBuilder<I> 102 where 103 I: ImageAccess, 104 { 105 /// Sets the image view type. 106 /// 107 /// By default, this is determined from the image, based on its dimensions and number of layers. 108 /// The value of `ty` must be compatible with the dimensions of the image and the selected 109 /// array layers. 110 #[inline] with_type(mut self, ty: ImageViewType) -> Self111 pub fn with_type(mut self, ty: ImageViewType) -> Self { 112 self.ty = ty; 113 self 114 } 115 116 /// Sets how to map components of each pixel. 117 /// 118 /// By default, this is the identity mapping, with every component mapped directly. 119 #[inline] with_component_mapping(mut self, component_mapping: ComponentMapping) -> Self120 pub fn with_component_mapping(mut self, component_mapping: ComponentMapping) -> Self { 121 self.component_mapping = component_mapping; 122 self 123 } 124 125 /// Sets the range of mipmap levels that the view should cover. 126 /// 127 /// By default, this is the full range of mipmaps present in the image. 128 #[inline] with_mipmap_levels(mut self, mipmap_levels: Range<u32>) -> Self129 pub fn with_mipmap_levels(mut self, mipmap_levels: Range<u32>) -> Self { 130 self.mipmap_levels = mipmap_levels; 131 self 132 } 133 134 /// Sets the range of array layers that the view should cover. 135 /// 136 /// By default, this is the full range of array layers present in the image. 137 #[inline] with_array_layers(mut self, array_layers: Range<u32>) -> Self138 pub fn with_array_layers(mut self, array_layers: Range<u32>) -> Self { 139 self.array_layers = array_layers; 140 self 141 } 142 143 /// Builds the `ImageView`. build(self) -> Result<Arc<ImageView<I>>, ImageViewCreationError>144 pub fn build(self) -> Result<Arc<ImageView<I>>, ImageViewCreationError> { 145 let dimensions = self.image.dimensions(); 146 let format = self.image.format(); 147 let image_inner = self.image.inner().image; 148 let usage = image_inner.usage(); 149 let flags = image_inner.flags(); 150 151 if self.mipmap_levels.end <= self.mipmap_levels.start 152 || self.mipmap_levels.end > image_inner.mipmap_levels() 153 { 154 return Err(ImageViewCreationError::MipMapLevelsOutOfRange); 155 } 156 157 if self.array_layers.end <= self.array_layers.start 158 || self.array_layers.end > dimensions.array_layers() 159 { 160 return Err(ImageViewCreationError::ArrayLayersOutOfRange); 161 } 162 163 if !(usage.sampled 164 || usage.storage 165 || usage.color_attachment 166 || usage.depth_stencil_attachment 167 || usage.input_attachment 168 || usage.transient_attachment) 169 { 170 return Err(ImageViewCreationError::InvalidImageUsage); 171 } 172 173 // Check for compatibility with the image 174 match ( 175 self.ty, 176 self.image.dimensions(), 177 self.array_layers.end - self.array_layers.start, 178 self.mipmap_levels.end - self.mipmap_levels.start, 179 ) { 180 (ImageViewType::Dim1d, ImageDimensions::Dim1d { .. }, 1, _) => (), 181 (ImageViewType::Dim1dArray, ImageDimensions::Dim1d { .. }, _, _) => (), 182 (ImageViewType::Dim2d, ImageDimensions::Dim2d { .. }, 1, _) => (), 183 (ImageViewType::Dim2dArray, ImageDimensions::Dim2d { .. }, _, _) => (), 184 (ImageViewType::Cubemap, ImageDimensions::Dim2d { .. }, 6, _) 185 if flags.cube_compatible => 186 { 187 () 188 } 189 (ImageViewType::CubemapArray, ImageDimensions::Dim2d { .. }, n, _) 190 if flags.cube_compatible && n % 6 == 0 => 191 { 192 () 193 } 194 (ImageViewType::Dim3d, ImageDimensions::Dim3d { .. }, 1, _) => (), 195 (ImageViewType::Dim2d, ImageDimensions::Dim3d { .. }, 1, 1) 196 if flags.array_2d_compatible => 197 { 198 () 199 } 200 (ImageViewType::Dim2dArray, ImageDimensions::Dim3d { .. }, _, 1) 201 if flags.array_2d_compatible => 202 { 203 () 204 } 205 _ => return Err(ImageViewCreationError::IncompatibleType), 206 } 207 208 let inner = unsafe { 209 UnsafeImageView::new( 210 image_inner, 211 self.ty, 212 self.component_mapping, 213 self.mipmap_levels, 214 self.array_layers.clone(), 215 )? 216 }; 217 218 Ok(Arc::new(ImageView { 219 image: self.image, 220 inner, 221 format, 222 223 ty: self.ty, 224 component_mapping: self.component_mapping, 225 array_layers: self.array_layers, 226 })) 227 } 228 } 229 230 /// Error that can happen when creating an image view. 231 #[derive(Clone, Debug, PartialEq, Eq)] 232 pub enum ImageViewCreationError { 233 /// Allocating memory failed. 234 AllocError(DeviceMemoryAllocError), 235 /// The specified range of array layers was out of range for the image. 236 ArrayLayersOutOfRange, 237 /// The specified range of mipmap levels was out of range for the image. 238 MipMapLevelsOutOfRange, 239 /// The requested [`ImageViewType`] was not compatible with the image, or with the specified ranges of array layers and mipmap levels. 240 IncompatibleType, 241 /// The image was not created with 242 /// [one of the required usages](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#valid-imageview-imageusage) 243 /// for image views. 244 InvalidImageUsage, 245 } 246 247 impl error::Error for ImageViewCreationError { 248 #[inline] source(&self) -> Option<&(dyn error::Error + 'static)>249 fn source(&self) -> Option<&(dyn error::Error + 'static)> { 250 match *self { 251 ImageViewCreationError::AllocError(ref err) => Some(err), 252 _ => None, 253 } 254 } 255 } 256 257 impl fmt::Display for ImageViewCreationError { 258 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>259 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 260 write!( 261 fmt, 262 "{}", 263 match *self { 264 ImageViewCreationError::AllocError(err) => "allocating memory failed", 265 ImageViewCreationError::ArrayLayersOutOfRange => "array layers are out of range", 266 ImageViewCreationError::MipMapLevelsOutOfRange => "mipmap levels are out of range", 267 ImageViewCreationError::IncompatibleType => 268 "image view type is not compatible with image, array layers or mipmap levels", 269 ImageViewCreationError::InvalidImageUsage => 270 "the usage of the image is not compatible with image views", 271 } 272 ) 273 } 274 } 275 276 impl From<OomError> for ImageViewCreationError { 277 #[inline] from(err: OomError) -> ImageViewCreationError278 fn from(err: OomError) -> ImageViewCreationError { 279 ImageViewCreationError::AllocError(DeviceMemoryAllocError::OomError(err)) 280 } 281 } 282 283 /// A low-level wrapper around a `vkImageView`. 284 pub struct UnsafeImageView { 285 view: ash::vk::ImageView, 286 device: Arc<Device>, 287 } 288 289 impl UnsafeImageView { 290 /// Creates a new view from an image. 291 /// 292 /// # Safety 293 /// - The returned `UnsafeImageView` must not outlive `image`. 294 /// - `image` must have a usage that is compatible with image views. 295 /// - `ty` must be compatible with the dimensions and flags of the image. 296 /// - `mipmap_levels` must not be empty, must be within the range of levels of the image, and be compatible with the requested `ty`. 297 /// - `array_layers` must not be empty, must be within the range of layers of the image, and be compatible with the requested `ty`. 298 /// 299 /// # Panics 300 /// Panics if the image is a YcbCr image, since the Vulkano API is not yet flexible enough to 301 /// specify the aspect of image. new( image: &UnsafeImage, ty: ImageViewType, component_mapping: ComponentMapping, mipmap_levels: Range<u32>, array_layers: Range<u32>, ) -> Result<UnsafeImageView, OomError>302 pub unsafe fn new( 303 image: &UnsafeImage, 304 ty: ImageViewType, 305 component_mapping: ComponentMapping, 306 mipmap_levels: Range<u32>, 307 array_layers: Range<u32>, 308 ) -> Result<UnsafeImageView, OomError> { 309 let fns = image.device().fns(); 310 311 debug_assert!(mipmap_levels.end > mipmap_levels.start); 312 debug_assert!(mipmap_levels.end <= image.mipmap_levels()); 313 debug_assert!(array_layers.end > array_layers.start); 314 debug_assert!(array_layers.end <= image.dimensions().array_layers()); 315 316 if image.format().ty() == FormatTy::Ycbcr { 317 unimplemented!(); 318 } 319 320 // TODO: Let user choose 321 let aspects = image.format().aspects(); 322 323 let view = { 324 let infos = ash::vk::ImageViewCreateInfo { 325 flags: ash::vk::ImageViewCreateFlags::empty(), 326 image: image.internal_object(), 327 view_type: ty.into(), 328 format: image.format().into(), 329 components: component_mapping.into(), 330 subresource_range: ash::vk::ImageSubresourceRange { 331 aspect_mask: aspects.into(), 332 base_mip_level: mipmap_levels.start, 333 level_count: mipmap_levels.end - mipmap_levels.start, 334 base_array_layer: array_layers.start, 335 layer_count: array_layers.end - array_layers.start, 336 }, 337 ..Default::default() 338 }; 339 340 let mut output = MaybeUninit::uninit(); 341 check_errors(fns.v1_0.create_image_view( 342 image.device().internal_object(), 343 &infos, 344 ptr::null(), 345 output.as_mut_ptr(), 346 ))?; 347 output.assume_init() 348 }; 349 350 Ok(UnsafeImageView { 351 view, 352 device: image.device().clone(), 353 }) 354 } 355 } 356 357 unsafe impl VulkanObject for UnsafeImageView { 358 type Object = ash::vk::ImageView; 359 360 #[inline] internal_object(&self) -> ash::vk::ImageView361 fn internal_object(&self) -> ash::vk::ImageView { 362 self.view 363 } 364 } 365 366 impl fmt::Debug for UnsafeImageView { 367 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>368 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 369 write!(fmt, "<Vulkan image view {:?}>", self.view) 370 } 371 } 372 373 impl Drop for UnsafeImageView { 374 #[inline] drop(&mut self)375 fn drop(&mut self) { 376 unsafe { 377 let fns = self.device.fns(); 378 fns.v1_0 379 .destroy_image_view(self.device.internal_object(), self.view, ptr::null()); 380 } 381 } 382 } 383 384 impl PartialEq for UnsafeImageView { 385 #[inline] eq(&self, other: &Self) -> bool386 fn eq(&self, other: &Self) -> bool { 387 self.view == other.view && self.device == other.device 388 } 389 } 390 391 impl Eq for UnsafeImageView {} 392 393 impl Hash for UnsafeImageView { 394 #[inline] hash<H: Hasher>(&self, state: &mut H)395 fn hash<H: Hasher>(&self, state: &mut H) { 396 self.view.hash(state); 397 self.device.hash(state); 398 } 399 } 400 401 /// The geometry type of an image view. 402 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 403 #[repr(i32)] 404 pub enum ImageViewType { 405 Dim1d = ash::vk::ImageViewType::TYPE_1D.as_raw(), 406 Dim1dArray = ash::vk::ImageViewType::TYPE_1D_ARRAY.as_raw(), 407 Dim2d = ash::vk::ImageViewType::TYPE_2D.as_raw(), 408 Dim2dArray = ash::vk::ImageViewType::TYPE_2D_ARRAY.as_raw(), 409 Dim3d = ash::vk::ImageViewType::TYPE_3D.as_raw(), 410 Cubemap = ash::vk::ImageViewType::CUBE.as_raw(), 411 CubemapArray = ash::vk::ImageViewType::CUBE_ARRAY.as_raw(), 412 } 413 414 impl From<ImageViewType> for ash::vk::ImageViewType { from(val: ImageViewType) -> Self415 fn from(val: ImageViewType) -> Self { 416 Self::from_raw(val as i32) 417 } 418 } 419 420 /// Specifies how the components of an image must be mapped. 421 /// 422 /// When creating an image view, it is possible to ask the implementation to modify the value 423 /// returned when accessing a given component from within a shader. 424 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] 425 pub struct ComponentMapping { 426 /// First component. 427 pub r: ComponentSwizzle, 428 /// Second component. 429 pub g: ComponentSwizzle, 430 /// Third component. 431 pub b: ComponentSwizzle, 432 /// Fourth component. 433 pub a: ComponentSwizzle, 434 } 435 436 impl ComponentMapping { 437 /// Returns `true` if the component mapping is identity swizzled, 438 /// meaning that all the members are `Identity`. 439 /// 440 /// Certain operations require views that are identity swizzled, and will return an error 441 /// otherwise. For example, attaching a view to a framebuffer is only possible if the view is 442 /// identity swizzled. 443 #[inline] is_identity(&self) -> bool444 pub fn is_identity(&self) -> bool { 445 self.r == ComponentSwizzle::Identity 446 && self.g == ComponentSwizzle::Identity 447 && self.b == ComponentSwizzle::Identity 448 && self.a == ComponentSwizzle::Identity 449 } 450 } 451 452 impl From<ComponentMapping> for ash::vk::ComponentMapping { 453 #[inline] from(value: ComponentMapping) -> Self454 fn from(value: ComponentMapping) -> Self { 455 Self { 456 r: value.r.into(), 457 g: value.g.into(), 458 b: value.b.into(), 459 a: value.a.into(), 460 } 461 } 462 } 463 464 /// Describes the value that an individual component must return when being accessed. 465 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 466 #[repr(i32)] 467 pub enum ComponentSwizzle { 468 /// Returns the value that this component should normally have. 469 /// 470 /// This is the `Default` value. 471 Identity = ash::vk::ComponentSwizzle::IDENTITY.as_raw(), 472 /// Always return zero. 473 Zero = ash::vk::ComponentSwizzle::ZERO.as_raw(), 474 /// Always return one. 475 One = ash::vk::ComponentSwizzle::ONE.as_raw(), 476 /// Returns the value of the first component. 477 Red = ash::vk::ComponentSwizzle::R.as_raw(), 478 /// Returns the value of the second component. 479 Green = ash::vk::ComponentSwizzle::G.as_raw(), 480 /// Returns the value of the third component. 481 Blue = ash::vk::ComponentSwizzle::B.as_raw(), 482 /// Returns the value of the fourth component. 483 Alpha = ash::vk::ComponentSwizzle::A.as_raw(), 484 } 485 486 impl From<ComponentSwizzle> for ash::vk::ComponentSwizzle { 487 #[inline] from(val: ComponentSwizzle) -> Self488 fn from(val: ComponentSwizzle) -> Self { 489 Self::from_raw(val as i32) 490 } 491 } 492 493 impl Default for ComponentSwizzle { 494 #[inline] default() -> ComponentSwizzle495 fn default() -> ComponentSwizzle { 496 ComponentSwizzle::Identity 497 } 498 } 499 500 /// Trait for types that represent the GPU can access an image view. 501 pub unsafe trait ImageViewAbstract { 502 /// Returns the wrapped image that this image view was created from. image(&self) -> &dyn ImageAccess503 fn image(&self) -> &dyn ImageAccess; 504 505 /// Returns the inner unsafe image view object used by this image view. inner(&self) -> &UnsafeImageView506 fn inner(&self) -> &UnsafeImageView; 507 508 /// Returns the range of array layers of the wrapped image that this view exposes. array_layers(&self) -> Range<u32>509 fn array_layers(&self) -> Range<u32>; 510 511 /// Returns the format of this view. This can be different from the parent's format. format(&self) -> Format512 fn format(&self) -> Format; 513 514 /// Returns the component mapping of this view. component_mapping(&self) -> ComponentMapping515 fn component_mapping(&self) -> ComponentMapping; 516 517 /// Returns the [`ImageViewType`] of this image view. ty(&self) -> ImageViewType518 fn ty(&self) -> ImageViewType; 519 520 /// Returns true if the given sampler can be used with this image view. 521 /// 522 /// This method should check whether the sampler's configuration can be used with the format 523 /// of the view. 524 // TODO: return a Result and propagate it when binding to a descriptor set can_be_sampled(&self, _sampler: &Sampler) -> bool525 fn can_be_sampled(&self, _sampler: &Sampler) -> bool { 526 true /* FIXME */ 527 } 528 } 529 530 unsafe impl<I> ImageViewAbstract for ImageView<I> 531 where 532 I: ImageAccess, 533 { 534 #[inline] image(&self) -> &dyn ImageAccess535 fn image(&self) -> &dyn ImageAccess { 536 &self.image 537 } 538 539 #[inline] inner(&self) -> &UnsafeImageView540 fn inner(&self) -> &UnsafeImageView { 541 &self.inner 542 } 543 544 #[inline] array_layers(&self) -> Range<u32>545 fn array_layers(&self) -> Range<u32> { 546 self.array_layers.clone() 547 } 548 549 #[inline] format(&self) -> Format550 fn format(&self) -> Format { 551 // TODO: remove this default impl 552 self.format 553 } 554 555 #[inline] component_mapping(&self) -> ComponentMapping556 fn component_mapping(&self) -> ComponentMapping { 557 self.component_mapping 558 } 559 560 #[inline] ty(&self) -> ImageViewType561 fn ty(&self) -> ImageViewType { 562 self.ty 563 } 564 } 565 566 unsafe impl<T> ImageViewAbstract for T 567 where 568 T: SafeDeref, 569 T::Target: ImageViewAbstract, 570 { 571 #[inline] image(&self) -> &dyn ImageAccess572 fn image(&self) -> &dyn ImageAccess { 573 (**self).image() 574 } 575 576 #[inline] inner(&self) -> &UnsafeImageView577 fn inner(&self) -> &UnsafeImageView { 578 (**self).inner() 579 } 580 581 #[inline] array_layers(&self) -> Range<u32>582 fn array_layers(&self) -> Range<u32> { 583 (**self).array_layers() 584 } 585 586 #[inline] format(&self) -> Format587 fn format(&self) -> Format { 588 (**self).format() 589 } 590 591 #[inline] component_mapping(&self) -> ComponentMapping592 fn component_mapping(&self) -> ComponentMapping { 593 (**self).component_mapping() 594 } 595 596 #[inline] ty(&self) -> ImageViewType597 fn ty(&self) -> ImageViewType { 598 (**self).ty() 599 } 600 601 #[inline] can_be_sampled(&self, sampler: &Sampler) -> bool602 fn can_be_sampled(&self, sampler: &Sampler) -> bool { 603 (**self).can_be_sampled(sampler) 604 } 605 } 606 607 impl PartialEq for dyn ImageViewAbstract + Send + Sync { 608 #[inline] eq(&self, other: &Self) -> bool609 fn eq(&self, other: &Self) -> bool { 610 self.inner() == other.inner() 611 } 612 } 613 614 impl Eq for dyn ImageViewAbstract + Send + Sync {} 615 616 impl Hash for dyn ImageViewAbstract + Send + Sync { 617 #[inline] hash<H: Hasher>(&self, state: &mut H)618 fn hash<H: Hasher>(&self, state: &mut H) { 619 self.inner().hash(state); 620 } 621 } 622