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