1use std::{ops::Deref, rc::Rc};
2
3use wgpu::BindGroupEntry;
4
5use crate::Gpu;
6
7impl crate::Buffer {
8 #[must_use]
19 pub fn bind_uniform(&self) -> Binding {
20 Binding {
21 gpu: &self.gpu,
22 visibility: Binding::DEFAULT_VISIBILITY,
23 ty: wgpu::BindingType::Buffer {
24 ty: wgpu::BufferBindingType::Uniform,
25 has_dynamic_offset: false,
26 min_binding_size: None,
27 },
28 resource: self.as_entire_binding(),
29 }
30 }
31
32 #[must_use]
34 pub fn bind(&self) -> Binding {
35 self.bind_uniform()
36 }
37
38 #[must_use]
47 pub fn bind_storage(&self) -> Binding {
48 Binding {
49 gpu: &self.gpu,
50 visibility: Binding::DEFAULT_VISIBILITY,
51 ty: wgpu::BindingType::Buffer {
52 ty: wgpu::BufferBindingType::Storage { read_only: false },
53 has_dynamic_offset: false,
54 min_binding_size: None,
55 },
56 resource: self.as_entire_binding(),
57 }
58 }
59
60 #[must_use]
70 pub fn bind_storage_readonly(&self) -> Binding {
71 Binding {
72 gpu: &self.gpu,
73 visibility: Binding::DEFAULT_VISIBILITY,
74 ty: wgpu::BindingType::Buffer {
75 ty: wgpu::BufferBindingType::Storage { read_only: true },
76 has_dynamic_offset: false,
77 min_binding_size: None,
78 },
79 resource: self.as_entire_binding(),
80 }
81 }
82}
83
84impl<D> crate::Texture<D>
85where
86 D: crate::TextureDimensions,
87{
88 pub fn bind_texture(&self) -> Binding {
91 Binding {
92 gpu: &self.gpu,
93 visibility: Binding::DEFAULT_VISIBILITY,
94 ty: wgpu::BindingType::Texture {
95 sample_type: sample_type(self.format),
96 view_dimension: match self.size.dim() {
98 wgpu::TextureDimension::D1 => wgpu::TextureViewDimension::D1,
99 wgpu::TextureDimension::D2 => wgpu::TextureViewDimension::D2,
100 wgpu::TextureDimension::D3 => wgpu::TextureViewDimension::D3,
101 },
102 multisampled: false,
103 },
104 resource: wgpu::BindingResource::TextureView(&self.view),
105 }
106 }
107
108 pub fn bind(&self) -> Binding {
111 self.bind_texture()
112 }
113
114 pub fn bind_storage_texture(&self) -> Binding {
117 Binding {
118 gpu: &self.gpu,
119 visibility: Binding::DEFAULT_VISIBILITY,
120 ty: wgpu::BindingType::StorageTexture {
121 view_dimension: match self.size.dim() {
123 wgpu::TextureDimension::D1 => wgpu::TextureViewDimension::D1,
124 wgpu::TextureDimension::D2 => wgpu::TextureViewDimension::D2,
125 wgpu::TextureDimension::D3 => wgpu::TextureViewDimension::D3,
126 },
127 access: wgpu::StorageTextureAccess::ReadWrite,
128 format: self.format,
129 },
130 resource: wgpu::BindingResource::TextureView(&self.view),
131 }
132 }
133}
134
135macro_rules! gen_binding_vis_fn {
136 ($($fn_name:ident => $stage:ident),*) => {
137 $(
138 pub const fn $fn_name(mut self) -> Self {
139 self.visibility = ::wgpu::ShaderStages::$stage;
140 self
141 }
142 )*
143 };
144}
145
146#[derive(Clone, Debug)]
147pub struct Binding<'a> {
148 pub gpu: &'a Gpu,
149 pub visibility: wgpu::ShaderStages,
150 pub ty: wgpu::BindingType,
151 pub resource: wgpu::BindingResource<'a>,
152}
153impl Binding<'_> {
154 pub(crate) const DEFAULT_VISIBILITY: wgpu::ShaderStages = wgpu::ShaderStages::VERTEX_FRAGMENT;
155
156 gen_binding_vis_fn!(
157 in_none => NONE,
158 in_vertex => VERTEX,
159 in_fragment => FRAGMENT,
160 in_compute => COMPUTE,
161 in_vertex_fragment => VERTEX_FRAGMENT
162 );
163
164 pub const fn buffer_dynamic_offset(mut self) -> Self {
165 if let wgpu::BindingType::Buffer {
166 ty,
167 min_binding_size,
168 ..
169 } = self.ty
170 {
171 self.ty = wgpu::BindingType::Buffer {
172 ty,
173 has_dynamic_offset: true,
174 min_binding_size,
175 };
176 } else {
177 #[cfg(feature = "const_panic")]
178 panic!("dynamic_offset is only supported for uniform buffers");
179 }
180 self
181 }
182
183 pub const fn sample_uint(mut self) -> Self {
184 if let wgpu::BindingType::Texture {
185 view_dimension,
186 multisampled,
187 ..
188 } = self.ty
189 {
190 self.ty = wgpu::BindingType::Texture {
191 sample_type: wgpu::TextureSampleType::Uint,
192 view_dimension,
193 multisampled,
194 };
195 } else {
196 #[cfg(feature = "const_panic")]
197 panic!("sample_uint is only supported for textures");
198 }
199 self
200 }
201}
202
203#[derive(Clone, Debug)]
204pub struct BindGroupLayout {
205 gpu: Gpu,
206 inner: Rc<wgpu::BindGroupLayout>,
207}
208impl Deref for BindGroupLayout {
209 type Target = wgpu::BindGroupLayout;
210 fn deref(&self) -> &Self::Target {
211 &self.inner
212 }
213}
214impl BindGroupLayout {
215 pub fn from_wgpu(gpu: Gpu, layout: wgpu::BindGroupLayout) -> Self {
216 Self {
217 gpu,
218 inner: Rc::new(layout),
219 }
220 }
221 pub fn inner(&self) -> &wgpu::BindGroupLayout {
222 &self.inner
223 }
224 pub fn create_bind_group(&self, bindings: &[Binding]) -> BindGroup {
225 let bind_group = self
226 .gpu
227 .device
228 .create_bind_group(&wgpu::BindGroupDescriptor {
229 label: None,
230 layout: self,
231 entries: bindings
232 .iter()
233 .enumerate()
234 .map(|(i, b)| BindGroupEntry {
235 binding: i as _,
236 resource: b.resource.clone(),
237 })
238 .collect::<Vec<_>>()
239 .as_slice(),
240 });
241
242 BindGroup {
243 gpu: self.gpu.clone(),
244 layout: self.clone(),
245 inner: bind_group,
246 }
247 }
248}
249
250#[derive(Debug)]
251pub struct BindGroup {
252 gpu: crate::Gpu,
253 pub layout: BindGroupLayout,
254 pub inner: wgpu::BindGroup,
255}
256crate::wgpu_inner_deref!(BindGroup);
257
258impl BindGroup {
259 pub fn new(gpu: crate::Gpu, bindings: &[Binding]) -> Self {
260 let bind_group_layout = gpu.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
261 label: None,
262 entries: bindings
263 .iter()
264 .enumerate()
265 .map(|(i, binding)| wgpu::BindGroupLayoutEntry {
266 binding: i as _,
267 visibility: binding.visibility,
268 ty: binding.ty,
269 count: None,
270 })
271 .collect::<Vec<_>>()
272 .as_slice(),
273 });
274
275 let bind_group = gpu.device.create_bind_group(&wgpu::BindGroupDescriptor {
276 label: None,
277 layout: &bind_group_layout,
278 entries: bindings
279 .iter()
280 .enumerate()
281 .map(|(i, b)| BindGroupEntry {
282 binding: i as _,
283 resource: b.resource.clone(),
284 })
285 .collect::<Vec<_>>()
286 .as_slice(),
287 });
288 let layout = BindGroupLayout::from_wgpu(gpu.clone(), bind_group_layout);
289
290 BindGroup {
291 gpu,
292 layout,
293 inner: bind_group,
294 }
295 }
296
297 pub fn instance(&self, bindings: &[Binding]) -> Self {
299 let bind_group = self
300 .gpu
301 .device
302 .create_bind_group(&wgpu::BindGroupDescriptor {
303 label: None,
304 layout: &self.layout,
305 entries: bindings
306 .iter()
307 .enumerate()
308 .map(|(i, b)| BindGroupEntry {
309 binding: i as _,
310 resource: b.resource.clone(),
311 })
312 .collect::<Vec<_>>()
313 .as_slice(),
314 });
315
316 BindGroup {
317 gpu: self.gpu.clone(),
318 layout: self.layout.clone(),
319 inner: bind_group,
320 }
321 }
322
323 pub fn rebind(&mut self, bindings: &[Binding]) -> &Self {
325 self.inner = self
326 .gpu
327 .device
328 .create_bind_group(&wgpu::BindGroupDescriptor {
329 label: None,
330 layout: &self.layout,
331 entries: bindings
332 .iter()
333 .enumerate()
334 .map(|(i, b)| BindGroupEntry {
335 binding: i as _,
336 resource: b.resource.clone(),
337 })
338 .collect::<Vec<_>>()
339 .as_slice(),
340 });
341 self
342 }
343}
344impl crate::Gpu {
345 pub fn create_bind_group(&self, bindings: &[Binding]) -> BindGroup {
346 BindGroup::new(self.clone(), bindings)
347 }
348}
349pub trait BindingsExt {
350 fn create_group(&self) -> BindGroup;
351}
352impl BindingsExt for [Binding<'_>] {
353 fn create_group(&self) -> BindGroup {
354 if let Some(Binding { gpu, .. }) = self.first() {
355 gpu.create_bind_group(self)
356 } else {
357 unreachable!("[Binding].group() array must not be empty")
358 }
359 }
360}
361
362pub(crate) const fn sample_type(format: wgpu::TextureFormat) -> wgpu::TextureSampleType {
364 const UINT: wgpu::TextureSampleType = wgpu::TextureSampleType::Uint;
366 const SINT: wgpu::TextureSampleType = wgpu::TextureSampleType::Sint;
367 const NEAREST: wgpu::TextureSampleType = wgpu::TextureSampleType::Float { filterable: false };
368 const FLOAT: wgpu::TextureSampleType = wgpu::TextureSampleType::Float { filterable: true };
369 const DEPTH: wgpu::TextureSampleType = wgpu::TextureSampleType::Depth;
370
371 match format {
372 wgpu::TextureFormat::R8Unorm => FLOAT,
374 wgpu::TextureFormat::R8Snorm => FLOAT,
375 wgpu::TextureFormat::R8Uint => UINT,
376 wgpu::TextureFormat::R8Sint => SINT,
377
378 wgpu::TextureFormat::R16Uint => UINT,
380 wgpu::TextureFormat::R16Sint => SINT,
381 wgpu::TextureFormat::R16Float => FLOAT,
382 wgpu::TextureFormat::Rg8Unorm => FLOAT,
383 wgpu::TextureFormat::Rg8Snorm => FLOAT,
384 wgpu::TextureFormat::Rg8Uint => UINT,
385 wgpu::TextureFormat::Rg8Sint => SINT,
386
387 wgpu::TextureFormat::R32Uint => UINT,
389 wgpu::TextureFormat::R32Sint => SINT,
390 wgpu::TextureFormat::R32Float => NEAREST,
391 wgpu::TextureFormat::Rg16Uint => UINT,
392 wgpu::TextureFormat::Rg16Sint => SINT,
393 wgpu::TextureFormat::Rg16Float => FLOAT,
394 wgpu::TextureFormat::Rgba8Unorm => FLOAT,
395 wgpu::TextureFormat::Rgba8UnormSrgb => FLOAT,
396 wgpu::TextureFormat::Rgba8Snorm => FLOAT,
397 wgpu::TextureFormat::Rgba8Uint => UINT,
398 wgpu::TextureFormat::Rgba8Sint => SINT,
399 wgpu::TextureFormat::Bgra8Unorm => FLOAT,
400 wgpu::TextureFormat::Bgra8UnormSrgb => FLOAT,
401
402 wgpu::TextureFormat::Rgb10a2Unorm => FLOAT,
404 wgpu::TextureFormat::Rg11b10Float => FLOAT,
405
406 wgpu::TextureFormat::Rg32Uint => UINT,
408 wgpu::TextureFormat::Rg32Sint => SINT,
409 wgpu::TextureFormat::Rg32Float => NEAREST,
410 wgpu::TextureFormat::Rgba16Uint => UINT,
411 wgpu::TextureFormat::Rgba16Sint => SINT,
412 wgpu::TextureFormat::Rgba16Float => FLOAT,
413
414 wgpu::TextureFormat::Rgba32Uint => UINT,
416 wgpu::TextureFormat::Rgba32Sint => SINT,
417 wgpu::TextureFormat::Rgba32Float => NEAREST,
418
419 wgpu::TextureFormat::Depth32Float => DEPTH,
421 wgpu::TextureFormat::Depth24Plus => DEPTH,
422 wgpu::TextureFormat::Depth24PlusStencil8 => DEPTH,
423
424 wgpu::TextureFormat::Rgb9e5Ufloat => FLOAT,
426
427 wgpu::TextureFormat::Bc1RgbaUnorm
429 | wgpu::TextureFormat::Bc1RgbaUnormSrgb
430 | wgpu::TextureFormat::Bc2RgbaUnorm
431 | wgpu::TextureFormat::Bc2RgbaUnormSrgb
432 | wgpu::TextureFormat::Bc3RgbaUnorm
433 | wgpu::TextureFormat::Bc3RgbaUnormSrgb
434 | wgpu::TextureFormat::Bc4RUnorm
435 | wgpu::TextureFormat::Bc4RSnorm
436 | wgpu::TextureFormat::Bc5RgUnorm
437 | wgpu::TextureFormat::Bc5RgSnorm
438 | wgpu::TextureFormat::Bc6hRgbUfloat
439 | wgpu::TextureFormat::Bc6hRgbSfloat
440 | wgpu::TextureFormat::Bc7RgbaUnorm
441 | wgpu::TextureFormat::Bc7RgbaUnormSrgb => FLOAT,
442
443 wgpu::TextureFormat::Etc2Rgb8Unorm
445 | wgpu::TextureFormat::Etc2Rgb8UnormSrgb
446 | wgpu::TextureFormat::Etc2Rgb8A1Unorm
447 | wgpu::TextureFormat::Etc2Rgb8A1UnormSrgb
448 | wgpu::TextureFormat::Etc2Rgba8Unorm
449 | wgpu::TextureFormat::Etc2Rgba8UnormSrgb
450 | wgpu::TextureFormat::EacR11Unorm
451 | wgpu::TextureFormat::EacR11Snorm
452 | wgpu::TextureFormat::EacRg11Unorm
453 | wgpu::TextureFormat::EacRg11Snorm => FLOAT,
454
455 wgpu::TextureFormat::Astc4x4RgbaUnorm
457 | wgpu::TextureFormat::Astc4x4RgbaUnormSrgb
458 | wgpu::TextureFormat::Astc5x4RgbaUnorm
459 | wgpu::TextureFormat::Astc5x4RgbaUnormSrgb
460 | wgpu::TextureFormat::Astc5x5RgbaUnorm
461 | wgpu::TextureFormat::Astc5x5RgbaUnormSrgb
462 | wgpu::TextureFormat::Astc6x5RgbaUnorm
463 | wgpu::TextureFormat::Astc6x5RgbaUnormSrgb
464 | wgpu::TextureFormat::Astc6x6RgbaUnorm
465 | wgpu::TextureFormat::Astc6x6RgbaUnormSrgb
466 | wgpu::TextureFormat::Astc8x5RgbaUnorm
467 | wgpu::TextureFormat::Astc8x5RgbaUnormSrgb
468 | wgpu::TextureFormat::Astc8x6RgbaUnorm
469 | wgpu::TextureFormat::Astc8x6RgbaUnormSrgb
470 | wgpu::TextureFormat::Astc10x5RgbaUnorm
471 | wgpu::TextureFormat::Astc10x5RgbaUnormSrgb
472 | wgpu::TextureFormat::Astc10x6RgbaUnorm
473 | wgpu::TextureFormat::Astc10x6RgbaUnormSrgb
474 | wgpu::TextureFormat::Astc8x8RgbaUnorm
475 | wgpu::TextureFormat::Astc8x8RgbaUnormSrgb
476 | wgpu::TextureFormat::Astc10x8RgbaUnorm
477 | wgpu::TextureFormat::Astc10x8RgbaUnormSrgb
478 | wgpu::TextureFormat::Astc10x10RgbaUnorm
479 | wgpu::TextureFormat::Astc10x10RgbaUnormSrgb
480 | wgpu::TextureFormat::Astc12x10RgbaUnorm
481 | wgpu::TextureFormat::Astc12x10RgbaUnormSrgb
482 | wgpu::TextureFormat::Astc12x12RgbaUnorm
483 | wgpu::TextureFormat::Astc12x12RgbaUnormSrgb => FLOAT,
484
485 wgpu::TextureFormat::R16Unorm
487 | wgpu::TextureFormat::R16Snorm
488 | wgpu::TextureFormat::Rg16Unorm
489 | wgpu::TextureFormat::Rg16Snorm
490 | wgpu::TextureFormat::Rgba16Unorm
491 | wgpu::TextureFormat::Rgba16Snorm => FLOAT,
492 }
493}