diff options
Diffstat (limited to 'third_party/rust/gfx-hal/src/pso/descriptor.rs')
-rw-r--r-- | third_party/rust/gfx-hal/src/pso/descriptor.rs | 316 |
1 files changed, 316 insertions, 0 deletions
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; + } +} |