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