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(©_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(©_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(©_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(©_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 } = ©_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 } = ©_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 } = ©_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 } = ©_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, ©_buffer_info); 3243 } else { 3244 (fns.khr_copy_commands2.cmd_copy_buffer2_khr)(self.handle, ©_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, ©_image_info); 3359 } else { 3360 (fns.khr_copy_commands2.cmd_copy_image2_khr)(self.handle, ©_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, ©_buffer_to_image_info); 3496 } else { 3497 (fns.khr_copy_commands2.cmd_copy_buffer_to_image2_khr)( 3498 self.handle, 3499 ©_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, ©_image_to_buffer_info); 3628 } else { 3629 (fns.khr_copy_commands2.cmd_copy_image_to_buffer2_khr)( 3630 self.handle, 3631 ©_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