1 // Copyright (c) 2016 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::buffer::TypedBufferAccess;
11 use crate::device::Device;
12 use crate::device::DeviceOwned;
13 use crate::format::Format;
14 use crate::format::IncompatiblePixelsType;
15 use crate::format::Pixel;
16 use crate::image::ImageAccess;
17 use crate::image::SampleCount;
18 use crate::DeviceSize;
19 use crate::VulkanObject;
20 use std::error;
21 use std::fmt;
22
23 /// Type of operation to check.
24 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
25 pub enum CheckCopyBufferImageTy {
26 BufferToImage,
27 ImageToBuffer,
28 }
29
30 /// Checks whether a copy buffer-image command is valid. Can check both buffer-to-image copies and
31 /// image-to-buffer copies.
32 ///
33 /// # Panic
34 ///
35 /// - Panics if the buffer and image were not created with `device`.
36 ///
check_copy_buffer_image<B, I, Px>( device: &Device, buffer: &B, image: &I, ty: CheckCopyBufferImageTy, image_offset: [u32; 3], image_size: [u32; 3], image_first_layer: u32, image_num_layers: u32, image_mipmap: u32, ) -> Result<(), CheckCopyBufferImageError> where I: ?Sized + ImageAccess, B: ?Sized + TypedBufferAccess<Content = [Px]>, Px: Pixel,37 pub fn check_copy_buffer_image<B, I, Px>(
38 device: &Device,
39 buffer: &B,
40 image: &I,
41 ty: CheckCopyBufferImageTy,
42 image_offset: [u32; 3],
43 image_size: [u32; 3],
44 image_first_layer: u32,
45 image_num_layers: u32,
46 image_mipmap: u32,
47 ) -> Result<(), CheckCopyBufferImageError>
48 where
49 I: ?Sized + ImageAccess,
50 B: ?Sized + TypedBufferAccess<Content = [Px]>,
51 Px: Pixel, // TODO: use a trait on the image itself instead
52 {
53 let buffer_inner = buffer.inner();
54 let image_inner = image.inner();
55
56 assert_eq!(
57 buffer_inner.buffer.device().internal_object(),
58 device.internal_object()
59 );
60 assert_eq!(
61 image_inner.image.device().internal_object(),
62 device.internal_object()
63 );
64
65 match ty {
66 CheckCopyBufferImageTy::BufferToImage => {
67 if !buffer_inner.buffer.usage().transfer_source {
68 return Err(CheckCopyBufferImageError::SourceMissingTransferUsage);
69 }
70 if !image_inner.image.usage().transfer_destination {
71 return Err(CheckCopyBufferImageError::DestinationMissingTransferUsage);
72 }
73 }
74 CheckCopyBufferImageTy::ImageToBuffer => {
75 if !image_inner.image.usage().transfer_source {
76 return Err(CheckCopyBufferImageError::SourceMissingTransferUsage);
77 }
78 if !buffer_inner.buffer.usage().transfer_destination {
79 return Err(CheckCopyBufferImageError::DestinationMissingTransferUsage);
80 }
81 }
82 }
83
84 if image.samples() != SampleCount::Sample1 {
85 return Err(CheckCopyBufferImageError::UnexpectedMultisampled);
86 }
87
88 let image_dimensions = match image.dimensions().mipmap_dimensions(image_mipmap) {
89 Some(d) => d,
90 None => return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange),
91 };
92
93 if image_first_layer + image_num_layers > image_dimensions.array_layers() {
94 return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
95 }
96
97 if image_offset[0] + image_size[0] > image_dimensions.width() {
98 return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
99 }
100
101 if image_offset[1] + image_size[1] > image_dimensions.height() {
102 return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
103 }
104
105 if image_offset[2] + image_size[2] > image_dimensions.depth() {
106 return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
107 }
108
109 Px::ensure_accepts(image.format())?;
110
111 {
112 let required_len =
113 required_len_for_format::<Px>(image.format(), image_size, image_num_layers);
114 if required_len > buffer.len() {
115 return Err(CheckCopyBufferImageError::BufferTooSmall {
116 required_len,
117 actual_len: buffer.len(),
118 });
119 }
120 }
121
122 // TODO: check memory overlap?
123
124 Ok(())
125 }
126
127 /// Computes the minimum required len in elements for buffer with image data in specified
128 /// format of specified size.
required_len_for_format<Px>( format: Format, image_size: [u32; 3], image_num_layers: u32, ) -> DeviceSize where Px: Pixel,129 fn required_len_for_format<Px>(
130 format: Format,
131 image_size: [u32; 3],
132 image_num_layers: u32,
133 ) -> DeviceSize
134 where
135 Px: Pixel,
136 {
137 let (block_width, block_height) = format.block_dimensions();
138 let num_blocks = (image_size[0] + block_width - 1) / block_width
139 * ((image_size[1] + block_height - 1) / block_height)
140 * image_size[2]
141 * image_num_layers;
142 let required_len = num_blocks as DeviceSize * Px::rate(format) as DeviceSize;
143
144 return required_len;
145 }
146
147 #[cfg(test)]
148 mod tests {
149 use crate::command_buffer::validity::copy_image_buffer::required_len_for_format;
150 use crate::format::Format;
151
152 #[test]
test_required_len_for_format()153 fn test_required_len_for_format() {
154 // issue #1292
155 assert_eq!(
156 required_len_for_format::<u8>(Format::BC1_RGBUnormBlock, [2048, 2048, 1], 1),
157 2097152
158 );
159 // other test cases
160 assert_eq!(
161 required_len_for_format::<u8>(Format::R8G8B8A8Unorm, [2048, 2048, 1], 1),
162 16777216
163 );
164 assert_eq!(
165 required_len_for_format::<u8>(Format::R4G4UnormPack8, [512, 512, 1], 1),
166 262144
167 );
168 assert_eq!(
169 required_len_for_format::<u8>(Format::R8G8B8Uscaled, [512, 512, 1], 1),
170 786432
171 );
172 assert_eq!(
173 required_len_for_format::<u8>(Format::R32G32Uint, [512, 512, 1], 1),
174 2097152
175 );
176 assert_eq!(
177 required_len_for_format::<u32>(Format::R32G32Uint, [512, 512, 1], 1),
178 524288
179 );
180 assert_eq!(
181 required_len_for_format::<[u32; 2]>(Format::R32G32Uint, [512, 512, 1], 1),
182 262144
183 );
184 assert_eq!(
185 required_len_for_format::<u8>(Format::ASTC_8x8UnormBlock, [512, 512, 1], 1),
186 65536
187 );
188 assert_eq!(
189 required_len_for_format::<u8>(Format::ASTC_12x12SrgbBlock, [512, 512, 1], 1),
190 29584
191 );
192 }
193 }
194
195 /// Error that can happen from `check_copy_buffer_image`.
196 #[derive(Debug, Copy, Clone)]
197 pub enum CheckCopyBufferImageError {
198 /// The source buffer or image is missing the transfer source usage.
199 SourceMissingTransferUsage,
200 /// The destination buffer or image is missing the transfer destination usage.
201 DestinationMissingTransferUsage,
202 /// The source and destination are overlapping.
203 OverlappingRanges,
204 /// The image must not be multisampled.
205 UnexpectedMultisampled,
206 /// The image coordinates are out of range.
207 ImageCoordinatesOutOfRange,
208 /// The type of pixels in the buffer isn't compatible with the image format.
209 WrongPixelType(IncompatiblePixelsType),
210 /// The buffer is too small for the copy operation.
211 BufferTooSmall {
212 /// Required number of elements in the buffer.
213 required_len: DeviceSize,
214 /// Actual number of elements in the buffer.
215 actual_len: DeviceSize,
216 },
217 }
218
219 impl error::Error for CheckCopyBufferImageError {
source(&self) -> Option<&(dyn error::Error + 'static)>220 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
221 match *self {
222 CheckCopyBufferImageError::WrongPixelType(ref err) => Some(err),
223 _ => None,
224 }
225 }
226 }
227
228 impl fmt::Display for CheckCopyBufferImageError {
229 #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>230 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
231 write!(
232 fmt,
233 "{}",
234 match *self {
235 CheckCopyBufferImageError::SourceMissingTransferUsage => {
236 "the source buffer is missing the transfer source usage"
237 }
238 CheckCopyBufferImageError::DestinationMissingTransferUsage => {
239 "the destination buffer is missing the transfer destination usage"
240 }
241 CheckCopyBufferImageError::OverlappingRanges => {
242 "the source and destination are overlapping"
243 }
244 CheckCopyBufferImageError::UnexpectedMultisampled => {
245 "the image must not be multisampled"
246 }
247 CheckCopyBufferImageError::ImageCoordinatesOutOfRange => {
248 "the image coordinates are out of range"
249 }
250 CheckCopyBufferImageError::WrongPixelType(_) => {
251 "the type of pixels in the buffer isn't compatible with the image format"
252 }
253 CheckCopyBufferImageError::BufferTooSmall { .. } => {
254 "the buffer is too small for the copy operation"
255 }
256 }
257 )
258 }
259 }
260
261 impl From<IncompatiblePixelsType> for CheckCopyBufferImageError {
262 #[inline]
from(err: IncompatiblePixelsType) -> CheckCopyBufferImageError263 fn from(err: IncompatiblePixelsType) -> CheckCopyBufferImageError {
264 CheckCopyBufferImageError::WrongPixelType(err)
265 }
266 }
267