kaldera 0.1.0

Lightweight 3D renderer powered by Vulkan
Documentation

use crate::ffi::vk::*;
use super::error::Result;
use super::error::ErrorCode;
use super::instance::{Instance, QueueFamily, PhysicalDevice, PhysicalDevicesBuilder};

use std::ptr;
use std::mem;
use std::mem::MaybeUninit;
use libc::{c_float, c_void};
use std::sync::Arc;
use std::io::Read;

pub struct Device {
    handle: VkDevice,
    physical_device: Arc<PhysicalDevice>,
}

impl Device {
    pub(crate) fn new(handle: VkDevice, physical_device: &Arc<PhysicalDevice>) -> Arc<Device> {
        let device = Device {
            handle,
            physical_device: Arc::clone(physical_device),
        };
        Arc::new(device)
    }

    #[inline]
    pub fn handle(&self) -> VkDevice {
        self.handle
    }

    #[inline]
    pub fn physical_device(&self) -> &Arc<PhysicalDevice> {
        &self.physical_device
    }
}

impl Drop for Device {
    fn drop(&mut self) {
        log_debug!("Drop Device");
        unsafe {
            vkDestroyDevice(self.handle, ptr::null());
            self.handle = ptr::null_mut();
        }
    }
}

pub struct CommandPool {
    handle: VkCommandPool,
    queue: Arc<Queue>,
}

impl CommandPool {
    pub fn new(queue: &Arc<Queue>) -> Result<Arc<Self>> {
        unsafe {
            let device = queue.device();
            let mut handle = MaybeUninit::<VkCommandPool>::zeroed();
            let info = VkCommandPoolCreateInfo::new(queue.family().index() as u32);
            vkCreateCommandPool(device.handle(), &info, ptr::null(), handle.as_mut_ptr())
                .into_result()?;
            let handle = handle.assume_init();
            let command_pool = CommandPool {
                handle: handle,
                queue: Arc::clone(queue),
            };
            Ok(Arc::new(command_pool))
        }
    }

    #[inline]
    pub fn handle(&self) -> VkCommandPool {
        self.handle
    }

    #[inline]
    pub fn queue(&self) -> &Arc<Queue> {
        &self.queue
    }
}

impl Drop for CommandPool {
    fn drop(&mut self) {
        log_debug!("Drop CommandPool");
        unsafe {
            vkDestroyCommandPool(self.queue().device().handle(), self.handle, ptr::null());
            self.handle = ptr::null_mut();
        }
    }
}

pub struct CommandBufferBuilder<'a> {
    command_pool: &'a Arc<CommandPool>,
}

impl<'a> CommandBufferBuilder<'a> {
    pub fn new(command_pool: &'a Arc<CommandPool>) -> Self {
        CommandBufferBuilder {
            command_pool,
        }
    }

    pub fn build<F>(self, op: F) -> Arc<CommandBuffer> where F: FnOnce(VkCommandBuffer) -> () {
        unsafe {
            let command_pool = self.command_pool;
            let device = command_pool.queue().device();
            let mut command_buffer = MaybeUninit::<VkCommandBuffer>::zeroed();
            {
                let alloc_info = VkCommandBufferAllocateInfo::new(command_pool.handle(), VkCommandBufferLevel::VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1);
                vkAllocateCommandBuffers(device.handle(), &alloc_info, command_buffer.as_mut_ptr())
                    .into_result()
                    .unwrap();
            }
            let command_buffer = command_buffer.assume_init();
            let mut fence = MaybeUninit::<VkFence>::zeroed();
            {
                let create_info = VkFenceCreateInfo::new(VkFenceCreateFlagBits::VK_FENCE_CREATE_SIGNALED_BIT as VkFlags);
                vkCreateFence(device.handle(), &create_info, ptr::null(), fence.as_mut_ptr())
                    .into_result()
                    .unwrap();
            }
            let fence = fence.assume_init();
            let begin_info = VkCommandBufferBeginInfo::new();
            vkBeginCommandBuffer(command_buffer, &begin_info)
                .into_result()
                .unwrap();
            {
                op(command_buffer);
            }
            vkEndCommandBuffer(command_buffer);
            CommandBuffer::new(command_pool, command_buffer, fence)
        }
    }
}

pub struct CommandBuffer {
    command_pool: Arc<CommandPool>,
    handle: VkCommandBuffer,
    fence: VkFence,
}

impl CommandBuffer {
    fn new(command_pool: &Arc<CommandPool>, handle: VkCommandBuffer, fence: VkFence) -> Arc<CommandBuffer> {
        let command_buffer = CommandBuffer {
            command_pool: Arc::clone(command_pool),
            handle,
            fence,
        };
        Arc::new(command_buffer)
    }

    pub fn submit_then_wait(&self, wait_mask: VkPipelineStageFlags) {
        unsafe {
            let queue = self.command_pool.queue();
            let device = queue.device();
            let fence = self.fence;
            let command_buffer = self.handle;
            vkResetFences(device.handle(), 1, &fence)
                .into_result()
                .unwrap();
            let submit_info = VkSubmitInfo::with_command_buffer_wait(1, &command_buffer, &wait_mask);
            vkQueueSubmit(queue.handle(), 1, &submit_info, fence);
            vkWaitForFences(device.handle(), 1, &fence, VK_TRUE, crate::vk::DEFAULT_TIMEOUT)
                .into_result()
                .unwrap();
        }
    }

    pub fn wait_and_reset(&self) {
        unsafe {
            let queue = self.command_pool.queue();
            let device = queue.device();
            let fence = self.fence;
            vkWaitForFences(device.handle(), 1, &fence, VK_TRUE, crate::vk::DEFAULT_TIMEOUT)
                .into_result()
                .unwrap();
            vkResetFences(device.handle(), 1, &fence)
                .into_result()
                .unwrap();
        }
    }

