vk_mem_3_erupt/
lib.rs

1//! Easy to use, high performance memory manager for Vulkan.
2
3#![allow(invalid_value)]
4
5extern crate erupt;
6#[macro_use]
7extern crate bitflags;
8#[cfg(feature = "failure")]
9extern crate failure;
10
11pub mod error;
12pub mod ffi;
13pub use crate::error::{Error, ErrorKind, Result};
14use erupt::ObjectHandle;
15use std::mem;
16use std::sync::Arc;
17
18/// Main allocator object
19pub struct Allocator {
20    /// Pointer to internal VmaAllocator instance
21    internal: ffi::VmaAllocator,
22    /// Vulkan device handle
23    #[allow(dead_code)]
24    device: Arc<erupt::DeviceLoader>,
25    /// Vulkan instance handle
26    #[allow(dead_code)]
27    instance: Arc<erupt::InstanceLoader>,
28}
29
30// Allocator is internally thread safe unless AllocatorCreateFlags::EXTERNALLY_SYNCHRONIZED is used (then you need to add synchronization!)
31unsafe impl Send for Allocator {}
32unsafe impl Sync for Allocator {}
33
34/// Represents custom memory pool
35///
36/// Fill structure `AllocatorPoolCreateInfo` and call `Allocator::create_pool` to create it.
37/// Call `Allocator::destroy_pool` to destroy it.
38#[derive(Debug, Clone)]
39pub struct AllocatorPool {
40    /// Pointer to internal VmaPool instance
41    internal: ffi::VmaPool,
42}
43
44/// Construct `AllocatorPool` with default values
45impl Default for AllocatorPool {
46    fn default() -> Self {
47        AllocatorPool {
48            internal: std::ptr::null_mut(),
49        }
50    }
51}
52
53/// Represents single memory allocation.
54///
55/// It may be either dedicated block of `erupt::vk::DeviceMemory` or a specific region of a
56/// bigger block of this type plus unique offset.
57///
58/// Although the library provides convenience functions that create a Vulkan buffer or image,
59/// allocate memory for it and bind them together, binding of the allocation to a buffer or an
60/// image is out of scope of the allocation itself.
61///
62/// Allocation object can exist without buffer/image bound, binding can be done manually by
63/// the user, and destruction of it can be done independently of destruction of the allocation.
64///
65/// The object also remembers its size and some other information. To retrieve this information,
66/// use `Allocator::get_allocation_info`.
67///
68/// Some kinds allocations can be in lost state.
69#[derive(Debug, Copy, Clone)]
70pub struct Allocation {
71    /// Pointer to internal VmaAllocation instance
72    internal: ffi::VmaAllocation,
73}
74
75impl Allocation {
76    pub fn null() -> Allocation {
77        Allocation {
78            internal: std::ptr::null_mut(),
79        }
80    }
81}
82
83impl Default for Allocation {
84    fn default() -> Self {
85        Self::null()
86    }
87}
88
89unsafe impl Send for Allocation {}
90unsafe impl Sync for Allocation {}
91
92/// Parameters of `Allocation` objects, that can be retrieved using `Allocator::get_allocation_info`.
93#[derive(Default, Debug, Clone)]
94pub struct AllocationInfo {
95    /// Pointer to internal VmaAllocationInfo instance
96    internal: ffi::VmaAllocationInfo,
97}
98
99unsafe impl Send for AllocationInfo {}
100unsafe impl Sync for AllocationInfo {}
101
102impl AllocationInfo {
103    #[inline(always)]
104    // Gets the memory type index that this allocation was allocated from. (Never changes)
105    pub fn get_memory_type(&self) -> u32 {
106        self.internal.memoryType
107    }
108
109    /// Handle to Vulkan memory object.
110    ///
111    /// Same memory object can be shared by multiple allocations.
112    ///
113    /// It can change after call to `Allocator::defragment` if this allocation is passed
114    /// to the function, or if allocation is lost.
115    ///
116    /// If the allocation is lost, it is equal to `erupt::vk::DeviceMemory::null()`.
117    #[inline(always)]
118    pub fn get_device_memory(&self) -> erupt::vk::DeviceMemory {
119        erupt::vk::DeviceMemory(self.internal.deviceMemory as u64)
120    }
121
122    /// Offset into device memory object to the beginning of this allocation, in bytes.
123    /// (`self.get_device_memory()`, `self.get_offset()`) pair is unique to this allocation.
124    ///
125    /// It can change after call to `Allocator::defragment` if this allocation is passed
126    /// to the function, or if allocation is lost.
127    #[inline(always)]
128    pub fn get_offset(&self) -> erupt::vk::DeviceSize {
129        self.internal.offset as erupt::vk::DeviceSize
130    }
131
132    /// Size of this allocation, in bytes.
133    ///
134    /// It never changes, unless allocation is lost.
135    #[inline(always)]
136    pub fn get_size(&self) -> erupt::vk::DeviceSize {
137        self.internal.size as erupt::vk::DeviceSize
138    }
139
140    /// Pointer to the beginning of this allocation as mapped data.
141    ///
142    /// If the allocation hasn't been mapped using `Allocator::map_memory` and hasn't been
143    /// created with `AllocationCreateFlags::MAPPED` flag, this value is null.
144    ///
145    /// It can change after call to `Allocator::map_memory`, `Allocator::unmap_memory`.
146    /// It can also change after call to `Allocator::defragment` if this allocation is
147    /// passed to the function.
148    #[inline(always)]
149    pub fn get_mapped_data(&self) -> *mut u8 {
150        self.internal.pMappedData as *mut u8
151    }
152
153    /*#[inline(always)]
154    pub fn get_mapped_slice(&self) -> Option<&mut &[u8]> {
155        if self.internal.pMappedData.is_null() {
156            None
157        } else {
158            Some(unsafe { &mut ::std::slice::from_raw_parts(self.internal.pMappedData as *mut u8, self.get_size()) })
159        }
160    }*/
161
162    /// Custom general-purpose pointer that was passed as `AllocationCreateInfo::user_data` or set using `Allocator::set_allocation_user_data`.
163    ///
164    /// It can change after a call to `Allocator::set_allocation_user_data` for this allocation.
165    #[inline(always)]
166    pub fn get_user_data(&self) -> *mut ::std::os::raw::c_void {
167        self.internal.pUserData
168    }
169
170    #[inline(always)]
171    pub fn get_name(&self) -> &std::ffi::CStr {
172        if self.internal.pName.is_null() {
173            Default::default()
174        } else {
175            unsafe { std::ffi::CStr::from_ptr(self.internal.pName) }
176        }
177    }
178}
179
180bitflags! {
181    /// Flags for configuring `Allocator` construction.
182    pub struct AllocatorCreateFlags: u32 {
183
184        /// Defaults
185        const NONE = 0;
186
187        /// Enables usage of VK_KHR_dedicated_allocation extension.
188        ///
189        /// The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`.
190        /// When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1.
191        ///
192        /// Using this extension will automatically allocate dedicated blocks of memory for
193        /// some buffers and images instead of suballocating place for them out of bigger
194        /// memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT
195        /// flag) when it is recommended by the driver. It may improve performance on some
196        /// GPUs.
197        ///
198        /// You may set this flag only if you found out that following device extensions are
199        /// supported, you enabled them while creating Vulkan device passed as
200        /// VmaAllocatorCreateInfo::device, and you want them to be used internally by this
201        /// library:
202        ///
203        /// - VK_KHR_get_memory_requirements2 (device extension)
204        /// - VK_KHR_dedicated_allocation (device extension)
205        ///
206        /// When this flag is set, you can experience following warnings reported by Vulkan
207        /// validation layer. You can ignore them.
208        ///
209        /// > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer.
210        const KHR_DEDICATED_ALLOCATION = ffi::VmaAllocatorCreateFlagBits_VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
211        /// Enables usage of VK_KHR_bind_memory2 extension.
212        ///
213        /// The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`.
214        /// When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1.
215        ///
216        /// You may set this flag only if you found out that this device extension is supported,
217        /// you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device,
218        /// and you want it to be used internally by this library.
219        ///
220        /// The extension provides functions `vkBindBufferMemory2KHR` and `vkBindImageMemory2KHR`,
221        /// which allow to pass a chain of `pNext` structures while binding.
222        /// This flag is required if you use `pNext` parameter in vmaBindBufferMemory2() or vmaBindImageMemory2().
223        const KHR_BIND_MEMORY2 = ffi::VmaAllocatorCreateFlagBits_VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
224        /// Enables usage of VK_EXT_memory_budget extension.
225        ///
226        /// You may set this flag only if you found out that this device extension is supported,
227        /// you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device,
228        /// and you want it to be used internally by this library, along with another instance extension
229        /// VK_KHR_get_physical_device_properties2, which is required by it (or Vulkan 1.1, where this extension is promoted).
230        ///
231        /// The extension provides query for current memory usage and budget, which will probably
232        /// be more accurate than an estimation used by the library otherwise.
233        const EXT_MEMORY_BUDGET = ffi::VmaAllocatorCreateFlagBits_VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
234        /// Enables usage of VK_AMD_device_coherent_memory extension.
235        ///
236        /// You may set this flag only if you:
237        ///
238        /// - found out that this device extension is supported and enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device,
239        /// - checked that `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true and set it while creating the Vulkan device,
240        /// - want it to be used internally by this library.
241        ///
242        /// The extension and accompanying device feature provide access to memory types with
243        /// `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flags.
244        /// They are useful mostly for writing breadcrumb markers - a common method for debugging GPU crash/hang/TDR.
245        ///
246        /// When the extension is not enabled, such memory types are still enumerated, but their usage is illegal.
247        /// To protect from this error, if you don't create the allocator with this flag, it will refuse to allocate any memory or create a custom pool in such memory type,
248        /// returning `VK_ERROR_FEATURE_NOT_PRESENT`.
249        const AMD_DEVICE_COHERENT_MEMORY = ffi::VmaAllocatorCreateFlagBits_VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT;
250        /// Enables usage of "buffer device address" feature, which allows you to use function
251        /// `vkGetBufferDeviceAddress*` to get raw GPU pointer to a buffer and pass it for usage inside a shader.
252        ///
253        /// You may set this flag only if you:
254        ///
255        /// 1. (For Vulkan version < 1.2) Found as available and enabled device extension
256        /// VK_KHR_buffer_device_address.
257        /// This extension is promoted to core Vulkan 1.2.
258        /// 2. Found as available and enabled device feature `VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress`.
259        ///
260        /// When this flag is set, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` using VMA.
261        /// The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT` to
262        /// allocated memory blocks wherever it might be needed.
263        ///
264        /// For more information, see documentation chapter \ref enabling_buffer_device_address.
265        const BUFFER_DEVICE_ADDRESS = ffi::VmaAllocatorCreateFlagBits_VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
266        /// Enables usage of VK_EXT_memory_priority extension in the library.
267        ///
268        /// You may set this flag only if you found available and enabled this device extension,
269        /// along with `VkPhysicalDeviceMemoryPriorityFeaturesEXT::memoryPriority == VK_TRUE`,
270        /// while creating Vulkan device passed as VmaAllocatorCreateInfo::device.
271        ///
272        /// When this flag is used, VmaAllocationCreateInfo::priority and VmaPoolCreateInfo::priority
273        /// are used to set priorities of allocated Vulkan memory. Without it, these variables are ignored.
274        ///
275        /// A priority must be a floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations.
276        /// Larger values are higher priority. The granularity of the priorities is implementation-dependent.
277        /// It is automatically passed to every call to `vkAllocateMemory` done by the library using structure `VkMemoryPriorityAllocateInfoEXT`.
278        /// The value to be used for default priority is 0.5.
279        /// For more details, see the documentation of the VK_EXT_memory_priority extension.
280        const EXT_MEMORY_PRIORITY = ffi::VmaAllocatorCreateFlagBits_VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT;
281    }
282}
283
284/// Construct `AllocatorCreateFlags` with default values
285impl Default for AllocatorCreateFlags {
286    fn default() -> Self {
287        AllocatorCreateFlags::NONE
288    }
289}
290
291/// Description of an `Allocator` to be created.
292pub struct AllocatorCreateInfo {
293    /// Vulkan physical device. It must be valid throughout whole lifetime of created allocator.
294    pub physical_device: erupt::vk::PhysicalDevice,
295
296    /// Vulkan device. It must be valid throughout whole lifetime of created allocator.
297    pub device: Arc<erupt::DeviceLoader>,
298
299    /// Vulkan instance. It must be valid throughout whole lifetime of created allocator.
300    pub instance: Arc<erupt::InstanceLoader>,
301
302    /// Flags for created allocator.
303    pub flags: AllocatorCreateFlags,
304
305    /// Preferred size of a single `erupt::vk::DeviceMemory` block to be allocated from large heaps > 1 GiB.
306    /// Set to 0 to use default, which is currently 256 MiB.
307    pub preferred_large_heap_block_size: usize,
308
309    /// Custom CPU memory allocation callbacks. Optional. Will be used for all CPU-side allocations.
310    pub allocation_callbacks: Option<erupt::vk::AllocationCallbacks>,
311
312    /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional.
313    pub device_memory_callbacks: Option<ffi::VmaDeviceMemoryCallbacks>,
314
315    /// Either empty or an array of limits on maximum number of bytes that can be allocated
316    /// out of particular Vulkan memory heap.
317    ///
318    /// If not empty, it must contain `erupt::vk::PhysicalDeviceMemoryProperties::memory_heap_count` elements,
319    /// defining limit on maximum number of bytes that can be allocated out of particular Vulkan
320    /// memory heap.
321    ///
322    /// Any of the elements may be equal to `erupt::vk::WHOLE_SIZE`, which means no limit on that
323    /// heap. This is also the default in case of an empty slice.
324    ///
325    /// If there is a limit defined for a heap:
326    ///
327    /// * If user tries to allocate more memory from that heap using this allocator, the allocation
328    /// fails with `erupt::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY`.
329    ///
330    /// * If the limit is smaller than heap size reported in `erupt::vk::MemoryHeap::size`, the value of this
331    /// limit will be reported instead when using `Allocator::get_memory_properties`.
332    ///
333    /// Warning! Using this feature may not be equivalent to installing a GPU with smaller amount of
334    /// memory, because graphics driver doesn't necessary fail new allocations with
335    /// `erupt::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is exceeded. It may return success
336    /// and just silently migrate some device memory" blocks to system RAM. This driver behavior can
337    /// also be controlled using the `VK_AMD_memory_overallocation_behavior` extension.
338    pub heap_size_limits: Option<Vec<erupt::vk::DeviceSize>>,
339
340    /// Optional. The highest version of Vulkan that the application is designed to use.
341    ///
342    /// It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`.
343    /// The patch version number specified is ignored. Only the major and minor versions are considered.
344    /// It must be less or equal (preferably equal) to value as passed to `vkCreateInstance` as `VkApplicationInfo::apiVersion`.
345    /// Only versions 1.0, 1.1, 1.2, 1.3 are supported by the current implementation.
346    /// Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`.
347    pub vulkan_api_version: u32,
348}
349
350// /// Construct `AllocatorCreateInfo` with default values
351// ///
352// /// Note that the default `device` and `instance` fields are filled with dummy
353// /// implementations that will panic if used. These fields must be overwritten.
354// impl Default for AllocatorCreateInfo {
355//     fn default() -> Self {
356//         extern "C" fn get_device_proc_addr(
357//             _: erupt::vk::Instance,
358//             _: *const std::os::raw::c_char,
359//         ) -> *const std::os::raw::c_void {
360//             std::ptr::null()
361//         }
362//         extern "C" fn get_instance_proc_addr(
363//             _: erupt::vk::Instance,
364//             _: *const std::os::raw::c_char,
365//         ) -> *const std::os::raw::c_void {
366//             get_device_proc_addr as *const _
367//         }
368//         let instance = Arc<>;
369//         let device = unsafe { Arc::new(DeviceLoader::) };
370//         AllocatorCreateInfo {
371//             physical_device: erupt::vk::PhysicalDevice::null(),
372//             device,
373//             instance,
374//             flags: AllocatorCreateFlags::NONE,
375//             preferred_large_heap_block_size: 0,
376//             frame_in_use_count: 0,
377//             heap_size_limits: None,
378//         }
379//     }
380// }
381
382/// Converts a raw result into an erupt result.
383#[inline]
384fn ffi_to_result(result: ffi::VkResult) -> erupt::vk::Result {
385    erupt::vk::Result(result)
386}
387
388/// Converts an `AllocationCreateInfo` struct into the raw representation.
389fn allocation_create_info_to_ffi(info: &AllocationCreateInfo) -> ffi::VmaAllocationCreateInfo {
390    ffi::VmaAllocationCreateInfo {
391        usage: info.usage as u32,
392        flags: info.flags.bits(),
393        requiredFlags: info.required_flags.bits(),
394        preferredFlags: info.preferred_flags.bits(),
395        memoryTypeBits: info.memory_type_bits,
396        pool: match &info.pool {
397            Some(pool) => pool.internal,
398            None => std::ptr::null_mut(),
399        },
400        pUserData: info.user_data.unwrap_or(::std::ptr::null_mut()),
401        priority: info.priority,
402    }
403}
404
405/// Converts an `AllocatorPoolCreateInfo` struct into the raw representation.
406fn pool_create_info_to_ffi(info: &AllocatorPoolCreateInfo) -> ffi::VmaPoolCreateInfo {
407    ffi::VmaPoolCreateInfo {
408        memoryTypeIndex: info.memory_type_index,
409        flags: info.flags.bits(),
410        blockSize: info.block_size as ffi::VkDeviceSize,
411        minBlockCount: info.min_block_count,
412        maxBlockCount: info.max_block_count,
413        minAllocationAlignment: info.min_allocation_alignment,
414        priority: info.priority,
415        pMemoryAllocateNext: std::ptr::null_mut(),
416    }
417}
418
419/// Intended usage of memory.
420#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)]
421#[repr(u32)]
422pub enum MemoryUsage {
423    /// No intended memory usage specified.
424    /// Use other members of `AllocationCreateInfo` to specify your requirements.
425    Unknown = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_UNKNOWN,
426
427    /// Memory will be used on device only, so fast access from the device is preferred.
428    /// It usually means device-local GPU (video) memory.
429    /// No need to be mappable on host.
430    /// It is roughly equivalent of `D3D12_HEAP_TYPE_DEFAULT`.
431    ///
432    /// Usage:
433    ///
434    /// - Resources written and read by device, e.g. images used as attachments.
435    /// - Resources transferred from host once (immutable) or infrequently and read by
436    ///   device multiple times, e.g. textures to be sampled, vertex buffers, uniform
437    ///   (constant) buffers, and majority of other types of resources used on GPU.
438    ///
439    /// Allocation may still end up in `erupt::vk::MemoryPropertyFlags::HOST_VISIBLE` memory on some implementations.
440    /// In such case, you are free to map it.
441    /// You can use `AllocationCreateFlags::MAPPED` with this usage type.
442    #[deprecated = "Obsolete, preserved for backward compatibility. Prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`."]
443    GpuOnly = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_GPU_ONLY,
444
445    /// Memory will be mappable on host.
446    /// It usually means CPU (system) memory.
447    /// Guarantees to be `erupt::vk::MemoryPropertyFlags::HOST_VISIBLE` and `erupt::vk::MemoryPropertyFlags::HOST_COHERENT`.
448    /// CPU access is typically uncached. Writes may be write-combined.
449    /// Resources created in this pool may still be accessible to the device, but access to them can be slow.
450    /// It is roughly equivalent of `D3D12_HEAP_TYPE_UPLOAD`.
451    ///
452    /// Usage: Staging copy of resources used as transfer source.
453    #[deprecated = "Obsolete, preserved for backward compatibility. Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` and `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`."]
454    CpuOnly = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_CPU_ONLY,
455
456    /// Memory that is both mappable on host (guarantees to be `erupt::vk::MemoryPropertyFlags::HOST_VISIBLE`) and preferably fast to access by GPU.
457    /// CPU access is typically uncached. Writes may be write-combined.
458    ///
459    /// Usage: Resources written frequently by host (dynamic), read by device. E.g. textures, vertex buffers,
460    /// uniform buffers updated every frame or every draw call.
461    #[deprecated = "Obsolete, preserved for backward compatibility. Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`."]
462    CpuToGpu = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_CPU_TO_GPU,
463
464    /// Memory mappable on host (guarantees to be `erupt::vk::MemoryPropertFlags::HOST_VISIBLE`) and cached.
465    /// It is roughly equivalent of `D3D12_HEAP_TYPE_READBACK`.
466    ///
467    /// Usage:
468    ///
469    /// - Resources written by device, read by host - results of some computations, e.g. screen capture, average scene luminance for HDR tone mapping.
470    /// - Any resources read or accessed randomly on host, e.g. CPU-side copy of vertex buffer used as source of transfer, but also used for collision detection.
471    #[deprecated = "Obsolete, preserved for backward compatibility. Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`."]
472    GpuToCpu = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_GPU_TO_CPU,
473
474    /// CPU memory - memory that is preferably not `DEVICE_LOCAL`, but also not guaranteed to be `HOST_VISIBLE`.
475    ///
476    /// Usage: Staging copy of resources moved from GPU memory to CPU memory as part
477    /// of custom paging/residency mechanism, to be moved back to GPU memory when needed.
478    #[deprecated = "Obsolete, preserved for backward compatibility. Prefers not `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`."]
479    CpuCopy = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_CPU_COPY,
480
481    /// Lazily allocated GPU memory having `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT`.
482    /// Exists mostly on mobile platforms. Using it on desktop PC or other GPUs with no such memory type present will fail the allocation.
483    ///
484    /// Usage: Memory for transient attachment images (color attachments, depth attachments etc.), created with `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`.
485    ///
486    /// Allocations with this usage are always created as dedicated - it implies #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT.
487    GpuLazilyAllocated = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED,
488
489    /// Selects best memory type automatically.
490    /// This flag is recommended for most common use cases.
491    ///
492    /// When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT),
493    /// you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT
494    /// in VmaAllocationCreateInfo::flags.
495    ///
496    /// It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g.
497    /// vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo()
498    /// and not with generic memory allocation functions.
499    Auto = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_AUTO,
500
501    /// Selects best memory type automatically with preference for GPU (device) memory.
502    ///
503    /// When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT),
504    /// you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT
505    /// in VmaAllocationCreateInfo::flags.
506    ///
507    /// It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g.
508    /// vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo()
509    /// and not with generic memory allocation functions.
510    AutoPreferDevice = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
511
512    /// Selects best memory type automatically with preference for CPU (host) memory.
513    ///
514    /// When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT),
515    /// you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT
516    /// in VmaAllocationCreateInfo::flags.
517    ///
518    /// It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g.
519    /// vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo()
520    /// and not with generic memory allocation functions.
521    AutoPreferHost = ffi::VmaMemoryUsage_VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
522}
523
524impl Default for MemoryUsage {
525    fn default() -> Self {
526        Self::Unknown
527    }
528}
529
530bitflags! {
531    /// Flags for configuring `AllocatorPool` construction.
532    pub struct AllocatorPoolCreateFlags: u32 {
533        const NONE = 0;
534
535        /// Use this flag if you always allocate only buffers and linear images or only optimal images
536        /// out of this pool and so buffer-image granularity can be ignored.
537        ///
538        /// This is an optional optimization flag.
539        ///
540        /// If you always allocate using `Allocator::create_buffer`, `Allocator::create_image`,
541        /// `Allocator::allocate_memory_for_buffer`, then you don't need to use it because allocator
542        /// knows exact type of your allocations so it can handle buffer-image granularity
543        /// in the optimal way.
544        ///
545        /// If you also allocate using `Allocator::allocate_memory_for_image` or `Allocator::allocate_memory`,
546        /// exact type of such allocations is not known, so allocator must be conservative
547        /// in handling buffer-image granularity, which can lead to suboptimal allocation
548        /// (wasted memory). In that case, if you can make sure you always allocate only
549        /// buffers and linear images or only optimal images out of this pool, use this flag
550        /// to make allocator disregard buffer-image granularity and so make allocations
551        /// faster and more optimal.
552        const IGNORE_BUFFER_IMAGE_GRANULARITY = ffi::VmaPoolCreateFlagBits_VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT;
553
554        /// Enables alternative, linear allocation algorithm in this pool.
555        ///
556        /// Specify this flag to enable linear allocation algorithm, which always creates
557        /// new allocations after last one and doesn't reuse space from allocations freed in
558        /// between. It trades memory consumption for simplified algorithm and data
559        /// structure, which has better performance and uses less memory for metadata.
560        ///
561        /// By using this flag, you can achieve behavior of free-at-once, stack,
562        /// ring buffer, and double stack.
563        const LINEAR_ALGORITHM = ffi::VmaPoolCreateFlagBits_VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT;
564
565
566        /// Bit mask to extract only `*_ALGORITHM` bits from entire set of flags.
567        const ALGORITHM_MASK = ffi::VmaPoolCreateFlagBits_VMA_POOL_CREATE_ALGORITHM_MASK;
568    }
569}
570
571impl Default for AllocatorPoolCreateFlags {
572    fn default() -> Self {
573        Self::NONE
574    }
575}
576
577bitflags! {
578    /// Flags for configuring `Allocation` construction.
579    pub struct AllocationCreateFlags: u32 {
580        /// Default configuration for allocation.
581        const NONE = 0x0000_0000;
582
583        /// Set this flag if the allocation should have its own memory block.
584        ///
585        /// Use it for special, big resources, like fullscreen images used as attachments.
586        ///
587        /// You should not use this flag if `AllocationCreateInfo::pool` is not `None`.
588        const DEDICATED_MEMORY = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
589
590        /// Set this flag to only try to allocate from existing `erupt::vk::DeviceMemory` blocks and never create new such block.
591        ///
592        /// If new allocation cannot be placed in any of the existing blocks, allocation
593        /// fails with `erupt::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY` error.
594        ///
595        /// You should not use `AllocationCreateFlags::DEDICATED_MEMORY` and `AllocationCreateFlags::NEVER_ALLOCATE` at the same time. It makes no sense.
596        ///
597        /// If `AllocationCreateInfo::pool` is not `None`, this flag is implied and ignored.
598        const NEVER_ALLOCATE = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT;
599
600        /// Set this flag to use a memory that will be persistently mapped and retrieve pointer to it.
601        ///
602        /// Pointer to mapped memory will be returned through `Allocation::get_mapped_data()`.
603        ///
604        /// Is it valid to use this flag for allocation made from memory type that is not
605        /// `erupt::vk::MemoryPropertyFlags::HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is
606        /// useful if you need an allocation that is efficient to use on GPU
607        /// (`erupt::vk::MemoryPropertyFlags::DEVICE_LOCAL`) and still want to map it directly if possible on platforms that
608        /// support it (e.g. Intel GPU).
609        const MAPPED = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_MAPPED_BIT;
610
611        /// Set this flag to treat `AllocationCreateInfo::user_data` as pointer to a
612        /// null-terminated string. Instead of copying pointer value, a local copy of the
613        /// string is made and stored in allocation's user data. The string is automatically
614        /// freed together with the allocation. It is also used in `Allocator::build_stats_string`.
615        #[deprecated = "Preserved for backward compatibility. Consider using vmaSetAllocationName() instead"]
616        const USER_DATA_COPY_STRING = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
617
618        /// Allocation will be created from upper stack in a double stack pool.
619        ///
620        /// This flag is only allowed for custom pools created with `AllocatorPoolCreateFlags::LINEAR_ALGORITHM` flag.
621        const UPPER_ADDRESS = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT;
622
623        /// Create both buffer/image and allocation, but don't bind them together.
624        /// It is useful when you want to bind yourself to do some more advanced binding, e.g. using some extensions.
625        /// The flag is meaningful only with functions that bind by default: vmaCreateBuffer(), vmaCreateImage().
626        /// Otherwise it is ignored.
627        ///
628        /// If you want to make sure the new buffer/image is not tied to the new memory allocation
629        /// through `VkMemoryDedicatedAllocateInfoKHR` structure in case the allocation ends up in its own memory block,
630        /// use also flag #VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT.
631        const DONT_BIND = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_DONT_BIND_BIT;
632
633        /// Create allocation only if additional device memory required for it, if any, won't exceed
634        /// memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`.
635        const WITHIN_BUDGET = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
636
637        /// Set this flag if the allocated memory will have aliasing resources.
638        ///
639        /// Usage of this flag prevents supplying `VkMemoryDedicatedAllocateInfoKHR` when #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT is specified.
640        /// Otherwise created dedicated memory will not be suitable for aliasing resources, resulting in Vulkan Validation Layer errors.
641        const CAN_ALIAS = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT;
642
643        /// Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT).
644        ///
645        /// - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value,
646        /// you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect.
647        /// - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`.
648        /// This includes allocations created in \ref custom_memory_pools.
649        ///
650        /// Declares that mapped memory will only be written sequentially, e.g. using `memcpy()` or a loop writing number-by-number,
651        /// never read or accessed randomly, so a memory type can be selected that is uncached and write-combined.
652        ///
653        /// Warning: Violating this declaration may work correctly, but will likely be very slow.
654        /// Watch out for implicit reads introduced by doing e.g. `pMappedData[i] += x;`
655        /// Better prepare your data in a local variable and `memcpy()` it to the mapped pointer all at once.
656        const HOST_ACCESS_SEQUENTIAL_WRITE = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
657
658        /// Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT).
659        ///
660        /// - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value,
661        /// you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect.
662        /// - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`.
663        /// This includes allocations created in \ref custom_memory_pools.
664        ///
665        /// Declares that mapped memory can be read, written, and accessed in random order,
666        /// so a `HOST_CACHED` memory type is required.
667        const HOST_ACCESS_RANDOM = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
668
669        /// Together with #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
670        /// it says that despite request for host access, a not-`HOST_VISIBLE` memory type can be selected
671        /// if it may improve performance.
672        ///
673        /// By using this flag, you declare that you will check if the allocation ended up in a `HOST_VISIBLE` memory type
674        /// (e.g. using vmaGetAllocationMemoryProperties()) and if not, you will create some "staging" buffer and
675        /// issue an explicit transfer to write/read your data.
676        /// To prepare for this possibility, don't forget to add appropriate flags like
677        /// `VK_BUFFER_USAGE_TRANSFER_DST_BIT`, `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` to the parameters of created buffer or image.
678        const HOST_ACCESS_ALLOW_TRANSFER_INSTEAD = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT;
679
680        /// Allocation strategy that chooses always the lowest offset in available space.
681        /// This is not the most efficient strategy but achieves highly packed data.
682        /// Used internally by defragmentation, not recomended in typical usage.
683        const STRATEGY_MIN_OFFSET = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT;
684
685        /// Allocation strategy that chooses smallest possible free range for the
686        /// allocation.
687        const STRATEGY_BEST_FIT = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT;
688
689        /// Allocation strategy that chooses first suitable free range for the
690        /// allocation.
691        ///
692        /// "First" doesn't necessarily means the one with smallest offset in memory,
693        /// but rather the one that is easiest and fastest to find.
694        const STRATEGY_FIRST_FIT = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT;
695
696        /// Allocation strategy that tries to minimize memory usage.
697        const STRATEGY_MIN_MEMORY = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT;
698
699        /// Allocation strategy that tries to minimize allocation time.
700        const STRATEGY_MIN_TIME = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT;
701
702        /// A bit mask to extract only `*_STRATEGY` bits from entire set of flags.
703        const STRATEGY_MASK = ffi::VmaAllocationCreateFlagBits_VMA_ALLOCATION_CREATE_STRATEGY_MASK;
704    }
705}
706
707impl Default for AllocationCreateFlags {
708    fn default() -> Self {
709        Self::NONE
710    }
711}
712
713/// Description of an `Allocation` to be created.
714#[derive(Default, Debug, Clone)]
715pub struct AllocationCreateInfo {
716    /// Flags for configuring the allocation
717    pub flags: AllocationCreateFlags,
718
719    /// Intended usage of memory.
720    ///
721    /// You can leave `MemoryUsage::UNKNOWN` if you specify memory requirements
722    /// in another way.
723    ///
724    /// If `pool` is not `None`, this member is ignored.
725    pub usage: MemoryUsage,
726
727    /// Flags that must be set in a Memory Type chosen for an allocation.
728    ///
729    /// Leave 0 if you specify memory requirements in other way.
730    ///
731    /// If `pool` is not `None`, this member is ignored.
732    pub required_flags: erupt::vk::MemoryPropertyFlags,
733
734    /// Flags that preferably should be set in a memory type chosen for an allocation.
735    ///
736    /// Set to 0 if no additional flags are prefered.
737    ///
738    /// If `pool` is not `None`, this member is ignored.
739    pub preferred_flags: erupt::vk::MemoryPropertyFlags,
740
741    /// Bit mask containing one bit set for every memory type acceptable for this allocation.
742    ///
743    /// Value 0 is equivalent to `std::u32::MAX` - it means any memory type is accepted if
744    /// it meets other requirements specified by this structure, with no further restrictions
745    /// on memory type index.
746    ///
747    /// If `pool` is not `None`, this member is ignored.
748    pub memory_type_bits: u32,
749
750    /// Pool that this allocation should be created in.
751    ///
752    /// Specify `None` to allocate from default pool. If not `None`, members:
753    /// `usage`, `required_flags`, `preferred_flags`, `memory_type_bits` are ignored.
754    pub pool: Option<AllocatorPool>,
755
756    /// Custom general-purpose pointer that will be stored in `Allocation`, can be read
757    /// as `Allocation::get_user_data()` and changed using `Allocator::set_allocation_user_data`.
758    ///
759    /// If `AllocationCreateFlags::USER_DATA_COPY_STRING` is used, it must be either null or pointer to a
760    /// null-terminated string. The string will be then copied to internal buffer, so it
761    /// doesn't need to be valid after allocation call.
762    pub user_data: Option<*mut ::std::os::raw::c_void>,
763
764    /// A floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations.
765    ///
766    /// It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object
767    /// and this allocation ends up as dedicated or is explicitly forced as dedicated using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT.
768    /// Otherwise, it has the priority of a memory block where it is placed and this variable is ignored.
769    pub priority: f32,
770}
771
772/// Description of an `AllocationPool` to be created.
773#[derive(Default, Debug, Clone)]
774pub struct AllocatorPoolCreateInfo {
775    /// Vulkan memory type index to allocate this pool from.
776    pub memory_type_index: u32,
777
778    /// Use combination of `AllocatorPoolCreateFlags`
779    pub flags: AllocatorPoolCreateFlags,
780
781    /// Size of a single `erupt::vk::DeviceMemory` block to be allocated as part of this
782    /// pool, in bytes.
783    ///
784    /// Specify non-zero to set explicit, constant size of memory blocks used by
785    /// this pool.
786    ///
787    /// Leave 0 to use default and let the library manage block sizes automatically.
788    /// Sizes of particular blocks may vary.
789    pub block_size: usize,
790
791    /// Minimum number of blocks to be always allocated in this pool, even if they stay empty.
792    ///
793    /// Set to 0 to have no preallocated blocks and allow the pool be completely empty.
794    pub min_block_count: usize,
795
796    /// Maximum number of blocks that can be allocated in this pool.
797    ///
798    /// Set to 0 to use default, which is no limit.
799    ///
800    /// Set to same value as `AllocatorPoolCreateInfo::min_block_count` to have fixed amount
801    /// of memory allocated throughout whole lifetime of this pool.
802    pub max_block_count: usize,
803
804    /// A floating-point value between 0 and 1, indicating the priority of the allocations in this pool relative to other memory allocations.
805    ///
806    /// It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object.
807    /// Otherwise, this variable is ignored.
808    pub priority: f32,
809
810    /// \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0.
811    ///
812    /// Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two.
813    /// It can be useful in cases where alignment returned by Vulkan by functions like `vkGetBufferMemoryRequirements` is not enough,
814    /// e.g. when doing interop with OpenGL.
815    pub min_allocation_alignment: erupt::vk::DeviceSize,
816}
817
818bitflags! {
819    /// Flags for configuring the defragmentation process.
820    pub struct DefragmentationFlags: u32 {
821        /// Default configuration for allocation.
822        const NONE = 0x0000_0000;
823
824        /// Use simple but fast algorithm for defragmentation.
825        /// May not achieve best results but will require least time to compute and least allocations to copy.
826        const ALGORITHM_FAST = ffi::VmaDefragmentationFlagBits_VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT;
827        /// Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified.
828        /// Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved.
829        const ALGORITHM_BALANCED = ffi::VmaDefragmentationFlagBits_VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT;
830        /// Perform full defragmentation of memory.
831        /// Can result in notably more time to compute and allocations to copy, but will achieve best memory packing.
832        const ALGORITHM_FULL = ffi::VmaDefragmentationFlagBits_VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT;
833        /// Use the most roboust algorithm at the cost of time to compute and number of copies to make.
834        /// Only available when bufferImageGranularity is greater than 1, since it aims to reduce
835        /// alignment issues between different types of resources.
836        /// Otherwise falls back to same behavior as #VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT.
837        const ALGORITHM_EXTENSIVE = ffi::VmaDefragmentationFlagBits_VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT;
838
839        /// A bit mask to extract only `ALGORITHM` bits from entire set of flags.
840        const ALGORITHM_MASK = ffi::VmaDefragmentationFlagBits_VMA_DEFRAGMENTATION_FLAG_ALGORITHM_MASK;
841    }
842}
843
844impl Default for DefragmentationFlags {
845    fn default() -> Self {
846        Self::NONE
847    }
848}
849
850/// Operation performed on single defragmentation move.
851#[repr(u32)]
852#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
853pub enum DefragmentationMoveOperation {
854    /// Buffer/image has been recreated at `dstTmpAllocation`, data has been copied, old buffer/image has been destroyed. `srcAllocation` should be changed to point to the new place. This is the default value set by vmaBeginDefragmentationPass().
855    Copy = ffi::VmaDefragmentationMoveOperation_VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY,
856    /// Set this value if you cannot move the allocation. New place reserved at `dstTmpAllocation` will be freed. `srcAllocation` will remain unchanged.
857    Ignore = ffi::VmaDefragmentationMoveOperation_VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE,
858    /// Set this value if you decide to abandon the allocation and you destroyed the buffer/image. New place reserved at `dstTmpAllocation` will be freed, along with `srcAllocation`, which will be destroyed.
859    Destroy = ffi::VmaDefragmentationMoveOperation_VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY,
860}
861
862impl TryFrom<u32> for DefragmentationMoveOperation {
863    type Error = u32;
864
865    fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
866        if value == Self::Copy as u32 {
867            Ok(Self::Copy)
868        } else if value == Self::Ignore as u32 {
869            Ok(Self::Ignore)
870        } else if value == Self::Destroy as u32 {
871            Ok(Self::Destroy)
872        } else {
873            Err(value)
874        }
875    }
876}
877
878impl Default for DefragmentationMoveOperation {
879    fn default() -> Self {
880        Self::Ignore
881    }
882}
883
884#[derive(Debug)]
885pub struct DefragmentationContext {
886    internal: ffi::VmaDefragmentationContext,
887}
888
889/// Parameters for defragmentation.
890///
891/// To be used with function `Allocator::defragmentation_begin`.
892#[derive(Debug, Clone)]
893pub struct DefragmentationInfo {
894    /// See `DefragmentationFlags`
895    pub flags: DefragmentationFlags,
896
897    /// Custom pool to be defragmented.
898    ///
899    /// If `None` then default pools will undergo defragmentation process.
900    pub pool: Option<AllocatorPool>,
901
902    /// Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places.
903    ///
904    /// `0` means no limit.
905    pub max_bytes_per_pass: erupt::vk::DeviceSize,
906
907    /// Maximum number of allocations that can be moved during single pass to a different place.
908    ///
909    /// `0` means no limit.
910    pub max_allocations_per_pass: u32,
911}
912
913/// Single move of an allocation to be done for defragmentation.
914#[derive(Debug, Clone)]
915pub struct DefragmentationMove {
916    /// Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it.
917    pub operation: DefragmentationMoveOperation,
918    /// Allocation that should be moved.
919    pub src_allocation: Allocation,
920    /// Temporary allocation pointing to destination memory that will replace `srcAllocation`.
921    ///
922    /// Warning: Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass,
923    /// to be used for binding new buffer/image to the destination memory using e.g. vmaBindBufferMemory().
924    /// vmaEndDefragmentationPass() will destroy it and make `srcAllocation` point to this memory.
925    pub dst_tmp_allocation: Allocation,
926}
927
928pub enum DefragmentationPassResult {
929    /// No more moves are possible. You can omit call to vmaEndDefragmentationPass() and simply end whole defragmentation.
930    Success,
931    /// There are pending moves returned. You need to perform them, call vmaEndDefragmentationPass(), and then preferably try another pass with vmaBeginDefragmentationPass().
932    Incomplete(DefragmentationPassMoveInfo),
933}
934
935/// Parameters for incremental defragmentation steps.
936///
937/// To be used with function `Allocator::defragmentation_begin_pass`.
938#[derive(Debug, Clone)]
939pub struct DefragmentationPassMoveInfo {
940    internal: ffi::VmaDefragmentationPassMoveInfo,
941    moves: Box<[DefragmentationMove]>,
942}
943
944// Slice accessors that prevent changing the array length
945impl DefragmentationPassMoveInfo {
946    pub fn moves(&self) -> &[DefragmentationMove] {
947        &self.moves
948    }
949    pub fn moves_mut(&mut self) -> &mut [DefragmentationMove] {
950        &mut self.moves
951    }
952}
953
954/// Statistics returned by `Allocator::defragment`
955#[derive(Debug, Copy, Clone)]
956pub struct DefragmentationStats {
957    /// Total number of bytes that have been copied while moving allocations to different places.
958    pub bytes_moved: usize,
959
960    /// Total number of bytes that have been released to the system by freeing empty `erupt::vk::DeviceMemory` objects.
961    pub bytes_freed: usize,
962
963    /// Number of allocations that have been moved to different places.
964    pub allocations_moved: u32,
965
966    /// Number of empty `erupt::vk::DeviceMemory` objects that have been released to the system.
967    pub device_memory_blocks_freed: u32,
968}
969
970impl Allocator {
971    /// Constructor a new `Allocator` using the provided options.
972    pub fn new(create_info: &AllocatorCreateInfo) -> Result<Self> {
973        let instance = create_info.instance.clone();
974        let device = create_info.device.clone();
975        let routed_functions = unsafe {
976            ffi::VmaVulkanFunctions {
977                vkGetInstanceProcAddr: mem::transmute::<_, ffi::PFN_vkGetInstanceProcAddr>(
978                    instance.get_instance_proc_addr,
979                ),
980                vkGetDeviceProcAddr: mem::transmute::<_, ffi::PFN_vkGetDeviceProcAddr>(
981                    instance.get_device_proc_addr,
982                ),
983                vkGetPhysicalDeviceProperties: mem::transmute::<
984                    _,
985                    ffi::PFN_vkGetPhysicalDeviceProperties,
986                >(
987                    instance.get_physical_device_properties
988                ),
989                vkGetPhysicalDeviceMemoryProperties: mem::transmute::<
990                    _,
991                    ffi::PFN_vkGetPhysicalDeviceMemoryProperties,
992                >(
993                    instance.get_physical_device_memory_properties,
994                ),
995                vkAllocateMemory: mem::transmute::<_, ffi::PFN_vkAllocateMemory>(
996                    device.allocate_memory,
997                ),
998                vkFreeMemory: mem::transmute::<_, ffi::PFN_vkFreeMemory>(device.free_memory),
999                vkMapMemory: mem::transmute::<_, ffi::PFN_vkMapMemory>(device.map_memory),
1000                vkUnmapMemory: mem::transmute::<_, ffi::PFN_vkUnmapMemory>(device.unmap_memory),
1001                vkFlushMappedMemoryRanges: mem::transmute::<_, ffi::PFN_vkFlushMappedMemoryRanges>(
1002                    device.flush_mapped_memory_ranges,
1003                ),
1004                vkInvalidateMappedMemoryRanges: mem::transmute::<
1005                    _,
1006                    ffi::PFN_vkInvalidateMappedMemoryRanges,
1007                >(
1008                    device.invalidate_mapped_memory_ranges
1009                ),
1010                vkBindBufferMemory: mem::transmute::<_, ffi::PFN_vkBindBufferMemory>(
1011                    device.bind_buffer_memory,
1012                ),
1013                vkBindBufferMemory2KHR: mem::transmute::<_, ffi::PFN_vkBindBufferMemory2KHR>(
1014                    device.bind_buffer_memory2,
1015                ),
1016                vkBindImageMemory: mem::transmute::<_, ffi::PFN_vkBindImageMemory>(
1017                    device.bind_image_memory,
1018                ),
1019                vkBindImageMemory2KHR: mem::transmute::<_, ffi::PFN_vkBindImageMemory2KHR>(
1020                    device.bind_image_memory2,
1021                ),
1022                vkGetBufferMemoryRequirements: mem::transmute::<
1023                    _,
1024                    ffi::PFN_vkGetBufferMemoryRequirements,
1025                >(
1026                    device.get_buffer_memory_requirements
1027                ),
1028                vkGetImageMemoryRequirements: mem::transmute::<
1029                    _,
1030                    ffi::PFN_vkGetImageMemoryRequirements,
1031                >(
1032                    device.get_image_memory_requirements
1033                ),
1034                vkCreateBuffer: mem::transmute::<_, ffi::PFN_vkCreateBuffer>(device.create_buffer),
1035                vkDestroyBuffer: mem::transmute::<_, ffi::PFN_vkDestroyBuffer>(
1036                    device.destroy_buffer,
1037                ),
1038                vkCreateImage: mem::transmute::<_, ffi::PFN_vkCreateImage>(device.create_image),
1039                vkDestroyImage: mem::transmute::<_, ffi::PFN_vkDestroyImage>(device.destroy_image),
1040                vkCmdCopyBuffer: mem::transmute::<_, ffi::PFN_vkCmdCopyBuffer>(
1041                    device.cmd_copy_buffer,
1042                ),
1043                vkGetBufferMemoryRequirements2KHR: mem::transmute::<
1044                    _,
1045                    ffi::PFN_vkGetBufferMemoryRequirements2KHR,
1046                >(
1047                    device.get_buffer_memory_requirements2
1048                ),
1049                vkGetImageMemoryRequirements2KHR: mem::transmute::<
1050                    _,
1051                    ffi::PFN_vkGetImageMemoryRequirements2KHR,
1052                >(
1053                    device.get_image_memory_requirements2
1054                ),
1055                vkGetPhysicalDeviceMemoryProperties2KHR: mem::transmute::<
1056                    _,
1057                    ffi::PFN_vkGetPhysicalDeviceMemoryProperties2KHR,
1058                >(
1059                    instance.get_physical_device_properties2
1060                ),
1061                vkGetDeviceBufferMemoryRequirements: mem::transmute::<
1062                    _,
1063                    ffi::PFN_vkGetDeviceBufferMemoryRequirements,
1064                >(
1065                    device.get_device_buffer_memory_requirements
1066                ),
1067                vkGetDeviceImageMemoryRequirements: mem::transmute::<
1068                    _,
1069                    ffi::PFN_vkGetDeviceImageMemoryRequirements,
1070                >(
1071                    device.get_device_image_memory_requirements
1072                ),
1073            }
1074        };
1075        let ffi_create_info = ffi::VmaAllocatorCreateInfo {
1076            physicalDevice: create_info.physical_device.to_raw() as ffi::VkPhysicalDevice,
1077            device: create_info.device.handle.to_raw() as ffi::VkDevice,
1078            instance: instance.handle.to_raw() as ffi::VkInstance,
1079            flags: create_info.flags.bits(),
1080            preferredLargeHeapBlockSize: create_info.preferred_large_heap_block_size as u64,
1081            pHeapSizeLimit: match &create_info.heap_size_limits {
1082                None => ::std::ptr::null(),
1083                Some(limits) => limits.as_ptr(),
1084            },
1085            pVulkanFunctions: &routed_functions,
1086            // Safety: identical structs with repr(C) layouts
1087            pAllocationCallbacks: if let Some(cbs) = create_info.allocation_callbacks.as_ref() {
1088                unsafe { std::mem::transmute(cbs as *const _) }
1089            } else {
1090                std::ptr::null()
1091            },
1092            pDeviceMemoryCallbacks: if let Some(cbs) = create_info.device_memory_callbacks.as_ref()
1093            {
1094                cbs as *const _
1095            } else {
1096                std::ptr::null()
1097            },
1098            vulkanApiVersion: create_info.vulkan_api_version,
1099            pTypeExternalMemoryHandleTypes: ::std::ptr::null(), // TODO: Make configurable
1100        };
1101        let mut internal: ffi::VmaAllocator = std::ptr::null_mut();
1102        let result = ffi_to_result(unsafe {
1103            ffi::vmaCreateAllocator(
1104                &ffi_create_info as *const ffi::VmaAllocatorCreateInfo,
1105                &mut internal,
1106            )
1107        });
1108        match result {
1109            erupt::vk::Result::SUCCESS => Ok(Allocator {
1110                internal,
1111                instance,
1112                device,
1113            }),
1114            _ => Err(Error::vulkan(result)),
1115        }
1116    }
1117
1118    /// The allocator fetches `erupt::vk::PhysicalDeviceProperties` from the physical device.
1119    /// You can get it here, without fetching it again on your own.
1120    pub fn get_physical_device_properties(&self) -> Result<erupt::vk::PhysicalDeviceProperties> {
1121        let mut ffi_properties: *const ffi::VkPhysicalDeviceProperties = std::ptr::null();
1122        Ok(unsafe {
1123            ffi::vmaGetPhysicalDeviceProperties(self.internal, &mut ffi_properties);
1124            mem::transmute::<ffi::VkPhysicalDeviceProperties, erupt::vk::PhysicalDeviceProperties>(
1125                *ffi_properties,
1126            )
1127        })
1128    }
1129
1130    /// The allocator fetches `erupt::vk::PhysicalDeviceMemoryProperties` from the physical device.
1131    /// You can get it here, without fetching it again on your own.
1132    pub fn get_memory_properties(&self) -> Result<erupt::vk::PhysicalDeviceMemoryProperties> {
1133        let mut ffi_properties: *const ffi::VkPhysicalDeviceMemoryProperties = std::ptr::null();
1134        Ok(unsafe {
1135            ffi::vmaGetMemoryProperties(self.internal, &mut ffi_properties);
1136            mem::transmute::<
1137                ffi::VkPhysicalDeviceMemoryProperties,
1138                erupt::vk::PhysicalDeviceMemoryProperties,
1139            >(*ffi_properties)
1140        })
1141    }
1142
1143    /// Given a memory type index, returns `erupt::vk::MemoryPropertyFlags` of this memory type.
1144    ///
1145    /// This is just a convenience function; the same information can be obtained using
1146    /// `Allocator::get_memory_properties`.
1147    pub fn get_memory_type_properties(
1148        &self,
1149        memory_type_index: u32,
1150    ) -> Result<erupt::vk::MemoryPropertyFlags> {
1151        let mut ffi_properties: ffi::VkMemoryPropertyFlags = Default::default();
1152        Ok(unsafe {
1153            ffi::vmaGetMemoryTypeProperties(self.internal, memory_type_index, &mut ffi_properties);
1154            mem::transmute::<ffi::VkMemoryPropertyFlags, erupt::vk::MemoryPropertyFlags>(
1155                ffi_properties,
1156            )
1157        })
1158    }
1159
1160    /// Sets index of the current frame.
1161    ///
1162    /// This function must be used if you make allocations with `AllocationCreateFlags::CAN_BECOME_LOST` and
1163    /// `AllocationCreateFlags::CAN_MAKE_OTHER_LOST` flags to inform the allocator when a new frame begins.
1164    /// Allocations queried using `Allocator::get_allocation_info` cannot become lost
1165    /// in the current frame.
1166    pub fn set_current_frame_index(&self, frame_index: u32) {
1167        unsafe {
1168            ffi::vmaSetCurrentFrameIndex(self.internal, frame_index);
1169        }
1170    }
1171
1172    /// Retrieves statistics from current state of the `Allocator`.
1173    pub fn calculate_statistics(&self) -> Result<ffi::VmaTotalStatistics> {
1174        let mut vma_stats: ffi::VmaTotalStatistics = Default::default();
1175        unsafe {
1176            ffi::vmaCalculateStatistics(self.internal, &mut vma_stats as *mut _);
1177        }
1178        Ok(vma_stats)
1179    }
1180
1181    /// Builds and returns statistics in `JSON` format.
1182    pub fn build_stats_string(&self, detailed_map: bool) -> Result<String> {
1183        let mut stats_string: *mut ::std::os::raw::c_char = ::std::ptr::null_mut();
1184        unsafe {
1185            ffi::vmaBuildStatsString(
1186                self.internal,
1187                &mut stats_string,
1188                if detailed_map { 1 } else { 0 },
1189            );
1190        }
1191        Ok(if stats_string.is_null() {
1192            String::new()
1193        } else {
1194            let result = unsafe {
1195                std::ffi::CStr::from_ptr(stats_string)
1196                    .to_string_lossy()
1197                    .into_owned()
1198            };
1199            unsafe {
1200                ffi::vmaFreeStatsString(self.internal, stats_string);
1201            }
1202            result
1203        })
1204    }
1205
1206    /// Helps to find memory type index, given memory type bits and allocation info.
1207    ///
1208    /// This algorithm tries to find a memory type that:
1209    ///
1210    /// - Is allowed by memory type bits.
1211    /// - Contains all the flags from `allocation_info.required_flags`.
1212    /// - Matches intended usage.
1213    /// - Has as many flags from `allocation_info.preferred_flags` as possible.
1214    ///
1215    /// Returns erupt::vk::Result::ERROR_FEATURE_NOT_PRESENT if not found. Receiving such a result
1216    /// from this function or any other allocating function probably means that your
1217    /// device doesn't support any memory type with requested features for the specific
1218    /// type of resource you want to use it for. Please check parameters of your
1219    /// resource, like image layout (OPTIMAL versus LINEAR) or mip level count.
1220    pub fn find_memory_type_index(
1221        &self,
1222        memory_type_bits: u32,
1223        allocation_info: &AllocationCreateInfo,
1224    ) -> Result<u32> {
1225        let create_info = allocation_create_info_to_ffi(allocation_info);
1226        let mut memory_type_index: u32 = 0;
1227        let result = ffi_to_result(unsafe {
1228            ffi::vmaFindMemoryTypeIndex(
1229                self.internal,
1230                memory_type_bits,
1231                &create_info,
1232                &mut memory_type_index,
1233            )
1234        });
1235        match result {
1236            erupt::vk::Result::SUCCESS => Ok(memory_type_index),
1237            _ => Err(Error::vulkan(result)),
1238        }
1239    }
1240
1241    /// Helps to find memory type index, given buffer info and allocation info.
1242    ///
1243    /// It can be useful e.g. to determine value to be used as `AllocatorPoolCreateInfo::memory_type_index`.
1244    /// It internally creates a temporary, dummy buffer that never has memory bound.
1245    /// It is just a convenience function, equivalent to calling:
1246    ///
1247    /// - `erupt::vk::Device::create_buffer`
1248    /// - `erupt::vk::Device::get_buffer_memory_requirements`
1249    /// - `Allocator::find_memory_type_index`
1250    /// - `erupt::vk::Device::destroy_buffer`
1251    pub fn find_memory_type_index_for_buffer_info(
1252        &self,
1253        buffer_info: &erupt::vk::BufferCreateInfo,
1254        allocation_info: &AllocationCreateInfo,
1255    ) -> Result<u32> {
1256        let allocation_create_info = allocation_create_info_to_ffi(allocation_info);
1257        let buffer_create_info = unsafe {
1258            mem::transmute::<erupt::vk::BufferCreateInfo, ffi::VkBufferCreateInfo>(*buffer_info)
1259        };
1260        let mut memory_type_index: u32 = 0;
1261        let result = ffi_to_result(unsafe {
1262            ffi::vmaFindMemoryTypeIndexForBufferInfo(
1263                self.internal,
1264                &buffer_create_info,
1265                &allocation_create_info,
1266                &mut memory_type_index,
1267            )
1268        });
1269        match result {
1270            erupt::vk::Result::SUCCESS => Ok(memory_type_index),
1271            _ => Err(Error::vulkan(result)),
1272        }
1273    }
1274
1275    /// Helps to find memory type index, given image info and allocation info.
1276    ///
1277    /// It can be useful e.g. to determine value to be used as `AllocatorPoolCreateInfo::memory_type_index`.
1278    /// It internally creates a temporary, dummy image that never has memory bound.
1279    /// It is just a convenience function, equivalent to calling:
1280    ///
1281    /// - `erupt::vk::Device::create_image`
1282    /// - `erupt::vk::Device::get_image_memory_requirements`
1283    /// - `Allocator::find_memory_type_index`
1284    /// - `erupt::vk::Device::destroy_image`
1285    pub fn find_memory_type_index_for_image_info(
1286        &self,
1287        image_info: &erupt::vk::ImageCreateInfo,
1288        allocation_info: &AllocationCreateInfo,
1289    ) -> Result<u32> {
1290        let allocation_create_info = allocation_create_info_to_ffi(allocation_info);
1291        let image_create_info = unsafe {
1292            mem::transmute::<erupt::vk::ImageCreateInfo, ffi::VkImageCreateInfo>(*image_info)
1293        };
1294        let mut memory_type_index: u32 = 0;
1295        let result = ffi_to_result(unsafe {
1296            ffi::vmaFindMemoryTypeIndexForImageInfo(
1297                self.internal,
1298                &image_create_info,
1299                &allocation_create_info,
1300                &mut memory_type_index,
1301            )
1302        });
1303        match result {
1304            erupt::vk::Result::SUCCESS => Ok(memory_type_index),
1305            _ => Err(Error::vulkan(result)),
1306        }
1307    }
1308
1309    /// Allocates Vulkan device memory and creates `AllocatorPool` object.
1310    pub fn create_pool(&self, pool_info: &AllocatorPoolCreateInfo) -> Result<AllocatorPool> {
1311        let mut ffi_pool: ffi::VmaPool = std::ptr::null_mut();
1312        let create_info = pool_create_info_to_ffi(pool_info);
1313        let result = ffi_to_result(unsafe {
1314            ffi::vmaCreatePool(self.internal, &create_info, &mut ffi_pool)
1315        });
1316        match result {
1317            erupt::vk::Result::SUCCESS => Ok(AllocatorPool { internal: ffi_pool }),
1318            _ => Err(Error::vulkan(result)),
1319        }
1320    }
1321
1322    /// Destroys `AllocatorPool` object and frees Vulkan device memory.
1323    pub fn destroy_pool(&self, pool: &AllocatorPool) {
1324        unsafe {
1325            ffi::vmaDestroyPool(self.internal, pool.internal);
1326        }
1327    }
1328
1329    /// Retrieves statistics of existing `AllocatorPool` object.
1330    pub fn get_pool_stats(&self, pool: &AllocatorPool) -> Result<ffi::VmaStatistics> {
1331        let mut pool_stats: ffi::VmaStatistics = Default::default();
1332        unsafe {
1333            ffi::vmaGetPoolStatistics(self.internal, pool.internal, &mut pool_stats);
1334        }
1335        Ok(pool_stats)
1336    }
1337
1338    /// Checks magic number in margins around all allocations in given memory pool in search for corruptions.
1339    ///
1340    /// Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero,
1341    /// `VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is
1342    /// `erupt::vk::MemoryPropertyFlags::HOST_VISIBLE` and `erupt::vk::MemoryPropertyFlags::HOST_COHERENT`.
1343    ///
1344    /// Possible error values:
1345    ///
1346    /// - `erupt::vk::Result::ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool.
1347    /// - `erupt::vk::Result::ERROR_VALIDATION_FAILED_EXT` - corruption detection has been performed and found memory corruptions around one of the allocations.
1348    ///   `VMA_ASSERT` is also fired in that case.
1349    /// - Other value: Error returned by Vulkan, e.g. memory mapping failure.
1350    pub fn check_pool_corruption(&self, pool: &AllocatorPool) -> Result<()> {
1351        let result =
1352            ffi_to_result(unsafe { ffi::vmaCheckPoolCorruption(self.internal, pool.internal) });
1353        match result {
1354            erupt::vk::Result::SUCCESS => Ok(()),
1355            _ => Err(Error::vulkan(result)),
1356        }
1357    }
1358
1359    /// General purpose memory allocation.
1360    ///
1361    /// You should free the memory using `Allocator::free_memory` or 'Allocator::free_memory_pages'.
1362    ///
1363    /// It is recommended to use `Allocator::allocate_memory_for_buffer`, `Allocator::allocate_memory_for_image`,
1364    /// `Allocator::create_buffer`, `Allocator::create_image` instead whenever possible.
1365    pub fn allocate_memory(
1366        &self,
1367        memory_requirements: &erupt::vk::MemoryRequirements,
1368        allocation_info: &AllocationCreateInfo,
1369    ) -> Result<(Allocation, AllocationInfo)> {
1370        let ffi_requirements = unsafe {
1371            mem::transmute::<erupt::vk::MemoryRequirements, ffi::VkMemoryRequirements>(
1372                *memory_requirements,
1373            )
1374        };
1375        let create_info = allocation_create_info_to_ffi(allocation_info);
1376        let mut allocation: Allocation = Default::default();
1377        let mut allocation_info: AllocationInfo = Default::default();
1378        let result = ffi_to_result(unsafe {
1379            ffi::vmaAllocateMemory(
1380                self.internal,
1381                &ffi_requirements,
1382                &create_info,
1383                &mut allocation.internal,
1384                &mut allocation_info.internal,
1385            )
1386        });
1387        match result {
1388            erupt::vk::Result::SUCCESS => Ok((allocation, allocation_info)),
1389            _ => Err(Error::vulkan(result)),
1390        }
1391    }
1392
1393    /// General purpose memory allocation for multiple allocation objects at once.
1394    ///
1395    /// You should free the memory using `Allocator::free_memory` or `Allocator::free_memory_pages`.
1396    ///
1397    /// Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding.
1398    /// It is just a general purpose allocation function able to make multiple allocations at once.
1399    /// It may be internally optimized to be more efficient than calling `Allocator::allocate_memory` `allocations.len()` times.
1400    ///
1401    /// All allocations are made using same parameters. All of them are created out of the same memory pool and type.
1402    pub fn allocate_memory_pages(
1403        &self,
1404        memory_requirements: &erupt::vk::MemoryRequirements,
1405        allocation_info: &AllocationCreateInfo,
1406        allocation_count: usize,
1407    ) -> Result<Vec<(Allocation, AllocationInfo)>> {
1408        let ffi_requirements = unsafe {
1409            mem::transmute::<erupt::vk::MemoryRequirements, ffi::VkMemoryRequirements>(
1410                *memory_requirements,
1411            )
1412        };
1413        let create_info = allocation_create_info_to_ffi(allocation_info);
1414        let mut allocations: Vec<ffi::VmaAllocation> = vec![std::ptr::null_mut(); allocation_count];
1415        let mut allocation_info: Vec<ffi::VmaAllocationInfo> =
1416            vec![Default::default(); allocation_count];
1417        let result = ffi_to_result(unsafe {
1418            ffi::vmaAllocateMemoryPages(
1419                self.internal,
1420                &ffi_requirements,
1421                &create_info,
1422                allocation_count,
1423                allocations.as_mut_ptr(),
1424                allocation_info.as_mut_ptr(),
1425            )
1426        });
1427        match result {
1428            erupt::vk::Result::SUCCESS => {
1429                let it = allocations.iter().zip(allocation_info.iter());
1430                let allocations: Vec<(Allocation, AllocationInfo)> = it
1431                    .map(|(alloc, info)| {
1432                        (
1433                            Allocation { internal: *alloc },
1434                            AllocationInfo { internal: *info },
1435                        )
1436                    })
1437                    .collect();
1438                Ok(allocations)
1439            }
1440            _ => Err(Error::vulkan(result)),
1441        }
1442    }
1443
1444    /// Buffer specialized memory allocation.
1445    ///
1446    /// You should free the memory using `Allocator::free_memory` or 'Allocator::free_memory_pages'.
1447    pub fn allocate_memory_for_buffer(
1448        &self,
1449        buffer: erupt::vk::Buffer,
1450        allocation_info: &AllocationCreateInfo,
1451    ) -> Result<(Allocation, AllocationInfo)> {
1452        let ffi_buffer = buffer.to_raw() as ffi::VkBuffer;
1453        let create_info = allocation_create_info_to_ffi(allocation_info);
1454        let mut allocation: Allocation = Default::default();
1455        let mut allocation_info: AllocationInfo = Default::default();
1456        let result = ffi_to_result(unsafe {
1457            ffi::vmaAllocateMemoryForBuffer(
1458                self.internal,
1459                ffi_buffer,
1460                &create_info,
1461                &mut allocation.internal,
1462                &mut allocation_info.internal,
1463            )
1464        });
1465        match result {
1466            erupt::vk::Result::SUCCESS => Ok((allocation, allocation_info)),
1467            _ => Err(Error::vulkan(result)),
1468        }
1469    }
1470
1471    /// Image specialized memory allocation.
1472    ///
1473    /// You should free the memory using `Allocator::free_memory` or 'Allocator::free_memory_pages'.
1474    pub fn allocate_memory_for_image(
1475        &self,
1476        image: erupt::vk::Image,
1477        allocation_info: &AllocationCreateInfo,
1478    ) -> Result<(Allocation, AllocationInfo)> {
1479        let ffi_image = image.to_raw() as ffi::VkImage;
1480        let create_info = allocation_create_info_to_ffi(allocation_info);
1481        let mut allocation: Allocation = Default::default();
1482        let mut allocation_info: AllocationInfo = Default::default();
1483        let result = ffi_to_result(unsafe {
1484            ffi::vmaAllocateMemoryForImage(
1485                self.internal,
1486                ffi_image,
1487                &create_info,
1488                &mut allocation.internal,
1489                &mut allocation_info.internal,
1490            )
1491        });
1492        match result {
1493            erupt::vk::Result::SUCCESS => Ok((allocation, allocation_info)),
1494            _ => Err(Error::vulkan(result)),
1495        }
1496    }
1497
1498    /// Frees memory previously allocated using `Allocator::allocate_memory`,
1499    /// `Allocator::allocate_memory_for_buffer`, or `Allocator::allocate_memory_for_image`.
1500    pub fn free_memory(&self, allocation: &Allocation) {
1501        unsafe {
1502            ffi::vmaFreeMemory(self.internal, allocation.internal);
1503        }
1504    }
1505
1506    /// Frees memory and destroys multiple allocations.
1507    ///
1508    /// Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding.
1509    /// It is just a general purpose function to free memory and destroy allocations made using e.g. `Allocator::allocate_memory',
1510    /// 'Allocator::allocate_memory_pages` and other functions.
1511    ///
1512    /// It may be internally optimized to be more efficient than calling 'Allocator::free_memory` `allocations.len()` times.
1513    ///
1514    /// Allocations in 'allocations' slice can come from any memory pools and types.
1515    pub fn free_memory_pages(&self, allocations: &[Allocation]) {
1516        let mut allocations_ffi: Vec<ffi::VmaAllocation> =
1517            allocations.iter().map(|x| x.internal).collect();
1518        unsafe {
1519            ffi::vmaFreeMemoryPages(
1520                self.internal,
1521                allocations_ffi.len(),
1522                allocations_ffi.as_mut_ptr(),
1523            );
1524        }
1525    }
1526
1527    /// Returns current information about specified allocation and atomically marks it as used in current frame.
1528    ///
1529    /// Current parameters of given allocation are returned in the result object, available through accessors.
1530    ///
1531    /// This function also atomically "touches" allocation - marks it as used in current frame,
1532    /// just like `Allocator::touch_allocation`.
1533    ///
1534    /// If the allocation is in lost state, `allocation.get_device_memory` returns `erupt::vk::DeviceMemory::null()`.
1535    ///
1536    /// Although this function uses atomics and doesn't lock any mutex, so it should be quite efficient,
1537    /// you can avoid calling it too often.
1538    ///
1539    /// If you just want to check if allocation is not lost, `Allocator::touch_allocation` will work faster.
1540    pub fn get_allocation_info(&self, allocation: &Allocation) -> Result<AllocationInfo> {
1541        let mut allocation_info: AllocationInfo = Default::default();
1542        unsafe {
1543            ffi::vmaGetAllocationInfo(
1544                self.internal,
1545                allocation.internal,
1546                &mut allocation_info.internal,
1547            )
1548        }
1549        Ok(allocation_info)
1550    }
1551
1552    /// Sets user data in given allocation to new value.
1553    ///
1554    /// # Safety
1555    ///
1556    /// If the allocation was created with `AllocationCreateFlags::USER_DATA_COPY_STRING`,
1557    /// `user_data` must be either null, or pointer to a null-terminated string. The function
1558    /// makes local copy of the string and sets it as allocation's user data. String
1559    /// passed as user data doesn't need to be valid for whole lifetime of the allocation -
1560    /// you can free it after this call. String previously pointed by allocation's
1561    /// user data is freed from memory.
1562    ///
1563    /// If the flag was not used, the value of pointer `user_data` is just copied to
1564    /// allocation's user data. It is opaque, so you can use it however you want - e.g.
1565    /// as a pointer, ordinal number or some handle to you own data.
1566    pub unsafe fn set_allocation_user_data(
1567        &self,
1568        allocation: &Allocation,
1569        user_data: *mut ::std::os::raw::c_void,
1570    ) {
1571        ffi::vmaSetAllocationUserData(self.internal, allocation.internal, user_data);
1572    }
1573
1574    /// Maps memory represented by given allocation and returns pointer to it.
1575    ///
1576    /// Maps memory represented by given allocation to make it accessible to CPU code.
1577    /// When succeeded, result is a pointer to first byte of this memory.
1578    ///
1579    /// If the allocation is part of bigger `erupt::vk::DeviceMemory` block, the pointer is
1580    /// correctly offseted to the beginning of region assigned to this particular
1581    /// allocation.
1582    ///
1583    /// Mapping is internally reference-counted and synchronized, so despite raw Vulkan
1584    /// function `erupt::vk::Device::MapMemory` cannot be used to map same block of
1585    /// `erupt::vk::DeviceMemory` multiple times simultaneously, it is safe to call this
1586    /// function on allocations assigned to the same memory block. Actual Vulkan memory
1587    /// will be mapped on first mapping and unmapped on last unmapping.
1588    ///
1589    /// If the function succeeded, you must call `Allocator::unmap_memory` to unmap the
1590    /// allocation when mapping is no longer needed or before freeing the allocation, at
1591    /// the latest.
1592    ///
1593    /// It also safe to call this function multiple times on the same allocation. You
1594    /// must call `Allocator::unmap_memory` same number of times as you called
1595    /// `Allocator::map_memory`.
1596    ///
1597    /// It is also safe to call this function on allocation created with
1598    /// `AllocationCreateFlags::MAPPED` flag. Its memory stays mapped all the time.
1599    /// You must still call `Allocator::unmap_memory` same number of times as you called
1600    /// `Allocator::map_memory`. You must not call `Allocator::unmap_memory` additional
1601    /// time to free the "0-th" mapping made automatically due to `AllocationCreateFlags::MAPPED` flag.
1602    ///
1603    /// This function fails when used on allocation made in memory type that is not
1604    /// `erupt::vk::MemoryPropertyFlags::HOST_VISIBLE`.
1605    ///
1606    /// This function always fails when called for allocation that was created with
1607    /// `AllocationCreateFlags::CAN_BECOME_LOST` flag. Such allocations cannot be mapped.
1608    pub fn map_memory(&self, allocation: &Allocation) -> Result<*mut u8> {
1609        let mut mapped_data: *mut ::std::os::raw::c_void = ::std::ptr::null_mut();
1610        let result = ffi_to_result(unsafe {
1611            ffi::vmaMapMemory(self.internal, allocation.internal, &mut mapped_data)
1612        });
1613        match result {
1614            erupt::vk::Result::SUCCESS => Ok(mapped_data as *mut u8),
1615            _ => Err(Error::vulkan(result)),
1616        }
1617    }
1618
1619    /// Unmaps memory represented by given allocation, mapped previously using `Allocator::map_memory`.
1620    pub fn unmap_memory(&self, allocation: &Allocation) {
1621        unsafe {
1622            ffi::vmaUnmapMemory(self.internal, allocation.internal);
1623        }
1624    }
1625
1626    /// Flushes memory of given allocation.
1627    ///
1628    /// Calls `erupt::vk::Device::FlushMappedMemoryRanges` for memory associated with given range of given allocation.
1629    ///
1630    /// - `offset` must be relative to the beginning of allocation.
1631    /// - `size` can be `erupt::vk::WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation.
1632    /// - `offset` and `size` don't have to be aligned; hey are internally rounded down/up to multiple of `nonCoherentAtomSize`.
1633    /// - If `size` is 0, this call is ignored.
1634    /// - If memory type that the `allocation` belongs to is not `erupt::vk::MemoryPropertyFlags::HOST_VISIBLE` or it is `erupt::vk::MemoryPropertyFlags::HOST_COHERENT`, this call is ignored.
1635    pub fn flush_allocation(&self, allocation: &Allocation, offset: usize, size: usize) {
1636        unsafe {
1637            ffi::vmaFlushAllocation(
1638                self.internal,
1639                allocation.internal,
1640                offset as ffi::VkDeviceSize,
1641                size as ffi::VkDeviceSize,
1642            );
1643        }
1644    }
1645
1646    /// Invalidates memory of given allocation.
1647    ///
1648    /// Calls `erupt::vk::Device::invalidate_mapped_memory_ranges` for memory associated with given range of given allocation.
1649    ///
1650    /// - `offset` must be relative to the beginning of allocation.
1651    /// - `size` can be `erupt::vk::WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation.
1652    /// - `offset` and `size` don't have to be aligned. They are internally rounded down/up to multiple of `nonCoherentAtomSize`.
1653    /// - If `size` is 0, this call is ignored.
1654    /// - If memory type that the `allocation` belongs to is not `erupt::vk::MemoryPropertyFlags::HOST_VISIBLE` or it is `erupt::vk::MemoryPropertyFlags::HOST_COHERENT`, this call is ignored.
1655    pub fn invalidate_allocation(&self, allocation: &Allocation, offset: usize, size: usize) {
1656        unsafe {
1657            ffi::vmaInvalidateAllocation(
1658                self.internal,
1659                allocation.internal,
1660                offset as ffi::VkDeviceSize,
1661                size as ffi::VkDeviceSize,
1662            );
1663        }
1664    }
1665
1666    /// Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions.
1667    ///
1668    /// `memory_type_bits` bit mask, where each bit set means that a memory type with that index should be checked.
1669    ///
1670    /// Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero,
1671    /// `VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are `HOST_VISIBLE` and `HOST_COHERENT`.
1672    ///
1673    /// Possible error values:
1674    ///
1675    /// - `erupt::vk::Result::ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types.
1676    /// - `erupt::vk::Result::ERROR_VALIDATION_FAILED_EXT` - corruption detection has been performed and found memory corruptions around one of the allocations.
1677    ///   `VMA_ASSERT` is also fired in that case.
1678    /// - Other value: Error returned by Vulkan, e.g. memory mapping failure.
1679    pub fn check_corruption(&self, memory_types: erupt::vk::MemoryPropertyFlags) -> Result<()> {
1680        let result =
1681            ffi_to_result(unsafe { ffi::vmaCheckCorruption(self.internal, memory_types.bits()) });
1682        match result {
1683            erupt::vk::Result::SUCCESS => Ok(()),
1684            _ => Err(Error::vulkan(result)),
1685        }
1686    }
1687
1688    /// Begins defragmentation process.
1689    ///
1690    /// Use this function instead of old, deprecated `Allocator::defragment`.
1691    ///
1692    /// Warning! Between the call to `Allocator::defragmentation_begin` and `Allocator::defragmentation_end`.
1693    ///
1694    /// - You should not use any of allocations passed as `allocations` or
1695    /// any allocations that belong to pools passed as `pools`,
1696    /// including calling `Allocator::get_allocation_info`, `Allocator::touch_allocation`, or access
1697    /// their data.
1698    ///
1699    /// - Some mutexes protecting internal data structures may be locked, so trying to
1700    /// make or free any allocations, bind buffers or images, map memory, or launch
1701    /// another simultaneous defragmentation in between may cause stall (when done on
1702    /// another thread) or deadlock (when done on the same thread), unless you are
1703    /// 100% sure that defragmented allocations are in different pools.
1704    ///
1705    /// - Information returned via stats and `info.allocations_changed` are undefined.
1706    /// They become valid after call to `Allocator::defragmentation_end`.
1707    ///
1708    /// - If `info.command_buffer` is not null, you must submit that command buffer
1709    /// and make sure it finished execution before calling `Allocator::defragmentation_end`.
1710    /**
1711    Interleaved allocations and deallocations of many objects of varying size can
1712    cause fragmentation over time, which can lead to a situation where the library is unable
1713    to find a continuous range of free memory for a new allocation despite there is
1714    enough free space, just scattered across many small free ranges between existing
1715    allocations.
1716
1717    To mitigate this problem, you can use defragmentation feature.
1718    It doesn't happen automatically though and needs your cooperation,
1719    because VMA is a low level library that only allocates memory.
1720    It cannot recreate buffers and images in a new place as it doesn't remember the contents of `VkBufferCreateInfo` / `VkImageCreateInfo` structures.
1721    It cannot copy their contents as it doesn't record any commands to a command buffer.
1722
1723    Although functions like vmaCreateBuffer(), vmaCreateImage(), vmaDestroyBuffer(), vmaDestroyImage()
1724    create/destroy an allocation and a buffer/image at once, these are just a shortcut for
1725    creating the resource, allocating memory, and binding them together.
1726    Defragmentation works on memory allocations only. You must handle the rest manually.
1727    Defragmentation is an iterative process that should repreat "passes" as long as related functions
1728    return `VK_INCOMPLETE` not `VK_SUCCESS`.
1729    In each pass:
1730
1731    1. vmaBeginDefragmentationPass() function call:
1732        - Calculates and returns the list of allocations to be moved in this pass.
1733            Note this can be a time-consuming process.
1734        - Reserves destination memory for them by creating temporary destination allocations
1735            that you can query for their `VkDeviceMemory` + offset using vmaGetAllocationInfo().
1736    2. Inside the pass, **you should**:
1737        - Inspect the returned list of allocations to be moved.
1738        - Create new buffers/images and bind them at the returned destination temporary allocations.
1739        - Copy data from source to destination resources if necessary.
1740        - Destroy the source buffers/images, but NOT their allocations.
1741    3. vmaEndDefragmentationPass() function call:
1742        - Frees the source memory reserved for the allocations that are moved.
1743        - Modifies source #VmaAllocation objects that are moved to point to the destination reserved memory.
1744        - Frees `VkDeviceMemory` blocks that became empty.
1745
1746    Unlike in previous iterations of the defragmentation API, there is no list of "movable" allocations passed as a parameter.
1747    Defragmentation algorithm tries to move all suitable allocations.
1748    You can, however, refuse to move some of them inside a defragmentation pass, by setting
1749    `pass.pMoves[i].operation` to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE.
1750    This is not recommended and may result in suboptimal packing of the allocations after defragmentation.
1751    If you cannot ensure any allocation can be moved, it is better to keep movable allocations separate in a custom pool.
1752
1753    Inside a pass, for each allocation that should be moved:
1754
1755    - You should copy its data from the source to the destination place by calling e.g. `vkCmdCopyBuffer()`, `vkCmdCopyImage()`.
1756    - You need to make sure these commands finished executing before destroying the source buffers/images and before calling vmaEndDefragmentationPass().
1757    - If a resource doesn't contain any meaningful data, e.g. it is a transient color attachment image to be cleared,
1758    filled, and used temporarily in each rendering frame, you can just recreate this image
1759    without copying its data.
1760    - If the resource is in `HOST_VISIBLE` and `HOST_CACHED` memory, you can copy its data on the CPU
1761    using `memcpy()`.
1762    - If you cannot move the allocation, you can set `pass.pMoves[i].operation` to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE.
1763    This will cancel the move.
1764    - vmaEndDefragmentationPass() will then free the destination memory
1765        not the source memory of the allocation, leaving it unchanged.
1766    - If you decide the allocation is unimportant and can be destroyed instead of moved (e.g. it wasn't used for long time),
1767    you can set `pass.pMoves[i].operation` to #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY.
1768    - vmaEndDefragmentationPass() will then free both source and destination memory, and will destroy the source #VmaAllocation object.
1769
1770    You can defragment a specific custom pool by setting VmaDefragmentationInfo::pool
1771    (like in the example above) or all the default pools by setting this member to null.
1772
1773    Defragmentation is always performed in each pool separately.
1774    Allocations are never moved between different Vulkan memory types.
1775    The size of the destination memory reserved for a moved allocation is the same as the original one.
1776    Alignment of an allocation as it was determined using `vkGetBufferMemoryRequirements()` etc. is also respected after defragmentation.
1777    Buffers/images should be recreated with the same `VkBufferCreateInfo` / `VkImageCreateInfo` parameters as the original ones.
1778
1779    You can perform the defragmentation incrementally to limit the number of allocations and bytes to be moved
1780    in each pass, e.g. to call it in sync with render frames and not to experience too big hitches.
1781    See members: VmaDefragmentationInfo::maxBytesPerPass, VmaDefragmentationInfo::maxAllocationsPerPass.
1782
1783    It is also safe to perform the defragmentation asynchronously to render frames and other Vulkan and VMA
1784    usage, possibly from multiple threads, with the exception that allocations
1785    returned in VmaDefragmentationPassMoveInfo::pMoves shouldn't be destroyed until the defragmentation pass is ended.
1786
1787    *Mapping* is preserved on allocations that are moved during defragmentation.
1788    Whether through #VMA_ALLOCATION_CREATE_MAPPED_BIT or vmaMapMemory(), the allocations
1789    are mapped at their new place. Of course, pointer to the mapped data changes, so it needs to be queried
1790    using VmaAllocationInfo::pMappedData.
1791
1792    Note: Defragmentation is not supported in custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT.
1793     */
1794    pub fn begin_defragmentation(
1795        &self,
1796        info: &DefragmentationInfo,
1797    ) -> Result<DefragmentationContext> {
1798        let mut context = DefragmentationContext {
1799            internal: std::ptr::null_mut(),
1800        };
1801        let ffi_info = ffi::VmaDefragmentationInfo {
1802            flags: info.flags.bits(),
1803            pool: info
1804                .pool
1805                .as_ref()
1806                .map(|p| p.internal)
1807                .unwrap_or(std::ptr::null_mut()),
1808            maxBytesPerPass: info.max_bytes_per_pass,
1809            maxAllocationsPerPass: info.max_allocations_per_pass,
1810        };
1811        let result = ffi_to_result(unsafe {
1812            ffi::vmaBeginDefragmentation(self.internal, &ffi_info, &mut context.internal)
1813        });
1814        match result {
1815            erupt::vk::Result::SUCCESS => Ok(context),
1816            _ => Err(Error::vulkan(result)),
1817        }
1818    }
1819
1820    /// Starts single defragmentation pass.
1821    pub fn begin_defragmentation_pass(
1822        &self,
1823        context: &mut DefragmentationContext,
1824    ) -> Result<DefragmentationPassResult> {
1825        let mut ffi_moves = ffi::VmaDefragmentationPassMoveInfo::default();
1826        let result = ffi_to_result(unsafe {
1827            ffi::vmaBeginDefragmentationPass(self.internal, context.internal, &mut ffi_moves)
1828        });
1829        match result {
1830            erupt::vk::Result::INCOMPLETE => {
1831                let mut moves = Vec::with_capacity(ffi_moves.moveCount as usize);
1832                for i in 0..ffi_moves.moveCount as usize {
1833                    let ffi_move: ffi::VmaDefragmentationMove =
1834                        unsafe { std::ptr::read(ffi_moves.pMoves.add(i)) };
1835                    moves.push(DefragmentationMove {
1836                        operation: ffi_move.operation.try_into().unwrap(),
1837                        src_allocation: Allocation {
1838                            internal: ffi_move.srcAllocation,
1839                        },
1840                        dst_tmp_allocation: Allocation {
1841                            internal: ffi_move.dstTmpAllocation,
1842                        },
1843                    })
1844                }
1845                Ok(DefragmentationPassResult::Incomplete(
1846                    DefragmentationPassMoveInfo {
1847                        internal: ffi_moves,
1848                        moves: moves.into(),
1849                    },
1850                ))
1851            }
1852            erupt::vk::Result::SUCCESS => Ok(DefragmentationPassResult::Success),
1853            error => Err(Error::vulkan(error)),
1854        }
1855    }
1856
1857    /// Ends single defragmentation pass.
1858    /// Returns true if no more moves are possible, or false if more defragmentations are possible.
1859    /// Ends incremental defragmentation pass and commits all defragmentation moves from pPassInfo. After this call:
1860    ///
1861    ///    - Allocations at moves[i].srcAllocation that had moves[i].operation == Copy (which is the default) will be pointing to the new destination place.
1862    ///    - Allocation at moves[i].srcAllocation that had moves[i].operation == Destroy will be freed.
1863    ///
1864    /// If no more moves are possible you can end whole defragmentation.
1865    pub fn end_defragmentation_pass(
1866        &self,
1867        context: &mut DefragmentationContext,
1868        moves: &mut DefragmentationPassMoveInfo,
1869    ) -> Result<bool> {
1870        for (i, mov) in moves.moves.iter().enumerate() {
1871            unsafe {
1872                let ffi_mov = moves.internal.pMoves.add(i);
1873                std::ptr::addr_of_mut!((*ffi_mov).operation)
1874                    .write(mov.operation as ffi::VmaDefragmentationMoveOperation);
1875            }
1876        }
1877        let result = ffi_to_result(unsafe {
1878            ffi::vmaEndDefragmentationPass(self.internal, context.internal, &mut moves.internal)
1879        });
1880        if !(result == erupt::vk::Result::SUCCESS || result == erupt::vk::Result::INCOMPLETE) {
1881            return Err(Error::vulkan(result));
1882        }
1883        for (i, mov) in moves.moves.iter_mut().enumerate() {
1884            unsafe {
1885                let ffi_mov = moves.internal.pMoves.add(i);
1886                mov.src_allocation.internal =
1887                    std::ptr::addr_of_mut!((*ffi_mov).srcAllocation).read();
1888            }
1889        }
1890        Ok(result == erupt::vk::Result::SUCCESS)
1891    }
1892
1893    /// Ends defragmentation process.
1894    ///
1895    /// Use this function to finish defragmentation started by `Allocator::begin_defragmentation`.
1896    pub fn end_defragmentation(
1897        &self,
1898        context: &mut DefragmentationContext,
1899    ) -> DefragmentationStats {
1900        let mut ffi_stats = ffi::VmaDefragmentationStats::default();
1901        unsafe {
1902            ffi::vmaEndDefragmentation(self.internal, context.internal, &mut ffi_stats);
1903        }
1904        DefragmentationStats {
1905            bytes_moved: ffi_stats.bytesMoved as usize,
1906            bytes_freed: ffi_stats.bytesFreed as usize,
1907            allocations_moved: ffi_stats.allocationsMoved,
1908            device_memory_blocks_freed: ffi_stats.deviceMemoryBlocksFreed,
1909        }
1910    }
1911
1912    /// Binds buffer to allocation.
1913    ///
1914    /// Binds specified buffer to region of memory represented by specified allocation.
1915    /// Gets `erupt::vk::DeviceMemory` handle and offset from the allocation.
1916    ///
1917    /// If you want to create a buffer, allocate memory for it and bind them together separately,
1918    /// you should use this function for binding instead of `erupt::vk::Device::bind_buffer_memory`,
1919    /// because it ensures proper synchronization so that when a `erupt::vk::DeviceMemory` object is
1920    /// used by multiple allocations, calls to `erupt::vk::Device::bind_buffer_memory()` or
1921    /// `erupt::vk::Device::map_memory()` won't happen from multiple threads simultaneously
1922    /// (which is illegal in Vulkan).
1923    ///
1924    /// It is recommended to use function `Allocator::create_buffer` instead of this one.
1925    pub fn bind_buffer_memory(
1926        &self,
1927        buffer: erupt::vk::Buffer,
1928        allocation: &Allocation,
1929    ) -> Result<()> {
1930        let result = ffi_to_result(unsafe {
1931            ffi::vmaBindBufferMemory(
1932                self.internal,
1933                allocation.internal,
1934                buffer.to_raw() as ffi::VkBuffer,
1935            )
1936        });
1937        match result {
1938            erupt::vk::Result::SUCCESS => Ok(()),
1939            _ => Err(Error::vulkan(result)),
1940        }
1941    }
1942
1943    /// Binds image to allocation.
1944    ///
1945    /// Binds specified image to region of memory represented by specified allocation.
1946    /// Gets `erupt::vk::DeviceMemory` handle and offset from the allocation.
1947    ///
1948    /// If you want to create a image, allocate memory for it and bind them together separately,
1949    /// you should use this function for binding instead of `erupt::vk::Device::bind_image_memory`,
1950    /// because it ensures proper synchronization so that when a `erupt::vk::DeviceMemory` object is
1951    /// used by multiple allocations, calls to `erupt::vk::Device::bind_image_memory()` or
1952    /// `erupt::vk::Device::map_memory()` won't happen from multiple threads simultaneously
1953    /// (which is illegal in Vulkan).
1954    ///
1955    /// It is recommended to use function `Allocator::create_image` instead of this one.
1956    pub fn bind_image_memory(
1957        &self,
1958        image: erupt::vk::Image,
1959        allocation: &Allocation,
1960    ) -> Result<()> {
1961        let result = ffi_to_result(unsafe {
1962            ffi::vmaBindImageMemory(
1963                self.internal,
1964                allocation.internal,
1965                image.to_raw() as ffi::VkImage,
1966            )
1967        });
1968        match result {
1969            erupt::vk::Result::SUCCESS => Ok(()),
1970            _ => Err(Error::vulkan(result)),
1971        }
1972    }
1973
1974    /// This function automatically creates a buffer, allocates appropriate memory
1975    /// for it, and binds the buffer with the memory.
1976    ///
1977    /// If the function succeeded, you must destroy both buffer and allocation when you
1978    /// no longer need them using either convenience function `Allocator::destroy_buffer` or
1979    /// separately, using `erupt::Device::destroy_buffer` and `Allocator::free_memory`.
1980    ///
1981    /// If `AllocatorCreateFlags::KHR_DEDICATED_ALLOCATION` flag was used,
1982    /// VK_KHR_dedicated_allocation extension is used internally to query driver whether
1983    /// it requires or prefers the new buffer to have dedicated allocation. If yes,
1984    /// and if dedicated allocation is possible (AllocationCreateInfo::pool is null
1985    /// and `AllocationCreateFlags::NEVER_ALLOCATE` is not used), it creates dedicated
1986    /// allocation for this buffer, just like when using `AllocationCreateFlags::DEDICATED_MEMORY`.
1987    pub fn create_buffer(
1988        &self,
1989        buffer_info: &erupt::vk::BufferCreateInfo,
1990        allocation_info: &AllocationCreateInfo,
1991    ) -> Result<(erupt::vk::Buffer, Allocation, AllocationInfo)> {
1992        let buffer_create_info = unsafe {
1993            mem::transmute::<erupt::vk::BufferCreateInfo, ffi::VkBufferCreateInfo>(*buffer_info)
1994        };
1995        let allocation_create_info = allocation_create_info_to_ffi(allocation_info);
1996        let mut buffer: ffi::VkBuffer = std::ptr::null_mut();
1997        let mut allocation: Allocation = Default::default();
1998        let mut allocation_info: AllocationInfo = Default::default();
1999        let result = ffi_to_result(unsafe {
2000            ffi::vmaCreateBuffer(
2001                self.internal,
2002                &buffer_create_info,
2003                &allocation_create_info,
2004                &mut buffer,
2005                &mut allocation.internal,
2006                &mut allocation_info.internal,
2007            )
2008        });
2009        match result {
2010            erupt::vk::Result::SUCCESS => Ok((
2011                erupt::vk::Buffer(buffer as u64),
2012                allocation,
2013                allocation_info,
2014            )),
2015            _ => Err(Error::vulkan(result)),
2016        }
2017    }
2018
2019    /// Destroys Vulkan buffer and frees allocated memory.
2020    ///
2021    /// This is just a convenience function equivalent to:
2022    ///
2023    /// ```ignore
2024    /// erupt::vk::Device::destroy_buffer(buffer, None);
2025    /// Allocator::free_memory(allocator, allocation);
2026    /// ```
2027    ///
2028    /// It it safe to pass null as `buffer` and/or `allocation`.
2029    pub fn destroy_buffer(&self, buffer: erupt::vk::Buffer, allocation: &Allocation) {
2030        unsafe {
2031            ffi::vmaDestroyBuffer(
2032                self.internal,
2033                buffer.to_raw() as ffi::VkBuffer,
2034                allocation.internal,
2035            );
2036        }
2037    }
2038
2039    /// This function automatically creates an image, allocates appropriate memory
2040    /// for it, and binds the image with the memory.
2041    ///
2042    /// If the function succeeded, you must destroy both image and allocation when you
2043    /// no longer need them using either convenience function `Allocator::destroy_image` or
2044    /// separately, using `erupt::Device::destroy_image` and `Allocator::free_memory`.
2045    ///
2046    /// If `AllocatorCreateFlags::KHR_DEDICATED_ALLOCATION` flag was used,
2047    /// `VK_KHR_dedicated_allocation extension` is used internally to query driver whether
2048    /// it requires or prefers the new image to have dedicated allocation. If yes,
2049    /// and if dedicated allocation is possible (AllocationCreateInfo::pool is null
2050    /// and `AllocationCreateFlags::NEVER_ALLOCATE` is not used), it creates dedicated
2051    /// allocation for this image, just like when using `AllocationCreateFlags::DEDICATED_MEMORY`.
2052    ///
2053    /// If `VK_ERROR_VALIDAITON_FAILED_EXT` is returned, VMA may have encountered a problem
2054    /// that is not caught by the validation layers. One example is if you try to create a 0x0
2055    /// image, a panic will occur and `VK_ERROR_VALIDAITON_FAILED_EXT` is thrown.
2056    pub fn create_image(
2057        &self,
2058        image_info: &erupt::vk::ImageCreateInfo,
2059        allocation_info: &AllocationCreateInfo,
2060    ) -> Result<(erupt::vk::Image, Allocation, AllocationInfo)> {
2061        let image_create_info = unsafe {
2062            mem::transmute::<erupt::vk::ImageCreateInfo, ffi::VkImageCreateInfo>(*image_info)
2063        };
2064        let allocation_create_info = allocation_create_info_to_ffi(allocation_info);
2065        let mut image: ffi::VkImage = std::ptr::null_mut();
2066        let mut allocation: Allocation = Default::default();
2067        let mut allocation_info: AllocationInfo = Default::default();
2068        let result = ffi_to_result(unsafe {
2069            ffi::vmaCreateImage(
2070                self.internal,
2071                &image_create_info,
2072                &allocation_create_info,
2073                &mut image,
2074                &mut allocation.internal,
2075                &mut allocation_info.internal,
2076            )
2077        });
2078        match result {
2079            erupt::vk::Result::SUCCESS => {
2080                Ok((erupt::vk::Image(image as u64), allocation, allocation_info))
2081            }
2082            _ => Err(Error::vulkan(result)),
2083        }
2084    }
2085
2086    /// Destroys Vulkan image and frees allocated memory.
2087    ///
2088    /// This is just a convenience function equivalent to:
2089    ///
2090    /// ```ignore
2091    /// erupt::vk::Device::destroy_image(image, None);
2092    /// Allocator::free_memory(allocator, allocation);
2093    /// ```
2094    ///
2095    /// It it safe to pass null as `image` and/or `allocation`.
2096    pub fn destroy_image(&self, image: erupt::vk::Image, allocation: &Allocation) {
2097        unsafe {
2098            ffi::vmaDestroyImage(
2099                self.internal,
2100                image.to_raw() as ffi::VkImage,
2101                allocation.internal,
2102            );
2103        }
2104    }
2105
2106    /// Destroys the internal allocator instance. After this has been called,
2107    /// no other functions may be called. Useful for ensuring a specific destruction
2108    /// order (for example, if an Allocator is a member of something that owns the Vulkan
2109    /// instance and destroys it in its own Drop).
2110    pub fn destroy(&mut self) {
2111        if !self.internal.is_null() {
2112            unsafe {
2113                ffi::vmaDestroyAllocator(self.internal);
2114                self.internal = std::ptr::null_mut();
2115            }
2116        }
2117    }
2118}
2119
2120/// Custom `Drop` implementation to clean up internal allocation instance
2121impl Drop for Allocator {
2122    fn drop(&mut self) {
2123        self.destroy();
2124    }
2125}