| // Copyright (c) 2017 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. |
| |
| use crate::device::Device; |
| use crate::format::FormatTy; |
| use crate::image::ImageAccess; |
| use crate::image::ImageDimensions; |
| use crate::image::SampleCount; |
| use crate::sampler::Filter; |
| use crate::VulkanObject; |
| use std::error; |
| use std::fmt; |
| |
| /// Checks whether a blit image command is valid. |
| /// |
| /// Note that this doesn't check whether `layer_count` is equal to 0. TODO: change that? |
| /// |
| /// # Panic |
| /// |
| /// - Panics if the source or the destination was not created with `device`. |
| /// |
| pub fn check_blit_image<S, D>( |
| device: &Device, |
| source: &S, |
| source_top_left: [i32; 3], |
| source_bottom_right: [i32; 3], |
| source_base_array_layer: u32, |
| source_mip_level: u32, |
| destination: &D, |
| destination_top_left: [i32; 3], |
| destination_bottom_right: [i32; 3], |
| destination_base_array_layer: u32, |
| destination_mip_level: u32, |
| layer_count: u32, |
| filter: Filter, |
| ) -> Result<(), CheckBlitImageError> |
| where |
| S: ?Sized + ImageAccess, |
| D: ?Sized + ImageAccess, |
| { |
| let source_inner = source.inner(); |
| let destination_inner = destination.inner(); |
| |
| assert_eq!( |
| source_inner.image.device().internal_object(), |
| device.internal_object() |
| ); |
| assert_eq!( |
| destination_inner.image.device().internal_object(), |
| device.internal_object() |
| ); |
| |
| if !source_inner.image.usage().transfer_source { |
| return Err(CheckBlitImageError::MissingTransferSourceUsage); |
| } |
| |
| if !destination_inner.image.usage().transfer_destination { |
| return Err(CheckBlitImageError::MissingTransferDestinationUsage); |
| } |
| |
| if !source_inner.image.format_features().blit_src { |
| return Err(CheckBlitImageError::SourceFormatNotSupported); |
| } |
| |
| if !destination_inner.image.format_features().blit_dst { |
| return Err(CheckBlitImageError::DestinationFormatNotSupported); |
| } |
| |
| if source.samples() != SampleCount::Sample1 || destination.samples() != SampleCount::Sample1 { |
| return Err(CheckBlitImageError::UnexpectedMultisampled); |
| } |
| |
| let source_format_ty = source.format().ty(); |
| let destination_format_ty = destination.format().ty(); |
| |
| if matches!( |
| source_format_ty, |
| FormatTy::Depth | FormatTy::Stencil | FormatTy::DepthStencil |
| ) { |
| if source.format() != destination.format() { |
| return Err(CheckBlitImageError::DepthStencilFormatMismatch); |
| } |
| |
| if filter != Filter::Nearest { |
| return Err(CheckBlitImageError::DepthStencilNearestMandatory); |
| } |
| } |
| |
| let types_should_be_same = source_format_ty == FormatTy::Uint |
| || destination_format_ty == FormatTy::Uint |
| || source_format_ty == FormatTy::Sint |
| || destination_format_ty == FormatTy::Sint; |
| if types_should_be_same && (source_format_ty != destination_format_ty) { |
| return Err(CheckBlitImageError::IncompatibleFormatsTypes { |
| source_format_ty: source.format().ty(), |
| destination_format_ty: destination.format().ty(), |
| }); |
| } |
| |
| let source_dimensions = match source.dimensions().mipmap_dimensions(source_mip_level) { |
| Some(d) => d, |
| None => return Err(CheckBlitImageError::SourceCoordinatesOutOfRange), |
| }; |
| |
| let destination_dimensions = match destination |
| .dimensions() |
| .mipmap_dimensions(destination_mip_level) |
| { |
| Some(d) => d, |
| None => return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange), |
| }; |
| |
| if source_base_array_layer + layer_count > source_dimensions.array_layers() { |
| return Err(CheckBlitImageError::SourceCoordinatesOutOfRange); |
| } |
| |
| if destination_base_array_layer + layer_count > destination_dimensions.array_layers() { |
| return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange); |
| } |
| |
| if source_top_left[0] < 0 || source_top_left[0] > source_dimensions.width() as i32 { |
| return Err(CheckBlitImageError::SourceCoordinatesOutOfRange); |
| } |
| |
| if source_top_left[1] < 0 || source_top_left[1] > source_dimensions.height() as i32 { |
| return Err(CheckBlitImageError::SourceCoordinatesOutOfRange); |
| } |
| |
| if source_top_left[2] < 0 || source_top_left[2] > source_dimensions.depth() as i32 { |
| return Err(CheckBlitImageError::SourceCoordinatesOutOfRange); |
| } |
| |
| if source_bottom_right[0] < 0 || source_bottom_right[0] > source_dimensions.width() as i32 { |
| return Err(CheckBlitImageError::SourceCoordinatesOutOfRange); |
| } |
| |
| if source_bottom_right[1] < 0 || source_bottom_right[1] > source_dimensions.height() as i32 { |
| return Err(CheckBlitImageError::SourceCoordinatesOutOfRange); |
| } |
| |
| if source_bottom_right[2] < 0 || source_bottom_right[2] > source_dimensions.depth() as i32 { |
| return Err(CheckBlitImageError::SourceCoordinatesOutOfRange); |
| } |
| |
| if destination_top_left[0] < 0 |
| || destination_top_left[0] > destination_dimensions.width() as i32 |
| { |
| return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange); |
| } |
| |
| if destination_top_left[1] < 0 |
| || destination_top_left[1] > destination_dimensions.height() as i32 |
| { |
| return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange); |
| } |
| |
| if destination_top_left[2] < 0 |
| || destination_top_left[2] > destination_dimensions.depth() as i32 |
| { |
| return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange); |
| } |
| |
| if destination_bottom_right[0] < 0 |
| || destination_bottom_right[0] > destination_dimensions.width() as i32 |
| { |
| return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange); |
| } |
| |
| if destination_bottom_right[1] < 0 |
| || destination_bottom_right[1] > destination_dimensions.height() as i32 |
| { |
| return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange); |
| } |
| |
| if destination_bottom_right[2] < 0 |
| || destination_bottom_right[2] > destination_dimensions.depth() as i32 |
| { |
| return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange); |
| } |
| |
| match source_dimensions { |
| ImageDimensions::Dim1d { .. } => { |
| if source_top_left[1] != 0 || source_bottom_right[1] != 1 { |
| return Err(CheckBlitImageError::IncompatibleRangeForImageType); |
| } |
| if source_top_left[2] != 0 || source_bottom_right[2] != 1 { |
| return Err(CheckBlitImageError::IncompatibleRangeForImageType); |
| } |
| } |
| ImageDimensions::Dim2d { .. } => { |
| if source_top_left[2] != 0 || source_bottom_right[2] != 1 { |
| return Err(CheckBlitImageError::IncompatibleRangeForImageType); |
| } |
| } |
| ImageDimensions::Dim3d { .. } => {} |
| } |
| |
| match destination_dimensions { |
| ImageDimensions::Dim1d { .. } => { |
| if destination_top_left[1] != 0 || destination_bottom_right[1] != 1 { |
| return Err(CheckBlitImageError::IncompatibleRangeForImageType); |
| } |
| if destination_top_left[2] != 0 || destination_bottom_right[2] != 1 { |
| return Err(CheckBlitImageError::IncompatibleRangeForImageType); |
| } |
| } |
| ImageDimensions::Dim2d { .. } => { |
| if destination_top_left[2] != 0 || destination_bottom_right[2] != 1 { |
| return Err(CheckBlitImageError::IncompatibleRangeForImageType); |
| } |
| } |
| ImageDimensions::Dim3d { .. } => {} |
| } |
| |
| Ok(()) |
| } |
| |
| /// Error that can happen from `check_clear_color_image`. |
| #[derive(Debug, Copy, Clone)] |
| pub enum CheckBlitImageError { |
| /// The source is missing the transfer source usage. |
| MissingTransferSourceUsage, |
| /// The destination is missing the transfer destination usage. |
| MissingTransferDestinationUsage, |
| /// The format of the source image doesn't support blit operations. |
| SourceFormatNotSupported, |
| /// The format of the destination image doesn't support blit operations. |
| DestinationFormatNotSupported, |
| /// You must use the nearest filter when blitting depth/stencil images. |
| DepthStencilNearestMandatory, |
| /// The format of the source and destination must be equal when blitting depth/stencil images. |
| DepthStencilFormatMismatch, |
| /// The types of the source format and the destination format aren't compatible. |
| IncompatibleFormatsTypes { |
| source_format_ty: FormatTy, |
| destination_format_ty: FormatTy, |
| }, |
| /// Blitting between multisampled images is forbidden. |
| UnexpectedMultisampled, |
| /// The offsets, array layers and/or mipmap levels are out of range in the source image. |
| SourceCoordinatesOutOfRange, |
| /// The offsets, array layers and/or mipmap levels are out of range in the destination image. |
| DestinationCoordinatesOutOfRange, |
| /// The top-left and/or bottom-right coordinates are incompatible with the image type. |
| IncompatibleRangeForImageType, |
| } |
| |
| impl error::Error for CheckBlitImageError {} |
| |
| impl fmt::Display for CheckBlitImageError { |
| #[inline] |
| fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
| write!( |
| fmt, |
| "{}", |
| match *self { |
| CheckBlitImageError::MissingTransferSourceUsage => { |
| "the source is missing the transfer source usage" |
| } |
| CheckBlitImageError::MissingTransferDestinationUsage => { |
| "the destination is missing the transfer destination usage" |
| } |
| CheckBlitImageError::SourceFormatNotSupported => { |
| "the format of the source image doesn't support blit operations" |
| } |
| CheckBlitImageError::DestinationFormatNotSupported => { |
| "the format of the destination image doesn't support blit operations" |
| } |
| CheckBlitImageError::DepthStencilNearestMandatory => { |
| "you must use the nearest filter when blitting depth/stencil images" |
| } |
| CheckBlitImageError::DepthStencilFormatMismatch => { |
| "the format of the source and destination must be equal when blitting \ |
| depth/stencil images" |
| } |
| CheckBlitImageError::IncompatibleFormatsTypes { .. } => { |
| "the types of the source format and the destination format aren't compatible" |
| } |
| CheckBlitImageError::UnexpectedMultisampled => { |
| "blitting between multisampled images is forbidden" |
| } |
| CheckBlitImageError::SourceCoordinatesOutOfRange => { |
| "the offsets, array layers and/or mipmap levels are out of range in the source \ |
| image" |
| } |
| CheckBlitImageError::DestinationCoordinatesOutOfRange => { |
| "the offsets, array layers and/or mipmap levels are out of range in the \ |
| destination image" |
| } |
| CheckBlitImageError::IncompatibleRangeForImageType => { |
| "the top-left and/or bottom-right coordinates are incompatible with the image type" |
| } |
| } |
| ) |
| } |
| } |