ursus_core/render/resource/
descriptor_binding.rs1use 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}