vk_mem/
lib.rs

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