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}