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 super::{ClearColorImageInfo, ClearDepthStencilImageInfo, ClearError, CommandBufferBuilder}; 11 use crate::{ 12 buffer::{BufferContents, BufferUsage, Subbuffer}, 13 command_buffer::{allocator::CommandBufferAllocator, ResourceInCommand, ResourceUseRef}, 14 device::{DeviceOwned, QueueFlags}, 15 format::FormatFeatures, 16 image::{ImageAccess, ImageAspects, ImageLayout, ImageUsage}, 17 sync::PipelineStageAccess, 18 DeviceSize, RequiresOneOf, Version, VulkanObject, 19 }; 20 use smallvec::SmallVec; 21 use std::mem::size_of_val; 22 23 impl<L, A> CommandBufferBuilder<L, A> 24 where 25 A: CommandBufferAllocator, 26 { 27 /// Clears a color image with a specific value. 28 /// 29 /// # Safety 30 /// 31 /// - Appropriate synchronization must be provided for all images 32 /// that are accessed by the command. 33 /// - All images that are accessed by the command must be in the expected image layout. 34 #[inline] clear_color_image( &mut self, clear_info: ClearColorImageInfo, ) -> Result<&mut Self, ClearError>35 pub unsafe fn clear_color_image( 36 &mut self, 37 clear_info: ClearColorImageInfo, 38 ) -> Result<&mut Self, ClearError> { 39 self.validate_clear_color_image(&clear_info)?; 40 41 unsafe { Ok(self.clear_color_image_unchecked(clear_info)) } 42 } 43 validate_clear_color_image( &self, clear_info: &ClearColorImageInfo, ) -> Result<(), ClearError>44 fn validate_clear_color_image( 45 &self, 46 clear_info: &ClearColorImageInfo, 47 ) -> Result<(), ClearError> { 48 let device = self.device(); 49 50 // VUID-vkCmdClearColorImage-renderpass 51 if self.builder_state.render_pass.is_some() { 52 return Err(ClearError::ForbiddenInsideRenderPass); 53 } 54 55 let queue_family_properties = self.queue_family_properties(); 56 57 // VUID-vkCmdClearColorImage-commandBuffer-cmdpool 58 if !queue_family_properties 59 .queue_flags 60 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 61 { 62 return Err(ClearError::NotSupportedByQueueFamily); 63 } 64 65 let &ClearColorImageInfo { 66 ref image, 67 image_layout, 68 clear_value: _, 69 ref regions, 70 _ne: _, 71 } = clear_info; 72 73 // VUID-vkCmdClearColorImage-imageLayout-parameter 74 image_layout.validate_device(device)?; 75 76 // VUID-vkCmdClearColorImage-commonparent 77 assert_eq!(device, image.device()); 78 79 // VUID-vkCmdClearColorImage-image-00002 80 if !image.usage().intersects(ImageUsage::TRANSFER_DST) { 81 return Err(ClearError::MissingUsage { 82 usage: "transfer_dst", 83 }); 84 } 85 86 if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 { 87 // VUID-vkCmdClearColorImage-image-01993 88 if !image 89 .format_features() 90 .intersects(FormatFeatures::TRANSFER_DST) 91 { 92 return Err(ClearError::MissingFormatFeature { 93 format_feature: "transfer_dst", 94 }); 95 } 96 } 97 98 let image_aspects = image.format().aspects(); 99 100 // VUID-vkCmdClearColorImage-image-00007 101 if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) { 102 return Err(ClearError::FormatNotSupported { 103 format: image.format(), 104 }); 105 } 106 107 // VUID-vkCmdClearColorImage-image-00007 108 if image.format().compression().is_some() { 109 return Err(ClearError::FormatNotSupported { 110 format: image.format(), 111 }); 112 } 113 114 // VUID-vkCmdClearColorImage-image-01545 115 if image.format().ycbcr_chroma_sampling().is_some() { 116 return Err(ClearError::FormatNotSupported { 117 format: image.format(), 118 }); 119 } 120 121 // VUID-vkCmdClearColorImage-imageLayout-01394 122 if !matches!( 123 image_layout, 124 ImageLayout::TransferDstOptimal | ImageLayout::General 125 ) { 126 return Err(ClearError::ImageLayoutInvalid { image_layout }); 127 } 128 129 for (region_index, subresource_range) in regions.iter().enumerate() { 130 // VUID-VkImageSubresourceRange-aspectMask-parameter 131 subresource_range.aspects.validate_device(device)?; 132 133 // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask 134 assert!(!subresource_range.aspects.is_empty()); 135 136 // VUID-vkCmdClearColorImage-aspectMask-02498 137 if !image_aspects.contains(subresource_range.aspects) { 138 return Err(ClearError::AspectsNotAllowed { 139 region_index, 140 aspects: subresource_range.aspects, 141 allowed_aspects: image_aspects, 142 }); 143 } 144 145 // VUID-VkImageSubresourceRange-levelCount-01720 146 assert!(!subresource_range.mip_levels.is_empty()); 147 148 // VUID-vkCmdClearColorImage-baseMipLevel-01470 149 // VUID-vkCmdClearColorImage-pRanges-01692 150 if subresource_range.mip_levels.end > image.mip_levels() { 151 return Err(ClearError::MipLevelsOutOfRange { 152 region_index, 153 mip_levels_range_end: subresource_range.mip_levels.end, 154 image_mip_levels: image.dimensions().array_layers(), 155 }); 156 } 157 158 // VUID-VkImageSubresourceRange-layerCount-01721 159 assert!(!subresource_range.array_layers.is_empty()); 160 161 // VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476 162 // VUID-vkCmdClearDepthStencilImage-pRanges-01695 163 if subresource_range.array_layers.end > image.dimensions().array_layers() { 164 return Err(ClearError::ArrayLayersOutOfRange { 165 region_index, 166 array_layers_range_end: subresource_range.array_layers.end, 167 image_array_layers: image.dimensions().array_layers(), 168 }); 169 } 170 } 171 172 // TODO: sync check 173 174 Ok(()) 175 } 176 177 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] clear_color_image_unchecked( &mut self, clear_info: ClearColorImageInfo, ) -> &mut Self178 pub unsafe fn clear_color_image_unchecked( 179 &mut self, 180 clear_info: ClearColorImageInfo, 181 ) -> &mut Self { 182 let ClearColorImageInfo { 183 image, 184 image_layout, 185 clear_value, 186 regions, 187 _ne: _, 188 } = clear_info; 189 190 if regions.is_empty() { 191 return self; 192 } 193 194 let image_inner = image.inner(); 195 let clear_value = clear_value.into(); 196 let ranges: SmallVec<[_; 8]> = regions 197 .iter() 198 .cloned() 199 .map(ash::vk::ImageSubresourceRange::from) 200 .collect(); 201 202 let fns = self.device().fns(); 203 (fns.v1_0.cmd_clear_color_image)( 204 self.handle(), 205 image_inner.image.handle(), 206 image_layout.into(), 207 &clear_value, 208 ranges.len() as u32, 209 ranges.as_ptr(), 210 ); 211 212 let command_index = self.next_command_index; 213 let command_name = "clear_color_image"; 214 let use_ref = ResourceUseRef { 215 command_index, 216 command_name, 217 resource_in_command: ResourceInCommand::Destination, 218 secondary_use_ref: None, 219 }; 220 221 for mut subresource_range in regions { 222 subresource_range.array_layers.start += image_inner.first_layer; 223 subresource_range.array_layers.end += image_inner.first_layer; 224 subresource_range.mip_levels.start += image_inner.first_mipmap_level; 225 subresource_range.mip_levels.end += image_inner.first_mipmap_level; 226 227 self.resources_usage_state.record_image_access( 228 &use_ref, 229 image_inner.image, 230 subresource_range, 231 PipelineStageAccess::Clear_TransferWrite, 232 image_layout, 233 ); 234 } 235 236 self.resources.push(Box::new(image)); 237 238 self.next_command_index += 1; 239 self 240 } 241 242 /// Clears a depth/stencil image with a specific value. 243 /// 244 /// # Safety 245 /// 246 /// - Appropriate synchronization must be provided for all images 247 /// that are accessed by the command. 248 /// - All images that are accessed by the command must be in the expected image layout. 249 #[inline] clear_depth_stencil_image( &mut self, clear_info: ClearDepthStencilImageInfo, ) -> Result<&mut Self, ClearError>250 pub unsafe fn clear_depth_stencil_image( 251 &mut self, 252 clear_info: ClearDepthStencilImageInfo, 253 ) -> Result<&mut Self, ClearError> { 254 self.validate_clear_depth_stencil_image(&clear_info)?; 255 256 unsafe { Ok(self.clear_depth_stencil_image_unchecked(clear_info)) } 257 } 258 validate_clear_depth_stencil_image( &self, clear_info: &ClearDepthStencilImageInfo, ) -> Result<(), ClearError>259 fn validate_clear_depth_stencil_image( 260 &self, 261 clear_info: &ClearDepthStencilImageInfo, 262 ) -> Result<(), ClearError> { 263 let device = self.device(); 264 265 // VUID-vkCmdClearDepthStencilImage-renderpass 266 if self.builder_state.render_pass.is_some() { 267 return Err(ClearError::ForbiddenInsideRenderPass); 268 } 269 270 let queue_family_properties = self.queue_family_properties(); 271 272 // VUID-vkCmdClearDepthStencilImage-commandBuffer-cmdpool 273 if !queue_family_properties 274 .queue_flags 275 .intersects(QueueFlags::GRAPHICS) 276 { 277 return Err(ClearError::NotSupportedByQueueFamily); 278 } 279 280 let &ClearDepthStencilImageInfo { 281 ref image, 282 image_layout, 283 clear_value, 284 ref regions, 285 _ne: _, 286 } = clear_info; 287 288 // VUID-vkCmdClearDepthStencilImage-imageLayout-parameter 289 image_layout.validate_device(device)?; 290 291 // VUID-vkCmdClearDepthStencilImage-commonparent 292 assert_eq!(device, image.device()); 293 294 if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 { 295 // VUID-vkCmdClearDepthStencilImage-image-01994 296 if !image 297 .format_features() 298 .intersects(FormatFeatures::TRANSFER_DST) 299 { 300 return Err(ClearError::MissingFormatFeature { 301 format_feature: "transfer_dst", 302 }); 303 } 304 } 305 306 let image_aspects = image.format().aspects(); 307 308 // VUID-vkCmdClearDepthStencilImage-image-00014 309 if !image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) { 310 return Err(ClearError::FormatNotSupported { 311 format: image.format(), 312 }); 313 } 314 315 // VUID-vkCmdClearDepthStencilImage-imageLayout-00012 316 if !matches!( 317 image_layout, 318 ImageLayout::TransferDstOptimal | ImageLayout::General 319 ) { 320 return Err(ClearError::ImageLayoutInvalid { image_layout }); 321 } 322 323 // VUID-VkClearDepthStencilValue-depth-00022 324 if !device.enabled_extensions().ext_depth_range_unrestricted 325 && !(0.0..=1.0).contains(&clear_value.depth) 326 { 327 return Err(ClearError::RequirementNotMet { 328 required_for: "`clear_info.clear_value.depth` is not between `0.0` and `1.0` \ 329 inclusive", 330 requires_one_of: RequiresOneOf { 331 device_extensions: &["ext_depth_range_unrestricted"], 332 ..Default::default() 333 }, 334 }); 335 } 336 337 let mut image_aspects_used = ImageAspects::empty(); 338 339 for (region_index, subresource_range) in regions.iter().enumerate() { 340 // VUID-VkImageSubresourceRange-aspectMask-parameter 341 subresource_range.aspects.validate_device(device)?; 342 343 // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask 344 assert!(!subresource_range.aspects.is_empty()); 345 346 // VUID-vkCmdClearDepthStencilImage-aspectMask-02824 347 // VUID-vkCmdClearDepthStencilImage-image-02825 348 // VUID-vkCmdClearDepthStencilImage-image-02826 349 if !image_aspects.contains(subresource_range.aspects) { 350 return Err(ClearError::AspectsNotAllowed { 351 region_index, 352 aspects: subresource_range.aspects, 353 allowed_aspects: image_aspects, 354 }); 355 } 356 357 image_aspects_used |= subresource_range.aspects; 358 359 // VUID-VkImageSubresourceRange-levelCount-01720 360 assert!(!subresource_range.mip_levels.is_empty()); 361 362 // VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474 363 // VUID-vkCmdClearDepthStencilImage-pRanges-01694 364 if subresource_range.mip_levels.end > image.mip_levels() { 365 return Err(ClearError::MipLevelsOutOfRange { 366 region_index, 367 mip_levels_range_end: subresource_range.mip_levels.end, 368 image_mip_levels: image.dimensions().array_layers(), 369 }); 370 } 371 372 // VUID-VkImageSubresourceRange-layerCount-01721 373 assert!(!subresource_range.array_layers.is_empty()); 374 375 // VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476 376 // VUID-vkCmdClearDepthStencilImage-pRanges-01695 377 if subresource_range.array_layers.end > image.dimensions().array_layers() { 378 return Err(ClearError::ArrayLayersOutOfRange { 379 region_index, 380 array_layers_range_end: subresource_range.array_layers.end, 381 image_array_layers: image.dimensions().array_layers(), 382 }); 383 } 384 } 385 386 // VUID-vkCmdClearDepthStencilImage-pRanges-02658 387 // VUID-vkCmdClearDepthStencilImage-pRanges-02659 388 if image_aspects_used.intersects(ImageAspects::STENCIL) 389 && !image.stencil_usage().intersects(ImageUsage::TRANSFER_DST) 390 { 391 return Err(ClearError::MissingUsage { 392 usage: "transfer_dst", 393 }); 394 } 395 396 // VUID-vkCmdClearDepthStencilImage-pRanges-02660 397 if !(image_aspects_used - ImageAspects::STENCIL).is_empty() 398 && !image.usage().intersects(ImageUsage::TRANSFER_DST) 399 { 400 return Err(ClearError::MissingUsage { 401 usage: "transfer_dst", 402 }); 403 } 404 405 // TODO: sync check 406 407 Ok(()) 408 } 409 410 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] clear_depth_stencil_image_unchecked( &mut self, clear_info: ClearDepthStencilImageInfo, ) -> &mut Self411 pub unsafe fn clear_depth_stencil_image_unchecked( 412 &mut self, 413 clear_info: ClearDepthStencilImageInfo, 414 ) -> &mut Self { 415 let ClearDepthStencilImageInfo { 416 image, 417 image_layout, 418 clear_value, 419 regions, 420 _ne: _, 421 } = clear_info; 422 423 if regions.is_empty() { 424 return self; 425 } 426 427 let image_inner = image.inner(); 428 let clear_value = clear_value.into(); 429 let ranges: SmallVec<[_; 8]> = regions 430 .iter() 431 .cloned() 432 .map(ash::vk::ImageSubresourceRange::from) 433 .collect(); 434 435 let fns = self.device().fns(); 436 (fns.v1_0.cmd_clear_depth_stencil_image)( 437 self.handle(), 438 image_inner.image.handle(), 439 image_layout.into(), 440 &clear_value, 441 ranges.len() as u32, 442 ranges.as_ptr(), 443 ); 444 445 let command_index = self.next_command_index; 446 let command_name = "clear_depth_stencil_image"; 447 let use_ref = ResourceUseRef { 448 command_index, 449 command_name, 450 resource_in_command: ResourceInCommand::Destination, 451 secondary_use_ref: None, 452 }; 453 454 for mut subresource_range in regions { 455 subresource_range.array_layers.start += image_inner.first_layer; 456 subresource_range.array_layers.end += image_inner.first_layer; 457 subresource_range.mip_levels.start += image_inner.first_mipmap_level; 458 subresource_range.mip_levels.end += image_inner.first_mipmap_level; 459 460 self.resources_usage_state.record_image_access( 461 &use_ref, 462 image_inner.image, 463 subresource_range, 464 PipelineStageAccess::Clear_TransferWrite, 465 image_layout, 466 ); 467 } 468 469 self.resources.push(Box::new(image)); 470 471 self.next_command_index += 1; 472 self 473 } 474 475 /// Fills a region of a buffer with repeated copies of a value. 476 /// 477 /// This function is similar to the `memset` function in C. The `data` parameter is a number 478 /// that will be repeatedly written through the entire buffer. 479 /// 480 /// # Panics 481 /// 482 /// - Panics if `dst_buffer` was not created from the same device as `self`. 483 /// 484 /// # Safety 485 /// 486 /// - Appropriate synchronization must be provided for all buffers 487 /// that are accessed by the command. 488 #[inline] fill_buffer( &mut self, dst_buffer: Subbuffer<[u32]>, data: u32, ) -> Result<&mut Self, ClearError>489 pub unsafe fn fill_buffer( 490 &mut self, 491 dst_buffer: Subbuffer<[u32]>, 492 data: u32, 493 ) -> Result<&mut Self, ClearError> { 494 self.validate_fill_buffer(&dst_buffer, data)?; 495 496 unsafe { Ok(self.fill_buffer_unchecked(dst_buffer, data)) } 497 } 498 validate_fill_buffer( &self, dst_buffer: &Subbuffer<[u32]>, _data: u32, ) -> Result<(), ClearError>499 fn validate_fill_buffer( 500 &self, 501 dst_buffer: &Subbuffer<[u32]>, 502 _data: u32, 503 ) -> Result<(), ClearError> { 504 let device = self.device(); 505 506 // VUID-vkCmdFillBuffer-renderpass 507 if self.builder_state.render_pass.is_some() { 508 return Err(ClearError::ForbiddenInsideRenderPass); 509 } 510 511 let queue_family_properties = self.queue_family_properties(); 512 513 if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 { 514 // VUID-vkCmdFillBuffer-commandBuffer-cmdpool 515 if !queue_family_properties 516 .queue_flags 517 .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 518 { 519 return Err(ClearError::NotSupportedByQueueFamily); 520 } 521 } else { 522 // VUID-vkCmdFillBuffer-commandBuffer-00030 523 if !queue_family_properties 524 .queue_flags 525 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 526 { 527 return Err(ClearError::NotSupportedByQueueFamily); 528 } 529 } 530 531 // VUID-vkCmdFillBuffer-commonparent 532 assert_eq!(device, dst_buffer.device()); 533 534 // VUID-vkCmdFillBuffer-size-00026 535 // Guaranteed by `Subbuffer` 536 537 // VUID-vkCmdFillBuffer-dstBuffer-00029 538 if !dst_buffer 539 .buffer() 540 .usage() 541 .intersects(BufferUsage::TRANSFER_DST) 542 { 543 return Err(ClearError::MissingUsage { 544 usage: "transfer_dst", 545 }); 546 } 547 548 // VUID-vkCmdFillBuffer-dstOffset-00024 549 // VUID-vkCmdFillBuffer-size-00027 550 // Guaranteed by `Subbuffer` 551 552 // VUID-vkCmdFillBuffer-dstOffset-00025 553 // VUID-vkCmdFillBuffer-size-00028 554 // Guaranteed because we take `Subbuffer<[u32]>` 555 556 // TODO: sync check 557 558 Ok(()) 559 } 560 561 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] fill_buffer_unchecked( &mut self, dst_buffer: Subbuffer<[u32]>, data: u32, ) -> &mut Self562 pub unsafe fn fill_buffer_unchecked( 563 &mut self, 564 dst_buffer: Subbuffer<[u32]>, 565 data: u32, 566 ) -> &mut Self { 567 let fns = self.device().fns(); 568 (fns.v1_0.cmd_fill_buffer)( 569 self.handle(), 570 dst_buffer.buffer().handle(), 571 dst_buffer.offset(), 572 dst_buffer.size(), 573 data, 574 ); 575 576 let command_index = self.next_command_index; 577 let command_name = "fill_buffer"; 578 let use_ref = ResourceUseRef { 579 command_index, 580 command_name, 581 resource_in_command: ResourceInCommand::Destination, 582 secondary_use_ref: None, 583 }; 584 585 self.resources_usage_state.record_buffer_access( 586 &use_ref, 587 dst_buffer.buffer(), 588 dst_buffer.range(), 589 PipelineStageAccess::Clear_TransferWrite, 590 ); 591 592 self.resources.push(Box::new(dst_buffer)); 593 594 self.next_command_index += 1; 595 self 596 } 597 598 /// Writes data to a region of a buffer. 599 /// 600 /// # Panics 601 /// 602 /// - Panics if `dst_buffer` was not created from the same device as `self`. 603 /// 604 /// # Safety 605 /// 606 /// - Appropriate synchronization must be provided for all buffers 607 /// that are accessed by the command. 608 #[inline] update_buffer<D>( &mut self, dst_buffer: Subbuffer<D>, data: &D, ) -> Result<&mut Self, ClearError> where D: BufferContents + ?Sized,609 pub unsafe fn update_buffer<D>( 610 &mut self, 611 dst_buffer: Subbuffer<D>, 612 data: &D, 613 ) -> Result<&mut Self, ClearError> 614 where 615 D: BufferContents + ?Sized, 616 { 617 self.validate_update_buffer(dst_buffer.as_bytes(), size_of_val(data) as DeviceSize)?; 618 619 unsafe { Ok(self.update_buffer_unchecked(dst_buffer, data)) } 620 } 621 validate_update_buffer( &self, dst_buffer: &Subbuffer<[u8]>, data_size: DeviceSize, ) -> Result<(), ClearError>622 fn validate_update_buffer( 623 &self, 624 dst_buffer: &Subbuffer<[u8]>, 625 data_size: DeviceSize, 626 ) -> Result<(), ClearError> { 627 let device = self.device(); 628 629 // VUID-vkCmdUpdateBuffer-renderpass 630 if self.builder_state.render_pass.is_some() { 631 return Err(ClearError::ForbiddenInsideRenderPass); 632 } 633 634 let queue_family_properties = self.queue_family_properties(); 635 636 // VUID-vkCmdUpdateBuffer-commandBuffer-cmdpool 637 if !queue_family_properties 638 .queue_flags 639 .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE) 640 { 641 return Err(ClearError::NotSupportedByQueueFamily); 642 } 643 644 // VUID-vkCmdUpdateBuffer-commonparent 645 assert_eq!(device, dst_buffer.device()); 646 647 // VUID-vkCmdUpdateBuffer-dataSize-arraylength 648 assert!(data_size != 0); 649 650 // VUID-vkCmdUpdateBuffer-dstBuffer-00034 651 if !dst_buffer 652 .buffer() 653 .usage() 654 .intersects(BufferUsage::TRANSFER_DST) 655 { 656 return Err(ClearError::MissingUsage { 657 usage: "transfer_dst", 658 }); 659 } 660 661 // VUID-vkCmdUpdateBuffer-dstOffset-00032 662 // VUID-vkCmdUpdateBuffer-dataSize-00033 663 if data_size > dst_buffer.size() { 664 return Err(ClearError::RegionOutOfBufferBounds { 665 region_index: 0, 666 offset_range_end: data_size, 667 buffer_size: dst_buffer.size(), 668 }); 669 } 670 671 // VUID-vkCmdUpdateBuffer-dstOffset-00036 672 if dst_buffer.offset() % 4 != 0 { 673 return Err(ClearError::OffsetNotAlignedForBuffer { 674 region_index: 0, 675 offset: dst_buffer.offset(), 676 required_alignment: 4, 677 }); 678 } 679 680 // VUID-vkCmdUpdateBuffer-dataSize-00037 681 if data_size > 65536 { 682 return Err(ClearError::DataTooLarge { 683 size: data_size, 684 max: 65536, 685 }); 686 } 687 688 // VUID-vkCmdUpdateBuffer-dataSize-00038 689 if data_size % 4 != 0 { 690 return Err(ClearError::SizeNotAlignedForBuffer { 691 region_index: 0, 692 size: data_size, 693 required_alignment: 4, 694 }); 695 } 696 697 // TODO: sync check 698 699 Ok(()) 700 } 701 702 #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] update_buffer_unchecked<D>( &mut self, dst_buffer: Subbuffer<D>, data: &D, ) -> &mut Self where D: BufferContents + ?Sized,703 pub unsafe fn update_buffer_unchecked<D>( 704 &mut self, 705 dst_buffer: Subbuffer<D>, 706 data: &D, 707 ) -> &mut Self 708 where 709 D: BufferContents + ?Sized, 710 { 711 let fns = self.device().fns(); 712 (fns.v1_0.cmd_update_buffer)( 713 self.handle(), 714 dst_buffer.buffer().handle(), 715 dst_buffer.offset(), 716 size_of_val(data) as DeviceSize, 717 data as *const _ as *const _, 718 ); 719 720 let command_index = self.next_command_index; 721 let command_name = "update_buffer"; 722 let use_ref = ResourceUseRef { 723 command_index, 724 command_name, 725 resource_in_command: ResourceInCommand::Destination, 726 secondary_use_ref: None, 727 }; 728 729 let dst_range = dst_buffer.offset()..dst_buffer.offset() + size_of_val(data) as DeviceSize; 730 self.resources_usage_state.record_buffer_access( 731 &use_ref, 732 dst_buffer.buffer(), 733 dst_range, 734 PipelineStageAccess::Clear_TransferWrite, 735 ); 736 737 self.resources.push(Box::new(dst_buffer)); 738 739 self.next_command_index += 1; 740 self 741 } 742 } 743