• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2022 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 use super::{CommandBufferBuilder, ExecuteCommandsError, RenderPassStateType};
11 use crate::{
12     command_buffer::{
13         allocator::{CommandBufferAlloc, CommandBufferAllocator},
14         CommandBufferInheritanceRenderPassType, PrimaryCommandBuffer, SecondaryCommandBuffer,
15         SubpassContents,
16     },
17     device::{DeviceOwned, QueueFlags},
18     query::QueryType,
19     RequiresOneOf, SafeDeref, VulkanObject,
20 };
21 
22 impl<A> CommandBufferBuilder<PrimaryCommandBuffer<A::Alloc>, A>
23 where
24     A: CommandBufferAllocator,
25 {
26     /// Executes a secondary command buffer.
27     ///
28     /// If the `usage` that `command_buffer` was created with are more restrictive than those of
29     /// `self`, then `self` will be restricted to match. E.g. executing a secondary command buffer
30     /// with [`OneTimeSubmit`] will set `self`'s usage to
31     /// `OneTimeSubmit` also.
32     ///
33     /// # Safety
34     ///
35     /// - Appropriate synchronization must be provided for all buffers and images
36     ///   that are accessed by the command.
37     /// - All images that are accessed by the command must be in the expected image layout.
38     ///
39     /// [`OneTimeSubmit`]: crate::command_buffer::CommandBufferUsage::OneTimeSubmit
execute_commands( &mut self, command_buffer: SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>, ) -> Result<&mut Self, ExecuteCommandsError>40     pub unsafe fn execute_commands(
41         &mut self,
42         command_buffer: SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>,
43     ) -> Result<&mut Self, ExecuteCommandsError> {
44         self.validate_execute_commands(&command_buffer, 0)?;
45 
46         unsafe { Ok(self.execute_commands_unchecked(command_buffer)) }
47     }
48 
validate_execute_commands( &self, command_buffer: &SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>, command_buffer_index: u32, ) -> Result<(), ExecuteCommandsError>49     fn validate_execute_commands(
50         &self,
51         command_buffer: &SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>,
52         command_buffer_index: u32,
53     ) -> Result<(), ExecuteCommandsError> {
54         // VUID-vkCmdExecuteCommands-commonparent
55         assert_eq!(self.device(), command_buffer.device());
56 
57         let queue_family_properties = self.queue_family_properties();
58 
59         // VUID-vkCmdExecuteCommands-commandBuffer-cmdpool
60         if !queue_family_properties
61             .queue_flags
62             .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
63         {
64             return Err(ExecuteCommandsError::NotSupportedByQueueFamily);
65         }
66 
67         // TODO:
68         // VUID-vkCmdExecuteCommands-pCommandBuffers-00094
69 
70         if let Some(render_pass_state) = &self.builder_state.render_pass {
71             // VUID-vkCmdExecuteCommands-contents-06018
72             // VUID-vkCmdExecuteCommands-flags-06024
73             if render_pass_state.contents != SubpassContents::SecondaryCommandBuffers {
74                 return Err(ExecuteCommandsError::ForbiddenWithSubpassContents {
75                     contents: render_pass_state.contents,
76                 });
77             }
78 
79             // VUID-vkCmdExecuteCommands-pCommandBuffers-00096
80             let inheritance_render_pass = command_buffer
81                 .inheritance_info()
82                 .render_pass
83                 .as_ref()
84                 .ok_or(ExecuteCommandsError::RenderPassInheritanceRequired {
85                     command_buffer_index,
86                 })?;
87 
88             match (&render_pass_state.render_pass, inheritance_render_pass) {
89                 (
90                     RenderPassStateType::BeginRenderPass(state),
91                     CommandBufferInheritanceRenderPassType::BeginRenderPass(inheritance_info),
92                 ) => {
93                     // VUID-vkCmdExecuteCommands-pBeginInfo-06020
94                     if !inheritance_info
95                         .subpass
96                         .render_pass()
97                         .is_compatible_with(state.subpass.render_pass())
98                     {
99                         return Err(ExecuteCommandsError::RenderPassNotCompatible {
100                             command_buffer_index,
101                         });
102                     }
103 
104                     // VUID-vkCmdExecuteCommands-pCommandBuffers-06019
105                     if inheritance_info.subpass.index() != state.subpass.index() {
106                         return Err(ExecuteCommandsError::RenderPassSubpassMismatch {
107                             command_buffer_index,
108                             required_subpass: state.subpass.index(),
109                             inherited_subpass: inheritance_info.subpass.index(),
110                         });
111                     }
112 
113                     // VUID-vkCmdExecuteCommands-pCommandBuffers-00099
114                     if let Some(framebuffer) = &inheritance_info.framebuffer {
115                         if framebuffer != state.framebuffer.as_ref().unwrap() {
116                             return Err(ExecuteCommandsError::RenderPassFramebufferMismatch {
117                                 command_buffer_index,
118                             });
119                         }
120                     }
121                 }
122                 (
123                     RenderPassStateType::BeginRendering(_),
124                     CommandBufferInheritanceRenderPassType::BeginRendering(inheritance_info),
125                 ) => {
126                     let attachments = render_pass_state.attachments.as_ref().unwrap();
127 
128                     // VUID-vkCmdExecuteCommands-colorAttachmentCount-06027
129                     if inheritance_info.color_attachment_formats.len()
130                         != attachments.color_attachments.len()
131                     {
132                         return Err(
133                             ExecuteCommandsError::RenderPassColorAttachmentCountMismatch {
134                                 command_buffer_index,
135                                 required_count: attachments.color_attachments.len() as u32,
136                                 inherited_count: inheritance_info.color_attachment_formats.len()
137                                     as u32,
138                             },
139                         );
140                     }
141 
142                     for (color_attachment_index, image_view, inherited_format) in attachments
143                         .color_attachments
144                         .iter()
145                         .zip(inheritance_info.color_attachment_formats.iter().copied())
146                         .enumerate()
147                         .filter_map(|(i, (a, f))| a.as_ref().map(|a| (i as u32, &a.image_view, f)))
148                     {
149                         let required_format = image_view.format().unwrap();
150 
151                         // VUID-vkCmdExecuteCommands-imageView-06028
152                         if Some(required_format) != inherited_format {
153                             return Err(
154                                 ExecuteCommandsError::RenderPassColorAttachmentFormatMismatch {
155                                     command_buffer_index,
156                                     color_attachment_index,
157                                     required_format,
158                                     inherited_format,
159                                 },
160                             );
161                         }
162 
163                         // VUID-vkCmdExecuteCommands-pNext-06035
164                         if image_view.image().samples() != inheritance_info.rasterization_samples {
165                             return Err(
166                                 ExecuteCommandsError::RenderPassColorAttachmentSamplesMismatch {
167                                     command_buffer_index,
168                                     color_attachment_index,
169                                     required_samples: image_view.image().samples(),
170                                     inherited_samples: inheritance_info.rasterization_samples,
171                                 },
172                             );
173                         }
174                     }
175 
176                     if let Some((image_view, format)) = attachments
177                         .depth_attachment
178                         .as_ref()
179                         .map(|a| (&a.image_view, inheritance_info.depth_attachment_format))
180                     {
181                         // VUID-vkCmdExecuteCommands-pDepthAttachment-06029
182                         if Some(image_view.format().unwrap()) != format {
183                             return Err(
184                                 ExecuteCommandsError::RenderPassDepthAttachmentFormatMismatch {
185                                     command_buffer_index,
186                                     required_format: image_view.format().unwrap(),
187                                     inherited_format: format,
188                                 },
189                             );
190                         }
191 
192                         // VUID-vkCmdExecuteCommands-pNext-06036
193                         if image_view.image().samples() != inheritance_info.rasterization_samples {
194                             return Err(
195                                 ExecuteCommandsError::RenderPassDepthAttachmentSamplesMismatch {
196                                     command_buffer_index,
197                                     required_samples: image_view.image().samples(),
198                                     inherited_samples: inheritance_info.rasterization_samples,
199                                 },
200                             );
201                         }
202                     }
203 
204                     if let Some((image_view, format)) = attachments
205                         .stencil_attachment
206                         .as_ref()
207                         .map(|a| (&a.image_view, inheritance_info.stencil_attachment_format))
208                     {
209                         // VUID-vkCmdExecuteCommands-pStencilAttachment-06030
210                         if Some(image_view.format().unwrap()) != format {
211                             return Err(
212                                 ExecuteCommandsError::RenderPassStencilAttachmentFormatMismatch {
213                                     command_buffer_index,
214                                     required_format: image_view.format().unwrap(),
215                                     inherited_format: format,
216                                 },
217                             );
218                         }
219 
220                         // VUID-vkCmdExecuteCommands-pNext-06037
221                         if image_view.image().samples() != inheritance_info.rasterization_samples {
222                             return Err(
223                                 ExecuteCommandsError::RenderPassStencilAttachmentSamplesMismatch {
224                                     command_buffer_index,
225                                     required_samples: image_view.image().samples(),
226                                     inherited_samples: inheritance_info.rasterization_samples,
227                                 },
228                             );
229                         }
230                     }
231 
232                     // VUID-vkCmdExecuteCommands-viewMask-06031
233                     if inheritance_info.view_mask != render_pass_state.rendering_info.view_mask {
234                         return Err(ExecuteCommandsError::RenderPassViewMaskMismatch {
235                             command_buffer_index,
236                             required_view_mask: render_pass_state.rendering_info.view_mask,
237                             inherited_view_mask: inheritance_info.view_mask,
238                         });
239                     }
240                 }
241                 _ => {
242                     // VUID-vkCmdExecuteCommands-pBeginInfo-06025
243                     return Err(ExecuteCommandsError::RenderPassTypeMismatch {
244                         command_buffer_index,
245                     });
246                 }
247             }
248 
249             // TODO:
250             // VUID-vkCmdExecuteCommands-commandBuffer-06533
251             // VUID-vkCmdExecuteCommands-commandBuffer-06534
252             // VUID-vkCmdExecuteCommands-pCommandBuffers-06535
253             // VUID-vkCmdExecuteCommands-pCommandBuffers-06536
254         } else {
255             // VUID-vkCmdExecuteCommands-pCommandBuffers-00100
256             if command_buffer.inheritance_info().render_pass.is_some() {
257                 return Err(ExecuteCommandsError::RenderPassInheritanceForbidden {
258                     command_buffer_index,
259                 });
260             }
261         }
262 
263         // VUID-vkCmdExecuteCommands-commandBuffer-00101
264         if !self.builder_state.queries.is_empty()
265             && !self.device().enabled_features().inherited_queries
266         {
267             return Err(ExecuteCommandsError::RequirementNotMet {
268                 required_for: "`CommandBufferBuilder::execute_commands` when a query is active",
269                 requires_one_of: RequiresOneOf {
270                     features: &["inherited_queries"],
271                     ..Default::default()
272                 },
273             });
274         }
275 
276         for state in self.builder_state.queries.values() {
277             match state.ty {
278                 QueryType::Occlusion => {
279                     // VUID-vkCmdExecuteCommands-commandBuffer-00102
280                     let inherited_flags = command_buffer.inheritance_info().occlusion_query.ok_or(
281                         ExecuteCommandsError::OcclusionQueryInheritanceRequired {
282                             command_buffer_index,
283                         },
284                     )?;
285 
286                     let inherited_flags_vk = ash::vk::QueryControlFlags::from(inherited_flags);
287                     let state_flags_vk = ash::vk::QueryControlFlags::from(state.flags);
288 
289                     // VUID-vkCmdExecuteCommands-commandBuffer-00103
290                     if inherited_flags_vk & state_flags_vk != state_flags_vk {
291                         return Err(ExecuteCommandsError::OcclusionQueryFlagsNotSuperset {
292                             command_buffer_index,
293                             required_flags: state.flags,
294                             inherited_flags,
295                         });
296                     }
297                 }
298                 QueryType::PipelineStatistics(state_flags) => {
299                     let inherited_flags = command_buffer.inheritance_info().query_statistics_flags;
300                     let inherited_flags_vk =
301                         ash::vk::QueryPipelineStatisticFlags::from(inherited_flags);
302                     let state_flags_vk = ash::vk::QueryPipelineStatisticFlags::from(state_flags);
303 
304                     // VUID-vkCmdExecuteCommands-commandBuffer-00104
305                     if inherited_flags_vk & state_flags_vk != state_flags_vk {
306                         return Err(
307                             ExecuteCommandsError::PipelineStatisticsQueryFlagsNotSuperset {
308                                 command_buffer_index,
309                                 required_flags: state_flags,
310                                 inherited_flags,
311                             },
312                         );
313                     }
314                 }
315                 QueryType::Timestamp => (),
316             }
317         }
318 
319         // TODO:
320         // VUID-vkCmdExecuteCommands-pCommandBuffers-00091
321         // VUID-vkCmdExecuteCommands-pCommandBuffers-00092
322         // VUID-vkCmdExecuteCommands-pCommandBuffers-00093
323         // VUID-vkCmdExecuteCommands-pCommandBuffers-00105
324 
325         // VUID-vkCmdExecuteCommands-bufferlevel
326         // Ensured by the type of the impl block.
327 
328         // VUID-vkCmdExecuteCommands-pCommandBuffers-00088
329         // VUID-vkCmdExecuteCommands-pCommandBuffers-00089
330         // Ensured by the SecondaryCommandBuffer trait.
331 
332         // TODO: sync check
333 
334         Ok(())
335     }
336 
337     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
execute_commands_unchecked( &mut self, command_buffer: SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>, ) -> &mut Self338     pub unsafe fn execute_commands_unchecked(
339         &mut self,
340         command_buffer: SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>,
341     ) -> &mut Self {
342         struct DropUnlock<As>(SecondaryCommandBuffer<As>)
343         where
344             As: CommandBufferAlloc;
345 
346         impl<As> std::ops::Deref for DropUnlock<As>
347         where
348             As: CommandBufferAlloc,
349         {
350             type Target = SecondaryCommandBuffer<As>;
351 
352             fn deref(&self) -> &Self::Target {
353                 &self.0
354             }
355         }
356         unsafe impl<As> SafeDeref for DropUnlock<As> where As: CommandBufferAlloc {}
357 
358         impl<As> Drop for DropUnlock<As>
359         where
360             As: CommandBufferAlloc,
361         {
362             fn drop(&mut self) {
363                 unsafe {
364                     self.unlock();
365                 }
366             }
367         }
368 
369         let command_buffer = {
370             command_buffer.lock_record().unwrap();
371             DropUnlock(command_buffer)
372         };
373 
374         let fns = self.device().fns();
375         (fns.v1_0.cmd_execute_commands)(self.handle(), 1, &command_buffer.handle());
376 
377         // The secondary command buffer could leave the primary in any state.
378         self.builder_state = Default::default();
379 
380         // If the secondary is non-concurrent or one-time use, that restricts the primary as well.
381         self.usage = std::cmp::min(self.usage, command_buffer.usage);
382 
383         let _command_index = self.next_command_index;
384         let _command_name = "execute_commands";
385 
386         // TODO: sync state update
387 
388         self.resources.push(Box::new(command_buffer));
389 
390         self.next_command_index += 1;
391         self
392     }
393 }
394