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}