1 // Copyright (c) 2016 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::{
11     allocator::{
12         CommandBufferAlloc, CommandBufferAllocator, CommandBufferBuilderAlloc,
13         StandardCommandBufferAlloc, StandardCommandBufferAllocator,
14     },
15     synced::{CommandBufferBuilderState, SyncCommandBuffer, SyncCommandBufferBuilder},
16     sys::CommandBufferBeginInfo,
17     CommandBufferExecError, CommandBufferInheritanceInfo, CommandBufferInheritanceRenderPassInfo,
18     CommandBufferInheritanceRenderPassType, CommandBufferLevel, CommandBufferResourcesUsage,
19     CommandBufferState, CommandBufferUsage, PrimaryCommandBufferAbstract, RenderingAttachmentInfo,
20     SecondaryCommandBufferAbstract, SecondaryCommandBufferResourcesUsage, SubpassContents,
21 };
22 use crate::{
23     command_buffer::CommandBufferInheritanceRenderingInfo,
24     device::{Device, DeviceOwned, QueueFamilyProperties},
25     format::{Format, FormatFeatures},
26     image::ImageAspects,
27     query::{QueryControlFlags, QueryType},
28     render_pass::{Framebuffer, Subpass},
29     OomError, RequirementNotMet, RequiresOneOf, VulkanObject,
30 };
31 use ahash::HashMap;
32 use parking_lot::{Mutex, MutexGuard};
33 use std::{
34     error::Error,
35     fmt::{Display, Error as FmtError, Formatter},
36     marker::PhantomData,
37     sync::{
38         atomic::{AtomicBool, Ordering},
39         Arc,
40     },
41 };
42 
43 /// Note that command buffers allocated from `StandardCommandBufferAllocator` don't implement
44 /// the `Send` and `Sync` traits. If you use this allocator, then the `AutoCommandBufferBuilder`
45 /// will not implement `Send` and `Sync` either. Once a command buffer is built, however, it *does*
46 /// implement `Send` and `Sync`.
47 pub struct AutoCommandBufferBuilder<L, A = StandardCommandBufferAllocator>
48 where
49     A: CommandBufferAllocator,
50 {
51     pub(super) inner: SyncCommandBufferBuilder,
52     builder_alloc: A::Builder, // Safety: must be dropped after `inner`
53 
54     // The index of the queue family that this command buffer is being created for.
55     queue_family_index: u32,
56 
57     // The inheritance for secondary command buffers.
58     // Must be `None` in a primary command buffer and `Some` in a secondary command buffer.
59     pub(super) inheritance_info: Option<CommandBufferInheritanceInfo>,
60 
61     // Usage flags passed when creating the command buffer.
62     pub(super) usage: CommandBufferUsage,
63 
64     // If we're inside a render pass, contains the render pass state.
65     pub(super) render_pass_state: Option<RenderPassState>,
66 
67     // If any queries are active, this hashmap contains their state.
68     pub(super) query_state: HashMap<ash::vk::QueryType, QueryState>,
69 
70     _data: PhantomData<L>,
71 }
72 
73 // The state of the current render pass.
74 pub(super) struct RenderPassState {
75     pub(super) contents: SubpassContents,
76     pub(super) render_area_offset: [u32; 2],
77     pub(super) render_area_extent: [u32; 2],
78     pub(super) render_pass: RenderPassStateType,
79     pub(super) view_mask: u32,
80 }
81 
82 pub(super) enum RenderPassStateType {
83     BeginRenderPass(BeginRenderPassState),
84     BeginRendering(BeginRenderingState),
85 }
86 
87 impl From<BeginRenderPassState> for RenderPassStateType {
from(val: BeginRenderPassState) -> Self88     fn from(val: BeginRenderPassState) -> Self {
89         Self::BeginRenderPass(val)
90     }
91 }
92 
93 impl From<BeginRenderingState> for RenderPassStateType {
from(val: BeginRenderingState) -> Self94     fn from(val: BeginRenderingState) -> Self {
95         Self::BeginRendering(val)
96     }
97 }
98 
99 pub(super) struct BeginRenderPassState {
100     pub(super) subpass: Subpass,
101     pub(super) framebuffer: Option<Arc<Framebuffer>>,
102 }
103 
104 pub(super) struct BeginRenderingState {
105     pub(super) attachments: Option<BeginRenderingAttachments>,
106     pub(super) color_attachment_formats: Vec<Option<Format>>,
107     pub(super) depth_attachment_format: Option<Format>,
108     pub(super) stencil_attachment_format: Option<Format>,
109     pub(super) pipeline_used: bool,
110 }
111 
112 pub(super) struct BeginRenderingAttachments {
113     pub(super) color_attachments: Vec<Option<RenderingAttachmentInfo>>,
114     pub(super) depth_attachment: Option<RenderingAttachmentInfo>,
115     pub(super) stencil_attachment: Option<RenderingAttachmentInfo>,
116 }
117 
118 // The state of an active query.
119 pub(super) struct QueryState {
120     pub(super) query_pool: ash::vk::QueryPool,
121     pub(super) query: u32,
122     pub(super) ty: QueryType,
123     pub(super) flags: QueryControlFlags,
124     pub(super) in_subpass: bool,
125 }
126 
127 impl<A> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, A>
128 where
129     A: CommandBufferAllocator,
130 {
131     /// Starts recording a primary command buffer.
132     #[inline]
primary( allocator: &A, queue_family_index: u32, usage: CommandBufferUsage, ) -> Result< AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<A::Alloc>, A>, CommandBufferBeginError, >133     pub fn primary(
134         allocator: &A,
135         queue_family_index: u32,
136         usage: CommandBufferUsage,
137     ) -> Result<
138         AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<A::Alloc>, A>,
139         CommandBufferBeginError,
140     > {
141         unsafe {
142             AutoCommandBufferBuilder::begin(
143                 allocator,
144                 queue_family_index,
145                 CommandBufferLevel::Primary,
146                 CommandBufferBeginInfo {
147                     usage,
148                     inheritance_info: None,
149                     _ne: crate::NonExhaustive(()),
150                 },
151             )
152         }
153     }
154 }
155 
156 impl<A> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, A>
157 where
158     A: CommandBufferAllocator,
159 {
160     /// Starts recording a secondary command buffer.
161     #[inline]
secondary( allocator: &A, queue_family_index: u32, usage: CommandBufferUsage, inheritance_info: CommandBufferInheritanceInfo, ) -> Result< AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<A::Alloc>, A>, CommandBufferBeginError, >162     pub fn secondary(
163         allocator: &A,
164         queue_family_index: u32,
165         usage: CommandBufferUsage,
166         inheritance_info: CommandBufferInheritanceInfo,
167     ) -> Result<
168         AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<A::Alloc>, A>,
169         CommandBufferBeginError,
170     > {
171         unsafe {
172             AutoCommandBufferBuilder::begin(
173                 allocator,
174                 queue_family_index,
175                 CommandBufferLevel::Secondary,
176                 CommandBufferBeginInfo {
177                     usage,
178                     inheritance_info: Some(inheritance_info),
179                     _ne: crate::NonExhaustive(()),
180                 },
181             )
182         }
183     }
184 }
185 
186 impl<L, A> AutoCommandBufferBuilder<L, A>
187 where
188     A: CommandBufferAllocator,
189 {
190     // Actual constructor. Private.
191     //
192     // `begin_info.inheritance_info` must match `level`.
begin( allocator: &A, queue_family_index: u32, level: CommandBufferLevel, begin_info: CommandBufferBeginInfo, ) -> Result<AutoCommandBufferBuilder<L, A>, CommandBufferBeginError>193     unsafe fn begin(
194         allocator: &A,
195         queue_family_index: u32,
196         level: CommandBufferLevel,
197         begin_info: CommandBufferBeginInfo,
198     ) -> Result<AutoCommandBufferBuilder<L, A>, CommandBufferBeginError> {
199         Self::validate_begin(allocator.device(), queue_family_index, level, &begin_info)?;
200 
201         let &CommandBufferBeginInfo {
202             usage,
203             ref inheritance_info,
204             _ne: _,
205         } = &begin_info;
206 
207         let inheritance_info = inheritance_info.clone();
208         let mut render_pass_state = None;
209 
210         if let Some(inheritance_info) = &inheritance_info {
211             let &CommandBufferInheritanceInfo {
212                 ref render_pass,
213                 occlusion_query: _,
214                 query_statistics_flags: _,
215                 _ne: _,
216             } = inheritance_info;
217 
218             if let Some(render_pass) = render_pass {
219                 // In a secondary command buffer, we don't know the render area yet, so use a
220                 // dummy value.
221                 let render_area_offset = [0, 0];
222                 let mut render_area_extent = [u32::MAX, u32::MAX];
223 
224                 match render_pass {
225                     CommandBufferInheritanceRenderPassType::BeginRenderPass(info) => {
226                         if let Some(framebuffer) = &info.framebuffer {
227                             // Still not exact, but it's a better upper bound.
228                             render_area_extent = framebuffer.extent();
229                         }
230 
231                         render_pass_state = Some(RenderPassState {
232                             contents: SubpassContents::Inline,
233                             render_area_offset,
234                             render_area_extent,
235                             render_pass: BeginRenderPassState {
236                                 subpass: info.subpass.clone(),
237                                 framebuffer: info.framebuffer.clone(),
238                             }
239                             .into(),
240                             view_mask: info.subpass.subpass_desc().view_mask,
241                         });
242                     }
243                     CommandBufferInheritanceRenderPassType::BeginRendering(info) => {
244                         render_pass_state = Some(RenderPassState {
245                             contents: SubpassContents::Inline,
246                             render_area_offset,
247                             render_area_extent,
248                             render_pass: BeginRenderingState {
249                                 attachments: None,
250                                 color_attachment_formats: info.color_attachment_formats.clone(),
251                                 depth_attachment_format: info.depth_attachment_format,
252                                 stencil_attachment_format: info.stencil_attachment_format,
253                                 pipeline_used: false,
254                             }
255                             .into(),
256                             view_mask: info.view_mask,
257                         });
258                     }
259                 }
260             }
261         }
262 
263         let builder_alloc = allocator
264             .allocate(queue_family_index, level, 1)?
265             .next()
266             .expect("requested one command buffer from the command pool, but got zero");
267 
268         let inner = SyncCommandBufferBuilder::new(builder_alloc.inner(), begin_info)?;
269 
270         Ok(AutoCommandBufferBuilder {
271             inner,
272             builder_alloc,
273             queue_family_index,
274             render_pass_state,
275             query_state: HashMap::default(),
276             inheritance_info,
277             usage,
278             _data: PhantomData,
279         })
280     }
281 
validate_begin( device: &Device, _queue_family_index: u32, level: CommandBufferLevel, begin_info: &CommandBufferBeginInfo, ) -> Result<(), CommandBufferBeginError>282     fn validate_begin(
283         device: &Device,
284         _queue_family_index: u32,
285         level: CommandBufferLevel,
286         begin_info: &CommandBufferBeginInfo,
287     ) -> Result<(), CommandBufferBeginError> {
288         let physical_device = device.physical_device();
289         let properties = physical_device.properties();
290 
291         let &CommandBufferBeginInfo {
292             usage: _,
293             ref inheritance_info,
294             _ne: _,
295         } = &begin_info;
296 
297         if let Some(inheritance_info) = &inheritance_info {
298             debug_assert!(level == CommandBufferLevel::Secondary);
299 
300             let &CommandBufferInheritanceInfo {
301                 ref render_pass,
302                 occlusion_query,
303                 query_statistics_flags,
304                 _ne: _,
305             } = inheritance_info;
306 
307             if let Some(render_pass) = render_pass {
308                 // VUID-VkCommandBufferBeginInfo-flags-06000
309                 // VUID-VkCommandBufferBeginInfo-flags-06002
310                 // Ensured by the definition of the `CommandBufferInheritanceRenderPassType` enum.
311 
312                 match render_pass {
313                     CommandBufferInheritanceRenderPassType::BeginRenderPass(render_pass_info) => {
314                         let &CommandBufferInheritanceRenderPassInfo {
315                             ref subpass,
316                             ref framebuffer,
317                         } = render_pass_info;
318 
319                         // VUID-VkCommandBufferInheritanceInfo-commonparent
320                         assert_eq!(device, subpass.render_pass().device().as_ref());
321 
322                         // VUID-VkCommandBufferBeginInfo-flags-06001
323                         // Ensured by how the `Subpass` type is constructed.
324 
325                         if let Some(framebuffer) = framebuffer {
326                             // VUID-VkCommandBufferInheritanceInfo-commonparent
327                             assert_eq!(device, framebuffer.device().as_ref());
328 
329                             // VUID-VkCommandBufferBeginInfo-flags-00055
330                             if !framebuffer
331                                 .render_pass()
332                                 .is_compatible_with(subpass.render_pass())
333                             {
334                                 return Err(CommandBufferBeginError::FramebufferNotCompatible);
335                             }
336                         }
337                     }
338                     CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
339                         let &CommandBufferInheritanceRenderingInfo {
340                             view_mask,
341                             ref color_attachment_formats,
342                             depth_attachment_format,
343                             stencil_attachment_format,
344                             rasterization_samples,
345                         } = rendering_info;
346 
347                         // VUID-VkCommandBufferInheritanceRenderingInfo-multiview-06008
348                         if view_mask != 0 && !device.enabled_features().multiview {
349                             return Err(CommandBufferBeginError::RequirementNotMet {
350                                 required_for: "`inheritance_info.render_pass` is \
351                                     `CommandBufferInheritanceRenderPassType::BeginRendering`, \
352                                     where `view_mask` is not `0`",
353                                 requires_one_of: RequiresOneOf {
354                                     features: &["multiview"],
355                                     ..Default::default()
356                                 },
357                             });
358                         }
359 
360                         let view_count = u32::BITS - view_mask.leading_zeros();
361 
362                         // VUID-VkCommandBufferInheritanceRenderingInfo-viewMask-06009
363                         if view_count > properties.max_multiview_view_count.unwrap_or(0) {
364                             return Err(CommandBufferBeginError::MaxMultiviewViewCountExceeded {
365                                 view_count,
366                                 max: properties.max_multiview_view_count.unwrap_or(0),
367                             });
368                         }
369 
370                         for (attachment_index, format) in color_attachment_formats
371                             .iter()
372                             .enumerate()
373                             .flat_map(|(i, f)| f.map(|f| (i, f)))
374                         {
375                             let attachment_index = attachment_index as u32;
376 
377                             // VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-parameter
378                             format.validate_device(device)?;
379 
380                             // VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-06006
381                             // Use unchecked, because all validation has been done above.
382                             if !unsafe { physical_device.format_properties_unchecked(format) }
383                                 .potential_format_features()
384                                 .intersects(FormatFeatures::COLOR_ATTACHMENT)
385                             {
386                                 return Err(
387                                     CommandBufferBeginError::ColorAttachmentFormatUsageNotSupported {
388                                         attachment_index,
389                                     },
390                                 );
391                             }
392                         }
393 
394                         if let Some(format) = depth_attachment_format {
395                             // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-parameter
396                             format.validate_device(device)?;
397 
398                             // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06540
399                             if !format.aspects().intersects(ImageAspects::DEPTH) {
400                                 return Err(
401                                     CommandBufferBeginError::DepthAttachmentFormatUsageNotSupported,
402                                 );
403                             }
404 
405                             // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06007
406                             // Use unchecked, because all validation has been done above.
407                             if !unsafe { physical_device.format_properties_unchecked(format) }
408                                 .potential_format_features()
409                                 .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
410                             {
411                                 return Err(
412                                     CommandBufferBeginError::DepthAttachmentFormatUsageNotSupported,
413                                 );
414                             }
415                         }
416 
417                         if let Some(format) = stencil_attachment_format {
418                             // VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-parameter
419                             format.validate_device(device)?;
420 
421                             // VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06541
422                             if !format.aspects().intersects(ImageAspects::STENCIL) {
423                                 return Err(
424                                     CommandBufferBeginError::StencilAttachmentFormatUsageNotSupported,
425                                 );
426                             }
427 
428                             // VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06199
429                             // Use unchecked, because all validation has been done above.
430                             if !unsafe { physical_device.format_properties_unchecked(format) }
431                                 .potential_format_features()
432                                 .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
433                             {
434                                 return Err(
435                                     CommandBufferBeginError::StencilAttachmentFormatUsageNotSupported,
436                                 );
437                             }
438                         }
439 
440                         if let (Some(depth_format), Some(stencil_format)) =
441                             (depth_attachment_format, stencil_attachment_format)
442                         {
443                             // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06200
444                             if depth_format != stencil_format {
445                                 return Err(
446                                     CommandBufferBeginError::DepthStencilAttachmentFormatMismatch,
447                                 );
448                             }
449                         }
450 
451                         // VUID-VkCommandBufferInheritanceRenderingInfo-rasterizationSamples-parameter
452                         rasterization_samples.validate_device(device)?;
453                     }
454                 }
455             }
456 
457             if let Some(control_flags) = occlusion_query {
458                 // VUID-VkCommandBufferInheritanceInfo-queryFlags-00057
459                 control_flags.validate_device(device)?;
460 
461                 // VUID-VkCommandBufferInheritanceInfo-occlusionQueryEnable-00056
462                 // VUID-VkCommandBufferInheritanceInfo-queryFlags-02788
463                 if !device.enabled_features().inherited_queries {
464                     return Err(CommandBufferBeginError::RequirementNotMet {
465                         required_for: "`inheritance_info.occlusion_query` is `Some`",
466                         requires_one_of: RequiresOneOf {
467                             features: &["inherited_queries"],
468                             ..Default::default()
469                         },
470                     });
471                 }
472 
473                 // VUID-vkBeginCommandBuffer-commandBuffer-00052
474                 if control_flags.intersects(QueryControlFlags::PRECISE)
475                     && !device.enabled_features().occlusion_query_precise
476                 {
477                     return Err(CommandBufferBeginError::RequirementNotMet {
478                         required_for: "`inheritance_info.occlusion_query` is \
479                             `Some(control_flags)`, where `control_flags` contains \
480                             `QueryControlFlags::PRECISE`",
481                         requires_one_of: RequiresOneOf {
482                             features: &["occlusion_query_precise"],
483                             ..Default::default()
484                         },
485                     });
486                 }
487             }
488 
489             // VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789
490             query_statistics_flags.validate_device(device)?;
491 
492             // VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-00058
493             if query_statistics_flags.count() > 0
494                 && !device.enabled_features().pipeline_statistics_query
495             {
496                 return Err(CommandBufferBeginError::RequirementNotMet {
497                     required_for: "`inheritance_info.query_statistics_flags` is not empty",
498                     requires_one_of: RequiresOneOf {
499                         features: &["pipeline_statistics_query"],
500                         ..Default::default()
501                     },
502                 });
503             }
504         } else {
505             debug_assert!(level == CommandBufferLevel::Primary);
506 
507             // VUID-vkBeginCommandBuffer-commandBuffer-02840
508             // Ensured by the definition of the `CommandBufferUsage` enum.
509         }
510 
511         Ok(())
512     }
513 }
514 
515 /// Error that can happen when beginning recording of a command buffer.
516 #[derive(Clone, Copy, Debug)]
517 pub enum CommandBufferBeginError {
518     /// Not enough memory.
519     OomError(OomError),
520 
521     RequirementNotMet {
522         required_for: &'static str,
523         requires_one_of: RequiresOneOf,
524     },
525 
526     /// A color attachment has a format that does not support that usage.
527     ColorAttachmentFormatUsageNotSupported { attachment_index: u32 },
528 
529     /// The depth attachment has a format that does not support that usage.
530     DepthAttachmentFormatUsageNotSupported,
531 
532     /// The depth and stencil attachments have different formats.
533     DepthStencilAttachmentFormatMismatch,
534 
535     /// The framebuffer is not compatible with the render pass.
536     FramebufferNotCompatible,
537 
538     /// The `max_multiview_view_count` limit has been exceeded.
539     MaxMultiviewViewCountExceeded { view_count: u32, max: u32 },
540 
541     /// The stencil attachment has a format that does not support that usage.
542     StencilAttachmentFormatUsageNotSupported,
543 }
544 
545 impl Error for CommandBufferBeginError {
source(&self) -> Option<&(dyn Error + 'static)>546     fn source(&self) -> Option<&(dyn Error + 'static)> {
547         match self {
548             Self::OomError(err) => Some(err),
549             _ => None,
550         }
551     }
552 }
553 
554 impl Display for CommandBufferBeginError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>555     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
556         match self {
557             Self::OomError(_) => write!(f, "not enough memory available"),
558             Self::RequirementNotMet {
559                 required_for,
560                 requires_one_of,
561             } => write!(
562                 f,
563                 "a requirement was not met for: {}; requires one of: {}",
564                 required_for, requires_one_of,
565             ),
566             Self::ColorAttachmentFormatUsageNotSupported { attachment_index } => write!(
567                 f,
568                 "color attachment {} has a format that does not support that usage",
569                 attachment_index,
570             ),
571             Self::DepthAttachmentFormatUsageNotSupported => write!(
572                 f,
573                 "the depth attachment has a format that does not support that usage",
574             ),
575             Self::DepthStencilAttachmentFormatMismatch => write!(
576                 f,
577                 "the depth and stencil attachments have different formats",
578             ),
579             Self::FramebufferNotCompatible => {
580                 write!(f, "the framebuffer is not compatible with the render pass")
581             }
582             Self::MaxMultiviewViewCountExceeded { .. } => {
583                 write!(f, "the `max_multiview_view_count` limit has been exceeded")
584             }
585             Self::StencilAttachmentFormatUsageNotSupported => write!(
586                 f,
587                 "the stencil attachment has a format that does not support that usage",
588             ),
589         }
590     }
591 }
592 
593 impl From<OomError> for CommandBufferBeginError {
from(err: OomError) -> Self594     fn from(err: OomError) -> Self {
595         Self::OomError(err)
596     }
597 }
598 
599 impl From<RequirementNotMet> for CommandBufferBeginError {
from(err: RequirementNotMet) -> Self600     fn from(err: RequirementNotMet) -> Self {
601         Self::RequirementNotMet {
602             required_for: err.required_for,
603             requires_one_of: err.requires_one_of,
604         }
605     }
606 }
607 
608 impl<A> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<A::Alloc>, A>
609 where
610     A: CommandBufferAllocator,
611 {
612     /// Builds the command buffer.
build(self) -> Result<PrimaryAutoCommandBuffer<A::Alloc>, BuildError>613     pub fn build(self) -> Result<PrimaryAutoCommandBuffer<A::Alloc>, BuildError> {
614         if self.render_pass_state.is_some() {
615             return Err(BuildError::RenderPassActive);
616         }
617 
618         if !self.query_state.is_empty() {
619             return Err(BuildError::QueryActive);
620         }
621 
622         Ok(PrimaryAutoCommandBuffer {
623             inner: self.inner.build()?,
624             _alloc: self.builder_alloc.into_alloc(),
625             usage: self.usage,
626 
627             state: Mutex::new(Default::default()),
628         })
629     }
630 }
631 
632 impl<A> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<A::Alloc>, A>
633 where
634     A: CommandBufferAllocator,
635 {
636     /// Builds the command buffer.
build(self) -> Result<SecondaryAutoCommandBuffer<A::Alloc>, BuildError>637     pub fn build(self) -> Result<SecondaryAutoCommandBuffer<A::Alloc>, BuildError> {
638         if !self.query_state.is_empty() {
639             return Err(BuildError::QueryActive);
640         }
641 
642         let submit_state = match self.usage {
643             CommandBufferUsage::MultipleSubmit => SubmitState::ExclusiveUse {
644                 in_use: AtomicBool::new(false),
645             },
646             CommandBufferUsage::SimultaneousUse => SubmitState::Concurrent,
647             CommandBufferUsage::OneTimeSubmit => SubmitState::OneTime {
648                 already_submitted: AtomicBool::new(false),
649             },
650         };
651 
652         Ok(SecondaryAutoCommandBuffer {
653             inner: self.inner.build()?,
654             _alloc: self.builder_alloc.into_alloc(),
655             usage: self.usage,
656             inheritance_info: self.inheritance_info.unwrap(),
657             submit_state,
658         })
659     }
660 }
661 
662 /// Error that can happen when building a command buffer.
663 #[derive(Clone, Debug)]
664 pub enum BuildError {
665     OomError(OomError),
666 
667     /// A render pass is still active on the command buffer.
668     RenderPassActive,
669 
670     /// A query is still active on the command buffer.
671     QueryActive,
672 }
673 
674 impl Error for BuildError {
source(&self) -> Option<&(dyn Error + 'static)>675     fn source(&self) -> Option<&(dyn Error + 'static)> {
676         match self {
677             Self::OomError(err) => Some(err),
678             _ => None,
679         }
680     }
681 }
682 
683 impl Display for BuildError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>684     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
685         match self {
686             Self::OomError(_) => write!(f, "out of memory"),
687             Self::RenderPassActive => {
688                 write!(f, "a render pass is still active on the command buffer")
689             }
690             Self::QueryActive => write!(f, "a query is still active on the command buffer"),
691         }
692     }
693 }
694 
695 impl From<OomError> for BuildError {
from(err: OomError) -> Self696     fn from(err: OomError) -> Self {
697         Self::OomError(err)
698     }
699 }
700 
701 impl<L, A> AutoCommandBufferBuilder<L, A>
702 where
703     A: CommandBufferAllocator,
704 {
queue_family_properties(&self) -> &QueueFamilyProperties705     pub(super) fn queue_family_properties(&self) -> &QueueFamilyProperties {
706         &self.device().physical_device().queue_family_properties()[self.queue_family_index as usize]
707     }
708 
709     /// Returns the binding/setting state.
state(&self) -> CommandBufferBuilderState<'_>710     pub fn state(&self) -> CommandBufferBuilderState<'_> {
711         self.inner.state()
712     }
713 }
714 
715 unsafe impl<L, A> DeviceOwned for AutoCommandBufferBuilder<L, A>
716 where
717     A: CommandBufferAllocator,
718 {
device(&self) -> &Arc<Device>719     fn device(&self) -> &Arc<Device> {
720         self.inner.device()
721     }
722 }
723 
724 pub struct PrimaryAutoCommandBuffer<A = StandardCommandBufferAlloc> {
725     inner: SyncCommandBuffer,
726     _alloc: A, // Safety: must be dropped after `inner`
727     usage: CommandBufferUsage,
728 
729     state: Mutex<CommandBufferState>,
730 }
731 
732 unsafe impl<A> DeviceOwned for PrimaryAutoCommandBuffer<A> {
device(&self) -> &Arc<Device>733     fn device(&self) -> &Arc<Device> {
734         self.inner.device()
735     }
736 }
737 
738 unsafe impl<A> VulkanObject for PrimaryAutoCommandBuffer<A> {
739     type Handle = ash::vk::CommandBuffer;
740 
handle(&self) -> Self::Handle741     fn handle(&self) -> Self::Handle {
742         self.inner.as_ref().handle()
743     }
744 }
745 
746 unsafe impl<A> PrimaryCommandBufferAbstract for PrimaryAutoCommandBuffer<A>
747 where
748     A: CommandBufferAlloc,
749 {
usage(&self) -> CommandBufferUsage750     fn usage(&self) -> CommandBufferUsage {
751         self.usage
752     }
753 
state(&self) -> MutexGuard<'_, CommandBufferState>754     fn state(&self) -> MutexGuard<'_, CommandBufferState> {
755         self.state.lock()
756     }
757 
resources_usage(&self) -> &CommandBufferResourcesUsage758     fn resources_usage(&self) -> &CommandBufferResourcesUsage {
759         self.inner.resources_usage()
760     }
761 }
762 
763 pub struct SecondaryAutoCommandBuffer<A = StandardCommandBufferAlloc> {
764     inner: SyncCommandBuffer,
765     _alloc: A, // Safety: must be dropped after `inner`
766     usage: CommandBufferUsage,
767     inheritance_info: CommandBufferInheritanceInfo,
768 
769     // Tracks usage of the command buffer on the GPU.
770     submit_state: SubmitState,
771 }
772 
773 unsafe impl<A> VulkanObject for SecondaryAutoCommandBuffer<A> {
774     type Handle = ash::vk::CommandBuffer;
775 
handle(&self) -> Self::Handle776     fn handle(&self) -> Self::Handle {
777         self.inner.as_ref().handle()
778     }
779 }
780 
781 unsafe impl<A> DeviceOwned for SecondaryAutoCommandBuffer<A> {
device(&self) -> &Arc<Device>782     fn device(&self) -> &Arc<Device> {
783         self.inner.device()
784     }
785 }
786 
787 unsafe impl<A> SecondaryCommandBufferAbstract for SecondaryAutoCommandBuffer<A>
788 where
789     A: CommandBufferAlloc,
790 {
usage(&self) -> CommandBufferUsage791     fn usage(&self) -> CommandBufferUsage {
792         self.usage
793     }
794 
inheritance_info(&self) -> &CommandBufferInheritanceInfo795     fn inheritance_info(&self) -> &CommandBufferInheritanceInfo {
796         &self.inheritance_info
797     }
798 
lock_record(&self) -> Result<(), CommandBufferExecError>799     fn lock_record(&self) -> Result<(), CommandBufferExecError> {
800         match self.submit_state {
801             SubmitState::OneTime {
802                 ref already_submitted,
803             } => {
804                 let was_already_submitted = already_submitted.swap(true, Ordering::SeqCst);
805                 if was_already_submitted {
806                     return Err(CommandBufferExecError::OneTimeSubmitAlreadySubmitted);
807                 }
808             }
809             SubmitState::ExclusiveUse { ref in_use } => {
810                 let already_in_use = in_use.swap(true, Ordering::SeqCst);
811                 if already_in_use {
812                     return Err(CommandBufferExecError::ExclusiveAlreadyInUse);
813                 }
814             }
815             SubmitState::Concurrent => (),
816         };
817 
818         Ok(())
819     }
820 
unlock(&self)821     unsafe fn unlock(&self) {
822         match self.submit_state {
823             SubmitState::OneTime {
824                 ref already_submitted,
825             } => {
826                 debug_assert!(already_submitted.load(Ordering::SeqCst));
827             }
828             SubmitState::ExclusiveUse { ref in_use } => {
829                 let old_val = in_use.swap(false, Ordering::SeqCst);
830                 debug_assert!(old_val);
831             }
832             SubmitState::Concurrent => (),
833         };
834     }
835 
resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage836     fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage {
837         self.inner.secondary_resources_usage()
838     }
839 }
840 
841 // Whether the command buffer can be submitted.
842 #[derive(Debug)]
843 enum SubmitState {
844     // The command buffer was created with the "SimultaneousUse" flag. Can always be submitted at
845     // any time.
846     Concurrent,
847 
848     // The command buffer can only be submitted once simultaneously.
849     ExclusiveUse {
850         // True if the command buffer is current in use by the GPU.
851         in_use: AtomicBool,
852     },
853 
854     // The command buffer can only ever be submitted once.
855     OneTime {
856         // True if the command buffer has already been submitted once and can be no longer be
857         // submitted.
858         already_submitted: AtomicBool,
859     },
860 }
861 
862 #[cfg(test)]
863 mod tests {
864     use super::*;
865     use crate::{
866         buffer::{Buffer, BufferCreateInfo, BufferUsage},
867         command_buffer::{
868             synced::SyncCommandBufferBuilderError, BufferCopy, CopyBufferInfoTyped, CopyError,
869             ExecuteCommandsError,
870         },
871         device::{DeviceCreateInfo, QueueCreateInfo},
872         memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
873         sync::GpuFuture,
874     };
875 
876     #[test]
copy_buffer_dimensions()877     fn copy_buffer_dimensions() {
878         let instance = instance!();
879 
880         let physical_device = match instance.enumerate_physical_devices().unwrap().next() {
881             Some(p) => p,
882             None => return,
883         };
884 
885         let (device, mut queues) = Device::new(
886             physical_device,
887             DeviceCreateInfo {
888                 queue_create_infos: vec![QueueCreateInfo {
889                     queue_family_index: 0,
890                     ..Default::default()
891                 }],
892                 ..Default::default()
893             },
894         )
895         .unwrap();
896 
897         let queue = queues.next().unwrap();
898         let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
899 
900         let source = Buffer::from_iter(
901             &memory_allocator,
902             BufferCreateInfo {
903                 usage: BufferUsage::TRANSFER_SRC,
904                 ..Default::default()
905             },
906             AllocationCreateInfo {
907                 usage: MemoryUsage::Upload,
908                 ..Default::default()
909             },
910             [1_u32, 2].iter().copied(),
911         )
912         .unwrap();
913 
914         let destination = Buffer::from_iter(
915             &memory_allocator,
916             BufferCreateInfo {
917                 usage: BufferUsage::TRANSFER_DST,
918                 ..Default::default()
919             },
920             AllocationCreateInfo {
921                 usage: MemoryUsage::Upload,
922                 ..Default::default()
923             },
924             [0_u32, 10, 20, 3, 4].iter().copied(),
925         )
926         .unwrap();
927 
928         let cb_allocator = StandardCommandBufferAllocator::new(device, Default::default());
929         let mut cbb = AutoCommandBufferBuilder::primary(
930             &cb_allocator,
931             queue.queue_family_index(),
932             CommandBufferUsage::OneTimeSubmit,
933         )
934         .unwrap();
935 
936         cbb.copy_buffer(CopyBufferInfoTyped {
937             regions: [BufferCopy {
938                 src_offset: 0,
939                 dst_offset: 1,
940                 size: 2,
941                 ..Default::default()
942             }]
943             .into(),
944             ..CopyBufferInfoTyped::buffers(source, destination.clone())
945         })
946         .unwrap();
947 
948         let cb = cbb.build().unwrap();
949 
950         let future = cb
951             .execute(queue)
952             .unwrap()
953             .then_signal_fence_and_flush()
954             .unwrap();
955         future.wait(None).unwrap();
956 
957         let result = destination.read().unwrap();
958 
959         assert_eq!(*result, [0_u32, 1, 2, 3, 4]);
960     }
961 
962     #[test]
secondary_nonconcurrent_conflict()963     fn secondary_nonconcurrent_conflict() {
964         let (device, queue) = gfx_dev_and_queue!();
965 
966         let cb_allocator = StandardCommandBufferAllocator::new(device, Default::default());
967 
968         // Make a secondary CB that doesn't support simultaneous use.
969         let builder = AutoCommandBufferBuilder::secondary(
970             &cb_allocator,
971             queue.queue_family_index(),
972             CommandBufferUsage::MultipleSubmit,
973             Default::default(),
974         )
975         .unwrap();
976         let secondary = Arc::new(builder.build().unwrap());
977 
978         {
979             let mut builder = AutoCommandBufferBuilder::primary(
980                 &cb_allocator,
981                 queue.queue_family_index(),
982                 CommandBufferUsage::SimultaneousUse,
983             )
984             .unwrap();
985 
986             // Add the secondary a first time
987             builder.execute_commands(secondary.clone()).unwrap();
988 
989             // Recording the same non-concurrent secondary command buffer twice into the same
990             // primary is an error.
991             assert!(matches!(
992                 builder.execute_commands(secondary.clone()),
993                 Err(ExecuteCommandsError::SyncCommandBufferBuilderError(
994                     SyncCommandBufferBuilderError::ExecError(
995                         CommandBufferExecError::ExclusiveAlreadyInUse
996                     )
997                 ))
998             ));
999         }
1000 
1001         {
1002             let mut builder = AutoCommandBufferBuilder::primary(
1003                 &cb_allocator,
1004                 queue.queue_family_index(),
1005                 CommandBufferUsage::SimultaneousUse,
1006             )
1007             .unwrap();
1008             builder.execute_commands(secondary.clone()).unwrap();
1009             let cb1 = builder.build().unwrap();
1010 
1011             let mut builder = AutoCommandBufferBuilder::primary(
1012                 &cb_allocator,
1013                 queue.queue_family_index(),
1014                 CommandBufferUsage::SimultaneousUse,
1015             )
1016             .unwrap();
1017 
1018             // Recording the same non-concurrent secondary command buffer into multiple
1019             // primaries is an error.
1020             assert!(matches!(
1021                 builder.execute_commands(secondary.clone()),
1022                 Err(ExecuteCommandsError::SyncCommandBufferBuilderError(
1023                     SyncCommandBufferBuilderError::ExecError(
1024                         CommandBufferExecError::ExclusiveAlreadyInUse
1025                     )
1026                 ))
1027             ));
1028 
1029             std::mem::drop(cb1);
1030 
1031             // Now that the first cb is dropped, we should be able to record.
1032             builder.execute_commands(secondary).unwrap();
1033         }
1034     }
1035 
1036     #[test]
buffer_self_copy_overlapping()1037     fn buffer_self_copy_overlapping() {
1038         let (device, queue) = gfx_dev_and_queue!();
1039 
1040         let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
1041         let source = Buffer::from_iter(
1042             &memory_allocator,
1043             BufferCreateInfo {
1044                 usage: BufferUsage::TRANSFER_SRC | BufferUsage::TRANSFER_DST,
1045                 ..Default::default()
1046             },
1047             AllocationCreateInfo {
1048                 usage: MemoryUsage::Upload,
1049                 ..Default::default()
1050             },
1051             [0_u32, 1, 2, 3].iter().copied(),
1052         )
1053         .unwrap();
1054 
1055         let cb_allocator = StandardCommandBufferAllocator::new(device, Default::default());
1056         let mut builder = AutoCommandBufferBuilder::primary(
1057             &cb_allocator,
1058             queue.queue_family_index(),
1059             CommandBufferUsage::OneTimeSubmit,
1060         )
1061         .unwrap();
1062 
1063         builder
1064             .copy_buffer(CopyBufferInfoTyped {
1065                 regions: [BufferCopy {
1066                     src_offset: 0,
1067                     dst_offset: 2,
1068                     size: 2,
1069                     ..Default::default()
1070                 }]
1071                 .into(),
1072                 ..CopyBufferInfoTyped::buffers(source.clone(), source.clone())
1073             })
1074             .unwrap();
1075 
1076         let cb = builder.build().unwrap();
1077 
1078         let future = cb
1079             .execute(queue)
1080             .unwrap()
1081             .then_signal_fence_and_flush()
1082             .unwrap();
1083         future.wait(None).unwrap();
1084 
1085         let result = source.read().unwrap();
1086 
1087         assert_eq!(*result, [0_u32, 1, 0, 1]);
1088     }
1089 
1090     #[test]
buffer_self_copy_not_overlapping()1091     fn buffer_self_copy_not_overlapping() {
1092         let (device, queue) = gfx_dev_and_queue!();
1093 
1094         let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
1095         let source = Buffer::from_iter(
1096             &memory_allocator,
1097             BufferCreateInfo {
1098                 usage: BufferUsage::TRANSFER_SRC | BufferUsage::TRANSFER_DST,
1099                 ..Default::default()
1100             },
1101             AllocationCreateInfo {
1102                 usage: MemoryUsage::Upload,
1103                 ..Default::default()
1104             },
1105             [0_u32, 1, 2, 3].iter().copied(),
1106         )
1107         .unwrap();
1108 
1109         let cb_allocator = StandardCommandBufferAllocator::new(device, Default::default());
1110         let mut builder = AutoCommandBufferBuilder::primary(
1111             &cb_allocator,
1112             queue.queue_family_index(),
1113             CommandBufferUsage::OneTimeSubmit,
1114         )
1115         .unwrap();
1116 
1117         assert!(matches!(
1118             builder.copy_buffer(CopyBufferInfoTyped {
1119                 regions: [BufferCopy {
1120                     src_offset: 0,
1121                     dst_offset: 1,
1122                     size: 2,
1123                     ..Default::default()
1124                 }]
1125                 .into(),
1126                 ..CopyBufferInfoTyped::buffers(source.clone(), source)
1127             }),
1128             Err(CopyError::OverlappingRegions {
1129                 src_region_index: 0,
1130                 dst_region_index: 0,
1131             })
1132         ));
1133     }
1134 }
1135