vulkan_lib/vma-rs/src/allocation.rs
2023-01-14 13:03:01 +01:00

470 lines
13 KiB
Rust

use crate::vma_bindings::*;
use anyhow::Result;
use vulkan_sys::prelude::*;
use crate::allocator_pool::AllocatorPool;
use std::mem::MaybeUninit;
use std::ptr;
use std::slice;
#[derive(Debug, Clone)]
pub struct AllocationBuilder {
allocator: VmaAllocator,
flags: VmaAllocationCreateFlags,
usage: VmaMemoryUsage,
required_flags: VkMemoryPropertyFlagBits,
preferred_flags: VkMemoryPropertyFlagBits,
memory_type_bits: u32,
priority: f32,
pool: Option<AllocatorPool>,
}
pub trait Build<T> {
fn build(self, argument: T) -> Result<Allocation>;
}
impl AllocationBuilder {
pub fn set_flags(mut self, flags: impl Into<VmaAllocationCreateFlags>) -> Self {
self.flags = flags.into();
self
}
pub fn set_usage(mut self, usage: VmaMemoryUsage) -> Self {
self.usage = usage;
self
}
pub fn priority(mut self, priority: f32) -> Self {
self.priority = priority;
self
}
pub fn set_required_flags(
mut self,
required_flags: impl Into<VkMemoryPropertyFlagBits>,
) -> Self {
self.required_flags = required_flags.into();
self
}
pub fn set_preferred_flags(
mut self,
preferred_flags: impl Into<VkMemoryPropertyFlagBits>,
) -> Self {
self.preferred_flags = preferred_flags.into();
self
}
pub fn set_memory_type_bits(mut self, memory_type_bits: u32) -> Self {
self.memory_type_bits = memory_type_bits;
self
}
pub fn set_pool(mut self, pool: AllocatorPool) -> Self {
self.pool = Some(pool);
self
}
fn vma_allocation_create_info(&self) -> VmaAllocationCreateInfo {
let mut create_info = VmaAllocationCreateInfo::new(
self.flags,
self.usage,
self.required_flags,
self.preferred_flags,
self.memory_type_bits,
self.priority,
);
if let Some(pool) = &self.pool {
create_info.set_pool(pool.pool());
}
create_info
}
}
impl Build<&VkMemoryRequirements> for AllocationBuilder {
fn build(self, memory_requirements: &VkMemoryRequirements) -> Result<Allocation> {
let create_info = self.vma_allocation_create_info();
let mut allocation = MaybeUninit::uninit();
let mut allocation_info = MaybeUninit::uninit();
let result = unsafe {
vmaAllocateMemory(
self.allocator,
memory_requirements,
&create_info,
allocation.as_mut_ptr(),
allocation_info.as_mut_ptr(),
)
};
if result == VK_SUCCESS {
Ok(Allocation::new(
self.allocator,
unsafe { allocation.assume_init() },
AllocationType::MemoryOnly,
unsafe { allocation_info.assume_init() },
))
} else {
Err(anyhow::Error::msg(format!(
"Failed allocating memory for Buffer: {:?}",
result
)))
}
}
}
impl Build<VkBuffer> for AllocationBuilder {
fn build(self, buffer: VkBuffer) -> Result<Allocation> {
let create_info = self.vma_allocation_create_info();
let mut allocation = MaybeUninit::uninit();
let mut allocation_info = MaybeUninit::uninit();
let result = unsafe {
vmaAllocateMemoryForBuffer(
self.allocator,
buffer,
&create_info,
allocation.as_mut_ptr(),
allocation_info.as_mut_ptr(),
)
};
if result == VK_SUCCESS {
let mut allocation = Allocation::new(
self.allocator,
unsafe { allocation.assume_init() },
AllocationType::MemoryOnly,
unsafe { allocation_info.assume_init() },
);
allocation.bind_buffer_memory(buffer)?;
Ok(allocation)
} else {
Err(anyhow::Error::msg(format!(
"Failed allocating memory for Buffer: {:?}",
result
)))
}
}
}
impl Build<VkImage> for AllocationBuilder {
fn build(self, image: VkImage) -> Result<Allocation> {
let create_info = self.vma_allocation_create_info();
let mut allocation = MaybeUninit::uninit();
let mut allocation_info = MaybeUninit::uninit();
let result = unsafe {
vmaAllocateMemoryForImage(
self.allocator,
image,
&create_info,
allocation.as_mut_ptr(),
allocation_info.as_mut_ptr(),
)
};
if result == VK_SUCCESS {
let mut allocation = Allocation::new(
self.allocator,
unsafe { allocation.assume_init() },
AllocationType::MemoryOnly,
unsafe { allocation_info.assume_init() },
);
allocation.bind_image_memory(image)?;
Ok(allocation)
} else {
Err(anyhow::Error::msg(format!(
"Failed allocating memory for Image: {:?}",
result
)))
}
}
}
impl Build<&VkImageCreateInfo> for AllocationBuilder {
fn build(self, image_create_info: &VkImageCreateInfo) -> Result<Allocation> {
let create_info = self.vma_allocation_create_info();
let mut image = MaybeUninit::uninit();
let mut allocation = MaybeUninit::uninit();
let mut allocation_info = MaybeUninit::uninit();
let result = unsafe {
vmaCreateImage(
self.allocator,
image_create_info,
&create_info,
image.as_mut_ptr(),
allocation.as_mut_ptr(),
allocation_info.as_mut_ptr(),
)
};
if result == VK_SUCCESS {
Ok(Allocation {
allocator: self.allocator,
allocation: unsafe { allocation.assume_init() },
allocation_type: AllocationType::Image(unsafe { image.assume_init() }),
allocation_info: unsafe { allocation_info.assume_init() },
})
} else {
Err(anyhow::Error::msg(format!(
"Failed creating Image and allocating memory for Image: {:?}",
result
)))
}
}
}
impl Build<&VkBufferCreateInfo> for AllocationBuilder {
fn build(self, buffer_create_info: &VkBufferCreateInfo) -> Result<Allocation> {
let create_info = self.vma_allocation_create_info();
let mut buffer = MaybeUninit::uninit();
let mut allocation = MaybeUninit::uninit();
let mut allocation_info = MaybeUninit::uninit();
let result = unsafe {
vmaCreateBuffer(
self.allocator,
buffer_create_info,
&create_info,
buffer.as_mut_ptr(),
allocation.as_mut_ptr(),
allocation_info.as_mut_ptr(),
)
};
if result == VK_SUCCESS {
Ok(Allocation {
allocator: self.allocator,
allocation: unsafe { allocation.assume_init() },
allocation_type: AllocationType::Buffer(unsafe { buffer.assume_init() }),
allocation_info: unsafe { allocation_info.assume_init() },
})
} else {
Err(anyhow::Error::msg(format!(
"Failed creating Buffer and allocating memory for Buffer: {:?}",
result
)))
}
}
}
impl AllocationBuilder {
pub(crate) fn new(allocator: VmaAllocator) -> Self {
AllocationBuilder {
allocator,
flags: VmaAllocationCreateFlags::default(),
usage: VmaMemoryUsage::VMA_MEMORY_USAGE_UNKNOWN,
required_flags: VkMemoryPropertyFlagBits::default(),
preferred_flags: VkMemoryPropertyFlagBits::default(),
memory_type_bits: 0,
priority: 0.0,
pool: None,
}
}
}
#[derive(Debug, Clone)]
enum AllocationType {
Buffer(VkBuffer),
Image(VkImage),
MemoryOnly,
}
#[derive(Debug, Clone)]
pub struct Allocation {
allocator: VmaAllocator,
allocation: VmaAllocation,
allocation_type: AllocationType,
allocation_info: VmaAllocationInfo,
}
unsafe impl Send for Allocation {}
unsafe impl Sync for Allocation {}
impl Allocation {
fn new(
allocator: VmaAllocator,
allocation: VmaAllocation,
allocation_type: AllocationType,
allocation_info: VmaAllocationInfo,
) -> Self {
Self {
allocator,
allocation,
allocation_type,
allocation_info,
}
}
pub fn memory_type_index(&self) -> u32 {
self.allocation_info.memoryType
}
pub fn device_memory(&self) -> VkDeviceMemory {
self.allocation_info.deviceMemory
}
pub fn offset(&self) -> VkDeviceSize {
self.allocation_info.offset
}
pub fn size(&self) -> VkDeviceSize {
self.allocation_info.size
}
pub fn map<T: Clone>(&self, length: VkDeviceSize) -> Result<VkMappedMemory<'_, T>> {
let mut data = MaybeUninit::uninit();
let result = unsafe { vmaMapMemory(self.allocator, self.allocation, data.as_mut_ptr()) };
let slice =
unsafe { slice::from_raw_parts_mut(data.assume_init() as *mut T, length as usize) };
if result == VK_SUCCESS {
let mut mapped_memory = VkMappedMemory::new(slice);
let allocation = self.allocation;
let allocator = self.allocator;
mapped_memory.set_unmap(move || unsafe { vmaUnmapMemory(allocator, allocation) });
Ok(mapped_memory)
} else {
Err(anyhow::Error::msg(format!(
"Mapping VkMemory failed: {:?}",
result
)))
}
}
pub fn buffer(&self) -> VkBuffer {
match self.allocation_type {
AllocationType::Buffer(buffer) => buffer,
AllocationType::Image(_) => panic!("Allocation is a VkBuffer"),
AllocationType::MemoryOnly => panic!("Allocation is memory only"),
}
}
pub fn image(&self) -> VkImage {
match self.allocation_type {
AllocationType::Buffer(_) => panic!("Allocation is a VkImage"),
AllocationType::Image(image) => image,
AllocationType::MemoryOnly => panic!("Allocation is memory only"),
}
}
pub fn bind_buffer_memory(&mut self, buffer: VkBuffer) -> Result<()> {
#[cfg(debug_assertions)]
{
match self.allocation_type {
AllocationType::Buffer(_) => panic!("allocation already bound to buffer"),
AllocationType::Image(_) => panic!("allocation already bound to image"),
AllocationType::MemoryOnly => (),
}
}
let result = unsafe { vmaBindBufferMemory(self.allocator, self.allocation, buffer) };
if result == VK_SUCCESS {
Ok(())
} else {
Err(anyhow::Error::msg(format!(
"Failed binding Buffer to memory: {:?}",
result
)))
}
}
pub fn bind_image_memory(&mut self, image: VkImage) -> Result<()> {
#[cfg(debug_assertions)]
{
match self.allocation_type {
AllocationType::Buffer(_) => panic!("allocation already bound to buffer"),
AllocationType::Image(_) => panic!("allocation already bound to image"),
AllocationType::MemoryOnly => (),
}
}
let result = unsafe { vmaBindImageMemory(self.allocator, self.allocation, image) };
if result == VK_SUCCESS {
Ok(())
} else {
Err(anyhow::Error::msg(format!(
"Failed binding Image to memory: {:?}",
result
)))
}
}
}
impl Drop for Allocation {
fn drop(&mut self) {
match self.allocation_type {
AllocationType::Buffer(buffer) => unsafe {
vmaDestroyBuffer(self.allocator, buffer, self.allocation)
},
AllocationType::Image(image) => unsafe {
vmaDestroyImage(self.allocator, image, self.allocation)
},
AllocationType::MemoryOnly => unsafe { vmaFreeMemory(self.allocator, self.allocation) },
}
}
}
impl VmaAllocationCreateInfo {
pub fn new(
flags: impl Into<VmaAllocationCreateFlags>,
usage: VmaMemoryUsage,
required_flags: VkMemoryPropertyFlagBits,
preferred_flags: VkMemoryPropertyFlagBits,
memory_type_bits: u32,
priority: f32,
) -> Self {
VmaAllocationCreateInfo {
flags: flags.into(),
usage,
requiredFlags: required_flags,
preferredFlags: preferred_flags,
memoryTypeBits: memory_type_bits,
pool: ptr::null_mut(),
pUserData: ptr::null_mut(),
priority,
}
}
pub fn set_pool(&mut self, pool: VmaPool) {
self.pool = pool;
}
// pub fn set_user_data<T>(&mut self, data: &mut T) {
// self.pUserData = data as *mut T as *mut _
// }
}