easy_wgpu/
bind_group_layout.rs

1use core::num::NonZeroU64;
2
3/// Convenience layout for the bind group. Can potentially be hashed and used in
4/// a arena-kind of way
5#[derive(Debug, Clone, Hash, PartialEq, Eq, Default)]
6pub struct BindGroupLayoutDesc {
7    label: Option<String>,
8    entries: Vec<wgpu::BindGroupLayoutEntry>,
9}
10impl BindGroupLayoutDesc {
11    pub fn into_bind_group_layout(self, device: &wgpu::Device) -> wgpu::BindGroupLayout {
12        let desc = wgpu::BindGroupLayoutDescriptor {
13            entries: self.entries.as_slice(),
14            label: self.label.as_deref(),
15        };
16        device.create_bind_group_layout(&desc)
17    }
18    pub fn empty() -> Self {
19        Self {
20            label: Some(String::from("emtpy_bgl")),
21            entries: Vec::new(),
22        }
23    }
24}
25
26pub struct BindGroupLayoutBuilder {
27    layout_desc: Option<BindGroupLayoutDesc>,
28    last_binding_number: u32,
29}
30impl Default for BindGroupLayoutBuilder {
31    fn default() -> Self {
32        Self::new()
33    }
34}
35impl BindGroupLayoutBuilder {
36    pub fn new() -> Self {
37        Self {
38            layout_desc: Some(BindGroupLayoutDesc::empty()),
39            last_binding_number: 0,
40        }
41    }
42
43    /// # Panics
44    /// Will panic if the builder was not constructed with ``new()``
45    #[must_use]
46    pub fn label(mut self, label: &str) -> Self {
47        self.layout_desc.as_mut().unwrap().label = Some(String::from(label));
48        self
49    }
50
51    #[must_use]
52    pub fn add_entry_empty(mut self) -> Self {
53        self.last_binding_number += 1;
54        self
55    }
56
57    /// # Panics
58    /// Will panic if the builder was not constructed with ``new()``
59    #[must_use]
60    pub fn add_entry_tex(mut self, visibility: wgpu::ShaderStages, sample_type: wgpu::TextureSampleType) -> Self {
61        //each entry we add will have sequential binding_indices
62        //this should correspond with the binding in the shader
63        let binding_number = self.last_binding_number;
64        //entry and id
65        let entry = wgpu::BindGroupLayoutEntry {
66            binding: binding_number, //matches with the @binding in the shader
67            visibility,
68            ty: wgpu::BindingType::Texture {
69                multisampled: false,
70                view_dimension: wgpu::TextureViewDimension::D2,
71                sample_type,
72            },
73            count: None,
74        };
75        //add
76        self.layout_desc.as_mut().unwrap().entries.push(entry);
77        self.last_binding_number += 1;
78        self
79    }
80
81    /// # Panics
82    /// Will panic if the builder was not constructed with ``new()``
83    #[must_use]
84    pub fn add_entries_tex(self, visibility: wgpu::ShaderStages, sample_type: wgpu::TextureSampleType, num_textures: usize) -> Self {
85        let mut builder = self;
86        for _i in 0..num_textures {
87            builder = builder.add_entry_tex(visibility, sample_type);
88        }
89        builder
90    }
91
92    /// # Panics
93    /// Will panic if the builder was not constructed with ``new()``
94    #[must_use]
95    pub fn add_entry_cubemap(mut self, visibility: wgpu::ShaderStages, sample_type: wgpu::TextureSampleType) -> Self {
96        //each entry we add will have sequential binding_indices
97        //this should correspond with the binding in the shader
98        let binding_number = self.last_binding_number;
99        //entry and id
100        let entry = wgpu::BindGroupLayoutEntry {
101            binding: binding_number, //matches with the @binding in the shader
102            visibility,
103            ty: wgpu::BindingType::Texture {
104                multisampled: false,
105                view_dimension: wgpu::TextureViewDimension::Cube,
106                sample_type,
107            },
108            count: None,
109        };
110        //add
111        self.layout_desc.as_mut().unwrap().entries.push(entry);
112        self.last_binding_number += 1;
113        self
114    }
115
116    /// # Panics
117    /// Will panic if the builder was not constructed with ``new()``
118    #[must_use]
119    pub fn add_entry_sampler(mut self, visibility: wgpu::ShaderStages, sampler_type: wgpu::SamplerBindingType) -> Self {
120        //each entry we add will have sequential binding_indices
121        //this should correspond with the binding in the shader
122        let binding_number = self.last_binding_number;
123        //entry and id
124        let entry = wgpu::BindGroupLayoutEntry {
125            binding: binding_number, //matches with the @binding in the shader
126            visibility,
127            ty: wgpu::BindingType::Sampler(sampler_type),
128            count: None,
129        };
130        //add
131        self.layout_desc.as_mut().unwrap().entries.push(entry);
132        self.last_binding_number += 1;
133        self
134    }
135
136    /// # Panics
137    /// Will panic if the builder was not constructed with ``new()``
138    #[must_use]
139    pub fn add_entry_uniform(mut self, visibility: wgpu::ShaderStages, has_dynamic_offset: bool, _min_binding_size: Option<NonZeroU64>) -> Self {
140        //each entry we add will have sequential binding_indices
141        //this should correspond with the binding in the shader
142        let binding_number = self.last_binding_number;
143        // println!("BINDING NUM {binding_number}");
144        // println!("MIN SIZE {:?}", min_binding_size);
145        // println!("LABEL {:?}", self.layout_desc.clone().unwrap().label);
146
147        //entry and id
148        // TODO: Why does min_binding_size have an issue here?
149        let entry = wgpu::BindGroupLayoutEntry {
150            binding: binding_number, //----- keep in sync with the binding in create_bind_group and also the shader
151            visibility,
152            ty: wgpu::BindingType::Buffer {
153                ty: wgpu::BufferBindingType::Uniform,
154                has_dynamic_offset, //important because we will change the offset intot his buffer for each mesh
155                // min_binding_size,
156                min_binding_size: None,
157            },
158            count: None,
159        };
160        //add
161        self.layout_desc.as_mut().unwrap().entries.push(entry);
162        self.last_binding_number += 1;
163        self
164    }
165
166    /// # Panics
167    /// Will panic if the builder was not constructed with ``new()``
168    pub fn build(&mut self) -> BindGroupLayoutDesc {
169        self.layout_desc.take().unwrap()
170    }
171}