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