You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

273 lines
6.0 KiB

use crate::render::{
CommandPool, Device, PhysicalDevice, Queue, Uniforms, Vertex,
};
use ash::{
version::{DeviceV1_0, InstanceV1_0},
vk,
};
use std::rc::Rc;
pub struct Buffer {
handle: vk::Buffer,
memory: vk::DeviceMemory,
pub device: Rc<Device>,
}
#[derive(Debug)]
pub enum ErrBufferCreate {
Vk(vk::Result),
NoMemoryType(vk::MemoryPropertyFlags, u32),
}
fn get_memory_type(
memory_props: vk::PhysicalDeviceMemoryProperties,
filter_flags: vk::MemoryPropertyFlags,
filter_types: u32,
) -> Result<u32, ErrBufferCreate> {
let count = memory_props.memory_type_count as usize;
let iter = memory_props.memory_types.iter().take(count).enumerate();
for (i, memory_type) in iter {
let has_flags = memory_type.property_flags.contains(filter_flags);
let has_types = filter_types & 1 << i;
if has_flags && has_types != 0 {
return Ok(i as u32);
}
}
Err(ErrBufferCreate::NoMemoryType(filter_flags, filter_types))
}
unsafe fn create_buffer(
device: &Device,
phys_device: &PhysicalDevice,
size: vk::DeviceSize,
usage: vk::BufferUsageFlags,
mem_flags: vk::MemoryPropertyFlags,
) -> Result<(vk::Buffer, vk::DeviceMemory), ErrBufferCreate> {
let create_info = vk::BufferCreateInfo {
size,
usage,
sharing_mode: vk::SharingMode::EXCLUSIVE,
..Default::default()
};
let handle = device.create_buffer(&create_info, None)?;
let memory_reqs = device.get_buffer_memory_requirements(handle);
let memory_props =
device.instance.get_physical_device_memory_properties(**phys_device);
let memory_type_index = get_memory_type(
memory_props,
mem_flags,
memory_reqs.memory_type_bits
)?;
let allocate_info = vk::MemoryAllocateInfo {
memory_type_index,
allocation_size: memory_reqs.size,
..Default::default()
};
let memory = device.allocate_memory(&allocate_info, None)?;
device.bind_buffer_memory(handle, memory, 0)?;
Ok((handle, memory))
}
/// Returns the size of `data` as a `vk::DeviceSize`.
fn dev_size_of<T>(data: &[T]) -> vk::DeviceSize {
(std::mem::size_of::<T>() * data.len()) as vk::DeviceSize
}
impl Buffer {
/// Creates a vertex buffer.
pub fn create_vertex(
device: Rc<Device>,
phys_device: &PhysicalDevice,
vertices: &[Vertex],
queue: &Queue,
) -> Result<Rc<Self>, ErrBufferCreate> {
let size = dev_size_of(vertices);
unsafe {
let (handle, memory) = create_buffer(
&device,
phys_device,
size,
vk::BufferUsageFlags::TRANSFER_DST |
vk::BufferUsageFlags::VERTEX_BUFFER,
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?;
let dst = Self { handle, memory, device };
dst.xfer_data(queue, phys_device, vertices)?;
Ok(Rc::new(dst))
}
}
/// Creates an index buffer.
pub fn create_index(
device: Rc<Device>,
phys_device: &PhysicalDevice,
indices: &[u16],
queue: &Queue,
) -> Result<Rc<Self>, ErrBufferCreate> {
let size = dev_size_of(indices);
unsafe {
let (handle, memory) = create_buffer(
&device,
phys_device,
size,
vk::BufferUsageFlags::TRANSFER_DST |
vk::BufferUsageFlags::INDEX_BUFFER,
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?;
let dst = Self { handle, memory, device };
dst.xfer_data(queue, phys_device, indices)?;
Ok(Rc::new(dst))
}
}
/// Creates a uniform buffer.
pub fn create_uniform(
device: Rc<Device>,
phys_device: &PhysicalDevice,
) -> Result<Rc<Self>, ErrBufferCreate> {
let (handle, memory) = unsafe {
create_buffer(
&device,
phys_device,
std::mem::size_of::<Uniforms>() as vk::DeviceSize,
vk::BufferUsageFlags::UNIFORM_BUFFER,
vk::MemoryPropertyFlags::HOST_VISIBLE |
vk::MemoryPropertyFlags::HOST_COHERENT,
)?
};
Ok(Rc::new(Self { handle, memory, device }))
}
/// Copies the contents of `src` to `self` using a transient pool.
unsafe fn copy_buffer(
&self,
src: &Self,
size: vk::DeviceSize,
queue: &Queue,
) -> Result<(), vk::Result> {
let pool = CommandPool::create_transfer(
self.device.clone(),
queue.index,
|cmd| cmd.transfer(src.handle, self.handle, size),
)?;
let submit_buffers = pool.buf_handles();
let submit_info = [
vk::SubmitInfo {
command_buffer_count: submit_buffers.len() as u32,
p_command_buffers: submit_buffers.as_ptr(),
..Default::default()
}
];
self.device.queue_submit(**queue, &submit_info, vk::Fence::null())?;
self.device.queue_wait_idle(**queue)
}
/// Transfers `data` from the client to the server.
pub fn xfer_data<T>(
&self,
queue: &Queue,
phys_device: &PhysicalDevice,
data: &[T],
) -> Result<(), ErrBufferCreate> {
let size = dev_size_of(data);
unsafe {
let (handle, memory) = create_buffer(
&self.device,
phys_device,
size,
vk::BufferUsageFlags::TRANSFER_SRC,
vk::MemoryPropertyFlags::HOST_VISIBLE |
vk::MemoryPropertyFlags::HOST_COHERENT,
)?;
let src = Self { handle, memory, device: self.device.clone() };
src.write_data(data)?;
self.copy_buffer(&src, size, queue)?;
}
Ok(())
}
/// Writes `data` to `self`.
pub fn write_data<T>(&self, data: &[T]) -> Result<(), vk::Result> {
let size = dev_size_of(data);
unsafe {
let flg = vk::MemoryMapFlags::empty();
let map = self.device.map_memory(self.memory, 0, size, flg)?;
(map as *mut T).copy_from(data.as_ptr(), data.len());
self.device.unmap_memory(self.memory);
}
Ok(())
}
}
impl Drop for Buffer {
fn drop(&mut self) {
unsafe {
self.device.free_memory(self.memory, None);
self.device.destroy_buffer(self.handle, None);
}
}
}
impl std::ops::Deref for Buffer {
type Target = vk::Buffer;
fn deref(&self) -> &Self::Target {
&self.handle
}
}
impl std::error::Error for ErrBufferCreate {}
impl From<vk::Result> for ErrBufferCreate {
fn from(res: vk::Result) -> Self {
Self::Vk(res)
}
}
impl std::fmt::Display for ErrBufferCreate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Vk(res) => res.fmt(f),
Self::NoMemoryType(filter_flags, filter_type) => write!(
f,
"No memory type matching {{ flags: {:?}, type: {} }}",
filter_flags, filter_type,
),
}
}
}
// EOF