|
- 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
|