• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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