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}