1use 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 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}