ursus_core/render/gfx/
pipeline_cache.rs1use 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}