aluminium 0.1.0

vulkan-based graphics engine
use ash::vk::{self, ColorSpaceKHR};
use super::device::Device;
use super::{Instance, Surface, VulkanError, VulkanResult};

pub struct Swapchain {
    pub(crate) raw: vk::SwapchainKHR,
    pub(crate) loader: ash::khr::swapchain::Device,
}

pub struct SwapchainBuilder<'a> {
    extent: Option<vk::Extent2D>,
    old_swapchain: Option<vk::SwapchainKHR>,
    format: Option<vk::Format>,
    present_mode: Option<vk::PresentModeKHR>,
    color_space: Option<vk::ColorSpaceKHR>,
    min_image_count: Option<u32>,
    surface: Option<&'a Surface>,
    instance: Option<&'a Instance>,
    device: &'a Device,
}

impl<'a> SwapchainBuilder<'a> {
    pub fn new(device: &'a Device) -> Self {
        SwapchainBuilder {
            device,
            color_space: None,
            extent: None,
            old_swapchain: None,
            format: None,
            present_mode: None,
            min_image_count: None,
            surface: None,
            instance: None,
        }
    }

    pub fn color_space(mut self, space: ColorSpaceKHR) -> Self {
        self.color_space = Some(space);
        self
    }

    pub fn surface(mut self, surface: &'a Surface) -> Self {
        self.surface = Some(surface);
        self
    }

    pub fn instance(mut self, instance: &'a Instance) -> Self {
        self.instance = Some(instance);
        self
    }

    pub fn present_mode(mut self, mode: vk::PresentModeKHR) -> Self {
        self.present_mode = Some(mode);
        self
    }

    pub fn old_swapchain(mut self, swapchian: vk::SwapchainKHR) -> Self {
        self.old_swapchain = Some(swapchian);
        self
    }

    pub fn format(mut self, format: vk::Format) -> Self {
        self.format = Some(format);
        self
    }

    pub fn extent(mut self, extent: vk::Extent2D) -> Self {
        self.extent = Some(extent);
        self
    }

    pub fn min_image_count(mut self, count: u32) -> Self {
        self.min_image_count = Some(count);
        self
    }

    pub fn build(self) -> VulkanResult<Swapchain> {

        let instance = self.instance.expect("Missing Instance");
        let surface = self.surface.expect("Missing Surface");
        let extent = self.extent.expect("Missing Extent");
        let present_mode = self.present_mode.expect("Missing Present mode");
        let min_image_count = self.min_image_count.expect("Missing Min image count");
        let format = self.format.expect("Missing Format");
        let color_space = self.color_space.expect("Missing Color space");
        let old_swapchain = self.old_swapchain.unwrap_or(vk::SwapchainKHR::null());

        let swapchain_loader = ash::khr::swapchain::Device::new(&instance.raw, &self.device.raw);

        let create_info = vk::SwapchainCreateInfoKHR::default()
            .clipped(true)
            .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
            .pre_transform(vk::SurfaceTransformFlagsKHR::IDENTITY)
            .image_array_layers(1)
            .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
            .image_sharing_mode(vk::SharingMode::EXCLUSIVE)
            .image_format(format)
            .surface(surface.raw)
            .image_extent(extent)
            .min_image_count(min_image_count)
            .present_mode(present_mode)
            .old_swapchain(old_swapchain)
            .image_color_space(color_space);

        let swapchain = unsafe {
            profiling::scope!("vkCreateSwapchainKHR");
            swapchain_loader
                .create_swapchain(&create_info, None)
                .map_err(|e| VulkanError::Unknown(e))
        }?;

        Ok(Swapchain {
            raw: swapchain,
            loader: swapchain_loader,
        })
    }
}

impl Swapchain {
    pub fn get_swapchain_images(&self) -> VulkanResult<Vec<vk::Image>> {
        unsafe {
            self.loader
                .get_swapchain_images(self.raw)
                .map_err(VulkanError::Unknown)
        }
    }

    pub fn destroy(&self) {
        unsafe {
            self.loader.destroy_swapchain(self.raw, None);
        }
    }
}