Skip to main content

vk_graph/driver/
descriptor_set.rs

1//! Explicit descriptor set allocation and update support.
2//!
3//! [`DescriptorSet::alloc_and_update`] creates an immutable descriptor set from a reflected
4//! pipeline layout. The result owns its Vulkan descriptor pool and keeps every resource referenced
5//! by a write or copy alive. Clone it cheaply to reuse the same allocation.
6//!
7//! Descriptor contents do not declare graph synchronization. Bind each referenced resource to the
8//! graph and declare its [`AccessType`](crate::driver::sync::AccessType) separately, then bind the
9//! set with [`PipelineCommand::bind_descriptor_set`](crate::cmd::PipelineCommand::bind_descriptor_set).
10//!
11//! Input attachments, texel buffers, and dynamic buffer descriptors are currently unsupported by
12//! this immutable API and prevent allocating a first-class set for their set index.
13
14use {
15    super::{
16        DescriptorSetLayout, DriverError,
17        accel_struct::AccelerationStructure,
18        buffer::{Buffer, BufferSubresourceRange},
19        compute::ComputePipeline,
20        device::Device,
21        format_aspect_mask,
22        graphics::GraphicsPipeline,
23        image::{Image, ImageViewInfo},
24        ray_tracing::RayTracingPipeline,
25        shader::PipelineDescriptorInfo,
26    },
27    ash::vk,
28    log::warn,
29    std::{
30        fmt::{Debug, Formatter},
31        iter,
32        ops::Deref,
33        slice,
34        sync::Arc,
35        thread::panicking,
36    },
37};
38
39/// Descriptor pool resource used to allocate descriptor sets for pipeline execution.
40///
41/// See [`VkDescriptorPool`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkDescriptorPool.html).
42#[derive(Debug)]
43#[read_only::cast]
44pub(crate) struct DescriptorPool {
45    /// The device which owns this descriptor pool resource.
46    ///
47    /// _Note:_ This field is read-only.
48    #[readonly]
49    pub device: Device,
50
51    /// The native Vulkan resource handle of this descriptor pool.
52    ///
53    /// _Note:_ This field is read-only.
54    #[readonly]
55    pub handle: vk::DescriptorPool,
56
57    /// Information used to create this descriptor pool resource.
58    ///
59    /// _Note:_ This field is read-only.
60    #[readonly]
61    pub(crate) info: DescriptorPoolInfo,
62}
63
64impl DescriptorPool {
65    #[profiling::function]
66    pub(crate) fn create(
67        device: &Device,
68        info: impl Into<DescriptorPoolInfo>,
69    ) -> Result<Self, DriverError> {
70        let device = device.clone();
71        let info = info.into();
72
73        let mut pool_sizes = [vk::DescriptorPoolSize {
74            ty: Default::default(),
75            descriptor_count: 0,
76        }; 12];
77        let mut pool_size_count = 0;
78
79        if info.acceleration_structure_count > 0 {
80            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
81                ty: vk::DescriptorType::ACCELERATION_STRUCTURE_KHR,
82                descriptor_count: info.acceleration_structure_count,
83            };
84            pool_size_count += 1;
85        }
86
87        if info.combined_image_sampler_count > 0 {
88            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
89                ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
90                descriptor_count: info.combined_image_sampler_count,
91            };
92            pool_size_count += 1;
93        }
94
95        if info.input_attachment_count > 0 {
96            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
97                ty: vk::DescriptorType::INPUT_ATTACHMENT,
98                descriptor_count: info.input_attachment_count,
99            };
100            pool_size_count += 1;
101        }
102
103        if info.sampled_image_count > 0 {
104            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
105                ty: vk::DescriptorType::SAMPLED_IMAGE,
106                descriptor_count: info.sampled_image_count,
107            };
108            pool_size_count += 1;
109        }
110
111        if info.sampler_count > 0 {
112            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
113                ty: vk::DescriptorType::SAMPLER,
114                descriptor_count: info.sampler_count,
115            };
116            pool_size_count += 1;
117        }
118
119        if info.storage_buffer_count > 0 {
120            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
121                ty: vk::DescriptorType::STORAGE_BUFFER,
122                descriptor_count: info.storage_buffer_count,
123            };
124            pool_size_count += 1;
125        }
126
127        if info.storage_buffer_dynamic_count > 0 {
128            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
129                ty: vk::DescriptorType::STORAGE_BUFFER_DYNAMIC,
130                descriptor_count: info.storage_buffer_dynamic_count,
131            };
132            pool_size_count += 1;
133        }
134
135        if info.storage_image_count > 0 {
136            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
137                ty: vk::DescriptorType::STORAGE_IMAGE,
138                descriptor_count: info.storage_image_count,
139            };
140            pool_size_count += 1;
141        }
142
143        if info.storage_texel_buffer_count > 0 {
144            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
145                ty: vk::DescriptorType::STORAGE_TEXEL_BUFFER,
146                descriptor_count: info.storage_texel_buffer_count,
147            };
148            pool_size_count += 1;
149        }
150
151        if info.uniform_buffer_count > 0 {
152            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
153                ty: vk::DescriptorType::UNIFORM_BUFFER,
154                descriptor_count: info.uniform_buffer_count,
155            };
156            pool_size_count += 1;
157        }
158
159        if info.uniform_buffer_dynamic_count > 0 {
160            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
161                ty: vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC,
162                descriptor_count: info.uniform_buffer_dynamic_count,
163            };
164            pool_size_count += 1;
165        }
166
167        if info.uniform_texel_buffer_count > 0 {
168            pool_sizes[pool_size_count] = vk::DescriptorPoolSize {
169                ty: vk::DescriptorType::UNIFORM_TEXEL_BUFFER,
170                descriptor_count: info.uniform_texel_buffer_count,
171            };
172            pool_size_count += 1;
173        }
174
175        let handle = unsafe {
176            device.create_descriptor_pool(
177                &vk::DescriptorPoolCreateInfo::default()
178                    .flags(vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET)
179                    .max_sets(info.max_sets)
180                    .pool_sizes(&pool_sizes[0..pool_size_count]),
181                None,
182            )
183        }
184        .map_err(|err| {
185            warn!("unable to create descriptor pool: {err}");
186
187            match err {
188                vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
189                    DriverError::OutOfMemory
190                }
191                _ => DriverError::Unsupported,
192            }
193        })?;
194
195        Ok(Self {
196            device,
197            handle,
198            info,
199        })
200    }
201
202    pub(crate) fn allocate_descriptor_set(
203        this: &Self,
204        layout: &DescriptorSetLayout,
205    ) -> Result<RawDescriptorSet, DriverError> {
206        Ok(Self::allocate_descriptor_sets(this, layout, 1)?
207            .next()
208            .expect("missing descriptor set"))
209    }
210
211    #[profiling::function]
212    pub(crate) fn allocate_descriptor_sets<'a>(
213        &'a self,
214        layout: &DescriptorSetLayout,
215        count: u32,
216    ) -> Result<impl Iterator<Item = RawDescriptorSet> + 'a, DriverError> {
217        let layout_handles = vec![layout.handle(); count as usize];
218        let create_info = vk::DescriptorSetAllocateInfo::default()
219            .descriptor_pool(self.handle)
220            .set_layouts(&layout_handles);
221
222        Ok(unsafe {
223            self.device
224                .allocate_descriptor_sets(&create_info)
225                .map_err(|err| {
226                    use {DriverError::*, vk::Result as vk};
227
228                    warn!("unable to allocate descriptor sets: {err}");
229
230                    match err {
231                        e if e == vk::ERROR_FRAGMENTED_POOL => InvalidData,
232                        e if e == vk::ERROR_OUT_OF_DEVICE_MEMORY => OutOfMemory,
233                        e if e == vk::ERROR_OUT_OF_HOST_MEMORY => OutOfMemory,
234                        e if e == vk::ERROR_OUT_OF_POOL_MEMORY => OutOfMemory,
235                        _ => Unsupported,
236                    }
237                })?
238                .into_iter()
239                .map(move |descriptor_set| RawDescriptorSet {
240                    descriptor_pool: self.handle,
241                    descriptor_set,
242                    device: self.device.clone(),
243                })
244        })
245    }
246}
247
248impl Drop for DescriptorPool {
249    #[profiling::function]
250    fn drop(&mut self) {
251        if panicking() {
252            return;
253        }
254
255        unsafe {
256            self.device.destroy_descriptor_pool(self.handle, None);
257        }
258    }
259}
260
261/// Descriptor counts and limits used to create a [`DescriptorPool`].
262///
263/// See [`VkDescriptorPoolCreateInfo`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkDescriptorPoolCreateInfo.html)
264/// and [`VkDescriptorPoolSize`](https://registry.khronos.org/vulkan/specs/latest/man/html/VkDescriptorPoolSize.html).
265#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
266pub(crate) struct DescriptorPoolInfo {
267    pub(crate) acceleration_structure_count: u32,
268    pub(crate) combined_image_sampler_count: u32,
269    pub(crate) input_attachment_count: u32,
270    pub(crate) max_sets: u32,
271    pub(crate) sampled_image_count: u32,
272    pub(crate) sampler_count: u32,
273    pub(crate) storage_buffer_count: u32,
274    pub(crate) storage_buffer_dynamic_count: u32,
275    pub(crate) storage_image_count: u32,
276    pub(crate) storage_texel_buffer_count: u32,
277    pub(crate) uniform_buffer_count: u32,
278    pub(crate) uniform_buffer_dynamic_count: u32,
279    pub(crate) uniform_texel_buffer_count: u32,
280}
281
282impl DescriptorPoolInfo {
283    fn for_layout(layout: &DescriptorSetLayout) -> Result<Self, DriverError> {
284        let mut info = Self {
285            max_sets: 1,
286            ..Default::default()
287        };
288
289        for binding in &layout.info().bindings {
290            let count = binding.descriptor_count;
291            let destination = match binding.descriptor_type {
292                vk::DescriptorType::ACCELERATION_STRUCTURE_KHR => {
293                    &mut info.acceleration_structure_count
294                }
295                vk::DescriptorType::COMBINED_IMAGE_SAMPLER => {
296                    &mut info.combined_image_sampler_count
297                }
298                vk::DescriptorType::INPUT_ATTACHMENT => &mut info.input_attachment_count,
299                vk::DescriptorType::SAMPLED_IMAGE => &mut info.sampled_image_count,
300                vk::DescriptorType::SAMPLER => &mut info.sampler_count,
301                vk::DescriptorType::STORAGE_BUFFER => &mut info.storage_buffer_count,
302                vk::DescriptorType::STORAGE_BUFFER_DYNAMIC => {
303                    &mut info.storage_buffer_dynamic_count
304                }
305                vk::DescriptorType::STORAGE_IMAGE => &mut info.storage_image_count,
306                vk::DescriptorType::STORAGE_TEXEL_BUFFER => &mut info.storage_texel_buffer_count,
307                vk::DescriptorType::UNIFORM_BUFFER => &mut info.uniform_buffer_count,
308                vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC => {
309                    &mut info.uniform_buffer_dynamic_count
310                }
311                vk::DescriptorType::UNIFORM_TEXEL_BUFFER => &mut info.uniform_texel_buffer_count,
312                _ => {
313                    warn!(
314                        "unsupported descriptor type {:?} in descriptor set layout",
315                        binding.descriptor_type
316                    );
317                    return Err(DriverError::Unsupported);
318                }
319            };
320            *destination = destination
321                .checked_add(count)
322                .ok_or(DriverError::InvalidData)?;
323        }
324
325        Ok(info)
326    }
327}
328
329/// An immutable, explicitly populated Vulkan descriptor set.
330///
331/// The set owns its descriptor pool and every resource referenced by its writes. Cloning this value
332/// shares the same allocation. To change descriptor contents, allocate a new set with
333/// [`Self::alloc_and_update`].
334#[derive(Clone)]
335pub struct DescriptorSet {
336    inner: Arc<DescriptorSetInner>,
337}
338
339impl DescriptorSet {
340    /// Allocates one descriptor set and applies all supplied writes and copies.
341    ///
342    /// `pipeline` supplies the reflected layout selected by [`DescriptorSetInfo::set`]. A single
343    /// [`DescriptorSetUpdateInfo`] or any owned collection of updates may be passed.
344    /// Writes are applied before copies, matching `vkUpdateDescriptorSets` ordering.
345    ///
346    /// Input attachments, texel buffers, and dynamic buffer descriptors are rejected because they
347    /// require render-pass-specific layouts, owned buffer views, or dynamic bind offsets.
348    #[profiling::function]
349    pub fn alloc_and_update<P, I>(
350        pipeline: &P,
351        info: impl Into<DescriptorSetInfo>,
352        updates: I,
353    ) -> Result<Self, DriverError>
354    where
355        P: DescriptorSetPipeline + ?Sized,
356        I: IntoIterator<Item = DescriptorSetUpdateInfo>,
357    {
358        let info = info.into();
359        let pipeline_info = descriptor_set_private::Sealed::descriptor_info(pipeline);
360        let device = descriptor_set_private::Sealed::device(pipeline);
361        let layout = pipeline_info
362            .layouts
363            .get(&info.set)
364            .ok_or_else(|| {
365                warn!("pipeline descriptor set {} does not exist", info.set);
366                DriverError::InvalidData
367            })?
368            .clone();
369        Self::validate_layout(&layout)?;
370        let updates = updates.into_iter().collect::<Vec<_>>();
371        let mut writes = Vec::with_capacity(updates.len());
372        let mut copies = Vec::with_capacity(updates.len());
373
374        for update in updates {
375            let destination_info = Self::validate_binding(&layout, update.destination, 1)?;
376            let descriptor_type = destination_info.descriptor_type;
377
378            match update.update {
379                DescriptorSetUpdate::AccelerationStructure(resource) => {
380                    if descriptor_type != vk::DescriptorType::ACCELERATION_STRUCTURE_KHR
381                        || !Device::is_same(device, &resource.buffer.device)
382                        || !matches!(
383                            resource.info.acceleration_structure_type,
384                            vk::AccelerationStructureTypeKHR::GENERIC
385                                | vk::AccelerationStructureTypeKHR::TOP_LEVEL
386                        )
387                    {
388                        warn!("invalid acceleration structure descriptor write");
389                        return Err(DriverError::InvalidData);
390                    }
391
392                    writes.push(PreparedWrite::AccelerationStructure {
393                        destination: update.destination,
394                        descriptor_type,
395                        resource,
396                    });
397                }
398                DescriptorSetUpdate::Buffer { buffer, range } => {
399                    let (required_usage, required_alignment, max_range) = match descriptor_type {
400                        vk::DescriptorType::STORAGE_BUFFER => (
401                            vk::BufferUsageFlags::STORAGE_BUFFER,
402                            device
403                                .physical
404                                .properties_v1_0
405                                .limits
406                                .min_storage_buffer_offset_alignment,
407                            vk::DeviceSize::from(
408                                device
409                                    .physical
410                                    .properties_v1_0
411                                    .limits
412                                    .max_storage_buffer_range,
413                            ),
414                        ),
415                        vk::DescriptorType::UNIFORM_BUFFER => (
416                            vk::BufferUsageFlags::UNIFORM_BUFFER,
417                            device
418                                .physical
419                                .properties_v1_0
420                                .limits
421                                .min_uniform_buffer_offset_alignment,
422                            vk::DeviceSize::from(
423                                device
424                                    .physical
425                                    .properties_v1_0
426                                    .limits
427                                    .max_uniform_buffer_range,
428                            ),
429                        ),
430                        _ => {
431                            warn!("invalid buffer descriptor type {descriptor_type:?}");
432                            return Err(DriverError::InvalidData);
433                        }
434                    };
435                    let range_size = if range.end == vk::WHOLE_SIZE {
436                        buffer.info.size.saturating_sub(range.start)
437                    } else {
438                        range.end.saturating_sub(range.start)
439                    };
440
441                    if !Device::is_same(device, &buffer.device)
442                        || !buffer.info.usage.contains(required_usage)
443                        || range.start >= buffer.info.size
444                        || range.end != vk::WHOLE_SIZE
445                            && (range.end <= range.start || range.end > buffer.info.size)
446                        || required_alignment > 1 && range.start % required_alignment != 0
447                        || range_size == 0
448                        || range_size > max_range
449                    {
450                        warn!("invalid buffer descriptor write");
451                        return Err(DriverError::InvalidData);
452                    }
453
454                    writes.push(PreparedWrite::Buffer {
455                        destination: update.destination,
456                        descriptor_type,
457                        resource: buffer,
458                        range,
459                    });
460                }
461                DescriptorSetUpdate::Copy {
462                    descriptor_count,
463                    source,
464                    source_binding,
465                } => {
466                    let destination_info =
467                        Self::validate_binding(&layout, update.destination, descriptor_count)?;
468                    let source_info = Self::validate_binding(
469                        &source.inner.layout,
470                        source_binding,
471                        descriptor_count,
472                    )?;
473
474                    if !Device::is_same(device, source.device())
475                        || source_info.descriptor_type != destination_info.descriptor_type
476                        || destination_info.descriptor_type == vk::DescriptorType::SAMPLER
477                            && destination_info.immutable_sampler.is_some()
478                    {
479                        warn!("invalid descriptor copy");
480                        return Err(DriverError::InvalidData);
481                    }
482
483                    copies.push(PreparedCopy {
484                        descriptor_count,
485                        destination: update.destination,
486                        source,
487                        source_binding,
488                    });
489                }
490                DescriptorSetUpdate::Image { image, view } => {
491                    let image_layout = Self::image_layout(descriptor_type).ok_or_else(|| {
492                        warn!("invalid image descriptor write");
493                        DriverError::InvalidData
494                    })?;
495                    let required_usage = match descriptor_type {
496                        vk::DescriptorType::COMBINED_IMAGE_SAMPLER
497                        | vk::DescriptorType::SAMPLED_IMAGE => vk::ImageUsageFlags::SAMPLED,
498                        vk::DescriptorType::STORAGE_IMAGE => vk::ImageUsageFlags::STORAGE,
499                        _ => {
500                            warn!("invalid image descriptor type {descriptor_type:?}");
501                            return Err(DriverError::InvalidData);
502                        }
503                    };
504                    let image_aspects = format_aspect_mask(image.info.format);
505                    let mip_level_count = if view.mip_level_count == vk::REMAINING_MIP_LEVELS {
506                        image
507                            .info
508                            .mip_level_count
509                            .saturating_sub(view.base_mip_level)
510                    } else {
511                        view.mip_level_count
512                    };
513                    let array_layer_count = if view.array_layer_count == vk::REMAINING_ARRAY_LAYERS
514                    {
515                        image
516                            .info
517                            .array_layer_count
518                            .saturating_sub(view.base_array_layer)
519                    } else {
520                        view.array_layer_count
521                    };
522
523                    if !Device::is_same(device, &image.device)
524                        || !image.info.usage.contains(required_usage)
525                        || view.format == vk::Format::UNDEFINED
526                        || view.aspect_mask.as_raw().count_ones() != 1
527                        || !image_aspects.contains(view.aspect_mask)
528                        || view.base_mip_level >= image.info.mip_level_count
529                        || mip_level_count == 0
530                        || mip_level_count > image.info.mip_level_count - view.base_mip_level
531                        || view.base_array_layer >= image.info.array_layer_count
532                        || array_layer_count == 0
533                        || array_layer_count > image.info.array_layer_count - view.base_array_layer
534                        || view.format != image.info.format
535                            && !image
536                                .info
537                                .flags
538                                .contains(vk::ImageCreateFlags::MUTABLE_FORMAT)
539                    {
540                        warn!("invalid image descriptor write");
541                        return Err(DriverError::InvalidData);
542                    }
543
544                    let image_view = image.view(view)?;
545                    writes.push(PreparedWrite::Image {
546                        destination: update.destination,
547                        descriptor_type,
548                        image_layout,
549                        image_view,
550                        resource: image,
551                    });
552                }
553            }
554        }
555
556        let descriptor_pool =
557            DescriptorPool::create(device, DescriptorPoolInfo::for_layout(&layout)?)?;
558        let descriptor_set = DescriptorPool::allocate_descriptor_set(&descriptor_pool, &layout)?;
559        let handle = *descriptor_set;
560
561        for write in &writes {
562            unsafe {
563                match write {
564                    PreparedWrite::AccelerationStructure {
565                        destination,
566                        descriptor_type,
567                        resource,
568                    } => {
569                        let acceleration_structures = [resource.handle];
570                        let mut acceleration_structure_info =
571                            vk::WriteDescriptorSetAccelerationStructureKHR::default()
572                                .acceleration_structures(&acceleration_structures);
573                        let write = vk::WriteDescriptorSet::default()
574                            .dst_set(handle)
575                            .dst_binding(destination.binding)
576                            .dst_array_element(destination.array_element)
577                            .descriptor_type(*descriptor_type)
578                            .descriptor_count(1)
579                            .push_next(&mut acceleration_structure_info);
580                        device.update_descriptor_sets(slice::from_ref(&write), &[]);
581                    }
582                    PreparedWrite::Buffer {
583                        destination,
584                        descriptor_type,
585                        resource,
586                        range,
587                    } => {
588                        let range_size = if range.end == vk::WHOLE_SIZE {
589                            vk::WHOLE_SIZE
590                        } else {
591                            range.end - range.start
592                        };
593                        let buffer_info = vk::DescriptorBufferInfo::default()
594                            .buffer(resource.handle)
595                            .offset(range.start)
596                            .range(range_size);
597                        let write = vk::WriteDescriptorSet::default()
598                            .dst_set(handle)
599                            .dst_binding(destination.binding)
600                            .dst_array_element(destination.array_element)
601                            .descriptor_type(*descriptor_type)
602                            .buffer_info(slice::from_ref(&buffer_info));
603                        device.update_descriptor_sets(slice::from_ref(&write), &[]);
604                    }
605                    PreparedWrite::Image {
606                        destination,
607                        descriptor_type,
608                        image_layout,
609                        image_view,
610                        ..
611                    } => {
612                        let image_info = vk::DescriptorImageInfo::default()
613                            .image_layout(*image_layout)
614                            .image_view(*image_view);
615                        let write = vk::WriteDescriptorSet::default()
616                            .dst_set(handle)
617                            .dst_binding(destination.binding)
618                            .dst_array_element(destination.array_element)
619                            .descriptor_type(*descriptor_type)
620                            .image_info(slice::from_ref(&image_info));
621                        device.update_descriptor_sets(slice::from_ref(&write), &[]);
622                    }
623                }
624            }
625        }
626
627        if !copies.is_empty() {
628            let copy_infos = copies
629                .iter()
630                .map(|copy| {
631                    vk::CopyDescriptorSet::default()
632                        .src_set(copy.source.handle())
633                        .src_binding(copy.source_binding.binding)
634                        .src_array_element(copy.source_binding.array_element)
635                        .dst_set(handle)
636                        .dst_binding(copy.destination.binding)
637                        .dst_array_element(copy.destination.array_element)
638                        .descriptor_count(copy.descriptor_count)
639                })
640                .collect::<Vec<_>>();
641
642            unsafe {
643                device.update_descriptor_sets(&[], &copy_infos);
644            }
645        }
646
647        let resources = writes
648            .into_iter()
649            .map(|write| match write {
650                PreparedWrite::AccelerationStructure { resource, .. } => {
651                    DescriptorSetResource::AccelerationStructure(resource)
652                }
653                PreparedWrite::Buffer { resource, .. } => DescriptorSetResource::Buffer(resource),
654                PreparedWrite::Image { resource, .. } => DescriptorSetResource::Image(resource),
655            })
656            .chain(
657                copies
658                    .into_iter()
659                    .map(|copy| DescriptorSetResource::DescriptorSet(copy.source)),
660            )
661            .collect();
662
663        Ok(Self {
664            inner: Arc::new(DescriptorSetInner {
665                descriptor_set,
666                _descriptor_pool: descriptor_pool,
667                info,
668                layout,
669                _resources: resources,
670            }),
671        })
672    }
673
674    /// The device which owns this descriptor set.
675    pub fn device(&self) -> &Device {
676        self.inner.layout.device()
677    }
678
679    /// The native Vulkan descriptor set handle.
680    pub fn handle(&self) -> vk::DescriptorSet {
681        *self.inner.descriptor_set
682    }
683
684    /// The information used to allocate this descriptor set.
685    pub fn info(&self) -> DescriptorSetInfo {
686        self.inner.info
687    }
688
689    /// Sets the debugging name assigned to this descriptor set.
690    pub fn set_debug_name(&self, name: impl AsRef<str>) {
691        Device::try_set_debug_utils_object_name(self.device(), self.handle(), &name);
692        Device::try_set_private_data_object_name(
693            self.device(),
694            vk::ObjectType::DESCRIPTOR_SET,
695            self.handle(),
696            &name,
697        );
698    }
699
700    /// Sets the debugging name assigned to this descriptor set.
701    pub fn with_debug_name(self, name: impl AsRef<str>) -> Self {
702        self.set_debug_name(name);
703
704        self
705    }
706
707    pub(crate) fn is_compatible(&self, set: u32, layout: &DescriptorSetLayout) -> bool {
708        self.inner.info.set == set && self.inner.layout.is_same(layout)
709    }
710
711    fn validate_layout(layout: &DescriptorSetLayout) -> Result<(), DriverError> {
712        for binding in &layout.info().bindings {
713            if matches!(
714                binding.descriptor_type,
715                vk::DescriptorType::INPUT_ATTACHMENT
716                    | vk::DescriptorType::STORAGE_BUFFER_DYNAMIC
717                    | vk::DescriptorType::STORAGE_TEXEL_BUFFER
718                    | vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC
719                    | vk::DescriptorType::UNIFORM_TEXEL_BUFFER
720            ) {
721                warn!(
722                    "descriptor set layout contains unsupported descriptor type {:?}",
723                    binding.descriptor_type
724                );
725                return Err(DriverError::Unsupported);
726            }
727        }
728
729        Ok(())
730    }
731
732    fn image_layout(descriptor_type: vk::DescriptorType) -> Option<vk::ImageLayout> {
733        match descriptor_type {
734            vk::DescriptorType::COMBINED_IMAGE_SAMPLER | vk::DescriptorType::SAMPLED_IMAGE => {
735                Some(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
736            }
737            vk::DescriptorType::STORAGE_IMAGE => Some(vk::ImageLayout::GENERAL),
738            _ => None,
739        }
740    }
741
742    fn validate_binding(
743        layout: &DescriptorSetLayout,
744        binding: DescriptorSetBinding,
745        descriptor_count: u32,
746    ) -> Result<&super::descriptor_set_layout::DescriptorSetLayoutBindingInfo, DriverError> {
747        let binding_info = layout.info().binding(binding.binding).ok_or_else(|| {
748            warn!("descriptor binding {} does not exist", binding.binding);
749            DriverError::InvalidData
750        })?;
751        let end = binding
752            .array_element
753            .checked_add(descriptor_count)
754            .ok_or(DriverError::InvalidData)?;
755
756        if descriptor_count == 0 || end > binding_info.descriptor_count {
757            warn!(
758                "descriptor binding {} array range {}..{} is out of bounds",
759                binding.binding, binding.array_element, end
760            );
761            return Err(DriverError::InvalidData);
762        }
763
764        Ok(binding_info)
765    }
766}
767
768impl Debug for DescriptorSet {
769    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
770        let mut result = f.debug_struct(stringify!(DescriptorSet));
771
772        if let Some(debug_name) = &Device::private_data_object_name(
773            self.device(),
774            vk::ObjectType::DESCRIPTOR_SET,
775            self.handle(),
776        ) {
777            result.field("debug_name", debug_name);
778        }
779
780        result
781            .field("handle", &self.handle())
782            .field("info", &self.info())
783            .finish()
784    }
785}
786
787/// Identifies one binding and array element within a descriptor set.
788#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
789pub struct DescriptorSetBinding {
790    /// The descriptor binding index.
791    pub binding: u32,
792
793    /// The array element within `binding`.
794    pub array_element: u32,
795}
796
797impl From<u32> for DescriptorSetBinding {
798    fn from(binding: u32) -> Self {
799        Self {
800            binding,
801            array_element: 0,
802        }
803    }
804}
805
806impl From<(u32, u32)> for DescriptorSetBinding {
807    fn from((binding, array_element): (u32, u32)) -> Self {
808        Self {
809            binding,
810            array_element,
811        }
812    }
813}
814
815impl From<(u32, [u32; 1])> for DescriptorSetBinding {
816    fn from((binding, [array_element]): (u32, [u32; 1])) -> Self {
817        Self {
818            binding,
819            array_element,
820        }
821    }
822}
823
824/// Information selecting the pipeline layout used to allocate a [`DescriptorSet`].
825///
826/// Descriptor contents are supplied separately through [`DescriptorSetUpdateInfo`] values.
827#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
828pub struct DescriptorSetInfo {
829    /// The pipeline descriptor set index whose layout will be used.
830    pub set: u32,
831}
832
833impl DescriptorSetInfo {
834    /// Creates a default descriptor set information builder.
835    pub const fn builder() -> DescriptorSetInfoBuilder {
836        DescriptorSetInfoBuilder { set: 0 }
837    }
838
839    /// Converts this information into a builder.
840    pub const fn into_builder(self) -> DescriptorSetInfoBuilder {
841        DescriptorSetInfoBuilder { set: self.set }
842    }
843}
844
845impl From<DescriptorSetInfoBuilder> for DescriptorSetInfo {
846    fn from(info: DescriptorSetInfoBuilder) -> Self {
847        info.build()
848    }
849}
850
851/// Builder for [`DescriptorSetInfo`].
852#[derive(Clone, Copy, Debug, Default)]
853pub struct DescriptorSetInfoBuilder {
854    set: u32,
855}
856
857impl DescriptorSetInfoBuilder {
858    /// Selects the pipeline descriptor set index whose layout will be used.
859    pub const fn set(mut self, set: u32) -> Self {
860        self.set = set;
861        self
862    }
863
864    /// Builds descriptor set information.
865    pub const fn build(self) -> DescriptorSetInfo {
866        DescriptorSetInfo { set: self.set }
867    }
868}
869
870struct DescriptorSetInner {
871    descriptor_set: RawDescriptorSet,
872    _descriptor_pool: DescriptorPool,
873    info: DescriptorSetInfo,
874    layout: DescriptorSetLayout,
875    _resources: Box<[DescriptorSetResource]>,
876}
877
878impl Drop for DescriptorSetInner {
879    fn drop(&mut self) {
880        if panicking() {
881            return;
882        }
883
884        Device::try_clear_private_data_object_name(
885            self.layout.device(),
886            vk::ObjectType::DESCRIPTOR_SET,
887            *self.descriptor_set,
888        );
889    }
890}
891
892#[allow(dead_code)]
893enum DescriptorSetResource {
894    AccelerationStructure(Arc<AccelerationStructure>),
895    Buffer(Arc<Buffer>),
896    DescriptorSet(DescriptorSet),
897    Image(Arc<Image>),
898}
899
900#[derive(Clone, Debug)]
901enum DescriptorSetUpdate {
902    AccelerationStructure(Arc<AccelerationStructure>),
903    Buffer {
904        buffer: Arc<Buffer>,
905        range: BufferSubresourceRange,
906    },
907    Copy {
908        descriptor_count: u32,
909        source: DescriptorSet,
910        source_binding: DescriptorSetBinding,
911    },
912    Image {
913        image: Arc<Image>,
914        view: ImageViewInfo,
915    },
916}
917
918/// One write or copy performed while allocating a [`DescriptorSet`].
919#[derive(Clone, Debug)]
920pub struct DescriptorSetUpdateInfo {
921    destination: DescriptorSetBinding,
922    update: DescriptorSetUpdate,
923}
924
925impl DescriptorSetUpdateInfo {
926    /// Writes an acceleration structure descriptor.
927    pub fn acceleration_structure(
928        destination: impl Into<DescriptorSetBinding>,
929        acceleration_structure: &Arc<AccelerationStructure>,
930    ) -> Self {
931        Self {
932            destination: destination.into(),
933            update: DescriptorSetUpdate::AccelerationStructure(acceleration_structure.clone()),
934        }
935    }
936
937    /// Writes a whole-buffer descriptor.
938    pub fn buffer(destination: impl Into<DescriptorSetBinding>, buffer: &Arc<Buffer>) -> Self {
939        Self::buffer_range(destination, buffer, buffer.info)
940    }
941
942    /// Writes a descriptor for a range of a buffer.
943    pub fn buffer_range(
944        destination: impl Into<DescriptorSetBinding>,
945        buffer: &Arc<Buffer>,
946        range: impl Into<BufferSubresourceRange>,
947    ) -> Self {
948        Self {
949            destination: destination.into(),
950            update: DescriptorSetUpdate::Buffer {
951                buffer: buffer.clone(),
952                range: range.into(),
953            },
954        }
955    }
956
957    /// Copies one descriptor from an existing descriptor set.
958    pub fn copy(
959        source: &DescriptorSet,
960        source_binding: impl Into<DescriptorSetBinding>,
961        destination: impl Into<DescriptorSetBinding>,
962    ) -> Self {
963        Self::copy_many(source, source_binding, destination, 1)
964    }
965
966    /// Copies consecutive descriptors from an existing descriptor set.
967    ///
968    /// The source and destination ranges must each remain within one reflected binding.
969    pub fn copy_many(
970        source: &DescriptorSet,
971        source_binding: impl Into<DescriptorSetBinding>,
972        destination: impl Into<DescriptorSetBinding>,
973        descriptor_count: u32,
974    ) -> Self {
975        Self {
976            destination: destination.into(),
977            update: DescriptorSetUpdate::Copy {
978                descriptor_count,
979                source: source.clone(),
980                source_binding: source_binding.into(),
981            },
982        }
983    }
984
985    /// Writes a descriptor using the image's default view.
986    ///
987    /// Depth/stencil formats require [`Self::image_view`] with exactly one selected aspect.
988    pub fn image(destination: impl Into<DescriptorSetBinding>, image: &Arc<Image>) -> Self {
989        Self::image_view(destination, image, image.info)
990    }
991
992    /// Writes a descriptor using a specific image view.
993    pub fn image_view(
994        destination: impl Into<DescriptorSetBinding>,
995        image: &Arc<Image>,
996        view: impl Into<ImageViewInfo>,
997    ) -> Self {
998        Self {
999            destination: destination.into(),
1000            update: DescriptorSetUpdate::Image {
1001                image: image.clone(),
1002                view: view.into(),
1003            },
1004        }
1005    }
1006}
1007
1008impl IntoIterator for DescriptorSetUpdateInfo {
1009    type Item = Self;
1010    type IntoIter = iter::Once<Self>;
1011
1012    fn into_iter(self) -> Self::IntoIter {
1013        iter::once(self)
1014    }
1015}
1016
1017impl IntoIterator for &DescriptorSetUpdateInfo {
1018    type Item = DescriptorSetUpdateInfo;
1019    type IntoIter = iter::Once<Self::Item>;
1020
1021    fn into_iter(self) -> Self::IntoIter {
1022        iter::once(self.clone())
1023    }
1024}
1025
1026/// A compute, graphics, or ray tracing pipeline that can provide a descriptor set layout.
1027#[doc(hidden)]
1028pub trait DescriptorSetPipeline: descriptor_set_private::Sealed {}
1029
1030macro_rules! descriptor_set_pipeline {
1031    ($pipeline:ty) => {
1032        #[allow(private_interfaces)]
1033        impl descriptor_set_private::Sealed for $pipeline {
1034            fn descriptor_info(&self) -> &PipelineDescriptorInfo {
1035                &self.inner.descriptor_info
1036            }
1037
1038            fn device(&self) -> &Device {
1039                self.device()
1040            }
1041        }
1042
1043        impl DescriptorSetPipeline for $pipeline {}
1044    };
1045}
1046
1047descriptor_set_pipeline!(ComputePipeline);
1048descriptor_set_pipeline!(GraphicsPipeline);
1049descriptor_set_pipeline!(RayTracingPipeline);
1050
1051#[allow(private_interfaces)]
1052mod descriptor_set_private {
1053    use super::{Device, PipelineDescriptorInfo};
1054
1055    pub trait Sealed {
1056        fn descriptor_info(&self) -> &PipelineDescriptorInfo;
1057
1058        fn device(&self) -> &Device;
1059    }
1060}
1061
1062enum PreparedWrite {
1063    AccelerationStructure {
1064        destination: DescriptorSetBinding,
1065        descriptor_type: vk::DescriptorType,
1066        resource: Arc<AccelerationStructure>,
1067    },
1068    Buffer {
1069        destination: DescriptorSetBinding,
1070        descriptor_type: vk::DescriptorType,
1071        resource: Arc<Buffer>,
1072        range: BufferSubresourceRange,
1073    },
1074    Image {
1075        destination: DescriptorSetBinding,
1076        descriptor_type: vk::DescriptorType,
1077        image_layout: vk::ImageLayout,
1078        image_view: vk::ImageView,
1079        resource: Arc<Image>,
1080    },
1081}
1082
1083struct PreparedCopy {
1084    descriptor_count: u32,
1085    destination: DescriptorSetBinding,
1086    source: DescriptorSet,
1087    source_binding: DescriptorSetBinding,
1088}
1089
1090#[derive(Debug)]
1091pub(crate) struct RawDescriptorSet {
1092    descriptor_pool: vk::DescriptorPool,
1093    descriptor_set: vk::DescriptorSet,
1094    device: Device,
1095}
1096
1097impl Deref for RawDescriptorSet {
1098    type Target = vk::DescriptorSet;
1099
1100    fn deref(&self) -> &Self::Target {
1101        &self.descriptor_set
1102    }
1103}
1104
1105impl Drop for RawDescriptorSet {
1106    #[profiling::function]
1107    fn drop(&mut self) {
1108        if panicking() {
1109            return;
1110        }
1111
1112        if let Err(err) = unsafe {
1113            self.device
1114                .free_descriptor_sets(self.descriptor_pool, slice::from_ref(&self.descriptor_set))
1115        } {
1116            warn!("unable to free descriptor set: {err}");
1117        }
1118    }
1119}
1120
1121#[cfg(test)]
1122mod test {
1123    use super::*;
1124
1125    #[test]
1126    fn descriptor_set_binding_conversions() {
1127        assert_eq!(
1128            DescriptorSetBinding::from(3),
1129            DescriptorSetBinding {
1130                binding: 3,
1131                array_element: 0,
1132            }
1133        );
1134        assert_eq!(
1135            DescriptorSetBinding::from((3, [7])),
1136            DescriptorSetBinding {
1137                binding: 3,
1138                array_element: 7,
1139            }
1140        );
1141    }
1142
1143    #[test]
1144    fn descriptor_set_info_builder() {
1145        let info = DescriptorSetInfo::builder().set(2).build();
1146
1147        assert_eq!(info.set, 2);
1148        assert_eq!(info, info.into_builder().build());
1149        assert_eq!(
1150            std::mem::size_of::<DescriptorSetInfo>(),
1151            std::mem::size_of::<u32>()
1152        );
1153    }
1154
1155    #[test]
1156    fn empty_descriptor_set_updates_are_inferred() {
1157        fn update_count(updates: impl IntoIterator<Item = DescriptorSetUpdateInfo>) -> usize {
1158            updates.into_iter().count()
1159        }
1160
1161        assert_eq!(update_count([]), 0);
1162        assert_eq!(update_count(None), 0);
1163    }
1164}