diff options
Diffstat (limited to 'src/command_buffer/mod.rs')
-rw-r--r-- | src/command_buffer/mod.rs | 677 |
1 files changed, 493 insertions, 184 deletions
diff --git a/src/command_buffer/mod.rs b/src/command_buffer/mod.rs index b439a4d..5808d51 100644 --- a/src/command_buffer/mod.rs +++ b/src/command_buffer/mod.rs @@ -7,141 +7,161 @@ // notice may not be copied, modified, or distributed except // according to those terms. -//! Commands that the GPU will execute (includes draw commands). +//! Recording commands to execute on the device. //! -//! With Vulkan, before the GPU can do anything you must create a `CommandBuffer`. A command buffer -//! is a list of commands that will executed by the GPU. Once a command buffer is created, you can -//! execute it. A command buffer must always be created even for the most simple tasks. +//! With Vulkan, to get the device to perform work, even relatively simple tasks, you must create a +//! command buffer. A command buffer is a list of commands that will executed by the device. +//! You must first record commands to a command buffer builder, then build it into an actual +//! command buffer, and then it can be used. Depending on how a command buffer is created, it can +//! be used only once, or reused many times. //! -//! # Primary and secondary command buffers. +//! # Command pools and allocators //! -//! There are three types of command buffers: +//! Command buffers are allocated from *command pools*. A command pool holds memory that is used to +//! record the sequence of commands in a command buffer. Command pools are not thread-safe, and +//! therefore commands cannot be recorded to a single command buffer from multiple threads at a +//! time. //! -//! - **Primary command buffers**. They can contain any command. They are the only type of command -//! buffer that can be submitted to a queue. -//! - **Secondary "graphics" command buffers**. They can only contain draw and clear commands. -//! They can only be called from a primary command buffer when inside a render pass. -//! - **Secondary "compute" command buffers**. They can only contain non-render-pass-related -//! commands (ie. everything but drawing, clearing, etc.) and cannot enter a render pass. They -//! can only be called from a primary command buffer outside of a render pass. +//! Raw command pools are unsafe to use, so Vulkano uses [command buffer allocators] to manage +//! command buffers and pools, to ensure their memory is used efficiently, and to protect against +//! invalid usage. Vulkano provides the [`StandardCommandBufferAllocator`] for this purpose, but +//! you can also create your own by implementing the [`CommandBufferAllocator`] trait. //! -//! Using secondary command buffers leads to slightly lower performance on the GPU, but they have -//! two advantages on the CPU side: +//! # Primary and secondary command buffers //! -//! - Building a command buffer is a single-threaded operation, but by using secondary command -//! buffers you can build multiple secondary command buffers in multiple threads simultaneously. -//! - Secondary command buffers can be kept alive between frames. When you always repeat the same -//! operations, it might be a good idea to build a secondary command buffer once at -//! initialization and then reuse it afterwards. +//! There are two levels of command buffers: //! -//! # The `AutoCommandBufferBuilder` +//! - [`PrimaryCommandBufferAbstract`] can be executed on a queue, and is the main command buffer +//! type. It cannot be executed within another command buffer. +//! - [`SecondaryCommandBufferAbstract`] can only be executed within a primary command buffer, +//! not directly on a queue. //! -//! The most basic (and recommended) way to create a command buffer is to create a -//! [`AutoCommandBufferBuilder`](struct.AutoCommandBufferBuilder.html), then record commands to it. -//! When you are done adding commands, build it to obtain either a `PrimaryAutoCommandBuffer` or -//! `SecondAutoCommandBuffer`. +//! Using secondary command buffers, there is slightly more overhead than using primary command +//! buffers alone, but there are also advantages. A single command buffer cannot be recorded +//! from multiple threads at a time, so if you want to divide the recording work among several +//! threads, each thread must record its own command buffer. While it is possible for these to be +//! all primary command buffers, there are limitations: a render pass or query cannot span multiple +//! primary command buffers, while secondary command buffers can [inherit] this state from their +//! parent primary command buffer. Therefore, to have a single render pass or query that is shared +//! across all the command buffers, you must record secondary command buffers. //! -//! Once built, use [the `PrimaryCommandBuffer` trait](trait.PrimaryCommandBuffer.html) to submit the -//! command buffer. Submitting a command buffer returns an object that implements the `GpuFuture` trait -//! and that represents the moment when the execution will end on the GPU. +//! # Recording a command buffer +//! +//! To record a new command buffer, the most direct way is to create a new +//! [`AutoCommandBufferBuilder`]. You can then call methods on this object to record new commands to +//! the command buffer. When you are done recording, you call [`build`] to finalise the command +//! buffer and turn it into either a [`PrimaryCommandBufferAbstract`] or a +//! [`SecondaryCommandBufferAbstract`]. +//! +// //! Using the standard `CommandBufferBuilder`, you must enter synchronization commands such as +// //! [pipeline barriers], to ensure that there are no races and memory access hazards. This can be +// //! difficult to do manually, so Vulkano also provides an alternative builder, +// //! [`AutoCommandBufferBuilder`]. Using this builder, you do not have to worry about managing +// //! synchronization, but the end result may not be quite as efficient. +//! +//! # Submitting a primary command buffer +//! +//! Once primary a command buffer is recorded and built, you can use the +//! [`PrimaryCommandBufferAbstract`] trait to submit the command buffer to a queue. Submitting a +//! command buffer returns an object that implements the [`GpuFuture`] trait and that represents +//! the moment when the execution will end on the GPU. //! //! ``` //! use vulkano::command_buffer::AutoCommandBufferBuilder; //! use vulkano::command_buffer::CommandBufferUsage; -//! use vulkano::command_buffer::PrimaryCommandBuffer; +//! use vulkano::command_buffer::PrimaryCommandBufferAbstract; +//! use vulkano::command_buffer::SubpassContents; +//! +//! # use vulkano::{buffer::BufferContents, pipeline::graphics::vertex_input::Vertex}; //! +//! # #[derive(BufferContents, Vertex)] +//! # #[repr(C)] +//! # struct PosVertex { +//! # #[format(R32G32B32_SFLOAT)] +//! # position: [f32; 3] +//! # }; //! # let device: std::sync::Arc<vulkano::device::Device> = return; //! # let queue: std::sync::Arc<vulkano::device::Queue> = return; +//! # let vertex_buffer: vulkano::buffer::Subbuffer<[PosVertex]> = return; +//! # let render_pass_begin_info: vulkano::command_buffer::RenderPassBeginInfo = return; +//! # let graphics_pipeline: std::sync::Arc<vulkano::pipeline::graphics::GraphicsPipeline> = return; +//! # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return; //! let cb = AutoCommandBufferBuilder::primary( -//! device.clone(), -//! queue.family(), +//! &command_buffer_allocator, +//! queue.queue_family_index(), //! CommandBufferUsage::MultipleSubmit //! ).unwrap() -//! // TODO: add an actual command to this example +//! .begin_render_pass(render_pass_begin_info, SubpassContents::Inline).unwrap() +//! .bind_pipeline_graphics(graphics_pipeline.clone()) +//! .bind_vertex_buffers(0, vertex_buffer.clone()) +//! .draw(vertex_buffer.len() as u32, 1, 0, 0).unwrap() +//! .end_render_pass().unwrap() //! .build().unwrap(); //! //! let _future = cb.execute(queue.clone()); //! ``` //! -//! # Internal architecture of vulkano -//! -//! The `commands_raw` and `commands_extra` modules contain structs that correspond to various -//! commands that can be added to command buffer builders. A command can be added to a command -//! buffer builder by using the `AddCommand<C>` trait, where `C` is the command struct. -//! -//! The `AutoCommandBufferBuilder` internally uses a `UnsafeCommandBufferBuilder` wrapped around -//! multiple layers. See the `cb` module for more information. -//! -//! Command pools are automatically handled by default, but vulkano also allows you to use -//! alternative command pool implementations and use them. See the `pool` module for more -//! information. - -pub use self::auto::AutoCommandBufferBuilder; -pub use self::auto::AutoCommandBufferBuilderContextError; -pub use self::auto::BeginError; -pub use self::auto::BeginQueryError; -pub use self::auto::BeginRenderPassError; -pub use self::auto::BlitImageError; -pub use self::auto::BuildError; -pub use self::auto::ClearColorImageError; -pub use self::auto::CopyBufferError; -pub use self::auto::CopyBufferImageError; -pub use self::auto::CopyImageError; -pub use self::auto::CopyQueryPoolResultsError; -pub use self::auto::DebugMarkerError; -pub use self::auto::DispatchError; -pub use self::auto::DispatchIndirectError; -pub use self::auto::DrawError; -pub use self::auto::DrawIndexedError; -pub use self::auto::DrawIndexedIndirectError; -pub use self::auto::DrawIndirectError; -pub use self::auto::EndQueryError; -pub use self::auto::ExecuteCommandsError; -pub use self::auto::FillBufferError; -pub use self::auto::PrimaryAutoCommandBuffer; -pub use self::auto::ResetQueryPoolError; -pub use self::auto::SecondaryAutoCommandBuffer; -pub use self::auto::UpdateBufferError; -pub use self::auto::WriteTimestampError; -pub use self::state_cacher::StateCacher; -pub use self::state_cacher::StateCacherOutcome; -pub use self::traits::CommandBufferExecError; -pub use self::traits::CommandBufferExecFuture; -pub use self::traits::PrimaryCommandBuffer; -pub use self::traits::SecondaryCommandBuffer; -use crate::pipeline::depth_stencil::DynamicStencilValue; -use crate::pipeline::viewport::{Scissor, Viewport}; -use crate::query::QueryControlFlags; -use crate::query::QueryPipelineStatisticFlags; -use crate::render_pass::{Framebuffer, Subpass}; -use std::sync::Arc; +//! [`StandardCommandBufferAllocator`]: self::allocator::StandardCommandBufferAllocator +//! [`CommandBufferAllocator`]: self::allocator::CommandBufferAllocator +//! [inherit]: CommandBufferInheritanceInfo +//! [`build`]: CommandBufferBuilder::build +//! [pipeline barriers]: CommandBufferBuilder::pipeline_barrier +//! [`GpuFuture`]: crate::sync::GpuFuture +#[doc(no_inline)] +pub(crate) use self::standard::{PrimaryCommandBuffer, SecondaryCommandBuffer}; +pub use self::{ + auto::{ + AutoCommandBufferBuilder, BuildError, CommandBufferBeginError, PrimaryAutoCommandBuffer, + SecondaryAutoCommandBuffer, + }, + commands::{ + clear::{ClearColorImageInfo, ClearDepthStencilImageInfo, ClearError}, + copy::{ + BlitImageInfo, BufferCopy, BufferImageCopy, CopyBufferInfo, CopyBufferInfoTyped, + CopyBufferToImageInfo, CopyError, CopyErrorResource, CopyImageInfo, + CopyImageToBufferInfo, ImageBlit, ImageCopy, ImageResolve, ResolveImageInfo, + }, + debug::DebugUtilsError, + pipeline::PipelineExecutionError, + query::QueryError, + render_pass::{ + ClearAttachment, ClearRect, RenderPassBeginInfo, RenderPassError, + RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo, + }, + secondary::ExecuteCommandsError, + }, + traits::{ + CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract, + SecondaryCommandBufferAbstract, + }, +}; +use crate::{ + buffer::{Buffer, Subbuffer}, + format::Format, + image::{sys::Image, ImageAccess, ImageLayout, ImageSubresourceRange, SampleCount}, + macros::vulkan_enum, + query::{QueryControlFlags, QueryPipelineStatisticFlags}, + range_map::RangeMap, + render_pass::{Framebuffer, Subpass}, + sync::{semaphore::Semaphore, PipelineMemoryAccess, PipelineStages}, + DeviceSize, +}; +use ahash::HashMap; +use bytemuck::{Pod, Zeroable}; +use std::{ops::Range, sync::Arc}; + +pub mod allocator; mod auto; +mod commands; pub mod pool; -mod state_cacher; -pub mod submit; +pub(crate) mod standard; pub mod synced; pub mod sys; mod traits; -pub mod validity; - -#[derive(Debug, Clone, Copy)] -pub enum ImageUninitializedSafe { - Safe, - Unsafe, -} - -impl ImageUninitializedSafe { - pub fn is_safe(&self) -> bool { - match self { - Self::Safe => true, - Self::Unsafe => false, - } - } -} #[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)] pub struct DrawIndirectCommand { pub vertex_count: u32, pub instance_count: u32, @@ -150,7 +170,7 @@ pub struct DrawIndirectCommand { } #[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)] pub struct DrawIndexedIndirectCommand { pub index_count: u32, pub instance_count: u32, @@ -160,84 +180,60 @@ pub struct DrawIndexedIndirectCommand { } #[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)] pub struct DispatchIndirectCommand { pub x: u32, pub y: u32, pub z: u32, } -/// The dynamic state to use for a draw command. -// TODO: probably not the right location -#[derive(Debug, Clone)] -pub struct DynamicState { - pub line_width: Option<f32>, - pub viewports: Option<Vec<Viewport>>, - pub scissors: Option<Vec<Scissor>>, - pub compare_mask: Option<DynamicStencilValue>, - pub write_mask: Option<DynamicStencilValue>, - pub reference: Option<DynamicStencilValue>, -} +vulkan_enum! { + #[non_exhaustive] -impl DynamicState { - #[inline] - pub fn none() -> DynamicState { - DynamicState { - line_width: None, - viewports: None, - scissors: None, - compare_mask: None, - write_mask: None, - reference: None, - } - } -} - -impl Default for DynamicState { - #[inline] - fn default() -> DynamicState { - DynamicState::none() - } -} + /// Describes what a subpass in a command buffer will contain. + SubpassContents = SubpassContents(i32); -/// Describes what a subpass in a command buffer will contain. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[repr(i32)] -pub enum SubpassContents { /// The subpass will only directly contain commands. - Inline = ash::vk::SubpassContents::INLINE.as_raw(), + Inline = INLINE, + /// The subpass will only contain secondary command buffers invocations. - SecondaryCommandBuffers = ash::vk::SubpassContents::SECONDARY_COMMAND_BUFFERS.as_raw(), + SecondaryCommandBuffers = SECONDARY_COMMAND_BUFFERS, } -impl From<SubpassContents> for ash::vk::SubpassContents { +impl From<SubpassContents> for ash::vk::RenderingFlags { #[inline] fn from(val: SubpassContents) -> Self { - Self::from_raw(val as i32) + match val { + SubpassContents::Inline => Self::empty(), + SubpassContents::SecondaryCommandBuffers => Self::CONTENTS_SECONDARY_COMMAND_BUFFERS, + } } } -/// Determines the kind of command buffer to create. -#[derive(Debug, Clone)] -pub enum CommandBufferLevel<F> { +vulkan_enum! { + /// Determines the kind of command buffer to create. + CommandBufferLevel = CommandBufferLevel(i32); + /// Primary command buffers can be executed on a queue, and can call secondary command buffers. /// Render passes must begin and end within the same primary command buffer. - Primary, + Primary = PRIMARY, /// Secondary command buffers cannot be executed on a queue, but can be executed by a primary /// command buffer. If created for a render pass, they must fit within a single render subpass. - Secondary(CommandBufferInheritance<F>), + Secondary = SECONDARY, } /// The context that a secondary command buffer can inherit from the primary command /// buffer it's executed in. -#[derive(Clone, Debug, Default)] -pub struct CommandBufferInheritance<F> { - /// If `Some`, the secondary command buffer is required to be executed within a specific - /// render subpass, and can only call draw operations. - /// If `None`, it must be executed outside a render pass, and can execute dispatch and transfer - /// operations, but not drawing operations. - render_pass: Option<CommandBufferInheritanceRenderPass<F>>, +#[derive(Clone, Debug)] +pub struct CommandBufferInheritanceInfo { + /// If `Some`, the secondary command buffer is required to be executed within a render pass + /// instance, and can only call draw operations. + /// If `None`, it must be executed outside a render pass instance, and can execute dispatch and + /// transfer operations, but not drawing operations. + /// + /// The default value is `None`. + pub render_pass: Option<CommandBufferInheritanceRenderPassType>, /// If `Some`, the secondary command buffer is allowed to be executed within a primary that has /// an occlusion query active. The inner `QueryControlFlags` specifies which flags the @@ -246,53 +242,156 @@ pub struct CommandBufferInheritance<F> { /// secondary command buffer is executed. /// /// The `inherited_queries` feature must be enabled if this is `Some`. - occlusion_query: Option<QueryControlFlags>, + /// + /// The default value is `None`. + pub occlusion_query: Option<QueryControlFlags>, /// Which pipeline statistics queries are allowed to be active on the primary command buffer /// when this secondary command buffer is executed. /// - /// The `pipeline_statistics_query` feature must be enabled if any of the flags of this value - /// are set. - query_statistics_flags: QueryPipelineStatisticFlags, + /// If this value is not empty, the [`pipeline_statistics_query`] feature must be enabled on + /// the device. + /// + /// The default value is [`QueryPipelineStatisticFlags::empty()`]. + /// + /// [`pipeline_statistics_query`]: crate::device::Features::pipeline_statistics_query + pub query_statistics_flags: QueryPipelineStatisticFlags, + + pub _ne: crate::NonExhaustive, +} + +impl Default for CommandBufferInheritanceInfo { + #[inline] + fn default() -> Self { + Self { + render_pass: None, + occlusion_query: None, + query_statistics_flags: QueryPipelineStatisticFlags::empty(), + _ne: crate::NonExhaustive(()), + } + } +} + +/// Selects the type of render pass for command buffer inheritance. +#[derive(Clone, Debug)] +pub enum CommandBufferInheritanceRenderPassType { + /// The secondary command buffer will be executed within a render pass begun with + /// `begin_render_pass`, using a `RenderPass` object and `Framebuffer`. + BeginRenderPass(CommandBufferInheritanceRenderPassInfo), + + /// The secondary command buffer will be executed within a render pass begun with + /// `begin_rendering`, using dynamic rendering. + BeginRendering(CommandBufferInheritanceRenderingInfo), +} + +impl From<Subpass> for CommandBufferInheritanceRenderPassType { + #[inline] + fn from(val: Subpass) -> Self { + Self::BeginRenderPass(val.into()) + } +} + +impl From<CommandBufferInheritanceRenderPassInfo> for CommandBufferInheritanceRenderPassType { + #[inline] + fn from(val: CommandBufferInheritanceRenderPassInfo) -> Self { + Self::BeginRenderPass(val) + } +} + +impl From<CommandBufferInheritanceRenderingInfo> for CommandBufferInheritanceRenderPassType { + #[inline] + fn from(val: CommandBufferInheritanceRenderingInfo) -> Self { + Self::BeginRendering(val) + } } /// The render pass context that a secondary command buffer is created for. -#[derive(Debug, Clone)] -pub struct CommandBufferInheritanceRenderPass<F> { +#[derive(Clone, Debug)] +pub struct CommandBufferInheritanceRenderPassInfo { /// The render subpass that this secondary command buffer must be executed within. + /// + /// There is no default value. pub subpass: Subpass, /// The framebuffer object that will be used when calling the command buffer. /// This parameter is optional and is an optimization hint for the implementation. - pub framebuffer: Option<F>, + /// + /// The default value is `None`. + pub framebuffer: Option<Arc<Framebuffer>>, } -impl CommandBufferLevel<Framebuffer<()>> { - /// Equivalent to `Kind::Primary`. - /// - /// > **Note**: If you use `let kind = Kind::Primary;` in your code, you will probably get a - /// > compilation error because the Rust compiler couldn't determine the template parameters - /// > of `Kind`. To solve that problem in an easy way you can use this function instead. +impl CommandBufferInheritanceRenderPassInfo { + /// Returns a `CommandBufferInheritanceRenderPassInfo` with the specified `subpass`. #[inline] - pub fn primary() -> CommandBufferLevel<Arc<Framebuffer<()>>> { - CommandBufferLevel::Primary + pub fn subpass(subpass: Subpass) -> Self { + Self { + subpass, + framebuffer: None, + } } +} + +impl From<Subpass> for CommandBufferInheritanceRenderPassInfo { + #[inline] + fn from(subpass: Subpass) -> Self { + Self { + subpass, + framebuffer: None, + } + } +} + +/// The dynamic rendering context that a secondary command buffer is created for. +#[derive(Clone, Debug)] +pub struct CommandBufferInheritanceRenderingInfo { + /// If not `0`, indicates that multiview rendering will be enabled, and specifies the view + /// indices that are rendered to. The value is a bitmask, so that that for example `0b11` will + /// draw to the first two views and `0b101` will draw to the first and third view. + /// + /// If set to a nonzero value, then the [`multiview`] feature must be enabled on the device. + /// + /// The default value is `0`. + /// + /// [`multiview`]: crate::device::Features::multiview + pub view_mask: u32, + + /// The formats of the color attachments that will be used during rendering. + /// + /// If an element is `None`, it indicates that the attachment will not be used. + /// + /// The default value is empty. + pub color_attachment_formats: Vec<Option<Format>>, + + /// The format of the depth attachment that will be used during rendering. + /// + /// If set to `None`, it indicates that no depth attachment will be used. + /// + /// The default value is `None`. + pub depth_attachment_format: Option<Format>, - /// Equivalent to `Kind::Secondary`. + /// The format of the stencil attachment that will be used during rendering. /// - /// > **Note**: If you use `let kind = Kind::Secondary;` in your code, you will probably get a - /// > compilation error because the Rust compiler couldn't determine the template parameters - /// > of `Kind`. To solve that problem in an easy way you can use this function instead. + /// If set to `None`, it indicates that no stencil attachment will be used. + /// + /// The default value is `None`. + pub stencil_attachment_format: Option<Format>, + + /// The number of samples that the color, depth and stencil attachments will have. + /// + /// The default value is [`SampleCount::Sample1`] + pub rasterization_samples: SampleCount, +} + +impl Default for CommandBufferInheritanceRenderingInfo { #[inline] - pub fn secondary( - occlusion_query: Option<QueryControlFlags>, - query_statistics_flags: QueryPipelineStatisticFlags, - ) -> CommandBufferLevel<Arc<Framebuffer<()>>> { - CommandBufferLevel::Secondary(CommandBufferInheritance { - render_pass: None, - occlusion_query, - query_statistics_flags, - }) + fn default() -> Self { + Self { + view_mask: 0, + color_attachment_formats: Vec::new(), + depth_attachment_format: None, + stencil_attachment_format: None, + rasterization_samples: SampleCount::Sample1, + } } } @@ -324,3 +423,213 @@ impl From<CommandBufferUsage> for ash::vk::CommandBufferUsageFlags { Self::from_raw(val as u32) } } + +/// Parameters to submit command buffers to a queue. +#[derive(Clone, Debug)] +pub struct SubmitInfo { + /// The semaphores to wait for before beginning the execution of this batch of + /// command buffer operations. + /// + /// The default value is empty. + pub wait_semaphores: Vec<SemaphoreSubmitInfo>, + + /// The command buffers to execute. + /// + /// The default value is empty. + pub command_buffers: Vec<Arc<dyn PrimaryCommandBufferAbstract>>, + + /// The semaphores to signal after the execution of this batch of command buffer operations + /// has completed. + /// + /// The default value is empty. + pub signal_semaphores: Vec<SemaphoreSubmitInfo>, + + pub _ne: crate::NonExhaustive, +} + +impl Default for SubmitInfo { + #[inline] + fn default() -> Self { + Self { + wait_semaphores: Vec::new(), + command_buffers: Vec::new(), + signal_semaphores: Vec::new(), + _ne: crate::NonExhaustive(()), + } + } +} + +/// Parameters for a semaphore signal or wait operation in a command buffer submission. +#[derive(Clone, Debug)] +pub struct SemaphoreSubmitInfo { + /// The semaphore to signal or wait for. + pub semaphore: Arc<Semaphore>, + + /// For a semaphore wait operation, specifies the pipeline stages in the second synchronization + /// scope: stages of queue operations following the wait operation that can start executing + /// after the semaphore is signalled. + /// + /// For a semaphore signal operation, specifies the pipeline stages in the first synchronization + /// scope: stages of queue operations preceding the signal operation that must complete before + /// the semaphore is signalled. + /// If this value does not equal [`ALL_COMMANDS`], then the [`synchronization2`] feature must + /// be enabled on the device. + /// + /// The default value is [`ALL_COMMANDS`]. + /// + /// [`ALL_COMMANDS`]: PipelineStages::ALL_COMMANDS + /// [`synchronization2`]: crate::device::Features::synchronization2 + pub stages: PipelineStages, + + pub _ne: crate::NonExhaustive, +} + +impl SemaphoreSubmitInfo { + /// Returns a `SemaphoreSubmitInfo` with the specified `semaphore`. + #[inline] + pub fn semaphore(semaphore: Arc<Semaphore>) -> Self { + Self { + semaphore, + stages: PipelineStages::ALL_COMMANDS, + _ne: crate::NonExhaustive(()), + } + } +} + +#[derive(Debug, Default)] +pub struct CommandBufferState { + has_been_submitted: bool, + pending_submits: u32, +} + +impl CommandBufferState { + pub(crate) fn has_been_submitted(&self) -> bool { + self.has_been_submitted + } + + pub(crate) fn is_submit_pending(&self) -> bool { + self.pending_submits != 0 + } + + pub(crate) unsafe fn add_queue_submit(&mut self) { + self.has_been_submitted = true; + self.pending_submits += 1; + } + + pub(crate) unsafe fn set_submit_finished(&mut self) { + self.pending_submits -= 1; + } +} + +#[doc(hidden)] +#[derive(Debug)] +pub struct CommandBufferResourcesUsage { + pub(crate) buffers: Vec<CommandBufferBufferUsage>, + pub(crate) images: Vec<CommandBufferImageUsage>, + pub(crate) buffer_indices: HashMap<Arc<Buffer>, usize>, + pub(crate) image_indices: HashMap<Arc<Image>, usize>, +} + +#[derive(Debug)] +pub(crate) struct CommandBufferBufferUsage { + pub(crate) buffer: Arc<Buffer>, + pub(crate) ranges: RangeMap<DeviceSize, CommandBufferBufferRangeUsage>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) struct CommandBufferBufferRangeUsage { + pub(crate) first_use: Option<ResourceUseRef>, + pub(crate) mutable: bool, +} + +#[derive(Debug)] +pub(crate) struct CommandBufferImageUsage { + pub(crate) image: Arc<Image>, + pub(crate) ranges: RangeMap<DeviceSize, CommandBufferImageRangeUsage>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) struct CommandBufferImageRangeUsage { + pub(crate) first_use: Option<ResourceUseRef>, + pub(crate) mutable: bool, + pub(crate) expected_layout: ImageLayout, + pub(crate) final_layout: ImageLayout, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct ResourceUseRef { + pub command_index: usize, + pub command_name: &'static str, + pub resource_in_command: ResourceInCommand, + pub secondary_use_ref: Option<SecondaryResourceUseRef>, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct SecondaryResourceUseRef { + pub command_index: usize, + pub command_name: &'static str, + pub resource_in_command: ResourceInCommand, +} + +impl From<ResourceUseRef> for SecondaryResourceUseRef { + #[inline] + fn from(val: ResourceUseRef) -> Self { + let ResourceUseRef { + command_index, + command_name, + resource_in_command, + secondary_use_ref, + } = val; + + debug_assert!(secondary_use_ref.is_none()); + + SecondaryResourceUseRef { + command_index, + command_name, + resource_in_command, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum ResourceInCommand { + ColorAttachment { index: u32 }, + ColorResolveAttachment { index: u32 }, + DepthStencilAttachment, + DepthStencilResolveAttachment, + DescriptorSet { set: u32, binding: u32, index: u32 }, + Destination, + FramebufferAttachment { index: u32 }, + ImageMemoryBarrier { index: u32 }, + IndexBuffer, + IndirectBuffer, + SecondaryCommandBuffer { index: u32 }, + Source, + VertexBuffer { binding: u32 }, +} + +#[doc(hidden)] +#[derive(Debug, Default)] +pub struct SecondaryCommandBufferResourcesUsage { + pub(crate) buffers: Vec<SecondaryCommandBufferBufferUsage>, + pub(crate) images: Vec<SecondaryCommandBufferImageUsage>, +} + +#[derive(Debug)] +pub(crate) struct SecondaryCommandBufferBufferUsage { + pub(crate) use_ref: ResourceUseRef, + pub(crate) buffer: Subbuffer<[u8]>, + pub(crate) range: Range<DeviceSize>, + pub(crate) memory: PipelineMemoryAccess, +} + +#[derive(Debug)] +pub(crate) struct SecondaryCommandBufferImageUsage { + pub(crate) use_ref: ResourceUseRef, + pub(crate) image: Arc<dyn ImageAccess>, + pub(crate) subresource_range: ImageSubresourceRange, + pub(crate) memory: PipelineMemoryAccess, + pub(crate) start_layout: ImageLayout, + pub(crate) end_layout: ImageLayout, +} |