Skip to main content

pebble/wgpu/
layout.rs

1/// A bind group layout tagged with the `@group(N)` it occupies in the pipeline.
2pub struct GroupLayout<'a> {
3    pub group: u32,
4    pub layout: &'a wgpu::BindGroupLayout,
5}
6
7/// An owned bind group layout tagged with the `@group(N)` it occupies, for descriptors that
8/// hold layouts by value.
9pub struct OwnedGroupLayout {
10    pub group: u32,
11    pub layout: wgpu::BindGroupLayout,
12}
13
14/// Assembles bind group layouts for a pipeline from explicit, group-tagged slots, rather
15/// than an implicit position-based order. Panics if any group index in `0..=max_index` is
16/// missing a layout, or if two slots claim the same index — both are almost always a
17/// mistake that would otherwise show up later as an opaque wgpu shader validation error.
18pub fn assemble_bind_group_layouts<'a>(
19    label: Option<&str>,
20    slots: Vec<GroupLayout<'a>>,
21) -> Vec<Option<&'a wgpu::BindGroupLayout>> {
22    let max_group = slots.iter().map(|s| s.group).max().unwrap_or(0);
23    let mut assembled: Vec<Option<&wgpu::BindGroupLayout>> = vec![None; (max_group + 1) as usize];
24
25    for GroupLayout { group, layout } in slots {
26        let slot = &mut assembled[group as usize];
27        if slot.is_some() {
28            panic!(
29                "bind group {group} assigned more than once building pipeline layout{}",
30                label.map(|l| format!(" '{l}'")).unwrap_or_default()
31            );
32        }
33        *slot = Some(layout);
34    }
35
36    for (i, slot) in assembled.iter().enumerate() {
37        if slot.is_none() {
38            panic!(
39                "bind group {i} has no layout assigned building pipeline layout{} (groups must be contiguous from 0)",
40                label.map(|l| format!(" '{l}'")).unwrap_or_default()
41            );
42        }
43    }
44
45    assembled
46}