1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use crate::{debug_label::DebugLabel, RenderContext};

use super::{
    bind_group_layout_pool::GpuBindGroupLayoutHandle,
    static_resource_pool::{StaticResourcePool, StaticResourcePoolReadLockAccessor},
};

slotmap::new_key_type! { pub struct GpuPipelineLayoutHandle; }

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct PipelineLayoutDesc {
    /// Debug label of the pipeline layout. This will show up in graphics debuggers for easy identification.
    pub label: DebugLabel,
    // TODO(andreas) use SmallVec or similar, limited to 4
    pub entries: Vec<GpuBindGroupLayoutHandle>,
}

#[derive(Default)]
pub struct GpuPipelineLayoutPool {
    pool: StaticResourcePool<GpuPipelineLayoutHandle, PipelineLayoutDesc, wgpu::PipelineLayout>,
}

impl GpuPipelineLayoutPool {
    pub fn get_or_create(
        &self,
        ctx: &RenderContext,
        desc: &PipelineLayoutDesc,
    ) -> GpuPipelineLayoutHandle {
        self.pool.get_or_create(desc, |desc| {
            // TODO(andreas): error handling

            let bind_groups = ctx.gpu_resources.bind_group_layouts.resources();

            ctx.device
                .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
                    label: desc.label.get(),
                    bind_group_layouts: &desc
                        .entries
                        .iter()
                        .map(|handle| bind_groups.get(*handle).unwrap())
                        .collect::<Vec<_>>(),
                    push_constant_ranges: &[], // Sadly not widely supported
                })
        })
    }

    /// Locks the resource pool for resolving handles.
    ///
    /// While it is locked, no new resources can be added.
    pub fn resources(
        &self,
    ) -> StaticResourcePoolReadLockAccessor<'_, GpuPipelineLayoutHandle, wgpu::PipelineLayout> {
        self.pool.resources()
    }

    pub fn begin_frame(&mut self, frame_index: u64) {
        self.pool.current_frame_index = frame_index;
    }

    pub fn num_resources(&self) -> usize {
        self.pool.num_resources()
    }
}