use std::ffi::c_void;
use std::ptr::NonNull;
use std::sync::{Arc, Mutex};
use anyhow::Result;
use ash::vk::{DeviceMemory, DeviceSize, MemoryRequirements};
use gpu_allocator::vulkan as vk_alloc;
use gpu_allocator::vulkan::AllocationScheme;
use crate::{Allocator, Device, Error, Instance, PhysicalDevice};
use crate::allocator::memory_type::MemoryType;
use crate::allocator::traits;
#[derive(Clone, Derivative)]
#[derivative(Debug)]
pub struct DefaultAllocator {
#[derivative(Debug = "ignore")]
alloc: Arc<Mutex<vk_alloc::Allocator>>,
}
#[derive(Derivative)]
#[derivative(Default, Debug)]
pub struct Allocation {
allocator: Option<DefaultAllocator>,
allocation: Option<vk_alloc::Allocation>,
}
impl DefaultAllocator {
pub fn new(
instance: &Instance,
device: &Device,
physical_device: &PhysicalDevice,
) -> Result<Self> {
Ok(Self {
alloc: Arc::new(Mutex::new(vk_alloc::Allocator::new(
&vk_alloc::AllocatorCreateDesc {
instance: (*instance).clone(),
device: unsafe { device.handle() },
physical_device: unsafe { physical_device.handle() },
debug_settings: Default::default(),
buffer_device_address: true,
},
)?)),
})
}
}
impl DefaultAllocator {
fn free_impl(&mut self, allocation: &mut <Self as Allocator>::Allocation) -> Result<()> {
let mut alloc = self.alloc.lock().map_err(|_| Error::PoisonError)?;
match allocation.allocation.take() {
None => {}
Some(allocation) => {
alloc.free(allocation)?;
}
}
Ok(())
}
}
impl Allocator for DefaultAllocator {
type Allocation = Allocation;
fn allocate(
&mut self,
name: &'static str,
requirements: &MemoryRequirements,
ty: MemoryType,
) -> Result<Self::Allocation> {
let mut alloc = self.alloc.lock().map_err(|_| Error::PoisonError)?;
let allocation = alloc.allocate(&vk_alloc::AllocationCreateDesc {
name,
requirements: *requirements,
location: gpu_allocator::MemoryLocation::from(ty),
linear: false,
allocation_scheme: AllocationScheme::GpuAllocatorManaged,
})?;
Ok(Allocation {
allocator: Some(self.clone()),
allocation: Some(allocation),
})
}
fn free(&mut self, mut allocation: Self::Allocation) -> Result<()> {
self.free_impl(&mut allocation)
}
}
impl traits::Allocation for Allocation {
unsafe fn memory(&self) -> DeviceMemory {
self.allocation.as_ref().unwrap().memory()
}
fn offset(&self) -> DeviceSize {
self.allocation.as_ref().unwrap().offset()
}
fn mapped_ptr(&self) -> Option<NonNull<c_void>> {
self.allocation.as_ref().unwrap().mapped_ptr()
}
}
impl Drop for Allocation {
fn drop(&mut self) {
let mut allocator = self.allocator.clone().unwrap();
allocator.free_impl(self).unwrap();
}
}