bort_vma/
allocator.rs

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