Skip to main content

ursus_core/render/resource/
pool.rs

1use crate::render::gfx::descriptor::ImageUsage;
2use crate::render::gfx::types::Format;
3use crate::render::resource::desc::{ExternalImageDesc, ResourceDesc, ResourceExtent, ResourceHandle, ResourceKind};
4use crate::render::resource::image::{ExternalSlot, ImageRef, ResourceEntry, TransientImage};
5use crate::vulkan::core::debug::set_object_name;
6use crate::vulkan::core::DeviceContext;
7use ash::ext::debug_utils;
8use ash::vk;
9use std::sync::Arc;
10
11pub struct ResourcePool {
12    entries: Vec<ResourceEntry>,
13    device: ash::Device,
14    physical_device: vk::PhysicalDevice,
15    instance: ash::Instance,
16    debug_utils: Option<Arc<debug_utils::Device>>,
17}
18
19impl ResourcePool {
20    pub fn new(
21        device: ash::Device,
22        physical_device: vk::PhysicalDevice,
23        instance: ash::Instance,
24        debug_utils: Option<Arc<debug_utils::Device>>,
25    ) -> Self {
26        Self { entries: Vec::new(), device, physical_device, instance, debug_utils }
27    }
28
29    pub fn register(&mut self, desc: ResourceDesc) -> ResourceHandle {
30        let handle = ResourceHandle(self.entries.len() as u32);
31        self.entries.push(ResourceEntry::Transient { desc, image: Box::new(None) });
32        handle
33    }
34
35    pub fn register_external(&mut self, desc: ExternalImageDesc) -> ResourceHandle {
36        let handle = ResourceHandle(self.entries.len() as u32);
37        self.entries.push(ResourceEntry::External(ExternalSlot {
38            desc,
39            image: vk::Image::null(),
40            view: vk::ImageView::null(),
41            extent: vk::Extent2D::default(),
42        }));
43        handle
44    }
45
46    pub fn register_swapchain_external(&mut self, format: Format) -> ResourceHandle {
47        self.register_external(ExternalImageDesc {
48            name: "swapchain".into(),
49            format: format.to_vk(),
50            kind: ResourceKind::Color,
51            initial_layout: vk::ImageLayout::UNDEFINED,
52            final_layout: vk::ImageLayout::PRESENT_SRC_KHR,
53        })
54    }
55
56    pub fn update_external(
57        &mut self,
58        handle: ResourceHandle,
59        image: vk::Image,
60        view: vk::ImageView,
61        extent: vk::Extent2D,
62    ) {
63        match &mut self.entries[handle.0 as usize] {
64            ResourceEntry::External(slot) => {
65                slot.image = image;
66                slot.view = view;
67                slot.extent = extent;
68            }
69            ResourceEntry::Transient { .. } => {
70                panic!("update_external called for a transient resource {:?}", handle);
71            }
72        }
73    }
74
75    pub fn add_usage(&mut self, handle: ResourceHandle, flags: ImageUsage) {
76        if let ResourceEntry::Transient { desc, .. } = &mut self.entries[handle.0 as usize] {
77            desc.usage |= flags;
78        }
79    }
80
81    pub fn allocate(&mut self, internal: (u32, u32), output: (u32, u32)) -> anyhow::Result<()> {
82        let device = &self.device;
83        let physical_device = self.physical_device;
84        let instance = &self.instance;
85        let debug_utils = &self.debug_utils;
86
87        for entry in &mut self.entries {
88            if let ResourceEntry::Transient { desc, image } = entry {
89                if image.is_none() {
90                    let (w, h) = desc.extent.resolve(internal, output);
91                    let ti = TransientImage::new(DeviceContext { device, physical_device, instance }, desc, w, h)?;
92                    debug_name(debug_utils.as_deref(), &ti, desc);
93                    **image = Some(ti);
94                }
95            }
96        }
97        Ok(())
98    }
99
100    pub fn resize_output(&mut self, internal: (u32, u32), new_output: (u32, u32)) -> anyhow::Result<()> {
101        for entry in &mut self.entries {
102            if let ResourceEntry::Transient { desc, image } = entry {
103                if matches!(desc.extent, ResourceExtent::ScaleOutput(_)) {
104                    **image = None;
105                    let (w, h) = desc.extent.resolve(internal, new_output);
106                    **image = Some(TransientImage::new(
107                        DeviceContext {
108                            device: &self.device,
109                            physical_device: self.physical_device,
110                            instance: &self.instance,
111                        },
112                        desc,
113                        w,
114                        h,
115                    )?);
116                }
117            }
118        }
119        Ok(())
120    }
121
122    pub fn resize_internal(&mut self, new_internal: (u32, u32), output: (u32, u32)) -> anyhow::Result<()> {
123        for entry in &mut self.entries {
124            if let ResourceEntry::Transient { desc, image } = entry {
125                if matches!(desc.extent, ResourceExtent::ScaleInternal(_)) {
126                    **image = None;
127                    let (w, h) = desc.extent.resolve(new_internal, output);
128                    **image = Some(TransientImage::new(
129                        DeviceContext {
130                            device: &self.device,
131                            physical_device: self.physical_device,
132                            instance: &self.instance,
133                        },
134                        desc,
135                        w,
136                        h,
137                    )?);
138                }
139            }
140        }
141        Ok(())
142    }
143
144    pub fn image(&self, handle: ResourceHandle) -> ImageRef<'_> {
145        match &self.entries[handle.0 as usize] {
146            ResourceEntry::Transient { desc, image } => {
147                let ti = (**image)
148                    .as_ref()
149                    .unwrap_or_else(|| panic!("ResourcePool: transient resource '{}' is not allocated", desc.name));
150                ImageRef {
151                    image: ti.image,
152                    view: ti.view,
153                    format: ti.format,
154                    extent: ti.extent,
155                    kind: ti.kind,
156                    name: &ti.name,
157                }
158            }
159            ResourceEntry::External(slot) => ImageRef {
160                image: slot.image,
161                view: slot.view,
162                format: slot.desc.format,
163                extent: slot.extent,
164                kind: slot.desc.kind,
165                name: &slot.desc.name,
166            },
167        }
168    }
169
170    pub fn desc(&self, handle: ResourceHandle) -> ResourceDescRef<'_> {
171        match &self.entries[handle.0 as usize] {
172            ResourceEntry::Transient { desc, .. } => ResourceDescRef::Transient(desc),
173            ResourceEntry::External(slot) => ResourceDescRef::External(&slot.desc),
174        }
175    }
176
177    pub fn external_initial_layout(&self, handle: ResourceHandle) -> Option<vk::ImageLayout> {
178        match &self.entries[handle.0 as usize] {
179            ResourceEntry::External(slot) => Some(slot.desc.initial_layout),
180            _ => None,
181        }
182    }
183
184    pub fn external_final_layout(&self, handle: ResourceHandle) -> Option<vk::ImageLayout> {
185        match &self.entries[handle.0 as usize] {
186            ResourceEntry::External(slot) => Some(slot.desc.final_layout),
187            _ => None,
188        }
189    }
190
191    pub fn internal_handles(&self) -> impl Iterator<Item = ResourceHandle> + '_ {
192        self.entries.iter().enumerate().filter_map(|(i, e)| {
193            if let ResourceEntry::Transient { desc, .. } = e {
194                if matches!(desc.extent, ResourceExtent::ScaleInternal(_)) {
195                    return Some(ResourceHandle(i as u32));
196                }
197            }
198            None
199        })
200    }
201
202    pub fn output_handles(&self) -> impl Iterator<Item = ResourceHandle> + '_ {
203        self.entries.iter().enumerate().filter_map(|(i, e)| {
204            if let ResourceEntry::Transient { desc, .. } = e {
205                if matches!(desc.extent, ResourceExtent::ScaleOutput(_)) {
206                    return Some(ResourceHandle(i as u32));
207                }
208            }
209            None
210        })
211    }
212
213    pub fn external_handles(&self) -> impl Iterator<Item = ResourceHandle> + '_ {
214        self.entries.iter().enumerate().filter_map(|(i, e)| {
215            if matches!(e, ResourceEntry::External(_)) {
216                Some(ResourceHandle(i as u32))
217            } else {
218                None
219            }
220        })
221    }
222
223    pub fn handle_by_name(&self, name: &str) -> ResourceHandle {
224        self.entries
225            .iter()
226            .position(|e| match e {
227                ResourceEntry::Transient { desc, .. } => desc.name == name,
228                ResourceEntry::External(slot) => slot.desc.name == name,
229            })
230            .map(|i| ResourceHandle(i as u32))
231            .expect("resource not found")
232    }
233}
234
235pub enum ResourceDescRef<'a> {
236    Transient(&'a ResourceDesc),
237    External(&'a ExternalImageDesc),
238}
239
240fn debug_name(debug_utils: Option<&debug_utils::Device>, ti: &TransientImage, desc: &ResourceDesc) {
241    if let Some(du) = debug_utils {
242        set_object_name(du, ti.image, &desc.name);
243        set_object_name(du, ti.view, &format!("{}_view", desc.name));
244        set_object_name(du, ti.memory, &format!("{}_memory", desc.name));
245    }
246}