blob: b439a4dc4c13dd8edf90ee8ecaf677ed4fe02573 [file] [log] [blame]
// 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)
}
}