//! Raw Pipeline State Objects //! //! This module contains items used to create and manage Pipelines. use crate::{device, pass, Backend}; mod compute; mod descriptor; mod graphics; mod input_assembler; mod output_merger; mod specialization; pub use self::{ compute::*, descriptor::*, graphics::*, input_assembler::*, output_merger::*, specialization::*, }; /// Error types happening upon PSO creation on the device side. #[derive(Clone, Debug, PartialEq)] pub enum CreationError { /// Unknown other error. Other, /// Unsupported pipeline on hardware or implementation. Example: mesh shaders on DirectX 11. UnsupportedPipeline, /// Invalid subpass (not part of renderpass). InvalidSubpass(pass::SubpassId), /// Shader compilation error. Shader(device::ShaderError), /// Out of either host or device memory. OutOfMemory(device::OutOfMemory), } impl From for CreationError { fn from(err: device::OutOfMemory) -> Self { CreationError::OutOfMemory(err) } } impl std::fmt::Display for CreationError { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { CreationError::OutOfMemory(err) => write!(fmt, "Failed to create pipeline: {}", err), CreationError::Other => write!(fmt, "Failed to create pipeline: Unsupported usage: Implementation specific error occurred"), CreationError::UnsupportedPipeline => write!(fmt, "Failed to create pipeline: pipeline type is not supported"), CreationError::InvalidSubpass(subpass) => write!(fmt, "Failed to create pipeline: Invalid subpass: {}", subpass), CreationError::Shader(err) => write!(fmt, "Failed to create pipeline: {}", err), } } } impl std::error::Error for CreationError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { CreationError::OutOfMemory(err) => Some(err), CreationError::Shader(err) => Some(err), CreationError::InvalidSubpass(_) => None, CreationError::Other => None, CreationError::UnsupportedPipeline => None, } } } bitflags!( /// Stages of the logical pipeline. /// /// The pipeline is structured by the ordering of the flags. /// Some stages are queue type dependent. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PipelineStage: u32 { /// Beginning of the command queue. const TOP_OF_PIPE = 0x1; /// Indirect data consumption. const DRAW_INDIRECT = 0x2; /// Vertex data consumption. const VERTEX_INPUT = 0x4; /// Vertex shader execution. const VERTEX_SHADER = 0x8; /// Hull shader execution. const HULL_SHADER = 0x10; /// Domain shader execution. const DOMAIN_SHADER = 0x20; /// Geometry shader execution. const GEOMETRY_SHADER = 0x40; /// Fragment shader execution. const FRAGMENT_SHADER = 0x80; /// Stage of early depth and stencil test. const EARLY_FRAGMENT_TESTS = 0x100; /// Stage of late depth and stencil test. const LATE_FRAGMENT_TESTS = 0x200; /// Stage of final color value calculation. const COLOR_ATTACHMENT_OUTPUT = 0x400; /// Compute shader execution, const COMPUTE_SHADER = 0x800; /// Copy/Transfer command execution. const TRANSFER = 0x1000; /// End of the command queue. const BOTTOM_OF_PIPE = 0x2000; /// Read/Write access from host. /// (Not a real pipeline stage) const HOST = 0x4000; /// Task shader stage. const TASK_SHADER = 0x80000; /// Mesh shader stage. const MESH_SHADER = 0x100000; } ); bitflags!( /// Combination of different shader pipeline stages. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Default)] pub struct ShaderStageFlags: u32 { /// Vertex shader stage. const VERTEX = 0x1; /// Hull (tessellation) shader stage. const HULL = 0x2; /// Domain (tessellation) shader stage. const DOMAIN = 0x4; /// Geometry shader stage. const GEOMETRY = 0x8; /// Fragment shader stage. const FRAGMENT = 0x10; /// Compute shader stage. const COMPUTE = 0x20; /// Task shader stage. const TASK = 0x40; /// Mesh shader stage. const MESH = 0x80; /// All graphics pipeline shader stages. const GRAPHICS = Self::VERTEX.bits | Self::HULL.bits | Self::DOMAIN.bits | Self::GEOMETRY.bits | Self::FRAGMENT.bits; /// All shader stages (matches Vulkan). const ALL = 0x7FFFFFFF; } ); /// Shader entry point. #[derive(Debug)] pub struct EntryPoint<'a, B: Backend> { /// Entry point name. pub entry: &'a str, /// Reference to the shader module containing this entry point. pub module: &'a B::ShaderModule, /// Specialization constants to be used when creating the pipeline. pub specialization: Specialization<'a>, } impl<'a, B: Backend> Clone for EntryPoint<'a, B> { fn clone(&self) -> Self { EntryPoint { entry: self.entry, module: self.module, specialization: self.specialization.clone(), } } } bitflags!( /// Pipeline creation flags. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PipelineCreationFlags: u32 { /// Disable pipeline optimizations. /// /// May speedup pipeline creation. const DISABLE_OPTIMIZATION = 0x1; /// Allow derivatives (children) of the pipeline. /// /// Must be set when pipelines set the pipeline as base. const ALLOW_DERIVATIVES = 0x2; } ); /// A reference to a parent pipeline. The assumption is that /// a parent and derivative/child pipeline have most settings /// in common, and one may be switched for another more quickly /// than entirely unrelated pipelines would be. #[derive(Debug)] pub enum BasePipeline<'a, P: 'a> { /// Referencing an existing pipeline as parent. Pipeline(&'a P), /// A pipeline in the same create pipelines call. /// /// The index of the parent must be lower than the index of the child. Index(usize), /// No parent pipeline exists. None, } /// Pipeline state which may be static or dynamic. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum State { /// Static state that cannot be altered. Static(T), /// Dynamic state set through a command buffer. Dynamic, } impl State { /// Returns the static value or a default. pub fn static_or(self, default: T) -> T { match self { State::Static(v) => v, State::Dynamic => default, } } /// Whether the state is static. pub fn is_static(self) -> bool { match self { State::Static(_) => true, State::Dynamic => false, } } /// Whether the state is dynamic. pub fn is_dynamic(self) -> bool { !self.is_static() } }