vk_mem_vulkanalia/lib.rs
1//! Easy to use, high performance memory manager for Vulkan.
2#![cfg_attr(not(feature = "std"), no_std)]
3#![cfg_attr(feature = "core_error", feature(no_std_error))]
4
5extern crate alloc;
6
7mod definitions;
8mod defragmentation;
9mod ffi;
10mod pool;
11mod utils;
12mod virtual_block;
13pub use definitions::*;
14pub use defragmentation::*;
15pub use pool::*;
16pub use utils::*;
17pub use virtual_block::*;
18
19use vulkanalia::VkResult;
20use vulkanalia::vk;
21use vulkanalia::vk::DeviceBufferMemoryRequirements;
22use vulkanalia::vk::MemoryRequirements2;
23use vulkanalia::vk::{
24 DeviceV1_0,
25 InstanceV1_0
26};
27use vulkanalia_sys::DeviceImageMemoryRequirements;
28use std::mem;
29
30/// Main allocator object
31pub struct Allocator {
32 /// Pointer to internal VmaAllocator instance
33 internal: ffi::VmaAllocator,
34}
35
36// Allocator is internally thread safe unless AllocatorCreateFlags::EXTERNALLY_SYNCHRONIZED is used (then you need to add synchronization!)
37unsafe impl Send for Allocator {}
38unsafe impl Sync for Allocator {}
39
40/// Represents single memory allocation.
41///
42/// It may be either dedicated block of `vk::DeviceMemory` or a specific region of a
43/// bigger block of this type plus unique offset.
44///
45/// Although the library provides convenience functions that create a Vulkan buffer or image,
46/// allocate memory for it and bind them together, binding of the allocation to a buffer or an
47/// image is out of scope of the allocation itself.
48///
49/// Allocation object can exist without buffer/image bound, binding can be done manually by
50/// the user, and destruction of it can be done independently of destruction of the allocation.
51///
52/// The object also remembers its size and some other information. To retrieve this information,
53/// use `Allocator::get_allocation_info`.
54///
55/// Some kinds allocations can be in lost state.
56#[derive(Debug)]
57pub struct Allocation(ffi::VmaAllocation);
58unsafe impl Send for Allocation {}
59unsafe impl Sync for Allocation {}
60
61impl Allocator {
62 /// Construct a new `Allocator` using the provided options.
63 /// Safety: [`AllocatorCreateInfo::instance`], [`AllocatorCreateInfo::device`] and
64 /// [`AllocatorCreateInfo::physical_device`] must be valid throughout the lifetime of the allocator.
65 pub unsafe fn new(create_info: AllocatorCreateInfo) -> VkResult<Self> {
66 unsafe extern "system" fn get_instance_proc_addr_stub(
67 _instance: vk::Instance,
68 _p_name: *const ::std::os::raw::c_char,
69 ) -> vk::PFN_vkVoidFunction {
70 panic!("VMA_DYNAMIC_VULKAN_FUNCTIONS is unsupported")
71 }
72
73 unsafe extern "system" fn get_get_device_proc_stub(
74 _device: vk::Device,
75 _p_name: *const ::std::os::raw::c_char,
76 ) -> vk::PFN_vkVoidFunction {
77 panic!("VMA_DYNAMIC_VULKAN_FUNCTIONS is unsupported")
78 }
79
80 let mut raw_create_info = ffi::VmaAllocatorCreateInfo {
81 flags: create_info.flags.bits(),
82 physicalDevice: create_info.physical_device,
83 device: create_info.device.handle(),
84 preferredLargeHeapBlockSize: create_info.preferred_large_heap_block_size,
85 pAllocationCallbacks: create_info
86 .allocation_callbacks
87 .map(|a| unsafe { std::mem::transmute(a) })
88 .unwrap_or(std::ptr::null()),
89 pDeviceMemoryCallbacks: create_info
90 .device_memory_callbacks
91 .map(|a| a as *const _)
92 .unwrap_or(std::ptr::null()),
93 pHeapSizeLimit: if create_info.heap_size_limits.is_empty() {
94 std::ptr::null()
95 } else {
96 create_info.heap_size_limits.as_ptr()
97 },
98 instance: create_info.instance.handle(),
99 vulkanApiVersion: create_info.vulkan_api_version,
100 pVulkanFunctions: std::ptr::null(),
101 pTypeExternalMemoryHandleTypes: if create_info
102 .type_external_memory_handle_types
103 .is_empty()
104 {
105 std::ptr::null()
106 } else {
107 create_info.type_external_memory_handle_types.as_ptr()
108 },
109 };
110
111 let version = create_info.instance.get_physical_device_properties(create_info.physical_device).api_version;
112 println!("vk version {}.{}", vk::version_major(version), vk::version_minor(version));
113
114 for extension in create_info.instance.extensions() {
115 println!("Extension {}", extension);
116 }
117
118 let has_ext = create_info.instance.extensions().contains(&vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name);
119
120 println!("Includes? {}", has_ext);
121
122 #[cfg(feature = "libloading")]
123 let routed_functions = ffi::VmaVulkanFunctions {
124 vkGetInstanceProcAddr: get_instance_proc_addr_stub,
125 vkGetDeviceProcAddr: get_get_device_proc_stub,
126 vkGetPhysicalDeviceProperties: create_info
127 .instance
128 .commands()
129 .get_physical_device_properties,
130 vkGetPhysicalDeviceMemoryProperties: create_info
131 .instance
132 .commands()
133 .get_physical_device_memory_properties,
134 vkAllocateMemory: create_info.device.commands().allocate_memory,
135 vkFreeMemory: create_info.device.commands().free_memory,
136 vkMapMemory: create_info.device.commands().map_memory,
137 vkUnmapMemory: create_info.device.commands().unmap_memory,
138 vkFlushMappedMemoryRanges: create_info.device.commands().flush_mapped_memory_ranges,
139 vkInvalidateMappedMemoryRanges: create_info
140 .device
141 .commands()
142 .invalidate_mapped_memory_ranges,
143 vkBindBufferMemory: create_info.device.commands().bind_buffer_memory,
144 vkBindImageMemory: create_info.device.commands().bind_image_memory,
145 vkGetBufferMemoryRequirements: create_info
146 .device
147 .commands()
148 .get_buffer_memory_requirements,
149 vkGetImageMemoryRequirements: create_info
150 .device
151 .commands()
152 .get_image_memory_requirements,
153 vkCreateBuffer: create_info.device.commands().create_buffer,
154 vkDestroyBuffer: create_info.device.commands().destroy_buffer,
155 vkCreateImage: create_info.device.commands().create_image,
156 vkDestroyImage: create_info.device.commands().destroy_image,
157 vkCmdCopyBuffer: create_info.device.commands().cmd_copy_buffer,
158 vkGetBufferMemoryRequirements2KHR: create_info
159 .device
160 .commands()
161 .get_buffer_memory_requirements2_khr,
162 vkGetImageMemoryRequirements2KHR: create_info
163 .device
164 .commands()
165 .get_image_memory_requirements2_khr,
166 vkBindBufferMemory2KHR: create_info.device.commands().bind_buffer_memory2_khr,
167 vkBindImageMemory2KHR: create_info.device.commands().bind_image_memory2_khr,
168 vkGetPhysicalDeviceMemoryProperties2KHR: create_info
169 .instance
170 .commands()
171 .get_physical_device_memory_properties2_khr,
172 vkGetDeviceBufferMemoryRequirements: pick_get_device_buffer_memory_requirements_fn(
173 &create_info),
174 vkGetDeviceImageMemoryRequirements: pick_get_device_image_memory_requirements_fn(&create_info),
175 };
176 #[cfg(feature = "libloading")]
177 {
178 raw_create_info.pVulkanFunctions = &routed_functions;
179 }
180 unsafe {
181 let mut internal: ffi::VmaAllocator = mem::zeroed();
182 ffi::vmaCreateAllocator(&raw_create_info, &mut internal);
183
184 Ok(Allocator { internal })
185 }
186 }
187
188 /// The allocator fetches `vk::PhysicalDeviceProperties` from the physical device.
189 /// You can get it here, without fetching it again on your own.
190 pub unsafe fn get_physical_device_properties(&self) -> VkResult<vk::PhysicalDeviceProperties> {
191 let mut properties = vk::PhysicalDeviceProperties::default();
192 ffi::vmaGetPhysicalDeviceProperties(
193 self.internal,
194 &mut properties as *mut _ as *mut *const _,
195 );
196
197 Ok(properties)
198 }
199
200 /// The allocator fetches `vk::PhysicalDeviceMemoryProperties` from the physical device.
201 /// You can get it here, without fetching it again on your own.
202 pub unsafe fn get_memory_properties(&self) -> &vk::PhysicalDeviceMemoryProperties {
203 let mut properties: *const vk::PhysicalDeviceMemoryProperties = std::ptr::null();
204 ffi::vmaGetMemoryProperties(self.internal, &mut properties);
205
206 &*properties
207 }
208
209 /// Sets index of the current frame.
210 ///
211 /// This function must be used if you make allocations with `AllocationCreateFlags::CAN_BECOME_LOST` and
212 /// `AllocationCreateFlags::CAN_MAKE_OTHER_LOST` flags to inform the allocator when a new frame begins.
213 /// Allocations queried using `Allocator::get_allocation_info` cannot become lost
214 /// in the current frame.
215 pub unsafe fn set_current_frame_index(&self, frame_index: u32) {
216 ffi::vmaSetCurrentFrameIndex(self.internal, frame_index);
217 }
218
219 /// Retrieves statistics from current state of the `Allocator`.
220 pub fn calculate_statistics(&self) -> VkResult<ffi::VmaTotalStatistics> {
221 unsafe {
222 let mut vma_stats: ffi::VmaTotalStatistics = mem::zeroed();
223 ffi::vmaCalculateStatistics(self.internal, &mut vma_stats);
224 Ok(vma_stats)
225 }
226 }
227
228 /// Retrieves information about current memory usage and budget for all memory heaps.
229 ///
230 /// This function is called "get" not "calculate" because it is very fast, suitable to be called
231 /// every frame or every allocation. For more detailed statistics use vmaCalculateStatistics().
232 ///
233 /// Note that when using allocator from multiple threads, returned information may immediately
234 /// become outdated.
235 pub fn get_heap_budgets(&self) -> VkResult<Vec<ffi::VmaBudget>> {
236 unsafe {
237 let len = self.get_memory_properties().memory_heap_count as usize;
238 let mut vma_budgets: Vec<ffi::VmaBudget> = Vec::with_capacity(len);
239 ffi::vmaGetHeapBudgets(self.internal, vma_budgets.as_mut_ptr());
240 vma_budgets.set_len(len);
241 Ok(vma_budgets)
242 }
243 }
244
245 /// Frees memory previously allocated using `Allocator::allocate_memory`,
246 /// `Allocator::allocate_memory_for_buffer`, or `Allocator::allocate_memory_for_image`.
247 pub unsafe fn free_memory(&self, allocation: &mut Allocation) {
248 ffi::vmaFreeMemory(self.internal, allocation.0);
249 }
250
251 /// Frees memory and destroys multiple allocations.
252 ///
253 /// Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding.
254 /// It is just a general purpose function to free memory and destroy allocations made using e.g. `Allocator::allocate_memory',
255 /// 'Allocator::allocate_memory_pages` and other functions.
256 ///
257 /// It may be internally optimized to be more efficient than calling 'Allocator::free_memory` `allocations.len()` times.
258 ///
259 /// Allocations in 'allocations' slice can come from any memory pools and types.
260 pub unsafe fn free_memory_pages(&self, allocations: &mut [Allocation]) {
261 ffi::vmaFreeMemoryPages(
262 self.internal,
263 allocations.len(),
264 allocations.as_ptr() as *mut _,
265 );
266 }
267
268 /// Returns current information about specified allocation and atomically marks it as used in current frame.
269 ///
270 /// Current parameters of given allocation are returned in the result object, available through accessors.
271 ///
272 /// This function also atomically "touches" allocation - marks it as used in current frame,
273 /// just like `Allocator::touch_allocation`.
274 ///
275 /// If the allocation is in lost state, `allocation.get_device_memory` returns `vk::DeviceMemory::null()`.
276 ///
277 /// Although this function uses atomics and doesn't lock any mutex, so it should be quite efficient,
278 /// you can avoid calling it too often.
279 ///
280 /// If you just want to check if allocation is not lost, `Allocator::touch_allocation` will work faster.
281 pub fn get_allocation_info(&self, allocation: &Allocation) -> AllocationInfo {
282 unsafe {
283 let mut allocation_info: ffi::VmaAllocationInfo = mem::zeroed();
284 ffi::vmaGetAllocationInfo(self.internal, allocation.0, &mut allocation_info);
285 allocation_info.into()
286 }
287 }
288
289 /// Sets user data in given allocation to new value.
290 ///
291 /// If the allocation was created with `AllocationCreateFlags::USER_DATA_COPY_STRING`,
292 /// `user_data` must be either null, or pointer to a null-terminated string. The function
293 /// makes local copy of the string and sets it as allocation's user data. String
294 /// passed as user data doesn't need to be valid for whole lifetime of the allocation -
295 /// you can free it after this call. String previously pointed by allocation's
296 /// user data is freed from memory.
297 ///
298 /// If the flag was not used, the value of pointer `user_data` is just copied to
299 /// allocation's user data. It is opaque, so you can use it however you want - e.g.
300 /// as a pointer, ordinal number or some handle to you own data.
301 pub unsafe fn set_allocation_user_data(
302 &self,
303 allocation: &mut Allocation,
304 user_data: *mut ::std::os::raw::c_void,
305 ) {
306 ffi::vmaSetAllocationUserData(self.internal, allocation.0, user_data);
307 }
308
309 /// Maps memory represented by given allocation and returns pointer to it.
310 ///
311 /// Maps memory represented by given allocation to make it accessible to CPU code.
312 /// When succeeded, result is a pointer to first byte of this memory.
313 ///
314 /// If the allocation is part of bigger `vk::DeviceMemory` block, the pointer is
315 /// correctly offseted to the beginning of region assigned to this particular
316 /// allocation.
317 ///
318 /// Mapping is internally reference-counted and synchronized, so despite raw Vulkan
319 /// function `vk::Device::MapMemory` cannot be used to map same block of
320 /// `vk::DeviceMemory` multiple times simultaneously, it is safe to call this
321 /// function on allocations assigned to the same memory block. Actual Vulkan memory
322 /// will be mapped on first mapping and unmapped on last unmapping.
323 ///
324 /// If the function succeeded, you must call `Allocator::unmap_memory` to unmap the
325 /// allocation when mapping is no longer needed or before freeing the allocation, at
326 /// the latest.
327 ///
328 /// It also safe to call this function multiple times on the same allocation. You
329 /// must call `Allocator::unmap_memory` same number of times as you called
330 /// `Allocator::map_memory`.
331 ///
332 /// It is also safe to call this function on allocation created with
333 /// `AllocationCreateFlags::MAPPED` flag. Its memory stays mapped all the time.
334 /// You must still call `Allocator::unmap_memory` same number of times as you called
335 /// `Allocator::map_memory`. You must not call `Allocator::unmap_memory` additional
336 /// time to free the "0-th" mapping made automatically due to `AllocationCreateFlags::MAPPED` flag.
337 ///
338 /// This function fails when used on allocation made in memory type that is not
339 /// `vk::MemoryPropertyFlags::HOST_VISIBLE`.
340 ///
341 /// This function always fails when called for allocation that was created with
342 /// `AllocationCreateFlags::CAN_BECOME_LOST` flag. Such allocations cannot be mapped.
343 pub unsafe fn map_memory(&self, allocation: &mut Allocation) -> VkResult<*mut u8> {
344 let mut mapped_data: *mut ::std::os::raw::c_void = ::std::ptr::null_mut();
345 ffi::vmaMapMemory(self.internal, allocation.0, &mut mapped_data);
346
347 Ok(mapped_data as *mut u8)
348 }
349
350 /// Unmaps memory represented by given allocation, mapped previously using `Allocator::map_memory`.
351 pub unsafe fn unmap_memory(&self, allocation: &mut Allocation) {
352 ffi::vmaUnmapMemory(self.internal, allocation.0);
353 }
354
355 /// Flushes memory of given allocation.
356 ///
357 /// Calls `vk::Device::FlushMappedMemoryRanges` for memory associated with given range of given allocation.
358 ///
359 /// - `offset` must be relative to the beginning of allocation.
360 /// - `size` can be `vk::WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation.
361 /// - `offset` and `size` don't have to be aligned; hey are internally rounded down/up to multiple of `nonCoherentAtomSize`.
362 /// - If `size` is 0, this call is ignored.
363 /// - If memory type that the `allocation` belongs to is not `vk::MemoryPropertyFlags::HOST_VISIBLE` or it is `vk::MemoryPropertyFlags::HOST_COHERENT`, this call is ignored.
364 pub fn flush_allocation(
365 &self,
366 allocation: &Allocation,
367 offset: vk::DeviceSize,
368 size: vk::DeviceSize,
369 ) -> VkResult<()> {
370 to_vk_result(unsafe { ffi::vmaFlushAllocation(self.internal, allocation.0, offset, size) })
371 }
372
373 /// Invalidates memory of given allocation.
374 ///
375 /// Calls `vk::Device::invalidate_mapped_memory_ranges` for memory associated with given range of given allocation.
376 ///
377 /// - `offset` must be relative to the beginning of allocation.
378 /// - `size` can be `vk::WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation.
379 /// - `offset` and `size` don't have to be aligned. They are internally rounded down/up to multiple of `nonCoherentAtomSize`.
380 /// - If `size` is 0, this call is ignored.
381 /// - If memory type that the `allocation` belongs to is not `vk::MemoryPropertyFlags::HOST_VISIBLE` or it is `vk::MemoryPropertyFlags::HOST_COHERENT`, this call is ignored.
382 pub fn invalidate_allocation(
383 &self,
384 allocation: &Allocation,
385 offset: vk::DeviceSize,
386 size: vk::DeviceSize,
387 ) -> VkResult<()> {
388 to_vk_result(unsafe { ffi::vmaInvalidateAllocation(self.internal, allocation.0, offset, size) })
389 }
390
391 /// Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions.
392 ///
393 /// `memory_type_bits` bit mask, where each bit set means that a memory type with that index should be checked.
394 ///
395 /// Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero,
396 /// `VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are `HOST_VISIBLE` and `HOST_COHERENT`.
397 ///
398 /// Possible error values:
399 ///
400 /// - `vk::Result::ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types.
401 /// - `vk::Result::ERROR_VALIDATION_FAILED_EXT` - corruption detection has been performed and found memory corruptions around one of the allocations.
402 /// `VMA_ASSERT` is also fired in that case.
403 /// - Other value: Error returned by Vulkan, e.g. memory mapping failure.
404 pub unsafe fn check_corruption(&self, memory_types: vk::MemoryPropertyFlags) -> VkResult<()> {
405 to_vk_result(ffi::vmaCheckCorruption(self.internal, memory_types.bits()))
406 }
407
408 /// Binds buffer to allocation.
409 ///
410 /// Binds specified buffer to region of memory represented by specified allocation.
411 /// Gets `vk::DeviceMemory` handle and offset from the allocation.
412 ///
413 /// If you want to create a buffer, allocate memory for it and bind them together separately,
414 /// you should use this function for binding instead of `vk::Device::bind_buffer_memory`,
415 /// because it ensures proper synchronization so that when a `vk::DeviceMemory` object is
416 /// used by multiple allocations, calls to `vk::Device::bind_buffer_memory()` or
417 /// `vk::Device::map_memory()` won't happen from multiple threads simultaneously
418 /// (which is illegal in Vulkan).
419 ///
420 /// It is recommended to use function `Allocator::create_buffer` instead of this one.
421 pub unsafe fn bind_buffer_memory(
422 &self,
423 allocation: &Allocation,
424 buffer: vk::Buffer,
425 ) -> VkResult<()> {
426 to_vk_result(ffi::vmaBindBufferMemory(self.internal, allocation.0, buffer))
427 }
428
429 /// Binds buffer to allocation with additional parameters.
430 ///
431 /// * `allocation`
432 /// * `allocation_local_offset` - Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0.
433 /// * `buffer`
434 /// * `next` - A chain of structures to be attached to `VkBindImageMemoryInfoKHR` structure used internally. Normally it should be null.
435 ///
436 /// This function is similar to vmaBindImageMemory(), but it provides additional parameters.
437 ///
438 /// If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag
439 /// or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails.
440 pub unsafe fn bind_buffer_memory2(
441 &self,
442 allocation: &Allocation,
443 allocation_local_offset: vk::DeviceSize,
444 buffer: vk::Buffer,
445 next: *const ::std::os::raw::c_void,
446 ) -> VkResult<()> {
447 to_vk_result(ffi::vmaBindBufferMemory2(
448 self.internal,
449 allocation.0,
450 allocation_local_offset,
451 buffer,
452 next,
453 ))
454 }
455
456 /// Binds image to allocation.
457 ///
458 /// Binds specified image to region of memory represented by specified allocation.
459 /// Gets `vk::DeviceMemory` handle and offset from the allocation.
460 ///
461 /// If you want to create a image, allocate memory for it and bind them together separately,
462 /// you should use this function for binding instead of `vk::Device::bind_image_memory`,
463 /// because it ensures proper synchronization so that when a `vk::DeviceMemory` object is
464 /// used by multiple allocations, calls to `vk::Device::bind_image_memory()` or
465 /// `vk::Device::map_memory()` won't happen from multiple threads simultaneously
466 /// (which is illegal in Vulkan).
467 ///
468 /// It is recommended to use function `Allocator::create_image` instead of this one.
469 pub unsafe fn bind_image_memory(
470 &self,
471 allocation: &Allocation,
472 image: vk::Image,
473 ) -> VkResult<()> {
474 to_vk_result(ffi::vmaBindImageMemory(self.internal, allocation.0, image))
475 }
476
477 /// Binds image to allocation with additional parameters.
478 ///
479 /// * `allocation`
480 /// * `allocation_local_offset` - Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0.
481 /// * `image`
482 /// * `next` - A chain of structures to be attached to `VkBindImageMemoryInfoKHR` structure used internally. Normally it should be null.
483 ///
484 /// This function is similar to vmaBindImageMemory(), but it provides additional parameters.
485 ///
486 /// If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag
487 /// or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails.
488 pub unsafe fn bind_image_memory2(
489 &self,
490 allocation: &Allocation,
491 allocation_local_offset: vk::DeviceSize,
492 image: vk::Image,
493 next: *const ::std::os::raw::c_void,
494 ) -> VkResult<()> {
495 to_vk_result(ffi::vmaBindImageMemory2(
496 self.internal,
497 allocation.0,
498 allocation_local_offset,
499 image,
500 next,
501 ))
502 }
503
504 /// Destroys Vulkan buffer and frees allocated memory.
505 ///
506 /// This is just a convenience function equivalent to:
507 ///
508 /// ```ignore
509 /// vk::Device::destroy_buffer(buffer, None);
510 /// Allocator::free_memory(allocator, allocation);
511 /// ```
512 ///
513 /// It it safe to pass null as `buffer` and/or `allocation`.
514 pub unsafe fn destroy_buffer(&self, buffer: vk::Buffer, allocation: &mut Allocation) {
515 ffi::vmaDestroyBuffer(self.internal, buffer, allocation.0);
516 }
517
518 /// Destroys Vulkan image and frees allocated memory.
519 ///
520 /// This is just a convenience function equivalent to:
521 ///
522 /// ```ignore
523 /// vk::Device::destroy_image(image, None);
524 /// Allocator::free_memory(allocator, allocation);
525 /// ```
526 ///
527 /// It it safe to pass null as `image` and/or `allocation`.
528 pub unsafe fn destroy_image(&self, image: vk::Image, allocation: &mut Allocation) {
529 ffi::vmaDestroyImage(self.internal, image, allocation.0);
530 }
531 /// Flushes memory of given set of allocations."]
532 ///
533 /// Calls `vkFlushMappedMemoryRanges()` for memory associated with given ranges of given allocations."]
534 /// For more information, see documentation of vmaFlushAllocation()."]
535 ///
536 /// * `allocations`
537 /// * `offsets` - If not None, it must be a slice of offsets of regions to flush, relative to the beginning of respective allocations. None means all ofsets are zero.
538 /// * `sizes` - If not None, it must be a slice of sizes of regions to flush in respective allocations. None means `VK_WHOLE_SIZE` for all allocations.
539 pub unsafe fn flush_allocations<'a>(
540 &self,
541 allocations: impl IntoIterator<Item = &'a Allocation>,
542 offsets: Option<&[vk::DeviceSize]>,
543 sizes: Option<&[vk::DeviceSize]>,
544 ) -> VkResult<()> {
545 let allocations: Vec<ffi::VmaAllocation> = allocations.into_iter().map(|a| a.0).collect();
546 to_vk_result(ffi::vmaFlushAllocations(
547 self.internal,
548 allocations.len() as u32,
549 allocations.as_ptr() as *mut _,
550 offsets.map_or(std::ptr::null(), |offsets| offsets.as_ptr()),
551 sizes.map_or(std::ptr::null(), |sizes| sizes.as_ptr()),
552 ))
553 }
554
555 /// Invalidates memory of given set of allocations."]
556 ///
557 /// Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given ranges of given allocations."]
558 /// For more information, see documentation of vmaInvalidateAllocation()."]
559 ///
560 /// * `allocations`
561 /// * `offsets` - If not None, it must be a slice of offsets of regions to flush, relative to the beginning of respective allocations. None means all ofsets are zero.
562 /// * `sizes` - If not None, it must be a slice of sizes of regions to flush in respective allocations. None means `VK_WHOLE_SIZE` for all allocations.
563 pub unsafe fn invalidate_allocations<'a>(
564 &self,
565 allocations: impl IntoIterator<Item = &'a Allocation>,
566 offsets: Option<&[vk::DeviceSize]>,
567 sizes: Option<&[vk::DeviceSize]>,
568 ) -> VkResult<()> {
569 let allocations: Vec<ffi::VmaAllocation> = allocations.into_iter().map(|a| a.0).collect();
570 to_vk_result(ffi::vmaInvalidateAllocations(
571 self.internal,
572 allocations.len() as u32,
573 allocations.as_ptr() as *mut _,
574 offsets.map_or(std::ptr::null(), |offsets| offsets.as_ptr()),
575 sizes.map_or(std::ptr::null(), |sizes| sizes.as_ptr()),
576 ))
577 }
578}
579
580/// Custom `Drop` implementation to clean up internal allocation instance
581impl Drop for Allocator {
582 fn drop(&mut self) {
583 unsafe {
584 ffi::vmaDestroyAllocator(self.internal);
585 self.internal = std::ptr::null_mut();
586 }
587 }
588}
589
590unsafe fn pick_get_device_buffer_memory_requirements_fn(
591 create_info: &AllocatorCreateInfo,
592) -> Option<
593 unsafe extern "system" fn(
594 vulkanalia_sys::Device,
595 *const DeviceBufferMemoryRequirements,
596 *mut MemoryRequirements2,
597 )
598> {
599 let version = create_info
600 .instance
601 .get_physical_device_properties(create_info.physical_device)
602 .api_version;
603
604 let major = vk::version_major(version);
605 let minor = vk::version_minor(version);
606
607 if major != 1 {
608 return None;
609 }
610
611 let commands = create_info.device.commands();
612
613 if minor == 3 {
614 return Some(commands.get_device_buffer_memory_requirements);
615 } else if minor >= 1 {
616 if create_info
617 .device
618 .extensions()
619 .contains(&vk::KHR_MAINTENANCE4_EXTENSION.name)
620 {
621 return Some(commands.get_device_buffer_memory_requirements_khr);
622 } else {
623 return None;
624 }
625 }
626
627 return None;
628}
629
630unsafe fn pick_get_device_image_memory_requirements_fn(
631 create_info: &AllocatorCreateInfo,
632) -> Option<
633 unsafe extern "system" fn(
634 vulkanalia_sys::Device,
635 *const DeviceImageMemoryRequirements,
636 *mut MemoryRequirements2,
637 )
638> {
639 let version = create_info
640 .instance
641 .get_physical_device_properties(create_info.physical_device)
642 .api_version;
643
644 let major = vk::version_major(version);
645 let minor = vk::version_minor(version);
646
647 if major != 1 {
648 return None;
649 }
650
651 let commands = create_info.device.commands();
652
653 if minor == 3 {
654 return Some(commands.get_device_image_memory_requirements);
655 } else if minor >= 1 {
656 if create_info
657 .device
658 .extensions()
659 .contains(&vk::KHR_MAINTENANCE4_EXTENSION.name)
660 {
661 return Some(commands.get_device_image_memory_requirements_khr);
662 } else {
663 return None;
664 }
665 }
666
667 return None;
668}