gfx_hal/pso/
descriptor.rs

1//! Descriptor sets and layouts.
2//!
3//! A [`Descriptor`] is an object that describes the connection between a resource, such as
4//! an `Image` or `Buffer`, and a variable in a shader. Descriptors are organized into
5//! `DescriptorSet`s, each of which contains multiple descriptors that are bound and unbound to
6//! shaders as a single unit. The contents of each descriptor in a set is defined by a
7//! `DescriptorSetLayout` which is in turn built of [`DescriptorSetLayoutBinding`]s. A `DescriptorSet`
8//! is then allocated from a [`DescriptorPool`] using the `DescriptorSetLayout`, and specific [`Descriptor`]s are
9//! then bound to each binding point in the set using a [`DescriptorSetWrite`] and/or [`DescriptorSetCopy`].
10//! Each descriptor set may contain descriptors to multiple different sorts of resources, and a shader may
11//! use multiple descriptor sets at a time.
12//!
13//! [`Descriptor`]: enum.Descriptor.html
14//! [`DescriptorSetLayoutBinding`]: struct.DescriptorSetLayoutBinding.html
15//! [`DescriptorPool`]: trait.DescriptorPool.html
16//! [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
17//! [`DescriptorSetCopy`]: struct.DescriptorSetWrite.html
18
19use crate::{
20    buffer::SubRange, device::OutOfMemory, image::Layout, pso::ShaderStageFlags, Backend, PseudoVec,
21};
22
23use std::{fmt, iter};
24
25///
26pub type DescriptorSetIndex = u16;
27///
28pub type DescriptorBinding = u32;
29///
30pub type DescriptorArrayIndex = usize;
31
32/// Specific type of a buffer.
33#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35pub enum BufferDescriptorType {
36    /// Storage buffers allow load, store, and atomic operations.
37    Storage {
38        /// If true, store operations are not permitted on this buffer.
39        read_only: bool,
40    },
41    /// Uniform buffers provide constant data to be accessed in a shader.
42    Uniform,
43}
44
45/// Format of a buffer.
46#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
47#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48pub enum BufferDescriptorFormat {
49    /// The buffer is interpreted as a structure defined in a shader.
50    Structured {
51        /// If true, the buffer is accessed by an additional offset specified in
52        /// the `offsets` parameter of `CommandBuffer::bind_*_descriptor_sets`.
53        dynamic_offset: bool,
54    },
55    /// The buffer is interpreted as a 1-D array of texels, which undergo format
56    /// conversion when loaded in a shader.
57    Texel,
58}
59
60/// Specific type of an image descriptor.
61#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63pub enum ImageDescriptorType {
64    /// A sampled image allows sampling operations.
65    Sampled {
66        /// If true, this descriptor corresponds to both a sampled image and a
67        /// sampler to be used with that image.
68        with_sampler: bool,
69    },
70    /// A storage image allows load, store and atomic operations.
71    Storage {
72        /// If true, store operations are not permitted on this image.
73        read_only: bool,
74    },
75}
76
77/// The type of a descriptor.
78#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
79#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
80pub enum DescriptorType {
81    /// A descriptor associated with sampler.
82    Sampler,
83    /// A descriptor associated with an image.
84    Image {
85        /// The specific type of this image descriptor.
86        ty: ImageDescriptorType,
87    },
88    /// A descriptor associated with a buffer.
89    Buffer {
90        /// The type of this buffer descriptor.
91        ty: BufferDescriptorType,
92        /// The format of this buffer descriptor.
93        format: BufferDescriptorFormat,
94    },
95    /// A descriptor associated with an input attachment.
96    InputAttachment,
97}
98
99/// Information about the contents of and in which stages descriptors may be bound to a descriptor
100/// set at a certain binding point. Multiple `DescriptorSetLayoutBinding`s are assembled into
101/// a `DescriptorSetLayout`, which is then allocated into a `DescriptorSet` using a
102/// [`DescriptorPool`].
103///
104/// A descriptor set consists of multiple binding points.
105/// Each binding point contains one or multiple descriptors of a certain type.
106/// The binding point is only valid for the pipelines stages specified.
107///
108/// The binding _must_ match with the corresponding shader interface.
109///
110/// [`DescriptorPool`]: trait.DescriptorPool.html
111#[derive(Clone, Debug)]
112#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
113pub struct DescriptorSetLayoutBinding {
114    /// Descriptor bindings range.
115    pub binding: DescriptorBinding,
116    /// Type of the bound descriptors.
117    pub ty: DescriptorType,
118    /// Number of descriptors in the array.
119    ///
120    /// *Note*: If count is zero, the binding point is reserved
121    /// and can't be accessed from any shader stages.
122    pub count: DescriptorArrayIndex,
123    /// Valid shader stages.
124    pub stage_flags: ShaderStageFlags,
125    /// Use the associated list of immutable samplers.
126    pub immutable_samplers: bool,
127}
128
129/// Set of descriptors of a specific type.
130#[derive(Clone, Copy, Debug)]
131#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
132pub struct DescriptorRangeDesc {
133    /// Type of the stored descriptors.
134    pub ty: DescriptorType,
135    /// Amount of space.
136    pub count: usize,
137}
138
139/// An error allocating descriptor sets from a pool.
140#[derive(Clone, Debug, PartialEq, thiserror::Error)]
141pub enum AllocationError {
142    /// OutOfMemory::Host: Memory allocation on the host side failed.
143    /// OutOfMemory::Device: Memory allocation on the device side failed.
144    /// This could be caused by a lack of memory or pool fragmentation.
145    #[error(transparent)]
146    OutOfMemory(#[from] OutOfMemory),
147    /// Memory allocation failed as there is not enough in the pool.
148    /// This could be caused by too many descriptor sets being created.
149    #[error("Out of pool memory")]
150    OutOfPoolMemory,
151    /// Memory allocation failed due to pool fragmentation.
152    #[error("Pool is fragmented")]
153    FragmentedPool,
154    /// Descriptor set allocation failed as the layout is incompatible with the pool.
155    #[error("Incompatible layout")]
156    IncompatibleLayout,
157}
158
159/// A descriptor pool is a collection of memory from which descriptor sets are allocated.
160pub trait DescriptorPool<B: Backend>: Send + Sync + fmt::Debug {
161    /// Allocate a descriptor set from the pool.
162    ///
163    /// The descriptor set will be allocated from the pool according to the corresponding set layout. However,
164    /// specific descriptors must still be written to the set before use using a [`DescriptorSetWrite`] or
165    /// [`DescriptorSetCopy`].
166    ///
167    /// Descriptors will become invalid once the pool is reset. Usage of invalidated descriptor sets results
168    /// in undefined behavior.
169    ///
170    /// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
171    /// [`DescriptorSetCopy`]: struct.DescriptorSetCopy.html
172    unsafe fn allocate_one(
173        &mut self,
174        layout: &B::DescriptorSetLayout,
175    ) -> Result<B::DescriptorSet, AllocationError> {
176        let mut result = PseudoVec(None);
177        self.allocate(iter::once(layout), &mut result)?;
178        Ok(result.0.unwrap())
179    }
180
181    /// Allocate multiple descriptor sets from the pool.
182    ///
183    /// The descriptor set will be allocated from the pool according to the corresponding set layout. However,
184    /// specific descriptors must still be written to the set before use using a [`DescriptorSetWrite`] or
185    /// [`DescriptorSetCopy`].
186    ///
187    /// Each descriptor set will be allocated from the pool according to the corresponding set layout.
188    /// Descriptors will become invalid once the pool is reset. Usage of invalidated descriptor sets results
189    /// in undefined behavior.
190    ///
191    /// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
192    /// [`DescriptorSetCopy`]: struct.DescriptorSetCopy.html
193    unsafe fn allocate<'a, I, E>(&mut self, layouts: I, list: &mut E) -> Result<(), AllocationError>
194    where
195        I: Iterator<Item = &'a B::DescriptorSetLayout>,
196        E: Extend<B::DescriptorSet>,
197    {
198        for layout in layouts {
199            let set = self.allocate_one(layout)?;
200            list.extend(iter::once(set));
201        }
202        Ok(())
203    }
204
205    /// Free the given descriptor sets provided as an iterator.
206    unsafe fn free<I>(&mut self, descriptor_sets: I)
207    where
208        I: Iterator<Item = B::DescriptorSet>;
209
210    /// Resets a descriptor pool, releasing all resources from all the descriptor sets
211    /// allocated from it and freeing the descriptor sets. Invalidates all descriptor
212    /// sets allocated from the pool; trying to use one after the pool has been reset
213    /// is undefined behavior.
214    unsafe fn reset(&mut self);
215}
216
217/// Writes the actual descriptors to be bound into a descriptor set.
218///
219/// Should be provided to the `write_descriptor_sets` method of a `Device`.
220#[derive(Debug)]
221pub struct DescriptorSetWrite<'a, B: Backend, I>
222where
223    I: Iterator<Item = Descriptor<'a, B>>,
224{
225    /// The descriptor set to modify.
226    pub set: &'a mut B::DescriptorSet,
227    /// Binding index to start writing at.
228    ///
229    /// *Note*: when there are more descriptors provided than
230    /// array elements left in the specified binding starting
231    /// at the specified offset, the updates are spilled onto
232    /// the next binding (starting with offset 0), and so on.
233    pub binding: DescriptorBinding,
234    /// Offset into the array to copy to.
235    pub array_offset: DescriptorArrayIndex,
236    /// Descriptors to write to the set.
237    pub descriptors: I,
238}
239
240/// A handle to a specific shader resource that can be bound for use in a `DescriptorSet`.
241/// Usually provided in a [`DescriptorSetWrite`]
242///
243/// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
244#[allow(missing_docs)]
245#[derive(Clone, Debug)]
246pub enum Descriptor<'a, B: Backend> {
247    Sampler(&'a B::Sampler),
248    Image(&'a B::ImageView, Layout),
249    CombinedImageSampler(&'a B::ImageView, Layout, &'a B::Sampler),
250    Buffer(&'a B::Buffer, SubRange),
251    TexelBuffer(&'a B::BufferView),
252}
253
254/// Copies a range of descriptors to be bound from one descriptor set to another.
255///
256/// Should be provided to the `copy_descriptor_sets` method of a `Device`.
257#[derive(Debug)]
258pub struct DescriptorSetCopy<'a, B: Backend> {
259    /// Descriptor set to copy from.
260    pub src_set: &'a B::DescriptorSet,
261    /// Binding to copy from.
262    ///
263    /// *Note*: when there are more descriptors required than
264    /// array elements left in the specified binding starting
265    /// at the specified offset, the updates are taken from
266    /// the next binding (starting with offset 0), and so on.
267    pub src_binding: DescriptorBinding,
268    /// Offset into the descriptor array to start copying from.
269    pub src_array_offset: DescriptorArrayIndex,
270    /// Descriptor set to copy to.
271    pub dst_set: &'a mut B::DescriptorSet,
272    /// Binding to copy to.
273    ///
274    /// *Note*: when there are more descriptors provided than
275    /// array elements left in the specified binding starting
276    /// at the specified offset, the updates are spilled onto
277    /// the next binding (starting with offset 0), and so on.
278    pub dst_binding: DescriptorBinding,
279    /// Offset into the descriptor array to copy to.
280    pub dst_array_offset: DescriptorArrayIndex,
281    /// How many descriptors to copy.
282    pub count: usize,
283}
284
285bitflags! {
286    /// Descriptor pool creation flags.
287    pub struct DescriptorPoolCreateFlags: u32 {
288        /// Specifies that descriptor sets are allowed to be freed from the pool
289        /// individually.
290        const FREE_DESCRIPTOR_SET = 0x1;
291    }
292}