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 super::device::{Device, CommandPool, CommandBuffer, CommandBufferBuilder, ShaderModule, ShaderModuleSource};
use super::memory::{StagingBuffer, StagingBufferUsage};
use super::swapchain::{SwapchainFramebuffers, SwapchainFramebuffer, SceneRenderPass};
use super::offscreen::{OffscreenGraphicsRender};
use super::scene::{SceneGraphicsRender};
use super::raytrace::{RayTracingGraphicsRender};

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

pub struct GraphicsRender {
    frames: Vec<GraphicsFramePrerender>,
    swapchain_framebuffers: Arc<SwapchainFramebuffers>,
    frame_renderer: Arc<GraphicsFrameRenderer>,
    command_pool: Arc<CommandPool>,
    present_semaphore: Arc<Semaphore>,
    render_semaphore: Arc<Semaphore>,
}

impl GraphicsRender {
    pub fn new(
        command_pool: &Arc<CommandPool>,
        swapchain_framebuffers: &Arc<SwapchainFramebuffers>, 
        frame_renderer: &Arc<GraphicsFrameRenderer>,
        extent: VkExtent2D,
    ) -> Result<Arc<Self>> {
        unsafe {
            Self::init(command_pool, swapchain_framebuffers, frame_renderer, extent)
        }
    }

    pub unsafe fn init(
        command_pool: &Arc<CommandPool>,
        swapchain_framebuffers: &Arc<SwapchainFramebuffers>, 
        frame_renderer: &Arc<GraphicsFrameRenderer>,
        extent: VkExtent2D,
    ) -> Result<Arc<Self>> {
        let device = swapchain_framebuffers.device();
        let area = VkRect2D {
            offset: VkOffset2D {
                x: 0,
                y: 0,
            },
            extent: extent,
        };
        let frames: Vec<GraphicsFramePrerender>;
        frames = swapchain_framebuffers.framebuffers()
            .iter()
            .map(|framebuffer| frame_renderer.render(command_pool, framebuffer, area))
            .collect();
        let render = GraphicsRender {
            frames,
            swapchain_framebuffers: Arc::clone(swapchain_framebuffers),
            frame_renderer: Arc::clone(frame_renderer),
            command_pool: Arc::clone(command_pool),
            present_semaphore: Semaphore::new(device)?,
            render_semaphore: Semaphore::new(device)?,
        };
        Ok(Arc::new(render))
    }

    pub fn draw(&self) -> Result<()> {
        let swapchain = self.swapchain_framebuffers.swapchain();
        let image = swapchain.acquire_next_image(self.present_semaphore.handle())?;
        let frame = self.frames.get(image.index())
            .ok_or_else(|| ErrorCode::RenderFrameNotFound)?;
        let command_buffer = frame.command_buffer();
        command_buffer.wait_and_reset();
        command_buffer.submit(
            VkPipelineStageFlagBits::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT as VkPipelineStageFlags,
            self.present_semaphore.handle(),
            self.render_semaphore.handle(),
        )?;
        swapchain.queue_present(image, self.render_semaphore.handle())?;
        Ok(())
    }
}

struct Semaphore {
    device: Arc<Device>,
    handle: VkSemaphore,
}

impl Semaphore {
    pub fn new(device: &Arc<Device>) -> Result<Arc<Self>> {
        unsafe {
            let create_info = VkSemaphoreCreateInfo {
                sType: VkStructureType::VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,
            };
            let mut handle = MaybeUninit::<VkSemaphore>::zeroed();
            vkCreateSemaphore(device.handle(), &create_info, ptr::null(), handle.as_mut_ptr())
                .into_result()?;
            let handle = handle.assume_init();
            let semaphore = Semaphore {
                device: Arc::clone(device),
                handle,
            };
            Ok(Arc::new(semaphore))
        }
    }

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

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

struct GraphicsFramePrerender {
    command_buffer: Arc<CommandBuffer>,
}

impl GraphicsFramePrerender {
    pub fn new(command_buffer: Arc<CommandBuffer>) -> Self {
        Self { 
            command_buffer,
        }
    }

    #[inline]
    fn command_buffer(&self) -> &Arc<CommandBuffer> {
        &self.command_buffer
    }
}

pub enum GraphicsFrameRenderer {
    RayTracing(Arc<GraphicsFrameRayTracingRenderer>),
    Rasterization(Arc<GraphicsFrameRasterizationRenderer>),
}

impl GraphicsFrameRenderer {
    pub fn raytracing(renderer: &Arc<GraphicsFrameRayTracingRenderer>) -> Arc<Self> {
        let renderer = Self::RayTracing(Arc::clone(renderer));
        Arc::new(renderer)
    }

    pub fn rasterization(renderer: &Arc<GraphicsFrameRasterizationRenderer>) -> Arc<Self> {
        let renderer = Self::Rasterization(Arc::clone(renderer));
        Arc::new(renderer)
    }

    unsafe fn render(&self, 
        command_pool: &Arc<CommandPool>, 
        framebuffer: &SwapchainFramebuffer, 
        area: VkRect2D,
    ) -> GraphicsFramePrerender {
        match &self {
            &Self::RayTracing(renderer) => renderer.render(command_pool, framebuffer, area),
            &Self::Rasterization(renderer) => renderer.render(command_pool, framebuffer, area),
        }
    }
}

pub struct GraphicsFrameRayTracingRenderer {
    raytracing_render: Arc<RayTracingGraphicsRender>,
    scene_render: Arc<SceneGraphicsRender>,
}

impl GraphicsFrameRayTracingRenderer {
    pub fn new(
        raytracing_render: &Arc<RayTracingGraphicsRender>,
        scene_render: &Arc<SceneGraphicsRender>,
    ) -> Result<Arc<Self>> {
        let renderer = Self {
            raytracing_render: Arc::clone(raytracing_render),
            scene_render: Arc::clone(scene_render),
        };
        Ok(Arc::new(renderer))
    }

    unsafe fn render(&self, 
        command_pool: &Arc<CommandPool>, 
        framebuffer: &SwapchainFramebuffer, 
        area: VkRect2D,
    ) -> GraphicsFramePrerender {
        let command_buffer = CommandBufferBuilder::new(command_pool).build(|command_buffer| {
            self.raytracing_render.command(command_buffer, area);
            self.scene_render.command(command_buffer, framebuffer, area);
        });
        GraphicsFramePrerender::new(command_buffer)
    }
}

pub struct GraphicsFrameRasterizationRenderer {
    offscreen_render: Arc<OffscreenGraphicsRender>,
    scene_render: Arc<SceneGraphicsRender>,
}

impl GraphicsFrameRasterizationRenderer {
    pub fn new(
        offscreen_render: &Arc<OffscreenGraphicsRender>,
        scene_render: &Arc<SceneGraphicsRender>,
    ) -> Result<Arc<Self>> {
        let renderer = Self {
            offscreen_render: Arc::clone(offscreen_render),
            scene_render: Arc::clone(scene_render),
        };
        Ok(Arc::new(renderer))
    }

    unsafe fn render(&self, 
        command_pool: &Arc<CommandPool>, 
        framebuffer: &SwapchainFramebuffer, 
        area: VkRect2D,
    ) -> GraphicsFramePrerender {
        let command_buffer = CommandBufferBuilder::new(command_pool).build(|command_buffer| {
            self.offscreen_render.command(command_buffer, area);
            self.scene_render.command(command_buffer, framebuffer, area);
        });
        GraphicsFramePrerender::new(command_buffer)
    }
}