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