// Copyright (c) 2016 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // 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 = return; //! # let queue: std::sync::Arc = 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` 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, pub viewports: Option>, pub scissors: Option>, pub compare_mask: Option, pub write_mask: Option, pub reference: Option, } 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 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 { /// 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), } /// 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 { /// 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>, /// 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, /// 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 { /// 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, } impl CommandBufferLevel> { /// 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>> { 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, query_statistics_flags: QueryPipelineStatisticFlags, ) -> CommandBufferLevel>> { 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 for ash::vk::CommandBufferUsageFlags { #[inline] fn from(val: CommandBufferUsage) -> Self { Self::from_raw(val as u32) } }