Skip to main content

ursus_core/render/gfx/
pipeline_cache.rs

1use crate::render::gfx::types::handles::PipelineId;
2use crate::render::gfx::types::Format;
3use crate::vulkan::gfx_pipeline::builder::PipelineBuilder;
4use crate::vulkan::gfx_pipeline::pipeline::PipelineDesc;
5use ash::vk;
6
7pub(crate) struct StoredPipeline {
8    pub handle: vk::Pipeline,
9    pub layout: vk::PipelineLayout,
10}
11
12#[derive(Default)]
13pub struct PipelineCache {
14    pipelines: Vec<StoredPipeline>,
15    device: Option<ash::Device>,
16}
17
18impl PipelineCache {
19    pub fn new(device: ash::Device) -> Self {
20        Self { pipelines: Vec::new(), device: Some(device) }
21    }
22
23    pub(crate) fn insert(&mut self, handle: vk::Pipeline, layout: vk::PipelineLayout) -> PipelineId {
24        let id = PipelineId(self.pipelines.len() as u32);
25        self.pipelines.push(StoredPipeline { handle, layout });
26        id
27    }
28
29    pub(crate) fn get(&self, id: PipelineId) -> &StoredPipeline {
30        &self.pipelines[id.0 as usize]
31    }
32
33    pub fn create_graphics_pipeline(
34        &mut self,
35        device: &ash::Device,
36        desc: &PipelineDesc,
37        set_layouts: &[vk::DescriptorSetLayout],
38    ) -> anyhow::Result<PipelineId> {
39        let binding = desc.vertex_layout.to_vk_binding(0);
40        let attributes = desc.vertex_layout.to_vk_attributes(0);
41
42        let depth_format_vk = desc.depth.format.map(Format::to_vk).unwrap_or(vk::Format::UNDEFINED);
43
44        let vk_blend: Option<Vec<vk::PipelineColorBlendAttachmentState>> =
45            desc.blend_attachments.map(|states| states.iter().map(|s| s.to_vk()).collect());
46
47        let mut builder = PipelineBuilder::mesh(
48            desc.vert_spv,
49            desc.frag_spv,
50            desc.color_formats,
51            std::slice::from_ref(&binding),
52            &attributes,
53        )
54        .cull_mode(desc.cull_mode.to_vk())
55        .depth_test(desc.depth.test, desc.depth.write)
56        .depth_compare(desc.depth.compare.to_vk())
57        .depth_format(depth_format_vk)
58        .set_layouts(set_layouts)
59        .push_constants(desc.push_constant_ranges);
60
61        if let Some(blend) = vk_blend.as_deref() {
62            builder = builder.blend_attachments(blend);
63        }
64
65        let (handle, layout) = builder.build(device)?;
66        Ok(self.insert(handle, layout))
67    }
68
69    pub fn layout_of(&self, id: PipelineId) -> vk::PipelineLayout {
70        self.get(id).layout
71    }
72}
73
74impl Drop for PipelineCache {
75    fn drop(&mut self) {
76        if let Some(device) = &self.device {
77            unsafe {
78                for p in &self.pipelines {
79                    device.destroy_pipeline(p.handle, None);
80                    device.destroy_pipeline_layout(p.layout, None);
81                }
82            }
83        }
84    }
85}