aboutsummaryrefslogtreecommitdiff
path: root/src/command_buffer/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/command_buffer/mod.rs')
-rw-r--r--src/command_buffer/mod.rs677
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,
+}