gpu_alloc_vulkanalia/
lib.rs1use std::ptr::NonNull;
2
3use gpu_alloc_types::{
4 AllocationFlags, DeviceMapError, DeviceProperties, MappedMemoryRange, MemoryDevice, MemoryHeap,
5 MemoryPropertyFlags, MemoryType, OutOfMemory,
6};
7use smallvec::SmallVec;
8use vulkanalia::prelude::v1_0::*;
9use vulkanalia::vk::InstanceV1_1;
10
11pub trait AsMemoryDevice {
13 fn as_memory_device(&self) -> &VulkanaliaMemoryDevice;
15}
16
17impl AsMemoryDevice for Device {
18 fn as_memory_device(&self) -> &VulkanaliaMemoryDevice {
19 VulkanaliaMemoryDevice::wrap(self)
20 }
21}
22
23#[repr(transparent)]
25pub struct VulkanaliaMemoryDevice {
26 device: Device,
27}
28
29impl VulkanaliaMemoryDevice {
30 pub fn wrap(device: &Device) -> &Self {
31 unsafe {
32 &*(device as *const Device).cast::<Self>()
34 }
35 }
36}
37
38impl MemoryDevice<vk::DeviceMemory> for VulkanaliaMemoryDevice {
39 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
40 unsafe fn allocate_memory(
41 &self,
42 size: u64,
43 memory_type: u32,
44 flags: AllocationFlags,
45 ) -> Result<vk::DeviceMemory, OutOfMemory> {
46 assert!((flags & !(AllocationFlags::DEVICE_ADDRESS)).is_empty());
47
48 let mut info = vk::MemoryAllocateInfo::builder()
49 .allocation_size(size)
50 .memory_type_index(memory_type);
51
52 let mut info_flags;
53
54 if flags.contains(AllocationFlags::DEVICE_ADDRESS) {
55 info_flags = vk::MemoryAllocateFlagsInfo::builder()
56 .flags(vk::MemoryAllocateFlags::DEVICE_ADDRESS);
57 info = info.push_next(&mut info_flags);
58 }
59
60 match self.device.allocate_memory(&info, None) {
61 Ok(memory) => Ok(memory),
62 Err(vk::ErrorCode::OUT_OF_DEVICE_MEMORY) => Err(OutOfMemory::OutOfDeviceMemory),
63 Err(vk::ErrorCode::OUT_OF_HOST_MEMORY) => Err(OutOfMemory::OutOfHostMemory),
64 Err(e) => panic!("Unexpected Vulkan error: {e}"),
65 }
66 }
67
68 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
69 unsafe fn deallocate_memory(&self, memory: vk::DeviceMemory) {
70 self.device.free_memory(memory, None);
71 }
72
73 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
74 unsafe fn map_memory(
75 &self,
76 memory: &mut vk::DeviceMemory,
77 offset: u64,
78 size: u64,
79 ) -> Result<std::ptr::NonNull<u8>, DeviceMapError> {
80 match self
81 .device
82 .map_memory(*memory, offset, size, vk::MemoryMapFlags::empty())
83 {
84 Ok(ptr) => {
85 Ok(NonNull::new(ptr as *mut u8)
86 .expect("Pointer to memory mapping must not be null"))
87 }
88 Err(vk::ErrorCode::OUT_OF_DEVICE_MEMORY) => Err(DeviceMapError::OutOfDeviceMemory),
89 Err(vk::ErrorCode::OUT_OF_HOST_MEMORY) => Err(DeviceMapError::OutOfHostMemory),
90 Err(vk::ErrorCode::MEMORY_MAP_FAILED) => Err(DeviceMapError::MapFailed),
91 Err(e) => panic!("Unexpected Vulkan error: {e}"),
92 }
93 }
94
95 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
96 unsafe fn unmap_memory(&self, memory: &mut vk::DeviceMemory) {
97 self.device.unmap_memory(*memory);
98 }
99
100 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
101 unsafe fn invalidate_memory_ranges(
102 &self,
103 ranges: &[MappedMemoryRange<'_, vk::DeviceMemory>],
104 ) -> Result<(), OutOfMemory> {
105 self.device
106 .invalidate_mapped_memory_ranges(
107 &ranges
108 .iter()
109 .map(|range| {
110 vk::MappedMemoryRange::builder()
111 .memory(*range.memory)
112 .offset(range.offset)
113 .size(range.size)
114 })
115 .collect::<SmallVec<[_; 4]>>(),
116 )
117 .map_err(|e| match e {
118 vk::ErrorCode::OUT_OF_DEVICE_MEMORY => OutOfMemory::OutOfDeviceMemory,
119 vk::ErrorCode::OUT_OF_HOST_MEMORY => OutOfMemory::OutOfHostMemory,
120 e => panic!("Unexpected Vulkan error: {e}"),
121 })
122 }
123
124 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
125 unsafe fn flush_memory_ranges(
126 &self,
127 ranges: &[MappedMemoryRange<'_, vk::DeviceMemory>],
128 ) -> Result<(), OutOfMemory> {
129 self.device
130 .flush_mapped_memory_ranges(
131 &ranges
132 .iter()
133 .map(|range| {
134 vk::MappedMemoryRange::builder()
135 .memory(*range.memory)
136 .offset(range.offset)
137 .size(range.size)
138 })
139 .collect::<SmallVec<[_; 4]>>(),
140 )
141 .map_err(|e| match e {
142 vk::ErrorCode::OUT_OF_DEVICE_MEMORY => OutOfMemory::OutOfDeviceMemory,
143 vk::ErrorCode::OUT_OF_HOST_MEMORY => OutOfMemory::OutOfHostMemory,
144 e => panic!("Unexpected Vulkan error: {e}"),
145 })
146 }
147}
148
149pub unsafe fn device_properties(
164 instance: &Instance,
165 version: u32,
166 physical_device: vk::PhysicalDevice,
167) -> VkResult<DeviceProperties<'static>> {
168 struct ExtInfo {
169 buffer_device_address: bool,
170 max_memory_allocation_size: u64,
171 }
172
173 let memory_properties = instance.get_physical_device_memory_properties(physical_device);
174
175 let (query_props, query_features) = 'query: {
177 let mut required_extensions: [_; 2] = [
178 Some(&vk::KHR_MAINTENANCE3_EXTENSION.name),
179 Some(&vk::KHR_BUFFER_DEVICE_ADDRESS_EXTENSION.name),
180 ];
181
182 match vk::version_minor(version) {
183 0 => {
184 if !instance
185 .extensions()
186 .contains(&vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name)
187 {
188 break 'query (false, false);
190 }
191 }
192 1 => {
193 required_extensions[1] = None;
195 }
196 _ => {
197 required_extensions = [None, None];
199 }
200 }
201
202 if required_extensions.iter().any(Option::is_some) {
203 let extensions =
204 instance.enumerate_device_extension_properties(physical_device, None)?;
205
206 let mut to_find = required_extensions.len();
208 'extensions: for extension in extensions {
209 if to_find == 0 {
210 break 'extensions;
211 }
212
213 for required in required_extensions.iter_mut() {
214 if let Some(name) = *required {
215 if name == &extension.extension_name {
216 *required = None;
217 to_find -= 1;
218 continue 'extensions;
219 }
220 }
221 }
222 }
223
224 let [limits_ext, bda_ext] = required_extensions;
225 (limits_ext.is_none(), bda_ext.is_none())
226 } else {
227 (true, true)
228 }
229 };
230
231 let mut ext_info = ExtInfo {
232 buffer_device_address: false,
233 max_memory_allocation_size: u64::MAX,
234 };
235
236 let limits = if query_props {
238 let mut properties = vk::PhysicalDeviceProperties2::builder();
239 let mut maintenance3 = vk::PhysicalDeviceMaintenance3Properties::builder();
240 properties = properties.push_next(&mut maintenance3);
241 instance.get_physical_device_properties2(physical_device, &mut properties);
242
243 let limits = properties.properties.limits;
244 ext_info.max_memory_allocation_size = maintenance3.max_memory_allocation_size;
245 limits
246 } else {
247 instance
248 .get_physical_device_properties(physical_device)
249 .limits
250 };
251
252 if query_features {
254 let mut features = vk::PhysicalDeviceFeatures2::builder();
255 let mut bda_features = vk::PhysicalDeviceBufferDeviceAddressFeatures::builder();
256 features = features.push_next(&mut bda_features);
257 instance.get_physical_device_features2(physical_device, &mut features);
258
259 ext_info.buffer_device_address = bda_features.buffer_device_address != 0;
260 };
261
262 Ok(DeviceProperties {
264 memory_types: memory_properties.memory_types
265 [..memory_properties.memory_type_count as usize]
266 .iter()
267 .map(|memory_type| MemoryType {
268 props: memory_properties_from(memory_type.property_flags),
269 heap: memory_type.heap_index,
270 })
271 .collect(),
272 memory_heaps: memory_properties.memory_heaps
273 [..memory_properties.memory_heap_count as usize]
274 .iter()
275 .map(|memory_heap| MemoryHeap {
276 size: memory_heap.size,
277 })
278 .collect(),
279 max_memory_allocation_count: limits.max_memory_allocation_count,
280 max_memory_allocation_size: ext_info.max_memory_allocation_size,
281 non_coherent_atom_size: limits.non_coherent_atom_size,
282 buffer_device_address: ext_info.buffer_device_address,
283 })
284}
285
286pub fn memory_properties_from(props: vk::MemoryPropertyFlags) -> MemoryPropertyFlags {
288 let mut result = MemoryPropertyFlags::empty();
289 if props.contains(vk::MemoryPropertyFlags::DEVICE_LOCAL) {
290 result |= MemoryPropertyFlags::DEVICE_LOCAL;
291 }
292 if props.contains(vk::MemoryPropertyFlags::HOST_VISIBLE) {
293 result |= MemoryPropertyFlags::HOST_VISIBLE;
294 }
295 if props.contains(vk::MemoryPropertyFlags::HOST_COHERENT) {
296 result |= MemoryPropertyFlags::HOST_COHERENT;
297 }
298 if props.contains(vk::MemoryPropertyFlags::HOST_CACHED) {
299 result |= MemoryPropertyFlags::HOST_CACHED;
300 }
301 if props.contains(vk::MemoryPropertyFlags::LAZILY_ALLOCATED) {
302 result |= MemoryPropertyFlags::LAZILY_ALLOCATED;
303 }
304 result
305}
306
307pub fn memory_properties_to(props: MemoryPropertyFlags) -> vk::MemoryPropertyFlags {
309 let mut result = vk::MemoryPropertyFlags::empty();
310 if props.contains(MemoryPropertyFlags::DEVICE_LOCAL) {
311 result |= vk::MemoryPropertyFlags::DEVICE_LOCAL;
312 }
313 if props.contains(MemoryPropertyFlags::HOST_VISIBLE) {
314 result |= vk::MemoryPropertyFlags::HOST_VISIBLE;
315 }
316 if props.contains(MemoryPropertyFlags::HOST_COHERENT) {
317 result |= vk::MemoryPropertyFlags::HOST_COHERENT;
318 }
319 if props.contains(MemoryPropertyFlags::HOST_CACHED) {
320 result |= vk::MemoryPropertyFlags::HOST_CACHED;
321 }
322 if props.contains(MemoryPropertyFlags::LAZILY_ALLOCATED) {
323 result |= vk::MemoryPropertyFlags::LAZILY_ALLOCATED;
324 }
325 result
326}