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