use super::device::DeviceInner;
use super::{Device, DeviceMemory, Error, Result, check};
use crate::raw::bindings::*;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BufferUsage(pub u32);
impl BufferUsage {
pub const TRANSFER_SRC: Self = Self(0x1);
pub const TRANSFER_DST: Self = Self(0x2);
pub const UNIFORM_TEXEL_BUFFER: Self = Self(0x4);
pub const STORAGE_TEXEL_BUFFER: Self = Self(0x8);
pub const UNIFORM_BUFFER: Self = Self(0x10);
pub const STORAGE_BUFFER: Self = Self(0x20);
pub const INDEX_BUFFER: Self = Self(0x40);
pub const VERTEX_BUFFER: Self = Self(0x80);
pub const INDIRECT_BUFFER: Self = Self(0x100);
pub const SHADER_DEVICE_ADDRESS: Self = Self(0x20000);
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
}
impl std::ops::BitOr for BufferUsage {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
}
#[derive(Debug, Clone)]
pub struct BufferCreateInfo {
pub size: u64,
pub usage: BufferUsage,
}
#[derive(Debug, Clone, Copy)]
pub struct MemoryRequirements {
pub size: u64,
pub alignment: u64,
pub memory_type_bits: u32,
}
pub struct Buffer {
pub(crate) handle: VkBuffer,
pub(crate) device: Arc<DeviceInner>,
pub(crate) size: u64,
}
impl Buffer {
pub fn new(device: &Device, info: BufferCreateInfo) -> Result<Self> {
let create = device
.inner
.dispatch
.vkCreateBuffer
.ok_or(Error::MissingFunction("vkCreateBuffer"))?;
let create_info = VkBufferCreateInfo {
sType: VkStructureType::STRUCTURE_TYPE_BUFFER_CREATE_INFO,
size: info.size,
usage: info.usage.0,
sharingMode: VkSharingMode::SHARING_MODE_EXCLUSIVE,
..Default::default()
};
let mut handle: VkBuffer = 0;
check(unsafe {
create(
device.inner.handle,
&create_info,
std::ptr::null(),
&mut handle,
)
})?;
Ok(Self {
handle,
device: Arc::clone(&device.inner),
size: info.size,
})
}
pub fn new_bound(
device: &Device,
physical: &super::PhysicalDevice,
info: BufferCreateInfo,
memory_flags: super::MemoryPropertyFlags,
) -> Result<(Buffer, DeviceMemory)> {
let buffer = Buffer::new(device, info)?;
let req = buffer.memory_requirements();
let type_index = physical
.find_memory_type(req.memory_type_bits, memory_flags)
.ok_or(Error::InvalidArgument(
"no compatible memory type for the requested property flags",
))?;
let memory = DeviceMemory::allocate(device, req.size, type_index)?;
buffer.bind_memory(&memory, 0)?;
Ok((buffer, memory))
}
pub fn raw(&self) -> VkBuffer {
self.handle
}
pub fn size(&self) -> u64 {
self.size
}
pub fn memory_requirements(&self) -> MemoryRequirements {
let get = self
.device
.dispatch
.vkGetBufferMemoryRequirements
.expect("vkGetBufferMemoryRequirements is required by Vulkan 1.0");
let mut req: VkMemoryRequirements = unsafe { std::mem::zeroed() };
unsafe { get(self.device.handle, self.handle, &mut req) };
MemoryRequirements {
size: req.size,
alignment: req.alignment,
memory_type_bits: req.memoryTypeBits,
}
}
pub fn bind_memory(&self, memory: &DeviceMemory, offset: u64) -> Result<()> {
let bind = self
.device
.dispatch
.vkBindBufferMemory
.ok_or(Error::MissingFunction("vkBindBufferMemory"))?;
check(unsafe { bind(self.device.handle, self.handle, memory.handle, offset) })
}
pub fn device_address(&self) -> Result<u64> {
let get = self
.device
.dispatch
.vkGetBufferDeviceAddress
.ok_or(Error::MissingFunction("vkGetBufferDeviceAddress"))?;
let info = VkBufferDeviceAddressInfo {
sType: VkStructureType::STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
buffer: self.handle,
..Default::default()
};
let addr = unsafe { get(self.device.handle, &info) };
Ok(addr)
}
}
impl Drop for Buffer {
fn drop(&mut self) {
if let Some(destroy) = self.device.dispatch.vkDestroyBuffer {
unsafe { destroy(self.device.handle, self.handle, std::ptr::null()) };
}
}
}