Skip to main content

ursus_core/render/resource/
descriptor_binding.rs

1use crate::assets::storage::GpuAssetServer;
2use crate::render::gfx::types::{DescriptorSetId, SamplerId};
3use crate::render::resource::desc::ResourceHandle;
4use crate::render::resource::pool::ResourcePool;
5use ash::vk;
6
7#[derive(Debug, Clone, Copy)]
8pub enum FlushReason {
9    InitialAllocation,
10    Resize,
11    LateBinding,
12}
13
14impl std::fmt::Display for FlushReason {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        let s = match self {
17            Self::InitialAllocation => "initial allocation",
18            Self::Resize => "resize",
19            Self::LateBinding => "late binding (pass added after allocate)",
20        };
21        write!(f, "{s}")
22    }
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum DescriptorImageType {
27    CombinedImageSampler(SamplerId),
28    SampledImage,
29}
30
31#[derive(Debug, Clone)]
32pub struct DescriptorBinding {
33    pub resource: ResourceHandle,
34    pub set: DescriptorSetId,
35    pub binding: u32,
36    pub array_element: u32,
37    pub image_type: DescriptorImageType,
38    pub image_layout: vk::ImageLayout,
39}
40
41pub struct DescriptorBindingRegistry {
42    bindings: Vec<DescriptorBinding>,
43    device: ash::Device,
44}
45
46impl DescriptorBindingRegistry {
47    pub fn new(device: ash::Device) -> Self {
48        Self { bindings: Vec::new(), device }
49    }
50
51    pub fn register(&mut self, binding: DescriptorBinding) {
52        self.bindings.push(binding);
53    }
54
55    pub fn flush(&self, pool: &ResourcePool, affected: &[ResourceHandle], gpu: &GpuAssetServer, reason: FlushReason) {
56        let relevant: Vec<&DescriptorBinding> =
57            self.bindings.iter().filter(|b| affected.contains(&b.resource)).collect();
58
59        if relevant.is_empty() {
60            return;
61        }
62
63        let image_infos: Vec<vk::DescriptorImageInfo> = relevant
64            .iter()
65            .map(|b| {
66                let img = pool.image(b.resource);
67                let sampler = match b.image_type {
68                    DescriptorImageType::CombinedImageSampler(s) => gpu.samplers.handle(s),
69                    DescriptorImageType::SampledImage => vk::Sampler::null(),
70                };
71                vk::DescriptorImageInfo::default().image_view(img.view).image_layout(b.image_layout).sampler(sampler)
72            })
73            .collect();
74
75        let writes: Vec<vk::WriteDescriptorSet> = relevant
76            .iter()
77            .zip(image_infos.iter())
78            .map(|(b, info)| {
79                let desc_type = match b.image_type {
80                    DescriptorImageType::CombinedImageSampler(_) => vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
81                    DescriptorImageType::SampledImage => vk::DescriptorType::SAMPLED_IMAGE,
82                };
83                vk::WriteDescriptorSet::default()
84                    .dst_set(gpu.descriptors.handle(b.set))
85                    .dst_binding(b.binding)
86                    .dst_array_element(b.array_element)
87                    .descriptor_type(desc_type)
88                    .image_info(std::slice::from_ref(info))
89            })
90            .collect();
91
92        unsafe { self.device.update_descriptor_sets(&writes, &[]) };
93        log::debug!("DescriptorBindingRegistry: rewrote {} descriptors ({reason})", writes.len());
94    }
95
96    pub fn flush_all(&self, pool: &ResourcePool, gpu: &GpuAssetServer, reason: FlushReason) {
97        let all: Vec<ResourceHandle> = self.bindings.iter().map(|b| b.resource).collect();
98        self.flush(pool, &all, gpu, reason);
99    }
100}