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, } pub trait Build { fn build(self, argument: T) -> Result; } impl AllocationBuilder { pub fn set_flags(mut self, flags: impl Into) -> 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, ) -> Self { self.required_flags = required_flags.into(); self } pub fn set_preferred_flags( mut self, preferred_flags: impl Into, ) -> 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 { 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 for AllocationBuilder { fn build(self, buffer: VkBuffer) -> Result { 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 for AllocationBuilder { fn build(self, image: VkImage) -> Result { 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 { 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 { 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(&self, length: VkDeviceSize) -> Result> { 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, 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(&mut self, data: &mut T) { // self.pUserData = data as *mut T as *mut _ // } }