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 BgResource {
14 TexView(wgpu::TextureView),
15 Buf(wgpu::Buffer),
16 Sampler(wgpu::Sampler),
17}
18
19pub struct BindGroupWrapper {
23 bind_group: wgpu::BindGroup,
24 resources: SmallVec<[BgResource; 16]>,
25}
26impl BindGroupWrapper {
27 fn new(bind_group: wgpu::BindGroup, resources: SmallVec<[BgResource; 16]>) -> Self {
28 Self { bind_group, resources }
29 }
30 pub fn bg(&self) -> &wgpu::BindGroup {
31 &self.bind_group
32 }
33 pub fn is_stale(&self, entries: &SmallVec<[wgpu::BindGroupEntry; 16]>) -> bool {
34 if self.resources.len() != entries.len() {
35 return true;
36 }
37
38 for it in entries.iter().zip(self.resources.iter()) {
39 let (entry, res) = it;
40 let is_different = match &entry.resource {
41 wgpu::BindingResource::Buffer(buffer_binding) => BgResource::Buf(buffer_binding.buffer.clone()) != *res,
42 wgpu::BindingResource::Sampler(sampler) => BgResource::Sampler((*sampler).clone()) != *res,
43 wgpu::BindingResource::TextureView(view) => BgResource::TexView((*view).clone()) != *res,
44 _ => unimplemented!("other binding types"),
45 };
46
47 if is_different {
48 return true;
49 }
50 }
51
52 false
53 }
54}
55
56pub struct BindGroupDesc<'a> {
58 pub label: Option<String>,
59 pub bind_group_entries: SmallVec<[wgpu::BindGroupEntry<'a>; 16]>,
60 last_binding_number: u32,
61}
62impl Default for BindGroupDesc<'_> {
63 fn default() -> Self {
64 Self {
65 label: None,
66 bind_group_entries: SmallVec::new(),
67 last_binding_number: 0,
68 }
69 }
70}
71impl<'a> BindGroupDesc<'a> {
72 pub fn new(label: &str, entries: SmallVec<[wgpu::BindGroupEntry<'a>; 16]>) -> Self {
73 Self {
74 label: Some(String::from(label)),
75 bind_group_entries: entries,
76 last_binding_number: 0,
77 }
78 }
79 pub fn into_bind_group_wrapper(self, device: &wgpu::Device, layout: &wgpu::BindGroupLayout) -> BindGroupWrapper {
80 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
82 layout,
83 entries: self.bind_group_entries.as_slice(),
84 label: self.label.as_deref(),
85 });
86 let mut bg_resources = SmallVec::new();
88 for res in self.bind_group_entries {
89 match res.resource {
90 wgpu::BindingResource::Buffer(buffer_binding) => bg_resources.push(BgResource::Buf(buffer_binding.buffer.clone())),
91 wgpu::BindingResource::Sampler(sampler) => bg_resources.push(BgResource::Sampler(sampler.clone())),
92 wgpu::BindingResource::TextureView(texture_view) => bg_resources.push(BgResource::TexView(texture_view.clone())),
93 _ => todo!(),
94 }
95 }
96 BindGroupWrapper::new(bind_group, bg_resources)
97 }
99}
100
101pub struct BindGroupBuilder<'a> {
105 bind_group_desc: Option<BindGroupDesc<'a>>,
106}
107impl Default for BindGroupBuilder<'_> {
108 fn default() -> Self {
109 Self::new()
110 }
111}
112impl<'a> BindGroupBuilder<'a> {
113 pub fn new() -> Self {
114 Self {
115 bind_group_desc: Some(BindGroupDesc::default()),
116 }
117 }
118
119 #[must_use]
122 pub fn label(mut self, label: &str) -> Self {
123 self.bind_group_desc.as_mut().unwrap().label = Some(String::from(label));
124 self
125 }
126
127 #[must_use]
130 pub fn add_entry_empty(mut self) -> Self {
131 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
132 self
133 }
134
135 #[must_use]
138 pub fn add_entry_tex(mut self, tex: &'a Texture) -> Self {
139 let binding_number = self.bind_group_desc.as_ref().unwrap().last_binding_number;
142 let entry = wgpu::BindGroupEntry {
144 binding: binding_number,
145 resource: wgpu::BindingResource::TextureView(&tex.view),
146 };
147 self.bind_group_desc.as_mut().unwrap().bind_group_entries.push(entry);
149 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
150 self
151 }
152
153 #[must_use]
156 pub fn add_entry_buf(mut self, buffer: &'a wgpu::Buffer) -> Self {
157 let binding_number = self.bind_group_desc.as_ref().unwrap().last_binding_number;
160 let entry = wgpu::BindGroupEntry {
162 binding: binding_number,
163 resource: buffer.as_entire_binding(),
164 };
165 self.bind_group_desc.as_mut().unwrap().bind_group_entries.push(entry);
167 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
168 self
169 }
170
171 #[must_use]
174 pub fn add_entry_buf_chunk<T>(mut self, buffer: &'a wgpu::Buffer) -> Self {
175 let binding_number = self.bind_group_desc.as_ref().unwrap().last_binding_number;
178 let binding = wgpu::BufferBinding {
180 buffer,
181 offset: 0,
182 size: wgpu::BufferSize::new(u64::try_from(align(std::mem::size_of::<T>(), 256)).unwrap()),
183 };
184 let entry = wgpu::BindGroupEntry {
186 binding: binding_number,
187 resource: wgpu::BindingResource::Buffer(binding),
188 };
189 self.bind_group_desc.as_mut().unwrap().bind_group_entries.push(entry);
191 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
192 self
193 }
194
195 #[must_use]
198 pub fn add_entry_sampler(mut self, sampler: &'a wgpu::Sampler) -> Self {
199 let binding_number = self.bind_group_desc.as_ref().unwrap().last_binding_number;
202 let entry = wgpu::BindGroupEntry {
204 binding: binding_number,
205 resource: wgpu::BindingResource::Sampler(sampler),
206 };
207 self.bind_group_desc.as_mut().unwrap().bind_group_entries.push(entry);
209 self.bind_group_desc.as_mut().unwrap().last_binding_number += 1;
210 self
211 }
212
213 pub fn build(&mut self, device: &wgpu::Device, layout: &wgpu::BindGroupLayout) -> BindGroupWrapper {
233 let desc = self.bind_group_desc.take().unwrap();
234 desc.into_bind_group_wrapper(device, layout)
235 }
236
237 pub fn build_bind_group(&mut self, device: &wgpu::Device, layout: &wgpu::BindGroupLayout) -> wgpu::BindGroup {
240 let desc = self.bind_group_desc.take().unwrap();
241 desc.into_bind_group_wrapper(device, layout).bind_group
242 }
243
244 pub fn build_entries(&mut self) -> SmallVec<[wgpu::BindGroupEntry<'a>; 16]> {
247 self.bind_group_desc.take().unwrap().bind_group_entries
248 }
249}