diff options
Diffstat (limited to 'third_party/rust/gfx-hal/src/pso')
-rw-r--r-- | third_party/rust/gfx-hal/src/pso/compute.rs | 31 | ||||
-rw-r--r-- | third_party/rust/gfx-hal/src/pso/descriptor.rs | 316 | ||||
-rw-r--r-- | third_party/rust/gfx-hal/src/pso/graphics.rs | 298 | ||||
-rw-r--r-- | third_party/rust/gfx-hal/src/pso/input_assembler.rs | 145 | ||||
-rw-r--r-- | third_party/rust/gfx-hal/src/pso/mod.rs | 220 | ||||
-rw-r--r-- | third_party/rust/gfx-hal/src/pso/output_merger.rs | 359 | ||||
-rw-r--r-- | third_party/rust/gfx-hal/src/pso/specialization.rs | 134 |
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() + } + }; +} |