1use {
107 ash::{vk, Device, Instance},
108 gpu_alloc_types::{
109 AllocationFlags, DeviceMapError, DeviceProperties, MappedMemoryRange, MemoryDevice,
110 MemoryHeap, MemoryPropertyFlags, MemoryType, OutOfMemory,
111 },
112 std::ptr::NonNull,
113 tinyvec::TinyVec,
114};
115
116#[repr(transparent)]
117pub struct AshMemoryDevice {
118 device: Device,
119}
120
121impl AshMemoryDevice {
122 pub fn wrap(device: &Device) -> &Self {
123 unsafe {
124 &*(device as *const Device as *const Self)
127 }
128 }
129}
130
131impl AsRef<AshMemoryDevice> for Device {
132 #[inline(always)]
133 fn as_ref(&self) -> &AshMemoryDevice {
134 AshMemoryDevice::wrap(self)
135 }
136}
137
138impl AsRef<AshMemoryDevice> for AshMemoryDevice {
141 #[inline(always)]
142 fn as_ref(&self) -> &AshMemoryDevice {
143 self
144 }
145}
146
147impl MemoryDevice<vk::DeviceMemory> for AshMemoryDevice {
148 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
149 unsafe fn allocate_memory(
150 &self,
151 size: u64,
152 memory_type: u32,
153 flags: AllocationFlags,
154 ) -> Result<vk::DeviceMemory, OutOfMemory> {
155 assert!((flags & !(AllocationFlags::DEVICE_ADDRESS)).is_empty());
156
157 let mut info = vk::MemoryAllocateInfo::default()
158 .allocation_size(size)
159 .memory_type_index(memory_type);
160
161 let mut info_flags;
162
163 if flags.contains(AllocationFlags::DEVICE_ADDRESS) {
164 info_flags = vk::MemoryAllocateFlagsInfo::default()
165 .flags(vk::MemoryAllocateFlags::DEVICE_ADDRESS);
166 info = info.push_next(&mut info_flags);
167 }
168
169 match self.device.allocate_memory(&info, None) {
170 Ok(memory) => Ok(memory),
171 Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => Err(OutOfMemory::OutOfDeviceMemory),
172 Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY) => Err(OutOfMemory::OutOfHostMemory),
173 Err(vk::Result::ERROR_TOO_MANY_OBJECTS) => panic!("Too many objects"),
174 Err(err) => panic!("Unexpected Vulkan error: `{}`", err),
175 }
176 }
177
178 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
179 unsafe fn deallocate_memory(&self, memory: vk::DeviceMemory) {
180 self.device.free_memory(memory, None);
181 }
182
183 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
184 unsafe fn map_memory(
185 &self,
186 memory: &mut vk::DeviceMemory,
187 offset: u64,
188 size: u64,
189 ) -> Result<NonNull<u8>, DeviceMapError> {
190 match self
191 .device
192 .map_memory(*memory, offset, size, vk::MemoryMapFlags::empty())
193 {
194 Ok(ptr) => {
195 Ok(NonNull::new(ptr as *mut u8)
196 .expect("Pointer to memory mapping must not be null"))
197 }
198 Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => Err(DeviceMapError::OutOfDeviceMemory),
199 Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY) => Err(DeviceMapError::OutOfHostMemory),
200 Err(vk::Result::ERROR_MEMORY_MAP_FAILED) => Err(DeviceMapError::MapFailed),
201 Err(err) => panic!("Unexpected Vulkan error: `{}`", err),
202 }
203 }
204
205 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
206 unsafe fn unmap_memory(&self, memory: &mut vk::DeviceMemory) {
207 self.device.unmap_memory(*memory);
208 }
209
210 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
211 unsafe fn invalidate_memory_ranges(
212 &self,
213 ranges: &[MappedMemoryRange<'_, vk::DeviceMemory>],
214 ) -> Result<(), OutOfMemory> {
215 self.device
216 .invalidate_mapped_memory_ranges(
217 &ranges
218 .iter()
219 .map(|range| {
220 vk::MappedMemoryRange::default()
221 .memory(*range.memory)
222 .offset(range.offset)
223 .size(range.size)
224 })
225 .collect::<TinyVec<[_; 4]>>(),
226 )
227 .map_err(|err| match err {
228 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => OutOfMemory::OutOfDeviceMemory,
229 vk::Result::ERROR_OUT_OF_HOST_MEMORY => OutOfMemory::OutOfHostMemory,
230 err => panic!("Unexpected Vulkan error: `{}`", err),
231 })
232 }
233
234 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
235 unsafe fn flush_memory_ranges(
236 &self,
237 ranges: &[MappedMemoryRange<'_, vk::DeviceMemory>],
238 ) -> Result<(), OutOfMemory> {
239 self.device
240 .flush_mapped_memory_ranges(
241 &ranges
242 .iter()
243 .map(|range| {
244 vk::MappedMemoryRange::default()
245 .memory(*range.memory)
246 .offset(range.offset)
247 .size(range.size)
248 })
249 .collect::<TinyVec<[_; 4]>>(),
250 )
251 .map_err(|err| match err {
252 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => OutOfMemory::OutOfDeviceMemory,
253 vk::Result::ERROR_OUT_OF_HOST_MEMORY => OutOfMemory::OutOfHostMemory,
254 err => panic!("Unexpected Vulkan error: `{}`", err),
255 })
256 }
257}
258
259pub unsafe fn device_properties(
269 instance: &Instance,
270 version: u32,
271 physical_device: vk::PhysicalDevice,
272) -> Result<DeviceProperties<'static>, vk::Result> {
273 use ash::vk::PhysicalDeviceFeatures2;
274
275 let limits = instance
276 .get_physical_device_properties(physical_device)
277 .limits;
278
279 let memory_properties = instance.get_physical_device_memory_properties(physical_device);
280
281 let buffer_device_address =
282 if vk::api_version_major(version) >= 1 && vk::api_version_minor(version) >= 2 {
283 let mut features = PhysicalDeviceFeatures2::default();
284 let mut bda_features = vk::PhysicalDeviceBufferDeviceAddressFeatures::default();
285 features.p_next =
286 &mut bda_features as *mut vk::PhysicalDeviceBufferDeviceAddressFeatures as *mut _;
287 instance.get_physical_device_features2(physical_device, &mut features);
288 bda_features.buffer_device_address != 0
289 } else {
290 false
291 };
292
293 Ok(DeviceProperties {
294 max_memory_allocation_count: limits.max_memory_allocation_count,
295 max_memory_allocation_size: u64::max_value(), non_coherent_atom_size: limits.non_coherent_atom_size,
297 memory_types: memory_properties.memory_types
298 [..memory_properties.memory_type_count as usize]
299 .iter()
300 .map(|memory_type| MemoryType {
301 props: memory_properties_from_ash(memory_type.property_flags),
302 heap: memory_type.heap_index,
303 })
304 .collect(),
305 memory_heaps: memory_properties.memory_heaps
306 [..memory_properties.memory_heap_count as usize]
307 .iter()
308 .map(|&memory_heap| MemoryHeap {
309 size: memory_heap.size,
310 })
311 .collect(),
312 buffer_device_address,
313 })
314}
315
316pub fn memory_properties_from_ash(props: vk::MemoryPropertyFlags) -> MemoryPropertyFlags {
317 let mut result = MemoryPropertyFlags::empty();
318 if props.contains(vk::MemoryPropertyFlags::DEVICE_LOCAL) {
319 result |= MemoryPropertyFlags::DEVICE_LOCAL;
320 }
321 if props.contains(vk::MemoryPropertyFlags::HOST_VISIBLE) {
322 result |= MemoryPropertyFlags::HOST_VISIBLE;
323 }
324 if props.contains(vk::MemoryPropertyFlags::HOST_COHERENT) {
325 result |= MemoryPropertyFlags::HOST_COHERENT;
326 }
327 if props.contains(vk::MemoryPropertyFlags::HOST_CACHED) {
328 result |= MemoryPropertyFlags::HOST_CACHED;
329 }
330 if props.contains(vk::MemoryPropertyFlags::LAZILY_ALLOCATED) {
331 result |= MemoryPropertyFlags::LAZILY_ALLOCATED;
332 }
333 result
334}
335
336pub fn memory_properties_to_ash(props: MemoryPropertyFlags) -> vk::MemoryPropertyFlags {
337 let mut result = vk::MemoryPropertyFlags::empty();
338 if props.contains(MemoryPropertyFlags::DEVICE_LOCAL) {
339 result |= vk::MemoryPropertyFlags::DEVICE_LOCAL;
340 }
341 if props.contains(MemoryPropertyFlags::HOST_VISIBLE) {
342 result |= vk::MemoryPropertyFlags::HOST_VISIBLE;
343 }
344 if props.contains(MemoryPropertyFlags::HOST_COHERENT) {
345 result |= vk::MemoryPropertyFlags::HOST_COHERENT;
346 }
347 if props.contains(MemoryPropertyFlags::HOST_CACHED) {
348 result |= vk::MemoryPropertyFlags::HOST_CACHED;
349 }
350 if props.contains(MemoryPropertyFlags::LAZILY_ALLOCATED) {
351 result |= vk::MemoryPropertyFlags::LAZILY_ALLOCATED;
352 }
353 result
354}