1use crate::HalError;
7use ash::vk;
8use std::sync::Mutex;
9
10pub const DEFAULT_MAX_STORAGE_BUFFERS: u32 = 16384;
11pub const DEFAULT_MAX_TEXTURES: u32 = 16384;
12pub const DEFAULT_MAX_SAMPLERS: u32 = 256;
13pub const DEFAULT_MAX_STORAGE_IMAGES: u32 = 16384;
14pub const PUSH_CONSTANT_SIZE: u32 = 128;
15
16pub struct VulkanBindlessHeap {
17 pub descriptor_set_layout: vk::DescriptorSetLayout,
18 pub descriptor_pool: vk::DescriptorPool,
19 pub descriptor_set: vk::DescriptorSet,
20 pub pipeline_layout: vk::PipelineLayout,
21 pub max_buffers: u32,
22 pub max_textures: u32,
23 pub max_samplers: u32,
24 pub max_storage_images: u32,
25 buffer_slots: Mutex<SlotPool>,
26 texture_slots: Mutex<SlotPool>,
27 sampler_slots: Mutex<SlotPool>,
28 storage_image_slots: Mutex<SlotPool>,
29}
30
31struct SlotPool {
32 free: Vec<u32>,
33 next: u32,
34}
35
36impl VulkanBindlessHeap {
37 pub fn new(
38 device: &ash::Device,
39 max_buffers: u32,
40 max_textures: u32,
41 max_samplers: u32,
42 max_storage_images: u32,
43 ) -> Result<Self, HalError> {
44 let bindings = [
50 vk::DescriptorSetLayoutBinding::default()
51 .binding(0)
52 .descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
53 .descriptor_count(max_buffers)
54 .stage_flags(vk::ShaderStageFlags::ALL),
55 vk::DescriptorSetLayoutBinding::default()
56 .binding(1)
57 .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE)
58 .descriptor_count(max_textures)
59 .stage_flags(vk::ShaderStageFlags::ALL),
60 vk::DescriptorSetLayoutBinding::default()
61 .binding(2)
62 .descriptor_type(vk::DescriptorType::SAMPLER)
63 .descriptor_count(max_samplers)
64 .stage_flags(vk::ShaderStageFlags::ALL),
65 vk::DescriptorSetLayoutBinding::default()
66 .binding(3)
67 .descriptor_type(vk::DescriptorType::STORAGE_IMAGE)
68 .descriptor_count(max_storage_images)
69 .stage_flags(vk::ShaderStageFlags::ALL),
70 ];
71
72 let binding_flags = [
73 vk::DescriptorBindingFlags::PARTIALLY_BOUND
74 | vk::DescriptorBindingFlags::UPDATE_AFTER_BIND,
75 vk::DescriptorBindingFlags::PARTIALLY_BOUND
76 | vk::DescriptorBindingFlags::UPDATE_AFTER_BIND,
77 vk::DescriptorBindingFlags::PARTIALLY_BOUND
78 | vk::DescriptorBindingFlags::UPDATE_AFTER_BIND,
79 vk::DescriptorBindingFlags::PARTIALLY_BOUND
80 | vk::DescriptorBindingFlags::UPDATE_AFTER_BIND,
81 ];
82
83 let mut flags_info =
84 vk::DescriptorSetLayoutBindingFlagsCreateInfo::default().binding_flags(&binding_flags);
85
86 let layout_info = vk::DescriptorSetLayoutCreateInfo::default()
87 .bindings(&bindings)
88 .flags(vk::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL)
89 .push_next(&mut flags_info);
90
91 let descriptor_set_layout = unsafe {
92 device
93 .create_descriptor_set_layout(&layout_info, None)
94 .map_err(|e| {
95 HalError::PipelineError(format!("Failed to create bindless set layout: {e}"))
96 })?
97 };
98
99 let push_constant_ranges = [vk::PushConstantRange::default()
101 .stage_flags(vk::ShaderStageFlags::ALL)
102 .offset(0)
103 .size(PUSH_CONSTANT_SIZE)];
104
105 let set_layouts = [descriptor_set_layout];
106 let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default()
107 .set_layouts(&set_layouts)
108 .push_constant_ranges(&push_constant_ranges);
109
110 let pipeline_layout = unsafe {
111 device
112 .create_pipeline_layout(&pipeline_layout_info, None)
113 .map_err(|e| {
114 HalError::PipelineError(format!(
115 "Failed to create bindless pipeline layout: {e}"
116 ))
117 })?
118 };
119
120 let pool_sizes = [
122 vk::DescriptorPoolSize::default()
123 .ty(vk::DescriptorType::STORAGE_BUFFER)
124 .descriptor_count(max_buffers),
125 vk::DescriptorPoolSize::default()
126 .ty(vk::DescriptorType::SAMPLED_IMAGE)
127 .descriptor_count(max_textures),
128 vk::DescriptorPoolSize::default()
129 .ty(vk::DescriptorType::SAMPLER)
130 .descriptor_count(max_samplers),
131 vk::DescriptorPoolSize::default()
132 .ty(vk::DescriptorType::STORAGE_IMAGE)
133 .descriptor_count(max_storage_images),
134 ];
135
136 let pool_info = vk::DescriptorPoolCreateInfo::default()
137 .pool_sizes(&pool_sizes)
138 .max_sets(1)
139 .flags(vk::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND);
140
141 let descriptor_pool = unsafe {
142 device
143 .create_descriptor_pool(&pool_info, None)
144 .map_err(|e| {
145 HalError::PipelineError(format!(
146 "Failed to create bindless descriptor pool: {e}"
147 ))
148 })?
149 };
150
151 let alloc_info = vk::DescriptorSetAllocateInfo::default()
153 .descriptor_pool(descriptor_pool)
154 .set_layouts(&set_layouts);
155
156 let descriptor_sets = unsafe {
157 device.allocate_descriptor_sets(&alloc_info).map_err(|e| {
158 HalError::PipelineError(format!("Failed to allocate bindless descriptor set: {e}"))
159 })?
160 };
161
162 Ok(Self {
163 descriptor_set_layout,
164 descriptor_pool,
165 descriptor_set: descriptor_sets[0],
166 pipeline_layout,
167 max_buffers,
168 max_textures,
169 max_samplers,
170 max_storage_images,
171 buffer_slots: Mutex::new(SlotPool {
172 free: Vec::new(),
173 next: 0,
174 }),
175 texture_slots: Mutex::new(SlotPool {
176 free: Vec::new(),
177 next: 0,
178 }),
179 sampler_slots: Mutex::new(SlotPool {
180 free: Vec::new(),
181 next: 0,
182 }),
183 storage_image_slots: Mutex::new(SlotPool {
184 free: Vec::new(),
185 next: 0,
186 }),
187 })
188 }
189
190 pub fn allocate_buffer_slot(&self) -> Result<u32, HalError> {
191 let mut pool = self.buffer_slots.lock().unwrap();
192 if let Some(slot) = pool.free.pop() {
193 return Ok(slot);
194 }
195 if pool.next >= self.max_buffers {
196 return Err(HalError::OutOfMemory(
197 "Exceeded max bindless buffer capacity".to_string(),
198 ));
199 }
200 let slot = pool.next;
201 pool.next += 1;
202 Ok(slot)
203 }
204
205 pub fn free_buffer_slot(&self, slot: u32) {
206 let mut pool = self.buffer_slots.lock().unwrap();
207 pool.free.push(slot);
208 }
209
210 pub fn write_buffer_descriptor(
211 &self,
212 device: &ash::Device,
213 slot: u32,
214 buffer: vk::Buffer,
215 size: u64,
216 ) {
217 let buffer_info = vk::DescriptorBufferInfo::default()
218 .buffer(buffer)
219 .offset(0)
220 .range(size);
221
222 let write = vk::WriteDescriptorSet::default()
223 .dst_set(self.descriptor_set)
224 .dst_binding(0)
225 .dst_array_element(slot)
226 .descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
227 .buffer_info(std::slice::from_ref(&buffer_info));
228
229 unsafe {
230 device.update_descriptor_sets(&[write], &[]);
231 }
232 }
233
234 pub fn allocate_texture_slot(&self) -> Result<u32, HalError> {
235 let mut pool = self.texture_slots.lock().unwrap();
236 if let Some(slot) = pool.free.pop() {
237 return Ok(slot);
238 }
239 if pool.next >= self.max_textures {
240 return Err(HalError::OutOfMemory(
241 "Exceeded max bindless texture capacity".to_string(),
242 ));
243 }
244 let slot = pool.next;
245 pool.next += 1;
246 Ok(slot)
247 }
248
249 pub fn free_texture_slot(&self, slot: u32) {
250 let mut pool = self.texture_slots.lock().unwrap();
251 pool.free.push(slot);
252 }
253
254 pub fn write_texture_descriptor(
255 &self,
256 device: &ash::Device,
257 slot: u32,
258 image_view: vk::ImageView,
259 image_layout: vk::ImageLayout,
260 ) {
261 let image_info = vk::DescriptorImageInfo::default()
262 .image_view(image_view)
263 .image_layout(image_layout);
264
265 let write = vk::WriteDescriptorSet::default()
266 .dst_set(self.descriptor_set)
267 .dst_binding(1)
268 .dst_array_element(slot)
269 .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE)
270 .image_info(std::slice::from_ref(&image_info));
271
272 unsafe {
273 device.update_descriptor_sets(&[write], &[]);
274 }
275 }
276
277 pub fn allocate_sampler_slot(&self) -> Result<u32, HalError> {
278 let mut pool = self.sampler_slots.lock().unwrap();
279 if let Some(slot) = pool.free.pop() {
280 return Ok(slot);
281 }
282 if pool.next >= self.max_samplers {
283 return Err(HalError::OutOfMemory(
284 "Exceeded max bindless sampler capacity".to_string(),
285 ));
286 }
287 let slot = pool.next;
288 pool.next += 1;
289 Ok(slot)
290 }
291
292 pub fn free_sampler_slot(&self, slot: u32) {
293 let mut pool = self.sampler_slots.lock().unwrap();
294 pool.free.push(slot);
295 }
296
297 pub fn write_sampler_descriptor(&self, device: &ash::Device, slot: u32, sampler: vk::Sampler) {
298 let sampler_info = vk::DescriptorImageInfo::default().sampler(sampler);
299
300 let write = vk::WriteDescriptorSet::default()
301 .dst_set(self.descriptor_set)
302 .dst_binding(2)
303 .dst_array_element(slot)
304 .descriptor_type(vk::DescriptorType::SAMPLER)
305 .image_info(std::slice::from_ref(&sampler_info));
306
307 unsafe {
308 device.update_descriptor_sets(&[write], &[]);
309 }
310 }
311
312 pub fn allocate_storage_image_slot(&self) -> Result<u32, HalError> {
313 let mut pool = self.storage_image_slots.lock().unwrap();
314 if let Some(slot) = pool.free.pop() {
315 return Ok(slot);
316 }
317 if pool.next >= self.max_storage_images {
318 return Err(HalError::OutOfMemory(
319 "Exceeded max bindless storage image capacity".to_string(),
320 ));
321 }
322 let slot = pool.next;
323 pool.next += 1;
324 Ok(slot)
325 }
326
327 pub fn free_storage_image_slot(&self, slot: u32) {
328 let mut pool = self.storage_image_slots.lock().unwrap();
329 pool.free.push(slot);
330 }
331
332 pub fn write_storage_image_descriptor(
333 &self,
334 device: &ash::Device,
335 slot: u32,
336 image_view: vk::ImageView,
337 image_layout: vk::ImageLayout,
338 ) {
339 let image_info = vk::DescriptorImageInfo::default()
340 .image_view(image_view)
341 .image_layout(image_layout);
342
343 let write = vk::WriteDescriptorSet::default()
344 .dst_set(self.descriptor_set)
345 .dst_binding(3)
346 .dst_array_element(slot)
347 .descriptor_type(vk::DescriptorType::STORAGE_IMAGE)
348 .image_info(std::slice::from_ref(&image_info));
349
350 unsafe {
351 device.update_descriptor_sets(&[write], &[]);
352 }
353 }
354
355 pub fn write_buffer_descriptors_batch(
356 &self,
357 device: &ash::Device,
358 writes: &[(u32, vk::Buffer, u64)],
359 ) {
360 if writes.is_empty() {
361 return;
362 }
363 let buffer_infos: Vec<vk::DescriptorBufferInfo> = writes
364 .iter()
365 .map(|(_, buffer, size)| {
366 vk::DescriptorBufferInfo::default()
367 .buffer(*buffer)
368 .offset(0)
369 .range(*size)
370 })
371 .collect();
372
373 let descriptor_writes: Vec<vk::WriteDescriptorSet> = writes
374 .iter()
375 .zip(buffer_infos.iter())
376 .map(|(&(slot, _, _), buffer_info)| {
377 vk::WriteDescriptorSet::default()
378 .dst_set(self.descriptor_set)
379 .dst_binding(0)
380 .dst_array_element(slot)
381 .descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
382 .buffer_info(std::slice::from_ref(buffer_info))
383 })
384 .collect();
385
386 unsafe {
387 device.update_descriptor_sets(&descriptor_writes, &[]);
388 }
389 }
390
391 pub fn write_texture_descriptors_batch(
392 &self,
393 device: &ash::Device,
394 writes: &[(u32, vk::ImageView, vk::ImageLayout)],
395 ) {
396 if writes.is_empty() {
397 return;
398 }
399 let image_infos: Vec<vk::DescriptorImageInfo> = writes
400 .iter()
401 .map(|(_, view, layout)| {
402 vk::DescriptorImageInfo::default()
403 .image_view(*view)
404 .image_layout(*layout)
405 })
406 .collect();
407
408 let descriptor_writes: Vec<vk::WriteDescriptorSet> = writes
409 .iter()
410 .zip(image_infos.iter())
411 .map(|(&(slot, _, _), image_info)| {
412 vk::WriteDescriptorSet::default()
413 .dst_set(self.descriptor_set)
414 .dst_binding(1)
415 .dst_array_element(slot)
416 .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE)
417 .image_info(std::slice::from_ref(image_info))
418 })
419 .collect();
420
421 unsafe {
422 device.update_descriptor_sets(&descriptor_writes, &[]);
423 }
424 }
425
426 pub fn write_storage_image_descriptors_batch(
427 &self,
428 device: &ash::Device,
429 writes: &[(u32, vk::ImageView, vk::ImageLayout)],
430 ) {
431 if writes.is_empty() {
432 return;
433 }
434 let image_infos: Vec<vk::DescriptorImageInfo> = writes
435 .iter()
436 .map(|(_, view, layout)| {
437 vk::DescriptorImageInfo::default()
438 .image_view(*view)
439 .image_layout(*layout)
440 })
441 .collect();
442
443 let descriptor_writes: Vec<vk::WriteDescriptorSet> = writes
444 .iter()
445 .zip(image_infos.iter())
446 .map(|(&(slot, _, _), image_info)| {
447 vk::WriteDescriptorSet::default()
448 .dst_set(self.descriptor_set)
449 .dst_binding(3)
450 .dst_array_element(slot)
451 .descriptor_type(vk::DescriptorType::STORAGE_IMAGE)
452 .image_info(std::slice::from_ref(image_info))
453 })
454 .collect();
455
456 unsafe {
457 device.update_descriptor_sets(&descriptor_writes, &[]);
458 }
459 }
460
461 pub fn destroy(&self, device: &ash::Device) {
462 unsafe {
463 device.destroy_descriptor_pool(self.descriptor_pool, None);
464 device.destroy_descriptor_set_layout(self.descriptor_set_layout, None);
465 device.destroy_pipeline_layout(self.pipeline_layout, None);
466 }
467 }
468}