nexg 0.1.1

Nexg is a pure-rust library that makes coding Vulkan functionality easier and more Rust-like.
Documentation
use ash::vk::{
    ImageUsageFlags, PresentInfoKHR, Semaphore, SharingMode, SwapchainCreateInfoKHR, SwapchainKHR,
};

use crate::{
    Device, DeviceConnecter, Image, ImageFormat, Instance, NxError, NxResult,
    QueuePresentDescriptor, Surface,
};

#[derive(Clone, Copy, Debug)]
pub enum SwapchainState {
    Normal,
    SubOptimal,
    Broken,
}

pub struct Swapchain {
    swapchain: ash::extensions::khr::Swapchain,
    khr: SwapchainKHR,
    format: ImageFormat,
}

impl Swapchain {
    pub fn new(
        surface: &Surface,
        instance: &Instance,
        device: &Device,
        connecter: DeviceConnecter,
    ) -> NxResult<Self> {
        if !connecter.is_support_swapchain(instance) {
            return Err(NxError::HardwareError);
        }

        let surface_capabilities = connecter.get_surface_capabilities(surface);
        let surface_formats = connecter.get_surface_formats(surface);
        let surface_present_modes = connecter.get_surface_present_modes(surface);

        let format = surface_formats[0];
        let present_mode = surface_present_modes[0];

        let create_info = SwapchainCreateInfoKHR::builder()
            .surface(surface.khr)
            .min_image_count(surface_capabilities.min_image_count + 1)
            .image_format(format.format)
            .image_color_space(format.color_space)
            .image_extent(surface_capabilities.current_extent)
            .image_array_layers(1)
            .image_usage(ImageUsageFlags::COLOR_ATTACHMENT)
            .image_sharing_mode(SharingMode::EXCLUSIVE)
            .pre_transform(surface_capabilities.current_transform)
            .present_mode(present_mode)
            .clipped(true)
            .build();
        let swapchain = ash::extensions::khr::Swapchain::new(&instance.instance, &device.device);
        let khr = match unsafe { swapchain.create_swapchain(&create_info, None) } {
            Ok(x) => x,
            Err(e) => return Err(NxError::InternalError(e)),
        };
        let format = format.format.into();
        Ok(Self {
            swapchain,
            khr,
            format,
        })
    }

    pub fn acquire_next_image(
        &self,
        semaphore: Option<&crate::Semaphore>,
    ) -> NxResult<(usize, SwapchainState)> {
        let semaphore = match semaphore {
            None => Semaphore::null(),
            Some(x) => x.semaphore,
        };
        match unsafe {
            self.swapchain.acquire_next_image(
                self.khr,
                1000000000,
                semaphore,
                ash::vk::Fence::null(),
            )
        } {
            Ok(result) => {
                let image = result.0 as usize;
                let state = if result.1 {
                    SwapchainState::Broken
                } else {
                    SwapchainState::Normal
                };
                Ok((image, state))
            }

            Err(e) => Err(NxError::InternalError(e)),
        }
    }

    pub fn format(&self) -> ImageFormat {
        self.format
    }

    pub fn present(&self, descriptor: &QueuePresentDescriptor, image: u32) -> NxResult<()> {
        let w_semaphores: Vec<Semaphore> = descriptor
            .wait_semaphores
            .iter()
            .map(|x| x.semaphore)
            .collect();
        let present_info = PresentInfoKHR::builder()
            .swapchains(&[self.khr])
            .image_indices(&[image])
            .wait_semaphores(&w_semaphores)
            .build();

        match unsafe {
            self.swapchain
                .queue_present(descriptor.queue.unwrap().0, &present_info)
        } {
            Ok(_) => Ok(()),
            Err(e) => Err(NxError::InternalError(e)),
        }
    }

    pub fn images(&self) -> NxResult<Vec<Image>> {
        let images = unsafe { self.swapchain.get_swapchain_images(self.khr).unwrap() };
        let images = images
            .iter()
            .map(|x| Image::from_raw(*x))
            .collect::<Vec<Image>>();
        if !images.is_empty() {
            Ok(images)
        } else {
            Err(NxError::NoValue)
        }
    }
}

impl Drop for Swapchain {
    fn drop(&mut self) {
        unsafe {
            self.swapchain.destroy_swapchain(self.khr, None);
        }
    }
}