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