1 // Copyright (c) 2022 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::{
11     buffer::{BufferUsage, Subbuffer},
12     command_buffer::{
13         allocator::CommandBufferAllocator,
14         synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError},
15         sys::UnsafeCommandBufferBuilder,
16         AutoCommandBufferBuilder, ResourceInCommand, ResourceUseRef,
17     },
18     device::{DeviceOwned, QueueFlags},
19     format::{Format, FormatFeatures, NumericType},
20     image::{
21         ImageAccess, ImageAspects, ImageDimensions, ImageLayout, ImageSubresourceLayers, ImageType,
22         ImageUsage, SampleCount, SampleCounts,
23     },
24     sampler::Filter,
25     sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
26     DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanObject,
27 };
28 use smallvec::{smallvec, SmallVec};
29 use std::{
30     cmp::{max, min},
31     error::Error,
32     fmt::{Display, Error as FmtError, Formatter},
33     mem::size_of,
34     sync::Arc,
35 };
36 
37 /// # Commands to transfer data between resources.
38 impl<L, A> AutoCommandBufferBuilder<L, A>
39 where
40     A: CommandBufferAllocator,
41 {
42     /// Copies data from a buffer to another buffer.
43     ///
44     /// # Panics
45     ///
46     /// - Panics if `src_buffer` or `dst_buffer` were not created from the same device
47     ///   as `self`.
copy_buffer( &mut self, copy_buffer_info: impl Into<CopyBufferInfo>, ) -> Result<&mut Self, CopyError>48     pub fn copy_buffer(
49         &mut self,
50         copy_buffer_info: impl Into<CopyBufferInfo>,
51     ) -> Result<&mut Self, CopyError> {
52         let copy_buffer_info = copy_buffer_info.into();
53         self.validate_copy_buffer(&copy_buffer_info)?;
54 
55         unsafe {
56             self.inner.copy_buffer(copy_buffer_info)?;
57         }
58 
59         Ok(self)
60     }
61 
validate_copy_buffer(&self, copy_buffer_info: &CopyBufferInfo) -> Result<(), CopyError>62     fn validate_copy_buffer(&self, copy_buffer_info: &CopyBufferInfo) -> Result<(), CopyError> {
63         let device = self.device();
64 
65         // VUID-vkCmdCopyBuffer2-renderpass
66         if self.render_pass_state.is_some() {
67             return Err(CopyError::ForbiddenInsideRenderPass);
68         }
69 
70         let queue_family_properties = self.queue_family_properties();
71 
72         // VUID-vkCmdCopyBuffer2-commandBuffer-cmdpool
73         if !queue_family_properties
74             .queue_flags
75             .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
76         {
77             return Err(CopyError::NotSupportedByQueueFamily);
78         }
79 
80         let &CopyBufferInfo {
81             ref src_buffer,
82             ref dst_buffer,
83             ref regions,
84             _ne: _,
85         } = copy_buffer_info;
86 
87         // VUID-VkCopyBufferInfo2-commonparent
88         assert_eq!(device, src_buffer.device());
89         assert_eq!(device, dst_buffer.device());
90 
91         // VUID-VkCopyBufferInfo2-srcBuffer-00118
92         if !src_buffer
93             .buffer()
94             .usage()
95             .intersects(BufferUsage::TRANSFER_SRC)
96         {
97             return Err(CopyError::MissingUsage {
98                 resource: CopyErrorResource::Source,
99                 usage: "transfer_src",
100             });
101         }
102 
103         // VUID-VkCopyBufferInfo2-dstBuffer-00120
104         if !dst_buffer
105             .buffer()
106             .usage()
107             .intersects(BufferUsage::TRANSFER_DST)
108         {
109             return Err(CopyError::MissingUsage {
110                 resource: CopyErrorResource::Destination,
111                 usage: "transfer_dst",
112             });
113         }
114 
115         let same_buffer = src_buffer.buffer() == dst_buffer.buffer();
116         let mut overlap_indices = None;
117 
118         for (region_index, region) in regions.iter().enumerate() {
119             let &BufferCopy {
120                 src_offset,
121                 dst_offset,
122                 size,
123                 _ne: _,
124             } = region;
125 
126             // VUID-VkBufferCopy2-size-01988
127             assert!(size != 0);
128 
129             // VUID-VkCopyBufferInfo2-srcOffset-00113
130             // VUID-VkCopyBufferInfo2-size-00115
131             if src_offset + size > src_buffer.size() {
132                 return Err(CopyError::RegionOutOfBufferBounds {
133                     resource: CopyErrorResource::Source,
134                     region_index,
135                     offset_range_end: src_offset + size,
136                     buffer_size: src_buffer.size(),
137                 });
138             }
139 
140             // VUID-VkCopyBufferInfo2-dstOffset-00114
141             // VUID-VkCopyBufferInfo2-size-00116
142             if dst_offset + size > dst_buffer.size() {
143                 return Err(CopyError::RegionOutOfBufferBounds {
144                     resource: CopyErrorResource::Destination,
145                     region_index,
146                     offset_range_end: dst_offset + size,
147                     buffer_size: dst_buffer.size(),
148                 });
149             }
150 
151             // VUID-VkCopyBufferInfo2-pRegions-00117
152             if same_buffer {
153                 let src_region_index = region_index;
154                 let src_range =
155                     src_buffer.offset() + src_offset..src_buffer.offset() + src_offset + size;
156 
157                 for (dst_region_index, dst_region) in regions.iter().enumerate() {
158                     let &BufferCopy { dst_offset, .. } = dst_region;
159 
160                     let dst_range =
161                         dst_buffer.offset() + dst_offset..dst_buffer.offset() + dst_offset + size;
162 
163                     if src_range.start >= dst_range.end || dst_range.start >= src_range.end {
164                         // The regions do not overlap
165                         continue;
166                     }
167 
168                     overlap_indices = Some((src_region_index, dst_region_index));
169                 }
170             }
171         }
172 
173         // VUID-VkCopyBufferInfo2-pRegions-00117
174         if let Some((src_region_index, dst_region_index)) = overlap_indices {
175             return Err(CopyError::OverlappingRegions {
176                 src_region_index,
177                 dst_region_index,
178             });
179         }
180 
181         Ok(())
182     }
183 
184     /// Copies data from an image to another image.
185     ///
186     /// There are several restrictions:
187     ///
188     /// - The number of samples in the source and destination images must be equal.
189     /// - The size of the uncompressed element format of the source image must be equal to the
190     ///   compressed element format of the destination.
191     /// - If you copy between depth, stencil or depth-stencil images, the format of both images
192     ///   must match exactly.
193     /// - For two-dimensional images, the Z coordinate must be 0 for the image offsets and 1 for
194     ///   the extent. Same for the Y coordinate for one-dimensional images.
195     /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
196     ///
197     /// If `layer_count` is greater than 1, the copy will happen between each individual layer as
198     /// if they were separate images.
199     ///
200     /// # Panics
201     ///
202     /// - Panics if `src_image` or `dst_image` were not created from the same device
203     ///   as `self`.
copy_image(&mut self, copy_image_info: CopyImageInfo) -> Result<&mut Self, CopyError>204     pub fn copy_image(&mut self, copy_image_info: CopyImageInfo) -> Result<&mut Self, CopyError> {
205         self.validate_copy_image(&copy_image_info)?;
206 
207         unsafe {
208             self.inner.copy_image(copy_image_info)?;
209         }
210 
211         Ok(self)
212     }
213 
validate_copy_image(&self, copy_image_info: &CopyImageInfo) -> Result<(), CopyError>214     fn validate_copy_image(&self, copy_image_info: &CopyImageInfo) -> Result<(), CopyError> {
215         let device = self.device();
216 
217         // VUID-vkCmdCopyImage2-renderpass
218         if self.render_pass_state.is_some() {
219             return Err(CopyError::ForbiddenInsideRenderPass);
220         }
221 
222         let queue_family_properties = self.queue_family_properties();
223 
224         // VUID-vkCmdCopyImage2-commandBuffer-cmdpool
225         if !queue_family_properties
226             .queue_flags
227             .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
228         {
229             return Err(CopyError::NotSupportedByQueueFamily);
230         }
231 
232         let &CopyImageInfo {
233             ref src_image,
234             src_image_layout,
235             ref dst_image,
236             dst_image_layout,
237             ref regions,
238             _ne: _,
239         } = copy_image_info;
240 
241         // VUID-VkCopyImageInfo2-srcImageLayout-parameter
242         src_image_layout.validate_device(device)?;
243 
244         // VUID-VkCopyImageInfo2-dstImageLayout-parameter
245         dst_image_layout.validate_device(device)?;
246 
247         // VUID-VkCopyImageInfo2-commonparent
248         assert_eq!(device, src_image.device());
249         assert_eq!(device, dst_image.device());
250 
251         let copy_2d_3d_supported =
252             device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1;
253         let src_image_inner = src_image.inner();
254         let dst_image_inner = dst_image.inner();
255         let mut src_image_aspects = src_image.format().aspects();
256         let mut dst_image_aspects = dst_image.format().aspects();
257 
258         if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
259             // VUID-VkCopyImageInfo2-srcImage-01995
260             if !src_image
261                 .format_features()
262                 .intersects(FormatFeatures::TRANSFER_SRC)
263             {
264                 return Err(CopyError::MissingFormatFeature {
265                     resource: CopyErrorResource::Source,
266                     format_feature: "transfer_src",
267                 });
268             }
269 
270             // VUID-VkCopyImageInfo2-dstImage-01996
271             if !dst_image
272                 .format_features()
273                 .intersects(FormatFeatures::TRANSFER_DST)
274             {
275                 return Err(CopyError::MissingFormatFeature {
276                     resource: CopyErrorResource::Destination,
277                     format_feature: "transfer_dst",
278                 });
279             }
280         }
281 
282         // VUID-VkCopyImageInfo2-srcImage-00136
283         if src_image.samples() != dst_image.samples() {
284             return Err(CopyError::SampleCountMismatch {
285                 src_sample_count: src_image.samples(),
286                 dst_sample_count: dst_image.samples(),
287             });
288         }
289 
290         if !(src_image_aspects.intersects(ImageAspects::COLOR)
291             || dst_image_aspects.intersects(ImageAspects::COLOR))
292         {
293             // VUID-VkCopyImageInfo2-srcImage-01548
294             if src_image.format() != dst_image.format() {
295                 return Err(CopyError::FormatsMismatch {
296                     src_format: src_image.format(),
297                     dst_format: dst_image.format(),
298                 });
299             }
300         }
301 
302         // VUID-VkCopyImageInfo2-srcImageLayout-01917
303         if !matches!(
304             src_image_layout,
305             ImageLayout::TransferSrcOptimal | ImageLayout::General
306         ) {
307             return Err(CopyError::ImageLayoutInvalid {
308                 resource: CopyErrorResource::Source,
309                 image_layout: src_image_layout,
310             });
311         }
312 
313         // VUID-VkCopyImageInfo2-dstImageLayout-01395
314         if !matches!(
315             dst_image_layout,
316             ImageLayout::TransferDstOptimal | ImageLayout::General
317         ) {
318             return Err(CopyError::ImageLayoutInvalid {
319                 resource: CopyErrorResource::Destination,
320                 image_layout: dst_image_layout,
321             });
322         }
323 
324         let extent_alignment = match queue_family_properties.min_image_transfer_granularity {
325             [0, 0, 0] => None,
326             min_image_transfer_granularity => {
327                 let granularity = move |block_extent: [u32; 3], is_multi_plane: bool| {
328                     if is_multi_plane {
329                         // Assume planes always have 1x1 blocks
330                         min_image_transfer_granularity
331                     } else {
332                         // "The value returned in minImageTransferGranularity has a unit of
333                         // compressed texel blocks for images having a block-compressed format, and
334                         // a unit of texels otherwise."
335                         [
336                             min_image_transfer_granularity[0] * block_extent[0],
337                             min_image_transfer_granularity[1] * block_extent[1],
338                             min_image_transfer_granularity[2] * block_extent[2],
339                         ]
340                     }
341                 };
342 
343                 Some((
344                     granularity(
345                         src_image.format().block_extent(),
346                         src_image_aspects.intersects(ImageAspects::PLANE_0),
347                     ),
348                     granularity(
349                         dst_image.format().block_extent(),
350                         dst_image_aspects.intersects(ImageAspects::PLANE_0),
351                     ),
352                 ))
353             }
354         };
355 
356         if src_image_aspects.intersects(ImageAspects::PLANE_0) {
357             // VUID-VkCopyImageInfo2-srcImage-01552
358             // VUID-VkCopyImageInfo2-srcImage-01553
359             src_image_aspects -= ImageAspects::COLOR;
360         }
361 
362         if dst_image_aspects.intersects(ImageAspects::PLANE_0) {
363             // VUID-VkCopyImageInfo2-dstImage-01554
364             // VUID-VkCopyImageInfo2-dstImage-01555
365             dst_image_aspects -= ImageAspects::COLOR;
366         }
367 
368         let mut src_image_aspects_used = ImageAspects::empty();
369         let mut dst_image_aspects_used = ImageAspects::empty();
370         let same_image = src_image_inner.image == dst_image_inner.image;
371         let mut overlap_subresource_indices = None;
372         let mut overlap_extent_indices = None;
373 
374         for (region_index, region) in regions.iter().enumerate() {
375             let &ImageCopy {
376                 ref src_subresource,
377                 src_offset,
378                 ref dst_subresource,
379                 dst_offset,
380                 extent,
381                 _ne,
382             } = region;
383 
384             let check_subresource = |resource: CopyErrorResource,
385                                      image: &dyn ImageAccess,
386                                      image_aspects: ImageAspects,
387                                      subresource: &ImageSubresourceLayers|
388              -> Result<_, CopyError> {
389                 // VUID-VkCopyImageInfo2-srcSubresource-01696
390                 // VUID-VkCopyImageInfo2-dstSubresource-01697
391                 if subresource.mip_level >= image.mip_levels() {
392                     return Err(CopyError::MipLevelsOutOfRange {
393                         resource,
394                         region_index,
395                         mip_levels_range_end: subresource.mip_level + 1,
396                         image_mip_levels: image.mip_levels(),
397                     });
398                 }
399 
400                 // VUID-VkImageSubresourceLayers-layerCount-01700
401                 assert!(!subresource.array_layers.is_empty());
402 
403                 // VUID-VkCopyImageInfo2-srcSubresource-01698
404                 // VUID-VkCopyImageInfo2-dstSubresource-01699
405                 // VUID-VkCopyImageInfo2-srcImage-04443
406                 // VUID-VkCopyImageInfo2-dstImage-04444
407                 if subresource.array_layers.end > image.dimensions().array_layers() {
408                     return Err(CopyError::ArrayLayersOutOfRange {
409                         resource,
410                         region_index,
411                         array_layers_range_end: subresource.array_layers.end,
412                         image_array_layers: image.dimensions().array_layers(),
413                     });
414                 }
415 
416                 // VUID-VkImageSubresourceLayers-aspectMask-parameter
417                 subresource.aspects.validate_device(device)?;
418 
419                 // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
420                 assert!(!subresource.aspects.is_empty());
421 
422                 // VUID-VkCopyImageInfo2-aspectMask-00142
423                 // VUID-VkCopyImageInfo2-aspectMask-00143
424                 if !image_aspects.contains(subresource.aspects) {
425                     return Err(CopyError::AspectsNotAllowed {
426                         resource,
427                         region_index,
428                         aspects: subresource.aspects,
429                         allowed_aspects: image_aspects,
430                     });
431                 }
432 
433                 let (subresource_format, subresource_extent) =
434                     if image_aspects.intersects(ImageAspects::PLANE_0) {
435                         // VUID-VkCopyImageInfo2-srcImage-01552
436                         // VUID-VkCopyImageInfo2-srcImage-01553
437                         // VUID-VkCopyImageInfo2-dstImage-01554
438                         // VUID-VkCopyImageInfo2-dstImage-01555
439                         if subresource.aspects.count() != 1 {
440                             return Err(CopyError::MultipleAspectsNotAllowed {
441                                 resource,
442                                 region_index,
443                                 aspects: subresource.aspects,
444                             });
445                         }
446 
447                         if subresource.aspects.intersects(ImageAspects::PLANE_0) {
448                             (
449                                 image.format().planes()[0],
450                                 image.dimensions().width_height_depth(),
451                             )
452                         } else if subresource.aspects.intersects(ImageAspects::PLANE_1) {
453                             (
454                                 image.format().planes()[1],
455                                 image
456                                     .format()
457                                     .ycbcr_chroma_sampling()
458                                     .unwrap()
459                                     .subsampled_extent(image.dimensions().width_height_depth()),
460                             )
461                         } else {
462                             (
463                                 image.format().planes()[2],
464                                 image
465                                     .format()
466                                     .ycbcr_chroma_sampling()
467                                     .unwrap()
468                                     .subsampled_extent(image.dimensions().width_height_depth()),
469                             )
470                         }
471                     } else {
472                         (
473                             image.format(),
474                             image
475                                 .dimensions()
476                                 .mip_level_dimensions(subresource.mip_level)
477                                 .unwrap()
478                                 .width_height_depth(),
479                         )
480                     };
481 
482                 Ok((subresource_format, subresource_extent))
483             };
484 
485             src_image_aspects_used |= src_subresource.aspects;
486             dst_image_aspects_used |= dst_subresource.aspects;
487 
488             let (src_subresource_format, src_subresource_extent) = check_subresource(
489                 CopyErrorResource::Source,
490                 src_image,
491                 src_image_aspects,
492                 src_subresource,
493             )?;
494             let (dst_subresource_format, dst_subresource_extent) = check_subresource(
495                 CopyErrorResource::Destination,
496                 dst_image,
497                 dst_image_aspects,
498                 dst_subresource,
499             )?;
500 
501             if !(src_image_aspects.intersects(ImageAspects::PLANE_0)
502                 || dst_image_aspects.intersects(ImageAspects::PLANE_0))
503             {
504                 // VUID-VkCopyImageInfo2-srcImage-01551
505                 if src_subresource.aspects != dst_subresource.aspects {
506                     return Err(CopyError::AspectsMismatch {
507                         region_index,
508                         src_aspects: src_subresource.aspects,
509                         dst_aspects: dst_subresource.aspects,
510                     });
511                 }
512             }
513 
514             // VUID-VkCopyImageInfo2-srcImage-01548
515             // VUID-VkCopyImageInfo2-None-01549
516             // Color formats must be size-compatible.
517             if src_subresource_format.block_size() != dst_subresource_format.block_size() {
518                 return Err(CopyError::FormatsNotCompatible {
519                     src_format: src_subresource_format,
520                     dst_format: dst_subresource_format,
521                 });
522             }
523 
524             // TODO:
525             // "When copying between compressed and uncompressed formats the extent members
526             // represent the texel dimensions of the source image and not the destination."
527             let mut src_extent = extent;
528             let mut dst_extent = extent;
529             let src_layer_count =
530                 src_subresource.array_layers.end - src_subresource.array_layers.start;
531             let dst_layer_count =
532                 dst_subresource.array_layers.end - dst_subresource.array_layers.start;
533 
534             if copy_2d_3d_supported {
535                 match (
536                     src_image.dimensions().image_type(),
537                     dst_image.dimensions().image_type(),
538                 ) {
539                     (ImageType::Dim2d, ImageType::Dim3d) => {
540                         src_extent[2] = 1;
541 
542                         // VUID-vkCmdCopyImage-srcImage-01791
543                         if dst_extent[2] != src_layer_count {
544                             return Err(CopyError::ArrayLayerCountMismatch {
545                                 region_index,
546                                 src_layer_count,
547                                 dst_layer_count: dst_extent[2],
548                             });
549                         }
550                     }
551                     (ImageType::Dim3d, ImageType::Dim2d) => {
552                         dst_extent[2] = 1;
553 
554                         // VUID-vkCmdCopyImage-dstImage-01792
555                         if src_extent[2] != dst_layer_count {
556                             return Err(CopyError::ArrayLayerCountMismatch {
557                                 region_index,
558                                 src_layer_count: src_extent[2],
559                                 dst_layer_count,
560                             });
561                         }
562                     }
563                     _ => {
564                         // VUID-VkImageCopy2-extent-00140
565                         if src_layer_count != dst_layer_count {
566                             return Err(CopyError::ArrayLayerCountMismatch {
567                                 region_index,
568                                 src_layer_count,
569                                 dst_layer_count,
570                             });
571                         }
572                     }
573                 }
574             } else {
575                 // VUID-VkImageCopy2-extent-00140
576                 if src_layer_count != dst_layer_count {
577                     return Err(CopyError::ArrayLayerCountMismatch {
578                         region_index,
579                         src_layer_count,
580                         dst_layer_count,
581                     });
582                 }
583             };
584 
585             if let Some((src_extent_alignment, dst_extent_alignment)) = extent_alignment {
586                 let check_offset_extent = |resource: CopyErrorResource,
587                                            extent_alignment: [u32; 3],
588                                            subresource_extent: [u32; 3],
589                                            offset: [u32; 3],
590                                            extent: [u32; 3]|
591                  -> Result<_, CopyError> {
592                     for i in 0..3 {
593                         // VUID-VkImageCopy2-extent-06668
594                         // VUID-VkImageCopy2-extent-06669
595                         // VUID-VkImageCopy2-extent-06670
596                         assert!(extent[i] != 0);
597 
598                         // VUID-VkCopyImageInfo2-srcOffset-00144
599                         // VUID-VkCopyImageInfo2-srcOffset-00145
600                         // VUID-VkCopyImageInfo2-srcOffset-00147
601                         // VUID-VkCopyImageInfo2-dstOffset-00150
602                         // VUID-VkCopyImageInfo2-dstOffset-00151
603                         // VUID-VkCopyImageInfo2-dstOffset-00153
604                         if offset[i] + extent[i] > subresource_extent[i] {
605                             return Err(CopyError::RegionOutOfImageBounds {
606                                 resource,
607                                 region_index,
608                                 offset_range_end: [
609                                     offset[0] + extent[0],
610                                     offset[1] + extent[1],
611                                     offset[2] + extent[2],
612                                 ],
613                                 subresource_extent,
614                             });
615                         }
616 
617                         // VUID-VkCopyImageInfo2-srcImage-01727
618                         // VUID-VkCopyImageInfo2-dstImage-01731
619                         // VUID-VkCopyImageInfo2-srcOffset-01783
620                         // VUID-VkCopyImageInfo2-dstOffset-01784
621                         if offset[i] % extent_alignment[i] != 0 {
622                             return Err(CopyError::OffsetNotAlignedForImage {
623                                 resource,
624                                 region_index,
625                                 offset,
626                                 required_alignment: extent_alignment,
627                             });
628                         }
629 
630                         // VUID-VkCopyImageInfo2-srcImage-01728
631                         // VUID-VkCopyImageInfo2-srcImage-01729
632                         // VUID-VkCopyImageInfo2-srcImage-01730
633                         // VUID-VkCopyImageInfo2-dstImage-01732
634                         // VUID-VkCopyImageInfo2-dstImage-01733
635                         // VUID-VkCopyImageInfo2-dstImage-01734
636                         if offset[i] + extent[i] != subresource_extent[i]
637                             && extent[i] % extent_alignment[i] != 0
638                         {
639                             return Err(CopyError::ExtentNotAlignedForImage {
640                                 resource,
641                                 region_index,
642                                 extent,
643                                 required_alignment: extent_alignment,
644                             });
645                         }
646                     }
647 
648                     Ok(())
649                 };
650 
651                 check_offset_extent(
652                     CopyErrorResource::Source,
653                     src_extent_alignment,
654                     src_subresource_extent,
655                     src_offset,
656                     src_extent,
657                 )?;
658                 check_offset_extent(
659                     CopyErrorResource::Destination,
660                     dst_extent_alignment,
661                     dst_subresource_extent,
662                     dst_offset,
663                     dst_extent,
664                 )?;
665 
666                 // VUID-VkCopyImageInfo2-pRegions-00124
667                 if same_image {
668                     let src_region_index = region_index;
669                     let src_subresource_axes = [
670                         src_image_inner.first_mipmap_level + src_subresource.mip_level
671                             ..src_image_inner.first_mipmap_level + src_subresource.mip_level + 1,
672                         src_image_inner.first_layer + src_subresource.array_layers.start
673                             ..src_image_inner.first_layer + src_subresource.array_layers.end,
674                     ];
675                     let src_extent_axes = [
676                         src_offset[0]..src_offset[0] + extent[0],
677                         src_offset[1]..src_offset[1] + extent[1],
678                         src_offset[2]..src_offset[2] + extent[2],
679                     ];
680 
681                     for (dst_region_index, dst_region) in regions.iter().enumerate() {
682                         let &ImageCopy {
683                             ref dst_subresource,
684                             dst_offset,
685                             ..
686                         } = dst_region;
687 
688                         // For a single-plane image, the aspects must always be identical anyway
689                         if src_image_aspects.intersects(ImageAspects::PLANE_0)
690                             && src_subresource.aspects != dst_subresource.aspects
691                         {
692                             continue;
693                         }
694 
695                         let dst_subresource_axes = [
696                             dst_image_inner.first_mipmap_level + dst_subresource.mip_level
697                                 ..dst_image_inner.first_mipmap_level
698                                     + dst_subresource.mip_level
699                                     + 1,
700                             dst_image_inner.first_layer + src_subresource.array_layers.start
701                                 ..dst_image_inner.first_layer + src_subresource.array_layers.end,
702                         ];
703 
704                         if src_subresource_axes.iter().zip(dst_subresource_axes).any(
705                             |(src_range, dst_range)| {
706                                 src_range.start >= dst_range.end || dst_range.start >= src_range.end
707                             },
708                         ) {
709                             continue;
710                         }
711 
712                         // If the subresource axes all overlap, then the source and destination must
713                         // have the same layout.
714                         overlap_subresource_indices = Some((src_region_index, dst_region_index));
715 
716                         let dst_extent_axes = [
717                             dst_offset[0]..dst_offset[0] + extent[0],
718                             dst_offset[1]..dst_offset[1] + extent[1],
719                             dst_offset[2]..dst_offset[2] + extent[2],
720                         ];
721 
722                         // There is only overlap if all of the axes overlap.
723                         if src_extent_axes.iter().zip(dst_extent_axes).any(
724                             |(src_range, dst_range)| {
725                                 src_range.start >= dst_range.end || dst_range.start >= src_range.end
726                             },
727                         ) {
728                             continue;
729                         }
730 
731                         overlap_extent_indices = Some((src_region_index, dst_region_index));
732                     }
733                 }
734             } else {
735                 // If granularity is `None`, then we can only copy whole subresources.
736                 let check_offset_extent = |resource: CopyErrorResource,
737                                            subresource_extent: [u32; 3],
738                                            offset: [u32; 3],
739                                            extent: [u32; 3]|
740                  -> Result<_, CopyError> {
741                     // VUID-VkCopyImageInfo2-srcImage-01727
742                     // VUID-VkCopyImageInfo2-dstImage-01731
743                     // VUID-vkCmdCopyImage-srcOffset-01783
744                     // VUID-vkCmdCopyImage-dstOffset-01784
745                     if offset != [0, 0, 0] {
746                         return Err(CopyError::OffsetNotAlignedForImage {
747                             resource,
748                             region_index,
749                             offset,
750                             required_alignment: subresource_extent,
751                         });
752                     }
753 
754                     // VUID-VkCopyImageInfo2-srcImage-01728
755                     // VUID-VkCopyImageInfo2-srcImage-01729
756                     // VUID-VkCopyImageInfo2-srcImage-01730
757                     // VUID-VkCopyImageInfo2-dstImage-01732
758                     // VUID-VkCopyImageInfo2-dstImage-01733
759                     // VUID-VkCopyImageInfo2-dstImage-01734
760                     if extent != subresource_extent {
761                         return Err(CopyError::ExtentNotAlignedForImage {
762                             resource,
763                             region_index,
764                             extent,
765                             required_alignment: subresource_extent,
766                         });
767                     }
768 
769                     Ok(())
770                 };
771 
772                 check_offset_extent(
773                     CopyErrorResource::Source,
774                     src_subresource_extent,
775                     src_offset,
776                     src_extent,
777                 )?;
778                 check_offset_extent(
779                     CopyErrorResource::Destination,
780                     dst_subresource_extent,
781                     dst_offset,
782                     dst_extent,
783                 )?;
784 
785                 // VUID-VkCopyImageInfo2-pRegions-00124
786                 // A simpler version that assumes the region covers the full extent.
787                 if same_image {
788                     let src_region_index = region_index;
789                     let src_axes = [
790                         src_image_inner.first_mipmap_level + src_subresource.mip_level
791                             ..src_image_inner.first_mipmap_level + src_subresource.mip_level + 1,
792                         src_image_inner.first_layer + src_subresource.array_layers.start
793                             ..src_image_inner.first_layer + src_subresource.array_layers.end,
794                     ];
795 
796                     for (dst_region_index, dst_region) in regions.iter().enumerate() {
797                         let &ImageCopy {
798                             ref dst_subresource,
799                             dst_offset: _,
800                             ..
801                         } = dst_region;
802 
803                         if src_image_aspects.intersects(ImageAspects::PLANE_0)
804                             && src_subresource.aspects != dst_subresource.aspects
805                         {
806                             continue;
807                         }
808 
809                         let dst_axes = [
810                             dst_image_inner.first_mipmap_level + dst_subresource.mip_level
811                                 ..dst_image_inner.first_mipmap_level
812                                     + dst_subresource.mip_level
813                                     + 1,
814                             dst_image_inner.first_layer + src_subresource.array_layers.start
815                                 ..dst_image_inner.first_layer + src_subresource.array_layers.end,
816                         ];
817 
818                         // There is only overlap if all of the axes overlap.
819                         if src_axes.iter().zip(dst_axes).any(|(src_range, dst_range)| {
820                             src_range.start >= dst_range.end || dst_range.start >= src_range.end
821                         }) {
822                             continue;
823                         }
824 
825                         overlap_extent_indices = Some((src_region_index, dst_region_index));
826                     }
827                 }
828             }
829         }
830 
831         // VUID-VkCopyImageInfo2-aspect-06662
832         if !(src_image_aspects_used - ImageAspects::STENCIL).is_empty()
833             && !src_image.usage().intersects(ImageUsage::TRANSFER_SRC)
834         {
835             return Err(CopyError::MissingUsage {
836                 resource: CopyErrorResource::Source,
837                 usage: "transfer_src",
838             });
839         }
840 
841         // VUID-VkCopyImageInfo2-aspect-06663
842         if !(dst_image_aspects_used - ImageAspects::STENCIL).is_empty()
843             && !dst_image.usage().intersects(ImageUsage::TRANSFER_DST)
844         {
845             return Err(CopyError::MissingUsage {
846                 resource: CopyErrorResource::Destination,
847                 usage: "transfer_dst",
848             });
849         }
850 
851         // VUID-VkCopyImageInfo2-aspect-06664
852         if src_image_aspects_used.intersects(ImageAspects::STENCIL)
853             && !src_image
854                 .stencil_usage()
855                 .intersects(ImageUsage::TRANSFER_SRC)
856         {
857             return Err(CopyError::MissingUsage {
858                 resource: CopyErrorResource::Source,
859                 usage: "transfer_src",
860             });
861         }
862 
863         // VUID-VkCopyImageInfo2-aspect-06665
864         if dst_image_aspects_used.intersects(ImageAspects::STENCIL)
865             && !dst_image
866                 .stencil_usage()
867                 .intersects(ImageUsage::TRANSFER_DST)
868         {
869             return Err(CopyError::MissingUsage {
870                 resource: CopyErrorResource::Destination,
871                 usage: "transfer_dst",
872             });
873         }
874 
875         // VUID-VkCopyImageInfo2-pRegions-00124
876         if let Some((src_region_index, dst_region_index)) = overlap_extent_indices {
877             return Err(CopyError::OverlappingRegions {
878                 src_region_index,
879                 dst_region_index,
880             });
881         }
882 
883         // VUID-VkCopyImageInfo2-srcImageLayout-00128
884         // VUID-VkCopyImageInfo2-dstImageLayout-00133
885         if let Some((src_region_index, dst_region_index)) = overlap_subresource_indices {
886             if src_image_layout != dst_image_layout {
887                 return Err(CopyError::OverlappingSubresourcesLayoutMismatch {
888                     src_region_index,
889                     dst_region_index,
890                     src_image_layout,
891                     dst_image_layout,
892                 });
893             }
894         }
895 
896         Ok(())
897     }
898 
899     /// Copies from a buffer to an image.
copy_buffer_to_image( &mut self, copy_buffer_to_image_info: CopyBufferToImageInfo, ) -> Result<&mut Self, CopyError>900     pub fn copy_buffer_to_image(
901         &mut self,
902         copy_buffer_to_image_info: CopyBufferToImageInfo,
903     ) -> Result<&mut Self, CopyError> {
904         self.validate_copy_buffer_to_image(&copy_buffer_to_image_info)?;
905 
906         unsafe {
907             self.inner.copy_buffer_to_image(copy_buffer_to_image_info)?;
908         }
909 
910         Ok(self)
911     }
912 
validate_copy_buffer_to_image( &self, copy_buffer_to_image_info: &CopyBufferToImageInfo, ) -> Result<(), CopyError>913     fn validate_copy_buffer_to_image(
914         &self,
915         copy_buffer_to_image_info: &CopyBufferToImageInfo,
916     ) -> Result<(), CopyError> {
917         let device = self.device();
918 
919         // VUID-vkCmdCopyBufferToImage2-renderpass
920         if self.render_pass_state.is_some() {
921             return Err(CopyError::ForbiddenInsideRenderPass);
922         }
923 
924         let queue_family_properties = self.queue_family_properties();
925 
926         // VUID-vkCmdCopyBufferToImage2-commandBuffer-cmdpool
927         if !queue_family_properties
928             .queue_flags
929             .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
930         {
931             return Err(CopyError::NotSupportedByQueueFamily);
932         }
933 
934         let &CopyBufferToImageInfo {
935             ref src_buffer,
936             ref dst_image,
937             dst_image_layout,
938             ref regions,
939             _ne: _,
940         } = copy_buffer_to_image_info;
941 
942         // VUID-VkCopyBufferToImageInfo2-dstImageLayout-parameter
943         dst_image_layout.validate_device(device)?;
944 
945         // VUID-VkCopyBufferToImageInfo2-commonparent
946         assert_eq!(device, src_buffer.device());
947         assert_eq!(device, dst_image.device());
948 
949         let mut image_aspects = dst_image.format().aspects();
950 
951         // VUID-VkCopyBufferToImageInfo2-commandBuffer-04477
952         if !queue_family_properties
953             .queue_flags
954             .intersects(QueueFlags::GRAPHICS)
955             && !image_aspects.intersects(ImageAspects::COLOR)
956         {
957             return Err(CopyError::DepthStencilNotSupportedByQueueFamily);
958         }
959 
960         // VUID-VkCopyBufferToImageInfo2-srcBuffer-00174
961         if !src_buffer
962             .buffer()
963             .usage()
964             .intersects(BufferUsage::TRANSFER_SRC)
965         {
966             return Err(CopyError::MissingUsage {
967                 resource: CopyErrorResource::Source,
968                 usage: "transfer_src",
969             });
970         }
971 
972         // VUID-VkCopyBufferToImageInfo2-dstImage-00177
973         if !dst_image.usage().intersects(ImageUsage::TRANSFER_DST) {
974             return Err(CopyError::MissingUsage {
975                 resource: CopyErrorResource::Destination,
976                 usage: "transfer_dst",
977             });
978         }
979 
980         if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
981             // VUID-VkCopyBufferToImageInfo2-dstImage-01997
982             if !dst_image
983                 .format_features()
984                 .intersects(FormatFeatures::TRANSFER_DST)
985             {
986                 return Err(CopyError::MissingFormatFeature {
987                     resource: CopyErrorResource::Destination,
988                     format_feature: "transfer_dst",
989                 });
990             }
991         }
992 
993         // VUID-VkCopyBufferToImageInfo2-dstImage-00179
994         if dst_image.samples() != SampleCount::Sample1 {
995             return Err(CopyError::SampleCountInvalid {
996                 resource: CopyErrorResource::Destination,
997                 sample_count: dst_image.samples(),
998                 allowed_sample_counts: SampleCounts::SAMPLE_1,
999             });
1000         }
1001 
1002         // VUID-VkCopyBufferToImageInfo2-dstImageLayout-01396
1003         if !matches!(
1004             dst_image_layout,
1005             ImageLayout::TransferDstOptimal | ImageLayout::General
1006         ) {
1007             return Err(CopyError::ImageLayoutInvalid {
1008                 resource: CopyErrorResource::Destination,
1009                 image_layout: dst_image_layout,
1010             });
1011         }
1012 
1013         let extent_alignment = match queue_family_properties.min_image_transfer_granularity {
1014             [0, 0, 0] => None,
1015             min_image_transfer_granularity => {
1016                 let granularity = move |block_extent: [u32; 3], is_multi_plane: bool| {
1017                     if is_multi_plane {
1018                         // Assume planes always have 1x1 blocks
1019                         min_image_transfer_granularity
1020                     } else {
1021                         // "The value returned in minImageTransferGranularity has a unit of
1022                         // compressed texel blocks for images having a block-compressed format, and
1023                         // a unit of texels otherwise."
1024                         [
1025                             min_image_transfer_granularity[0] * block_extent[0],
1026                             min_image_transfer_granularity[1] * block_extent[1],
1027                             min_image_transfer_granularity[2] * block_extent[2],
1028                         ]
1029                     }
1030                 };
1031 
1032                 Some(granularity(
1033                     dst_image.format().block_extent(),
1034                     image_aspects.intersects(ImageAspects::PLANE_0),
1035                 ))
1036             }
1037         };
1038 
1039         if image_aspects.intersects(ImageAspects::PLANE_0) {
1040             // VUID-VkCopyBufferToImageInfo2-aspectMask-01560
1041             image_aspects -= ImageAspects::COLOR;
1042         }
1043 
1044         for (region_index, region) in regions.iter().enumerate() {
1045             let &BufferImageCopy {
1046                 buffer_offset,
1047                 buffer_row_length,
1048                 buffer_image_height,
1049                 ref image_subresource,
1050                 image_offset,
1051                 image_extent,
1052                 _ne: _,
1053             } = region;
1054 
1055             // VUID-VkCopyBufferToImageInfo2-imageSubresource-01701
1056             if image_subresource.mip_level >= dst_image.mip_levels() {
1057                 return Err(CopyError::MipLevelsOutOfRange {
1058                     resource: CopyErrorResource::Destination,
1059                     region_index,
1060                     mip_levels_range_end: image_subresource.mip_level + 1,
1061                     image_mip_levels: dst_image.mip_levels(),
1062                 });
1063             }
1064 
1065             // VUID-VkImageSubresourceLayers-layerCount-01700
1066             // VUID-VkCopyBufferToImageInfo2-baseArrayLayer-00213
1067             assert!(!image_subresource.array_layers.is_empty());
1068 
1069             // VUID-VkCopyBufferToImageInfo2-imageSubresource-01702
1070             // VUID-VkCopyBufferToImageInfo2-baseArrayLayer-00213
1071             if image_subresource.array_layers.end > dst_image.dimensions().array_layers() {
1072                 return Err(CopyError::ArrayLayersOutOfRange {
1073                     resource: CopyErrorResource::Destination,
1074                     region_index,
1075                     array_layers_range_end: image_subresource.array_layers.end,
1076                     image_array_layers: dst_image.dimensions().array_layers(),
1077                 });
1078             }
1079 
1080             // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
1081             assert!(!image_subresource.aspects.is_empty());
1082 
1083             // VUID-VkCopyBufferToImageInfo2-aspectMask-00211
1084             if !image_aspects.contains(image_subresource.aspects) {
1085                 return Err(CopyError::AspectsNotAllowed {
1086                     resource: CopyErrorResource::Destination,
1087                     region_index,
1088                     aspects: image_subresource.aspects,
1089                     allowed_aspects: image_aspects,
1090                 });
1091             }
1092 
1093             // VUID-VkBufferImageCopy2-aspectMask-00212
1094             // VUID-VkCopyBufferToImageInfo2-aspectMask-01560
1095             if image_subresource.aspects.count() != 1 {
1096                 return Err(CopyError::MultipleAspectsNotAllowed {
1097                     resource: CopyErrorResource::Destination,
1098                     region_index,
1099                     aspects: image_subresource.aspects,
1100                 });
1101             }
1102 
1103             let (image_subresource_format, image_subresource_extent) =
1104                 if image_aspects.intersects(ImageAspects::PLANE_0) {
1105                     if image_subresource.aspects.intersects(ImageAspects::PLANE_0) {
1106                         (
1107                             dst_image.format().planes()[0],
1108                             dst_image.dimensions().width_height_depth(),
1109                         )
1110                     } else if image_subresource.aspects.intersects(ImageAspects::PLANE_1) {
1111                         (
1112                             dst_image.format().planes()[1],
1113                             dst_image
1114                                 .format()
1115                                 .ycbcr_chroma_sampling()
1116                                 .unwrap()
1117                                 .subsampled_extent(dst_image.dimensions().width_height_depth()),
1118                         )
1119                     } else {
1120                         (
1121                             dst_image.format().planes()[2],
1122                             dst_image
1123                                 .format()
1124                                 .ycbcr_chroma_sampling()
1125                                 .unwrap()
1126                                 .subsampled_extent(dst_image.dimensions().width_height_depth()),
1127                         )
1128                     }
1129                 } else {
1130                     (
1131                         dst_image.format(),
1132                         dst_image
1133                             .dimensions()
1134                             .mip_level_dimensions(image_subresource.mip_level)
1135                             .unwrap()
1136                             .width_height_depth(),
1137                     )
1138                 };
1139 
1140             if let Some(extent_alignment) = extent_alignment {
1141                 for i in 0..3 {
1142                     // VUID-VkBufferImageCopy2-imageExtent-06659
1143                     // VUID-VkBufferImageCopy2-imageExtent-06660
1144                     // VUID-VkBufferImageCopy2-imageExtent-06661
1145                     assert!(image_extent[i] != 0);
1146 
1147                     // VUID-VkCopyBufferToImageInfo2-pRegions-06223
1148                     // VUID-VkCopyBufferToImageInfo2-pRegions-06224
1149                     // VUID-VkCopyBufferToImageInfo2-imageOffset-00200
1150                     if image_offset[i] + image_extent[i] > image_subresource_extent[i] {
1151                         return Err(CopyError::RegionOutOfImageBounds {
1152                             resource: CopyErrorResource::Destination,
1153                             region_index,
1154                             offset_range_end: [
1155                                 image_offset[0] + image_extent[0],
1156                                 image_offset[1] + image_extent[1],
1157                                 image_offset[2] + image_extent[2],
1158                             ],
1159                             subresource_extent: image_subresource_extent,
1160                         });
1161                     }
1162 
1163                     // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
1164                     // VUID-VkCopyBufferToImageInfo2-imageOffset-00205
1165                     if image_offset[i] % extent_alignment[i] != 0 {
1166                         return Err(CopyError::OffsetNotAlignedForImage {
1167                             resource: CopyErrorResource::Destination,
1168                             region_index,
1169                             offset: image_offset,
1170                             required_alignment: extent_alignment,
1171                         });
1172                     }
1173 
1174                     // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
1175                     // VUID-VkCopyBufferToImageInfo2-imageExtent-00207
1176                     // VUID-VkCopyBufferToImageInfo2-imageExtent-00208
1177                     // VUID-VkCopyBufferToImageInfo2-imageExtent-00209
1178                     if image_offset[i] + image_extent[i] != image_subresource_extent[i]
1179                         && image_extent[i] % extent_alignment[i] != 0
1180                     {
1181                         return Err(CopyError::ExtentNotAlignedForImage {
1182                             resource: CopyErrorResource::Destination,
1183                             region_index,
1184                             extent: image_extent,
1185                             required_alignment: extent_alignment,
1186                         });
1187                     }
1188                 }
1189             } else {
1190                 // If granularity is `None`, then we can only copy whole subresources.
1191 
1192                 // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
1193                 if image_offset != [0, 0, 0] {
1194                     return Err(CopyError::OffsetNotAlignedForImage {
1195                         resource: CopyErrorResource::Destination,
1196                         region_index,
1197                         offset: image_offset,
1198                         required_alignment: image_subresource_extent,
1199                     });
1200                 }
1201 
1202                 // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
1203                 if image_extent != image_subresource_extent {
1204                     return Err(CopyError::ExtentNotAlignedForImage {
1205                         resource: CopyErrorResource::Destination,
1206                         region_index,
1207                         extent: image_extent,
1208                         required_alignment: image_subresource_extent,
1209                     });
1210                 }
1211             }
1212 
1213             // VUID-VkBufferImageCopy2-bufferRowLength-00195
1214             if !(buffer_row_length == 0 || buffer_row_length >= image_extent[0]) {
1215                 return Err(CopyError::BufferRowLengthTooSmall {
1216                     resource: CopyErrorResource::Source,
1217                     region_index,
1218                     row_length: buffer_row_length,
1219                     min: image_extent[0],
1220                 });
1221             }
1222 
1223             // VUID-VkBufferImageCopy2-bufferImageHeight-00196
1224             if !(buffer_image_height == 0 || buffer_image_height >= image_extent[1]) {
1225                 return Err(CopyError::BufferImageHeightTooSmall {
1226                     resource: CopyErrorResource::Source,
1227                     region_index,
1228                     image_height: buffer_image_height,
1229                     min: image_extent[1],
1230                 });
1231             }
1232 
1233             let image_subresource_block_extent = image_subresource_format.block_extent();
1234 
1235             // VUID-VkCopyBufferToImageInfo2-bufferRowLength-00203
1236             if buffer_row_length % image_subresource_block_extent[0] != 0 {
1237                 return Err(CopyError::BufferRowLengthNotAligned {
1238                     resource: CopyErrorResource::Source,
1239                     region_index,
1240                     row_length: buffer_row_length,
1241                     required_alignment: image_subresource_block_extent[0],
1242                 });
1243             }
1244 
1245             // VUID-VkCopyBufferToImageInfo2-bufferImageHeight-00204
1246             if buffer_image_height % image_subresource_block_extent[1] != 0 {
1247                 return Err(CopyError::BufferImageHeightNotAligned {
1248                     resource: CopyErrorResource::Source,
1249                     region_index,
1250                     image_height: buffer_image_height,
1251                     required_alignment: image_subresource_block_extent[1],
1252                 });
1253             }
1254 
1255             // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBufferImageCopy.html#_description
1256             let image_subresource_block_size =
1257                 if image_subresource.aspects.intersects(ImageAspects::STENCIL) {
1258                     1
1259                 } else if image_subresource.aspects.intersects(ImageAspects::DEPTH) {
1260                     match image_subresource_format {
1261                         Format::D16_UNORM | Format::D16_UNORM_S8_UINT => 2,
1262                         Format::D32_SFLOAT
1263                         | Format::D32_SFLOAT_S8_UINT
1264                         | Format::X8_D24_UNORM_PACK32
1265                         | Format::D24_UNORM_S8_UINT => 4,
1266                         _ => unreachable!(),
1267                     }
1268                 } else {
1269                     image_subresource_format.block_size().unwrap()
1270                 };
1271 
1272             // VUID-VkCopyBufferToImageInfo2-pRegions-04725
1273             // VUID-VkCopyBufferToImageInfo2-pRegions-04726
1274             if (buffer_row_length / image_subresource_block_extent[0]) as DeviceSize
1275                 * image_subresource_block_size
1276                 > 0x7FFFFFFF
1277             {
1278                 return Err(CopyError::BufferRowLengthTooLarge {
1279                     resource: CopyErrorResource::Source,
1280                     region_index,
1281                     buffer_row_length,
1282                 });
1283             }
1284 
1285             let buffer_offset_alignment =
1286                 if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
1287                     4
1288                 } else {
1289                     let mut buffer_offset_alignment = image_subresource_block_size;
1290 
1291                     // VUID-VkCopyBufferToImageInfo2-commandBuffer-04052
1292                     // Make the alignment a multiple of 4.
1293                     if !queue_family_properties
1294                         .queue_flags
1295                         .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
1296                     {
1297                         if buffer_offset_alignment % 2 != 0 {
1298                             buffer_offset_alignment *= 2;
1299                         }
1300 
1301                         if buffer_offset_alignment % 4 != 0 {
1302                             buffer_offset_alignment *= 2;
1303                         }
1304                     }
1305 
1306                     buffer_offset_alignment
1307                 };
1308 
1309             // VUID-VkCopyBufferToImageInfo2-bufferOffset-00206
1310             // VUID-VkCopyBufferToImageInfo2-bufferOffset-01558
1311             // VUID-VkCopyBufferToImageInfo2-bufferOffset-01559
1312             // VUID-VkCopyBufferToImageInfo2-srcImage-04053
1313             if (src_buffer.offset() + buffer_offset) % buffer_offset_alignment != 0 {
1314                 return Err(CopyError::OffsetNotAlignedForBuffer {
1315                     resource: CopyErrorResource::Source,
1316                     region_index,
1317                     offset: src_buffer.offset() + buffer_offset,
1318                     required_alignment: buffer_offset_alignment,
1319                 });
1320             }
1321 
1322             let buffer_copy_size = region.buffer_copy_size(image_subresource_format);
1323 
1324             // VUID-VkCopyBufferToImageInfo2-pRegions-00171
1325             if buffer_offset + buffer_copy_size > src_buffer.size() {
1326                 return Err(CopyError::RegionOutOfBufferBounds {
1327                     resource: CopyErrorResource::Source,
1328                     region_index,
1329                     offset_range_end: buffer_offset + buffer_copy_size,
1330                     buffer_size: src_buffer.size(),
1331                 });
1332             }
1333         }
1334 
1335         // VUID-VkCopyBufferToImageInfo2-pRegions-00173
1336         // Can't occur as long as memory aliasing isn't allowed.
1337 
1338         Ok(())
1339     }
1340 
1341     /// Copies from an image to a buffer.
copy_image_to_buffer( &mut self, copy_image_to_buffer_info: CopyImageToBufferInfo, ) -> Result<&mut Self, CopyError>1342     pub fn copy_image_to_buffer(
1343         &mut self,
1344         copy_image_to_buffer_info: CopyImageToBufferInfo,
1345     ) -> Result<&mut Self, CopyError> {
1346         self.validate_copy_image_to_buffer(&copy_image_to_buffer_info)?;
1347 
1348         unsafe {
1349             self.inner.copy_image_to_buffer(copy_image_to_buffer_info)?;
1350         }
1351 
1352         Ok(self)
1353     }
1354 
validate_copy_image_to_buffer( &self, copy_image_to_buffer_info: &CopyImageToBufferInfo, ) -> Result<(), CopyError>1355     fn validate_copy_image_to_buffer(
1356         &self,
1357         copy_image_to_buffer_info: &CopyImageToBufferInfo,
1358     ) -> Result<(), CopyError> {
1359         let device = self.device();
1360 
1361         // VUID-vkCmdCopyImageToBuffer2-renderpass
1362         if self.render_pass_state.is_some() {
1363             return Err(CopyError::ForbiddenInsideRenderPass);
1364         }
1365 
1366         let queue_family_properties = self.queue_family_properties();
1367 
1368         // VUID-vkCmdCopyImageToBuffer2-commandBuffer-cmdpool
1369         if !queue_family_properties
1370             .queue_flags
1371             .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
1372         {
1373             return Err(CopyError::NotSupportedByQueueFamily);
1374         }
1375 
1376         let &CopyImageToBufferInfo {
1377             ref src_image,
1378             src_image_layout,
1379             ref dst_buffer,
1380             ref regions,
1381             _ne: _,
1382         } = copy_image_to_buffer_info;
1383 
1384         // VUID-VkCopyImageToBufferInfo2-srcImageLayout-parameter
1385         src_image_layout.validate_device(device)?;
1386 
1387         // VUID-VkCopyImageToBufferInfo2-commonparent
1388         assert_eq!(device, dst_buffer.device());
1389         assert_eq!(device, src_image.device());
1390 
1391         let mut image_aspects = src_image.format().aspects();
1392 
1393         // VUID-VkCopyImageToBufferInfo2-srcImage-00186
1394         if !src_image.usage().intersects(ImageUsage::TRANSFER_SRC) {
1395             return Err(CopyError::MissingUsage {
1396                 resource: CopyErrorResource::Source,
1397                 usage: "transfer_src",
1398             });
1399         }
1400 
1401         // VUID-VkCopyImageToBufferInfo2-dstBuffer-00191
1402         if !dst_buffer
1403             .buffer()
1404             .usage()
1405             .intersects(BufferUsage::TRANSFER_DST)
1406         {
1407             return Err(CopyError::MissingUsage {
1408                 resource: CopyErrorResource::Destination,
1409                 usage: "transfer_dst",
1410             });
1411         }
1412 
1413         if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
1414             // VUID-VkCopyImageToBufferInfo2-srcImage-01998
1415             if !src_image
1416                 .format_features()
1417                 .intersects(FormatFeatures::TRANSFER_SRC)
1418             {
1419                 return Err(CopyError::MissingFormatFeature {
1420                     resource: CopyErrorResource::Source,
1421                     format_feature: "transfer_src",
1422                 });
1423             }
1424         }
1425 
1426         // VUID-VkCopyImageToBufferInfo2-srcImage-00188
1427         if src_image.samples() != SampleCount::Sample1 {
1428             return Err(CopyError::SampleCountInvalid {
1429                 resource: CopyErrorResource::Source,
1430                 sample_count: src_image.samples(),
1431                 allowed_sample_counts: SampleCounts::SAMPLE_1,
1432             });
1433         }
1434 
1435         // VUID-VkCopyImageToBufferInfo2-srcImageLayout-01397
1436         if !matches!(
1437             src_image_layout,
1438             ImageLayout::TransferSrcOptimal | ImageLayout::General
1439         ) {
1440             return Err(CopyError::ImageLayoutInvalid {
1441                 resource: CopyErrorResource::Source,
1442                 image_layout: src_image_layout,
1443             });
1444         }
1445 
1446         let extent_alignment = match queue_family_properties.min_image_transfer_granularity {
1447             [0, 0, 0] => None,
1448             min_image_transfer_granularity => {
1449                 let granularity = move |block_extent: [u32; 3], is_multi_plane: bool| {
1450                     if is_multi_plane {
1451                         // Assume planes always have 1x1 blocks
1452                         min_image_transfer_granularity
1453                     } else {
1454                         // "The value returned in minImageTransferGranularity has a unit of
1455                         // compressed texel blocks for images having a block-compressed format, and
1456                         // a unit of texels otherwise."
1457                         [
1458                             min_image_transfer_granularity[0] * block_extent[0],
1459                             min_image_transfer_granularity[1] * block_extent[1],
1460                             min_image_transfer_granularity[2] * block_extent[2],
1461                         ]
1462                     }
1463                 };
1464 
1465                 Some(granularity(
1466                     src_image.format().block_extent(),
1467                     image_aspects.intersects(ImageAspects::PLANE_0),
1468                 ))
1469             }
1470         };
1471 
1472         if image_aspects.intersects(ImageAspects::PLANE_0) {
1473             // VUID-VkCopyImageToBufferInfo2-aspectMask-01560
1474             image_aspects -= ImageAspects::COLOR;
1475         }
1476 
1477         for (region_index, region) in regions.iter().enumerate() {
1478             let &BufferImageCopy {
1479                 buffer_offset,
1480                 buffer_row_length,
1481                 buffer_image_height,
1482                 ref image_subresource,
1483                 image_offset,
1484                 image_extent,
1485                 _ne: _,
1486             } = region;
1487 
1488             // VUID-VkCopyImageToBufferInfo2-imageSubresource-01703
1489             if image_subresource.mip_level >= src_image.mip_levels() {
1490                 return Err(CopyError::MipLevelsOutOfRange {
1491                     resource: CopyErrorResource::Source,
1492                     region_index,
1493                     mip_levels_range_end: image_subresource.mip_level + 1,
1494                     image_mip_levels: src_image.mip_levels(),
1495                 });
1496             }
1497 
1498             // VUID-VkImageSubresourceLayers-layerCount-01700
1499             assert!(!image_subresource.array_layers.is_empty());
1500 
1501             // VUID-VkCopyImageToBufferInfo2-imageSubresource-01704
1502             // VUID-VkCopyImageToBufferInfo2-baseArrayLayer-00213
1503             if image_subresource.array_layers.end > src_image.dimensions().array_layers() {
1504                 return Err(CopyError::ArrayLayersOutOfRange {
1505                     resource: CopyErrorResource::Source,
1506                     region_index,
1507                     array_layers_range_end: image_subresource.array_layers.end,
1508                     image_array_layers: src_image.dimensions().array_layers(),
1509                 });
1510             }
1511 
1512             // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
1513             assert!(!image_subresource.aspects.is_empty());
1514 
1515             // VUID-VkCopyImageToBufferInfo2-aspectMask-00211
1516             if !image_aspects.contains(image_subresource.aspects) {
1517                 return Err(CopyError::AspectsNotAllowed {
1518                     resource: CopyErrorResource::Source,
1519                     region_index,
1520                     aspects: image_subresource.aspects,
1521                     allowed_aspects: image_aspects,
1522                 });
1523             }
1524 
1525             // VUID-VkBufferImageCopy2-aspectMask-00212
1526             if image_subresource.aspects.count() != 1 {
1527                 return Err(CopyError::MultipleAspectsNotAllowed {
1528                     resource: CopyErrorResource::Source,
1529                     region_index,
1530                     aspects: image_subresource.aspects,
1531                 });
1532             }
1533 
1534             let (image_subresource_format, image_subresource_extent) =
1535                 if image_aspects.intersects(ImageAspects::PLANE_0) {
1536                     if image_subresource.aspects.intersects(ImageAspects::PLANE_0) {
1537                         (
1538                             src_image.format().planes()[0],
1539                             src_image.dimensions().width_height_depth(),
1540                         )
1541                     } else if image_subresource.aspects.intersects(ImageAspects::PLANE_1) {
1542                         (
1543                             src_image.format().planes()[1],
1544                             src_image
1545                                 .format()
1546                                 .ycbcr_chroma_sampling()
1547                                 .unwrap()
1548                                 .subsampled_extent(src_image.dimensions().width_height_depth()),
1549                         )
1550                     } else {
1551                         (
1552                             src_image.format().planes()[2],
1553                             src_image
1554                                 .format()
1555                                 .ycbcr_chroma_sampling()
1556                                 .unwrap()
1557                                 .subsampled_extent(src_image.dimensions().width_height_depth()),
1558                         )
1559                     }
1560                 } else {
1561                     (
1562                         src_image.format(),
1563                         src_image
1564                             .dimensions()
1565                             .mip_level_dimensions(image_subresource.mip_level)
1566                             .unwrap()
1567                             .width_height_depth(),
1568                     )
1569                 };
1570 
1571             if let Some(extent_alignment) = extent_alignment {
1572                 for i in 0..3 {
1573                     // VUID-VkBufferImageCopy2-imageExtent-06659
1574                     // VUID-VkBufferImageCopy2-imageExtent-06660
1575                     // VUID-VkBufferImageCopy2-imageExtent-06661
1576                     assert!(image_extent[i] != 0);
1577 
1578                     // VUID-VkCopyImageToBufferInfo2-imageOffset-00197
1579                     // VUID-VkCopyImageToBufferInfo2-imageOffset-00198
1580                     // VUID-VkCopyImageToBufferInfo2-imageOffset-00200
1581                     if image_offset[i] + image_extent[i] > image_subresource_extent[i] {
1582                         return Err(CopyError::RegionOutOfImageBounds {
1583                             resource: CopyErrorResource::Source,
1584                             region_index,
1585                             offset_range_end: [
1586                                 image_offset[0] + image_extent[0],
1587                                 image_offset[1] + image_extent[1],
1588                                 image_offset[2] + image_extent[2],
1589                             ],
1590                             subresource_extent: image_subresource_extent,
1591                         });
1592                     }
1593 
1594                     // VUID-VkCopyImageToBufferInfo2-imageOffset-01794
1595                     // VUID-VkCopyImageToBufferInfo2-imageOffset-00205
1596                     if image_offset[i] % extent_alignment[i] != 0 {
1597                         return Err(CopyError::OffsetNotAlignedForImage {
1598                             resource: CopyErrorResource::Source,
1599                             region_index,
1600                             offset: image_offset,
1601                             required_alignment: extent_alignment,
1602                         });
1603                     }
1604 
1605                     // VUID-VkCopyImageToBufferInfo2-imageOffset-01794
1606                     // VUID-VkCopyImageToBufferInfo2-imageExtent-00207
1607                     // VUID-VkCopyImageToBufferInfo2-imageExtent-00208
1608                     // VUID-VkCopyImageToBufferInfo2-imageExtent-00209
1609                     if image_offset[i] + image_extent[i] != image_subresource_extent[i]
1610                         && image_extent[i] % extent_alignment[i] != 0
1611                     {
1612                         return Err(CopyError::ExtentNotAlignedForImage {
1613                             resource: CopyErrorResource::Source,
1614                             region_index,
1615                             extent: image_extent,
1616                             required_alignment: extent_alignment,
1617                         });
1618                     }
1619                 }
1620             } else {
1621                 // If granularity is `None`, then we can only copy whole subresources.
1622 
1623                 // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
1624                 if image_offset != [0, 0, 0] {
1625                     return Err(CopyError::OffsetNotAlignedForImage {
1626                         resource: CopyErrorResource::Source,
1627                         region_index,
1628                         offset: image_offset,
1629                         required_alignment: image_subresource_extent,
1630                     });
1631                 }
1632 
1633                 // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
1634                 if image_extent != image_subresource_extent {
1635                     return Err(CopyError::ExtentNotAlignedForImage {
1636                         resource: CopyErrorResource::Source,
1637                         region_index,
1638                         extent: image_extent,
1639                         required_alignment: image_subresource_extent,
1640                     });
1641                 }
1642             }
1643 
1644             // VUID-VkBufferImageCopy2-bufferRowLength-00195
1645             if !(buffer_row_length == 0 || buffer_row_length >= image_extent[0]) {
1646                 return Err(CopyError::BufferRowLengthTooSmall {
1647                     resource: CopyErrorResource::Destination,
1648                     region_index,
1649                     row_length: buffer_row_length,
1650                     min: image_extent[0],
1651                 });
1652             }
1653 
1654             // VUID-VkBufferImageCopy2-bufferImageHeight-00196
1655             if !(buffer_image_height == 0 || buffer_image_height >= image_extent[1]) {
1656                 return Err(CopyError::BufferImageHeightTooSmall {
1657                     resource: CopyErrorResource::Destination,
1658                     region_index,
1659                     image_height: buffer_image_height,
1660                     min: image_extent[1],
1661                 });
1662             }
1663 
1664             let image_subresource_block_extent = image_subresource_format.block_extent();
1665 
1666             // VUID-VkCopyImageToBufferInfo2-bufferRowLength-00203
1667             if buffer_row_length % image_subresource_block_extent[0] != 0 {
1668                 return Err(CopyError::BufferRowLengthNotAligned {
1669                     resource: CopyErrorResource::Destination,
1670                     region_index,
1671                     row_length: buffer_row_length,
1672                     required_alignment: image_subresource_block_extent[0],
1673                 });
1674             }
1675 
1676             // VUID-VkCopyImageToBufferInfo2-bufferImageHeight-00204
1677             if buffer_image_height % image_subresource_block_extent[1] != 0 {
1678                 return Err(CopyError::BufferImageHeightNotAligned {
1679                     resource: CopyErrorResource::Destination,
1680                     region_index,
1681                     image_height: buffer_image_height,
1682                     required_alignment: image_subresource_block_extent[1],
1683                 });
1684             }
1685 
1686             // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBufferImageCopy.html#_description
1687             let image_subresource_block_size =
1688                 if image_subresource.aspects.intersects(ImageAspects::STENCIL) {
1689                     1
1690                 } else if image_subresource.aspects.intersects(ImageAspects::DEPTH) {
1691                     match image_subresource_format {
1692                         Format::D16_UNORM | Format::D16_UNORM_S8_UINT => 2,
1693                         Format::D32_SFLOAT
1694                         | Format::D32_SFLOAT_S8_UINT
1695                         | Format::X8_D24_UNORM_PACK32
1696                         | Format::D24_UNORM_S8_UINT => 4,
1697                         _ => unreachable!(),
1698                     }
1699                 } else {
1700                     image_subresource_format.block_size().unwrap()
1701                 };
1702 
1703             // VUID-VkCopyImageToBufferInfo2-pRegions-04725
1704             // VUID-VkCopyImageToBufferInfo2-pRegions-04726
1705             if (buffer_row_length / image_subresource_block_extent[0]) as DeviceSize
1706                 * image_subresource_block_size
1707                 > 0x7FFFFFFF
1708             {
1709                 return Err(CopyError::BufferRowLengthTooLarge {
1710                     resource: CopyErrorResource::Destination,
1711                     region_index,
1712                     buffer_row_length,
1713                 });
1714             }
1715 
1716             let buffer_offset_alignment =
1717                 if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
1718                     4
1719                 } else {
1720                     let mut buffer_offset_alignment = image_subresource_block_size;
1721 
1722                     // VUID-VkCopyImageToBufferInfo2-commandBuffer-04052
1723                     // Make the alignment a multiple of 4.
1724                     if !queue_family_properties
1725                         .queue_flags
1726                         .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
1727                     {
1728                         if buffer_offset_alignment % 2 != 0 {
1729                             buffer_offset_alignment *= 2;
1730                         }
1731 
1732                         if buffer_offset_alignment % 4 != 0 {
1733                             buffer_offset_alignment *= 2;
1734                         }
1735                     }
1736 
1737                     buffer_offset_alignment
1738                 };
1739 
1740             // VUID-VkCopyImageToBufferInfo2-bufferOffset-01558
1741             // VUID-VkCopyImageToBufferInfo2-bufferOffset-01559
1742             // VUID-VkCopyImageToBufferInfo2-bufferOffset-00206
1743             // VUID-VkCopyImageToBufferInfo2-srcImage-04053
1744             if (dst_buffer.offset() + buffer_offset) % buffer_offset_alignment != 0 {
1745                 return Err(CopyError::OffsetNotAlignedForBuffer {
1746                     resource: CopyErrorResource::Destination,
1747                     region_index,
1748                     offset: dst_buffer.offset() + buffer_offset,
1749                     required_alignment: buffer_offset_alignment,
1750                 });
1751             }
1752 
1753             let buffer_copy_size = region.buffer_copy_size(image_subresource_format);
1754 
1755             // VUID-VkCopyImageToBufferInfo2-pRegions-00183
1756             if buffer_offset + buffer_copy_size > dst_buffer.size() {
1757                 return Err(CopyError::RegionOutOfBufferBounds {
1758                     resource: CopyErrorResource::Destination,
1759                     region_index,
1760                     offset_range_end: buffer_offset + buffer_copy_size,
1761                     buffer_size: dst_buffer.size(),
1762                 });
1763             }
1764         }
1765 
1766         // VUID-VkCopyImageToBufferInfo2-pRegions-00184
1767         // Can't occur as long as memory aliasing isn't allowed.
1768 
1769         Ok(())
1770     }
1771 
1772     /// Blits an image to another.
1773     ///
1774     /// A *blit* is similar to an image copy operation, except that the portion of the image that
1775     /// is transferred can be resized. You choose an area of the source and an area of the
1776     /// destination, and the implementation will resize the area of the source so that it matches
1777     /// the size of the area of the destination before writing it.
1778     ///
1779     /// Blit operations have several restrictions:
1780     ///
1781     /// - Blit operations are only allowed on queue families that support graphics operations.
1782     /// - The format of the source and destination images must support blit operations, which
1783     ///   depends on the Vulkan implementation. Vulkan guarantees that some specific formats must
1784     ///   always be supported. See tables 52 to 61 of the specifications.
1785     /// - Only single-sampled images are allowed.
1786     /// - You can only blit between two images whose formats belong to the same type. The types
1787     ///   are: floating-point, signed integers, unsigned integers, depth-stencil.
1788     /// - If you blit between depth, stencil or depth-stencil images, the format of both images
1789     ///   must match exactly.
1790     /// - If you blit between depth, stencil or depth-stencil images, only the `Nearest` filter is
1791     ///   allowed.
1792     /// - For two-dimensional images, the Z coordinate must be 0 for the top-left offset and 1 for
1793     ///   the bottom-right offset. Same for the Y coordinate for one-dimensional images.
1794     /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
1795     ///
1796     /// If `layer_count` is greater than 1, the blit will happen between each individual layer as
1797     /// if they were separate images.
1798     ///
1799     /// # Panics
1800     ///
1801     /// - Panics if the source or the destination was not created with `device`.
blit_image(&mut self, blit_image_info: BlitImageInfo) -> Result<&mut Self, CopyError>1802     pub fn blit_image(&mut self, blit_image_info: BlitImageInfo) -> Result<&mut Self, CopyError> {
1803         self.validate_blit_image(&blit_image_info)?;
1804 
1805         unsafe {
1806             self.inner.blit_image(blit_image_info)?;
1807         }
1808 
1809         Ok(self)
1810     }
1811 
validate_blit_image(&self, blit_image_info: &BlitImageInfo) -> Result<(), CopyError>1812     fn validate_blit_image(&self, blit_image_info: &BlitImageInfo) -> Result<(), CopyError> {
1813         let device = self.device();
1814 
1815         // VUID-vkCmdBlitImage2-renderpass
1816         if self.render_pass_state.is_some() {
1817             return Err(CopyError::ForbiddenInsideRenderPass);
1818         }
1819 
1820         let queue_family_properties = self.queue_family_properties();
1821 
1822         // VUID-vkCmdBlitImage2-commandBuffer-cmdpool
1823         if !queue_family_properties
1824             .queue_flags
1825             .intersects(QueueFlags::GRAPHICS)
1826         {
1827             return Err(CopyError::NotSupportedByQueueFamily);
1828         }
1829 
1830         let &BlitImageInfo {
1831             ref src_image,
1832             src_image_layout,
1833             ref dst_image,
1834             dst_image_layout,
1835             ref regions,
1836             filter,
1837             _ne: _,
1838         } = blit_image_info;
1839 
1840         // VUID-VkBlitImageInfo2-srcImageLayout-parameter
1841         src_image_layout.validate_device(device)?;
1842 
1843         // VUID-VkBlitImageInfo2-dstImageLayout-parameter
1844         dst_image_layout.validate_device(device)?;
1845 
1846         // VUID-VkBlitImageInfo2-filter-parameter
1847         filter.validate_device(device)?;
1848 
1849         let src_image_inner = src_image.inner();
1850         let dst_image_inner = dst_image.inner();
1851 
1852         // VUID-VkBlitImageInfo2-commonparent
1853         assert_eq!(device, src_image.device());
1854         assert_eq!(device, dst_image.device());
1855 
1856         let src_image_aspects = src_image.format().aspects();
1857         let dst_image_aspects = dst_image.format().aspects();
1858         let src_image_type = src_image.dimensions().image_type();
1859         let dst_image_type = dst_image.dimensions().image_type();
1860 
1861         // VUID-VkBlitImageInfo2-srcImage-00219
1862         if !src_image.usage().intersects(ImageUsage::TRANSFER_SRC) {
1863             return Err(CopyError::MissingUsage {
1864                 resource: CopyErrorResource::Source,
1865                 usage: "transfer_src",
1866             });
1867         }
1868 
1869         // VUID-VkBlitImageInfo2-dstImage-00224
1870         if !dst_image.usage().intersects(ImageUsage::TRANSFER_DST) {
1871             return Err(CopyError::MissingUsage {
1872                 resource: CopyErrorResource::Destination,
1873                 usage: "transfer_dst",
1874             });
1875         }
1876 
1877         // VUID-VkBlitImageInfo2-srcImage-01999
1878         if !src_image
1879             .format_features()
1880             .intersects(FormatFeatures::BLIT_SRC)
1881         {
1882             return Err(CopyError::MissingFormatFeature {
1883                 resource: CopyErrorResource::Source,
1884                 format_feature: "blit_src",
1885             });
1886         }
1887 
1888         // VUID-VkBlitImageInfo2-dstImage-02000
1889         if !dst_image
1890             .format_features()
1891             .intersects(FormatFeatures::BLIT_DST)
1892         {
1893             return Err(CopyError::MissingFormatFeature {
1894                 resource: CopyErrorResource::Destination,
1895                 format_feature: "blit_dst",
1896             });
1897         }
1898 
1899         // VUID-VkBlitImageInfo2-srcImage-06421
1900         if src_image.format().ycbcr_chroma_sampling().is_some() {
1901             return Err(CopyError::FormatNotSupported {
1902                 resource: CopyErrorResource::Source,
1903                 format: src_image.format(),
1904             });
1905         }
1906 
1907         // VUID-VkBlitImageInfo2-dstImage-06422
1908         if dst_image.format().ycbcr_chroma_sampling().is_some() {
1909             return Err(CopyError::FormatNotSupported {
1910                 resource: CopyErrorResource::Destination,
1911                 format: src_image.format(),
1912             });
1913         }
1914 
1915         if !(src_image_aspects.intersects(ImageAspects::COLOR)
1916             && dst_image_aspects.intersects(ImageAspects::COLOR))
1917         {
1918             // VUID-VkBlitImageInfo2-srcImage-00231
1919             if src_image.format() != dst_image.format() {
1920                 return Err(CopyError::FormatsMismatch {
1921                     src_format: src_image.format(),
1922                     dst_format: dst_image.format(),
1923                 });
1924             }
1925         } else {
1926             // VUID-VkBlitImageInfo2-srcImage-00229
1927             // VUID-VkBlitImageInfo2-srcImage-00230
1928             if !matches!(
1929                 (
1930                     src_image.format().type_color().unwrap(),
1931                     dst_image.format().type_color().unwrap()
1932                 ),
1933                 (
1934                     NumericType::SFLOAT
1935                         | NumericType::UFLOAT
1936                         | NumericType::SNORM
1937                         | NumericType::UNORM
1938                         | NumericType::SSCALED
1939                         | NumericType::USCALED
1940                         | NumericType::SRGB,
1941                     NumericType::SFLOAT
1942                         | NumericType::UFLOAT
1943                         | NumericType::SNORM
1944                         | NumericType::UNORM
1945                         | NumericType::SSCALED
1946                         | NumericType::USCALED
1947                         | NumericType::SRGB,
1948                 ) | (NumericType::SINT, NumericType::SINT)
1949                     | (NumericType::UINT, NumericType::UINT)
1950             ) {
1951                 return Err(CopyError::FormatsNotCompatible {
1952                     src_format: src_image.format(),
1953                     dst_format: dst_image.format(),
1954                 });
1955             }
1956         }
1957 
1958         // VUID-VkBlitImageInfo2-srcImage-00233
1959         if src_image.samples() != SampleCount::Sample1 {
1960             return Err(CopyError::SampleCountInvalid {
1961                 resource: CopyErrorResource::Destination,
1962                 sample_count: dst_image.samples(),
1963                 allowed_sample_counts: SampleCounts::SAMPLE_1,
1964             });
1965         }
1966 
1967         // VUID-VkBlitImageInfo2-dstImage-00234
1968         if dst_image.samples() != SampleCount::Sample1 {
1969             return Err(CopyError::SampleCountInvalid {
1970                 resource: CopyErrorResource::Destination,
1971                 sample_count: dst_image.samples(),
1972                 allowed_sample_counts: SampleCounts::SAMPLE_1,
1973             });
1974         }
1975 
1976         // VUID-VkBlitImageInfo2-srcImageLayout-01398
1977         if !matches!(
1978             src_image_layout,
1979             ImageLayout::TransferSrcOptimal | ImageLayout::General
1980         ) {
1981             return Err(CopyError::ImageLayoutInvalid {
1982                 resource: CopyErrorResource::Source,
1983                 image_layout: src_image_layout,
1984             });
1985         }
1986 
1987         // VUID-VkBlitImageInfo2-dstImageLayout-01399
1988         if !matches!(
1989             dst_image_layout,
1990             ImageLayout::TransferDstOptimal | ImageLayout::General
1991         ) {
1992             return Err(CopyError::ImageLayoutInvalid {
1993                 resource: CopyErrorResource::Destination,
1994                 image_layout: dst_image_layout,
1995             });
1996         }
1997 
1998         // VUID-VkBlitImageInfo2-srcImage-00232
1999         if !src_image_aspects.intersects(ImageAspects::COLOR) && filter != Filter::Nearest {
2000             return Err(CopyError::FilterNotSupportedByFormat);
2001         }
2002 
2003         match filter {
2004             Filter::Nearest => (),
2005             Filter::Linear => {
2006                 // VUID-VkBlitImageInfo2-filter-02001
2007                 if !src_image
2008                     .format_features()
2009                     .intersects(FormatFeatures::SAMPLED_IMAGE_FILTER_LINEAR)
2010                 {
2011                     return Err(CopyError::FilterNotSupportedByFormat);
2012                 }
2013             }
2014             Filter::Cubic => {
2015                 // VUID-VkBlitImageInfo2-filter-02002
2016                 if !src_image
2017                     .format_features()
2018                     .intersects(FormatFeatures::SAMPLED_IMAGE_FILTER_CUBIC)
2019                 {
2020                     return Err(CopyError::FilterNotSupportedByFormat);
2021                 }
2022 
2023                 // VUID-VkBlitImageInfo2-filter-00237
2024                 if !matches!(src_image.dimensions(), ImageDimensions::Dim2d { .. }) {
2025                     return Err(CopyError::FilterNotSupportedForImageType);
2026                 }
2027             }
2028         }
2029 
2030         let same_image = src_image_inner.image == dst_image_inner.image;
2031         let mut overlap_subresource_indices = None;
2032         let mut overlap_extent_indices = None;
2033 
2034         for (region_index, region) in regions.iter().enumerate() {
2035             let &ImageBlit {
2036                 ref src_subresource,
2037                 src_offsets,
2038                 ref dst_subresource,
2039                 dst_offsets,
2040                 _ne: _,
2041             } = region;
2042 
2043             let check_subresource = |resource: CopyErrorResource,
2044                                      image: &dyn ImageAccess,
2045                                      image_aspects: ImageAspects,
2046                                      subresource: &ImageSubresourceLayers|
2047              -> Result<_, CopyError> {
2048                 // VUID-VkBlitImageInfo2-srcSubresource-01705
2049                 // VUID-VkBlitImageInfo2-dstSubresource-01706
2050                 if subresource.mip_level >= image.mip_levels() {
2051                     return Err(CopyError::MipLevelsOutOfRange {
2052                         resource,
2053                         region_index,
2054                         mip_levels_range_end: subresource.mip_level + 1,
2055                         image_mip_levels: image.mip_levels(),
2056                     });
2057                 }
2058 
2059                 // VUID-VkImageSubresourceLayers-layerCount-01700
2060                 assert!(!subresource.array_layers.is_empty());
2061 
2062                 // VUID-VkBlitImageInfo2-srcSubresource-01707
2063                 // VUID-VkBlitImageInfo2-dstSubresource-01708
2064                 // VUID-VkBlitImageInfo2-srcImage-00240
2065                 if subresource.array_layers.end > image.dimensions().array_layers() {
2066                     return Err(CopyError::ArrayLayersOutOfRange {
2067                         resource,
2068                         region_index,
2069                         array_layers_range_end: subresource.array_layers.end,
2070                         image_array_layers: image.dimensions().array_layers(),
2071                     });
2072                 }
2073 
2074                 // VUID-VkImageSubresourceLayers-aspectMask-parameter
2075                 subresource.aspects.validate_device(device)?;
2076 
2077                 // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
2078                 assert!(!subresource.aspects.is_empty());
2079 
2080                 // VUID-VkBlitImageInfo2-aspectMask-00241
2081                 // VUID-VkBlitImageInfo2-aspectMask-00242
2082                 if !image_aspects.contains(subresource.aspects) {
2083                     return Err(CopyError::AspectsNotAllowed {
2084                         resource,
2085                         region_index,
2086                         aspects: subresource.aspects,
2087                         allowed_aspects: image_aspects,
2088                     });
2089                 }
2090 
2091                 Ok(image
2092                     .dimensions()
2093                     .mip_level_dimensions(subresource.mip_level)
2094                     .unwrap()
2095                     .width_height_depth())
2096             };
2097 
2098             let src_subresource_extent = check_subresource(
2099                 CopyErrorResource::Source,
2100                 src_image,
2101                 src_image_aspects,
2102                 src_subresource,
2103             )?;
2104             let dst_subresource_extent = check_subresource(
2105                 CopyErrorResource::Destination,
2106                 dst_image,
2107                 dst_image_aspects,
2108                 dst_subresource,
2109             )?;
2110 
2111             // VUID-VkImageBlit2-aspectMask-00238
2112             if src_subresource.aspects != dst_subresource.aspects {
2113                 return Err(CopyError::AspectsMismatch {
2114                     region_index,
2115                     src_aspects: src_subresource.aspects,
2116                     dst_aspects: dst_subresource.aspects,
2117                 });
2118             }
2119 
2120             let src_layer_count =
2121                 src_subresource.array_layers.end - src_subresource.array_layers.start;
2122             let dst_layer_count =
2123                 dst_subresource.array_layers.end - dst_subresource.array_layers.start;
2124 
2125             // VUID-VkImageBlit2-layerCount-00239
2126             // VUID-VkBlitImageInfo2-srcImage-00240
2127             if src_layer_count != dst_layer_count {
2128                 return Err(CopyError::ArrayLayerCountMismatch {
2129                     region_index,
2130                     src_layer_count,
2131                     dst_layer_count,
2132                 });
2133             }
2134 
2135             let check_offset_extent = |resource: CopyErrorResource,
2136                                        image_type: ImageType,
2137                                        subresource_extent: [u32; 3],
2138                                        offsets: [[u32; 3]; 2]|
2139              -> Result<_, CopyError> {
2140                 match image_type {
2141                     ImageType::Dim1d => {
2142                         // VUID-VkBlitImageInfo2-srcImage-00245
2143                         // VUID-VkBlitImageInfo2-dstImage-00250
2144                         if !(offsets[0][1] == 0 && offsets[1][1] == 1) {
2145                             return Err(CopyError::OffsetsInvalidForImageType {
2146                                 resource,
2147                                 region_index,
2148                                 offsets: [offsets[0][1], offsets[1][1]],
2149                             });
2150                         }
2151 
2152                         // VUID-VkBlitImageInfo2-srcImage-00247
2153                         // VUID-VkBlitImageInfo2-dstImage-00252
2154                         if !(offsets[0][2] == 0 && offsets[1][2] == 1) {
2155                             return Err(CopyError::OffsetsInvalidForImageType {
2156                                 resource,
2157                                 region_index,
2158                                 offsets: [offsets[0][2], offsets[1][2]],
2159                             });
2160                         }
2161                     }
2162                     ImageType::Dim2d => {
2163                         // VUID-VkBlitImageInfo2-srcImage-00247
2164                         // VUID-VkBlitImageInfo2-dstImage-00252
2165                         if !(offsets[0][2] == 0 && offsets[1][2] == 1) {
2166                             return Err(CopyError::OffsetsInvalidForImageType {
2167                                 resource,
2168                                 region_index,
2169                                 offsets: [offsets[0][2], offsets[1][2]],
2170                             });
2171                         }
2172                     }
2173                     ImageType::Dim3d => (),
2174                 }
2175 
2176                 let offset_range_end = [
2177                     max(offsets[0][0], offsets[1][0]),
2178                     max(offsets[0][1], offsets[1][1]),
2179                     max(offsets[0][2], offsets[1][2]),
2180                 ];
2181 
2182                 for i in 0..3 {
2183                     // VUID-VkBlitImageInfo2-srcOffset-00243
2184                     // VUID-VkBlitImageInfo2-srcOffset-00244
2185                     // VUID-VkBlitImageInfo2-srcOffset-00246
2186                     // VUID-VkBlitImageInfo2-dstOffset-00248
2187                     // VUID-VkBlitImageInfo2-dstOffset-00249
2188                     // VUID-VkBlitImageInfo2-dstOffset-00251
2189                     if offset_range_end[i] > subresource_extent[i] {
2190                         return Err(CopyError::RegionOutOfImageBounds {
2191                             resource,
2192                             region_index,
2193                             offset_range_end,
2194                             subresource_extent,
2195                         });
2196                     }
2197                 }
2198 
2199                 Ok(())
2200             };
2201 
2202             check_offset_extent(
2203                 CopyErrorResource::Source,
2204                 src_image_type,
2205                 src_subresource_extent,
2206                 src_offsets,
2207             )?;
2208             check_offset_extent(
2209                 CopyErrorResource::Destination,
2210                 dst_image_type,
2211                 dst_subresource_extent,
2212                 dst_offsets,
2213             )?;
2214 
2215             // VUID-VkBlitImageInfo2-pRegions-00217
2216             if same_image {
2217                 let src_region_index = region_index;
2218                 let src_subresource_axes = [
2219                     src_image_inner.first_mipmap_level + src_subresource.mip_level
2220                         ..src_image_inner.first_mipmap_level + src_subresource.mip_level + 1,
2221                     src_image_inner.first_layer + src_subresource.array_layers.start
2222                         ..src_image_inner.first_layer + src_subresource.array_layers.end,
2223                 ];
2224                 let src_extent_axes = [
2225                     min(src_offsets[0][0], src_offsets[1][0])
2226                         ..max(src_offsets[0][0], src_offsets[1][0]),
2227                     min(src_offsets[0][1], src_offsets[1][1])
2228                         ..max(src_offsets[0][1], src_offsets[1][1]),
2229                     min(src_offsets[0][2], src_offsets[1][2])
2230                         ..max(src_offsets[0][2], src_offsets[1][2]),
2231                 ];
2232 
2233                 for (dst_region_index, dst_region) in regions.iter().enumerate() {
2234                     let &ImageBlit {
2235                         ref dst_subresource,
2236                         dst_offsets,
2237                         ..
2238                     } = dst_region;
2239 
2240                     let dst_subresource_axes = [
2241                         dst_image_inner.first_mipmap_level + dst_subresource.mip_level
2242                             ..dst_image_inner.first_mipmap_level + dst_subresource.mip_level + 1,
2243                         dst_image_inner.first_layer + src_subresource.array_layers.start
2244                             ..dst_image_inner.first_layer + src_subresource.array_layers.end,
2245                     ];
2246 
2247                     if src_subresource_axes.iter().zip(dst_subresource_axes).any(
2248                         |(src_range, dst_range)| {
2249                             src_range.start >= dst_range.end || dst_range.start >= src_range.end
2250                         },
2251                     ) {
2252                         continue;
2253                     }
2254 
2255                     // If the subresource axes all overlap, then the source and destination must
2256                     // have the same layout.
2257                     overlap_subresource_indices = Some((src_region_index, dst_region_index));
2258 
2259                     let dst_extent_axes = [
2260                         min(dst_offsets[0][0], dst_offsets[1][0])
2261                             ..max(dst_offsets[0][0], dst_offsets[1][0]),
2262                         min(dst_offsets[0][1], dst_offsets[1][1])
2263                             ..max(dst_offsets[0][1], dst_offsets[1][1]),
2264                         min(dst_offsets[0][2], dst_offsets[1][2])
2265                             ..max(dst_offsets[0][2], dst_offsets[1][2]),
2266                     ];
2267 
2268                     if src_extent_axes
2269                         .iter()
2270                         .zip(dst_extent_axes)
2271                         .any(|(src_range, dst_range)| {
2272                             src_range.start >= dst_range.end || dst_range.start >= src_range.end
2273                         })
2274                     {
2275                         continue;
2276                     }
2277 
2278                     // If the extent axes *also* overlap, then that's an error.
2279                     overlap_extent_indices = Some((src_region_index, dst_region_index));
2280                 }
2281             }
2282         }
2283 
2284         // VUID-VkBlitImageInfo2-pRegions-00217
2285         if let Some((src_region_index, dst_region_index)) = overlap_extent_indices {
2286             return Err(CopyError::OverlappingRegions {
2287                 src_region_index,
2288                 dst_region_index,
2289             });
2290         }
2291 
2292         // VUID-VkBlitImageInfo2-srcImageLayout-00221
2293         // VUID-VkBlitImageInfo2-dstImageLayout-00226
2294         if let Some((src_region_index, dst_region_index)) = overlap_subresource_indices {
2295             if src_image_layout != dst_image_layout {
2296                 return Err(CopyError::OverlappingSubresourcesLayoutMismatch {
2297                     src_region_index,
2298                     dst_region_index,
2299                     src_image_layout,
2300                     dst_image_layout,
2301                 });
2302             }
2303         }
2304 
2305         Ok(())
2306     }
2307 
2308     /// Resolves a multisampled image into a single-sampled image.
2309     ///
2310     /// # Panics
2311     ///
2312     /// - Panics if `src_image` or `dst_image` were not created from the same device
2313     ///   as `self`.
resolve_image( &mut self, resolve_image_info: ResolveImageInfo, ) -> Result<&mut Self, CopyError>2314     pub fn resolve_image(
2315         &mut self,
2316         resolve_image_info: ResolveImageInfo,
2317     ) -> Result<&mut Self, CopyError> {
2318         self.validate_resolve_image(&resolve_image_info)?;
2319 
2320         unsafe {
2321             self.inner.resolve_image(resolve_image_info)?;
2322         }
2323 
2324         Ok(self)
2325     }
2326 
validate_resolve_image( &self, resolve_image_info: &ResolveImageInfo, ) -> Result<(), CopyError>2327     fn validate_resolve_image(
2328         &self,
2329         resolve_image_info: &ResolveImageInfo,
2330     ) -> Result<(), CopyError> {
2331         let device = self.device();
2332 
2333         // VUID-vkCmdResolveImage2-renderpass
2334         if self.render_pass_state.is_some() {
2335             return Err(CopyError::ForbiddenInsideRenderPass);
2336         }
2337 
2338         let queue_family_properties = self.queue_family_properties();
2339 
2340         // VUID-vkCmdResolveImage2-commandBuffer-cmdpool
2341         if !queue_family_properties
2342             .queue_flags
2343             .intersects(QueueFlags::GRAPHICS)
2344         {
2345             return Err(CopyError::NotSupportedByQueueFamily);
2346         }
2347 
2348         let &ResolveImageInfo {
2349             ref src_image,
2350             src_image_layout,
2351             ref dst_image,
2352             dst_image_layout,
2353             ref regions,
2354             _ne: _,
2355         } = resolve_image_info;
2356 
2357         // VUID-VkResolveImageInfo2-srcImageLayout-parameter
2358         src_image_layout.validate_device(device)?;
2359 
2360         // VUID-VkResolveImageInfo2-dstImageLayout-parameter
2361         dst_image_layout.validate_device(device)?;
2362 
2363         // VUID-VkResolveImageInfo2-commonparent
2364         assert_eq!(device, src_image.device());
2365         assert_eq!(device, dst_image.device());
2366 
2367         let src_image_type = src_image.dimensions().image_type();
2368         let dst_image_type = dst_image.dimensions().image_type();
2369 
2370         // VUID-VkResolveImageInfo2-srcImage-00257
2371         if src_image.samples() == SampleCount::Sample1 {
2372             return Err(CopyError::SampleCountInvalid {
2373                 resource: CopyErrorResource::Source,
2374                 sample_count: dst_image.samples(),
2375                 allowed_sample_counts: SampleCounts::SAMPLE_2
2376                     | SampleCounts::SAMPLE_4
2377                     | SampleCounts::SAMPLE_8
2378                     | SampleCounts::SAMPLE_16
2379                     | SampleCounts::SAMPLE_32
2380                     | SampleCounts::SAMPLE_64,
2381             });
2382         }
2383 
2384         // VUID-VkResolveImageInfo2-dstImage-00259
2385         if dst_image.samples() != SampleCount::Sample1 {
2386             return Err(CopyError::SampleCountInvalid {
2387                 resource: CopyErrorResource::Destination,
2388                 sample_count: dst_image.samples(),
2389                 allowed_sample_counts: SampleCounts::SAMPLE_1,
2390             });
2391         }
2392 
2393         // VUID-VkResolveImageInfo2-dstImage-02003
2394         if !dst_image
2395             .format_features()
2396             .intersects(FormatFeatures::COLOR_ATTACHMENT)
2397         {
2398             return Err(CopyError::MissingFormatFeature {
2399                 resource: CopyErrorResource::Destination,
2400                 format_feature: "color_attachment",
2401             });
2402         }
2403 
2404         // VUID-VkResolveImageInfo2-srcImage-01386
2405         if src_image.format() != dst_image.format() {
2406             return Err(CopyError::FormatsMismatch {
2407                 src_format: src_image.format(),
2408                 dst_format: dst_image.format(),
2409             });
2410         }
2411 
2412         // VUID-VkResolveImageInfo2-srcImageLayout-01400
2413         if !matches!(
2414             src_image_layout,
2415             ImageLayout::TransferSrcOptimal | ImageLayout::General
2416         ) {
2417             return Err(CopyError::ImageLayoutInvalid {
2418                 resource: CopyErrorResource::Source,
2419                 image_layout: src_image_layout,
2420             });
2421         }
2422 
2423         // VUID-VkResolveImageInfo2-dstImageLayout-01401
2424         if !matches!(
2425             dst_image_layout,
2426             ImageLayout::TransferDstOptimal | ImageLayout::General
2427         ) {
2428             return Err(CopyError::ImageLayoutInvalid {
2429                 resource: CopyErrorResource::Destination,
2430                 image_layout: dst_image_layout,
2431             });
2432         }
2433 
2434         // Should be guaranteed by the requirement that formats match, and that the destination
2435         // image format features support color attachments.
2436         debug_assert!(
2437             src_image.format().aspects().intersects(ImageAspects::COLOR)
2438                 && dst_image.format().aspects().intersects(ImageAspects::COLOR)
2439         );
2440 
2441         for (region_index, region) in regions.iter().enumerate() {
2442             let &ImageResolve {
2443                 ref src_subresource,
2444                 src_offset,
2445                 ref dst_subresource,
2446                 dst_offset,
2447                 extent,
2448                 _ne: _,
2449             } = region;
2450 
2451             let check_subresource = |resource: CopyErrorResource,
2452                                      image: &dyn ImageAccess,
2453                                      subresource: &ImageSubresourceLayers|
2454              -> Result<_, CopyError> {
2455                 // VUID-VkResolveImageInfo2-srcSubresource-01709
2456                 // VUID-VkResolveImageInfo2-dstSubresource-01710
2457                 if subresource.mip_level >= image.mip_levels() {
2458                     return Err(CopyError::MipLevelsOutOfRange {
2459                         resource,
2460                         region_index,
2461                         mip_levels_range_end: subresource.mip_level + 1,
2462                         image_mip_levels: image.mip_levels(),
2463                     });
2464                 }
2465 
2466                 // VUID-VkImageSubresourceLayers-layerCount-01700
2467                 // VUID-VkResolveImageInfo2-srcImage-04446
2468                 // VUID-VkResolveImageInfo2-srcImage-04447
2469                 assert!(!subresource.array_layers.is_empty());
2470 
2471                 // VUID-VkResolveImageInfo2-srcSubresource-01711
2472                 // VUID-VkResolveImageInfo2-dstSubresource-01712
2473                 // VUID-VkResolveImageInfo2-srcImage-04446
2474                 // VUID-VkResolveImageInfo2-srcImage-04447
2475                 if subresource.array_layers.end > image.dimensions().array_layers() {
2476                     return Err(CopyError::ArrayLayersOutOfRange {
2477                         resource: CopyErrorResource::Destination,
2478                         region_index,
2479                         array_layers_range_end: subresource.array_layers.end,
2480                         image_array_layers: image.dimensions().array_layers(),
2481                     });
2482                 }
2483 
2484                 // VUID-VkImageSubresourceLayers-aspectMask-parameter
2485                 subresource.aspects.validate_device(device)?;
2486 
2487                 // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
2488                 // VUID-VkImageResolve2-aspectMask-00266
2489                 if subresource.aspects != (ImageAspects::COLOR) {
2490                     return Err(CopyError::AspectsNotAllowed {
2491                         resource,
2492                         region_index,
2493                         aspects: subresource.aspects,
2494                         allowed_aspects: ImageAspects::COLOR,
2495                     });
2496                 }
2497 
2498                 Ok(image
2499                     .dimensions()
2500                     .mip_level_dimensions(subresource.mip_level)
2501                     .unwrap()
2502                     .width_height_depth())
2503             };
2504 
2505             let src_subresource_extent =
2506                 check_subresource(CopyErrorResource::Source, src_image, src_subresource)?;
2507             let dst_subresource_extent =
2508                 check_subresource(CopyErrorResource::Destination, dst_image, dst_subresource)?;
2509 
2510             let src_layer_count =
2511                 src_subresource.array_layers.end - src_subresource.array_layers.start;
2512             let dst_layer_count =
2513                 dst_subresource.array_layers.end - dst_subresource.array_layers.start;
2514 
2515             // VUID-VkImageResolve2-layerCount-00267
2516             // VUID-VkResolveImageInfo2-srcImage-04446
2517             // VUID-VkResolveImageInfo2-srcImage-04447
2518             if src_layer_count != dst_layer_count {
2519                 return Err(CopyError::ArrayLayerCountMismatch {
2520                     region_index,
2521                     src_layer_count,
2522                     dst_layer_count,
2523                 });
2524             }
2525 
2526             // No VUID, but it makes sense?
2527             assert!(extent[0] != 0 && extent[1] != 0 && extent[2] != 0);
2528 
2529             let check_offset_extent = |resource: CopyErrorResource,
2530                                        _image_type: ImageType,
2531                                        subresource_extent: [u32; 3],
2532                                        offset: [u32; 3]|
2533              -> Result<_, CopyError> {
2534                 for i in 0..3 {
2535                     // No VUID, but makes sense?
2536                     assert!(extent[i] != 0);
2537 
2538                     // VUID-VkResolveImageInfo2-srcOffset-00269
2539                     // VUID-VkResolveImageInfo2-srcOffset-00270
2540                     // VUID-VkResolveImageInfo2-srcOffset-00272
2541                     // VUID-VkResolveImageInfo2-dstOffset-00274
2542                     // VUID-VkResolveImageInfo2-dstOffset-00275
2543                     // VUID-VkResolveImageInfo2-dstOffset-00277
2544                     if offset[i] + extent[i] > subresource_extent[i] {
2545                         return Err(CopyError::RegionOutOfImageBounds {
2546                             resource,
2547                             region_index,
2548                             offset_range_end: [
2549                                 offset[0] + extent[0],
2550                                 offset[1] + extent[1],
2551                                 offset[2] + extent[2],
2552                             ],
2553                             subresource_extent,
2554                         });
2555                     }
2556                 }
2557 
2558                 Ok(())
2559             };
2560 
2561             check_offset_extent(
2562                 CopyErrorResource::Source,
2563                 src_image_type,
2564                 src_subresource_extent,
2565                 src_offset,
2566             )?;
2567             check_offset_extent(
2568                 CopyErrorResource::Destination,
2569                 dst_image_type,
2570                 dst_subresource_extent,
2571                 dst_offset,
2572             )?;
2573         }
2574 
2575         // VUID-VkResolveImageInfo2-pRegions-00255
2576         // Can't occur as long as memory aliasing isn't allowed, because `src_image` and
2577         // `dst_image` must have different sample counts and therefore can never be the same image.
2578 
2579         Ok(())
2580     }
2581 }
2582 
2583 impl SyncCommandBufferBuilder {
2584     /// Calls `vkCmdCopyBuffer` on the builder.
2585     ///
2586     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
2587     /// usage of the command anyway.
2588     #[inline]
copy_buffer( &mut self, copy_buffer_info: CopyBufferInfo, ) -> Result<(), SyncCommandBufferBuilderError>2589     pub unsafe fn copy_buffer(
2590         &mut self,
2591         copy_buffer_info: CopyBufferInfo,
2592     ) -> Result<(), SyncCommandBufferBuilderError> {
2593         struct Cmd {
2594             copy_buffer_info: CopyBufferInfo,
2595         }
2596 
2597         impl Command for Cmd {
2598             fn name(&self) -> &'static str {
2599                 "copy_buffer"
2600             }
2601 
2602             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
2603                 out.copy_buffer(&self.copy_buffer_info);
2604             }
2605         }
2606 
2607         let CopyBufferInfo {
2608             src_buffer,
2609             dst_buffer,
2610             regions,
2611             _ne: _,
2612         } = &copy_buffer_info;
2613 
2614         let command_index = self.commands.len();
2615         let command_name = "copy_buffer";
2616         let resources: SmallVec<[_; 8]> = regions
2617             .iter()
2618             .flat_map(|region| {
2619                 let &BufferCopy {
2620                     src_offset,
2621                     dst_offset,
2622                     size,
2623                     _ne: _,
2624                 } = region;
2625 
2626                 [
2627                     (
2628                         ResourceUseRef {
2629                             command_index,
2630                             command_name,
2631                             resource_in_command: ResourceInCommand::Source,
2632                             secondary_use_ref: None,
2633                         },
2634                         Resource::Buffer {
2635                             buffer: src_buffer.clone(),
2636                             range: src_offset..src_offset + size,
2637                             memory: PipelineMemoryAccess {
2638                                 stages: PipelineStages::ALL_TRANSFER,
2639                                 access: AccessFlags::TRANSFER_READ,
2640                                 exclusive: false,
2641                             },
2642                         },
2643                     ),
2644                     (
2645                         ResourceUseRef {
2646                             command_index,
2647                             command_name,
2648                             resource_in_command: ResourceInCommand::Destination,
2649                             secondary_use_ref: None,
2650                         },
2651                         Resource::Buffer {
2652                             buffer: dst_buffer.clone(),
2653                             range: dst_offset..dst_offset + size,
2654                             memory: PipelineMemoryAccess {
2655                                 stages: PipelineStages::ALL_TRANSFER,
2656                                 access: AccessFlags::TRANSFER_WRITE,
2657                                 exclusive: true,
2658                             },
2659                         },
2660                     ),
2661                 ]
2662             })
2663             .collect();
2664 
2665         for resource in &resources {
2666             self.check_resource_conflicts(resource)?;
2667         }
2668 
2669         self.commands.push(Box::new(Cmd { copy_buffer_info }));
2670 
2671         for resource in resources {
2672             self.add_resource(resource);
2673         }
2674 
2675         Ok(())
2676     }
2677 
2678     /// Calls `vkCmdCopyImage` on the builder.
2679     ///
2680     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
2681     /// usage of the command anyway.
2682     #[inline]
copy_image( &mut self, copy_image_info: CopyImageInfo, ) -> Result<(), SyncCommandBufferBuilderError>2683     pub unsafe fn copy_image(
2684         &mut self,
2685         copy_image_info: CopyImageInfo,
2686     ) -> Result<(), SyncCommandBufferBuilderError> {
2687         struct Cmd {
2688             copy_image_info: CopyImageInfo,
2689         }
2690 
2691         impl Command for Cmd {
2692             fn name(&self) -> &'static str {
2693                 "copy_buffer_to_image"
2694             }
2695 
2696             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
2697                 out.copy_image(&self.copy_image_info);
2698             }
2699         }
2700 
2701         let &CopyImageInfo {
2702             ref src_image,
2703             src_image_layout,
2704             ref dst_image,
2705             dst_image_layout,
2706             ref regions,
2707             _ne: _,
2708         } = &copy_image_info;
2709 
2710         let command_index = self.commands.len();
2711         let command_name = "copy_image";
2712         let resources: SmallVec<[_; 8]> = regions
2713             .iter()
2714             .flat_map(|region| {
2715                 let &ImageCopy {
2716                     ref src_subresource,
2717                     src_offset: _,
2718                     ref dst_subresource,
2719                     dst_offset: _,
2720                     extent: _,
2721                     _ne: _,
2722                 } = region;
2723 
2724                 [
2725                     (
2726                         ResourceUseRef {
2727                             command_index,
2728                             command_name,
2729                             resource_in_command: ResourceInCommand::Source,
2730                             secondary_use_ref: None,
2731                         },
2732                         Resource::Image {
2733                             image: src_image.clone(),
2734                             subresource_range: src_subresource.clone().into(),
2735                             memory: PipelineMemoryAccess {
2736                                 stages: PipelineStages::ALL_TRANSFER,
2737                                 access: AccessFlags::TRANSFER_READ,
2738                                 exclusive: false,
2739                             },
2740                             start_layout: src_image_layout,
2741                             end_layout: src_image_layout,
2742                         },
2743                     ),
2744                     (
2745                         ResourceUseRef {
2746                             command_index,
2747                             command_name,
2748                             resource_in_command: ResourceInCommand::Destination,
2749                             secondary_use_ref: None,
2750                         },
2751                         Resource::Image {
2752                             image: dst_image.clone(),
2753                             subresource_range: dst_subresource.clone().into(),
2754                             memory: PipelineMemoryAccess {
2755                                 stages: PipelineStages::ALL_TRANSFER,
2756                                 access: AccessFlags::TRANSFER_WRITE,
2757                                 exclusive: true,
2758                             },
2759                             start_layout: dst_image_layout,
2760                             end_layout: dst_image_layout,
2761                         },
2762                     ),
2763                 ]
2764             })
2765             .collect();
2766 
2767         for resource in &resources {
2768             self.check_resource_conflicts(resource)?;
2769         }
2770 
2771         self.commands.push(Box::new(Cmd { copy_image_info }));
2772 
2773         for resource in resources {
2774             self.add_resource(resource);
2775         }
2776 
2777         Ok(())
2778     }
2779 
2780     /// Calls `vkCmdCopyBufferToImage` on the builder.
2781     ///
2782     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
2783     /// usage of the command anyway.
2784     #[inline]
copy_buffer_to_image( &mut self, copy_buffer_to_image_info: CopyBufferToImageInfo, ) -> Result<(), SyncCommandBufferBuilderError>2785     pub unsafe fn copy_buffer_to_image(
2786         &mut self,
2787         copy_buffer_to_image_info: CopyBufferToImageInfo,
2788     ) -> Result<(), SyncCommandBufferBuilderError> {
2789         struct Cmd {
2790             copy_buffer_to_image_info: CopyBufferToImageInfo,
2791         }
2792 
2793         impl Command for Cmd {
2794             fn name(&self) -> &'static str {
2795                 "copy_buffer_to_image"
2796             }
2797 
2798             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
2799                 out.copy_buffer_to_image(&self.copy_buffer_to_image_info);
2800             }
2801         }
2802 
2803         let &CopyBufferToImageInfo {
2804             ref src_buffer,
2805             ref dst_image,
2806             dst_image_layout,
2807             ref regions,
2808             _ne: _,
2809         } = &copy_buffer_to_image_info;
2810 
2811         let command_index = self.commands.len();
2812         let command_name = "copy_buffer_to_image";
2813         let resources: SmallVec<[_; 8]> = regions
2814             .iter()
2815             .flat_map(|region| {
2816                 let &BufferImageCopy {
2817                     buffer_offset,
2818                     buffer_row_length: _,
2819                     buffer_image_height: _,
2820                     ref image_subresource,
2821                     image_offset: _,
2822                     image_extent: _,
2823                     _ne: _,
2824                 } = region;
2825 
2826                 [
2827                     (
2828                         ResourceUseRef {
2829                             command_index,
2830                             command_name,
2831                             resource_in_command: ResourceInCommand::Source,
2832                             secondary_use_ref: None,
2833                         },
2834                         Resource::Buffer {
2835                             buffer: src_buffer.clone(),
2836                             range: buffer_offset
2837                                 ..buffer_offset + region.buffer_copy_size(dst_image.format()),
2838                             memory: PipelineMemoryAccess {
2839                                 stages: PipelineStages::ALL_TRANSFER,
2840                                 access: AccessFlags::TRANSFER_READ,
2841                                 exclusive: false,
2842                             },
2843                         },
2844                     ),
2845                     (
2846                         ResourceUseRef {
2847                             command_index,
2848                             command_name,
2849                             resource_in_command: ResourceInCommand::Destination,
2850                             secondary_use_ref: None,
2851                         },
2852                         Resource::Image {
2853                             image: dst_image.clone(),
2854                             subresource_range: image_subresource.clone().into(),
2855                             memory: PipelineMemoryAccess {
2856                                 stages: PipelineStages::ALL_TRANSFER,
2857                                 access: AccessFlags::TRANSFER_WRITE,
2858                                 exclusive: true,
2859                             },
2860                             start_layout: dst_image_layout,
2861                             end_layout: dst_image_layout,
2862                         },
2863                     ),
2864                 ]
2865             })
2866             .collect();
2867 
2868         for resource in &resources {
2869             self.check_resource_conflicts(resource)?;
2870         }
2871 
2872         self.commands.push(Box::new(Cmd {
2873             copy_buffer_to_image_info,
2874         }));
2875 
2876         for resource in resources {
2877             self.add_resource(resource);
2878         }
2879 
2880         Ok(())
2881     }
2882 
2883     /// Calls `vkCmdCopyImageToBuffer` on the builder.
2884     ///
2885     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
2886     /// usage of the command anyway.
2887     #[inline]
copy_image_to_buffer( &mut self, copy_image_to_buffer_info: CopyImageToBufferInfo, ) -> Result<(), SyncCommandBufferBuilderError>2888     pub unsafe fn copy_image_to_buffer(
2889         &mut self,
2890         copy_image_to_buffer_info: CopyImageToBufferInfo,
2891     ) -> Result<(), SyncCommandBufferBuilderError> {
2892         struct Cmd {
2893             copy_image_to_buffer_info: CopyImageToBufferInfo,
2894         }
2895 
2896         impl Command for Cmd {
2897             fn name(&self) -> &'static str {
2898                 "copy_image_to_buffer"
2899             }
2900 
2901             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
2902                 out.copy_image_to_buffer(&self.copy_image_to_buffer_info);
2903             }
2904         }
2905 
2906         let &CopyImageToBufferInfo {
2907             ref src_image,
2908             src_image_layout,
2909             ref dst_buffer,
2910             ref regions,
2911             _ne: _,
2912         } = &copy_image_to_buffer_info;
2913 
2914         let command_index = self.commands.len();
2915         let command_name = "copy_image_to_buffer";
2916         let resources: SmallVec<[_; 8]> = regions
2917             .iter()
2918             .flat_map(|region| {
2919                 let &BufferImageCopy {
2920                     buffer_offset,
2921                     buffer_row_length: _,
2922                     buffer_image_height: _,
2923                     ref image_subresource,
2924                     image_offset: _,
2925                     image_extent: _,
2926                     _ne: _,
2927                 } = region;
2928 
2929                 [
2930                     (
2931                         ResourceUseRef {
2932                             command_index,
2933                             command_name,
2934                             resource_in_command: ResourceInCommand::Source,
2935                             secondary_use_ref: None,
2936                         },
2937                         Resource::Image {
2938                             image: src_image.clone(),
2939                             subresource_range: image_subresource.clone().into(),
2940                             memory: PipelineMemoryAccess {
2941                                 stages: PipelineStages::ALL_TRANSFER,
2942                                 access: AccessFlags::TRANSFER_READ,
2943                                 exclusive: false,
2944                             },
2945                             start_layout: src_image_layout,
2946                             end_layout: src_image_layout,
2947                         },
2948                     ),
2949                     (
2950                         ResourceUseRef {
2951                             command_index,
2952                             command_name,
2953                             resource_in_command: ResourceInCommand::Destination,
2954                             secondary_use_ref: None,
2955                         },
2956                         Resource::Buffer {
2957                             buffer: dst_buffer.clone(),
2958                             range: buffer_offset
2959                                 ..buffer_offset + region.buffer_copy_size(src_image.format()),
2960                             memory: PipelineMemoryAccess {
2961                                 stages: PipelineStages::ALL_TRANSFER,
2962                                 access: AccessFlags::TRANSFER_WRITE,
2963                                 exclusive: true,
2964                             },
2965                         },
2966                     ),
2967                 ]
2968             })
2969             .collect();
2970 
2971         for resource in &resources {
2972             self.check_resource_conflicts(resource)?;
2973         }
2974 
2975         self.commands.push(Box::new(Cmd {
2976             copy_image_to_buffer_info,
2977         }));
2978 
2979         for resource in resources {
2980             self.add_resource(resource);
2981         }
2982 
2983         Ok(())
2984     }
2985 
2986     /// Calls `vkCmdBlitImage` on the builder.
2987     ///
2988     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
2989     /// usage of the command anyway.
2990     #[inline]
blit_image( &mut self, blit_image_info: BlitImageInfo, ) -> Result<(), SyncCommandBufferBuilderError>2991     pub unsafe fn blit_image(
2992         &mut self,
2993         blit_image_info: BlitImageInfo,
2994     ) -> Result<(), SyncCommandBufferBuilderError> {
2995         struct Cmd {
2996             blit_image_info: BlitImageInfo,
2997         }
2998 
2999         impl Command for Cmd {
3000             fn name(&self) -> &'static str {
3001                 "blit_image"
3002             }
3003 
3004             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
3005                 out.blit_image(&self.blit_image_info);
3006             }
3007         }
3008 
3009         let &BlitImageInfo {
3010             ref src_image,
3011             src_image_layout,
3012             ref dst_image,
3013             dst_image_layout,
3014             ref regions,
3015             filter: _,
3016             _ne: _,
3017         } = &blit_image_info;
3018 
3019         let command_index = self.commands.len();
3020         let command_name = "blit_image";
3021         let resources: SmallVec<[_; 8]> = regions
3022             .iter()
3023             .flat_map(|region| {
3024                 let &ImageBlit {
3025                     ref src_subresource,
3026                     src_offsets: _,
3027                     ref dst_subresource,
3028                     dst_offsets: _,
3029                     _ne: _,
3030                 } = region;
3031 
3032                 [
3033                     (
3034                         ResourceUseRef {
3035                             command_index,
3036                             command_name,
3037                             resource_in_command: ResourceInCommand::Source,
3038                             secondary_use_ref: None,
3039                         },
3040                         Resource::Image {
3041                             image: src_image.clone(),
3042                             subresource_range: src_subresource.clone().into(),
3043                             memory: PipelineMemoryAccess {
3044                                 stages: PipelineStages::ALL_TRANSFER,
3045                                 access: AccessFlags::TRANSFER_READ,
3046                                 exclusive: false,
3047                             },
3048                             start_layout: src_image_layout,
3049                             end_layout: src_image_layout,
3050                         },
3051                     ),
3052                     (
3053                         ResourceUseRef {
3054                             command_index,
3055                             command_name,
3056                             resource_in_command: ResourceInCommand::Destination,
3057                             secondary_use_ref: None,
3058                         },
3059                         Resource::Image {
3060                             image: dst_image.clone(),
3061                             subresource_range: dst_subresource.clone().into(),
3062                             memory: PipelineMemoryAccess {
3063                                 stages: PipelineStages::ALL_TRANSFER,
3064                                 access: AccessFlags::TRANSFER_WRITE,
3065                                 exclusive: true,
3066                             },
3067                             start_layout: dst_image_layout,
3068                             end_layout: dst_image_layout,
3069                         },
3070                     ),
3071                 ]
3072             })
3073             .collect();
3074 
3075         for resource in &resources {
3076             self.check_resource_conflicts(resource)?;
3077         }
3078 
3079         self.commands.push(Box::new(Cmd { blit_image_info }));
3080 
3081         for resource in resources {
3082             self.add_resource(resource);
3083         }
3084 
3085         Ok(())
3086     }
3087 
3088     /// Calls `vkCmdResolveImage` on the builder.
3089     ///
3090     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
3091     /// usage of the command anyway.
3092     #[inline]
resolve_image( &mut self, resolve_image_info: ResolveImageInfo, ) -> Result<(), SyncCommandBufferBuilderError>3093     pub unsafe fn resolve_image(
3094         &mut self,
3095         resolve_image_info: ResolveImageInfo,
3096     ) -> Result<(), SyncCommandBufferBuilderError> {
3097         struct Cmd {
3098             resolve_image_info: ResolveImageInfo,
3099         }
3100 
3101         impl Command for Cmd {
3102             fn name(&self) -> &'static str {
3103                 "resolve_image"
3104             }
3105 
3106             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
3107                 out.resolve_image(&self.resolve_image_info);
3108             }
3109         }
3110 
3111         let &ResolveImageInfo {
3112             ref src_image,
3113             src_image_layout,
3114             ref dst_image,
3115             dst_image_layout,
3116             ref regions,
3117             _ne: _,
3118         } = &resolve_image_info;
3119 
3120         let command_index = self.commands.len();
3121         let command_name = "resolve_image";
3122         let resources: SmallVec<[_; 8]> = regions
3123             .iter()
3124             .flat_map(|region| {
3125                 let &ImageResolve {
3126                     ref src_subresource,
3127                     src_offset: _,
3128                     ref dst_subresource,
3129                     dst_offset: _,
3130                     extent: _,
3131                     _ne: _,
3132                 } = region;
3133 
3134                 [
3135                     (
3136                         ResourceUseRef {
3137                             command_index,
3138                             command_name,
3139                             resource_in_command: ResourceInCommand::Source,
3140                             secondary_use_ref: None,
3141                         },
3142                         Resource::Image {
3143                             image: src_image.clone(),
3144                             subresource_range: src_subresource.clone().into(),
3145                             memory: PipelineMemoryAccess {
3146                                 stages: PipelineStages::ALL_TRANSFER,
3147                                 access: AccessFlags::TRANSFER_READ,
3148                                 exclusive: false,
3149                             },
3150                             start_layout: src_image_layout,
3151                             end_layout: src_image_layout,
3152                         },
3153                     ),
3154                     (
3155                         ResourceUseRef {
3156                             command_index,
3157                             command_name,
3158                             resource_in_command: ResourceInCommand::Destination,
3159                             secondary_use_ref: None,
3160                         },
3161                         Resource::Image {
3162                             image: dst_image.clone(),
3163                             subresource_range: dst_subresource.clone().into(),
3164                             memory: PipelineMemoryAccess {
3165                                 stages: PipelineStages::ALL_TRANSFER,
3166                                 access: AccessFlags::TRANSFER_WRITE,
3167                                 exclusive: true,
3168                             },
3169                             start_layout: dst_image_layout,
3170                             end_layout: dst_image_layout,
3171                         },
3172                     ),
3173                 ]
3174             })
3175             .collect();
3176 
3177         for resource in &resources {
3178             self.check_resource_conflicts(resource)?;
3179         }
3180 
3181         self.commands.push(Box::new(Cmd { resolve_image_info }));
3182 
3183         for resource in resources {
3184             self.add_resource(resource);
3185         }
3186 
3187         Ok(())
3188     }
3189 }
3190 
3191 impl UnsafeCommandBufferBuilder {
3192     /// Calls `vkCmdCopyBuffer` on the builder.
3193     ///
3194     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
3195     /// usage of the command anyway.
3196     #[inline]
copy_buffer(&mut self, copy_buffer_info: &CopyBufferInfo)3197     pub unsafe fn copy_buffer(&mut self, copy_buffer_info: &CopyBufferInfo) {
3198         let CopyBufferInfo {
3199             src_buffer,
3200             dst_buffer,
3201             regions,
3202             _ne: _,
3203         } = copy_buffer_info;
3204 
3205         if regions.is_empty() {
3206             return;
3207         }
3208 
3209         let fns = self.device.fns();
3210 
3211         if self.device.api_version() >= Version::V1_3
3212             || self.device.enabled_extensions().khr_copy_commands2
3213         {
3214             let regions: SmallVec<[_; 8]> = regions
3215                 .iter()
3216                 .map(|region| {
3217                     let &BufferCopy {
3218                         src_offset,
3219                         dst_offset,
3220                         size,
3221                         _ne,
3222                     } = region;
3223 
3224                     ash::vk::BufferCopy2 {
3225                         src_offset: src_offset + src_buffer.offset(),
3226                         dst_offset: dst_offset + dst_buffer.offset(),
3227                         size,
3228                         ..Default::default()
3229                     }
3230                 })
3231                 .collect();
3232 
3233             let copy_buffer_info = ash::vk::CopyBufferInfo2 {
3234                 src_buffer: src_buffer.buffer().handle(),
3235                 dst_buffer: dst_buffer.buffer().handle(),
3236                 region_count: regions.len() as u32,
3237                 p_regions: regions.as_ptr(),
3238                 ..Default::default()
3239             };
3240 
3241             if self.device.api_version() >= Version::V1_3 {
3242                 (fns.v1_3.cmd_copy_buffer2)(self.handle, &copy_buffer_info);
3243             } else {
3244                 (fns.khr_copy_commands2.cmd_copy_buffer2_khr)(self.handle, &copy_buffer_info);
3245             }
3246         } else {
3247             let regions: SmallVec<[_; 8]> = regions
3248                 .iter()
3249                 .map(|region| {
3250                     let &BufferCopy {
3251                         src_offset,
3252                         dst_offset,
3253                         size,
3254                         _ne,
3255                     } = region;
3256 
3257                     ash::vk::BufferCopy {
3258                         src_offset: src_offset + src_buffer.offset(),
3259                         dst_offset: dst_offset + dst_buffer.offset(),
3260                         size,
3261                     }
3262                 })
3263                 .collect();
3264 
3265             (fns.v1_0.cmd_copy_buffer)(
3266                 self.handle,
3267                 src_buffer.buffer().handle(),
3268                 dst_buffer.buffer().handle(),
3269                 regions.len() as u32,
3270                 regions.as_ptr(),
3271             );
3272         }
3273     }
3274 
3275     /// Calls `vkCmdCopyImage` on the builder.
3276     ///
3277     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
3278     /// usage of the command anyway.
3279     #[inline]
copy_image(&mut self, copy_image_info: &CopyImageInfo)3280     pub unsafe fn copy_image(&mut self, copy_image_info: &CopyImageInfo) {
3281         let &CopyImageInfo {
3282             ref src_image,
3283             src_image_layout,
3284             ref dst_image,
3285             dst_image_layout,
3286             ref regions,
3287             _ne: _,
3288         } = copy_image_info;
3289 
3290         if regions.is_empty() {
3291             return;
3292         }
3293 
3294         let src_image_inner = src_image.inner();
3295         let dst_image_inner = dst_image.inner();
3296 
3297         let fns = self.device.fns();
3298 
3299         if self.device.api_version() >= Version::V1_3
3300             || self.device.enabled_extensions().khr_copy_commands2
3301         {
3302             let regions: SmallVec<[_; 8]> = regions
3303                 .into_iter()
3304                 .map(|region| {
3305                     let &ImageCopy {
3306                         ref src_subresource,
3307                         src_offset,
3308                         ref dst_subresource,
3309                         dst_offset,
3310                         extent,
3311                         _ne: _,
3312                     } = region;
3313 
3314                     let mut src_subresource = src_subresource.clone();
3315                     src_subresource.array_layers.start += src_image_inner.first_layer;
3316                     src_subresource.array_layers.end += src_image_inner.first_layer;
3317                     src_subresource.mip_level += src_image_inner.first_mipmap_level;
3318 
3319                     let mut dst_subresource = dst_subresource.clone();
3320                     dst_subresource.array_layers.start += dst_image_inner.first_layer;
3321                     dst_subresource.array_layers.end += dst_image_inner.first_layer;
3322                     dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
3323 
3324                     ash::vk::ImageCopy2 {
3325                         src_subresource: src_subresource.into(),
3326                         src_offset: ash::vk::Offset3D {
3327                             x: src_offset[0] as i32,
3328                             y: src_offset[1] as i32,
3329                             z: src_offset[2] as i32,
3330                         },
3331                         dst_subresource: dst_subresource.into(),
3332                         dst_offset: ash::vk::Offset3D {
3333                             x: dst_offset[0] as i32,
3334                             y: dst_offset[1] as i32,
3335                             z: dst_offset[2] as i32,
3336                         },
3337                         extent: ash::vk::Extent3D {
3338                             width: extent[0],
3339                             height: extent[1],
3340                             depth: extent[2],
3341                         },
3342                         ..Default::default()
3343                     }
3344                 })
3345                 .collect();
3346 
3347             let copy_image_info = ash::vk::CopyImageInfo2 {
3348                 src_image: src_image_inner.image.handle(),
3349                 src_image_layout: src_image_layout.into(),
3350                 dst_image: dst_image_inner.image.handle(),
3351                 dst_image_layout: dst_image_layout.into(),
3352                 region_count: regions.len() as u32,
3353                 p_regions: regions.as_ptr(),
3354                 ..Default::default()
3355             };
3356 
3357             if self.device.api_version() >= Version::V1_3 {
3358                 (fns.v1_3.cmd_copy_image2)(self.handle, &copy_image_info);
3359             } else {
3360                 (fns.khr_copy_commands2.cmd_copy_image2_khr)(self.handle, &copy_image_info);
3361             }
3362         } else {
3363             let regions: SmallVec<[_; 8]> = regions
3364                 .into_iter()
3365                 .map(|region| {
3366                     let &ImageCopy {
3367                         ref src_subresource,
3368                         src_offset,
3369                         ref dst_subresource,
3370                         dst_offset,
3371                         extent,
3372                         _ne: _,
3373                     } = region;
3374 
3375                     let mut src_subresource = src_subresource.clone();
3376                     src_subresource.array_layers.start += src_image_inner.first_layer;
3377                     src_subresource.array_layers.end += src_image_inner.first_layer;
3378                     src_subresource.mip_level += src_image_inner.first_mipmap_level;
3379 
3380                     let mut dst_subresource = dst_subresource.clone();
3381                     dst_subresource.array_layers.start += dst_image_inner.first_layer;
3382                     dst_subresource.array_layers.end += dst_image_inner.first_layer;
3383                     dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
3384 
3385                     ash::vk::ImageCopy {
3386                         src_subresource: src_subresource.into(),
3387                         src_offset: ash::vk::Offset3D {
3388                             x: src_offset[0] as i32,
3389                             y: src_offset[1] as i32,
3390                             z: src_offset[2] as i32,
3391                         },
3392                         dst_subresource: dst_subresource.into(),
3393                         dst_offset: ash::vk::Offset3D {
3394                             x: dst_offset[0] as i32,
3395                             y: dst_offset[1] as i32,
3396                             z: dst_offset[2] as i32,
3397                         },
3398                         extent: ash::vk::Extent3D {
3399                             width: extent[0],
3400                             height: extent[1],
3401                             depth: extent[2],
3402                         },
3403                     }
3404                 })
3405                 .collect();
3406 
3407             (fns.v1_0.cmd_copy_image)(
3408                 self.handle,
3409                 src_image_inner.image.handle(),
3410                 src_image_layout.into(),
3411                 dst_image_inner.image.handle(),
3412                 dst_image_layout.into(),
3413                 regions.len() as u32,
3414                 regions.as_ptr(),
3415             );
3416         }
3417     }
3418 
3419     /// Calls `vkCmdCopyBufferToImage` on the builder.
3420     ///
3421     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
3422     /// usage of the command anyway.
3423     #[inline]
copy_buffer_to_image( &mut self, copy_buffer_to_image_info: &CopyBufferToImageInfo, )3424     pub unsafe fn copy_buffer_to_image(
3425         &mut self,
3426         copy_buffer_to_image_info: &CopyBufferToImageInfo,
3427     ) {
3428         let &CopyBufferToImageInfo {
3429             ref src_buffer,
3430             ref dst_image,
3431             dst_image_layout,
3432             ref regions,
3433             _ne: _,
3434         } = copy_buffer_to_image_info;
3435 
3436         if regions.is_empty() {
3437             return;
3438         }
3439 
3440         let dst_image_inner = dst_image.inner();
3441 
3442         let fns = self.device.fns();
3443 
3444         if self.device.api_version() >= Version::V1_3
3445             || self.device.enabled_extensions().khr_copy_commands2
3446         {
3447             let regions: SmallVec<[_; 8]> = regions
3448                 .iter()
3449                 .map(|region| {
3450                     let &BufferImageCopy {
3451                         buffer_offset,
3452                         buffer_row_length,
3453                         buffer_image_height,
3454                         ref image_subresource,
3455                         image_offset,
3456                         image_extent,
3457                         _ne: _,
3458                     } = region;
3459 
3460                     let mut image_subresource = image_subresource.clone();
3461                     image_subresource.array_layers.start += dst_image_inner.first_layer;
3462                     image_subresource.array_layers.end += dst_image_inner.first_layer;
3463                     image_subresource.mip_level += dst_image_inner.first_mipmap_level;
3464 
3465                     ash::vk::BufferImageCopy2 {
3466                         buffer_offset: buffer_offset + src_buffer.offset(),
3467                         buffer_row_length,
3468                         buffer_image_height,
3469                         image_subresource: image_subresource.into(),
3470                         image_offset: ash::vk::Offset3D {
3471                             x: image_offset[0] as i32,
3472                             y: image_offset[1] as i32,
3473                             z: image_offset[2] as i32,
3474                         },
3475                         image_extent: ash::vk::Extent3D {
3476                             width: image_extent[0],
3477                             height: image_extent[1],
3478                             depth: image_extent[2],
3479                         },
3480                         ..Default::default()
3481                     }
3482                 })
3483                 .collect();
3484 
3485             let copy_buffer_to_image_info = ash::vk::CopyBufferToImageInfo2 {
3486                 src_buffer: src_buffer.buffer().handle(),
3487                 dst_image: dst_image_inner.image.handle(),
3488                 dst_image_layout: dst_image_layout.into(),
3489                 region_count: regions.len() as u32,
3490                 p_regions: regions.as_ptr(),
3491                 ..Default::default()
3492             };
3493 
3494             if self.device.api_version() >= Version::V1_3 {
3495                 (fns.v1_3.cmd_copy_buffer_to_image2)(self.handle, &copy_buffer_to_image_info);
3496             } else {
3497                 (fns.khr_copy_commands2.cmd_copy_buffer_to_image2_khr)(
3498                     self.handle,
3499                     &copy_buffer_to_image_info,
3500                 );
3501             }
3502         } else {
3503             let regions: SmallVec<[_; 8]> = regions
3504                 .iter()
3505                 .map(|region| {
3506                     let &BufferImageCopy {
3507                         buffer_offset,
3508                         buffer_row_length,
3509                         buffer_image_height,
3510                         ref image_subresource,
3511                         image_offset,
3512                         image_extent,
3513                         _ne: _,
3514                     } = region;
3515 
3516                     let mut image_subresource = image_subresource.clone();
3517                     image_subresource.array_layers.start += dst_image_inner.first_layer;
3518                     image_subresource.array_layers.end += dst_image_inner.first_layer;
3519                     image_subresource.mip_level += dst_image_inner.first_mipmap_level;
3520 
3521                     ash::vk::BufferImageCopy {
3522                         buffer_offset: buffer_offset + src_buffer.offset(),
3523                         buffer_row_length,
3524                         buffer_image_height,
3525                         image_subresource: image_subresource.into(),
3526                         image_offset: ash::vk::Offset3D {
3527                             x: image_offset[0] as i32,
3528                             y: image_offset[1] as i32,
3529                             z: image_offset[2] as i32,
3530                         },
3531                         image_extent: ash::vk::Extent3D {
3532                             width: image_extent[0],
3533                             height: image_extent[1],
3534                             depth: image_extent[2],
3535                         },
3536                     }
3537                 })
3538                 .collect();
3539 
3540             (fns.v1_0.cmd_copy_buffer_to_image)(
3541                 self.handle,
3542                 src_buffer.buffer().handle(),
3543                 dst_image_inner.image.handle(),
3544                 dst_image_layout.into(),
3545                 regions.len() as u32,
3546                 regions.as_ptr(),
3547             );
3548         }
3549     }
3550 
3551     /// Calls `vkCmdCopyImageToBuffer` on the builder.
3552     ///
3553     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
3554     /// usage of the command anyway.
3555     #[inline]
copy_image_to_buffer( &mut self, copy_image_to_buffer_info: &CopyImageToBufferInfo, )3556     pub unsafe fn copy_image_to_buffer(
3557         &mut self,
3558         copy_image_to_buffer_info: &CopyImageToBufferInfo,
3559     ) {
3560         let &CopyImageToBufferInfo {
3561             ref src_image,
3562             src_image_layout,
3563             ref dst_buffer,
3564             ref regions,
3565             _ne: _,
3566         } = copy_image_to_buffer_info;
3567 
3568         if regions.is_empty() {
3569             return;
3570         }
3571 
3572         let src_image_inner = src_image.inner();
3573 
3574         let fns = self.device.fns();
3575 
3576         if self.device.api_version() >= Version::V1_3
3577             || self.device.enabled_extensions().khr_copy_commands2
3578         {
3579             let regions: SmallVec<[_; 8]> = regions
3580                 .iter()
3581                 .map(|region| {
3582                     let &BufferImageCopy {
3583                         buffer_offset,
3584                         buffer_row_length,
3585                         buffer_image_height,
3586                         ref image_subresource,
3587                         image_offset,
3588                         image_extent,
3589                         _ne: _,
3590                     } = region;
3591 
3592                     let mut image_subresource = image_subresource.clone();
3593                     image_subresource.array_layers.start += src_image_inner.first_layer;
3594                     image_subresource.array_layers.end += src_image_inner.first_layer;
3595                     image_subresource.mip_level += src_image_inner.first_mipmap_level;
3596 
3597                     ash::vk::BufferImageCopy2 {
3598                         buffer_offset: buffer_offset + dst_buffer.offset(),
3599                         buffer_row_length,
3600                         buffer_image_height,
3601                         image_subresource: image_subresource.into(),
3602                         image_offset: ash::vk::Offset3D {
3603                             x: image_offset[0] as i32,
3604                             y: image_offset[1] as i32,
3605                             z: image_offset[2] as i32,
3606                         },
3607                         image_extent: ash::vk::Extent3D {
3608                             width: image_extent[0],
3609                             height: image_extent[1],
3610                             depth: image_extent[2],
3611                         },
3612                         ..Default::default()
3613                     }
3614                 })
3615                 .collect();
3616 
3617             let copy_image_to_buffer_info = ash::vk::CopyImageToBufferInfo2 {
3618                 src_image: src_image_inner.image.handle(),
3619                 src_image_layout: src_image_layout.into(),
3620                 dst_buffer: dst_buffer.buffer().handle(),
3621                 region_count: regions.len() as u32,
3622                 p_regions: regions.as_ptr(),
3623                 ..Default::default()
3624             };
3625 
3626             if self.device.api_version() >= Version::V1_3 {
3627                 (fns.v1_3.cmd_copy_image_to_buffer2)(self.handle, &copy_image_to_buffer_info);
3628             } else {
3629                 (fns.khr_copy_commands2.cmd_copy_image_to_buffer2_khr)(
3630                     self.handle,
3631                     &copy_image_to_buffer_info,
3632                 );
3633             }
3634         } else {
3635             let regions: SmallVec<[_; 8]> = regions
3636                 .iter()
3637                 .map(|region| {
3638                     let &BufferImageCopy {
3639                         buffer_offset,
3640                         buffer_row_length,
3641                         buffer_image_height,
3642                         ref image_subresource,
3643                         image_offset,
3644                         image_extent,
3645                         _ne: _,
3646                     } = region;
3647                     let mut image_subresource = image_subresource.clone();
3648                     image_subresource.array_layers.start += src_image_inner.first_layer;
3649                     image_subresource.array_layers.end += src_image_inner.first_layer;
3650                     image_subresource.mip_level += src_image_inner.first_mipmap_level;
3651 
3652                     ash::vk::BufferImageCopy {
3653                         buffer_offset: buffer_offset + dst_buffer.offset(),
3654                         buffer_row_length,
3655                         buffer_image_height,
3656                         image_subresource: image_subresource.into(),
3657                         image_offset: ash::vk::Offset3D {
3658                             x: image_offset[0] as i32,
3659                             y: image_offset[1] as i32,
3660                             z: image_offset[2] as i32,
3661                         },
3662                         image_extent: ash::vk::Extent3D {
3663                             width: image_extent[0],
3664                             height: image_extent[1],
3665                             depth: image_extent[2],
3666                         },
3667                     }
3668                 })
3669                 .collect();
3670 
3671             (fns.v1_0.cmd_copy_image_to_buffer)(
3672                 self.handle,
3673                 src_image_inner.image.handle(),
3674                 src_image_layout.into(),
3675                 dst_buffer.buffer().handle(),
3676                 regions.len() as u32,
3677                 regions.as_ptr(),
3678             );
3679         }
3680     }
3681 
3682     /// Calls `vkCmdBlitImage` on the builder.
3683     ///
3684     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
3685     /// usage of the command anyway.
3686     #[inline]
blit_image(&mut self, blit_image_info: &BlitImageInfo)3687     pub unsafe fn blit_image(&mut self, blit_image_info: &BlitImageInfo) {
3688         let &BlitImageInfo {
3689             ref src_image,
3690             src_image_layout,
3691             ref dst_image,
3692             dst_image_layout,
3693             ref regions,
3694             filter,
3695             _ne,
3696         } = blit_image_info;
3697 
3698         if regions.is_empty() {
3699             return;
3700         }
3701 
3702         let src_image_inner = src_image.inner();
3703         let dst_image_inner = dst_image.inner();
3704 
3705         let fns = self.device.fns();
3706 
3707         if self.device.api_version() >= Version::V1_3
3708             || self.device.enabled_extensions().khr_copy_commands2
3709         {
3710             let regions: SmallVec<[_; 8]> = regions
3711                 .into_iter()
3712                 .map(|region| {
3713                     let &ImageBlit {
3714                         ref src_subresource,
3715                         src_offsets,
3716                         ref dst_subresource,
3717                         dst_offsets,
3718                         _ne: _,
3719                     } = region;
3720 
3721                     let mut src_subresource = src_subresource.clone();
3722                     src_subresource.array_layers.start += src_image_inner.first_layer;
3723                     src_subresource.array_layers.end += src_image_inner.first_layer;
3724                     src_subresource.mip_level += src_image_inner.first_mipmap_level;
3725 
3726                     let mut dst_subresource = dst_subresource.clone();
3727                     dst_subresource.array_layers.start += dst_image_inner.first_layer;
3728                     dst_subresource.array_layers.end += dst_image_inner.first_layer;
3729                     dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
3730 
3731                     ash::vk::ImageBlit2 {
3732                         src_subresource: src_subresource.into(),
3733                         src_offsets: [
3734                             ash::vk::Offset3D {
3735                                 x: src_offsets[0][0] as i32,
3736                                 y: src_offsets[0][1] as i32,
3737                                 z: src_offsets[0][2] as i32,
3738                             },
3739                             ash::vk::Offset3D {
3740                                 x: src_offsets[1][0] as i32,
3741                                 y: src_offsets[1][1] as i32,
3742                                 z: src_offsets[1][2] as i32,
3743                             },
3744                         ],
3745                         dst_subresource: dst_subresource.into(),
3746                         dst_offsets: [
3747                             ash::vk::Offset3D {
3748                                 x: dst_offsets[0][0] as i32,
3749                                 y: dst_offsets[0][1] as i32,
3750                                 z: dst_offsets[0][2] as i32,
3751                             },
3752                             ash::vk::Offset3D {
3753                                 x: dst_offsets[1][0] as i32,
3754                                 y: dst_offsets[1][1] as i32,
3755                                 z: dst_offsets[1][2] as i32,
3756                             },
3757                         ],
3758                         ..Default::default()
3759                     }
3760                 })
3761                 .collect();
3762 
3763             let blit_image_info = ash::vk::BlitImageInfo2 {
3764                 src_image: src_image_inner.image.handle(),
3765                 src_image_layout: src_image_layout.into(),
3766                 dst_image: dst_image_inner.image.handle(),
3767                 dst_image_layout: dst_image_layout.into(),
3768                 region_count: regions.len() as u32,
3769                 p_regions: regions.as_ptr(),
3770                 filter: filter.into(),
3771                 ..Default::default()
3772             };
3773 
3774             if self.device.api_version() >= Version::V1_3 {
3775                 (fns.v1_3.cmd_blit_image2)(self.handle, &blit_image_info);
3776             } else {
3777                 (fns.khr_copy_commands2.cmd_blit_image2_khr)(self.handle, &blit_image_info);
3778             }
3779         } else {
3780             let regions: SmallVec<[_; 8]> = regions
3781                 .into_iter()
3782                 .map(|region| {
3783                     let &ImageBlit {
3784                         ref src_subresource,
3785                         src_offsets,
3786                         ref dst_subresource,
3787                         dst_offsets,
3788                         _ne: _,
3789                     } = region;
3790 
3791                     let mut src_subresource = src_subresource.clone();
3792                     src_subresource.array_layers.start += src_image_inner.first_layer;
3793                     src_subresource.array_layers.end += src_image_inner.first_layer;
3794                     src_subresource.mip_level += src_image_inner.first_mipmap_level;
3795 
3796                     let mut dst_subresource = dst_subresource.clone();
3797                     dst_subresource.array_layers.start += dst_image_inner.first_layer;
3798                     dst_subresource.array_layers.end += dst_image_inner.first_layer;
3799                     dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
3800 
3801                     ash::vk::ImageBlit {
3802                         src_subresource: src_subresource.into(),
3803                         src_offsets: [
3804                             ash::vk::Offset3D {
3805                                 x: src_offsets[0][0] as i32,
3806                                 y: src_offsets[0][1] as i32,
3807                                 z: src_offsets[0][2] as i32,
3808                             },
3809                             ash::vk::Offset3D {
3810                                 x: src_offsets[1][0] as i32,
3811                                 y: src_offsets[1][1] as i32,
3812                                 z: src_offsets[1][2] as i32,
3813                             },
3814                         ],
3815                         dst_subresource: dst_subresource.into(),
3816                         dst_offsets: [
3817                             ash::vk::Offset3D {
3818                                 x: dst_offsets[0][0] as i32,
3819                                 y: dst_offsets[0][1] as i32,
3820                                 z: dst_offsets[0][2] as i32,
3821                             },
3822                             ash::vk::Offset3D {
3823                                 x: dst_offsets[1][0] as i32,
3824                                 y: dst_offsets[1][1] as i32,
3825                                 z: dst_offsets[1][2] as i32,
3826                             },
3827                         ],
3828                     }
3829                 })
3830                 .collect();
3831 
3832             (fns.v1_0.cmd_blit_image)(
3833                 self.handle,
3834                 src_image_inner.image.handle(),
3835                 src_image_layout.into(),
3836                 dst_image_inner.image.handle(),
3837                 dst_image_layout.into(),
3838                 regions.len() as u32,
3839                 regions.as_ptr(),
3840                 filter.into(),
3841             );
3842         }
3843     }
3844 
3845     /// Calls `vkCmdResolveImage` on the builder.
3846     ///
3847     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
3848     /// usage of the command anyway.
3849     #[inline]
resolve_image(&mut self, resolve_image_info: &ResolveImageInfo)3850     pub unsafe fn resolve_image(&mut self, resolve_image_info: &ResolveImageInfo) {
3851         let &ResolveImageInfo {
3852             ref src_image,
3853             src_image_layout,
3854             ref dst_image,
3855             dst_image_layout,
3856             ref regions,
3857             _ne: _,
3858         } = resolve_image_info;
3859 
3860         if regions.is_empty() {
3861             return;
3862         }
3863 
3864         let src_image_inner = src_image.inner();
3865         let dst_image_inner = dst_image.inner();
3866 
3867         let fns = self.device.fns();
3868 
3869         if self.device.api_version() >= Version::V1_3
3870             || self.device.enabled_extensions().khr_copy_commands2
3871         {
3872             let regions: SmallVec<[_; 8]> = regions
3873                 .into_iter()
3874                 .map(|region| {
3875                     let &ImageResolve {
3876                         ref src_subresource,
3877                         src_offset,
3878                         ref dst_subresource,
3879                         dst_offset,
3880                         extent,
3881                         _ne: _,
3882                     } = region;
3883 
3884                     let mut src_subresource = src_subresource.clone();
3885                     src_subresource.array_layers.start += src_image_inner.first_layer;
3886                     src_subresource.array_layers.end += src_image_inner.first_layer;
3887                     src_subresource.mip_level += src_image_inner.first_mipmap_level;
3888 
3889                     let mut dst_subresource = dst_subresource.clone();
3890                     dst_subresource.array_layers.start += dst_image_inner.first_layer;
3891                     dst_subresource.array_layers.end += dst_image_inner.first_layer;
3892                     dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
3893 
3894                     ash::vk::ImageResolve2 {
3895                         src_subresource: src_subresource.into(),
3896                         src_offset: ash::vk::Offset3D {
3897                             x: src_offset[0] as i32,
3898                             y: src_offset[1] as i32,
3899                             z: src_offset[2] as i32,
3900                         },
3901                         dst_subresource: dst_subresource.into(),
3902                         dst_offset: ash::vk::Offset3D {
3903                             x: dst_offset[0] as i32,
3904                             y: dst_offset[1] as i32,
3905                             z: dst_offset[2] as i32,
3906                         },
3907                         extent: ash::vk::Extent3D {
3908                             width: extent[0],
3909                             height: extent[1],
3910                             depth: extent[2],
3911                         },
3912                         ..Default::default()
3913                     }
3914                 })
3915                 .collect();
3916 
3917             let resolve_image_info = ash::vk::ResolveImageInfo2 {
3918                 src_image: src_image_inner.image.handle(),
3919                 src_image_layout: src_image_layout.into(),
3920                 dst_image: dst_image_inner.image.handle(),
3921                 dst_image_layout: dst_image_layout.into(),
3922                 region_count: regions.len() as u32,
3923                 p_regions: regions.as_ptr(),
3924                 ..Default::default()
3925             };
3926 
3927             if self.device.api_version() >= Version::V1_3 {
3928                 (fns.v1_3.cmd_resolve_image2)(self.handle, &resolve_image_info);
3929             } else {
3930                 (fns.khr_copy_commands2.cmd_resolve_image2_khr)(self.handle, &resolve_image_info);
3931             }
3932         } else {
3933             let regions: SmallVec<[_; 8]> = regions
3934                 .into_iter()
3935                 .map(|region| {
3936                     let &ImageResolve {
3937                         ref src_subresource,
3938                         src_offset,
3939                         ref dst_subresource,
3940                         dst_offset,
3941                         extent,
3942                         _ne: _,
3943                     } = region;
3944 
3945                     let mut src_subresource = src_subresource.clone();
3946                     src_subresource.array_layers.start += src_image_inner.first_layer;
3947                     src_subresource.array_layers.end += src_image_inner.first_layer;
3948                     src_subresource.mip_level += src_image_inner.first_mipmap_level;
3949 
3950                     let mut dst_subresource = dst_subresource.clone();
3951                     dst_subresource.array_layers.start += dst_image_inner.first_layer;
3952                     dst_subresource.array_layers.end += dst_image_inner.first_layer;
3953                     dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
3954 
3955                     ash::vk::ImageResolve {
3956                         src_subresource: src_subresource.into(),
3957                         src_offset: ash::vk::Offset3D {
3958                             x: src_offset[0] as i32,
3959                             y: src_offset[1] as i32,
3960                             z: src_offset[2] as i32,
3961                         },
3962                         dst_subresource: dst_subresource.into(),
3963                         dst_offset: ash::vk::Offset3D {
3964                             x: dst_offset[0] as i32,
3965                             y: dst_offset[1] as i32,
3966                             z: dst_offset[2] as i32,
3967                         },
3968                         extent: ash::vk::Extent3D {
3969                             width: extent[0],
3970                             height: extent[1],
3971                             depth: extent[2],
3972                         },
3973                     }
3974                 })
3975                 .collect();
3976 
3977             (fns.v1_0.cmd_resolve_image)(
3978                 self.handle,
3979                 src_image_inner.image.handle(),
3980                 src_image_layout.into(),
3981                 dst_image_inner.image.handle(),
3982                 dst_image_layout.into(),
3983                 regions.len() as u32,
3984                 regions.as_ptr(),
3985             );
3986         }
3987     }
3988 }
3989 
3990 /// Parameters to copy data from a buffer to another buffer.
3991 ///
3992 /// The fields of `regions` represent bytes.
3993 #[derive(Clone, Debug)]
3994 pub struct CopyBufferInfo {
3995     /// The buffer to copy from.
3996     ///
3997     /// There is no default value.
3998     pub src_buffer: Subbuffer<[u8]>,
3999 
4000     /// The buffer to copy to.
4001     ///
4002     /// There is no default value.
4003     pub dst_buffer: Subbuffer<[u8]>,
4004 
4005     /// The regions of both buffers to copy between, specified in bytes.
4006     ///
4007     /// The default value is a single region, with zero offsets and a `size` equal to the smallest
4008     /// of the two buffers.
4009     pub regions: SmallVec<[BufferCopy; 1]>,
4010 
4011     pub _ne: crate::NonExhaustive,
4012 }
4013 
4014 impl CopyBufferInfo {
4015     /// Returns a `CopyBufferInfo` with the specified `src_buffer` and `dst_buffer`.
4016     #[inline]
buffers(src_buffer: Subbuffer<impl ?Sized>, dst_buffer: Subbuffer<impl ?Sized>) -> Self4017     pub fn buffers(src_buffer: Subbuffer<impl ?Sized>, dst_buffer: Subbuffer<impl ?Sized>) -> Self {
4018         let region = BufferCopy {
4019             src_offset: 0,
4020             dst_offset: 0,
4021             size: min(src_buffer.size(), dst_buffer.size()),
4022             ..Default::default()
4023         };
4024 
4025         Self {
4026             src_buffer: src_buffer.into_bytes(),
4027             dst_buffer: dst_buffer.into_bytes(),
4028             regions: smallvec![region],
4029             _ne: crate::NonExhaustive(()),
4030         }
4031     }
4032 }
4033 
4034 /// Parameters to copy data from a buffer to another buffer, with type information.
4035 ///
4036 /// The fields of `regions` represent elements of `T`.
4037 #[derive(Clone, Debug)]
4038 pub struct CopyBufferInfoTyped<T> {
4039     /// The buffer to copy from.
4040     ///
4041     /// There is no default value.
4042     pub src_buffer: Subbuffer<[T]>,
4043 
4044     /// The buffer to copy to.
4045     ///
4046     /// There is no default value.
4047     pub dst_buffer: Subbuffer<[T]>,
4048 
4049     /// The regions of both buffers to copy between, specified in elements of `T`.
4050     ///
4051     /// The default value is a single region, with zero offsets and a `size` equal to the smallest
4052     /// of the two buffers.
4053     pub regions: SmallVec<[BufferCopy; 1]>,
4054 
4055     pub _ne: crate::NonExhaustive,
4056 }
4057 
4058 impl<T> CopyBufferInfoTyped<T> {
4059     /// Returns a `CopyBufferInfoTyped` with the specified `src_buffer` and `dst_buffer`.
buffers(src_buffer: Subbuffer<[T]>, dst_buffer: Subbuffer<[T]>) -> Self4060     pub fn buffers(src_buffer: Subbuffer<[T]>, dst_buffer: Subbuffer<[T]>) -> Self {
4061         let region = BufferCopy {
4062             size: min(src_buffer.len(), dst_buffer.len()),
4063             ..Default::default()
4064         };
4065 
4066         Self {
4067             src_buffer,
4068             dst_buffer,
4069             regions: smallvec![region],
4070             _ne: crate::NonExhaustive(()),
4071         }
4072     }
4073 }
4074 
4075 impl<T> From<CopyBufferInfoTyped<T>> for CopyBufferInfo {
from(typed: CopyBufferInfoTyped<T>) -> Self4076     fn from(typed: CopyBufferInfoTyped<T>) -> Self {
4077         let CopyBufferInfoTyped {
4078             src_buffer,
4079             dst_buffer,
4080             mut regions,
4081             _ne: _,
4082         } = typed;
4083 
4084         for region in &mut regions {
4085             region.src_offset *= size_of::<T>() as DeviceSize;
4086             region.dst_offset *= size_of::<T>() as DeviceSize;
4087             region.size *= size_of::<T>() as DeviceSize;
4088         }
4089 
4090         Self {
4091             src_buffer: src_buffer.as_bytes().clone(),
4092             dst_buffer: dst_buffer.as_bytes().clone(),
4093             regions,
4094             _ne: crate::NonExhaustive(()),
4095         }
4096     }
4097 }
4098 
4099 /// A region of data to copy between buffers.
4100 #[derive(Clone, Debug)]
4101 pub struct BufferCopy {
4102     /// The offset in bytes or elements from the start of `src_buffer` that copying will
4103     /// start from.
4104     ///
4105     /// The default value is `0`.
4106     pub src_offset: DeviceSize,
4107 
4108     /// The offset in bytes or elements from the start of `dst_buffer` that copying will
4109     /// start from.
4110     ///
4111     /// The default value is `0`.
4112     pub dst_offset: DeviceSize,
4113 
4114     /// The number of bytes or elements to copy.
4115     ///
4116     /// The default value is `0`, which must be overridden.
4117     pub size: DeviceSize,
4118 
4119     pub _ne: crate::NonExhaustive,
4120 }
4121 
4122 impl Default for BufferCopy {
4123     #[inline]
default() -> Self4124     fn default() -> Self {
4125         Self {
4126             src_offset: 0,
4127             dst_offset: 0,
4128             size: 0,
4129             _ne: crate::NonExhaustive(()),
4130         }
4131     }
4132 }
4133 
4134 /// Parameters to copy data from an image to another image.
4135 #[derive(Clone, Debug)]
4136 pub struct CopyImageInfo {
4137     /// The image to copy from.
4138     ///
4139     /// There is no default value.
4140     pub src_image: Arc<dyn ImageAccess>,
4141 
4142     /// The layout used for `src_image` during the copy operation.
4143     ///
4144     /// The following layouts are allowed:
4145     /// - [`ImageLayout::TransferSrcOptimal`]
4146     /// - [`ImageLayout::General`]
4147     ///
4148     /// The default value is [`ImageLayout::TransferSrcOptimal`].
4149     pub src_image_layout: ImageLayout,
4150 
4151     /// The image to copy to.
4152     ///
4153     /// There is no default value.
4154     pub dst_image: Arc<dyn ImageAccess>,
4155 
4156     /// The layout used for `dst_image` during the copy operation.
4157     ///
4158     /// The following layouts are allowed:
4159     /// - [`ImageLayout::TransferDstOptimal`]
4160     /// - [`ImageLayout::General`]
4161     ///
4162     /// The default value is [`ImageLayout::TransferDstOptimal`].
4163     pub dst_image_layout: ImageLayout,
4164 
4165     /// The regions of both images to copy between.
4166     ///
4167     /// The default value is a single region, covering the first mip level, and the smallest of the
4168     /// array layers and extent of the two images. All aspects of each image are selected, or
4169     /// `plane0` if the image is multi-planar.
4170     pub regions: SmallVec<[ImageCopy; 1]>,
4171 
4172     pub _ne: crate::NonExhaustive,
4173 }
4174 
4175 impl CopyImageInfo {
4176     /// Returns a `CopyImageInfo` with the specified `src_image` and `dst_image`.
4177     #[inline]
images(src_image: Arc<dyn ImageAccess>, dst_image: Arc<dyn ImageAccess>) -> Self4178     pub fn images(src_image: Arc<dyn ImageAccess>, dst_image: Arc<dyn ImageAccess>) -> Self {
4179         let min_array_layers = src_image
4180             .dimensions()
4181             .array_layers()
4182             .min(dst_image.dimensions().array_layers());
4183         let region = ImageCopy {
4184             src_subresource: ImageSubresourceLayers {
4185                 array_layers: 0..min_array_layers,
4186                 ..src_image.subresource_layers()
4187             },
4188             dst_subresource: ImageSubresourceLayers {
4189                 array_layers: 0..min_array_layers,
4190                 ..dst_image.subresource_layers()
4191             },
4192             extent: {
4193                 let src_extent = src_image.dimensions().width_height_depth();
4194                 let dst_extent = dst_image.dimensions().width_height_depth();
4195 
4196                 [
4197                     src_extent[0].min(dst_extent[0]),
4198                     src_extent[1].min(dst_extent[1]),
4199                     src_extent[2].min(dst_extent[2]),
4200                 ]
4201             },
4202             ..Default::default()
4203         };
4204 
4205         Self {
4206             src_image,
4207             src_image_layout: ImageLayout::TransferSrcOptimal,
4208             dst_image,
4209             dst_image_layout: ImageLayout::TransferDstOptimal,
4210             regions: smallvec![region],
4211             _ne: crate::NonExhaustive(()),
4212         }
4213     }
4214 }
4215 
4216 /// A region of data to copy between images.
4217 #[derive(Clone, Debug)]
4218 pub struct ImageCopy {
4219     /// The subresource of `src_image` to copy from.
4220     ///
4221     /// The default value is empty, which must be overridden.
4222     pub src_subresource: ImageSubresourceLayers,
4223 
4224     /// The offset from the zero coordinate of `src_image` that copying will start from.
4225     ///
4226     /// The default value is `[0; 3]`.
4227     pub src_offset: [u32; 3],
4228 
4229     /// The subresource of `dst_image` to copy to.
4230     ///
4231     /// The default value is empty, which must be overridden.
4232     pub dst_subresource: ImageSubresourceLayers,
4233 
4234     /// The offset from the zero coordinate of `dst_image` that copying will start from.
4235     ///
4236     /// The default value is `[0; 3]`.
4237     pub dst_offset: [u32; 3],
4238 
4239     /// The extent of texels to copy.
4240     ///
4241     /// The default value is `[0; 3]`, which must be overridden.
4242     pub extent: [u32; 3],
4243 
4244     pub _ne: crate::NonExhaustive,
4245 }
4246 
4247 impl Default for ImageCopy {
4248     #[inline]
default() -> Self4249     fn default() -> Self {
4250         Self {
4251             src_subresource: ImageSubresourceLayers {
4252                 aspects: ImageAspects::empty(),
4253                 mip_level: 0,
4254                 array_layers: 0..0,
4255             },
4256             src_offset: [0; 3],
4257             dst_subresource: ImageSubresourceLayers {
4258                 aspects: ImageAspects::empty(),
4259                 mip_level: 0,
4260                 array_layers: 0..0,
4261             },
4262             dst_offset: [0; 3],
4263             extent: [0; 3],
4264             _ne: crate::NonExhaustive(()),
4265         }
4266     }
4267 }
4268 
4269 /// Parameters to copy data from a buffer to an image.
4270 #[derive(Clone, Debug)]
4271 pub struct CopyBufferToImageInfo {
4272     /// The buffer to copy from.
4273     ///
4274     /// There is no default value.
4275     pub src_buffer: Subbuffer<[u8]>,
4276 
4277     /// The image to copy to.
4278     ///
4279     /// There is no default value.
4280     pub dst_image: Arc<dyn ImageAccess>,
4281 
4282     /// The layout used for `dst_image` during the copy operation.
4283     ///
4284     /// The following layouts are allowed:
4285     /// - [`ImageLayout::TransferDstOptimal`]
4286     /// - [`ImageLayout::General`]
4287     ///
4288     /// The default value is [`ImageLayout::TransferDstOptimal`].
4289     pub dst_image_layout: ImageLayout,
4290 
4291     /// The regions of the buffer and image to copy between.
4292     ///
4293     /// The default value is a single region, covering all of the buffer and the first mip level of
4294     /// the image. All aspects of the image are selected, or `plane0` if the image is multi-planar.
4295     pub regions: SmallVec<[BufferImageCopy; 1]>,
4296 
4297     pub _ne: crate::NonExhaustive,
4298 }
4299 
4300 impl CopyBufferToImageInfo {
4301     /// Returns a `CopyBufferToImageInfo` with the specified `src_buffer` and
4302     /// `dst_image`.
4303     #[inline]
buffer_image( src_buffer: Subbuffer<impl ?Sized>, dst_image: Arc<dyn ImageAccess>, ) -> Self4304     pub fn buffer_image(
4305         src_buffer: Subbuffer<impl ?Sized>,
4306         dst_image: Arc<dyn ImageAccess>,
4307     ) -> Self {
4308         let region = BufferImageCopy {
4309             image_subresource: dst_image.subresource_layers(),
4310             image_extent: dst_image.dimensions().width_height_depth(),
4311             ..Default::default()
4312         };
4313 
4314         Self {
4315             src_buffer: src_buffer.into_bytes(),
4316             dst_image,
4317             dst_image_layout: ImageLayout::TransferDstOptimal,
4318             regions: smallvec![region],
4319             _ne: crate::NonExhaustive(()),
4320         }
4321     }
4322 }
4323 
4324 /// Parameters to copy data from an image to a buffer.
4325 #[derive(Clone, Debug)]
4326 pub struct CopyImageToBufferInfo {
4327     /// The image to copy from.
4328     ///
4329     /// There is no default value.
4330     pub src_image: Arc<dyn ImageAccess>,
4331 
4332     /// The layout used for `src_image` during the copy operation.
4333     ///
4334     /// The following layouts are allowed:
4335     /// - [`ImageLayout::TransferSrcOptimal`]
4336     /// - [`ImageLayout::General`]
4337     ///
4338     /// The default value is [`ImageLayout::TransferSrcOptimal`].
4339     pub src_image_layout: ImageLayout,
4340 
4341     /// The buffer to copy to.
4342     ///
4343     /// There is no default value.
4344     pub dst_buffer: Subbuffer<[u8]>,
4345 
4346     /// The regions of the image and buffer to copy between.
4347     ///
4348     /// The default value is a single region, covering all of the buffer and the first mip level of
4349     /// the image. All aspects of the image are selected, or `plane0` if the image is multi-planar.
4350     pub regions: SmallVec<[BufferImageCopy; 1]>,
4351 
4352     pub _ne: crate::NonExhaustive,
4353 }
4354 
4355 impl CopyImageToBufferInfo {
4356     /// Returns a `CopyImageToBufferInfo` with the specified `src_image` and
4357     /// `dst_buffer`.
4358     #[inline]
image_buffer( src_image: Arc<dyn ImageAccess>, dst_buffer: Subbuffer<impl ?Sized>, ) -> Self4359     pub fn image_buffer(
4360         src_image: Arc<dyn ImageAccess>,
4361         dst_buffer: Subbuffer<impl ?Sized>,
4362     ) -> Self {
4363         let region = BufferImageCopy {
4364             image_subresource: src_image.subresource_layers(),
4365             image_extent: src_image.dimensions().width_height_depth(),
4366             ..Default::default()
4367         };
4368 
4369         Self {
4370             src_image,
4371             src_image_layout: ImageLayout::TransferSrcOptimal,
4372             dst_buffer: dst_buffer.into_bytes(),
4373             regions: smallvec![region],
4374             _ne: crate::NonExhaustive(()),
4375         }
4376     }
4377 }
4378 
4379 /// A region of data to copy between a buffer and an image.
4380 #[derive(Clone, Debug)]
4381 pub struct BufferImageCopy {
4382     /// The offset in bytes from the start of the buffer that copying will start from.
4383     ///
4384     /// The default value is `0`.
4385     pub buffer_offset: DeviceSize,
4386 
4387     /// The number of texels between successive rows of image data in the buffer.
4388     ///
4389     /// If set to `0`, the width of the image is used.
4390     ///
4391     /// The default value is `0`.
4392     pub buffer_row_length: u32,
4393 
4394     /// The number of rows between successive depth slices of image data in the buffer.
4395     ///
4396     /// If set to `0`, the height of the image is used.
4397     ///
4398     /// The default value is `0`.
4399     pub buffer_image_height: u32,
4400 
4401     /// The subresource of the image to copy from/to.
4402     ///
4403     /// The default value is empty, which must be overridden.
4404     pub image_subresource: ImageSubresourceLayers,
4405 
4406     /// The offset from the zero coordinate of the image that copying will start from.
4407     ///
4408     /// The default value is `[0; 3]`.
4409     pub image_offset: [u32; 3],
4410 
4411     /// The extent of texels in the image to copy.
4412     ///
4413     /// The default value is `[0; 3]`, which must be overridden.
4414     pub image_extent: [u32; 3],
4415 
4416     pub _ne: crate::NonExhaustive,
4417 }
4418 
4419 impl Default for BufferImageCopy {
4420     #[inline]
default() -> Self4421     fn default() -> Self {
4422         Self {
4423             buffer_offset: 0,
4424             buffer_row_length: 0,
4425             buffer_image_height: 0,
4426             image_subresource: ImageSubresourceLayers {
4427                 aspects: ImageAspects::empty(),
4428                 mip_level: 0,
4429                 array_layers: 0..0,
4430             },
4431             image_offset: [0; 3],
4432             image_extent: [0; 3],
4433             _ne: crate::NonExhaustive(()),
4434         }
4435     }
4436 }
4437 
4438 impl BufferImageCopy {
4439     // Following
4440     // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap20.html#copies-buffers-images-addressing
buffer_copy_size(&self, format: Format) -> DeviceSize4441     pub(crate) fn buffer_copy_size(&self, format: Format) -> DeviceSize {
4442         let &BufferImageCopy {
4443             buffer_offset: _,
4444             mut buffer_row_length,
4445             mut buffer_image_height,
4446             ref image_subresource,
4447             image_offset: _,
4448             mut image_extent,
4449             _ne: _,
4450         } = self;
4451 
4452         if buffer_row_length == 0 {
4453             buffer_row_length = image_extent[0];
4454         }
4455 
4456         if buffer_image_height == 0 {
4457             buffer_image_height = image_extent[1];
4458         }
4459 
4460         // Scale down from texels to texel blocks, rounding up if needed.
4461         let block_extent = format.block_extent();
4462         buffer_row_length = (buffer_row_length + block_extent[0] - 1) / block_extent[0];
4463         buffer_image_height = (buffer_image_height + block_extent[1] - 1) / block_extent[1];
4464 
4465         for i in 0..3 {
4466             image_extent[i] = (image_extent[i] + block_extent[i] - 1) / block_extent[i];
4467         }
4468 
4469         // Only one of these is greater than 1, take the greater number.
4470         image_extent[2] = max(
4471             image_extent[2],
4472             image_subresource.array_layers.end - image_subresource.array_layers.start,
4473         );
4474 
4475         let blocks_to_last_slice = (image_extent[2] as DeviceSize - 1)
4476             * buffer_image_height as DeviceSize
4477             * buffer_row_length as DeviceSize;
4478         let blocks_to_last_row =
4479             (image_extent[1] as DeviceSize - 1) * buffer_row_length as DeviceSize;
4480         let num_blocks = blocks_to_last_slice + blocks_to_last_row + image_extent[0] as DeviceSize;
4481 
4482         // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBufferImageCopy.html#_description
4483         let block_size = if image_subresource.aspects.intersects(ImageAspects::STENCIL) {
4484             1
4485         } else if image_subresource.aspects.intersects(ImageAspects::DEPTH) {
4486             match format {
4487                 Format::D16_UNORM | Format::D16_UNORM_S8_UINT => 2,
4488                 Format::D32_SFLOAT
4489                 | Format::D32_SFLOAT_S8_UINT
4490                 | Format::X8_D24_UNORM_PACK32
4491                 | Format::D24_UNORM_S8_UINT => 4,
4492                 _ => unreachable!(),
4493             }
4494         } else {
4495             format.block_size().unwrap()
4496         };
4497 
4498         num_blocks * block_size
4499     }
4500 }
4501 
4502 /// Parameters to blit image data.
4503 #[derive(Clone, Debug)]
4504 pub struct BlitImageInfo {
4505     /// The image to blit from.
4506     ///
4507     /// There is no default value.
4508     pub src_image: Arc<dyn ImageAccess>,
4509 
4510     /// The layout used for `src_image` during the blit operation.
4511     ///
4512     /// The following layouts are allowed:
4513     /// - [`ImageLayout::TransferSrcOptimal`]
4514     /// - [`ImageLayout::General`]
4515     ///
4516     /// The default value is [`ImageLayout::TransferSrcOptimal`].
4517     pub src_image_layout: ImageLayout,
4518 
4519     /// The image to blit to.
4520     ///
4521     /// There is no default value.
4522     pub dst_image: Arc<dyn ImageAccess>,
4523 
4524     /// The layout used for `dst_image` during the blit operation.
4525     ///
4526     /// The following layouts are allowed:
4527     /// - [`ImageLayout::TransferDstOptimal`]
4528     /// - [`ImageLayout::General`]
4529     ///
4530     /// The default value is [`ImageLayout::TransferDstOptimal`].
4531     pub dst_image_layout: ImageLayout,
4532 
4533     /// The regions of both images to blit between.
4534     ///
4535     /// The default value is a single region, covering the first mip level, and the smallest of the
4536     /// array layers of the two images. The whole extent of each image is covered, scaling if
4537     /// necessary. All aspects of each image are selected, or `plane0` if the image is multi-planar.
4538     pub regions: SmallVec<[ImageBlit; 1]>,
4539 
4540     /// The filter to use for sampling `src_image` when the `src_extent` and
4541     /// `dst_extent` of a region are not the same size.
4542     ///
4543     /// The default value is [`Filter::Nearest`].
4544     pub filter: Filter,
4545 
4546     pub _ne: crate::NonExhaustive,
4547 }
4548 
4549 impl BlitImageInfo {
4550     /// Returns a `BlitImageInfo` with the specified `src_image` and `dst_image`.
4551     #[inline]
images(src_image: Arc<dyn ImageAccess>, dst_image: Arc<dyn ImageAccess>) -> Self4552     pub fn images(src_image: Arc<dyn ImageAccess>, dst_image: Arc<dyn ImageAccess>) -> Self {
4553         let min_array_layers = src_image
4554             .dimensions()
4555             .array_layers()
4556             .min(dst_image.dimensions().array_layers());
4557         let region = ImageBlit {
4558             src_subresource: ImageSubresourceLayers {
4559                 array_layers: 0..min_array_layers,
4560                 ..src_image.subresource_layers()
4561             },
4562             src_offsets: [[0; 3], src_image.dimensions().width_height_depth()],
4563             dst_subresource: ImageSubresourceLayers {
4564                 array_layers: 0..min_array_layers,
4565                 ..dst_image.subresource_layers()
4566             },
4567             dst_offsets: [[0; 3], dst_image.dimensions().width_height_depth()],
4568             ..Default::default()
4569         };
4570 
4571         Self {
4572             src_image,
4573             src_image_layout: ImageLayout::TransferSrcOptimal,
4574             dst_image,
4575             dst_image_layout: ImageLayout::TransferDstOptimal,
4576             regions: smallvec![region],
4577             filter: Filter::Nearest,
4578             _ne: crate::NonExhaustive(()),
4579         }
4580     }
4581 }
4582 
4583 /// A region of data to blit between images.
4584 #[derive(Clone, Debug)]
4585 pub struct ImageBlit {
4586     /// The subresource of `src_image` to blit from.
4587     ///
4588     /// The default value is empty, which must be overridden.
4589     pub src_subresource: ImageSubresourceLayers,
4590 
4591     /// The offsets from the zero coordinate of `src_image`, defining two corners of the region
4592     /// to blit from.
4593     /// If the ordering of the two offsets differs between source and destination, the image will
4594     /// be flipped.
4595     ///
4596     /// The default value is `[[0; 3]; 2]`, which must be overridden.
4597     pub src_offsets: [[u32; 3]; 2],
4598 
4599     /// The subresource of `dst_image` to blit to.
4600     ///
4601     /// The default value is empty, which must be overridden.
4602     pub dst_subresource: ImageSubresourceLayers,
4603 
4604     /// The offset from the zero coordinate of `dst_image` defining two corners of the
4605     /// region to blit to.
4606     /// If the ordering of the two offsets differs between source and destination, the image will
4607     /// be flipped.
4608     ///
4609     /// The default value is `[[0; 3]; 2]`, which must be overridden.
4610     pub dst_offsets: [[u32; 3]; 2],
4611 
4612     pub _ne: crate::NonExhaustive,
4613 }
4614 
4615 impl Default for ImageBlit {
4616     #[inline]
default() -> Self4617     fn default() -> Self {
4618         Self {
4619             src_subresource: ImageSubresourceLayers {
4620                 aspects: ImageAspects::empty(),
4621                 mip_level: 0,
4622                 array_layers: 0..0,
4623             },
4624             src_offsets: [[0; 3]; 2],
4625             dst_subresource: ImageSubresourceLayers {
4626                 aspects: ImageAspects::empty(),
4627                 mip_level: 0,
4628                 array_layers: 0..0,
4629             },
4630             dst_offsets: [[0; 3]; 2],
4631             _ne: crate::NonExhaustive(()),
4632         }
4633     }
4634 }
4635 
4636 /// Parameters to resolve image data.
4637 #[derive(Clone, Debug)]
4638 pub struct ResolveImageInfo {
4639     /// The multisampled image to resolve from.
4640     ///
4641     /// There is no default value.
4642     pub src_image: Arc<dyn ImageAccess>,
4643 
4644     /// The layout used for `src_image` during the resolve operation.
4645     ///
4646     /// The following layouts are allowed:
4647     /// - [`ImageLayout::TransferSrcOptimal`]
4648     /// - [`ImageLayout::General`]
4649     ///
4650     /// The default value is [`ImageLayout::TransferSrcOptimal`].
4651     pub src_image_layout: ImageLayout,
4652 
4653     /// The non-multisampled image to resolve into.
4654     ///
4655     /// There is no default value.
4656     pub dst_image: Arc<dyn ImageAccess>,
4657 
4658     /// The layout used for `dst_image` during the resolve operation.
4659     ///
4660     /// The following layouts are allowed:
4661     /// - [`ImageLayout::TransferDstOptimal`]
4662     /// - [`ImageLayout::General`]
4663     ///
4664     /// The default value is [`ImageLayout::TransferDstOptimal`].
4665     pub dst_image_layout: ImageLayout,
4666 
4667     /// The regions of both images to resolve between.
4668     ///
4669     /// The default value is a single region, covering the first mip level, and the smallest of the
4670     /// array layers and extent of the two images. All aspects of each image are selected, or
4671     /// `plane0` if the image is multi-planar.
4672     pub regions: SmallVec<[ImageResolve; 1]>,
4673 
4674     pub _ne: crate::NonExhaustive,
4675 }
4676 
4677 impl ResolveImageInfo {
4678     /// Returns a `ResolveImageInfo` with the specified `src_image` and `dst_image`.
4679     #[inline]
images(src_image: Arc<dyn ImageAccess>, dst_image: Arc<dyn ImageAccess>) -> Self4680     pub fn images(src_image: Arc<dyn ImageAccess>, dst_image: Arc<dyn ImageAccess>) -> Self {
4681         let min_array_layers = src_image
4682             .dimensions()
4683             .array_layers()
4684             .min(dst_image.dimensions().array_layers());
4685         let region = ImageResolve {
4686             src_subresource: ImageSubresourceLayers {
4687                 array_layers: 0..min_array_layers,
4688                 ..src_image.subresource_layers()
4689             },
4690             dst_subresource: ImageSubresourceLayers {
4691                 array_layers: 0..min_array_layers,
4692                 ..dst_image.subresource_layers()
4693             },
4694             extent: {
4695                 let src_extent = src_image.dimensions().width_height_depth();
4696                 let dst_extent = dst_image.dimensions().width_height_depth();
4697 
4698                 [
4699                     src_extent[0].min(dst_extent[0]),
4700                     src_extent[1].min(dst_extent[1]),
4701                     src_extent[2].min(dst_extent[2]),
4702                 ]
4703             },
4704             ..Default::default()
4705         };
4706 
4707         Self {
4708             src_image,
4709             src_image_layout: ImageLayout::TransferSrcOptimal,
4710             dst_image,
4711             dst_image_layout: ImageLayout::TransferDstOptimal,
4712             regions: smallvec![region],
4713             _ne: crate::NonExhaustive(()),
4714         }
4715     }
4716 }
4717 
4718 /// A region of data to resolve between images.
4719 #[derive(Clone, Debug)]
4720 pub struct ImageResolve {
4721     /// The subresource of `src_image` to resolve from.
4722     ///
4723     /// The default value is empty, which must be overridden.
4724     pub src_subresource: ImageSubresourceLayers,
4725 
4726     /// The offset from the zero coordinate of `src_image` that resolving will start from.
4727     ///
4728     /// The default value is `[0; 3]`.
4729     pub src_offset: [u32; 3],
4730 
4731     /// The subresource of `dst_image` to resolve into.
4732     ///
4733     /// The default value is empty, which must be overridden.
4734     pub dst_subresource: ImageSubresourceLayers,
4735 
4736     /// The offset from the zero coordinate of `dst_image` that resolving will start from.
4737     ///
4738     /// The default value is `[0; 3]`.
4739     pub dst_offset: [u32; 3],
4740 
4741     /// The extent of texels to resolve.
4742     ///
4743     /// The default value is `[0; 3]`, which must be overridden.
4744     pub extent: [u32; 3],
4745 
4746     pub _ne: crate::NonExhaustive,
4747 }
4748 
4749 impl Default for ImageResolve {
4750     #[inline]
default() -> Self4751     fn default() -> Self {
4752         Self {
4753             src_subresource: ImageSubresourceLayers {
4754                 aspects: ImageAspects::empty(),
4755                 mip_level: 0,
4756                 array_layers: 0..0,
4757             },
4758             src_offset: [0; 3],
4759             dst_subresource: ImageSubresourceLayers {
4760                 aspects: ImageAspects::empty(),
4761                 mip_level: 0,
4762                 array_layers: 0..0,
4763             },
4764             dst_offset: [0; 3],
4765             extent: [0; 3],
4766             _ne: crate::NonExhaustive(()),
4767         }
4768     }
4769 }
4770 
4771 /// Error that can happen when recording a copy command.
4772 #[derive(Clone, Debug)]
4773 pub enum CopyError {
4774     SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
4775 
4776     RequirementNotMet {
4777         required_for: &'static str,
4778         requires_one_of: RequiresOneOf,
4779     },
4780 
4781     /// Operation forbidden inside of a render pass.
4782     ForbiddenInsideRenderPass,
4783 
4784     /// The queue family doesn't allow this operation.
4785     NotSupportedByQueueFamily,
4786 
4787     /// The array layer counts of the source and destination subresource ranges of a region do not
4788     /// match.
4789     ArrayLayerCountMismatch {
4790         region_index: usize,
4791         src_layer_count: u32,
4792         dst_layer_count: u32,
4793     },
4794 
4795     /// The end of the range of accessed array layers of the subresource range of a region is
4796     /// greater than the number of array layers in the image.
4797     ArrayLayersOutOfRange {
4798         resource: CopyErrorResource,
4799         region_index: usize,
4800         array_layers_range_end: u32,
4801         image_array_layers: u32,
4802     },
4803 
4804     /// The aspects of the source and destination subresource ranges of a region do not match.
4805     AspectsMismatch {
4806         region_index: usize,
4807         src_aspects: ImageAspects,
4808         dst_aspects: ImageAspects,
4809     },
4810 
4811     /// The aspects of the subresource range of a region contain aspects that are not present
4812     /// in the image, or that are not allowed.
4813     AspectsNotAllowed {
4814         resource: CopyErrorResource,
4815         region_index: usize,
4816         aspects: ImageAspects,
4817         allowed_aspects: ImageAspects,
4818     },
4819 
4820     /// The buffer image height of a region is not a multiple of the required buffer alignment.
4821     BufferImageHeightNotAligned {
4822         resource: CopyErrorResource,
4823         region_index: usize,
4824         image_height: u32,
4825         required_alignment: u32,
4826     },
4827 
4828     /// The buffer image height of a region is smaller than the image extent height.
4829     BufferImageHeightTooSmall {
4830         resource: CopyErrorResource,
4831         region_index: usize,
4832         image_height: u32,
4833         min: u32,
4834     },
4835 
4836     /// The buffer row length of a region is not a multiple of the required buffer alignment.
4837     BufferRowLengthNotAligned {
4838         resource: CopyErrorResource,
4839         region_index: usize,
4840         row_length: u32,
4841         required_alignment: u32,
4842     },
4843 
4844     /// The buffer row length of a region specifies a row of texels that is greater than 0x7FFFFFFF
4845     /// bytes in size.
4846     BufferRowLengthTooLarge {
4847         resource: CopyErrorResource,
4848         region_index: usize,
4849         buffer_row_length: u32,
4850     },
4851 
4852     /// The buffer row length of a region is smaller than the image extent width.
4853     BufferRowLengthTooSmall {
4854         resource: CopyErrorResource,
4855         region_index: usize,
4856         row_length: u32,
4857         min: u32,
4858     },
4859 
4860     /// Depth/stencil images are not supported by the queue family of this command buffer; a
4861     /// graphics queue family is required.
4862     DepthStencilNotSupportedByQueueFamily,
4863 
4864     /// The image extent of a region is not a multiple of the required image alignment.
4865     ExtentNotAlignedForImage {
4866         resource: CopyErrorResource,
4867         region_index: usize,
4868         extent: [u32; 3],
4869         required_alignment: [u32; 3],
4870     },
4871 
4872     /// The chosen filter type does not support the dimensionality of the source image.
4873     FilterNotSupportedForImageType,
4874 
4875     /// The chosen filter type does not support the format of the source image.
4876     FilterNotSupportedByFormat,
4877 
4878     /// The format of an image is not supported for this operation.
4879     FormatNotSupported {
4880         resource: CopyErrorResource,
4881         format: Format,
4882     },
4883 
4884     /// The format of the source image does not match the format of the destination image.
4885     FormatsMismatch {
4886         src_format: Format,
4887         dst_format: Format,
4888     },
4889 
4890     /// The format of the source image subresource is not compatible with the format of the
4891     /// destination image subresource.
4892     FormatsNotCompatible {
4893         src_format: Format,
4894         dst_format: Format,
4895     },
4896 
4897     /// A specified image layout is not valid for this operation.
4898     ImageLayoutInvalid {
4899         resource: CopyErrorResource,
4900         image_layout: ImageLayout,
4901     },
4902 
4903     /// The end of the range of accessed mip levels of the subresource range of a region is greater
4904     /// than the number of mip levels in the image.
4905     MipLevelsOutOfRange {
4906         resource: CopyErrorResource,
4907         region_index: usize,
4908         mip_levels_range_end: u32,
4909         image_mip_levels: u32,
4910     },
4911 
4912     /// An image does not have a required format feature.
4913     MissingFormatFeature {
4914         resource: CopyErrorResource,
4915         format_feature: &'static str,
4916     },
4917 
4918     /// A resource did not have a required usage enabled.
4919     MissingUsage {
4920         resource: CopyErrorResource,
4921         usage: &'static str,
4922     },
4923 
4924     /// A subresource range of a region specifies multiple aspects, but only one aspect can be
4925     /// selected for the image.
4926     MultipleAspectsNotAllowed {
4927         resource: CopyErrorResource,
4928         region_index: usize,
4929         aspects: ImageAspects,
4930     },
4931 
4932     /// The buffer offset of a region is not a multiple of the required buffer alignment.
4933     OffsetNotAlignedForBuffer {
4934         resource: CopyErrorResource,
4935         region_index: usize,
4936         offset: DeviceSize,
4937         required_alignment: DeviceSize,
4938     },
4939 
4940     /// The image offset of a region is not a multiple of the required image alignment.
4941     OffsetNotAlignedForImage {
4942         resource: CopyErrorResource,
4943         region_index: usize,
4944         offset: [u32; 3],
4945         required_alignment: [u32; 3],
4946     },
4947 
4948     /// The image offsets of a region are not the values required for that axis ([0, 1]) for the
4949     /// type of the image.
4950     OffsetsInvalidForImageType {
4951         resource: CopyErrorResource,
4952         region_index: usize,
4953         offsets: [u32; 2],
4954     },
4955 
4956     /// The source bounds of a region overlap with the destination bounds of a region.
4957     OverlappingRegions {
4958         src_region_index: usize,
4959         dst_region_index: usize,
4960     },
4961 
4962     /// The source subresources of a region overlap with the destination subresources of a region,
4963     /// but the source image layout does not equal the destination image layout.
4964     OverlappingSubresourcesLayoutMismatch {
4965         src_region_index: usize,
4966         dst_region_index: usize,
4967         src_image_layout: ImageLayout,
4968         dst_image_layout: ImageLayout,
4969     },
4970 
4971     /// The end of the range of accessed byte offsets of a region is greater than the size of the
4972     /// buffer.
4973     RegionOutOfBufferBounds {
4974         resource: CopyErrorResource,
4975         region_index: usize,
4976         offset_range_end: DeviceSize,
4977         buffer_size: DeviceSize,
4978     },
4979 
4980     /// The end of the range of accessed texel offsets of a region is greater than the extent of
4981     /// the selected subresource of the image.
4982     RegionOutOfImageBounds {
4983         resource: CopyErrorResource,
4984         region_index: usize,
4985         offset_range_end: [u32; 3],
4986         subresource_extent: [u32; 3],
4987     },
4988 
4989     /// An image has a sample count that is not valid for this operation.
4990     SampleCountInvalid {
4991         resource: CopyErrorResource,
4992         sample_count: SampleCount,
4993         allowed_sample_counts: SampleCounts,
4994     },
4995 
4996     /// The source image has a different sample count than the destination image.
4997     SampleCountMismatch {
4998         src_sample_count: SampleCount,
4999         dst_sample_count: SampleCount,
5000     },
5001 }
5002 
5003 impl Error for CopyError {
source(&self) -> Option<&(dyn Error + 'static)>5004     fn source(&self) -> Option<&(dyn Error + 'static)> {
5005         match self {
5006             Self::SyncCommandBufferBuilderError(err) => Some(err),
5007             _ => None,
5008         }
5009     }
5010 }
5011 
5012 impl Display for CopyError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>5013     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
5014         match self {
5015             Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
5016             Self::RequirementNotMet {
5017                 required_for,
5018                 requires_one_of,
5019             } => write!(
5020                 f,
5021                 "a requirement was not met for: {}; requires one of: {}",
5022                 required_for, requires_one_of,
5023             ),
5024             Self::ForbiddenInsideRenderPass => {
5025                 write!(f, "operation forbidden inside of a render pass")
5026             }
5027             Self::NotSupportedByQueueFamily => {
5028                 write!(f, "the queue family doesn't allow this operation")
5029             }
5030             Self::ArrayLayerCountMismatch {
5031                 region_index,
5032                 src_layer_count,
5033                 dst_layer_count,
5034             } => write!(
5035                 f,
5036                 "the array layer counts of the source and destination subresource ranges of region \
5037                 {} do not match (source: {}; destination: {})",
5038                 region_index, src_layer_count, dst_layer_count,
5039             ),
5040             Self::ArrayLayersOutOfRange {
5041                 resource,
5042                 region_index,
5043                 array_layers_range_end,
5044                 image_array_layers,
5045             } => write!(
5046                 f,
5047                 "the end of the range of accessed array layers ({}) of the {} subresource range of \
5048                 region {} is greater than the number of array layers in the {} image ({})",
5049                 array_layers_range_end, resource, region_index, resource, image_array_layers,
5050             ),
5051             Self::AspectsMismatch {
5052                 region_index,
5053                 src_aspects,
5054                 dst_aspects,
5055             } => write!(
5056                 f,
5057                 "the aspects of the source and destination subresource ranges of region {} do not \
5058                 match (source: {:?}; destination: {:?})",
5059                 region_index, src_aspects, dst_aspects,
5060             ),
5061             Self::AspectsNotAllowed {
5062                 resource,
5063                 region_index,
5064                 aspects,
5065                 allowed_aspects,
5066             } => write!(
5067                 f,
5068                 "the aspects ({:?}) of the {} subresource range of region {} contain aspects that \
5069                 are not present in the {} image, or that are not allowed ({:?})",
5070                 aspects, resource, region_index, resource, allowed_aspects,
5071             ),
5072             Self::BufferImageHeightNotAligned {
5073                 resource,
5074                 region_index,
5075                 image_height,
5076                 required_alignment,
5077             } => write!(
5078                 f,
5079                 "the {} buffer image height ({}) of region {} is not a multiple of the required {} \
5080                 buffer alignment ({})",
5081                 resource, image_height, region_index, resource, required_alignment,
5082             ),
5083             Self::BufferRowLengthTooLarge {
5084                 resource,
5085                 region_index,
5086                 buffer_row_length,
5087             } => write!(
5088                 f,
5089                 "the {} buffer row length ({}) of region {} specifies a row of texels that is \
5090                 greater than 0x7FFFFFFF bytes in size",
5091                 resource, buffer_row_length, region_index,
5092             ),
5093             Self::BufferImageHeightTooSmall {
5094                 resource,
5095                 region_index,
5096                 image_height,
5097                 min,
5098             } => write!(
5099                 f,
5100                 "the {} buffer image height ({}) of region {} is smaller than the {} image extent \
5101                 height ({})",
5102                 resource, image_height, region_index, resource, min,
5103             ),
5104             Self::BufferRowLengthNotAligned {
5105                 resource,
5106                 region_index,
5107                 row_length,
5108                 required_alignment,
5109             } => write!(
5110                 f,
5111                 "the {} buffer row length ({}) of region {} is not a multiple of the required {} \
5112                 buffer alignment ({})",
5113                 resource, row_length, region_index, resource, required_alignment,
5114             ),
5115             Self::BufferRowLengthTooSmall {
5116                 resource,
5117                 region_index,
5118                 row_length,
5119                 min,
5120             } => write!(
5121                 f,
5122                 "the {} buffer row length length ({}) of region {} is smaller than the {} image \
5123                 extent width ({})",
5124                 resource, row_length, region_index, resource, min,
5125             ),
5126             Self::DepthStencilNotSupportedByQueueFamily => write!(
5127                 f,
5128                 "depth/stencil images are not supported by the queue family of this command \
5129                 buffer; a graphics queue family is required",
5130             ),
5131             Self::ExtentNotAlignedForImage {
5132                 resource,
5133                 region_index,
5134                 extent,
5135                 required_alignment,
5136             } => write!(
5137                 f,
5138                 "the {} image extent ({:?}) of region {} is not a multiple of the required {} \
5139                 image alignment ({:?})",
5140                 resource, extent, region_index, resource, required_alignment,
5141             ),
5142             Self::FilterNotSupportedForImageType => write!(
5143                 f,
5144                 "the chosen filter is not supported for the source image type",
5145             ),
5146             Self::FilterNotSupportedByFormat => write!(
5147                 f,
5148                 "the chosen filter is not supported by the format of the source image",
5149             ),
5150             Self::FormatNotSupported { resource, format } => write!(
5151                 f,
5152                 "the format of the {} image ({:?}) is not supported for this operation",
5153                 resource, format,
5154             ),
5155             Self::FormatsMismatch {
5156                 src_format,
5157                 dst_format,
5158             } => write!(
5159                 f,
5160                 "the format of the source image ({:?}) does not match the format of the \
5161                 destination image ({:?})",
5162                 src_format, dst_format,
5163             ),
5164             Self::FormatsNotCompatible {
5165                 src_format,
5166                 dst_format,
5167             } => write!(
5168                 f,
5169                 "the format of the source image subresource ({:?}) is not compatible with the \
5170                 format of the destination image subresource ({:?})",
5171                 src_format, dst_format,
5172             ),
5173             Self::ImageLayoutInvalid {
5174                 resource,
5175                 image_layout,
5176             } => write!(
5177                 f,
5178                 "the specified {} image layout {:?} is not valid for this operation",
5179                 resource, image_layout,
5180             ),
5181             Self::MipLevelsOutOfRange {
5182                 resource,
5183                 region_index,
5184                 mip_levels_range_end,
5185                 image_mip_levels,
5186             } => write!(
5187                 f,
5188                 "the end of the range of accessed mip levels ({}) of the {} subresource range of \
5189                 region {} is not less than the number of mip levels in the {} image ({})",
5190                 mip_levels_range_end, resource, region_index, resource, image_mip_levels,
5191             ),
5192             Self::MissingFormatFeature {
5193                 resource,
5194                 format_feature,
5195             } => write!(
5196                 f,
5197                 "the {} image does not have the required format feature {}",
5198                 resource, format_feature,
5199             ),
5200             Self::MissingUsage { resource, usage } => write!(
5201                 f,
5202                 "the {} resource did not have the required usage {} enabled",
5203                 resource, usage,
5204             ),
5205             Self::MultipleAspectsNotAllowed {
5206                 resource,
5207                 region_index,
5208                 aspects,
5209             } => write!(
5210                 f,
5211                 "the {} subresource range of region {} specifies multiple aspects ({:?}), but only \
5212                 one aspect can be selected for the {} image",
5213                 resource, region_index, aspects, resource,
5214             ),
5215             Self::OffsetNotAlignedForBuffer {
5216                 resource,
5217                 region_index,
5218                 offset,
5219                 required_alignment,
5220             } => write!(
5221                 f,
5222                 "the {} buffer offset ({}) of region {} is not a multiple of the required {} \
5223                 buffer alignment ({})",
5224                 resource, offset, region_index, resource, required_alignment,
5225             ),
5226             Self::OffsetNotAlignedForImage {
5227                 resource,
5228                 region_index,
5229                 offset,
5230                 required_alignment,
5231             } => write!(
5232                 f,
5233                 "the {} image offset ({:?}) of region {} is not a multiple of the required {} \
5234                 image alignment ({:?})",
5235                 resource, offset, region_index, resource, required_alignment,
5236             ),
5237             Self::OffsetsInvalidForImageType {
5238                 resource,
5239                 region_index,
5240                 offsets,
5241             } => write!(
5242                 f,
5243                 "the {} image offsets ({:?}) of region {} are not the values required for that \
5244                 axis ([0, 1]) for the type of the {} image",
5245                 resource, offsets, region_index, resource,
5246             ),
5247             Self::OverlappingRegions {
5248                 src_region_index,
5249                 dst_region_index,
5250             } => write!(
5251                 f,
5252                 "the source bounds of region {} overlap with the destination bounds of region {}",
5253                 src_region_index, dst_region_index,
5254             ),
5255             Self::OverlappingSubresourcesLayoutMismatch {
5256                 src_region_index,
5257                 dst_region_index,
5258                 src_image_layout,
5259                 dst_image_layout,
5260             } => write!(
5261                 f,
5262                 "the source subresources of region {} overlap with the destination subresources of \
5263                 region {}, but the source image layout ({:?}) does not equal the destination image \
5264                 layout ({:?})",
5265                 src_region_index, dst_region_index, src_image_layout, dst_image_layout,
5266             ),
5267             Self::RegionOutOfBufferBounds {
5268                 resource,
5269                 region_index,
5270                 offset_range_end,
5271                 buffer_size,
5272             } => write!(
5273                 f,
5274                 "the end of the range of accessed {} byte offsets ({}) of region {} is greater \
5275                 than the size of the {} buffer ({})",
5276                 resource, offset_range_end, region_index, resource, buffer_size,
5277             ),
5278             Self::RegionOutOfImageBounds {
5279                 resource,
5280                 region_index,
5281                 offset_range_end,
5282                 subresource_extent,
5283             } => write!(
5284                 f,
5285                 "the end of the range of accessed {} texel offsets ({:?}) of region {} is greater \
5286                 than the extent of the selected subresource of the {} image ({:?})",
5287                 resource, offset_range_end, region_index, resource, subresource_extent,
5288             ),
5289             Self::SampleCountInvalid {
5290                 resource,
5291                 sample_count,
5292                 allowed_sample_counts,
5293             } => write!(
5294                 f,
5295                 "the {} image has a sample count ({:?}) that is not valid for this operation \
5296                 ({:?})",
5297                 resource, sample_count, allowed_sample_counts,
5298             ),
5299             Self::SampleCountMismatch {
5300                 src_sample_count,
5301                 dst_sample_count,
5302             } => write!(
5303                 f,
5304                 "the source image has a different sample count ({:?}) than the destination image \
5305                 ({:?})",
5306                 src_sample_count, dst_sample_count,
5307             ),
5308         }
5309     }
5310 }
5311 
5312 impl From<SyncCommandBufferBuilderError> for CopyError {
from(err: SyncCommandBufferBuilderError) -> Self5313     fn from(err: SyncCommandBufferBuilderError) -> Self {
5314         Self::SyncCommandBufferBuilderError(err)
5315     }
5316 }
5317 
5318 impl From<RequirementNotMet> for CopyError {
from(err: RequirementNotMet) -> Self5319     fn from(err: RequirementNotMet) -> Self {
5320         Self::RequirementNotMet {
5321             required_for: err.required_for,
5322             requires_one_of: err.requires_one_of,
5323         }
5324     }
5325 }
5326 
5327 /// Indicates which resource a `CopyError` applies to.
5328 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
5329 pub enum CopyErrorResource {
5330     Source,
5331     Destination,
5332 }
5333 
5334 impl Display for CopyErrorResource {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>5335     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
5336         match self {
5337             Self::Source => write!(f, "source"),
5338             Self::Destination => write!(f, "destination"),
5339         }
5340     }
5341 }
5342 
5343 #[cfg(test)]
5344 mod tests {
5345     use super::*;
5346     use crate::format::Format;
5347 
5348     /// Computes the minimum required len in elements for buffer with image data in specified
5349     /// format of specified size.
required_size_for_format(format: Format, extent: [u32; 3], layer_count: u32) -> DeviceSize5350     fn required_size_for_format(format: Format, extent: [u32; 3], layer_count: u32) -> DeviceSize {
5351         let num_blocks = extent
5352             .into_iter()
5353             .zip(format.block_extent())
5354             .map(|(extent, block_extent)| {
5355                 let extent = extent as DeviceSize;
5356                 let block_extent = block_extent as DeviceSize;
5357                 (extent + block_extent - 1) / block_extent
5358             })
5359             .product::<DeviceSize>()
5360             * layer_count as DeviceSize;
5361         let block_size = format
5362             .block_size()
5363             .expect("this format cannot accept pixels");
5364         num_blocks * block_size
5365     }
5366 
5367     #[test]
test_required_len_for_format()5368     fn test_required_len_for_format() {
5369         // issue #1292
5370         assert_eq!(
5371             required_size_for_format(Format::BC1_RGB_UNORM_BLOCK, [2048, 2048, 1], 1),
5372             2097152
5373         );
5374         // other test cases
5375         assert_eq!(
5376             required_size_for_format(Format::R8G8B8A8_UNORM, [2048, 2048, 1], 1),
5377             16777216
5378         );
5379         assert_eq!(
5380             required_size_for_format(Format::R4G4_UNORM_PACK8, [512, 512, 1], 1),
5381             262144
5382         );
5383         assert_eq!(
5384             required_size_for_format(Format::R8G8B8_USCALED, [512, 512, 1], 1),
5385             786432
5386         );
5387         assert_eq!(
5388             required_size_for_format(Format::R32G32_UINT, [512, 512, 1], 1),
5389             2097152
5390         );
5391         assert_eq!(
5392             required_size_for_format(Format::R32G32_UINT, [512, 512, 1], 1),
5393             2097152
5394         );
5395         assert_eq!(
5396             required_size_for_format(Format::ASTC_8x8_UNORM_BLOCK, [512, 512, 1], 1),
5397             65536
5398         );
5399         assert_eq!(
5400             required_size_for_format(Format::ASTC_12x12_SRGB_BLOCK, [512, 512, 1], 1),
5401             29584
5402         );
5403     }
5404 }
5405