vrust 0.0.1

VRust game engine
use super::super::system::vulkan as vk;
use super::synchronizer::semaphore::Semaphore;
use super::device::logical::Logical as LogicalDevice;
use std::ptr::{null, null_mut};
use super::image::view::View as ImageView;
use std::sync::Arc;

pub enum NextImageResult {
    NeedsRefresh,
    Next(u32),
}

pub struct Swapchain {
    pub logical_device: Arc<LogicalDevice>,
    pub surface_format: vk::VkSurfaceFormatKHR,
    pub image_views: Vec<Arc<ImageView>>,
    pub vk_data: vk::VkSwapchainKHR,
}

impl Swapchain {
    pub fn new(logical_device: Arc<LogicalDevice>) -> Self {
        let surface_caps = logical_device.physical_device.get_surface_capabilities();
        let surface_formats = logical_device.physical_device.get_surface_formats();
        let mut best_surface_format = vk::VkSurfaceFormatKHR::default();
        for format in surface_formats.clone() {
            if format.format as u32 == vk::VkFormat::VK_FORMAT_R8G8B8A8_UNORM as u32 {
                best_surface_format = format;
                break;
            }
        }
        if best_surface_format.format as u32 != vk::VkFormat::VK_FORMAT_R8G8B8A8_UNORM as u32 {
            logi!("VK_FORMAT_R8G8B8A8_UNORM not found in the surface.");
            best_surface_format = surface_formats[0];
            if best_surface_format.format as u32 == vk::VkFormat::VK_FORMAT_UNDEFINED as u32 {
                best_surface_format.format = vk::VkFormat::VK_FORMAT_R8G8B8A8_UNORM;
            }
        }
        logi!("The specified format is {:?}", best_surface_format);
        let mut swapchain_images_count = surface_caps.minImageCount + 1;
        if surface_caps.maxImageCount > 0 && swapchain_images_count > surface_caps.maxImageCount {
            swapchain_images_count = surface_caps.maxImageCount;
        }
        let mut image_usage = vk::VkImageUsageFlagBits::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT as u32;
        let mut format_props = vk::VkFormatProperties::default();
        unsafe {
            vk::vkGetPhysicalDeviceFormatProperties(
                logical_device.physical_device.vk_data,
                best_surface_format.format,
                &mut format_props,
            );
        };
        if ((format_props.optimalTilingFeatures as u32) &
            (vk::VkFormatFeatureFlagBits::VK_FORMAT_FEATURE_BLIT_DST_BIT as u32)) != 0
        {
            image_usage |= vk::VkImageUsageFlagBits::VK_IMAGE_USAGE_TRANSFER_SRC_BIT as u32;
        }
        let mut swapchain_create_info = vk::VkSwapchainCreateInfoKHR::default();
        swapchain_create_info.sType =
            vk::VkStructureType::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
        swapchain_create_info.surface = logical_device.physical_device.surface.vk_data;
        swapchain_create_info.minImageCount = swapchain_images_count;
        swapchain_create_info.imageFormat = best_surface_format.format;
        swapchain_create_info.imageColorSpace = best_surface_format.colorSpace;
        swapchain_create_info.imageExtent = surface_caps.currentExtent;
        swapchain_create_info.imageUsage = image_usage;
        swapchain_create_info.preTransform =
            vk::VkSurfaceTransformFlagBitsKHR::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
        swapchain_create_info.imageArrayLayers = 1;
        swapchain_create_info.imageSharingMode = vk::VkSharingMode::VK_SHARING_MODE_EXCLUSIVE;
        swapchain_create_info.presentMode = vk::VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR;
        swapchain_create_info.clipped = 1 as vk::VkBool32;
        if ((surface_caps.supportedCompositeAlpha as u32) &
            (vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR as u32)) !=
            0
        {
            swapchain_create_info.compositeAlpha =
                vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
        } else if ((surface_caps.supportedCompositeAlpha as u32) &
            (vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR as u32)) !=
            0
        {
            swapchain_create_info.compositeAlpha =
                vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
        } else if ((surface_caps.supportedCompositeAlpha as u32) &
            (vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR as
                u32)) != 0
        {
            swapchain_create_info.compositeAlpha =
                vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
        } else if ((surface_caps.supportedCompositeAlpha as u32) &
            (vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR as
                u32)) != 0
        {
            swapchain_create_info.compositeAlpha =
                vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
        } else if ((surface_caps.supportedCompositeAlpha as u32) &
            (vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR as
                u32)) != 0
        {
            swapchain_create_info.compositeAlpha =
                vk::VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR;
        } else {
            logf!("Error composite is unknown.");
        }
        let mut vk_data = 0 as vk::VkSwapchainKHR;
        vulkan_check!(vk::vkCreateSwapchainKHR(
            logical_device.vk_data,
            &swapchain_create_info,
            null(),
            &mut vk_data,
        ));
        let mut count = 0u32;
        vulkan_check!(vk::vkGetSwapchainImagesKHR(
            logical_device.vk_data,
            vk_data,
            &mut count,
            null_mut(),
        ));
        let mut images = vec![0 as vk::VkImage; count as usize];
        vulkan_check!(vk::vkGetSwapchainImagesKHR(
            logical_device.vk_data,
            vk_data,
            &mut count,
            images.as_mut_ptr(),
        ));
        let mut views = Vec::new();
        for i in 0..(count as usize) {
            views.push(Arc::new(ImageView::new_with_vk_image(
                logical_device.clone(),
                images[i],
                best_surface_format.format,
            )));
        }
        Swapchain {
            logical_device: logical_device,
            surface_format: best_surface_format,
            image_views: views,
            vk_data: vk_data,
        }
    }
    pub fn get_next_image_index(&self, sem: &Semaphore) -> NextImageResult {
        let mut image_index = 0u32;
        let res = unsafe {
            vk::vkAcquireNextImageKHR(
                self.logical_device.vk_data,
                self.vk_data,
                u64::max_value(),
                sem.vk_data,
                0 as vk::VkFence,
                &mut image_index,
            )
        };
        match res {
            vk::VkResult::VK_ERROR_OUT_OF_DATE_KHR | vk::VkResult::VK_SUBOPTIMAL_KHR => {
                return NextImageResult::NeedsRefresh;
            }
            res @ _ => {
                vulkan_check!(res);
            }
        }
        return NextImageResult::Next(image_index);
    }
}

impl Drop for Swapchain {
    fn drop(&mut self) {
        self.image_views.clear();
        unsafe {
            vk::vkDestroySwapchainKHR(self.logical_device.vk_data, self.vk_data, null());
        }
    }
}