rotex-vulkan 0.1.0

A Vulkan backend for rotex_core
Documentation
use super::{VulkanBridge, surface_not_attached_error};
use crate::backend::vulkan::{Device, Semaphore, Swapchain};
use crate::core::Instance;
use crate::error::{Error, vk_error};
use rotex_types::{Extent2D as FrontendExtent2D, SurfaceDescriptor as FrontendSurfaceDescriptor};

impl VulkanBridge {
    pub fn attach_surface(
        &mut self,
        surface_descriptor: FrontendSurfaceDescriptor,
    ) -> Result<(), Error> {
        self.destroy_surface_state();
        let raw_surface = unsafe {
            ash_window::create_surface(
                self.instance.raw_entry(),
                self.instance.raw_instance(),
                surface_descriptor.display_handle,
                surface_descriptor.window_handle,
                None,
            )
        }
        .map_err(vk_error)?;
        let surface = self.instance.create_surface_from_raw(raw_surface);
        let extent = super::init::to_vk_extent(surface_descriptor.extent);
        let swapchain = surface.create_swapchain(&self.instance, &self.device, extent)?;
        let color_targets =
            Self::create_targets(self.instance.raw(), self.device.raw(), swapchain.raw(), false)?;
        let image_available = Semaphore::new(self.device.raw())?;
        let render_finished =
            Self::create_render_finished(self.device.raw(), swapchain.raw().images().len())?;
        self.surface_state = Some(super::types::SurfaceState {
            surface,
            swapchain,
            extent,
            color_targets,
            depth_targets: None,
            image_available,
            render_finished,
        });
        Ok(())
    }

    pub(super) fn create_targets(
        instance: &Instance,
        device: &Device,
        swapchain: &Swapchain,
        with_depth: bool,
    ) -> Result<super::types::RenderTargets, Error> {
        let depth_format = if with_depth {
            Some(super::render::find_depth_format(instance, device)?)
        } else {
            None
        };
        let render_pass = super::render::create_render_pass(device, swapchain.format(), depth_format)?;
        let depth_image = match depth_format {
            Some(format) => Some(super::render::create_depth_image(
                instance,
                device,
                swapchain.extent(),
                format,
            )?),
            None => None,
        };
        let framebuffers = super::render::build_framebuffers(
            device,
            swapchain,
            render_pass.handle(),
            depth_image.as_ref(),
        )?;
        Ok(super::types::RenderTargets {
            render_pass,
            framebuffers,
            depth_image,
        })
    }

    pub(super) fn recreate_swapchain(&mut self) -> Result<(), Error> {
        unsafe { self.device.raw().logical_device().device_wait_idle() }.map_err(vk_error)?;
        self.destroy_all_pipelines();
        let Some(state) = self.surface_state.as_mut() else {
            return Err(surface_not_attached_error());
        };
        for sem in state.render_finished.drain(..) {
            sem.destroy(self.device.raw());
        }
        let old_swapchain_handle = state.swapchain.handle();
        let mut old_swapchain = std::mem::replace(
            &mut state.swapchain,
            state.surface.create_swapchain_with_old(
                &self.instance,
                &self.device,
                state.extent,
                old_swapchain_handle,
            )?,
        );
        old_swapchain.destroy_in_place(&self.device);

        let old_color_targets = std::mem::replace(
            &mut state.color_targets,
            Self::create_targets(
                self.instance.raw(),
                self.device.raw(),
                state.swapchain.raw(),
                false,
            )?,
        );
        old_color_targets.destroy(self.device.raw());

        if let Some(old_depth_targets) = state.depth_targets.take() {
            old_depth_targets.destroy(self.device.raw());
            state.depth_targets = Some(Self::create_targets(
                self.instance.raw(),
                self.device.raw(),
                state.swapchain.raw(),
                true,
            )?);
        }

        state.render_finished =
            Self::create_render_finished(self.device.raw(), state.swapchain.raw().images().len())?;
        Ok(())
    }

    pub(super) fn ensure_depth_targets(&mut self) -> Result<(), Error> {
        let Some(state) = self.surface_state.as_mut() else {
            return Err(surface_not_attached_error());
        };
        if state.depth_targets.is_none() {
            state.depth_targets = Some(Self::create_targets(
                self.instance.raw(),
                self.device.raw(),
                state.swapchain.raw(),
                true,
            )?);
        }
        Ok(())
    }

    pub(super) fn create_render_finished(
        device: &Device,
        count: usize,
    ) -> Result<Vec<Semaphore>, Error> {
        (0..count).map(|_| Semaphore::new(device)).collect()
    }

    pub fn resize(&mut self, extent: FrontendExtent2D) -> Result<(), Error> {
        if let Some(state) = self.surface_state.as_mut() {
            state.extent = super::init::to_vk_extent(extent);
            return self.recreate_swapchain();
        }
        Err(surface_not_attached_error())
    }

    pub fn destroy(mut self) {
        let _ = self.in_flight_fence.wait(self.device.raw(), u64::MAX);
        unsafe {
            let _ = self.device.raw().logical_device().device_wait_idle();
        }
        self.destroy_all_pipelines();
        for (_, mesh) in self.meshes.drain() {
            mesh.vertex_buffer.destroy(self.device.raw());
            mesh.index_buffer.destroy(self.device.raw());
        }
        for (_, texture) in self.textures.drain() {
            texture.destroy(self.device.raw(), &self.texture_descriptor_pool);
        }
        if let Some(default_texture) = self.default_texture.take() {
            default_texture.destroy(self.device.raw(), &self.texture_descriptor_pool);
        }
        self.destroy_surface_state();
        self.texture_descriptor_pool.destroy(self.device.raw());
        self.texture_set_layout.destroy(self.device.raw());
        self.command_pool.destroy(self.device.raw());
        self.in_flight_fence.destroy(self.device.raw());
        self.device.destroy();
        self.instance.destroy();
    }

    pub(super) fn destroy_surface_state(&mut self) {
        if let Some(state) = self.surface_state.take() {
            for sem in state.render_finished {
                sem.destroy(self.device.raw());
            }
            state.image_available.destroy(self.device.raw());
            state.color_targets.destroy(self.device.raw());
            if let Some(depth_targets) = state.depth_targets {
                depth_targets.destroy(self.device.raw());
            }
            state.swapchain.destroy(&self.device);
            state.surface.destroy();
        }
    }
}