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