• 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::image::SampleCount;
15 use crate::sampler::Filter;
16 use crate::VulkanObject;
17 use std::error;
18 use std::fmt;
19 
20 /// Checks whether a blit image command is valid.
21 ///
22 /// Note that this doesn't check whether `layer_count` is equal to 0. TODO: change that?
23 ///
24 /// # Panic
25 ///
26 /// - Panics if the source or the destination was not created with `device`.
27 ///
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,28 pub fn check_blit_image<S, D>(
29     device: &Device,
30     source: &S,
31     source_top_left: [i32; 3],
32     source_bottom_right: [i32; 3],
33     source_base_array_layer: u32,
34     source_mip_level: u32,
35     destination: &D,
36     destination_top_left: [i32; 3],
37     destination_bottom_right: [i32; 3],
38     destination_base_array_layer: u32,
39     destination_mip_level: u32,
40     layer_count: u32,
41     filter: Filter,
42 ) -> Result<(), CheckBlitImageError>
43 where
44     S: ?Sized + ImageAccess,
45     D: ?Sized + ImageAccess,
46 {
47     let source_inner = source.inner();
48     let destination_inner = destination.inner();
49 
50     assert_eq!(
51         source_inner.image.device().internal_object(),
52         device.internal_object()
53     );
54     assert_eq!(
55         destination_inner.image.device().internal_object(),
56         device.internal_object()
57     );
58 
59     if !source_inner.image.usage().transfer_source {
60         return Err(CheckBlitImageError::MissingTransferSourceUsage);
61     }
62 
63     if !destination_inner.image.usage().transfer_destination {
64         return Err(CheckBlitImageError::MissingTransferDestinationUsage);
65     }
66 
67     if !source_inner.image.format_features().blit_src {
68         return Err(CheckBlitImageError::SourceFormatNotSupported);
69     }
70 
71     if !destination_inner.image.format_features().blit_dst {
72         return Err(CheckBlitImageError::DestinationFormatNotSupported);
73     }
74 
75     if source.samples() != SampleCount::Sample1 || destination.samples() != SampleCount::Sample1 {
76         return Err(CheckBlitImageError::UnexpectedMultisampled);
77     }
78 
79     let source_format_ty = source.format().ty();
80     let destination_format_ty = destination.format().ty();
81 
82     if matches!(
83         source_format_ty,
84         FormatTy::Depth | FormatTy::Stencil | FormatTy::DepthStencil
85     ) {
86         if source.format() != destination.format() {
87             return Err(CheckBlitImageError::DepthStencilFormatMismatch);
88         }
89 
90         if filter != Filter::Nearest {
91             return Err(CheckBlitImageError::DepthStencilNearestMandatory);
92         }
93     }
94 
95     let types_should_be_same = source_format_ty == FormatTy::Uint
96         || destination_format_ty == FormatTy::Uint
97         || source_format_ty == FormatTy::Sint
98         || destination_format_ty == FormatTy::Sint;
99     if types_should_be_same && (source_format_ty != destination_format_ty) {
100         return Err(CheckBlitImageError::IncompatibleFormatsTypes {
101             source_format_ty: source.format().ty(),
102             destination_format_ty: destination.format().ty(),
103         });
104     }
105 
106     let source_dimensions = match source.dimensions().mipmap_dimensions(source_mip_level) {
107         Some(d) => d,
108         None => return Err(CheckBlitImageError::SourceCoordinatesOutOfRange),
109     };
110 
111     let destination_dimensions = match destination
112         .dimensions()
113         .mipmap_dimensions(destination_mip_level)
114     {
115         Some(d) => d,
116         None => return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange),
117     };
118 
119     if source_base_array_layer + layer_count > source_dimensions.array_layers() {
120         return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
121     }
122 
123     if destination_base_array_layer + layer_count > destination_dimensions.array_layers() {
124         return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
125     }
126 
127     if source_top_left[0] < 0 || source_top_left[0] > source_dimensions.width() as i32 {
128         return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
129     }
130 
131     if source_top_left[1] < 0 || source_top_left[1] > source_dimensions.height() as i32 {
132         return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
133     }
134 
135     if source_top_left[2] < 0 || source_top_left[2] > source_dimensions.depth() as i32 {
136         return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
137     }
138 
139     if source_bottom_right[0] < 0 || source_bottom_right[0] > source_dimensions.width() as i32 {
140         return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
141     }
142 
143     if source_bottom_right[1] < 0 || source_bottom_right[1] > source_dimensions.height() as i32 {
144         return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
145     }
146 
147     if source_bottom_right[2] < 0 || source_bottom_right[2] > source_dimensions.depth() as i32 {
148         return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
149     }
150 
151     if destination_top_left[0] < 0
152         || destination_top_left[0] > destination_dimensions.width() as i32
153     {
154         return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
155     }
156 
157     if destination_top_left[1] < 0
158         || destination_top_left[1] > destination_dimensions.height() as i32
159     {
160         return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
161     }
162 
163     if destination_top_left[2] < 0
164         || destination_top_left[2] > destination_dimensions.depth() as i32
165     {
166         return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
167     }
168 
169     if destination_bottom_right[0] < 0
170         || destination_bottom_right[0] > destination_dimensions.width() as i32
171     {
172         return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
173     }
174 
175     if destination_bottom_right[1] < 0
176         || destination_bottom_right[1] > destination_dimensions.height() as i32
177     {
178         return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
179     }
180 
181     if destination_bottom_right[2] < 0
182         || destination_bottom_right[2] > destination_dimensions.depth() as i32
183     {
184         return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
185     }
186 
187     match source_dimensions {
188         ImageDimensions::Dim1d { .. } => {
189             if source_top_left[1] != 0 || source_bottom_right[1] != 1 {
190                 return Err(CheckBlitImageError::IncompatibleRangeForImageType);
191             }
192             if source_top_left[2] != 0 || source_bottom_right[2] != 1 {
193                 return Err(CheckBlitImageError::IncompatibleRangeForImageType);
194             }
195         }
196         ImageDimensions::Dim2d { .. } => {
197             if source_top_left[2] != 0 || source_bottom_right[2] != 1 {
198                 return Err(CheckBlitImageError::IncompatibleRangeForImageType);
199             }
200         }
201         ImageDimensions::Dim3d { .. } => {}
202     }
203 
204     match destination_dimensions {
205         ImageDimensions::Dim1d { .. } => {
206             if destination_top_left[1] != 0 || destination_bottom_right[1] != 1 {
207                 return Err(CheckBlitImageError::IncompatibleRangeForImageType);
208             }
209             if destination_top_left[2] != 0 || destination_bottom_right[2] != 1 {
210                 return Err(CheckBlitImageError::IncompatibleRangeForImageType);
211             }
212         }
213         ImageDimensions::Dim2d { .. } => {
214             if destination_top_left[2] != 0 || destination_bottom_right[2] != 1 {
215                 return Err(CheckBlitImageError::IncompatibleRangeForImageType);
216             }
217         }
218         ImageDimensions::Dim3d { .. } => {}
219     }
220 
221     Ok(())
222 }
223 
224 /// Error that can happen from `check_clear_color_image`.
225 #[derive(Debug, Copy, Clone)]
226 pub enum CheckBlitImageError {
227     /// The source is missing the transfer source usage.
228     MissingTransferSourceUsage,
229     /// The destination is missing the transfer destination usage.
230     MissingTransferDestinationUsage,
231     /// The format of the source image doesn't support blit operations.
232     SourceFormatNotSupported,
233     /// The format of the destination image doesn't support blit operations.
234     DestinationFormatNotSupported,
235     /// You must use the nearest filter when blitting depth/stencil images.
236     DepthStencilNearestMandatory,
237     /// The format of the source and destination must be equal when blitting depth/stencil images.
238     DepthStencilFormatMismatch,
239     /// The types of the source format and the destination format aren't compatible.
240     IncompatibleFormatsTypes {
241         source_format_ty: FormatTy,
242         destination_format_ty: FormatTy,
243     },
244     /// Blitting between multisampled images is forbidden.
245     UnexpectedMultisampled,
246     /// The offsets, array layers and/or mipmap levels are out of range in the source image.
247     SourceCoordinatesOutOfRange,
248     /// The offsets, array layers and/or mipmap levels are out of range in the destination image.
249     DestinationCoordinatesOutOfRange,
250     /// The top-left and/or bottom-right coordinates are incompatible with the image type.
251     IncompatibleRangeForImageType,
252 }
253 
254 impl error::Error for CheckBlitImageError {}
255 
256 impl fmt::Display for CheckBlitImageError {
257     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>258     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
259         write!(
260             fmt,
261             "{}",
262             match *self {
263                 CheckBlitImageError::MissingTransferSourceUsage => {
264                     "the source is missing the transfer source usage"
265                 }
266                 CheckBlitImageError::MissingTransferDestinationUsage => {
267                     "the destination is missing the transfer destination usage"
268                 }
269                 CheckBlitImageError::SourceFormatNotSupported => {
270                     "the format of the source image doesn't support blit operations"
271                 }
272                 CheckBlitImageError::DestinationFormatNotSupported => {
273                     "the format of the destination image doesn't support blit operations"
274                 }
275                 CheckBlitImageError::DepthStencilNearestMandatory => {
276                     "you must use the nearest filter when blitting depth/stencil images"
277                 }
278                 CheckBlitImageError::DepthStencilFormatMismatch => {
279                     "the format of the source and destination must be equal when blitting \
280                  depth/stencil images"
281                 }
282                 CheckBlitImageError::IncompatibleFormatsTypes { .. } => {
283                     "the types of the source format and the destination format aren't compatible"
284                 }
285                 CheckBlitImageError::UnexpectedMultisampled => {
286                     "blitting between multisampled images is forbidden"
287                 }
288                 CheckBlitImageError::SourceCoordinatesOutOfRange => {
289                     "the offsets, array layers and/or mipmap levels are out of range in the source \
290                  image"
291                 }
292                 CheckBlitImageError::DestinationCoordinatesOutOfRange => {
293                     "the offsets, array layers and/or mipmap levels are out of range in the \
294                  destination image"
295                 }
296                 CheckBlitImageError::IncompatibleRangeForImageType => {
297                     "the top-left and/or bottom-right coordinates are incompatible with the image type"
298                 }
299             }
300         )
301     }
302 }
303