rotex-vulkan 0.1.1

A Vulkan backend for rotex_core
Documentation
use ash::vk;

use super::device::Device;

#[derive(Debug, Clone)]
pub struct SubpassBlueprint {
    pub color_attachments: Vec<u32>,
    pub depth_attachment: Option<u32>,
}

pub struct RenderPass {
    pub(crate) render_pass: vk::RenderPass,
    attachments: Vec<vk::AttachmentDescription>,
}

impl RenderPass {
    pub fn handle(&self) -> vk::RenderPass {
        self.render_pass
    }

    pub fn attachments(&self) -> &[vk::AttachmentDescription] {
        &self.attachments
    }

    pub fn destroy(&self, device: &Device) {
        unsafe {
            device
                .logical_device()
                .destroy_render_pass(self.render_pass, None);
        }
    }
}

pub struct RenderPassBuilder {
    attachments: Vec<vk::AttachmentDescription>,
    subpasses: Vec<SubpassBlueprint>,
    dependencies: Vec<vk::SubpassDependency>,
}

impl RenderPassBuilder {
    pub fn new() -> Self {
        Self {
            attachments: Vec::new(),
            subpasses: Vec::new(),
            dependencies: Vec::new(),
        }
    }

    pub fn with_attachment(mut self, attachment: vk::AttachmentDescription) -> Self {
        self.attachments.push(attachment);
        self
    }

    pub fn with_subpass(mut self, subpass: SubpassBlueprint) -> Self {
        self.subpasses.push(subpass);
        self
    }

    pub fn with_dependency(mut self, dependency: vk::SubpassDependency) -> Self {
        self.dependencies.push(dependency);
        self
    }

    pub fn build(self, device: &Device) -> Result<RenderPass, vk::Result> {
        let mut all_color_refs: Vec<Vec<vk::AttachmentReference>> =
            Vec::with_capacity(self.subpasses.len());
        let mut all_depth_refs: Vec<Option<vk::AttachmentReference>> =
            Vec::with_capacity(self.subpasses.len());

        for blueprint in &self.subpasses {
            let color_refs: Vec<vk::AttachmentReference> = blueprint
                .color_attachments
                .iter()
                .map(|&idx| {
                    vk::AttachmentReference::default()
                        .attachment(idx)
                        .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
                })
                .collect();
            all_color_refs.push(color_refs);

            let depth_ref = blueprint.depth_attachment.map(|idx| {
                vk::AttachmentReference::default()
                    .attachment(idx)
                    .layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
            });
            all_depth_refs.push(depth_ref);
        }

        let mut vk_subpasses: Vec<vk::SubpassDescription> = Vec::with_capacity(self.subpasses.len());

        for i in 0..self.subpasses.len() {
            let mut subpass_desc = vk::SubpassDescription::default()
                .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
                .color_attachments(&all_color_refs[i]);

            if let Some(depth_ref) = &all_depth_refs[i] {
                subpass_desc = subpass_desc.depth_stencil_attachment(depth_ref);
            }

            vk_subpasses.push(subpass_desc);
        }

        let render_pass_info = vk::RenderPassCreateInfo::default()
            .attachments(&self.attachments)
            .subpasses(&vk_subpasses)
            .dependencies(&self.dependencies);

        let render_pass = unsafe {
            device
                .logical_device()
                .create_render_pass(&render_pass_info, None)?
        };
        Ok(RenderPass {
            render_pass,
            attachments: self.attachments,
        })
    }
}