vulkanalia_vma/
allocator.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use alloc::vec::Vec;
4use core::mem;
5
6use vulkanalia::prelude::v1_0::*;
7use vulkanalia::vk::{DeviceCommands, InstanceCommands};
8use vulkanalia::{ResultExt, Version};
9
10use crate::Allocation;
11use crate::flags::AllocatorCreateFlags;
12use crate::vma::*;
13
14#[derive(Copy, Clone, Debug)]
15pub struct AllocatorOptions<'a> {
16    pub instance: &'a Instance,
17    pub device: &'a Device,
18    pub physical_device: vk::PhysicalDevice,
19    pub version: Version,
20    pub flags: AllocatorCreateFlags,
21    pub preferred_large_heap_block_size: vk::DeviceSize,
22    pub heap_size_limits: &'a [vk::DeviceSize],
23    pub external_memory_handle_types: &'a [vk::ExternalMemoryHandleTypeFlagsKHR],
24}
25
26impl<'a> AllocatorOptions<'a> {
27    pub fn new(
28        instance: &'a Instance,
29        device: &'a Device,
30        physical_device: vk::PhysicalDevice,
31    ) -> Self {
32        Self {
33            instance,
34            device,
35            physical_device,
36            version: Version::V1_0_0,
37            flags: AllocatorCreateFlags::empty(),
38            preferred_large_heap_block_size: 0,
39            heap_size_limits: &[],
40            external_memory_handle_types: &[],
41        }
42    }
43}
44
45#[repr(transparent)]
46#[derive(Debug)]
47pub struct Allocator(pub(crate) VmaAllocator);
48
49impl Allocator {
50    pub unsafe fn new(options: &AllocatorOptions) -> VkResult<Self> {
51        let functions = get_functions(
52            options.instance.version(),
53            options.instance.commands(),
54            options.device.commands(),
55        );
56
57        let heap_size_limits = if !options.heap_size_limits.is_empty() {
58            options.heap_size_limits.as_ptr()
59        } else {
60            core::ptr::null()
61        };
62
63        let external_memory_handle_types = if !options.external_memory_handle_types.is_empty() {
64            options.external_memory_handle_types.as_ptr()
65        } else {
66            core::ptr::null()
67        };
68
69        let info = VmaAllocatorCreateInfo {
70            instance: options.instance.handle(),
71            device: options.device.handle(),
72            physicalDevice: options.physical_device,
73            flags: options.flags.bits(),
74            preferredLargeHeapBlockSize: 0,
75            pAllocationCallbacks: core::ptr::null(),
76            pDeviceMemoryCallbacks: core::ptr::null(),
77            pHeapSizeLimit: heap_size_limits,
78            pVulkanFunctions: &functions,
79            vulkanApiVersion: options.version.into(),
80            pTypeExternalMemoryHandleTypes: external_memory_handle_types,
81        };
82
83        unsafe {
84            let mut allocator: VmaAllocator = mem::zeroed();
85            vmaCreateAllocator(&info, &mut allocator).result()?;
86            Ok(Self(allocator))
87        }
88    }
89
90    pub fn get_physical_device_properties(&self) -> vk::PhysicalDeviceProperties {
91        unsafe {
92            let mut properties = vk::PhysicalDeviceProperties::default();
93            let pointer = &mut properties as *mut _ as *mut *const _;
94            vmaGetPhysicalDeviceProperties(self.0, pointer);
95            properties
96        }
97    }
98
99    pub fn get_memory_properties(&self) -> &vk::PhysicalDeviceMemoryProperties {
100        unsafe {
101            let mut properties = core::ptr::null();
102            vmaGetMemoryProperties(self.0, &mut properties);
103            &*properties
104        }
105    }
106
107    pub fn calculate_statistics(&self) -> VkResult<VmaTotalStatistics> {
108        unsafe {
109            let mut statistics: VmaTotalStatistics = mem::zeroed();
110            vmaCalculateStatistics(self.0, &mut statistics);
111            Ok(statistics)
112        }
113    }
114
115    pub fn get_heap_budgets(&self) -> VkResult<Vec<VmaBudget>> {
116        unsafe {
117            let len = self.get_memory_properties().memory_heap_count as usize;
118            let mut budgets = Vec::with_capacity(len);
119            vmaGetHeapBudgets(self.0, budgets.as_mut_ptr());
120            budgets.set_len(len);
121            Ok(budgets)
122        }
123    }
124
125    pub fn check_corruption(&self, flags: vk::MemoryPropertyFlags) -> VkResult<()> {
126        unsafe { vmaCheckCorruption(self.0, flags.bits()).result() }
127    }
128
129    pub fn get_allocation_info(&self, allocation: Allocation) -> VmaAllocationInfo {
130        unsafe {
131            let mut info: VmaAllocationInfo = mem::zeroed();
132            vmaGetAllocationInfo(self.0, allocation.0, &mut info);
133            info
134        }
135    }
136
137    pub unsafe fn set_current_frame_index(&self, frame_index: u32) {
138        vmaSetCurrentFrameIndex(self.0, frame_index);
139    }
140
141    pub unsafe fn map_memory(&self, allocation: Allocation) -> VkResult<*mut u8> {
142        let mut data = core::ptr::null_mut();
143        vmaMapMemory(self.0, allocation.0, &mut data).result()?;
144        Ok(data.cast())
145    }
146
147    pub unsafe fn unmap_memory(&self, allocation: Allocation) {
148        vmaUnmapMemory(self.0, allocation.0);
149    }
150
151    pub unsafe fn bind_buffer_memory(
152        &self,
153        allocation: Allocation,
154        buffer: vk::Buffer,
155    ) -> VkResult<()> {
156        vmaBindBufferMemory(self.0, allocation.0, buffer).result()
157    }
158
159    pub unsafe fn bind_buffer_memory2(
160        &self,
161        allocation: Allocation,
162        allocation_local_offset: vk::DeviceSize,
163        buffer: vk::Buffer,
164        next: *const core::ffi::c_void,
165    ) -> VkResult<()> {
166        vmaBindBufferMemory2(self.0, allocation.0, allocation_local_offset, buffer, next).result()
167    }
168
169    pub unsafe fn bind_image_memory(
170        &self,
171        allocation: Allocation,
172        image: vk::Image,
173    ) -> VkResult<()> {
174        vmaBindImageMemory(self.0, allocation.0, image).result()
175    }
176
177    pub unsafe fn bind_image_memory2(
178        &self,
179        allocation: Allocation,
180        allocation_local_offset: vk::DeviceSize,
181        image: vk::Image,
182        next: *const core::ffi::c_void,
183    ) -> VkResult<()> {
184        vmaBindImageMemory2(self.0, allocation.0, allocation_local_offset, image, next).result()
185    }
186
187    pub unsafe fn free_memory(&self, allocation: Allocation) {
188        vmaFreeMemory(self.0, allocation.0);
189    }
190
191    pub unsafe fn free_memory_pages(&self, allocations: &[Allocation]) {
192        vmaFreeMemoryPages(self.0, allocations.len(), allocations.as_ptr() as *mut _);
193    }
194
195    pub unsafe fn destroy_buffer(&self, buffer: vk::Buffer, allocation: Allocation) {
196        vmaDestroyBuffer(self.0, buffer, allocation.0)
197    }
198
199    pub unsafe fn destroy_image(&self, image: vk::Image, allocation: Allocation) {
200        vmaDestroyImage(self.0, image, allocation.0)
201    }
202
203    pub unsafe fn flush_allocation(
204        &self,
205        allocation: Allocation,
206        offset: vk::DeviceSize,
207        size: vk::DeviceSize,
208    ) -> VkResult<()> {
209        vmaFlushAllocation(self.0, allocation.0, offset, size).result()
210    }
211
212    pub unsafe fn invalidate_allocation(
213        &self,
214        allocation: Allocation,
215        offset: vk::DeviceSize,
216        size: vk::DeviceSize,
217    ) -> VkResult<()> {
218        vmaInvalidateAllocation(self.0, allocation.0, offset, size).result()
219    }
220}
221
222impl Drop for Allocator {
223    fn drop(&mut self) {
224        unsafe { vmaDestroyAllocator(self.0) };
225        self.0 = core::ptr::null_mut();
226    }
227}
228
229unsafe impl Send for Allocator {}
230unsafe impl Sync for Allocator {}
231
232#[rustfmt::skip]
233fn get_functions(
234    version: Version,
235    instance: &InstanceCommands,
236    device: &DeviceCommands,
237) -> VmaVulkanFunctions {
238    extern "system" fn get_instance_proc_addr(
239        _: vk::Instance,
240        _: *const core::ffi::c_char,
241    ) -> vk::PFN_vkVoidFunction {
242        panic!("VMA_DYNAMIC_VULKAN_FUNCTIONS is not supported!")
243    }
244
245    extern "system" fn get_device_proc_addr(
246        _: vk::Device,
247        _: *const core::ffi::c_char,
248    ) -> vk::PFN_vkVoidFunction {
249        panic!("VMA_DYNAMIC_VULKAN_FUNCTIONS is not supported!")
250    }
251
252    let mut functions = VmaVulkanFunctions {
253        vkGetInstanceProcAddr: get_instance_proc_addr,
254        vkGetDeviceProcAddr: get_device_proc_addr,
255        vkAllocateMemory: device.allocate_memory,
256        vkBindBufferMemory: device.bind_buffer_memory,
257        vkBindBufferMemory2KHR: device.bind_buffer_memory2_khr,
258        vkBindImageMemory: device.bind_image_memory,
259        vkBindImageMemory2KHR: device.bind_image_memory2_khr,
260        vkCmdCopyBuffer: device.cmd_copy_buffer,
261        vkCreateBuffer: device.create_buffer,
262        vkCreateImage: device.create_image,
263        vkDestroyBuffer: device.destroy_buffer,
264        vkDestroyImage: device.destroy_image,
265        vkFlushMappedMemoryRanges: device.flush_mapped_memory_ranges,
266        vkFreeMemory: device.free_memory,
267        vkGetBufferMemoryRequirements: device.get_buffer_memory_requirements,
268        vkGetBufferMemoryRequirements2KHR: device.get_buffer_memory_requirements2_khr,
269        vkGetDeviceBufferMemoryRequirements: device.get_device_buffer_memory_requirements,
270        vkGetDeviceImageMemoryRequirements: device.get_device_image_memory_requirements,
271        vkGetImageMemoryRequirements: device.get_image_memory_requirements,
272        vkGetImageMemoryRequirements2KHR: device.get_image_memory_requirements2_khr,
273        vkGetPhysicalDeviceMemoryProperties: instance.get_physical_device_memory_properties,
274        vkGetPhysicalDeviceMemoryProperties2KHR: instance.get_physical_device_memory_properties2_khr,
275        vkGetPhysicalDeviceProperties: instance.get_physical_device_properties,
276        vkInvalidateMappedMemoryRanges: device.invalidate_mapped_memory_ranges,
277        vkMapMemory: device.map_memory,
278        vkUnmapMemory: device.unmap_memory,
279    };
280
281    // Use standard functions for extensions that were adopted in 1.1.
282    if version >= Version::V1_1_0 {
283        functions.vkBindBufferMemory2KHR = device.bind_buffer_memory2;
284        functions.vkBindImageMemory2KHR = device.bind_image_memory2;
285        functions.vkGetBufferMemoryRequirements2KHR = device.get_buffer_memory_requirements2;
286        functions.vkGetImageMemoryRequirements2KHR = device.get_image_memory_requirements2;
287        functions.vkGetPhysicalDeviceMemoryProperties2KHR = instance.get_physical_device_memory_properties2;
288    }
289
290    functions
291}