diff options
Diffstat (limited to 'src/image/mod.rs')
-rw-r--r-- | src/image/mod.rs | 701 |
1 files changed, 0 insertions, 701 deletions
diff --git a/src/image/mod.rs b/src/image/mod.rs deleted file mode 100644 index 4e7f4af..0000000 --- a/src/image/mod.rs +++ /dev/null @@ -1,701 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT -// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -//! Image storage (1D, 2D, 3D, arrays, etc.) and image views. -//! -//! An *image* is a region of memory whose purpose is to store multi-dimensional data. Its -//! most common use is to store a 2D array of color pixels (in other words an *image* in -//! everyday language), but it can also be used to store arbitrary data. -//! -//! The advantage of using an image compared to a buffer is that the memory layout is optimized -//! for locality. When reading a specific pixel of an image, reading the nearby pixels is really -//! fast. Most implementations have hardware dedicated to reading from images if you access them -//! through a sampler. -//! -//! # Properties of an image -//! -//! # Images and image views -//! -//! There is a distinction between *images* and *image views*. As its name suggests, an image -//! view describes how the GPU must interpret the image. -//! -//! Transfer and memory operations operate on images themselves, while reading/writing an image -//! operates on image views. You can create multiple image views from the same image. -//! -//! # High-level wrappers -//! -//! In the vulkano library, an image is any object that implements the [`ImageAccess`] trait. You -//! can create a view by wrapping them in an [`ImageView`](crate::image::view::ImageView). -//! -//! Since the `ImageAccess` trait is low-level, you are encouraged to not implement it yourself but -//! instead use one of the provided implementations that are specialized depending on the way you -//! are going to use the image: -//! -//! - An `AttachmentImage` can be used when you want to draw to an image. -//! - An `ImmutableImage` stores data which never need be changed after the initial upload, -//! like a texture. -//! -//! # Low-level information -//! -//! To be written. -//! - -pub use self::aspect::ImageAspect; -pub use self::aspect::ImageAspects; -pub use self::attachment::AttachmentImage; -pub use self::immutable::ImmutableImage; -pub use self::layout::ImageDescriptorLayouts; -pub use self::layout::ImageLayout; -pub use self::storage::StorageImage; -pub use self::swapchain::SwapchainImage; -pub use self::sys::ImageCreationError; -pub use self::traits::ImageAccess; -pub use self::traits::ImageInner; -pub use self::usage::ImageUsage; -pub use self::view::ImageViewAbstract; -use std::cmp; -use std::convert::TryFrom; - -mod aspect; -pub mod attachment; // TODO: make private -pub mod immutable; // TODO: make private -mod layout; -mod storage; -pub mod swapchain; // TODO: make private -pub mod sys; -pub mod traits; -mod usage; -pub mod view; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[repr(u32)] -pub enum SampleCount { - Sample1 = ash::vk::SampleCountFlags::TYPE_1.as_raw(), - Sample2 = ash::vk::SampleCountFlags::TYPE_2.as_raw(), - Sample4 = ash::vk::SampleCountFlags::TYPE_4.as_raw(), - Sample8 = ash::vk::SampleCountFlags::TYPE_8.as_raw(), - Sample16 = ash::vk::SampleCountFlags::TYPE_16.as_raw(), - Sample32 = ash::vk::SampleCountFlags::TYPE_32.as_raw(), - Sample64 = ash::vk::SampleCountFlags::TYPE_64.as_raw(), -} - -impl From<SampleCount> for ash::vk::SampleCountFlags { - #[inline] - fn from(val: SampleCount) -> Self { - Self::from_raw(val as u32) - } -} - -impl TryFrom<ash::vk::SampleCountFlags> for SampleCount { - type Error = (); - - #[inline] - fn try_from(val: ash::vk::SampleCountFlags) -> Result<Self, Self::Error> { - match val { - ash::vk::SampleCountFlags::TYPE_1 => Ok(Self::Sample1), - ash::vk::SampleCountFlags::TYPE_2 => Ok(Self::Sample2), - ash::vk::SampleCountFlags::TYPE_4 => Ok(Self::Sample4), - ash::vk::SampleCountFlags::TYPE_8 => Ok(Self::Sample8), - ash::vk::SampleCountFlags::TYPE_16 => Ok(Self::Sample16), - ash::vk::SampleCountFlags::TYPE_32 => Ok(Self::Sample32), - ash::vk::SampleCountFlags::TYPE_64 => Ok(Self::Sample64), - _ => Err(()), - } - } -} - -impl TryFrom<u32> for SampleCount { - type Error = (); - - #[inline] - fn try_from(val: u32) -> Result<Self, Self::Error> { - match val { - 1 => Ok(Self::Sample1), - 2 => Ok(Self::Sample2), - 4 => Ok(Self::Sample4), - 8 => Ok(Self::Sample8), - 16 => Ok(Self::Sample16), - 32 => Ok(Self::Sample32), - 64 => Ok(Self::Sample64), - _ => Err(()), - } - } -} - -/// Specifies how many sample counts supported for an image used for storage operations. -#[derive(Debug, Copy, Clone, Default)] -pub struct SampleCounts { - // specify an image with one sample per pixel - pub sample1: bool, - // specify an image with 2 samples per pixel - pub sample2: bool, - // specify an image with 4 samples per pixel - pub sample4: bool, - // specify an image with 8 samples per pixel - pub sample8: bool, - // specify an image with 16 samples per pixel - pub sample16: bool, - // specify an image with 32 samples per pixel - pub sample32: bool, - // specify an image with 64 samples per pixel - pub sample64: bool, -} - -impl From<ash::vk::SampleCountFlags> for SampleCounts { - fn from(sample_counts: ash::vk::SampleCountFlags) -> SampleCounts { - SampleCounts { - sample1: !(sample_counts & ash::vk::SampleCountFlags::TYPE_1).is_empty(), - sample2: !(sample_counts & ash::vk::SampleCountFlags::TYPE_2).is_empty(), - sample4: !(sample_counts & ash::vk::SampleCountFlags::TYPE_4).is_empty(), - sample8: !(sample_counts & ash::vk::SampleCountFlags::TYPE_8).is_empty(), - sample16: !(sample_counts & ash::vk::SampleCountFlags::TYPE_16).is_empty(), - sample32: !(sample_counts & ash::vk::SampleCountFlags::TYPE_32).is_empty(), - sample64: !(sample_counts & ash::vk::SampleCountFlags::TYPE_64).is_empty(), - } - } -} - -impl From<SampleCounts> for ash::vk::SampleCountFlags { - fn from(val: SampleCounts) -> ash::vk::SampleCountFlags { - let mut sample_counts = ash::vk::SampleCountFlags::default(); - - if val.sample1 { - sample_counts |= ash::vk::SampleCountFlags::TYPE_1; - } - if val.sample2 { - sample_counts |= ash::vk::SampleCountFlags::TYPE_2; - } - if val.sample4 { - sample_counts |= ash::vk::SampleCountFlags::TYPE_4; - } - if val.sample8 { - sample_counts |= ash::vk::SampleCountFlags::TYPE_8; - } - if val.sample16 { - sample_counts |= ash::vk::SampleCountFlags::TYPE_16; - } - if val.sample32 { - sample_counts |= ash::vk::SampleCountFlags::TYPE_32; - } - if val.sample64 { - sample_counts |= ash::vk::SampleCountFlags::TYPE_64; - } - - sample_counts - } -} - -/// Specifies how many mipmaps must be allocated. -/// -/// Note that at least one mipmap must be allocated, to store the main level of the image. -#[derive(Debug, Copy, Clone)] -pub enum MipmapsCount { - /// Allocates the number of mipmaps required to store all the mipmaps of the image where each - /// mipmap is half the dimensions of the previous level. Guaranteed to be always supported. - /// - /// Note that this is not necessarily the maximum number of mipmaps, as the Vulkan - /// implementation may report that it supports a greater value. - Log2, - - /// Allocate one mipmap (ie. just the main level). Always supported. - One, - - /// Allocate the given number of mipmaps. May result in an error if the value is out of range - /// of what the implementation supports. - Specific(u32), -} - -impl From<u32> for MipmapsCount { - #[inline] - fn from(num: u32) -> MipmapsCount { - MipmapsCount::Specific(num) - } -} - -/// Helper type for creating extents -#[derive(Debug, Copy, Clone)] -pub enum Extent { - E1D([u32; 1]), - E2D([u32; 2]), - E3D([u32; 3]), -} - -impl From<ash::vk::Extent2D> for Extent { - fn from(extent: ash::vk::Extent2D) -> Self { - Extent::E2D([extent.width, extent.height]) - } -} - -impl From<ash::vk::Extent3D> for Extent { - fn from(extent: ash::vk::Extent3D) -> Self { - Extent::E3D([extent.width, extent.height, extent.depth]) - } -} -impl TryFrom<Extent> for ash::vk::Extent2D { - type Error = (); - - fn try_from(extent: Extent) -> Result<Self, Self::Error> { - match extent { - Extent::E2D(a) => Ok(ash::vk::Extent2D { - width: a[0], - height: a[1], - }), - _ => Err(()), - } - } -} - -impl TryFrom<Extent> for ash::vk::Extent3D { - type Error = (); - - fn try_from(extent: Extent) -> Result<Self, Self::Error> { - match extent { - Extent::E3D(a) => Ok(ash::vk::Extent3D { - width: a[0], - height: a[1], - depth: a[2], - }), - _ => Err(()), - } - } -} - -/// Helper type returned from Device's `fn image_format_properties()` -pub struct ImageFormatProperties { - pub max_extent: Extent, - pub max_mip_levels: MipmapsCount, - pub max_array_layers: u32, - pub sample_counts: SampleCounts, - pub max_resource_size: usize, -} - -impl From<ash::vk::ImageFormatProperties> for ImageFormatProperties { - fn from(props: ash::vk::ImageFormatProperties) -> Self { - Self { - max_extent: props.max_extent.into(), - max_mip_levels: props.max_mip_levels.into(), - max_array_layers: props.max_array_layers, - sample_counts: props.sample_counts.into(), - max_resource_size: props.max_resource_size as usize, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] -pub struct ImageCreateFlags { - pub sparse_binding: bool, - pub sparse_residency: bool, - pub sparse_aliased: bool, - pub mutable_format: bool, - pub cube_compatible: bool, - pub array_2d_compatible: bool, -} - -impl ImageCreateFlags { - pub fn all() -> Self { - Self { - sparse_binding: true, - sparse_residency: true, - sparse_aliased: true, - mutable_format: true, - cube_compatible: true, - array_2d_compatible: true, - } - } - - pub fn none() -> Self { - Self::default() - } -} - -impl From<ImageCreateFlags> for ash::vk::ImageCreateFlags { - fn from(flags: ImageCreateFlags) -> Self { - let mut vk_flags = Self::default(); - if flags.sparse_binding { - vk_flags |= ash::vk::ImageCreateFlags::SPARSE_BINDING - }; - if flags.sparse_residency { - vk_flags |= ash::vk::ImageCreateFlags::SPARSE_RESIDENCY - }; - if flags.sparse_aliased { - vk_flags |= ash::vk::ImageCreateFlags::SPARSE_ALIASED - }; - if flags.mutable_format { - vk_flags |= ash::vk::ImageCreateFlags::MUTABLE_FORMAT - }; - if flags.cube_compatible { - vk_flags |= ash::vk::ImageCreateFlags::CUBE_COMPATIBLE - }; - if flags.array_2d_compatible { - vk_flags |= ash::vk::ImageCreateFlags::TYPE_2D_ARRAY_COMPATIBLE_KHR - }; - vk_flags - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(i32)] -pub enum ImageType { - Dim1d = ash::vk::ImageType::TYPE_1D.as_raw(), - Dim2d = ash::vk::ImageType::TYPE_2D.as_raw(), - Dim3d = ash::vk::ImageType::TYPE_3D.as_raw(), -} -impl From<ImageType> for ash::vk::ImageType { - fn from(val: ImageType) -> Self { - ash::vk::ImageType::from_raw(val as i32) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(i32)] -pub enum ImageTiling { - Optimal = ash::vk::ImageTiling::OPTIMAL.as_raw(), - Linear = ash::vk::ImageTiling::LINEAR.as_raw(), -} - -impl From<ImageTiling> for ash::vk::ImageTiling { - fn from(val: ImageTiling) -> Self { - ash::vk::ImageTiling::from_raw(val as i32) - } -} - -/// The dimensions of an image. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ImageDimensions { - Dim1d { - width: u32, - array_layers: u32, - }, - Dim2d { - width: u32, - height: u32, - array_layers: u32, - }, - Dim3d { - width: u32, - height: u32, - depth: u32, - }, -} - -impl ImageDimensions { - #[inline] - pub fn width(&self) -> u32 { - match *self { - ImageDimensions::Dim1d { width, .. } => width, - ImageDimensions::Dim2d { width, .. } => width, - ImageDimensions::Dim3d { width, .. } => width, - } - } - - #[inline] - pub fn height(&self) -> u32 { - match *self { - ImageDimensions::Dim1d { .. } => 1, - ImageDimensions::Dim2d { height, .. } => height, - ImageDimensions::Dim3d { height, .. } => height, - } - } - - #[inline] - pub fn width_height(&self) -> [u32; 2] { - [self.width(), self.height()] - } - - #[inline] - pub fn depth(&self) -> u32 { - match *self { - ImageDimensions::Dim1d { .. } => 1, - ImageDimensions::Dim2d { .. } => 1, - ImageDimensions::Dim3d { depth, .. } => depth, - } - } - - #[inline] - pub fn width_height_depth(&self) -> [u32; 3] { - [self.width(), self.height(), self.depth()] - } - - #[inline] - pub fn array_layers(&self) -> u32 { - match *self { - ImageDimensions::Dim1d { array_layers, .. } => array_layers, - ImageDimensions::Dim2d { array_layers, .. } => array_layers, - ImageDimensions::Dim3d { .. } => 1, - } - } - - /// Returns the total number of texels for an image of these dimensions. - #[inline] - pub fn num_texels(&self) -> u32 { - self.width() * self.height() * self.depth() * self.array_layers() - } - - /// Returns the maximum number of mipmaps for these image dimensions. - /// - /// The returned value is always at least superior or equal to 1. - /// - /// # Example - /// - /// ``` - /// use vulkano::image::ImageDimensions; - /// - /// let dims = ImageDimensions::Dim2d { - /// width: 32, - /// height: 50, - /// array_layers: 1, - /// }; - /// - /// assert_eq!(dims.max_mipmaps(), 6); - /// ``` - /// - pub fn max_mipmaps(&self) -> u32 { - 32 - (self.width() | self.height() | self.depth()).leading_zeros() - } - - /// Returns the dimensions of the `level`th mipmap level. If `level` is 0, then the dimensions - /// are left unchanged. - /// - /// Returns `None` if `level` is superior or equal to `max_mipmaps()`. - /// - /// # Example - /// - /// ``` - /// use vulkano::image::ImageDimensions; - /// - /// let dims = ImageDimensions::Dim2d { - /// width: 963, - /// height: 256, - /// array_layers: 1, - /// }; - /// - /// assert_eq!(dims.mipmap_dimensions(0), Some(dims)); - /// assert_eq!(dims.mipmap_dimensions(1), Some(ImageDimensions::Dim2d { - /// width: 481, - /// height: 128, - /// array_layers: 1, - /// })); - /// assert_eq!(dims.mipmap_dimensions(6), Some(ImageDimensions::Dim2d { - /// width: 15, - /// height: 4, - /// array_layers: 1, - /// })); - /// assert_eq!(dims.mipmap_dimensions(9), Some(ImageDimensions::Dim2d { - /// width: 1, - /// height: 1, - /// array_layers: 1, - /// })); - /// assert_eq!(dims.mipmap_dimensions(11), None); - /// ``` - /// - /// # Panic - /// - /// In debug mode, Panics if `width`, `height` or `depth` is equal to 0. In release, returns - /// an unspecified value. - /// - pub fn mipmap_dimensions(&self, level: u32) -> Option<ImageDimensions> { - if level == 0 { - return Some(*self); - } - - if level >= self.max_mipmaps() { - return None; - } - - Some(match *self { - ImageDimensions::Dim1d { - width, - array_layers, - } => { - debug_assert_ne!(width, 0); - ImageDimensions::Dim1d { - array_layers, - width: cmp::max(1, width >> level), - } - } - - ImageDimensions::Dim2d { - width, - height, - array_layers, - } => { - debug_assert_ne!(width, 0); - debug_assert_ne!(height, 0); - ImageDimensions::Dim2d { - width: cmp::max(1, width >> level), - height: cmp::max(1, height >> level), - array_layers, - } - } - - ImageDimensions::Dim3d { - width, - height, - depth, - } => { - debug_assert_ne!(width, 0); - debug_assert_ne!(height, 0); - ImageDimensions::Dim3d { - width: cmp::max(1, width >> level), - height: cmp::max(1, height >> level), - depth: cmp::max(1, depth >> level), - } - } - }) - } -} - -#[cfg(test)] -mod tests { - use crate::format::Format; - use crate::image::ImageDimensions; - use crate::image::ImmutableImage; - use crate::image::MipmapsCount; - - #[test] - fn max_mipmaps() { - let dims = ImageDimensions::Dim2d { - width: 2, - height: 1, - array_layers: 1, - }; - assert_eq!(dims.max_mipmaps(), 2); - - let dims = ImageDimensions::Dim2d { - width: 2, - height: 3, - array_layers: 1, - }; - assert_eq!(dims.max_mipmaps(), 2); - - let dims = ImageDimensions::Dim2d { - width: 512, - height: 512, - array_layers: 1, - }; - assert_eq!(dims.max_mipmaps(), 10); - } - - #[test] - fn mipmap_dimensions() { - let dims = ImageDimensions::Dim2d { - width: 283, - height: 175, - array_layers: 1, - }; - assert_eq!(dims.mipmap_dimensions(0), Some(dims)); - assert_eq!( - dims.mipmap_dimensions(1), - Some(ImageDimensions::Dim2d { - width: 141, - height: 87, - array_layers: 1, - }) - ); - assert_eq!( - dims.mipmap_dimensions(2), - Some(ImageDimensions::Dim2d { - width: 70, - height: 43, - array_layers: 1, - }) - ); - assert_eq!( - dims.mipmap_dimensions(3), - Some(ImageDimensions::Dim2d { - width: 35, - height: 21, - array_layers: 1, - }) - ); - - assert_eq!( - dims.mipmap_dimensions(4), - Some(ImageDimensions::Dim2d { - width: 17, - height: 10, - array_layers: 1, - }) - ); - assert_eq!( - dims.mipmap_dimensions(5), - Some(ImageDimensions::Dim2d { - width: 8, - height: 5, - array_layers: 1, - }) - ); - assert_eq!( - dims.mipmap_dimensions(6), - Some(ImageDimensions::Dim2d { - width: 4, - height: 2, - array_layers: 1, - }) - ); - assert_eq!( - dims.mipmap_dimensions(7), - Some(ImageDimensions::Dim2d { - width: 2, - height: 1, - array_layers: 1, - }) - ); - assert_eq!( - dims.mipmap_dimensions(8), - Some(ImageDimensions::Dim2d { - width: 1, - height: 1, - array_layers: 1, - }) - ); - assert_eq!(dims.mipmap_dimensions(9), None); - } - - #[test] - fn mipmap_working_immutable_image() { - let (device, queue) = gfx_dev_and_queue!(); - - let dimensions = ImageDimensions::Dim2d { - width: 512, - height: 512, - array_layers: 1, - }; - { - let mut vec = Vec::new(); - - vec.resize(512 * 512, 0u8); - - let (image, _) = ImmutableImage::from_iter( - vec.into_iter(), - dimensions, - MipmapsCount::One, - Format::R8Unorm, - queue.clone(), - ) - .unwrap(); - assert_eq!(image.mipmap_levels(), 1); - } - { - let mut vec = Vec::new(); - - vec.resize(512 * 512, 0u8); - - let (image, _) = ImmutableImage::from_iter( - vec.into_iter(), - dimensions, - MipmapsCount::Log2, - Format::R8Unorm, - queue.clone(), - ) - .unwrap(); - assert_eq!(image.mipmap_levels(), 10); - } - } -} |