diff options
Diffstat (limited to 'src/command_buffer/standard/builder/secondary.rs')
-rw-r--r-- | src/command_buffer/standard/builder/secondary.rs | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/command_buffer/standard/builder/secondary.rs b/src/command_buffer/standard/builder/secondary.rs new file mode 100644 index 0000000..b7678b8 --- /dev/null +++ b/src/command_buffer/standard/builder/secondary.rs @@ -0,0 +1,393 @@ +// Copyright (c) 2022 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT +// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +use super::{CommandBufferBuilder, ExecuteCommandsError, RenderPassStateType}; +use crate::{ + command_buffer::{ + allocator::{CommandBufferAlloc, CommandBufferAllocator}, + CommandBufferInheritanceRenderPassType, PrimaryCommandBuffer, SecondaryCommandBuffer, + SubpassContents, + }, + device::{DeviceOwned, QueueFlags}, + query::QueryType, + RequiresOneOf, SafeDeref, VulkanObject, +}; + +impl<A> CommandBufferBuilder<PrimaryCommandBuffer<A::Alloc>, A> +where + A: CommandBufferAllocator, +{ + /// Executes a secondary command buffer. + /// + /// If the `usage` that `command_buffer` was created with are more restrictive than those of + /// `self`, then `self` will be restricted to match. E.g. executing a secondary command buffer + /// with [`OneTimeSubmit`] will set `self`'s usage to + /// `OneTimeSubmit` also. + /// + /// # Safety + /// + /// - Appropriate synchronization must be provided for all buffers and images + /// that are accessed by the command. + /// - All images that are accessed by the command must be in the expected image layout. + /// + /// [`OneTimeSubmit`]: crate::command_buffer::CommandBufferUsage::OneTimeSubmit + pub unsafe fn execute_commands( + &mut self, + command_buffer: SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>, + ) -> Result<&mut Self, ExecuteCommandsError> { + self.validate_execute_commands(&command_buffer, 0)?; + + unsafe { Ok(self.execute_commands_unchecked(command_buffer)) } + } + + fn validate_execute_commands( + &self, + command_buffer: &SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>, + command_buffer_index: u32, + ) -> Result<(), ExecuteCommandsError> { + // VUID-vkCmdExecuteCommands-commonparent + assert_eq!(self.device(), command_buffer.device()); + + let queue_family_properties = self.queue_family_properties(); + + // VUID-vkCmdExecuteCommands-commandBuffer-cmdpool + if !queue_family_properties + .queue_flags + .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE) + { + return Err(ExecuteCommandsError::NotSupportedByQueueFamily); + } + + // TODO: + // VUID-vkCmdExecuteCommands-pCommandBuffers-00094 + + if let Some(render_pass_state) = &self.builder_state.render_pass { + // VUID-vkCmdExecuteCommands-contents-06018 + // VUID-vkCmdExecuteCommands-flags-06024 + if render_pass_state.contents != SubpassContents::SecondaryCommandBuffers { + return Err(ExecuteCommandsError::ForbiddenWithSubpassContents { + contents: render_pass_state.contents, + }); + } + + // VUID-vkCmdExecuteCommands-pCommandBuffers-00096 + let inheritance_render_pass = command_buffer + .inheritance_info() + .render_pass + .as_ref() + .ok_or(ExecuteCommandsError::RenderPassInheritanceRequired { + command_buffer_index, + })?; + + match (&render_pass_state.render_pass, inheritance_render_pass) { + ( + RenderPassStateType::BeginRenderPass(state), + CommandBufferInheritanceRenderPassType::BeginRenderPass(inheritance_info), + ) => { + // VUID-vkCmdExecuteCommands-pBeginInfo-06020 + if !inheritance_info + .subpass + .render_pass() + .is_compatible_with(state.subpass.render_pass()) + { + return Err(ExecuteCommandsError::RenderPassNotCompatible { + command_buffer_index, + }); + } + + // VUID-vkCmdExecuteCommands-pCommandBuffers-06019 + if inheritance_info.subpass.index() != state.subpass.index() { + return Err(ExecuteCommandsError::RenderPassSubpassMismatch { + command_buffer_index, + required_subpass: state.subpass.index(), + inherited_subpass: inheritance_info.subpass.index(), + }); + } + + // VUID-vkCmdExecuteCommands-pCommandBuffers-00099 + if let Some(framebuffer) = &inheritance_info.framebuffer { + if framebuffer != state.framebuffer.as_ref().unwrap() { + return Err(ExecuteCommandsError::RenderPassFramebufferMismatch { + command_buffer_index, + }); + } + } + } + ( + RenderPassStateType::BeginRendering(_), + CommandBufferInheritanceRenderPassType::BeginRendering(inheritance_info), + ) => { + let attachments = render_pass_state.attachments.as_ref().unwrap(); + + // VUID-vkCmdExecuteCommands-colorAttachmentCount-06027 + if inheritance_info.color_attachment_formats.len() + != attachments.color_attachments.len() + { + return Err( + ExecuteCommandsError::RenderPassColorAttachmentCountMismatch { + command_buffer_index, + required_count: attachments.color_attachments.len() as u32, + inherited_count: inheritance_info.color_attachment_formats.len() + as u32, + }, + ); + } + + for (color_attachment_index, image_view, inherited_format) in attachments + .color_attachments + .iter() + .zip(inheritance_info.color_attachment_formats.iter().copied()) + .enumerate() + .filter_map(|(i, (a, f))| a.as_ref().map(|a| (i as u32, &a.image_view, f))) + { + let required_format = image_view.format().unwrap(); + + // VUID-vkCmdExecuteCommands-imageView-06028 + if Some(required_format) != inherited_format { + return Err( + ExecuteCommandsError::RenderPassColorAttachmentFormatMismatch { + command_buffer_index, + color_attachment_index, + required_format, + inherited_format, + }, + ); + } + + // VUID-vkCmdExecuteCommands-pNext-06035 + if image_view.image().samples() != inheritance_info.rasterization_samples { + return Err( + ExecuteCommandsError::RenderPassColorAttachmentSamplesMismatch { + command_buffer_index, + color_attachment_index, + required_samples: image_view.image().samples(), + inherited_samples: inheritance_info.rasterization_samples, + }, + ); + } + } + + if let Some((image_view, format)) = attachments + .depth_attachment + .as_ref() + .map(|a| (&a.image_view, inheritance_info.depth_attachment_format)) + { + // VUID-vkCmdExecuteCommands-pDepthAttachment-06029 + if Some(image_view.format().unwrap()) != format { + return Err( + ExecuteCommandsError::RenderPassDepthAttachmentFormatMismatch { + command_buffer_index, + required_format: image_view.format().unwrap(), + inherited_format: format, + }, + ); + } + + // VUID-vkCmdExecuteCommands-pNext-06036 + if image_view.image().samples() != inheritance_info.rasterization_samples { + return Err( + ExecuteCommandsError::RenderPassDepthAttachmentSamplesMismatch { + command_buffer_index, + required_samples: image_view.image().samples(), + inherited_samples: inheritance_info.rasterization_samples, + }, + ); + } + } + + if let Some((image_view, format)) = attachments + .stencil_attachment + .as_ref() + .map(|a| (&a.image_view, inheritance_info.stencil_attachment_format)) + { + // VUID-vkCmdExecuteCommands-pStencilAttachment-06030 + if Some(image_view.format().unwrap()) != format { + return Err( + ExecuteCommandsError::RenderPassStencilAttachmentFormatMismatch { + command_buffer_index, + required_format: image_view.format().unwrap(), + inherited_format: format, + }, + ); + } + + // VUID-vkCmdExecuteCommands-pNext-06037 + if image_view.image().samples() != inheritance_info.rasterization_samples { + return Err( + ExecuteCommandsError::RenderPassStencilAttachmentSamplesMismatch { + command_buffer_index, + required_samples: image_view.image().samples(), + inherited_samples: inheritance_info.rasterization_samples, + }, + ); + } + } + + // VUID-vkCmdExecuteCommands-viewMask-06031 + if inheritance_info.view_mask != render_pass_state.rendering_info.view_mask { + return Err(ExecuteCommandsError::RenderPassViewMaskMismatch { + command_buffer_index, + required_view_mask: render_pass_state.rendering_info.view_mask, + inherited_view_mask: inheritance_info.view_mask, + }); + } + } + _ => { + // VUID-vkCmdExecuteCommands-pBeginInfo-06025 + return Err(ExecuteCommandsError::RenderPassTypeMismatch { + command_buffer_index, + }); + } + } + + // TODO: + // VUID-vkCmdExecuteCommands-commandBuffer-06533 + // VUID-vkCmdExecuteCommands-commandBuffer-06534 + // VUID-vkCmdExecuteCommands-pCommandBuffers-06535 + // VUID-vkCmdExecuteCommands-pCommandBuffers-06536 + } else { + // VUID-vkCmdExecuteCommands-pCommandBuffers-00100 + if command_buffer.inheritance_info().render_pass.is_some() { + return Err(ExecuteCommandsError::RenderPassInheritanceForbidden { + command_buffer_index, + }); + } + } + + // VUID-vkCmdExecuteCommands-commandBuffer-00101 + if !self.builder_state.queries.is_empty() + && !self.device().enabled_features().inherited_queries + { + return Err(ExecuteCommandsError::RequirementNotMet { + required_for: "`CommandBufferBuilder::execute_commands` when a query is active", + requires_one_of: RequiresOneOf { + features: &["inherited_queries"], + ..Default::default() + }, + }); + } + + for state in self.builder_state.queries.values() { + match state.ty { + QueryType::Occlusion => { + // VUID-vkCmdExecuteCommands-commandBuffer-00102 + let inherited_flags = command_buffer.inheritance_info().occlusion_query.ok_or( + ExecuteCommandsError::OcclusionQueryInheritanceRequired { + command_buffer_index, + }, + )?; + + let inherited_flags_vk = ash::vk::QueryControlFlags::from(inherited_flags); + let state_flags_vk = ash::vk::QueryControlFlags::from(state.flags); + + // VUID-vkCmdExecuteCommands-commandBuffer-00103 + if inherited_flags_vk & state_flags_vk != state_flags_vk { + return Err(ExecuteCommandsError::OcclusionQueryFlagsNotSuperset { + command_buffer_index, + required_flags: state.flags, + inherited_flags, + }); + } + } + QueryType::PipelineStatistics(state_flags) => { + let inherited_flags = command_buffer.inheritance_info().query_statistics_flags; + let inherited_flags_vk = + ash::vk::QueryPipelineStatisticFlags::from(inherited_flags); + let state_flags_vk = ash::vk::QueryPipelineStatisticFlags::from(state_flags); + + // VUID-vkCmdExecuteCommands-commandBuffer-00104 + if inherited_flags_vk & state_flags_vk != state_flags_vk { + return Err( + ExecuteCommandsError::PipelineStatisticsQueryFlagsNotSuperset { + command_buffer_index, + required_flags: state_flags, + inherited_flags, + }, + ); + } + } + QueryType::Timestamp => (), + } + } + + // TODO: + // VUID-vkCmdExecuteCommands-pCommandBuffers-00091 + // VUID-vkCmdExecuteCommands-pCommandBuffers-00092 + // VUID-vkCmdExecuteCommands-pCommandBuffers-00093 + // VUID-vkCmdExecuteCommands-pCommandBuffers-00105 + + // VUID-vkCmdExecuteCommands-bufferlevel + // Ensured by the type of the impl block. + + // VUID-vkCmdExecuteCommands-pCommandBuffers-00088 + // VUID-vkCmdExecuteCommands-pCommandBuffers-00089 + // Ensured by the SecondaryCommandBuffer trait. + + // TODO: sync check + + Ok(()) + } + + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + pub unsafe fn execute_commands_unchecked( + &mut self, + command_buffer: SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>, + ) -> &mut Self { + struct DropUnlock<As>(SecondaryCommandBuffer<As>) + where + As: CommandBufferAlloc; + + impl<As> std::ops::Deref for DropUnlock<As> + where + As: CommandBufferAlloc, + { + type Target = SecondaryCommandBuffer<As>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + unsafe impl<As> SafeDeref for DropUnlock<As> where As: CommandBufferAlloc {} + + impl<As> Drop for DropUnlock<As> + where + As: CommandBufferAlloc, + { + fn drop(&mut self) { + unsafe { + self.unlock(); + } + } + } + + let command_buffer = { + command_buffer.lock_record().unwrap(); + DropUnlock(command_buffer) + }; + + let fns = self.device().fns(); + (fns.v1_0.cmd_execute_commands)(self.handle(), 1, &command_buffer.handle()); + + // The secondary command buffer could leave the primary in any state. + self.builder_state = Default::default(); + + // If the secondary is non-concurrent or one-time use, that restricts the primary as well. + self.usage = std::cmp::min(self.usage, command_buffer.usage); + + let _command_index = self.next_command_index; + let _command_name = "execute_commands"; + + // TODO: sync state update + + self.resources.push(Box::new(command_buffer)); + + self.next_command_index += 1; + self + } +} |