crystal-vk 0.1.1

Graphics wrapper for Vulkan
Documentation
use std::{
    error::Error,
    marker::PhantomData,
    ops::Range,
    sync::{Arc, RwLock},
};

use ash::vk;

use crate::{
    device::Device,
    traits::{CommandBufferBinding, DescriptorSetBinding},
};

pub trait BufferUsage {}

pub struct VertexBuffer {}
impl BufferUsage for VertexBuffer {}

pub struct IndexBuffer {}
impl BufferUsage for IndexBuffer {}

pub struct InderectBuffer {}
impl BufferUsage for InderectBuffer {}

pub struct AnyBuffer {}
impl BufferUsage for AnyBuffer {}

#[derive(Clone, Copy)]
pub struct BufferInfo {
    pub size: u64,
    pub sharing_mode: vk::SharingMode,
    pub usage: vk::BufferUsageFlags,
    pub properties: vk::MemoryPropertyFlags,
}

pub struct Buffer<Usage: BufferUsage> {
    pub(super) handle: vk::Buffer,
    memory: vk::DeviceMemory,
    pub info: BufferInfo,
    pub mapped: *mut u8,

    pub device: Arc<Device>,

    _usage: PhantomData<Usage>,
}

unsafe impl<Usage: BufferUsage> Send for Buffer<Usage> {}
unsafe impl<Usage: BufferUsage> Sync for Buffer<Usage> {}

impl<Usage: BufferUsage> DescriptorSetBinding for RwLock<Buffer<Usage>> {}
impl<Usage: BufferUsage> CommandBufferBinding for RwLock<Buffer<Usage>> {}

impl<Usage: BufferUsage> Drop for Buffer<Usage> {
    fn drop(&mut self) {
        unsafe {
            self.device.handle.free_memory(self.memory, None);
            self.device.handle.destroy_buffer(self.handle, None);
        }
    }
}

impl<Usage: BufferUsage> Buffer<Usage> {
    pub fn new(device: Arc<Device>, info: BufferInfo) -> Result<Arc<RwLock<Self>>, Box<dyn Error>> {
        let create_info = vk::BufferCreateInfo::default()
            .size(info.size)
            .usage(info.usage)
            .sharing_mode(info.sharing_mode);

        let buffer = unsafe { device.handle.create_buffer(&create_info, None) }?;

        let memory_requirements = unsafe { device.handle.get_buffer_memory_requirements(buffer) };

        let memory_type_index = device
            .physical_device
            .find_memory_type_index(info.properties, memory_requirements.memory_type_bits)?;

        let memory_allocate_info = vk::MemoryAllocateInfo::default()
            .allocation_size(memory_requirements.size)
            .memory_type_index(memory_type_index);

        let device_memory = unsafe { device.handle.allocate_memory(&memory_allocate_info, None) }?;

        unsafe { device.handle.bind_buffer_memory(buffer, device_memory, 0) }?;

        Ok(Arc::new(RwLock::new(Self {
            handle: buffer,
            memory: device_memory,
            mapped: std::ptr::null_mut(),
            info,
            device,
            _usage: PhantomData,
        })))
    }

    pub fn bind_memory<'a>(&mut self, range: Range<u64>) -> Result<&'a mut [u8], Box<dyn Error>> {
        if !self.mapped.is_null() {
            unsafe { self.device.handle.unmap_memory(self.memory) };
            self.mapped = std::ptr::null_mut();
        }

        let mapped = unsafe {
            self.device.handle.map_memory(
                self.memory,
                range.start,
                range.end - range.start,
                vk::MemoryMapFlags::empty(),
            )
        }? as *mut u8;

        self.mapped = mapped;

        let slice =
            unsafe { std::slice::from_raw_parts_mut(mapped, (range.end - range.start) as usize) };

        Ok(slice)
    }
}