• 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 crate::{
11     buffer::{BufferContents, 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::{ClearColorValue, ClearDepthStencilValue, Format, FormatFeatures},
20     image::{ImageAccess, ImageAspects, ImageLayout, ImageSubresourceRange, ImageUsage},
21     sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
22     DeviceSize, RequirementNotMet, RequiresOneOf, SafeDeref, Version, VulkanObject,
23 };
24 use smallvec::{smallvec, SmallVec};
25 use std::{
26     error::Error,
27     fmt::{Display, Error as FmtError, Formatter},
28     mem::size_of_val,
29     sync::Arc,
30 };
31 
32 /// # Commands to fill resources with new data.
33 impl<L, A> AutoCommandBufferBuilder<L, A>
34 where
35     A: CommandBufferAllocator,
36 {
37     /// Clears a color image with a specific value.
clear_color_image( &mut self, clear_info: ClearColorImageInfo, ) -> Result<&mut Self, ClearError>38     pub fn clear_color_image(
39         &mut self,
40         clear_info: ClearColorImageInfo,
41     ) -> Result<&mut Self, ClearError> {
42         self.validate_clear_color_image(&clear_info)?;
43 
44         unsafe {
45             self.inner.clear_color_image(clear_info)?;
46         }
47 
48         Ok(self)
49     }
50 
validate_clear_color_image( &self, clear_info: &ClearColorImageInfo, ) -> Result<(), ClearError>51     fn validate_clear_color_image(
52         &self,
53         clear_info: &ClearColorImageInfo,
54     ) -> Result<(), ClearError> {
55         let device = self.device();
56 
57         // VUID-vkCmdClearColorImage-renderpass
58         if self.render_pass_state.is_some() {
59             return Err(ClearError::ForbiddenInsideRenderPass);
60         }
61 
62         let queue_family_properties = self.queue_family_properties();
63 
64         // VUID-vkCmdClearColorImage-commandBuffer-cmdpool
65         if !queue_family_properties
66             .queue_flags
67             .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
68         {
69             return Err(ClearError::NotSupportedByQueueFamily);
70         }
71 
72         let &ClearColorImageInfo {
73             ref image,
74             image_layout,
75             clear_value: _,
76             ref regions,
77             _ne: _,
78         } = clear_info;
79 
80         // VUID-vkCmdClearColorImage-imageLayout-parameter
81         image_layout.validate_device(device)?;
82 
83         // VUID-vkCmdClearColorImage-commonparent
84         assert_eq!(device, image.device());
85 
86         // VUID-vkCmdClearColorImage-image-00002
87         if !image.usage().intersects(ImageUsage::TRANSFER_DST) {
88             return Err(ClearError::MissingUsage {
89                 usage: "transfer_dst",
90             });
91         }
92 
93         if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
94             // VUID-vkCmdClearColorImage-image-01993
95             if !image
96                 .format_features()
97                 .intersects(FormatFeatures::TRANSFER_DST)
98             {
99                 return Err(ClearError::MissingFormatFeature {
100                     format_feature: "transfer_dst",
101                 });
102             }
103         }
104 
105         let image_aspects = image.format().aspects();
106 
107         // VUID-vkCmdClearColorImage-image-00007
108         if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
109             return Err(ClearError::FormatNotSupported {
110                 format: image.format(),
111             });
112         }
113 
114         // VUID-vkCmdClearColorImage-image-00007
115         if image.format().compression().is_some() {
116             return Err(ClearError::FormatNotSupported {
117                 format: image.format(),
118             });
119         }
120 
121         // VUID-vkCmdClearColorImage-image-01545
122         if image.format().ycbcr_chroma_sampling().is_some() {
123             return Err(ClearError::FormatNotSupported {
124                 format: image.format(),
125             });
126         }
127 
128         // VUID-vkCmdClearColorImage-imageLayout-01394
129         if !matches!(
130             image_layout,
131             ImageLayout::TransferDstOptimal | ImageLayout::General
132         ) {
133             return Err(ClearError::ImageLayoutInvalid { image_layout });
134         }
135 
136         for (region_index, subresource_range) in regions.iter().enumerate() {
137             // VUID-VkImageSubresourceRange-aspectMask-parameter
138             subresource_range.aspects.validate_device(device)?;
139 
140             // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
141             assert!(!subresource_range.aspects.is_empty());
142 
143             // VUID-vkCmdClearColorImage-aspectMask-02498
144             if !image_aspects.contains(subresource_range.aspects) {
145                 return Err(ClearError::AspectsNotAllowed {
146                     region_index,
147                     aspects: subresource_range.aspects,
148                     allowed_aspects: image_aspects,
149                 });
150             }
151 
152             // VUID-VkImageSubresourceRange-levelCount-01720
153             assert!(!subresource_range.mip_levels.is_empty());
154 
155             // VUID-vkCmdClearColorImage-baseMipLevel-01470
156             // VUID-vkCmdClearColorImage-pRanges-01692
157             if subresource_range.mip_levels.end > image.mip_levels() {
158                 return Err(ClearError::MipLevelsOutOfRange {
159                     region_index,
160                     mip_levels_range_end: subresource_range.mip_levels.end,
161                     image_mip_levels: image.dimensions().array_layers(),
162                 });
163             }
164 
165             // VUID-VkImageSubresourceRange-layerCount-01721
166             assert!(!subresource_range.array_layers.is_empty());
167 
168             // VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476
169             // VUID-vkCmdClearDepthStencilImage-pRanges-01695
170             if subresource_range.array_layers.end > image.dimensions().array_layers() {
171                 return Err(ClearError::ArrayLayersOutOfRange {
172                     region_index,
173                     array_layers_range_end: subresource_range.array_layers.end,
174                     image_array_layers: image.dimensions().array_layers(),
175                 });
176             }
177         }
178 
179         Ok(())
180     }
181 
182     /// Clears a depth/stencil image with a specific value.
clear_depth_stencil_image( &mut self, clear_info: ClearDepthStencilImageInfo, ) -> Result<&mut Self, ClearError>183     pub fn clear_depth_stencil_image(
184         &mut self,
185         clear_info: ClearDepthStencilImageInfo,
186     ) -> Result<&mut Self, ClearError> {
187         self.validate_clear_depth_stencil_image(&clear_info)?;
188 
189         unsafe {
190             self.inner.clear_depth_stencil_image(clear_info)?;
191         }
192 
193         Ok(self)
194     }
195 
validate_clear_depth_stencil_image( &self, clear_info: &ClearDepthStencilImageInfo, ) -> Result<(), ClearError>196     fn validate_clear_depth_stencil_image(
197         &self,
198         clear_info: &ClearDepthStencilImageInfo,
199     ) -> Result<(), ClearError> {
200         let device = self.device();
201 
202         // VUID-vkCmdClearDepthStencilImage-renderpass
203         if self.render_pass_state.is_some() {
204             return Err(ClearError::ForbiddenInsideRenderPass);
205         }
206 
207         let queue_family_properties = self.queue_family_properties();
208 
209         // VUID-vkCmdClearDepthStencilImage-commandBuffer-cmdpool
210         if !queue_family_properties
211             .queue_flags
212             .intersects(QueueFlags::GRAPHICS)
213         {
214             return Err(ClearError::NotSupportedByQueueFamily);
215         }
216 
217         let &ClearDepthStencilImageInfo {
218             ref image,
219             image_layout,
220             clear_value,
221             ref regions,
222             _ne: _,
223         } = clear_info;
224 
225         // VUID-vkCmdClearDepthStencilImage-imageLayout-parameter
226         image_layout.validate_device(device)?;
227 
228         // VUID-vkCmdClearDepthStencilImage-commonparent
229         assert_eq!(device, image.device());
230 
231         if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
232             // VUID-vkCmdClearDepthStencilImage-image-01994
233             if !image
234                 .format_features()
235                 .intersects(FormatFeatures::TRANSFER_DST)
236             {
237                 return Err(ClearError::MissingFormatFeature {
238                     format_feature: "transfer_dst",
239                 });
240             }
241         }
242 
243         let image_aspects = image.format().aspects();
244 
245         // VUID-vkCmdClearDepthStencilImage-image-00014
246         if !image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
247             return Err(ClearError::FormatNotSupported {
248                 format: image.format(),
249             });
250         }
251 
252         // VUID-vkCmdClearDepthStencilImage-imageLayout-00012
253         if !matches!(
254             image_layout,
255             ImageLayout::TransferDstOptimal | ImageLayout::General
256         ) {
257             return Err(ClearError::ImageLayoutInvalid { image_layout });
258         }
259 
260         // VUID-VkClearDepthStencilValue-depth-00022
261         if !device.enabled_extensions().ext_depth_range_unrestricted
262             && !(0.0..=1.0).contains(&clear_value.depth)
263         {
264             return Err(ClearError::RequirementNotMet {
265                 required_for: "`clear_info.clear_value.depth` is not between `0.0` and `1.0` \
266                     inclusive",
267                 requires_one_of: RequiresOneOf {
268                     device_extensions: &["ext_depth_range_unrestricted"],
269                     ..Default::default()
270                 },
271             });
272         }
273 
274         let mut image_aspects_used = ImageAspects::empty();
275 
276         for (region_index, subresource_range) in regions.iter().enumerate() {
277             // VUID-VkImageSubresourceRange-aspectMask-parameter
278             subresource_range.aspects.validate_device(device)?;
279 
280             // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
281             assert!(!subresource_range.aspects.is_empty());
282 
283             // VUID-vkCmdClearDepthStencilImage-aspectMask-02824
284             // VUID-vkCmdClearDepthStencilImage-image-02825
285             // VUID-vkCmdClearDepthStencilImage-image-02826
286             if !image_aspects.contains(subresource_range.aspects) {
287                 return Err(ClearError::AspectsNotAllowed {
288                     region_index,
289                     aspects: subresource_range.aspects,
290                     allowed_aspects: image_aspects,
291                 });
292             }
293 
294             image_aspects_used |= subresource_range.aspects;
295 
296             // VUID-VkImageSubresourceRange-levelCount-01720
297             assert!(!subresource_range.mip_levels.is_empty());
298 
299             // VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474
300             // VUID-vkCmdClearDepthStencilImage-pRanges-01694
301             if subresource_range.mip_levels.end > image.mip_levels() {
302                 return Err(ClearError::MipLevelsOutOfRange {
303                     region_index,
304                     mip_levels_range_end: subresource_range.mip_levels.end,
305                     image_mip_levels: image.dimensions().array_layers(),
306                 });
307             }
308 
309             // VUID-VkImageSubresourceRange-layerCount-01721
310             assert!(!subresource_range.array_layers.is_empty());
311 
312             // VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476
313             // VUID-vkCmdClearDepthStencilImage-pRanges-01695
314             if subresource_range.array_layers.end > image.dimensions().array_layers() {
315                 return Err(ClearError::ArrayLayersOutOfRange {
316                     region_index,
317                     array_layers_range_end: subresource_range.array_layers.end,
318                     image_array_layers: image.dimensions().array_layers(),
319                 });
320             }
321         }
322 
323         // VUID-vkCmdClearDepthStencilImage-pRanges-02658
324         // VUID-vkCmdClearDepthStencilImage-pRanges-02659
325         if image_aspects_used.intersects(ImageAspects::STENCIL)
326             && !image.stencil_usage().intersects(ImageUsage::TRANSFER_DST)
327         {
328             return Err(ClearError::MissingUsage {
329                 usage: "transfer_dst",
330             });
331         }
332 
333         // VUID-vkCmdClearDepthStencilImage-pRanges-02660
334         if !(image_aspects_used - ImageAspects::STENCIL).is_empty()
335             && !image.usage().intersects(ImageUsage::TRANSFER_DST)
336         {
337             return Err(ClearError::MissingUsage {
338                 usage: "transfer_dst",
339             });
340         }
341 
342         Ok(())
343     }
344 
345     /// Fills a region of a buffer with repeated copies of a value.
346     ///
347     /// This function is similar to the `memset` function in C. The `data` parameter is a number
348     /// that will be repeatedly written through the entire buffer.
349     ///
350     /// # Panics
351     ///
352     /// - Panics if `dst_buffer` was not created from the same device as `self`.
fill_buffer( &mut self, dst_buffer: Subbuffer<[u32]>, data: u32, ) -> Result<&mut Self, ClearError>353     pub fn fill_buffer(
354         &mut self,
355         dst_buffer: Subbuffer<[u32]>,
356         data: u32,
357     ) -> Result<&mut Self, ClearError> {
358         self.validate_fill_buffer(&dst_buffer, data)?;
359 
360         unsafe {
361             self.inner.fill_buffer(dst_buffer, data)?;
362         }
363 
364         Ok(self)
365     }
366 
validate_fill_buffer( &self, dst_buffer: &Subbuffer<[u32]>, _data: u32, ) -> Result<(), ClearError>367     fn validate_fill_buffer(
368         &self,
369         dst_buffer: &Subbuffer<[u32]>,
370         _data: u32,
371     ) -> Result<(), ClearError> {
372         let device = self.device();
373 
374         // VUID-vkCmdFillBuffer-renderpass
375         if self.render_pass_state.is_some() {
376             return Err(ClearError::ForbiddenInsideRenderPass);
377         }
378 
379         let queue_family_properties = self.queue_family_properties();
380 
381         if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
382             // VUID-vkCmdFillBuffer-commandBuffer-cmdpool
383             if !queue_family_properties
384                 .queue_flags
385                 .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
386             {
387                 return Err(ClearError::NotSupportedByQueueFamily);
388             }
389         } else {
390             // VUID-vkCmdFillBuffer-commandBuffer-00030
391             if !queue_family_properties
392                 .queue_flags
393                 .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
394             {
395                 return Err(ClearError::NotSupportedByQueueFamily);
396             }
397         }
398 
399         // VUID-vkCmdFillBuffer-commonparent
400         assert_eq!(device, dst_buffer.device());
401 
402         // VUID-vkCmdFillBuffer-size-00026
403         // Guaranteed by `Subbuffer`
404 
405         // VUID-vkCmdFillBuffer-dstBuffer-00029
406         if !dst_buffer
407             .buffer()
408             .usage()
409             .intersects(BufferUsage::TRANSFER_DST)
410         {
411             return Err(ClearError::MissingUsage {
412                 usage: "transfer_dst",
413             });
414         }
415 
416         // VUID-vkCmdFillBuffer-dstOffset-00024
417         // VUID-vkCmdFillBuffer-size-00027
418         // Guaranteed by `Subbuffer`
419 
420         // VUID-vkCmdFillBuffer-dstOffset-00025
421         // VUID-vkCmdFillBuffer-size-00028
422         // Guaranteed because we take `Subbuffer<[u32]>`
423 
424         Ok(())
425     }
426 
427     /// Writes data to a region of a buffer.
428     ///
429     /// # Panics
430     ///
431     /// - Panics if `dst_buffer` was not created from the same device as `self`.
update_buffer<D, Dd>( &mut self, dst_buffer: Subbuffer<D>, data: Dd, ) -> Result<&mut Self, ClearError> where D: BufferContents + ?Sized, Dd: SafeDeref<Target = D> + Send + Sync + 'static,432     pub fn update_buffer<D, Dd>(
433         &mut self,
434         dst_buffer: Subbuffer<D>,
435         data: Dd,
436     ) -> Result<&mut Self, ClearError>
437     where
438         D: BufferContents + ?Sized,
439         Dd: SafeDeref<Target = D> + Send + Sync + 'static,
440     {
441         self.validate_update_buffer(
442             dst_buffer.as_bytes(),
443             size_of_val(data.deref()) as DeviceSize,
444         )?;
445 
446         unsafe {
447             self.inner.update_buffer(dst_buffer, data)?;
448         }
449 
450         Ok(self)
451     }
452 
validate_update_buffer( &self, dst_buffer: &Subbuffer<[u8]>, data_size: DeviceSize, ) -> Result<(), ClearError>453     fn validate_update_buffer(
454         &self,
455         dst_buffer: &Subbuffer<[u8]>,
456         data_size: DeviceSize,
457     ) -> Result<(), ClearError> {
458         let device = self.device();
459 
460         // VUID-vkCmdUpdateBuffer-renderpass
461         if self.render_pass_state.is_some() {
462             return Err(ClearError::ForbiddenInsideRenderPass);
463         }
464 
465         let queue_family_properties = self.queue_family_properties();
466 
467         // VUID-vkCmdUpdateBuffer-commandBuffer-cmdpool
468         if !queue_family_properties
469             .queue_flags
470             .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
471         {
472             return Err(ClearError::NotSupportedByQueueFamily);
473         }
474 
475         // VUID-vkCmdUpdateBuffer-commonparent
476         assert_eq!(device, dst_buffer.device());
477 
478         // VUID-vkCmdUpdateBuffer-dataSize-arraylength
479         assert!(data_size != 0);
480 
481         // VUID-vkCmdUpdateBuffer-dstBuffer-00034
482         if !dst_buffer
483             .buffer()
484             .usage()
485             .intersects(BufferUsage::TRANSFER_DST)
486         {
487             return Err(ClearError::MissingUsage {
488                 usage: "transfer_dst",
489             });
490         }
491 
492         // VUID-vkCmdUpdateBuffer-dstOffset-00032
493         // VUID-vkCmdUpdateBuffer-dataSize-00033
494         if data_size > dst_buffer.size() {
495             return Err(ClearError::RegionOutOfBufferBounds {
496                 region_index: 0,
497                 offset_range_end: data_size,
498                 buffer_size: dst_buffer.size(),
499             });
500         }
501 
502         // VUID-vkCmdUpdateBuffer-dstOffset-00036
503         if dst_buffer.offset() % 4 != 0 {
504             return Err(ClearError::OffsetNotAlignedForBuffer {
505                 region_index: 0,
506                 offset: dst_buffer.offset(),
507                 required_alignment: 4,
508             });
509         }
510 
511         // VUID-vkCmdUpdateBuffer-dataSize-00037
512         if data_size > 65536 {
513             return Err(ClearError::DataTooLarge {
514                 size: data_size,
515                 max: 65536,
516             });
517         }
518 
519         // VUID-vkCmdUpdateBuffer-dataSize-00038
520         if data_size % 4 != 0 {
521             return Err(ClearError::SizeNotAlignedForBuffer {
522                 region_index: 0,
523                 size: data_size,
524                 required_alignment: 4,
525             });
526         }
527 
528         Ok(())
529     }
530 }
531 
532 impl SyncCommandBufferBuilder {
533     /// Calls `vkCmdClearColorImage` on the builder.
534     ///
535     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
536     /// usage of the command anyway.
537     #[inline]
clear_color_image( &mut self, clear_info: ClearColorImageInfo, ) -> Result<(), SyncCommandBufferBuilderError>538     pub unsafe fn clear_color_image(
539         &mut self,
540         clear_info: ClearColorImageInfo,
541     ) -> Result<(), SyncCommandBufferBuilderError> {
542         struct Cmd {
543             clear_info: ClearColorImageInfo,
544         }
545 
546         impl Command for Cmd {
547             fn name(&self) -> &'static str {
548                 "clear_color_image"
549             }
550 
551             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
552                 out.clear_color_image(&self.clear_info);
553             }
554         }
555 
556         let &ClearColorImageInfo {
557             ref image,
558             image_layout,
559             clear_value: _,
560             ref regions,
561             _ne: _,
562         } = &clear_info;
563 
564         let command_index = self.commands.len();
565         let command_name = "clear_color_image";
566         let resources: SmallVec<[_; 8]> = regions
567             .iter()
568             .cloned()
569             .flat_map(|subresource_range| {
570                 [(
571                     ResourceUseRef {
572                         command_index,
573                         command_name,
574                         resource_in_command: ResourceInCommand::Destination,
575                         secondary_use_ref: None,
576                     },
577                     Resource::Image {
578                         image: image.clone(),
579                         subresource_range,
580                         memory: PipelineMemoryAccess {
581                             stages: PipelineStages::ALL_TRANSFER,
582                             access: AccessFlags::TRANSFER_WRITE,
583                             exclusive: true,
584                         },
585                         start_layout: image_layout,
586                         end_layout: image_layout,
587                     },
588                 )]
589             })
590             .collect();
591 
592         for resource in &resources {
593             self.check_resource_conflicts(resource)?;
594         }
595 
596         self.commands.push(Box::new(Cmd { clear_info }));
597 
598         for resource in resources {
599             self.add_resource(resource);
600         }
601 
602         Ok(())
603     }
604 
605     /// Calls `vkCmdClearDepthStencilImage` on the builder.
606     ///
607     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
608     /// usage of the command anyway.
609     #[inline]
clear_depth_stencil_image( &mut self, clear_info: ClearDepthStencilImageInfo, ) -> Result<(), SyncCommandBufferBuilderError>610     pub unsafe fn clear_depth_stencil_image(
611         &mut self,
612         clear_info: ClearDepthStencilImageInfo,
613     ) -> Result<(), SyncCommandBufferBuilderError> {
614         struct Cmd {
615             clear_info: ClearDepthStencilImageInfo,
616         }
617 
618         impl Command for Cmd {
619             fn name(&self) -> &'static str {
620                 "clear_depth_stencil_image"
621             }
622 
623             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
624                 out.clear_depth_stencil_image(&self.clear_info);
625             }
626         }
627 
628         let &ClearDepthStencilImageInfo {
629             ref image,
630             image_layout,
631             clear_value: _,
632             ref regions,
633             _ne: _,
634         } = &clear_info;
635 
636         let command_index = self.commands.len();
637         let command_name = "clear_depth_stencil_image";
638         let resources: SmallVec<[_; 8]> = regions
639             .iter()
640             .cloned()
641             .flat_map(|subresource_range| {
642                 [(
643                     ResourceUseRef {
644                         command_index,
645                         command_name,
646                         resource_in_command: ResourceInCommand::Destination,
647                         secondary_use_ref: None,
648                     },
649                     Resource::Image {
650                         image: image.clone(),
651                         subresource_range,
652                         memory: PipelineMemoryAccess {
653                             stages: PipelineStages::ALL_TRANSFER,
654                             access: AccessFlags::TRANSFER_WRITE,
655                             exclusive: true,
656                         },
657                         start_layout: image_layout,
658                         end_layout: image_layout,
659                     },
660                 )]
661             })
662             .collect();
663 
664         for resource in &resources {
665             self.check_resource_conflicts(resource)?;
666         }
667 
668         self.commands.push(Box::new(Cmd { clear_info }));
669 
670         for resource in resources {
671             self.add_resource(resource);
672         }
673 
674         Ok(())
675     }
676 
677     /// Calls `vkCmdFillBuffer` on the builder.
678     #[inline]
fill_buffer( &mut self, dst_buffer: Subbuffer<[u32]>, data: u32, ) -> Result<(), SyncCommandBufferBuilderError>679     pub unsafe fn fill_buffer(
680         &mut self,
681         dst_buffer: Subbuffer<[u32]>,
682         data: u32,
683     ) -> Result<(), SyncCommandBufferBuilderError> {
684         struct Cmd {
685             dst_buffer: Subbuffer<[u32]>,
686             data: u32,
687         }
688 
689         impl Command for Cmd {
690             fn name(&self) -> &'static str {
691                 "fill_buffer"
692             }
693 
694             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
695                 out.fill_buffer(&self.dst_buffer, self.data);
696             }
697         }
698 
699         let command_index = self.commands.len();
700         let command_name = "fill_buffer";
701         let resources = [(
702             ResourceUseRef {
703                 command_index,
704                 command_name,
705                 resource_in_command: ResourceInCommand::Destination,
706                 secondary_use_ref: None,
707             },
708             Resource::Buffer {
709                 buffer: dst_buffer.as_bytes().clone(),
710                 range: 0..dst_buffer.size(),
711                 memory: PipelineMemoryAccess {
712                     stages: PipelineStages::ALL_TRANSFER,
713                     access: AccessFlags::TRANSFER_WRITE,
714                     exclusive: true,
715                 },
716             },
717         )];
718 
719         for resource in &resources {
720             self.check_resource_conflicts(resource)?;
721         }
722 
723         self.commands.push(Box::new(Cmd { dst_buffer, data }));
724 
725         for resource in resources {
726             self.add_resource(resource);
727         }
728 
729         Ok(())
730     }
731 
732     /// Calls `vkCmdUpdateBuffer` on the builder.
update_buffer<D, Dd>( &mut self, dst_buffer: Subbuffer<D>, data: Dd, ) -> Result<(), SyncCommandBufferBuilderError> where D: BufferContents + ?Sized, Dd: SafeDeref<Target = D> + Send + Sync + 'static,733     pub unsafe fn update_buffer<D, Dd>(
734         &mut self,
735         dst_buffer: Subbuffer<D>,
736         data: Dd,
737     ) -> Result<(), SyncCommandBufferBuilderError>
738     where
739         D: BufferContents + ?Sized,
740         Dd: SafeDeref<Target = D> + Send + Sync + 'static,
741     {
742         struct Cmd<D: ?Sized, Dd> {
743             dst_buffer: Subbuffer<D>,
744             data: Dd,
745         }
746 
747         impl<D, Dd> Command for Cmd<D, Dd>
748         where
749             D: BufferContents + ?Sized,
750             Dd: SafeDeref<Target = D> + Send + Sync + 'static,
751         {
752             fn name(&self) -> &'static str {
753                 "update_buffer"
754             }
755 
756             unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
757                 out.update_buffer(&self.dst_buffer, self.data.deref());
758             }
759         }
760 
761         let command_index = self.commands.len();
762         let command_name = "update_buffer";
763         let resources = [(
764             ResourceUseRef {
765                 command_index,
766                 command_name,
767                 resource_in_command: ResourceInCommand::Destination,
768                 secondary_use_ref: None,
769             },
770             Resource::Buffer {
771                 buffer: dst_buffer.as_bytes().clone(),
772                 range: 0..size_of_val(data.deref()) as DeviceSize,
773                 memory: PipelineMemoryAccess {
774                     stages: PipelineStages::ALL_TRANSFER,
775                     access: AccessFlags::TRANSFER_WRITE,
776                     exclusive: true,
777                 },
778             },
779         )];
780 
781         for resource in &resources {
782             self.check_resource_conflicts(resource)?;
783         }
784 
785         self.commands.push(Box::new(Cmd { dst_buffer, data }));
786 
787         for resource in resources {
788             self.add_resource(resource);
789         }
790 
791         Ok(())
792     }
793 }
794 
795 impl UnsafeCommandBufferBuilder {
796     /// Calls `vkCmdClearColorImage` on the builder.
797     ///
798     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
799     /// usage of the command anyway.
800     #[inline]
clear_color_image(&mut self, clear_info: &ClearColorImageInfo)801     pub unsafe fn clear_color_image(&mut self, clear_info: &ClearColorImageInfo) {
802         let &ClearColorImageInfo {
803             ref image,
804             image_layout,
805             clear_value,
806             ref regions,
807             _ne: _,
808         } = clear_info;
809 
810         if regions.is_empty() {
811             return;
812         }
813 
814         let clear_value = clear_value.into();
815         let ranges: SmallVec<[_; 8]> = regions
816             .iter()
817             .cloned()
818             .map(ash::vk::ImageSubresourceRange::from)
819             .collect();
820 
821         let fns = self.device.fns();
822         (fns.v1_0.cmd_clear_color_image)(
823             self.handle,
824             image.inner().image.handle(),
825             image_layout.into(),
826             &clear_value,
827             ranges.len() as u32,
828             ranges.as_ptr(),
829         );
830     }
831 
832     /// Calls `vkCmdClearDepthStencilImage` on the builder.
833     ///
834     /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
835     /// usage of the command anyway.
836     #[inline]
clear_depth_stencil_image(&mut self, clear_info: &ClearDepthStencilImageInfo)837     pub unsafe fn clear_depth_stencil_image(&mut self, clear_info: &ClearDepthStencilImageInfo) {
838         let &ClearDepthStencilImageInfo {
839             ref image,
840             image_layout,
841             clear_value,
842             ref regions,
843             _ne: _,
844         } = clear_info;
845 
846         if regions.is_empty() {
847             return;
848         }
849 
850         let clear_value = clear_value.into();
851         let ranges: SmallVec<[_; 8]> = regions
852             .iter()
853             .cloned()
854             .map(ash::vk::ImageSubresourceRange::from)
855             .collect();
856 
857         let fns = self.device.fns();
858         (fns.v1_0.cmd_clear_depth_stencil_image)(
859             self.handle,
860             image.inner().image.handle(),
861             image_layout.into(),
862             &clear_value,
863             ranges.len() as u32,
864             ranges.as_ptr(),
865         );
866     }
867 
868     /// Calls `vkCmdFillBuffer` on the builder.
869     #[inline]
fill_buffer(&mut self, dst_buffer: &Subbuffer<[u32]>, data: u32)870     pub unsafe fn fill_buffer(&mut self, dst_buffer: &Subbuffer<[u32]>, data: u32) {
871         let fns = self.device.fns();
872         (fns.v1_0.cmd_fill_buffer)(
873             self.handle,
874             dst_buffer.buffer().handle(),
875             dst_buffer.offset(),
876             dst_buffer.size(),
877             data,
878         );
879     }
880 
881     /// Calls `vkCmdUpdateBuffer` on the builder.
update_buffer<D>(&mut self, dst_buffer: &Subbuffer<D>, data: &D) where D: BufferContents + ?Sized,882     pub unsafe fn update_buffer<D>(&mut self, dst_buffer: &Subbuffer<D>, data: &D)
883     where
884         D: BufferContents + ?Sized,
885     {
886         let fns = self.device.fns();
887         (fns.v1_0.cmd_update_buffer)(
888             self.handle,
889             dst_buffer.buffer().handle(),
890             dst_buffer.offset(),
891             size_of_val(data) as DeviceSize,
892             data as *const _ as *const _,
893         );
894     }
895 }
896 
897 /// Parameters to clear a color image.
898 #[derive(Clone, Debug)]
899 pub struct ClearColorImageInfo {
900     /// The image to clear.
901     ///
902     /// There is no default value.
903     pub image: Arc<dyn ImageAccess>,
904 
905     /// The layout used for `image` during the clear operation.
906     ///
907     /// The following layouts are allowed:
908     /// - [`ImageLayout::TransferDstOptimal`]
909     /// - [`ImageLayout::General`]
910     ///
911     /// The default value is [`ImageLayout::TransferDstOptimal`].
912     pub image_layout: ImageLayout,
913 
914     /// The color value to clear the image to.
915     ///
916     /// The default value is `ClearColorValue::Float([0.0; 4])`.
917     pub clear_value: ClearColorValue,
918 
919     /// The subresource ranges of `image` to clear.
920     ///
921     /// The default value is a single region, covering the whole image.
922     pub regions: SmallVec<[ImageSubresourceRange; 1]>,
923 
924     pub _ne: crate::NonExhaustive,
925 }
926 
927 impl ClearColorImageInfo {
928     /// Returns a `ClearColorImageInfo` with the specified `image`.
929     #[inline]
image(image: Arc<dyn ImageAccess>) -> Self930     pub fn image(image: Arc<dyn ImageAccess>) -> Self {
931         let range = image.subresource_range();
932 
933         Self {
934             image,
935             image_layout: ImageLayout::TransferDstOptimal,
936             clear_value: ClearColorValue::Float([0.0; 4]),
937             regions: smallvec![range],
938             _ne: crate::NonExhaustive(()),
939         }
940     }
941 }
942 
943 /// Parameters to clear a depth/stencil image.
944 #[derive(Clone, Debug)]
945 pub struct ClearDepthStencilImageInfo {
946     /// The image to clear.
947     ///
948     /// There is no default value.
949     pub image: Arc<dyn ImageAccess>,
950 
951     /// The layout used for `image` during the clear operation.
952     ///
953     /// The following layouts are allowed:
954     /// - [`ImageLayout::TransferDstOptimal`]
955     /// - [`ImageLayout::General`]
956     ///
957     /// The default value is [`ImageLayout::TransferDstOptimal`].
958     pub image_layout: ImageLayout,
959 
960     /// The depth/stencil values to clear the image to.
961     ///
962     /// The default value is zero for both.
963     pub clear_value: ClearDepthStencilValue,
964 
965     /// The subresource ranges of `image` to clear.
966     ///
967     /// The default value is a single region, covering the whole image.
968     pub regions: SmallVec<[ImageSubresourceRange; 1]>,
969 
970     pub _ne: crate::NonExhaustive,
971 }
972 
973 impl ClearDepthStencilImageInfo {
974     /// Returns a `ClearDepthStencilImageInfo` with the specified `image`.
975     #[inline]
image(image: Arc<dyn ImageAccess>) -> Self976     pub fn image(image: Arc<dyn ImageAccess>) -> Self {
977         let range = image.subresource_range();
978 
979         Self {
980             image,
981             image_layout: ImageLayout::TransferDstOptimal,
982             clear_value: ClearDepthStencilValue::default(),
983             regions: smallvec![range],
984             _ne: crate::NonExhaustive(()),
985         }
986     }
987 }
988 
989 /// Error that can happen when recording a clear command.
990 #[derive(Clone, Debug)]
991 pub enum ClearError {
992     SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
993 
994     RequirementNotMet {
995         required_for: &'static str,
996         requires_one_of: RequiresOneOf,
997     },
998 
999     /// Operation forbidden inside of a render pass.
1000     ForbiddenInsideRenderPass,
1001 
1002     /// The queue family doesn't allow this operation.
1003     NotSupportedByQueueFamily,
1004 
1005     /// The end of the range of accessed array layers of the subresource range of a region is
1006     /// greater than the number of array layers in the image.
1007     ArrayLayersOutOfRange {
1008         region_index: usize,
1009         array_layers_range_end: u32,
1010         image_array_layers: u32,
1011     },
1012 
1013     /// The aspects of the subresource range of a region contain aspects that are not present
1014     /// in the image, or that are not allowed.
1015     AspectsNotAllowed {
1016         region_index: usize,
1017         aspects: ImageAspects,
1018         allowed_aspects: ImageAspects,
1019     },
1020 
1021     /// The provided data has a size larger than the maximum allowed.
1022     DataTooLarge {
1023         size: DeviceSize,
1024         max: DeviceSize,
1025     },
1026 
1027     /// The format of an image is not supported for this operation.
1028     FormatNotSupported {
1029         format: Format,
1030     },
1031 
1032     /// A specified image layout is not valid for this operation.
1033     ImageLayoutInvalid {
1034         image_layout: ImageLayout,
1035     },
1036 
1037     /// The end of the range of accessed mip levels of the subresource range of a region is greater
1038     /// than the number of mip levels in the image.
1039     MipLevelsOutOfRange {
1040         region_index: usize,
1041         mip_levels_range_end: u32,
1042         image_mip_levels: u32,
1043     },
1044 
1045     /// An image does not have a required format feature.
1046     MissingFormatFeature {
1047         format_feature: &'static str,
1048     },
1049 
1050     /// A resource did not have a required usage enabled.
1051     MissingUsage {
1052         usage: &'static str,
1053     },
1054 
1055     /// The buffer offset of a region is not a multiple of the required buffer alignment.
1056     OffsetNotAlignedForBuffer {
1057         region_index: usize,
1058         offset: DeviceSize,
1059         required_alignment: DeviceSize,
1060     },
1061 
1062     /// The end of the range of accessed byte offsets of a region is greater than the size of the
1063     /// buffer.
1064     RegionOutOfBufferBounds {
1065         region_index: usize,
1066         offset_range_end: DeviceSize,
1067         buffer_size: DeviceSize,
1068     },
1069 
1070     /// The buffer size of a region is not a multiple of the required buffer alignment.
1071     SizeNotAlignedForBuffer {
1072         region_index: usize,
1073         size: DeviceSize,
1074         required_alignment: DeviceSize,
1075     },
1076 }
1077 
1078 impl Error for ClearError {
source(&self) -> Option<&(dyn Error + 'static)>1079     fn source(&self) -> Option<&(dyn Error + 'static)> {
1080         match self {
1081             Self::SyncCommandBufferBuilderError(err) => Some(err),
1082             _ => None,
1083         }
1084     }
1085 }
1086 
1087 impl Display for ClearError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1088     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1089         match self {
1090             Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
1091             Self::RequirementNotMet {
1092                 required_for,
1093                 requires_one_of,
1094             } => write!(
1095                 f,
1096                 "a requirement was not met for: {}; requires one of: {}",
1097                 required_for, requires_one_of,
1098             ),
1099             Self::ForbiddenInsideRenderPass => {
1100                 write!(f, "operation forbidden inside of a render pass")
1101             }
1102             Self::NotSupportedByQueueFamily => {
1103                 write!(f, "the queue family doesn't allow this operation")
1104             }
1105             Self::ArrayLayersOutOfRange {
1106                 region_index,
1107                 array_layers_range_end,
1108                 image_array_layers,
1109             } => write!(
1110                 f,
1111                 "the end of the range of accessed array layers ({}) of the subresource range of \
1112                 region {} is greater than the number of array layers in the image ({})",
1113                 array_layers_range_end, region_index, image_array_layers,
1114             ),
1115             Self::AspectsNotAllowed {
1116                 region_index,
1117                 aspects,
1118                 allowed_aspects,
1119             } => write!(
1120                 f,
1121                 "the aspects ({:?}) of the subresource range of region {} contain aspects that \
1122                 are not present in the image, or that are not allowed ({:?})",
1123                 aspects, region_index, allowed_aspects,
1124             ),
1125             Self::DataTooLarge { size, max } => write!(
1126                 f,
1127                 "the provided data has a size ({}) greater than the maximum allowed ({})",
1128                 size, max,
1129             ),
1130             Self::FormatNotSupported { format } => write!(
1131                 f,
1132                 "the format of the image ({:?}) is not supported for this operation",
1133                 format,
1134             ),
1135             Self::ImageLayoutInvalid { image_layout } => write!(
1136                 f,
1137                 "the specified image layout {:?} is not valid for this operation",
1138                 image_layout,
1139             ),
1140             Self::MipLevelsOutOfRange {
1141                 region_index,
1142                 mip_levels_range_end,
1143                 image_mip_levels,
1144             } => write!(
1145                 f,
1146                 "the end of the range of accessed mip levels ({}) of the subresource range of \
1147                 region {} is not less than the number of mip levels in the image ({})",
1148                 mip_levels_range_end, region_index, image_mip_levels,
1149             ),
1150             Self::MissingFormatFeature { format_feature } => write!(
1151                 f,
1152                 "the image does not have the required format feature {}",
1153                 format_feature,
1154             ),
1155             Self::MissingUsage { usage } => write!(
1156                 f,
1157                 "the resource did not have the required usage {} enabled",
1158                 usage,
1159             ),
1160             Self::OffsetNotAlignedForBuffer {
1161                 region_index,
1162                 offset,
1163                 required_alignment,
1164             } => write!(
1165                 f,
1166                 "the buffer offset ({}) of region {} is not a multiple of the required \
1167                 buffer alignment ({})",
1168                 offset, region_index, required_alignment,
1169             ),
1170             Self::RegionOutOfBufferBounds {
1171                 region_index,
1172                 offset_range_end,
1173                 buffer_size,
1174             } => write!(
1175                 f,
1176                 "the end of the range of accessed byte offsets ({}) of region {} is greater \
1177                 than the size of the buffer ({})",
1178                 offset_range_end, region_index, buffer_size,
1179             ),
1180             Self::SizeNotAlignedForBuffer {
1181                 region_index,
1182                 size,
1183                 required_alignment,
1184             } => write!(
1185                 f,
1186                 "the buffer size ({}) of region {} is not a multiple of the required buffer \
1187                 alignment ({})",
1188                 size, region_index, required_alignment,
1189             ),
1190         }
1191     }
1192 }
1193 
1194 impl From<SyncCommandBufferBuilderError> for ClearError {
from(err: SyncCommandBufferBuilderError) -> Self1195     fn from(err: SyncCommandBufferBuilderError) -> Self {
1196         Self::SyncCommandBufferBuilderError(err)
1197     }
1198 }
1199 
1200 impl From<RequirementNotMet> for ClearError {
from(err: RequirementNotMet) -> Self1201     fn from(err: RequirementNotMet) -> Self {
1202         Self::RequirementNotMet {
1203             required_for: err.required_for,
1204             requires_one_of: err.requires_one_of,
1205         }
1206     }
1207 }
1208