summaryrefslogtreecommitdiffstats
path: root/third_party/rust/gfx-hal/src/pso
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/gfx-hal/src/pso')
-rw-r--r--third_party/rust/gfx-hal/src/pso/compute.rs31
-rw-r--r--third_party/rust/gfx-hal/src/pso/descriptor.rs316
-rw-r--r--third_party/rust/gfx-hal/src/pso/graphics.rs298
-rw-r--r--third_party/rust/gfx-hal/src/pso/input_assembler.rs145
-rw-r--r--third_party/rust/gfx-hal/src/pso/mod.rs220
-rw-r--r--third_party/rust/gfx-hal/src/pso/output_merger.rs359
-rw-r--r--third_party/rust/gfx-hal/src/pso/specialization.rs134
7 files changed, 1503 insertions, 0 deletions
diff --git a/third_party/rust/gfx-hal/src/pso/compute.rs b/third_party/rust/gfx-hal/src/pso/compute.rs
new file mode 100644
index 0000000000..8757e9a4e1
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/compute.rs
@@ -0,0 +1,31 @@
+//! Compute pipeline descriptor.
+
+use crate::{
+ pso::{BasePipeline, EntryPoint, PipelineCreationFlags},
+ Backend,
+};
+
+/// A description of the data needed to construct a compute pipeline.
+#[derive(Debug)]
+pub struct ComputePipelineDesc<'a, B: Backend> {
+ /// The shader entry point that performs the computation.
+ pub shader: EntryPoint<'a, B>,
+ /// Pipeline layout.
+ pub layout: &'a B::PipelineLayout,
+ /// Any flags necessary for the pipeline creation.
+ pub flags: PipelineCreationFlags,
+ /// The parent pipeline to this one, if any.
+ pub parent: BasePipeline<'a, B::ComputePipeline>,
+}
+
+impl<'a, B: Backend> ComputePipelineDesc<'a, B> {
+ /// Create a new empty PSO descriptor.
+ pub fn new(shader: EntryPoint<'a, B>, layout: &'a B::PipelineLayout) -> Self {
+ ComputePipelineDesc {
+ shader,
+ layout,
+ flags: PipelineCreationFlags::empty(),
+ parent: BasePipeline::None,
+ }
+ }
+}
diff --git a/third_party/rust/gfx-hal/src/pso/descriptor.rs b/third_party/rust/gfx-hal/src/pso/descriptor.rs
new file mode 100644
index 0000000000..c1d3a71d9e
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/descriptor.rs
@@ -0,0 +1,316 @@
+//! Descriptor sets and layouts.
+//!
+//! A [`Descriptor`] is an object that describes the connection between a resource, such as
+//! an `Image` or `Buffer`, and a variable in a shader. Descriptors are organized into
+//! `DescriptorSet`s, each of which contains multiple descriptors that are bound and unbound to
+//! shaders as a single unit. The contents of each descriptor in a set is defined by a
+//! `DescriptorSetLayout` which is in turn built of [`DescriptorSetLayoutBinding`]s. A `DescriptorSet`
+//! is then allocated from a [`DescriptorPool`] using the `DescriptorSetLayout`, and specific [`Descriptor`]s are
+//! then bound to each binding point in the set using a [`DescriptorSetWrite`] and/or [`DescriptorSetCopy`].
+//! Each descriptor set may contain descriptors to multiple different sorts of resources, and a shader may
+//! use multiple descriptor sets at a time.
+//!
+//! [`Descriptor`]: enum.Descriptor.html
+//! [`DescriptorSetLayoutBinding`]: struct.DescriptorSetLayoutBinding.html
+//! [`DescriptorPool`]: trait.DescriptorPool.html
+//! [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
+//! [`DescriptorSetCopy`]: struct.DescriptorSetWrite.html
+
+use std::{borrow::Borrow, fmt, iter};
+
+use crate::{
+ buffer::SubRange, device::OutOfMemory, image::Layout, pso::ShaderStageFlags, Backend, PseudoVec,
+};
+
+///
+pub type DescriptorSetIndex = u16;
+///
+pub type DescriptorBinding = u32;
+///
+pub type DescriptorArrayIndex = usize;
+
+/// Specific type of a buffer.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum BufferDescriptorType {
+ /// Storage buffers allow load, store, and atomic operations.
+ Storage {
+ /// If true, store operations are not permitted on this buffer.
+ read_only: bool,
+ },
+ /// Uniform buffers provide constant data to be accessed in a shader.
+ Uniform,
+}
+
+/// Format of a buffer.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum BufferDescriptorFormat {
+ /// The buffer is interpreted as a structure defined in a shader.
+ Structured {
+ /// If true, the buffer is accessed by an additional offset specified in
+ /// the `offsets` parameter of `CommandBuffer::bind_*_descriptor_sets`.
+ dynamic_offset: bool,
+ },
+ /// The buffer is interpreted as a 1-D array of texels, which undergo format
+ /// conversion when loaded in a shader.
+ Texel,
+}
+
+/// Specific type of an image descriptor.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum ImageDescriptorType {
+ /// A sampled image allows sampling operations.
+ Sampled {
+ /// If true, this descriptor corresponds to both a sampled image and a
+ /// sampler to be used with that image.
+ with_sampler: bool,
+ },
+ /// A storage image allows load, store and atomic operations.
+ Storage {
+ /// If true, store operations are not permitted on this image.
+ read_only: bool,
+ },
+}
+
+/// The type of a descriptor.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum DescriptorType {
+ /// A descriptor associated with sampler.
+ Sampler,
+ /// A descriptor associated with an image.
+ Image {
+ /// The specific type of this image descriptor.
+ ty: ImageDescriptorType,
+ },
+ /// A descriptor associated with a buffer.
+ Buffer {
+ /// The type of this buffer descriptor.
+ ty: BufferDescriptorType,
+ /// The format of this buffer descriptor.
+ format: BufferDescriptorFormat,
+ },
+ /// A descriptor associated with an input attachment.
+ InputAttachment,
+}
+
+/// Information about the contents of and in which stages descriptors may be bound to a descriptor
+/// set at a certain binding point. Multiple `DescriptorSetLayoutBinding`s are assembled into
+/// a `DescriptorSetLayout`, which is then allocated into a `DescriptorSet` using a
+/// [`DescriptorPool`].
+///
+/// A descriptor set consists of multiple binding points.
+/// Each binding point contains one or multiple descriptors of a certain type.
+/// The binding point is only valid for the pipelines stages specified.
+///
+/// The binding _must_ match with the corresponding shader interface.
+///
+/// [`DescriptorPool`]: trait.DescriptorPool.html
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DescriptorSetLayoutBinding {
+ /// Descriptor bindings range.
+ pub binding: DescriptorBinding,
+ /// Type of the bound descriptors.
+ pub ty: DescriptorType,
+ /// Number of descriptors in the array.
+ ///
+ /// *Note*: If count is zero, the binding point is reserved
+ /// and can't be accessed from any shader stages.
+ pub count: DescriptorArrayIndex,
+ /// Valid shader stages.
+ pub stage_flags: ShaderStageFlags,
+ /// Use the associated list of immutable samplers.
+ pub immutable_samplers: bool,
+}
+
+/// Set of descriptors of a specific type.
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DescriptorRangeDesc {
+ /// Type of the stored descriptors.
+ pub ty: DescriptorType,
+ /// Amount of space.
+ pub count: usize,
+}
+
+/// An error allocating descriptor sets from a pool.
+#[derive(Clone, Debug, PartialEq)]
+pub enum AllocationError {
+ /// OutOfMemory::Host: Memory allocation on the host side failed.
+ /// OutOfMemory::Device: Memory allocation on the device side failed.
+ /// This could be caused by a lack of memory or pool fragmentation.
+ OutOfMemory(OutOfMemory),
+ /// Memory allocation failed as there is not enough in the pool.
+ /// This could be caused by too many descriptor sets being created.
+ OutOfPoolMemory,
+ /// Memory allocation failed due to pool fragmentation.
+ FragmentedPool,
+ /// Descriptor set allocation failed as the layout is incompatible with the pool.
+ IncompatibleLayout,
+}
+
+impl std::fmt::Display for AllocationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ AllocationError::OutOfMemory(OutOfMemory::Host) => {
+ write!(fmt, "Failed to allocate descriptor set: Out of host memory")
+ }
+ AllocationError::OutOfMemory(OutOfMemory::Device) => write!(
+ fmt,
+ "Failed to allocate descriptor set: Out of device memory"
+ ),
+ AllocationError::OutOfPoolMemory => {
+ write!(fmt, "Failed to allocate descriptor set: Out of pool memory")
+ }
+ AllocationError::FragmentedPool => {
+ write!(fmt, "Failed to allocate descriptor set: Pool is fragmented")
+ }
+ AllocationError::IncompatibleLayout => write!(
+ fmt,
+ "Failed to allocate descriptor set: Incompatible layout"
+ ),
+ }
+ }
+}
+
+impl std::error::Error for AllocationError {}
+
+/// A descriptor pool is a collection of memory from which descriptor sets are allocated.
+pub trait DescriptorPool<B: Backend>: Send + Sync + fmt::Debug {
+ /// Allocate a descriptor set from the pool.
+ ///
+ /// The descriptor set will be allocated from the pool according to the corresponding set layout. However,
+ /// specific descriptors must still be written to the set before use using a [`DescriptorSetWrite`] or
+ /// [`DescriptorSetCopy`].
+ ///
+ /// Descriptors will become invalid once the pool is reset. Usage of invalidated descriptor sets results
+ /// in undefined behavior.
+ ///
+ /// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
+ /// [`DescriptorSetCopy`]: struct.DescriptorSetCopy.html
+ unsafe fn allocate_set(
+ &mut self,
+ layout: &B::DescriptorSetLayout,
+ ) -> Result<B::DescriptorSet, AllocationError> {
+ let mut result = PseudoVec(None);
+ self.allocate(iter::once(layout), &mut result)?;
+ Ok(result.0.unwrap())
+ }
+
+ /// Allocate multiple descriptor sets from the pool.
+ ///
+ /// The descriptor set will be allocated from the pool according to the corresponding set layout. However,
+ /// specific descriptors must still be written to the set before use using a [`DescriptorSetWrite`] or
+ /// [`DescriptorSetCopy`].
+ ///
+ /// Each descriptor set will be allocated from the pool according to the corresponding set layout.
+ /// Descriptors will become invalid once the pool is reset. Usage of invalidated descriptor sets results
+ /// in undefined behavior.
+ ///
+ /// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
+ /// [`DescriptorSetCopy`]: struct.DescriptorSetCopy.html
+ unsafe fn allocate<I, E>(&mut self, layouts: I, list: &mut E) -> Result<(), AllocationError>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<B::DescriptorSetLayout>,
+ E: Extend<B::DescriptorSet>,
+ {
+ for layout in layouts {
+ let set = self.allocate_set(layout.borrow())?;
+ list.extend(iter::once(set));
+ }
+ Ok(())
+ }
+
+ /// Free the given descriptor sets provided as an iterator.
+ unsafe fn free<I>(&mut self, descriptor_sets: I)
+ where
+ I: IntoIterator<Item = B::DescriptorSet>;
+
+ /// Resets a descriptor pool, releasing all resources from all the descriptor sets
+ /// allocated from it and freeing the descriptor sets. Invalidates all descriptor
+ /// sets allocated from the pool; trying to use one after the pool has been reset
+ /// is undefined behavior.
+ unsafe fn reset(&mut self);
+}
+
+/// Writes the actual descriptors to be bound into a descriptor set.
+///
+/// Should be provided to the `write_descriptor_sets` method of a `Device`.
+#[derive(Debug)]
+pub struct DescriptorSetWrite<'a, B: Backend, WI>
+where
+ WI: IntoIterator,
+ WI::Item: Borrow<Descriptor<'a, B>>,
+{
+ /// The descriptor set to modify.
+ pub set: &'a B::DescriptorSet,
+ /// Binding index to start writing at.
+ ///
+ /// *Note*: when there are more descriptors provided than
+ /// array elements left in the specified binding starting
+ /// at the specified offset, the updates are spilled onto
+ /// the next binding (starting with offset 0), and so on.
+ pub binding: DescriptorBinding,
+ /// Offset into the array to copy to.
+ pub array_offset: DescriptorArrayIndex,
+ /// Descriptors to write to the set.
+ pub descriptors: WI,
+}
+
+/// A handle to a specific shader resource that can be bound for use in a `DescriptorSet`.
+/// Usually provided in a [`DescriptorSetWrite`]
+///
+/// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
+#[allow(missing_docs)]
+#[derive(Clone, Debug)]
+pub enum Descriptor<'a, B: Backend> {
+ Sampler(&'a B::Sampler),
+ Image(&'a B::ImageView, Layout),
+ CombinedImageSampler(&'a B::ImageView, Layout, &'a B::Sampler),
+ Buffer(&'a B::Buffer, SubRange),
+ TexelBuffer(&'a B::BufferView),
+}
+
+/// Copies a range of descriptors to be bound from one descriptor set to another.
+///
+/// Should be provided to the `copy_descriptor_sets` method of a `Device`.
+#[derive(Clone, Copy, Debug)]
+pub struct DescriptorSetCopy<'a, B: Backend> {
+ /// Descriptor set to copy from.
+ pub src_set: &'a B::DescriptorSet,
+ /// Binding to copy from.
+ ///
+ /// *Note*: when there are more descriptors required than
+ /// array elements left in the specified binding starting
+ /// at the specified offset, the updates are taken from
+ /// the next binding (starting with offset 0), and so on.
+ pub src_binding: DescriptorBinding,
+ /// Offset into the descriptor array to start copying from.
+ pub src_array_offset: DescriptorArrayIndex,
+ /// Descriptor set to copy to.
+ pub dst_set: &'a B::DescriptorSet,
+ /// Binding to copy to.
+ ///
+ /// *Note*: when there are more descriptors provided than
+ /// array elements left in the specified binding starting
+ /// at the specified offset, the updates are spilled onto
+ /// the next binding (starting with offset 0), and so on.
+ pub dst_binding: DescriptorBinding,
+ /// Offset into the descriptor array to copy to.
+ pub dst_array_offset: DescriptorArrayIndex,
+ /// How many descriptors to copy.
+ pub count: usize,
+}
+
+bitflags! {
+ /// Descriptor pool creation flags.
+ pub struct DescriptorPoolCreateFlags: u32 {
+ /// Specifies that descriptor sets are allowed to be freed from the pool
+ /// individually.
+ const FREE_DESCRIPTOR_SET = 0x1;
+ }
+}
diff --git a/third_party/rust/gfx-hal/src/pso/graphics.rs b/third_party/rust/gfx-hal/src/pso/graphics.rs
new file mode 100644
index 0000000000..b647b1d611
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/graphics.rs
@@ -0,0 +1,298 @@
+//! Graphics pipeline descriptor.
+
+use crate::{
+ image, pass,
+ pso::{
+ input_assembler::{AttributeDesc, InputAssemblerDesc, VertexBufferDesc},
+ output_merger::{ColorBlendDesc, DepthStencilDesc, Face},
+ BasePipeline, EntryPoint, PipelineCreationFlags, State,
+ },
+ Backend,
+};
+
+use std::ops::Range;
+
+/// A simple struct describing a rect with integer coordinates.
+#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Rect {
+ /// X position.
+ pub x: i16,
+ /// Y position.
+ pub y: i16,
+ /// Width.
+ pub w: i16,
+ /// Height.
+ pub h: i16,
+}
+
+/// A simple struct describing a rect with integer coordinates.
+#[derive(Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct ClearRect {
+ /// 2D region.
+ pub rect: Rect,
+ /// Layer range.
+ pub layers: Range<image::Layer>,
+}
+
+/// A viewport, generally equating to a window on a display.
+#[derive(Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Viewport {
+ /// The viewport boundaries.
+ pub rect: Rect,
+ /// The viewport depth limits.
+ pub depth: Range<f32>,
+}
+
+/// A single RGBA float color.
+pub type ColorValue = [f32; 4];
+/// A single depth value from a depth buffer.
+pub type DepthValue = f32;
+/// A single value from a stencil buffer.
+pub type StencilValue = u32;
+/// Baked-in pipeline states.
+#[derive(Clone, Debug, Default, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct BakedStates {
+ /// Static viewport. TODO: multiple viewports
+ pub viewport: Option<Viewport>,
+ /// Static scissor. TODO: multiple scissors
+ pub scissor: Option<Rect>,
+ /// Static blend constant color.
+ pub blend_color: Option<ColorValue>,
+ /// Static depth bounds.
+ pub depth_bounds: Option<Range<f32>>,
+}
+#[derive(Debug)]
+/// Primitive Assembler describes how input data are fetched in the pipeline and formed into primitives before being sent into the fragment shader.
+pub enum PrimitiveAssemblerDesc<'a, B: Backend> {
+ /// Vertex based pipeline
+ Vertex {
+ /// Vertex buffers (IA)
+ buffers: &'a [VertexBufferDesc],
+ /// Vertex attributes (IA)
+ attributes: &'a [AttributeDesc],
+ /// Input assembler attributes, describes how
+ /// vertices are assembled into primitives (such as triangles).
+ input_assembler: InputAssemblerDesc,
+ /// A shader that outputs a vertex in a model.
+ vertex: EntryPoint<'a, B>,
+ /// Tesselation shaders consisting of:
+ ///
+ /// 1. Hull shader: takes in an input patch (values representing
+ /// a small portion of a shape, which may be actual geometry or may
+ /// be parameters for creating geometry) and produces one or more
+ /// output patches.
+ ///
+ /// 2. Domain shader: takes in domains produced from a hull shader's output
+ /// patches and computes actual vertex positions.
+ tessellation: Option<(EntryPoint<'a, B>, EntryPoint<'a, B>)>,
+ /// A shader that takes given input vertexes and outputs zero
+ /// or more output vertexes.
+ geometry: Option<EntryPoint<'a, B>>,
+ },
+ /// Mesh shading pipeline
+ Mesh {
+ /// A shader that creates a variable amount of mesh shader
+ /// invocations.
+ task: Option<EntryPoint<'a, B>>,
+ /// A shader of which each workgroup emits zero or
+ /// more output primitives and the group of vertices and their
+ /// associated data required for each output primitive.
+ mesh: EntryPoint<'a, B>,
+ },
+}
+/// A description of all the settings that can be altered
+/// when creating a graphics pipeline.
+#[derive(Debug)]
+pub struct GraphicsPipelineDesc<'a, B: Backend> {
+ /// Primitive assembler
+ pub primitive_assembler: PrimitiveAssemblerDesc<'a, B>,
+ /// Rasterizer setup
+ pub rasterizer: Rasterizer,
+ /// A shader that outputs a value for a fragment.
+ /// Usually this value is a color that is then displayed as a
+ /// pixel on a screen.
+ ///
+ /// If a fragment shader is omitted, the results of fragment
+ /// processing are undefined. Specifically, any fragment color
+ /// outputs are considered to have undefined values, and the
+ /// fragment depth is considered to be unmodified. This can
+ /// be useful for depth-only rendering.
+ pub fragment: Option<EntryPoint<'a, B>>,
+ /// Description of how blend operations should be performed.
+ pub blender: BlendDesc,
+ /// Depth stencil (DSV)
+ pub depth_stencil: DepthStencilDesc,
+ /// Multisampling.
+ pub multisampling: Option<Multisampling>,
+ /// Static pipeline states.
+ pub baked_states: BakedStates,
+ /// Pipeline layout.
+ pub layout: &'a B::PipelineLayout,
+ /// Subpass in which the pipeline can be executed.
+ pub subpass: pass::Subpass<'a, B>,
+ /// Options that may be set to alter pipeline properties.
+ pub flags: PipelineCreationFlags,
+ /// The parent pipeline, which may be
+ /// `BasePipeline::None`.
+ pub parent: BasePipeline<'a, B::GraphicsPipeline>,
+}
+
+impl<'a, B: Backend> GraphicsPipelineDesc<'a, B> {
+ /// Create a new empty PSO descriptor.
+ pub fn new(
+ primitive_assembler: PrimitiveAssemblerDesc<'a, B>,
+ rasterizer: Rasterizer,
+ fragment: Option<EntryPoint<'a, B>>,
+ layout: &'a B::PipelineLayout,
+ subpass: pass::Subpass<'a, B>,
+ ) -> Self {
+ GraphicsPipelineDesc {
+ primitive_assembler,
+ rasterizer,
+ fragment,
+ blender: BlendDesc::default(),
+ depth_stencil: DepthStencilDesc::default(),
+ multisampling: None,
+ baked_states: BakedStates::default(),
+ layout,
+ subpass,
+ flags: PipelineCreationFlags::empty(),
+ parent: BasePipeline::None,
+ }
+ }
+}
+
+/// Methods for rasterizing polygons, ie, turning the mesh
+/// into a raster image.
+#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum PolygonMode {
+ /// Rasterize as a point.
+ Point,
+ /// Rasterize as a line with the given width.
+ Line,
+ /// Rasterize as a face.
+ Fill,
+}
+
+/// The front face winding order of a set of vertices. This is
+/// the order of vertexes that define which side of a face is
+/// the "front".
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum FrontFace {
+ /// Clockwise winding order.
+ Clockwise,
+ /// Counter-clockwise winding order.
+ CounterClockwise,
+}
+
+/// A depth bias allows changing the produced depth values
+/// for fragments slightly but consistently. This permits
+/// drawing of multiple polygons in the same plane without
+/// Z-fighting, such as when trying to draw shadows on a wall.
+///
+/// For details of the algorithm and equations, see
+/// [the Vulkan spec](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#primsrast-depthbias).
+#[derive(Copy, Clone, Debug, Default, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DepthBias {
+ /// A constant depth value added to each fragment.
+ pub const_factor: f32,
+ /// The minimum or maximum depth bias of a fragment.
+ pub clamp: f32,
+ /// A constant bias applied to the fragment's slope.
+ pub slope_factor: f32,
+}
+
+/// Rasterization state.
+#[derive(Copy, Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Rasterizer {
+ /// How to rasterize this primitive.
+ pub polygon_mode: PolygonMode,
+ /// Which face should be culled.
+ pub cull_face: Face,
+ /// Which vertex winding is considered to be the front face for culling.
+ pub front_face: FrontFace,
+ /// Whether or not to enable depth clamping; when enabled, instead of
+ /// fragments being omitted when they are outside the bounds of the z-plane,
+ /// they will be clamped to the min or max z value.
+ pub depth_clamping: bool,
+ /// What depth bias, if any, to use for the drawn primitives.
+ pub depth_bias: Option<State<DepthBias>>,
+ /// Controls how triangles will be rasterized depending on their overlap with pixels.
+ pub conservative: bool,
+ /// Controls width of rasterized line segments.
+ pub line_width: State<f32>,
+}
+
+impl Rasterizer {
+ /// Simple polygon-filling rasterizer state
+ pub const FILL: Self = Rasterizer {
+ polygon_mode: PolygonMode::Fill,
+ cull_face: Face::NONE,
+ front_face: FrontFace::CounterClockwise,
+ depth_clamping: false,
+ depth_bias: None,
+ conservative: false,
+ line_width: State::Static(1.0),
+ };
+}
+
+/// A description of an equation for how to blend transparent, overlapping fragments.
+#[derive(Clone, Debug, Default, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct BlendDesc {
+ /// The logic operation to apply to the blending equation, if any.
+ pub logic_op: Option<LogicOp>,
+ /// Which color targets to apply the blending operation to.
+ pub targets: Vec<ColorBlendDesc>,
+}
+
+/// Logic operations used for specifying blend equations.
+#[derive(Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[allow(missing_docs)]
+pub enum LogicOp {
+ Clear = 0,
+ And = 1,
+ AndReverse = 2,
+ Copy = 3,
+ AndInverted = 4,
+ NoOp = 5,
+ Xor = 6,
+ Or = 7,
+ Nor = 8,
+ Equivalent = 9,
+ Invert = 10,
+ OrReverse = 11,
+ CopyInverted = 12,
+ OrInverted = 13,
+ Nand = 14,
+ Set = 15,
+}
+
+///
+pub type SampleMask = u64;
+
+///
+#[derive(Clone, Debug, PartialEq)]
+pub struct Multisampling {
+ ///
+ pub rasterization_samples: image::NumSamples,
+ ///
+ pub sample_shading: Option<f32>,
+ ///
+ pub sample_mask: SampleMask,
+ /// Toggles alpha-to-coverage multisampling, which can produce nicer edges
+ /// when many partially-transparent polygons are overlapping.
+ /// See [here]( https://msdn.microsoft.com/en-us/library/windows/desktop/bb205072(v=vs.85).aspx#Alpha_To_Coverage) for a full description.
+ pub alpha_coverage: bool,
+ ///
+ pub alpha_to_one: bool,
+}
diff --git a/third_party/rust/gfx-hal/src/pso/input_assembler.rs b/third_party/rust/gfx-hal/src/pso/input_assembler.rs
new file mode 100644
index 0000000000..55ba01bae7
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/input_assembler.rs
@@ -0,0 +1,145 @@
+//! Input Assembler (IA) stage description.
+//! The input assembler collects raw vertex and index data.
+
+use crate::{format, IndexType};
+
+/// Shader binding location.
+pub type Location = u32;
+/// Index of a vertex buffer.
+pub type BufferIndex = u32;
+/// Offset of an attribute from the start of the buffer, in bytes
+pub type ElemOffset = u32;
+/// Offset between attribute values, in bytes
+pub type ElemStride = u32;
+/// Number of instances between each advancement of the vertex buffer.
+pub type InstanceRate = u8;
+/// Number of vertices in a patch
+pub type PatchSize = u8;
+
+/// The rate at which to advance input data to shaders for the given buffer
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum VertexInputRate {
+ /// Advance the buffer after every vertex
+ Vertex,
+ /// Advance the buffer after every instance
+ Instance(InstanceRate),
+}
+
+impl VertexInputRate {
+ /// Get the numeric representation of the rate
+ pub fn as_uint(&self) -> u8 {
+ match *self {
+ VertexInputRate::Vertex => 0,
+ VertexInputRate::Instance(divisor) => divisor,
+ }
+ }
+}
+
+/// A struct element descriptor.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Element<F> {
+ /// Element format
+ pub format: F,
+ /// Offset from the beginning of the container, in bytes
+ pub offset: ElemOffset,
+}
+
+/// Vertex buffer description. Notably, completely separate from resource `Descriptor`s
+/// used in `DescriptorSet`s.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct VertexBufferDesc {
+ /// Binding number of this vertex buffer. This binding number is
+ /// used only for vertex buffers, and is completely separate from
+ /// `Descriptor` and `DescriptorSet` bind points.
+ pub binding: BufferIndex,
+ /// Total container size, in bytes.
+ /// Specifies the byte distance between two consecutive elements.
+ pub stride: ElemStride,
+ /// The rate at which to advance data for the given buffer
+ ///
+ /// i.e. the rate at which data passed to shaders will get advanced by
+ /// `stride` bytes
+ pub rate: VertexInputRate,
+}
+
+/// Vertex attribute description. Notably, completely separate from resource `Descriptor`s
+/// used in `DescriptorSet`s.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct AttributeDesc {
+ /// Attribute binding location in the shader. Attribute locations are
+ /// shared between all vertex buffers in a pipeline, meaning that even if the
+ /// data for this attribute comes from a different vertex buffer, it still cannot
+ /// share the same location with another attribute.
+ pub location: Location,
+ /// Binding number of the associated vertex buffer.
+ pub binding: BufferIndex,
+ /// Attribute element description.
+ pub element: Element<format::Format>,
+}
+
+/// Describes the type of geometric primitives,
+/// created from vertex data.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[repr(u8)]
+pub enum Primitive {
+ /// Each vertex represents a single point.
+ PointList,
+ /// Each pair of vertices represent a single line segment. For example, with `[a, b, c, d,
+ /// e]`, `a` and `b` form a line, `c` and `d` form a line, and `e` is discarded.
+ LineList,
+ /// Every two consecutive vertices represent a single line segment. Visually forms a "path" of
+ /// lines, as they are all connected. For example, with `[a, b, c]`, `a` and `b` form a line
+ /// line, and `b` and `c` form a line.
+ LineStrip,
+ /// Each triplet of vertices represent a single triangle. For example, with `[a, b, c, d, e]`,
+ /// `a`, `b`, and `c` form a triangle, `d` and `e` are discarded.
+ TriangleList,
+ /// Every three consecutive vertices represent a single triangle. For example, with `[a, b, c,
+ /// d]`, `a`, `b`, and `c` form a triangle, and `b`, `c`, and `d` form a triangle.
+ TriangleStrip,
+ /// Patch list,
+ /// used with shaders capable of producing primitives on their own (tessellation)
+ PatchList(PatchSize),
+}
+
+/// All the information needed to create an input assembler.
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct InputAssemblerDesc {
+ /// Type of the primitive
+ pub primitive: Primitive,
+ /// When adjacency information is enabled, every even-numbered vertex
+ /// (every other starting from the first) represents an additional
+ /// vertex for the primitive, while odd-numbered vertices (every other starting from the
+ /// second) represent adjacent vertices.
+ ///
+ /// For example, with `[a, b, c, d, e, f, g, h]`, `[a, c,
+ /// e, g]` form a triangle strip, and `[b, d, f, h]` are the adjacent vertices, where `b`, `d`,
+ /// and `f` are adjacent to the first triangle in the strip, and `d`, `f`, and `h` are adjacent
+ /// to the second.
+ pub with_adjacency: bool,
+ /// Describes whether or not primitive restart is supported for
+ /// an input assembler. Primitive restart is a feature that
+ /// allows a mark to be placed in an index buffer where it is
+ /// is "broken" into multiple pieces of geometry.
+ ///
+ /// See <https://www.khronos.org/opengl/wiki/Vertex_Rendering#Primitive_Restart>
+ /// for more detail.
+ pub restart_index: Option<IndexType>,
+}
+
+impl InputAssemblerDesc {
+ /// Create a new IA descriptor without primitive restart or adjucency.
+ pub fn new(primitive: Primitive) -> Self {
+ InputAssemblerDesc {
+ primitive,
+ with_adjacency: false,
+ restart_index: None,
+ }
+ }
+}
diff --git a/third_party/rust/gfx-hal/src/pso/mod.rs b/third_party/rust/gfx-hal/src/pso/mod.rs
new file mode 100644
index 0000000000..981605baac
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/mod.rs
@@ -0,0 +1,220 @@
+//! 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<device::OutOfMemory> 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<T> {
+ /// Static state that cannot be altered.
+ Static(T),
+ /// Dynamic state set through a command buffer.
+ Dynamic,
+}
+
+impl<T> State<T> {
+ /// 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()
+ }
+}
diff --git a/third_party/rust/gfx-hal/src/pso/output_merger.rs b/third_party/rust/gfx-hal/src/pso/output_merger.rs
new file mode 100644
index 0000000000..88fbc8a8b6
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/output_merger.rs
@@ -0,0 +1,359 @@
+//! Output Merger (OM) stage description.
+//! The final stage in a pipeline that creates pixel colors from
+//! the input shader results, depth/stencil information, etc.
+
+use crate::pso::{graphics::StencilValue, State};
+
+/// A pixel-wise comparison function.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Comparison {
+ /// `false`
+ Never = 0,
+ /// `x < y`
+ Less = 1,
+ /// `x == y`
+ Equal = 2,
+ /// `x <= y`
+ LessEqual = 3,
+ /// `x > y`
+ Greater = 4,
+ /// `x != y`
+ NotEqual = 5,
+ /// `x >= y`
+ GreaterEqual = 6,
+ /// `true`
+ Always = 7,
+}
+
+bitflags!(
+ /// Target output color mask.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct ColorMask: u8 {
+ /// Red mask
+ const RED = 0x1;
+ /// Green mask
+ const GREEN = 0x2;
+ /// Blue mask
+ const BLUE = 0x4;
+ /// Alpha channel mask
+ const ALPHA = 0x8;
+ /// Mask for RGB channels
+ const COLOR = 0x7;
+ /// Mask all channels
+ const ALL = 0xF;
+ /// Mask no channels.
+ const NONE = 0x0;
+ }
+);
+
+impl Default for ColorMask {
+ fn default() -> Self {
+ Self::ALL
+ }
+}
+
+/// Defines the possible blending factors.
+/// During blending, the source or destination fragment may be
+/// multiplied by a factor to produce the final result.
+#[allow(missing_docs)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Factor {
+ Zero = 0,
+ One = 1,
+ SrcColor = 2,
+ OneMinusSrcColor = 3,
+ DstColor = 4,
+ OneMinusDstColor = 5,
+ SrcAlpha = 6,
+ OneMinusSrcAlpha = 7,
+ DstAlpha = 8,
+ OneMinusDstAlpha = 9,
+ ConstColor = 10,
+ OneMinusConstColor = 11,
+ ConstAlpha = 12,
+ OneMinusConstAlpha = 13,
+ SrcAlphaSaturate = 14,
+ Src1Color = 15,
+ OneMinusSrc1Color = 16,
+ Src1Alpha = 17,
+ OneMinusSrc1Alpha = 18,
+}
+
+/// Blending operations.
+#[allow(missing_docs)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum BlendOp {
+ /// Adds source and destination.
+ /// Source and destination are multiplied by factors before addition.
+ Add { src: Factor, dst: Factor },
+ /// Subtracts destination from source.
+ /// Source and destination are multiplied by factors before subtraction.
+ Sub { src: Factor, dst: Factor },
+ /// Subtracts source from destination.
+ /// Source and destination are multiplied by factors before subtraction.
+ RevSub { src: Factor, dst: Factor },
+ /// Component-wise minimum value of source and destination.
+ Min,
+ /// Component-wise maximum value of source and destination.
+ Max,
+}
+
+impl BlendOp {
+ /// Replace the destination value with the source.
+ pub const REPLACE: Self = BlendOp::Add {
+ src: Factor::One,
+ dst: Factor::Zero,
+ };
+ /// Add the source and destination together.
+ pub const ADD: Self = BlendOp::Add {
+ src: Factor::One,
+ dst: Factor::One,
+ };
+ /// Alpha blend the source and destination together.
+ pub const ALPHA: Self = BlendOp::Add {
+ src: Factor::SrcAlpha,
+ dst: Factor::OneMinusSrcAlpha,
+ };
+ /// Alpha blend a premultiplied-alpha source with the destination.
+ pub const PREMULTIPLIED_ALPHA: Self = BlendOp::Add {
+ src: Factor::One,
+ dst: Factor::OneMinusSrcAlpha,
+ };
+}
+
+/// Specifies whether to use blending, and if so,
+/// which operations to use for color and alpha channels.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct BlendState {
+ /// The blend operation to use for the color channels.
+ pub color: BlendOp,
+ /// The blend operation to use for the alpha channel.
+ pub alpha: BlendOp,
+}
+
+impl BlendState {
+ /// Replace the color.
+ pub const REPLACE: Self = BlendState {
+ color: BlendOp::REPLACE,
+ alpha: BlendOp::REPLACE,
+ };
+ /// Additive blending.
+ pub const ADD: Self = BlendState {
+ color: BlendOp::ADD,
+ alpha: BlendOp::ADD,
+ };
+ /// Multiplicative blending.
+ pub const MULTIPLY: Self = BlendState {
+ color: BlendOp::Add {
+ src: Factor::Zero,
+ dst: Factor::SrcColor,
+ },
+ alpha: BlendOp::Add {
+ src: Factor::Zero,
+ dst: Factor::SrcAlpha,
+ },
+ };
+ /// Alpha blending.
+ pub const ALPHA: Self = BlendState {
+ color: BlendOp::ALPHA,
+ alpha: BlendOp::PREMULTIPLIED_ALPHA,
+ };
+ /// Pre-multiplied alpha blending.
+ pub const PREMULTIPLIED_ALPHA: Self = BlendState {
+ color: BlendOp::PREMULTIPLIED_ALPHA,
+ alpha: BlendOp::PREMULTIPLIED_ALPHA,
+ };
+}
+
+/// PSO color target descriptor.
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct ColorBlendDesc {
+ /// Color write mask.
+ pub mask: ColorMask,
+ /// Blend state, if enabled.
+ pub blend: Option<BlendState>,
+}
+
+impl ColorBlendDesc {
+ /// Empty blend descriptor just writes out the color without blending.
+ // this can be used because `Default::default()` isn't a const function...
+ pub const EMPTY: Self = ColorBlendDesc {
+ mask: ColorMask::ALL,
+ blend: None,
+ };
+}
+
+/// Depth test state.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DepthTest {
+ /// Comparison function to use.
+ pub fun: Comparison,
+ /// Specify whether to write to the depth buffer or not.
+ pub write: bool,
+}
+
+impl DepthTest {
+ /// A depth test that always fails.
+ pub const FAIL: Self = DepthTest {
+ fun: Comparison::Never,
+ write: false,
+ };
+ /// A depth test that always succeeds but doesn't
+ /// write to the depth buffer
+ // DOC TODO: Not a terribly helpful description there...
+ pub const PASS_TEST: Self = DepthTest {
+ fun: Comparison::Always,
+ write: false,
+ };
+ /// A depth test that always succeeds and writes its result
+ /// to the depth buffer.
+ pub const PASS_WRITE: Self = DepthTest {
+ fun: Comparison::Always,
+ write: true,
+ };
+}
+
+/// The operation to use for stencil masking.
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum StencilOp {
+ /// Keep the current value in the stencil buffer (no change).
+ Keep = 0,
+ /// Set the value in the stencil buffer to zero.
+ Zero = 1,
+ /// Set the stencil buffer value to `reference` from `StencilFace`.
+ Replace = 2,
+ /// Increment the stencil buffer value, clamping to its maximum value.
+ IncrementClamp = 3,
+ /// Decrement the stencil buffer value, clamping to its minimum value.
+ DecrementClamp = 4,
+ /// Bitwise invert the current value in the stencil buffer.
+ Invert = 5,
+ /// Increment the stencil buffer value, wrapping around to 0 on overflow.
+ IncrementWrap = 6,
+ /// Decrement the stencil buffer value, wrapping around to the maximum value on overflow.
+ DecrementWrap = 7,
+}
+
+/// Complete stencil state for a given side of a face.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct StencilFace {
+ /// Comparison function to use to determine if the stencil test passes.
+ pub fun: Comparison,
+ /// What operation to do if the stencil test fails.
+ pub op_fail: StencilOp,
+ /// What operation to do if the stencil test passes but the depth test fails.
+ pub op_depth_fail: StencilOp,
+ /// What operation to do if both the depth and stencil test pass.
+ pub op_pass: StencilOp,
+}
+
+impl Default for StencilFace {
+ fn default() -> StencilFace {
+ StencilFace {
+ fun: Comparison::Never,
+ op_fail: StencilOp::Keep,
+ op_depth_fail: StencilOp::Keep,
+ op_pass: StencilOp::Keep,
+ }
+ }
+}
+
+/// A generic struct holding the properties of two sides of a polygon.
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Sided<T> {
+ /// Information about the front face.
+ pub front: T,
+ /// Information about the back face.
+ pub back: T,
+}
+
+impl<T: Copy> Sided<T> {
+ /// Create a new `Sided` structure with both `front` and `back` holding
+ /// the same value.
+ pub fn new(value: T) -> Self {
+ Sided {
+ front: value,
+ back: value,
+ }
+ }
+}
+
+/// Pair of stencil values that could be either baked into a graphics pipeline
+/// or provided dynamically.
+pub type StencilValues = State<Sided<StencilValue>>;
+
+/// Defines a stencil test. Stencil testing is an operation
+/// performed to cull fragments;
+/// the new fragment is tested against the value held in the
+/// stencil buffer, and if the test fails the fragment is
+/// discarded.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct StencilTest {
+ /// Operations for stencil faces.
+ pub faces: Sided<StencilFace>,
+ /// Masks that are ANDd with both the stencil buffer value and the reference value when they
+ /// are read before doing the stencil test.
+ pub read_masks: StencilValues,
+ /// Mask that are ANDd with the stencil value before writing to the stencil buffer.
+ pub write_masks: StencilValues,
+ /// The reference values used for stencil tests.
+ pub reference_values: StencilValues,
+}
+
+impl Default for StencilTest {
+ fn default() -> Self {
+ StencilTest {
+ faces: Sided::default(),
+ read_masks: State::Static(Sided::new(!0)),
+ write_masks: State::Static(Sided::new(!0)),
+ reference_values: State::Static(Sided::new(0)),
+ }
+ }
+}
+
+/// PSO depth-stencil target descriptor.
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DepthStencilDesc {
+ /// Optional depth testing/writing.
+ pub depth: Option<DepthTest>,
+ /// Enable depth bounds testing.
+ pub depth_bounds: bool,
+ /// Stencil test/write.
+ pub stencil: Option<StencilTest>,
+}
+
+impl DepthStencilDesc {
+ /// Returns true if the descriptor assumes the depth attachment.
+ pub fn uses_depth(&self) -> bool {
+ self.depth.is_some() || self.depth_bounds
+ }
+ /// Returns true if the descriptor assumes the stencil attachment.
+ pub fn uses_stencil(&self) -> bool {
+ self.stencil.is_some()
+ }
+}
+
+bitflags!(
+ /// Face.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Face: u32 {
+ /// Empty face. TODO: remove when constexpr are stabilized to use empty()
+ const NONE = 0x0;
+ /// Front face.
+ const FRONT = 0x1;
+ /// Back face.
+ const BACK = 0x2;
+ }
+);
diff --git a/third_party/rust/gfx-hal/src/pso/specialization.rs b/third_party/rust/gfx-hal/src/pso/specialization.rs
new file mode 100644
index 0000000000..d4c15c3d25
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/specialization.rs
@@ -0,0 +1,134 @@
+//! Pipeline specialization types.
+
+use std::{borrow::Cow, ops::Range, slice};
+
+/// Description of a specialization constant for the pipeline.
+#[derive(Debug, Clone, Hash, PartialEq)]
+pub struct SpecializationConstant {
+ /// Constant identifier in shader source.
+ pub id: u32,
+ /// Value to override specialization constant.
+ pub range: Range<u16>,
+}
+
+/// Information required for pipeline specialization.
+///
+/// Specialization allows for easy configuration of multiple similar pipelines.
+/// For example, there may be a boolean exposed to the shader that switches
+/// the [specularity](https://en.wikipedia.org/wiki/Specularity) on/off,
+/// provided via a [specialization constant][SpecializationConstant].
+///
+/// That would produce separate PSO's for the "on" and "off" states
+/// but they share most of the internal stuff and are fast to produce.
+/// More importantly, they are fast to execute, since the driver
+/// can optimize out the branch on that other PSO creation.
+#[derive(Debug, Clone)]
+pub struct Specialization<'a> {
+ /// Array of descriptors of specialization constants to override.
+ pub constants: Cow<'a, [SpecializationConstant]>,
+ /// Raw data of the specialization constants
+ pub data: Cow<'a, [u8]>,
+}
+
+impl Specialization<'_> {
+ /// Empty specialization instance.
+ pub const EMPTY: Self = Specialization {
+ constants: Cow::Borrowed(&[]),
+ data: Cow::Borrowed(&[]),
+ };
+}
+
+impl Default for Specialization<'_> {
+ fn default() -> Self {
+ Specialization::EMPTY
+ }
+}
+
+#[doc(hidden)]
+#[derive(Debug, Default)]
+pub struct SpecializationStorage {
+ constants: Vec<SpecializationConstant>,
+ data: Vec<u8>,
+}
+
+/// List of specialization constants.
+#[doc(hidden)]
+pub trait SpecConstList: Sized {
+ fn fold(self, storage: &mut SpecializationStorage);
+}
+
+impl<T> From<T> for Specialization<'_>
+where
+ T: SpecConstList,
+{
+ fn from(list: T) -> Self {
+ let mut storage = SpecializationStorage::default();
+ list.fold(&mut storage);
+ Specialization {
+ data: Cow::Owned(storage.data),
+ constants: Cow::Owned(storage.constants),
+ }
+ }
+}
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct SpecConstListNil;
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct SpecConstListCons<H, T> {
+ pub head: (u32, H),
+ pub tail: T,
+}
+
+impl SpecConstList for SpecConstListNil {
+ fn fold(self, _storage: &mut SpecializationStorage) {}
+}
+
+impl<H, T> SpecConstList for SpecConstListCons<H, T>
+where
+ T: SpecConstList,
+{
+ fn fold(self, storage: &mut SpecializationStorage) {
+ let size = std::mem::size_of::<H>();
+ assert!(storage.data.len() + size <= u16::max_value() as usize);
+ let offset = storage.data.len() as u16;
+ storage.data.extend_from_slice(unsafe {
+ // Inspecting bytes is always safe.
+ let head_ptr: *const H = &self.head.1;
+ slice::from_raw_parts(head_ptr as *const u8, size)
+ });
+ storage.constants.push(SpecializationConstant {
+ id: self.head.0,
+ range: offset..offset + size as u16,
+ });
+ self.tail.fold(storage)
+ }
+}
+
+/// Macro for specifying list of specialization constants for `EntryPoint`.
+#[macro_export]
+macro_rules! spec_const_list {
+ (@ $(,)?) => {
+ $crate::pso::SpecConstListNil
+ };
+
+ (@ $head_id:expr => $head_constant:expr $(,$tail_id:expr => $tail_constant:expr)* $(,)?) => {
+ $crate::pso::SpecConstListCons {
+ head: ($head_id, $head_constant),
+ tail: $crate::spec_const_list!(@ $($tail_id => $tail_constant),*),
+ }
+ };
+
+ ($($id:expr => $constant:expr),* $(,)?) => {
+ $crate::spec_const_list!(@ $($id => $constant),*).into()
+ };
+
+ ($($constant:expr),* $(,)?) => {
+ {
+ let mut counter = 0;
+ $crate::spec_const_list!(@ $({ counter += 1; counter - 1 } => $constant),*).into()
+ }
+ };
+}