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