1use smallvec::SmallVec;
2use wgpu;
3
4use crate::texture::Texture;
5
6pub fn align(size: usize, alignment: usize) -> usize {
7 size.div_ceil(alignment) * alignment
8}
9
10#[derive(PartialEq, Clone)]
13pub enum BgEntriesId {
14 Tex(wgpu::Id<wgpu::Texture>),
15 Buf(wgpu::Id<wgpu::Buffer>),
16 Sampler(wgpu::Id<wgpu::Sampler>),
17}
18
19pub struct BindGroupWrapper {
23 bind_group: wgpu::BindGroup,
24 ids: SmallVec<[BgEntriesId; 16]>,
25}
26impl BindGroupWrapper {
27 fn new(bind_group: wgpu::BindGroup, ids: SmallVec<[BgEntriesId; 16]>) -> Self {
28 Self { bind_group, ids }
29 }
30 pub fn bg(&self) -> &wgpu::BindGroup {
31 &self.bind_group
32 }
33 pub fn is_stale(&self, entries: &SmallVec<[BindGroupEntry; 16]>) -> bool {
34 if self.ids.len() != entries.len() {
35 return true;
36 }
37
38 for it in entries.iter().zip(self.ids.iter()) {
39 let (entry, id) = it;
40 if entry.id != *id {
43 return true;
44 }
45 }
46
47 false
48 }
49}
50
51pub struct BindGroupEntry<'a> {
55 pub entry: wgpu::BindGroupEntry<'a>,
56 pub id: BgEntriesId,
57}
58
59pub struct BindGroupDesc<'a> {
61 pub label: Option<String>,
62 pub bind_group_entries: SmallVec<[BindGroupEntry<'a>; 16]>,
63 last_binding_number: u32,
64}
65impl Default for BindGroupDesc<'_> {
66 fn default() -> Self {
67 Self {
68 label: None,
69 bind_group_entries: SmallVec::new(),
70 last_binding_number: 0,
71 }
72 }
73}
74impl<'a> BindGroupDesc<'a> {
75 pub fn new(label: &str, entries: SmallVec<[BindGroupEntry<'a>; 16]>) -> Self {
76 Self {
77 label: Some(String::from(label)),
78 bind_group_entries: entries,
79 last_binding_number: 0,
80 }
81 }
82 pub fn into_bind_group_wrapper(self, device: &wgpu::Device, layout: &wgpu::BindGroupLayout) -> BindGroupWrapper {
83 let mut vec_entries: SmallVec<[wgpu::BindGroupEntry; 16]> = SmallVec::new();
85 let mut ids: SmallVec<[BgEntriesId; 16]> = SmallVec::new();
86 for bg_entry in self.bind_group_entries {
87 vec_entries.push(bg_entry.entry);
89 ids.push(bg_entry.id);
90 }
91 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
93 layout,
94 entries: vec_entries.as_slice(),
96 label: self.label.as_deref(),
97 });
98 BindGroupWrapper::new(bind_group, ids) }
101}
102
103pub struct BindGroupBuilder<'a> {
107 bind_group_desc: Option<BindGroupDesc<'a>>,
108}
109impl Default for BindGroupBuilder<'_> {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114impl<'a> BindGroupBuilder<'a> {
115 pub fn new() -> Self {
116 Self {
117 bind_group_desc: Some(BindGroupDesc::default()),
118 }
119 }
120
121 #[must_use]
124 pub fn label(mut self, label: &str) -> Self {
125 self.bind_group_desc.as_mut().unwrap().label = Some(String::from(label));
126 self
127 }
128
129 #[must_use]
132 pub fn add_entry_empty(mut self) -> Self {
133 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
134 self
135 }
136
137 #[must_use]
140 pub fn add_entry_tex(mut self, tex: &'a Texture) -> Self {
141 let binding_number = self.bind_group_desc.as_ref().unwrap().last_binding_number;
144 let entry = BindGroupEntry {
146 entry: wgpu::BindGroupEntry {
147 binding: binding_number,
148 resource: wgpu::BindingResource::TextureView(&tex.view),
149 },
150 id: BgEntriesId::Tex(tex.texture.global_id()),
151 };
152 self.bind_group_desc.as_mut().unwrap().bind_group_entries.push(entry);
154 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
155 self
156 }
157
158 #[must_use]
161 pub fn add_entry_buf(mut self, buffer: &'a wgpu::Buffer) -> Self {
162 let binding_number = self.bind_group_desc.as_ref().unwrap().last_binding_number;
165 let entry = BindGroupEntry {
167 entry: wgpu::BindGroupEntry {
168 binding: binding_number,
169 resource: buffer.as_entire_binding(),
170 },
171 id: BgEntriesId::Buf(buffer.global_id()),
172 };
173 self.bind_group_desc.as_mut().unwrap().bind_group_entries.push(entry);
175 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
176 self
177 }
178
179 #[must_use]
182 pub fn add_entry_buf_chunk<T>(mut self, buffer: &'a wgpu::Buffer) -> Self {
183 let binding_number = self.bind_group_desc.as_ref().unwrap().last_binding_number;
186 let binding = wgpu::BufferBinding {
188 buffer,
189 offset: 0,
190 size: wgpu::BufferSize::new(u64::try_from(align(std::mem::size_of::<T>(), 256)).unwrap()),
191 };
192 let entry = BindGroupEntry {
194 entry: wgpu::BindGroupEntry {
195 binding: binding_number,
196 resource: wgpu::BindingResource::Buffer(binding),
197 },
198 id: BgEntriesId::Buf(buffer.global_id()),
199 };
200 self.bind_group_desc.as_mut().unwrap().bind_group_entries.push(entry);
202 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
203 self
204 }
205
206 #[must_use]
209 pub fn add_entry_sampler(mut self, sampler: &'a wgpu::Sampler) -> Self {
210 let binding_number = self.bind_group_desc.as_ref().unwrap().last_binding_number;
213 let entry = BindGroupEntry {
215 entry: wgpu::BindGroupEntry {
216 binding: binding_number,
217 resource: wgpu::BindingResource::Sampler(sampler),
218 },
219 id: BgEntriesId::Sampler(sampler.global_id()),
220 };
221 self.bind_group_desc.as_mut().unwrap().bind_group_entries.push(entry);
223 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
224 self
225 }
226
227 pub fn build(&mut self, device: &wgpu::Device, layout: &wgpu::BindGroupLayout) -> BindGroupWrapper {
247 let desc = self.bind_group_desc.take().unwrap();
248 desc.into_bind_group_wrapper(device, layout)
249 }
250
251 pub fn build_bind_group(&mut self, device: &wgpu::Device, layout: &wgpu::BindGroupLayout) -> wgpu::BindGroup {
254 let desc = self.bind_group_desc.take().unwrap();
255 desc.into_bind_group_wrapper(device, layout).bind_group
256 }
257
258 pub fn build_entries(&mut self) -> SmallVec<[BindGroupEntry<'a>; 16]> {
261 self.bind_group_desc.take().unwrap().bind_group_entries
262 }
263}