    pub fn submit(&self, wait_mask: VkPipelineStageFlags, wait_semaphore: VkSemaphore, signal_semaphore: VkSemaphore) -> Result<()> {
        unsafe {
            let queue = self.command_pool.queue();
            let fence = self.fence;
            let command_buffer = self.handle;
            let submit_info = VkSubmitInfo {
                sType: VkStructureType::VK_STRUCTURE_TYPE_SUBMIT_INFO,
                pNext: ptr::null(),
                waitSemaphoreCount: 1,
                pWaitSemaphores: &wait_semaphore,
                pWaitDstStageMask: &wait_mask,
                commandBufferCount: 1,
                pCommandBuffers: &command_buffer,
                signalSemaphoreCount: 1,
                pSignalSemaphores: &signal_semaphore,
            };
            vkQueueSubmit(queue.handle(), 1, &submit_info, fence)
                .into_result()?;
            Ok(())
        }
    }

    #[inline]
    pub fn handle(&self) -> VkCommandBuffer {
        self.handle
    }
}

impl Drop for CommandBuffer {
    fn drop(&mut self) {
        log_debug!("Drop CommandBuffer");
        unsafe {
            let command_pool = &self.command_pool;
            let device = command_pool.queue().device();
            vkDestroyFence(device.handle(), self.fence, ptr::null());
            self.fence = ptr::null_mut();
            vkFreeCommandBuffers(device.handle(), command_pool.handle(), 1, &self.handle);
            self.handle = ptr::null_mut();
        }
    }
}

pub struct Queue {
    handle: VkQueue,
    family: QueueFamily,
    device: Arc<Device>,
}

impl Queue {
    pub fn new(handle: VkQueue, family: QueueFamily, device: &Arc<Device>) -> Arc<Self> {
        let queue = Queue { 
            handle: handle, 
            family: family,
            device: Arc::clone(device),
        };
        Arc::new(queue)
    }

    #[inline]
    pub fn handle(&self) -> VkQueue {
        self.handle
    }

    #[inline]
    pub fn family(&self) -> &QueueFamily {
        &self.family
    }

    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }

    pub unsafe fn submit_then_wait(&self, command_buffers: &[VkCommandBuffer]) -> Result<()> {
        let submit_info = VkSubmitInfo {
            sType: VkStructureType::VK_STRUCTURE_TYPE_SUBMIT_INFO,
            pNext: ptr::null(),
            waitSemaphoreCount: 0,
            pWaitSemaphores: ptr::null(),
            pWaitDstStageMask: ptr::null(),
            commandBufferCount: command_buffers.len() as u32,
            pCommandBuffers: command_buffers.as_ptr(),
            signalSemaphoreCount: 0,
            pSignalSemaphores: ptr::null(),
        };
        vkQueueSubmit(self.handle(), 1, &submit_info, ptr::null_mut());
        vkQueueWaitIdle(self.handle())
            .into_result()
    }
}

pub enum ShaderModuleSource {
    FilePath(String),
    Bytes(Vec<u8>),
}

impl ShaderModuleSource {
    pub fn from_file(filename: impl Into<String>) -> Self {
        ShaderModuleSource::FilePath(filename.into())        
    }

    pub fn from_bytes(bytes: Vec<u8>) -> Self {
        ShaderModuleSource::Bytes(bytes)        
    }

    fn load(self) -> Result<(Vec<u8>, usize)> {
        match self {
            ShaderModuleSource::FilePath(filename) => {
                let mut file = std::fs::File::open(filename)
                    .map_err(|v| ErrorCode::ShaderLoadIO(v))?;
                let mut buffer = Vec::<u8>::new();
                let bytes = file.read_to_end(&mut buffer)
                    .map_err(|v| ErrorCode::ShaderLoadIO(v))?;
                if bytes > 0 && (bytes % 4) == 0 {
                    Ok((buffer, bytes))
                } else {
                    Err(ErrorCode::ShaderLoadUnaligned.into())
                }
            },
            ShaderModuleSource::Bytes(vector) => {
                let bytes = vector.len();
                if bytes > 0 && (bytes % 4) == 0 {
                    Ok((vector, bytes))
                } else {
                    Err(ErrorCode::ShaderLoadUnaligned.into())
                }
            },
        }
    }
}

pub struct ShaderModule {
    handle: VkShaderModule,
    device: Arc<Device>,
}

impl ShaderModule {
    pub fn new(device: &Arc<Device>, source: ShaderModuleSource) -> Result<Arc<Self>> {
        unsafe {
            let (buffer, num_bytes) = source.load()?;
            let mut handle = MaybeUninit::<VkShaderModule>::zeroed();
            let create_info = VkShaderModuleCreateInfo::new(num_bytes, buffer.as_ptr() as *const u32);
            vkCreateShaderModule(device.handle, &create_info, ptr::null(), handle.as_mut_ptr())
                .into_result()?;
            let handle = handle.assume_init();
            let shader_module = ShaderModule {
                handle: handle,
                device: Arc::clone(device),
            };
            Ok(Arc::new(shader_module))
        }
    }

    #[inline]
    pub fn handle(&self) -> VkShaderModule {
        self.handle
    }
}

impl Drop for ShaderModule {
    fn drop(&mut self) {
        log_debug!("Drop ShaderModule");
        unsafe {
            vkDestroyShaderModule(self.device.handle(), self.handle, ptr::null());
            self.handle = ptr::null_mut();
        }
    }
}