diff options
Diffstat (limited to 'src/command_buffer/mod.rs')
-rw-r--r-- | src/command_buffer/mod.rs | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/src/command_buffer/mod.rs b/src/command_buffer/mod.rs new file mode 100644 index 0000000..b439a4d --- /dev/null +++ b/src/command_buffer/mod.rs @@ -0,0 +1,326 @@ +// Copyright (c) 2016 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. + +//! Commands that the GPU will execute (includes draw commands). +//! +//! 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. +//! +//! # Primary and secondary command buffers. +//! +//! There are three types of command buffers: +//! +//! - **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. +//! +//! Using secondary command buffers leads to slightly lower performance on the GPU, but they have +//! two advantages on the CPU side: +//! +//! - 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. +//! +//! # The `AutoCommandBufferBuilder` +//! +//! 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`. +//! +//! 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. +//! +//! ``` +//! use vulkano::command_buffer::AutoCommandBufferBuilder; +//! use vulkano::command_buffer::CommandBufferUsage; +//! use vulkano::command_buffer::PrimaryCommandBuffer; +//! +//! # let device: std::sync::Arc<vulkano::device::Device> = return; +//! # let queue: std::sync::Arc<vulkano::device::Queue> = return; +//! let cb = AutoCommandBufferBuilder::primary( +//! device.clone(), +//! queue.family(), +//! CommandBufferUsage::MultipleSubmit +//! ).unwrap() +//! // TODO: add an actual command to this example +//! .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; + +mod auto; +pub mod pool; +mod state_cacher; +pub mod submit; +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)] +pub struct DrawIndirectCommand { + pub vertex_count: u32, + pub instance_count: u32, + pub first_vertex: u32, + pub first_instance: u32, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct DrawIndexedIndirectCommand { + pub index_count: u32, + pub instance_count: u32, + pub first_index: u32, + pub vertex_offset: u32, + pub first_instance: u32, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, 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>, +} + +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. +#[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(), + /// The subpass will only contain secondary command buffers invocations. + SecondaryCommandBuffers = ash::vk::SubpassContents::SECONDARY_COMMAND_BUFFERS.as_raw(), +} + +impl From<SubpassContents> for ash::vk::SubpassContents { + #[inline] + fn from(val: SubpassContents) -> Self { + Self::from_raw(val as i32) + } +} + +/// Determines the kind of command buffer to create. +#[derive(Debug, Clone)] +pub enum CommandBufferLevel<F> { + /// 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, + + /// 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>), +} + +/// 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>>, + + /// 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 + /// active occlusion is allowed to have enabled. + /// If `None`, the primary command buffer cannot have an occlusion query active when this + /// secondary command buffer is executed. + /// + /// The `inherited_queries` feature must be enabled if this is `Some`. + 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, +} + +/// The render pass context that a secondary command buffer is created for. +#[derive(Debug, Clone)] +pub struct CommandBufferInheritanceRenderPass<F> { + /// The render subpass that this secondary command buffer must be executed within. + 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>, +} + +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. + #[inline] + pub fn primary() -> CommandBufferLevel<Arc<Framebuffer<()>>> { + CommandBufferLevel::Primary + } + + /// Equivalent to `Kind::Secondary`. + /// + /// > **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. + #[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, + }) + } +} + +/// Usage flags to pass when creating a command buffer. +/// +/// The safest option is `SimultaneousUse`, but it may be slower than the other two. +// NOTE: The ordering is important: the variants are listed from least to most permissive! +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[repr(u32)] +pub enum CommandBufferUsage { + /// The command buffer can only be submitted once before being destroyed. Any further submit is + /// forbidden. This makes it possible for the implementation to perform additional + /// optimizations. + OneTimeSubmit = ash::vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT.as_raw(), + + /// The command buffer can be used multiple times, but must not execute or record more than once + /// simultaneously. In other words, it is as if executing the command buffer borrows it mutably. + MultipleSubmit = 0, + + /// The command buffer can be executed multiple times in parallel on different queues. + /// If it's a secondary command buffer, it can be recorded to multiple primary command buffers + /// at once. + SimultaneousUse = ash::vk::CommandBufferUsageFlags::SIMULTANEOUS_USE.as_raw(), +} + +impl From<CommandBufferUsage> for ash::vk::CommandBufferUsageFlags { + #[inline] + fn from(val: CommandBufferUsage) -> Self { + Self::from_raw(val as u32) + } +} |