• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 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 use crate::device::Device;
11 use crate::format::FormatTy;
12 use crate::image::ImageAccess;
13 use crate::image::ImageDimensions;
14 use crate::VulkanObject;
15 use std::error;
16 use std::fmt;
17 
18 /// Checks whether a copy image command is valid.
19 ///
20 /// Note that this doesn't check whether `layer_count` is equal to 0. TODO: change that?
21 ///
22 /// # Panic
23 ///
24 /// - Panics if the source or the destination was not created with `device`.
25 ///
check_copy_image<S, D>( device: &Device, source: &S, source_offset: [i32; 3], source_base_array_layer: u32, source_mip_level: u32, destination: &D, destination_offset: [i32; 3], destination_base_array_layer: u32, destination_mip_level: u32, extent: [u32; 3], layer_count: u32, ) -> Result<(), CheckCopyImageError> where S: ?Sized + ImageAccess, D: ?Sized + ImageAccess,26 pub fn check_copy_image<S, D>(
27     device: &Device,
28     source: &S,
29     source_offset: [i32; 3],
30     source_base_array_layer: u32,
31     source_mip_level: u32,
32     destination: &D,
33     destination_offset: [i32; 3],
34     destination_base_array_layer: u32,
35     destination_mip_level: u32,
36     extent: [u32; 3],
37     layer_count: u32,
38 ) -> Result<(), CheckCopyImageError>
39 where
40     S: ?Sized + ImageAccess,
41     D: ?Sized + ImageAccess,
42 {
43     let source_inner = source.inner();
44     let destination_inner = destination.inner();
45 
46     assert_eq!(
47         source_inner.image.device().internal_object(),
48         device.internal_object()
49     );
50     assert_eq!(
51         destination_inner.image.device().internal_object(),
52         device.internal_object()
53     );
54 
55     if !source_inner.image.usage().transfer_source {
56         return Err(CheckCopyImageError::MissingTransferSourceUsage);
57     }
58 
59     if !destination_inner.image.usage().transfer_destination {
60         return Err(CheckCopyImageError::MissingTransferDestinationUsage);
61     }
62 
63     if source.samples() != destination.samples() {
64         return Err(CheckCopyImageError::SampleCountMismatch);
65     }
66 
67     let source_format_ty = source.format().ty();
68     let destination_format_ty = destination.format().ty();
69 
70     if matches!(
71         source_format_ty,
72         FormatTy::Depth | FormatTy::Stencil | FormatTy::DepthStencil
73     ) {
74         if source.format() != destination.format() {
75             return Err(CheckCopyImageError::DepthStencilFormatMismatch);
76         }
77     }
78 
79     // TODO: The correct check here is that the uncompressed element size of the source is
80     // equal to the compressed element size of the destination.  However, format doesn't
81     // currently expose this information, so to be safe, we simply disallow compressed formats.
82     if source.format().ty() == FormatTy::Compressed
83         || destination.format().ty() == FormatTy::Compressed
84         || (source.format().size() != destination.format().size())
85     {
86         return Err(CheckCopyImageError::SizeIncompatibleFormatsTypes {
87             source_format_ty: source.format().ty(),
88             destination_format_ty: destination.format().ty(),
89         });
90     }
91 
92     let source_dimensions = match source.dimensions().mipmap_dimensions(source_mip_level) {
93         Some(d) => d,
94         None => return Err(CheckCopyImageError::SourceCoordinatesOutOfRange),
95     };
96 
97     let destination_dimensions = match destination
98         .dimensions()
99         .mipmap_dimensions(destination_mip_level)
100     {
101         Some(d) => d,
102         None => return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange),
103     };
104 
105     if source_base_array_layer + layer_count > source_dimensions.array_layers() {
106         return Err(CheckCopyImageError::SourceCoordinatesOutOfRange);
107     }
108 
109     if destination_base_array_layer + layer_count > destination_dimensions.array_layers() {
110         return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange);
111     }
112 
113     if source_offset[0] < 0 || source_offset[0] as u32 + extent[0] > source_dimensions.width() {
114         return Err(CheckCopyImageError::SourceCoordinatesOutOfRange);
115     }
116 
117     if source_offset[1] < 0 || source_offset[1] as u32 + extent[1] > source_dimensions.height() {
118         return Err(CheckCopyImageError::SourceCoordinatesOutOfRange);
119     }
120 
121     if source_offset[2] < 0 || source_offset[2] as u32 + extent[2] > source_dimensions.depth() {
122         return Err(CheckCopyImageError::SourceCoordinatesOutOfRange);
123     }
124 
125     if destination_offset[0] < 0
126         || destination_offset[0] as u32 + extent[0] > destination_dimensions.width()
127     {
128         return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange);
129     }
130 
131     if destination_offset[1] < 0
132         || destination_offset[1] as u32 + extent[1] > destination_dimensions.height()
133     {
134         return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange);
135     }
136 
137     if destination_offset[2] < 0
138         || destination_offset[2] as u32 + extent[2] > destination_dimensions.depth()
139     {
140         return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange);
141     }
142 
143     match source_dimensions {
144         ImageDimensions::Dim1d { .. } => {
145             if source_offset[1] != 0 || extent[1] != 1 {
146                 return Err(CheckCopyImageError::IncompatibleRangeForImageType);
147             }
148             if source_offset[2] != 0 || extent[2] != 1 {
149                 return Err(CheckCopyImageError::IncompatibleRangeForImageType);
150             }
151         }
152         ImageDimensions::Dim2d { .. } => {
153             if source_offset[2] != 0 || extent[2] != 1 {
154                 return Err(CheckCopyImageError::IncompatibleRangeForImageType);
155             }
156         }
157         ImageDimensions::Dim3d { .. } => {}
158     }
159 
160     match destination_dimensions {
161         ImageDimensions::Dim1d { .. } => {
162             if destination_offset[1] != 0 || extent[1] != 1 {
163                 return Err(CheckCopyImageError::IncompatibleRangeForImageType);
164             }
165             if destination_offset[2] != 0 || extent[2] != 1 {
166                 return Err(CheckCopyImageError::IncompatibleRangeForImageType);
167             }
168         }
169         ImageDimensions::Dim2d { .. } => {
170             if destination_offset[2] != 0 || extent[2] != 1 {
171                 return Err(CheckCopyImageError::IncompatibleRangeForImageType);
172             }
173         }
174         ImageDimensions::Dim3d { .. } => {}
175     }
176 
177     Ok(())
178 }
179 
180 /// Error that can happen from `check_copy_image`.
181 #[derive(Debug, Copy, Clone)]
182 pub enum CheckCopyImageError {
183     /// The source is missing the transfer source usage.
184     MissingTransferSourceUsage,
185     /// The destination is missing the transfer destination usage.
186     MissingTransferDestinationUsage,
187     /// The number of samples in the source and destination do not match.
188     SampleCountMismatch,
189     /// The format of the source and destination must be equal when copying depth/stencil images.
190     DepthStencilFormatMismatch,
191     /// The types of the source format and the destination format aren't size-compatible.
192     SizeIncompatibleFormatsTypes {
193         source_format_ty: FormatTy,
194         destination_format_ty: FormatTy,
195     },
196     /// The offsets, array layers and/or mipmap levels are out of range in the source image.
197     SourceCoordinatesOutOfRange,
198     /// The offsets, array layers and/or mipmap levels are out of range in the destination image.
199     DestinationCoordinatesOutOfRange,
200     /// The offsets or extent are incompatible with the image type.
201     IncompatibleRangeForImageType,
202 }
203 
204 impl error::Error for CheckCopyImageError {}
205 
206 impl fmt::Display for CheckCopyImageError {
207     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>208     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
209         write!(
210             fmt,
211             "{}",
212             match *self {
213                 CheckCopyImageError::MissingTransferSourceUsage => {
214                     "the source is missing the transfer source usage"
215                 }
216                 CheckCopyImageError::MissingTransferDestinationUsage => {
217                     "the destination is missing the transfer destination usage"
218                 }
219                 CheckCopyImageError::SampleCountMismatch => {
220                     "the number of samples in the source and destination do not match"
221                 }
222                 CheckCopyImageError::DepthStencilFormatMismatch => {
223                     "the format of the source and destination must be equal when copying \
224                  depth/stencil images"
225                 }
226                 CheckCopyImageError::SizeIncompatibleFormatsTypes { .. } => {
227                     "the types of the source format and the destination format aren't size-compatible"
228                 }
229                 CheckCopyImageError::SourceCoordinatesOutOfRange => {
230                     "the offsets, array layers and/or mipmap levels are out of range in the source \
231                  image"
232                 }
233                 CheckCopyImageError::DestinationCoordinatesOutOfRange => {
234                     "the offsets, array layers and/or mipmap levels are out of range in the \
235                  destination image"
236                 }
237                 CheckCopyImageError::IncompatibleRangeForImageType => {
238                     "the offsets or extent are incompatible with the image type"
239                 }
240             }
241         )
242     }
243 }
244