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