vk_mem/
pool.rs

1use std::ffi::CStr;
2use std::sync::Arc;
3
4use crate::ffi;
5use crate::Allocation;
6use crate::AllocationCreateInfo;
7use crate::Allocator;
8use crate::PoolCreateInfo;
9use ash::prelude::VkResult;
10use ash::vk;
11#[derive(Clone, Copy)]
12pub struct PoolHandle(ffi::VmaPool);
13
14/// Represents custom memory pool handle.
15pub struct AllocatorPool {
16    allocator: Arc<Allocator>,
17    pub(crate) pool: PoolHandle,
18}
19unsafe impl Send for AllocatorPool {}
20unsafe impl Sync for AllocatorPool {}
21
22impl Allocator {
23    /// Allocates Vulkan device memory and creates `AllocatorPool` object.
24    pub fn create_pool(self: &Arc<Self>, create_info: &PoolCreateInfo) -> VkResult<AllocatorPool> {
25        unsafe {
26            let mut ffi_pool: ffi::VmaPool = std::mem::zeroed();
27            let raw_info = ffi::VmaPoolCreateInfo {
28                memoryTypeIndex: create_info.memory_type_index,
29                flags: create_info.flags.bits(),
30                blockSize: create_info.block_size,
31                minBlockCount: create_info.min_block_count,
32                maxBlockCount: create_info.max_block_count,
33                priority: create_info.priority,
34                minAllocationAlignment: create_info.min_allocation_alignment,
35                pMemoryAllocateNext: create_info.memory_allocate_next as *mut std::ffi::c_void,
36            };
37            ffi::vmaCreatePool(self.internal, &raw_info, &mut ffi_pool).result()?;
38            Ok(AllocatorPool {
39                pool: PoolHandle(ffi_pool),
40                allocator: self.clone(),
41            })
42        }
43    }
44
45    pub fn default_pool(self: &Arc<Self>) -> AllocatorPool {
46        AllocatorPool {
47            pool: PoolHandle(std::ptr::null_mut()),
48            allocator: self.clone(),
49        }
50    }
51}
52
53impl Drop for AllocatorPool {
54    fn drop(&mut self) {
55        unsafe {
56            ffi::vmaDestroyPool(self.allocator.internal, self.pool.0);
57        }
58    }
59}
60
61impl AllocatorPool {
62    pub fn set_name(&self, name: Option<&CStr>) {
63        if self.pool.0.is_null() {
64            return;
65        }
66        unsafe {
67            ffi::vmaSetPoolName(
68                self.allocator.internal,
69                self.pool.0,
70                name.map_or(std::ptr::null(), CStr::as_ptr),
71            );
72        }
73    }
74    pub fn name(&self) -> Option<&CStr> {
75        if self.pool.0.is_null() {
76            return None;
77        }
78        let mut ptr: *const ::std::os::raw::c_char = std::ptr::null();
79        unsafe {
80            ffi::vmaGetPoolName(self.allocator.internal, self.pool.0, &mut ptr);
81            if ptr.is_null() {
82                return None;
83            }
84            Some(CStr::from_ptr(ptr))
85        }
86    }
87    /// Retrieves statistics of existing `AllocatorPool` object.
88    pub fn get_statistics(&self) -> VkResult<ffi::VmaStatistics> {
89        unsafe {
90            let mut pool_stats: ffi::VmaStatistics = std::mem::zeroed();
91            ffi::vmaGetPoolStatistics(self.allocator.internal, self.pool.0, &mut pool_stats);
92            Ok(pool_stats)
93        }
94    }
95
96    /// Retrieves statistics of existing `AllocatorPool` object.
97    pub fn calculate_statistics(&self) -> VkResult<ffi::VmaDetailedStatistics> {
98        unsafe {
99            let mut pool_stats: ffi::VmaDetailedStatistics = std::mem::zeroed();
100            ffi::vmaCalculatePoolStatistics(self.allocator.internal, self.pool.0, &mut pool_stats);
101            Ok(pool_stats)
102        }
103    }
104
105    /// Checks magic number in margins around all allocations in given memory pool in search for corruptions.
106    ///
107    /// Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero,
108    /// `VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is
109    /// `ash::vk::MemoryPropertyFlags::HOST_VISIBLE` and `ash::vk::MemoryPropertyFlags::HOST_COHERENT`.
110    ///
111    /// Possible error values:
112    ///
113    /// - `ash::vk::Result::ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool.
114    /// - `ash::vk::Result::ERROR_VALIDATION_FAILED_EXT` - corruption detection has been performed and found memory corruptions around one of the allocations.
115    ///   `VMA_ASSERT` is also fired in that case.
116    /// - Other value: Error returned by Vulkan, e.g. memory mapping failure.
117    pub fn check_corruption(&self) -> VkResult<()> {
118        unsafe { ffi::vmaCheckPoolCorruption(self.allocator.internal, self.pool.0).result() }
119    }
120}
121
122pub trait Alloc {
123    fn allocator(&self) -> &Allocator;
124    fn pool(&self) -> PoolHandle;
125    /// Helps to find memory type index, given memory type bits and allocation info.
126    ///
127    /// This algorithm tries to find a memory type that:
128    ///
129    /// - Is allowed by memory type bits.
130    /// - Contains all the flags from `allocation_info.required_flags`.
131    /// - Matches intended usage.
132    /// - Has as many flags from `allocation_info.preferred_flags` as possible.
133    ///
134    /// Returns ash::vk::Result::ERROR_FEATURE_NOT_PRESENT if not found. Receiving such a result
135    /// from this function or any other allocating function probably means that your
136    /// device doesn't support any memory type with requested features for the specific
137    /// type of resource you want to use it for. Please check parameters of your
138    /// resource, like image layout (OPTIMAL versus LINEAR) or mip level count.
139    unsafe fn find_memory_type_index(
140        &self,
141        memory_type_bits: u32,
142        allocation_info: &AllocationCreateInfo,
143    ) -> VkResult<u32> {
144        let mut memory_type_index: u32 = 0;
145        let mut allocation_info: ffi::VmaAllocationCreateInfo = allocation_info.into();
146        allocation_info.pool = self.pool().0;
147        ffi::vmaFindMemoryTypeIndex(
148            self.allocator().internal,
149            memory_type_bits,
150            &allocation_info,
151            &mut memory_type_index,
152        )
153        .result()?;
154
155        Ok(memory_type_index)
156    }
157
158    /// Helps to find memory type index, given buffer info and allocation info.
159    ///
160    /// It can be useful e.g. to determine value to be used as `AllocatorPoolCreateInfo::memory_type_index`.
161    /// It internally creates a temporary, dummy buffer that never has memory bound.
162    /// It is just a convenience function, equivalent to calling:
163    ///
164    /// - `ash::vk::Device::create_buffer`
165    /// - `ash::vk::Device::get_buffer_memory_requirements`
166    /// - `Allocator::find_memory_type_index`
167    /// - `ash::vk::Device::destroy_buffer`
168    unsafe fn find_memory_type_index_for_buffer_info(
169        &self,
170        buffer_info: &ash::vk::BufferCreateInfo,
171        allocation_info: &AllocationCreateInfo,
172    ) -> VkResult<u32> {
173        let mut allocation_info: ffi::VmaAllocationCreateInfo = allocation_info.into();
174        allocation_info.pool = self.pool().0;
175        let mut memory_type_index: u32 = 0;
176        ffi::vmaFindMemoryTypeIndexForBufferInfo(
177            self.allocator().internal,
178            buffer_info,
179            &allocation_info,
180            &mut memory_type_index,
181        )
182        .result()?;
183
184        Ok(memory_type_index)
185    }
186
187    /// Helps to find memory type index, given image info and allocation info.
188    ///
189    /// It can be useful e.g. to determine value to be used as `AllocatorPoolCreateInfo::memory_type_index`.
190    /// It internally creates a temporary, dummy image that never has memory bound.
191    /// It is just a convenience function, equivalent to calling:
192    ///
193    /// - `ash::vk::Device::create_image`
194    /// - `ash::vk::Device::get_image_memory_requirements`
195    /// - `Allocator::find_memory_type_index`
196    /// - `ash::vk::Device::destroy_image`
197    unsafe fn find_memory_type_index_for_image_info(
198        &self,
199        image_info: ash::vk::ImageCreateInfo,
200        allocation_info: &AllocationCreateInfo,
201    ) -> VkResult<u32> {
202        let mut allocation_info: ffi::VmaAllocationCreateInfo = allocation_info.into();
203        allocation_info.pool = self.pool().0;
204        let mut memory_type_index: u32 = 0;
205        ffi::vmaFindMemoryTypeIndexForImageInfo(
206            self.allocator().internal,
207            &image_info,
208            &allocation_info,
209            &mut memory_type_index,
210        )
211        .result()?;
212
213        Ok(memory_type_index)
214    }
215
216    /// General purpose memory allocation.
217    ///
218    /// You should free the memory using `Allocator::free_memory` or 'Allocator::free_memory_pages'.
219    ///
220    /// It is recommended to use `Allocator::allocate_memory_for_buffer`, `Allocator::allocate_memory_for_image`,
221    /// `Allocator::create_buffer`, `Allocator::create_image` instead whenever possible.
222    unsafe fn allocate_memory(
223        &self,
224        memory_requirements: &ash::vk::MemoryRequirements,
225        create_info: &AllocationCreateInfo,
226    ) -> VkResult<Allocation> {
227        let mut create_info: ffi::VmaAllocationCreateInfo = create_info.into();
228        create_info.pool = self.pool().0;
229        let mut allocation: ffi::VmaAllocation = std::mem::zeroed();
230        ffi::vmaAllocateMemory(
231            self.allocator().internal,
232            memory_requirements,
233            &create_info,
234            &mut allocation,
235            std::ptr::null_mut(),
236        )
237        .result()?;
238
239        Ok(Allocation(allocation))
240    }
241
242    /// General purpose memory allocation for multiple allocation objects at once.
243    ///
244    /// You should free the memory using `Allocator::free_memory` or `Allocator::free_memory_pages`.
245    ///
246    /// Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding.
247    /// It is just a general purpose allocation function able to make multiple allocations at once.
248    /// It may be internally optimized to be more efficient than calling `Allocator::allocate_memory` `allocations.len()` times.
249    ///
250    /// All allocations are made using same parameters. All of them are created out of the same memory pool and type.
251    unsafe fn allocate_memory_pages(
252        &self,
253        memory_requirements: &ash::vk::MemoryRequirements,
254        create_info: &AllocationCreateInfo,
255        allocation_count: usize,
256    ) -> VkResult<Vec<Allocation>> {
257        let mut create_info: ffi::VmaAllocationCreateInfo = create_info.into();
258        create_info.pool = self.pool().0;
259        let mut allocations: Vec<ffi::VmaAllocation> = vec![std::mem::zeroed(); allocation_count];
260        ffi::vmaAllocateMemoryPages(
261            self.allocator().internal,
262            memory_requirements,
263            &create_info,
264            allocation_count,
265            allocations.as_mut_ptr(),
266            std::ptr::null_mut(),
267        )
268        .result()?;
269
270        let allocations: Vec<Allocation> = allocations
271            .into_iter()
272            .map(|alloc| Allocation(alloc))
273            .collect();
274
275        Ok(allocations)
276    }
277
278    /// Buffer specialized memory allocation.
279    ///
280    /// You should free the memory using `Allocator::free_memory` or 'Allocator::free_memory_pages'.
281    unsafe fn allocate_memory_for_buffer(
282        &self,
283        buffer: ash::vk::Buffer,
284        create_info: &AllocationCreateInfo,
285    ) -> VkResult<Allocation> {
286        let mut create_info: ffi::VmaAllocationCreateInfo = create_info.into();
287        create_info.pool = self.pool().0;
288        let mut allocation: ffi::VmaAllocation = std::mem::zeroed();
289        let mut allocation_info: ffi::VmaAllocationInfo = std::mem::zeroed();
290        ffi::vmaAllocateMemoryForBuffer(
291            self.allocator().internal,
292            buffer,
293            &create_info,
294            &mut allocation,
295            &mut allocation_info,
296        )
297        .result()?;
298
299        Ok(Allocation(allocation))
300    }
301
302    /// Image specialized memory allocation.
303    ///
304    /// You should free the memory using `Allocator::free_memory` or 'Allocator::free_memory_pages'.
305    unsafe fn allocate_memory_for_image(
306        &self,
307        image: ash::vk::Image,
308        create_info: &AllocationCreateInfo,
309    ) -> VkResult<Allocation> {
310        let mut create_info: ffi::VmaAllocationCreateInfo = create_info.into();
311        create_info.pool = self.pool().0;
312        let mut allocation: ffi::VmaAllocation = std::mem::zeroed();
313        ffi::vmaAllocateMemoryForImage(
314            self.allocator().internal,
315            image,
316            &create_info,
317            &mut allocation,
318            std::ptr::null_mut(),
319        )
320        .result()?;
321
322        Ok(Allocation(allocation))
323    }
324
325    /// This function automatically creates a buffer, allocates appropriate memory
326    /// for it, and binds the buffer with the memory.
327    ///
328    /// If the function succeeded, you must destroy both buffer and allocation when you
329    /// no longer need them using either convenience function `Allocator::destroy_buffer` or
330    /// separately, using `ash::Device::destroy_buffer` and `Allocator::free_memory`.
331    ///
332    /// If `AllocatorCreateFlags::KHR_DEDICATED_ALLOCATION` flag was used,
333    /// VK_KHR_dedicated_allocation extension is used internally to query driver whether
334    /// it requires or prefers the new buffer to have dedicated allocation. If yes,
335    /// and if dedicated allocation is possible (AllocationCreateInfo::pool is null
336    /// and `AllocationCreateFlags::NEVER_ALLOCATE` is not used), it creates dedicated
337    /// allocation for this buffer, just like when using `AllocationCreateFlags::DEDICATED_MEMORY`.
338    unsafe fn create_buffer(
339        &self,
340        buffer_info: &ash::vk::BufferCreateInfo,
341        create_info: &AllocationCreateInfo,
342    ) -> VkResult<(ash::vk::Buffer, Allocation)> {
343        let mut create_info: ffi::VmaAllocationCreateInfo = create_info.into();
344        create_info.pool = self.pool().0;
345        let mut buffer = vk::Buffer::null();
346        let mut allocation: ffi::VmaAllocation = std::mem::zeroed();
347        ffi::vmaCreateBuffer(
348            self.allocator().internal,
349            &*buffer_info,
350            &create_info,
351            &mut buffer,
352            &mut allocation,
353            std::ptr::null_mut(),
354        )
355        .result()?;
356
357        Ok((buffer, Allocation(allocation)))
358    }
359    /// brief Creates a buffer with additional minimum alignment.
360    ///
361    /// Similar to vmaCreateBuffer() but provides additional parameter `minAlignment` which allows to specify custom,
362    /// minimum alignment to be used when placing the buffer inside a larger memory block, which may be needed e.g.
363    /// for interop with OpenGL.
364    unsafe fn create_buffer_with_alignment(
365        &self,
366        buffer_info: &ash::vk::BufferCreateInfo,
367        create_info: &AllocationCreateInfo,
368        min_alignment: vk::DeviceSize,
369    ) -> VkResult<(ash::vk::Buffer, Allocation)> {
370        let mut create_info: ffi::VmaAllocationCreateInfo = create_info.into();
371        create_info.pool = self.pool().0;
372        let mut buffer = vk::Buffer::null();
373        let mut allocation: ffi::VmaAllocation = std::mem::zeroed();
374        ffi::vmaCreateBufferWithAlignment(
375            self.allocator().internal,
376            &*buffer_info,
377            &create_info,
378            min_alignment,
379            &mut buffer,
380            &mut allocation,
381            std::ptr::null_mut(),
382        )
383        .result()?;
384
385        Ok((buffer, Allocation(allocation)))
386    }
387    /// This function automatically creates an image, allocates appropriate memory
388    /// for it, and binds the image with the memory.
389    ///
390    /// If the function succeeded, you must destroy both image and allocation when you
391    /// no longer need them using either convenience function `Allocator::destroy_image` or
392    /// separately, using `ash::Device::destroy_image` and `Allocator::free_memory`.
393    ///
394    /// If `AllocatorCreateFlags::KHR_DEDICATED_ALLOCATION` flag was used,
395    /// `VK_KHR_dedicated_allocation extension` is used internally to query driver whether
396    /// it requires or prefers the new image to have dedicated allocation. If yes,
397    /// and if dedicated allocation is possible (AllocationCreateInfo::pool is null
398    /// and `AllocationCreateFlags::NEVER_ALLOCATE` is not used), it creates dedicated
399    /// allocation for this image, just like when using `AllocationCreateFlags::DEDICATED_MEMORY`.
400    ///
401    /// If `VK_ERROR_VALIDAITON_FAILED_EXT` is returned, VMA may have encountered a problem
402    /// that is not caught by the validation layers. One example is if you try to create a 0x0
403    /// image, a panic will occur and `VK_ERROR_VALIDAITON_FAILED_EXT` is thrown.
404    unsafe fn create_image(
405        &self,
406        image_info: &ash::vk::ImageCreateInfo,
407        create_info: &AllocationCreateInfo,
408    ) -> VkResult<(ash::vk::Image, Allocation)> {
409        let mut create_info: ffi::VmaAllocationCreateInfo = create_info.into();
410        create_info.pool = self.pool().0;
411        let mut image = vk::Image::null();
412        let mut allocation: ffi::VmaAllocation = std::mem::zeroed();
413        ffi::vmaCreateImage(
414            self.allocator().internal,
415            &*image_info,
416            &create_info,
417            &mut image,
418            &mut allocation,
419            std::ptr::null_mut(),
420        )
421        .result()?;
422
423        Ok((image, Allocation(allocation)))
424    }
425}
426
427impl Alloc for AllocatorPool {
428    fn allocator(&self) -> &Allocator {
429        self.allocator.as_ref()
430    }
431
432    fn pool(&self) -> PoolHandle {
433        self.pool
434    }
435}
436impl Alloc for Allocator {
437    fn allocator(&self) -> &Allocator {
438        self
439    }
440
441    fn pool(&self) -> PoolHandle {
442        PoolHandle(std::ptr::null_mut())
443    }
444}