use std::{ borrow::Cow, ops::{Deref, DerefMut}, sync::Arc, }; use ash::{prelude::VkResult, vk}; use itertools::Itertools; use vk_mem::Alloc; use crate::{ define_device_owned_handle, device::{DeviceOwned, QueueFlags}, Device, }; #[derive(Clone)] pub struct BufferDesc { pub flags: vk::BufferCreateFlags, pub name: Option>, pub size: u64, pub usage: vk::BufferUsageFlags, pub queue_families: QueueFlags, pub mem_usage: vk_mem::MemoryUsage, pub alloc_flags: vk_mem::AllocationCreateFlags, } impl std::hash::Hash for BufferDesc { fn hash(&self, state: &mut H) { self.flags.hash(state); self.size.hash(state); self.usage.hash(state); self.queue_families.hash(state); self.mem_usage.hash(state); self.alloc_flags.bits().hash(state); } } impl std::fmt::Debug for BufferDesc { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("BufferDesc") .field("flags", &self.flags) .field("name", &self.name) .field("size", &self.size) .field("usage", &self.usage) .field("queue_families", &self.queue_families) .field("mem_usage", &self.mem_usage) .field_with("alloc_flags", |f| { write!( f, "{}", self.alloc_flags .iter_names() .map(|(name, _)| name) .format(" | ") ) }) .finish() } } impl Eq for BufferDesc {} impl PartialEq for BufferDesc { fn eq(&self, other: &Self) -> bool { self.flags == other.flags // for hashmaps, `Eq` may be more strict than `Hash` && self.name == other.name && self.size == other.size && self.usage == other.usage && self.queue_families == other.queue_families && self.mem_usage == other.mem_usage && self.alloc_flags.bits() == other.alloc_flags.bits() } } impl Default for BufferDesc { fn default() -> Self { Self { flags: Default::default(), name: Default::default(), size: Default::default(), usage: Default::default(), queue_families: QueueFlags::empty(), alloc_flags: vk_mem::AllocationCreateFlags::empty(), mem_usage: vk_mem::MemoryUsage::Auto, } } } define_device_owned_handle! { #[derive(Debug)] pub Buffer(vk::Buffer) { alloc: vk_mem::Allocation, size: u64, } => |this| unsafe { this.device().clone().alloc().destroy_buffer(this.handle(), &mut this.alloc); } } impl Eq for Buffer {} impl PartialEq for Buffer { fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl Buffer { pub fn new(device: Device, desc: BufferDesc) -> VkResult { let queue_families = device.queue_families().family_indices(desc.queue_families); let sharing_mode = if queue_families.len() > 1 { vk::SharingMode::CONCURRENT } else { vk::SharingMode::EXCLUSIVE }; let (buffer, allocation) = unsafe { device.alloc().create_buffer( &vk::BufferCreateInfo::default() .size(desc.size) .usage(desc.usage) .queue_family_indices(&queue_families) .sharing_mode(sharing_mode), &vk_mem::AllocationCreateInfo { flags: desc.alloc_flags, usage: desc.mem_usage, ..Default::default() }, )? }; Ok(Self::construct( device, buffer, desc.name, allocation, desc.size, )?) } #[allow(dead_code)] pub fn map_arc(self: &mut Arc) -> VkResult> { Arc::get_mut(self).map(Self::map).unwrap() } pub fn map(&mut self) -> VkResult> { let bytes = unsafe { let data = self.inner.dev().alloc().map_memory(&mut self.alloc)?; let slice = core::slice::from_raw_parts_mut(data, self.size as usize); slice }; Ok(MappedBuffer { inner: self, bytes }) } pub fn buffer(&self) -> vk::Buffer { self.handle() } pub fn len(&self) -> u64 { self.size } } pub struct MappedBuffer<'a> { bytes: &'a mut [u8], inner: &'a mut Buffer, } impl Drop for MappedBuffer<'_> { fn drop(&mut self) { unsafe { self.inner .inner .dev() .alloc() .unmap_memory(&mut self.inner.alloc); } } } impl Deref for MappedBuffer<'_> { type Target = [u8]; fn deref(&self) -> &Self::Target { self.bytes } } impl DerefMut for MappedBuffer<'_> { fn deref_mut(&mut self) -> &mut Self::Target { self.bytes } }