Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_material/src/bind_group_layout_entries.rs
9357 views
1
use core::num::NonZero;
2
use variadics_please::all_tuples_with_size;
3
use wgpu_types::{BindGroupLayoutEntry, BindingType, ShaderStages};
4
5
/// Helper for constructing bind group layouts.
6
///
7
/// Allows constructing the layout's entries as:
8
/// ```ignore (render_device cannot be easily accessed)
9
/// let layout = render_device.create_bind_group_layout(
10
/// "my_bind_group_layout",
11
/// &BindGroupLayoutEntries::with_indices(
12
/// // The layout entries will only be visible in the fragment stage
13
/// ShaderStages::FRAGMENT,
14
/// (
15
/// // Screen texture
16
/// (2, texture_2d(TextureSampleType::Float { filterable: true })),
17
/// // Sampler
18
/// (3, sampler(SamplerBindingType::Filtering)),
19
/// ),
20
/// ),
21
/// );
22
/// ```
23
///
24
/// instead of
25
///
26
/// ```ignore (render_device cannot be easily accessed)
27
/// let layout = render_device.create_bind_group_layout(
28
/// "my_bind_group_layout",
29
/// &[
30
/// // Screen texture
31
/// BindGroupLayoutEntry {
32
/// binding: 2,
33
/// visibility: ShaderStages::FRAGMENT,
34
/// ty: BindingType::Texture {
35
/// sample_type: TextureSampleType::Float { filterable: true },
36
/// view_dimension: TextureViewDimension::D2,
37
/// multisampled: false,
38
/// },
39
/// count: None,
40
/// },
41
/// // Sampler
42
/// BindGroupLayoutEntry {
43
/// binding: 3,
44
/// visibility: ShaderStages::FRAGMENT,
45
/// ty: BindingType::Sampler(SamplerBindingType::Filtering),
46
/// count: None,
47
/// },
48
/// ],
49
/// );
50
/// ```
51
///
52
/// or
53
///
54
/// ```ignore (render_device cannot be easily accessed)
55
/// render_device.create_bind_group_layout(
56
/// "my_bind_group_layout",
57
/// &BindGroupLayoutEntries::sequential(
58
/// ShaderStages::FRAGMENT,
59
/// (
60
/// // Screen texture
61
/// texture_2d(TextureSampleType::Float { filterable: true }),
62
/// // Sampler
63
/// sampler(SamplerBindingType::Filtering),
64
/// ),
65
/// ),
66
/// );
67
/// ```
68
///
69
/// instead of
70
///
71
/// ```ignore (render_device cannot be easily accessed)
72
/// let layout = render_device.create_bind_group_layout(
73
/// "my_bind_group_layout",
74
/// &[
75
/// // Screen texture
76
/// BindGroupLayoutEntry {
77
/// binding: 0,
78
/// visibility: ShaderStages::FRAGMENT,
79
/// ty: BindingType::Texture {
80
/// sample_type: TextureSampleType::Float { filterable: true },
81
/// view_dimension: TextureViewDimension::D2,
82
/// multisampled: false,
83
/// },
84
/// count: None,
85
/// },
86
/// // Sampler
87
/// BindGroupLayoutEntry {
88
/// binding: 1,
89
/// visibility: ShaderStages::FRAGMENT,
90
/// ty: BindingType::Sampler(SamplerBindingType::Filtering),
91
/// count: None,
92
/// },
93
/// ],
94
/// );
95
/// ```
96
///
97
/// or
98
///
99
/// ```ignore (render_device cannot be easily accessed)
100
/// render_device.create_bind_group_layout(
101
/// "my_bind_group_layout",
102
/// &BindGroupLayoutEntries::single(
103
/// ShaderStages::FRAGMENT,
104
/// texture_2d(TextureSampleType::Float { filterable: true }),
105
/// ),
106
/// );
107
/// ```
108
///
109
/// instead of
110
///
111
/// ```ignore (render_device cannot be easily accessed)
112
/// let layout = render_device.create_bind_group_layout(
113
/// "my_bind_group_layout",
114
/// &[
115
/// BindGroupLayoutEntry {
116
/// binding: 0,
117
/// visibility: ShaderStages::FRAGMENT,
118
/// ty: BindingType::Texture {
119
/// sample_type: TextureSampleType::Float { filterable: true },
120
/// view_dimension: TextureViewDimension::D2,
121
/// multisampled: false,
122
/// },
123
/// count: None,
124
/// },
125
/// ],
126
/// );
127
/// ```
128
129
#[derive(Clone, Copy)]
130
pub struct BindGroupLayoutEntryBuilder {
131
ty: BindingType,
132
visibility: Option<ShaderStages>,
133
count: Option<NonZero<u32>>,
134
}
135
136
impl BindGroupLayoutEntryBuilder {
137
pub fn visibility(mut self, visibility: ShaderStages) -> Self {
138
self.visibility = Some(visibility);
139
self
140
}
141
142
pub fn count(mut self, count: NonZero<u32>) -> Self {
143
self.count = Some(count);
144
self
145
}
146
147
pub fn build(&self, binding: u32, default_visibility: ShaderStages) -> BindGroupLayoutEntry {
148
BindGroupLayoutEntry {
149
binding,
150
ty: self.ty,
151
visibility: self.visibility.unwrap_or(default_visibility),
152
count: self.count,
153
}
154
}
155
}
156
157
pub struct BindGroupLayoutEntries<const N: usize> {
158
entries: [BindGroupLayoutEntry; N],
159
}
160
161
impl<const N: usize> BindGroupLayoutEntries<N> {
162
#[inline]
163
pub fn sequential(
164
default_visibility: ShaderStages,
165
entries_ext: impl IntoBindGroupLayoutEntryBuilderArray<N>,
166
) -> Self {
167
let mut i = 0;
168
Self {
169
entries: entries_ext.into_array().map(|entry| {
170
let binding = i;
171
i += 1;
172
entry.build(binding, default_visibility)
173
}),
174
}
175
}
176
177
#[inline]
178
pub fn with_indices(
179
default_visibility: ShaderStages,
180
indexed_entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,
181
) -> Self {
182
Self {
183
entries: indexed_entries
184
.into_array()
185
.map(|(binding, entry)| entry.build(binding, default_visibility)),
186
}
187
}
188
}
189
190
impl BindGroupLayoutEntries<1> {
191
pub fn single(
192
visibility: ShaderStages,
193
resource: impl IntoBindGroupLayoutEntryBuilder,
194
) -> [BindGroupLayoutEntry; 1] {
195
[resource
196
.into_bind_group_layout_entry_builder()
197
.build(0, visibility)]
198
}
199
}
200
201
impl<const N: usize> core::ops::Deref for BindGroupLayoutEntries<N> {
202
type Target = [BindGroupLayoutEntry];
203
fn deref(&self) -> &[BindGroupLayoutEntry] {
204
&self.entries
205
}
206
}
207
208
pub trait IntoBindGroupLayoutEntryBuilder {
209
fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder;
210
}
211
212
impl IntoBindGroupLayoutEntryBuilder for BindingType {
213
fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder {
214
BindGroupLayoutEntryBuilder {
215
ty: self,
216
visibility: None,
217
count: None,
218
}
219
}
220
}
221
222
impl IntoBindGroupLayoutEntryBuilder for BindGroupLayoutEntry {
223
fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder {
224
if self.binding != u32::MAX {
225
tracing::warn!("The BindGroupLayoutEntries api ignores the binding index when converting a raw wgpu::BindGroupLayoutEntry. You can ignore this warning by setting it to u32::MAX.");
226
}
227
BindGroupLayoutEntryBuilder {
228
ty: self.ty,
229
visibility: Some(self.visibility),
230
count: self.count,
231
}
232
}
233
}
234
235
impl IntoBindGroupLayoutEntryBuilder for BindGroupLayoutEntryBuilder {
236
fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder {
237
self
238
}
239
}
240
241
pub trait IntoBindGroupLayoutEntryBuilderArray<const N: usize> {
242
fn into_array(self) -> [BindGroupLayoutEntryBuilder; N];
243
}
244
macro_rules! impl_to_binding_type_slice {
245
($N: expr, $(#[$meta:meta])* $(($T: ident, $I: ident)),*) => {
246
$(#[$meta])*
247
impl<$($T: IntoBindGroupLayoutEntryBuilder),*> IntoBindGroupLayoutEntryBuilderArray<$N> for ($($T,)*) {
248
#[inline]
249
fn into_array(self) -> [BindGroupLayoutEntryBuilder; $N] {
250
let ($($I,)*) = self;
251
[$($I.into_bind_group_layout_entry_builder(), )*]
252
}
253
}
254
}
255
}
256
all_tuples_with_size!(
257
#[doc(fake_variadic)]
258
impl_to_binding_type_slice,
259
1,
260
32,
261
T,
262
s
263
);
264
265
pub trait IntoIndexedBindGroupLayoutEntryBuilderArray<const N: usize> {
266
fn into_array(self) -> [(u32, BindGroupLayoutEntryBuilder); N];
267
}
268
macro_rules! impl_to_indexed_binding_type_slice {
269
($N: expr, $(($T: ident, $S: ident, $I: ident)),*) => {
270
impl<$($T: IntoBindGroupLayoutEntryBuilder),*> IntoIndexedBindGroupLayoutEntryBuilderArray<$N> for ($((u32, $T),)*) {
271
#[inline]
272
fn into_array(self) -> [(u32, BindGroupLayoutEntryBuilder); $N] {
273
let ($(($S, $I),)*) = self;
274
[$(($S, $I.into_bind_group_layout_entry_builder())), *]
275
}
276
}
277
}
278
}
279
all_tuples_with_size!(impl_to_indexed_binding_type_slice, 1, 32, T, n, s);
280
281
impl<const N: usize> IntoBindGroupLayoutEntryBuilderArray<N> for [BindGroupLayoutEntry; N] {
282
fn into_array(self) -> [BindGroupLayoutEntryBuilder; N] {
283
self.map(IntoBindGroupLayoutEntryBuilder::into_bind_group_layout_entry_builder)
284
}
285
}
286
287
pub struct DynamicBindGroupLayoutEntries {
288
default_visibility: ShaderStages,
289
entries: Vec<BindGroupLayoutEntry>,
290
}
291
292
impl DynamicBindGroupLayoutEntries {
293
pub fn sequential<const N: usize>(
294
default_visibility: ShaderStages,
295
entries: impl IntoBindGroupLayoutEntryBuilderArray<N>,
296
) -> Self {
297
Self {
298
default_visibility,
299
entries: entries
300
.into_array()
301
.into_iter()
302
.enumerate()
303
.map(|(ix, resource)| resource.build(ix as u32, default_visibility))
304
.collect(),
305
}
306
}
307
308
pub fn extend_sequential<const N: usize>(
309
mut self,
310
entries: impl IntoBindGroupLayoutEntryBuilderArray<N>,
311
) -> Self {
312
let start = self.entries.last().unwrap().binding + 1;
313
self.entries.extend(
314
entries
315
.into_array()
316
.into_iter()
317
.enumerate()
318
.map(|(ix, resource)| resource.build(start + ix as u32, self.default_visibility)),
319
);
320
self
321
}
322
323
pub fn new_with_indices<const N: usize>(
324
default_visibility: ShaderStages,
325
entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,
326
) -> Self {
327
Self {
328
default_visibility,
329
entries: entries
330
.into_array()
331
.into_iter()
332
.map(|(binding, resource)| resource.build(binding, default_visibility))
333
.collect(),
334
}
335
}
336
337
pub fn new(default_visibility: ShaderStages) -> Self {
338
Self {
339
default_visibility,
340
entries: Vec::new(),
341
}
342
}
343
344
pub fn extend_with_indices<const N: usize>(
345
mut self,
346
entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,
347
) -> Self {
348
self.entries.extend(
349
entries
350
.into_array()
351
.into_iter()
352
.map(|(binding, resource)| resource.build(binding, self.default_visibility)),
353
);
354
self
355
}
356
}
357
358
impl core::ops::Deref for DynamicBindGroupLayoutEntries {
359
type Target = [BindGroupLayoutEntry];
360
361
fn deref(&self) -> &[BindGroupLayoutEntry] {
362
&self.entries
363
}
364
}
365
366
pub mod binding_types {
367
use core::num::NonZero;
368
use encase::ShaderType;
369
use wgpu_types::{
370
BufferBindingType, SamplerBindingType, TextureSampleType, TextureViewDimension,
371
};
372
use wgpu_types::{StorageTextureAccess, TextureFormat};
373
374
use super::*;
375
376
pub fn storage_buffer<T: ShaderType>(has_dynamic_offset: bool) -> BindGroupLayoutEntryBuilder {
377
storage_buffer_sized(has_dynamic_offset, Some(T::min_size()))
378
}
379
380
pub fn storage_buffer_sized(
381
has_dynamic_offset: bool,
382
min_binding_size: Option<NonZero<u64>>,
383
) -> BindGroupLayoutEntryBuilder {
384
BindingType::Buffer {
385
ty: BufferBindingType::Storage { read_only: false },
386
has_dynamic_offset,
387
min_binding_size,
388
}
389
.into_bind_group_layout_entry_builder()
390
}
391
392
pub fn storage_buffer_read_only<T: ShaderType>(
393
has_dynamic_offset: bool,
394
) -> BindGroupLayoutEntryBuilder {
395
storage_buffer_read_only_sized(has_dynamic_offset, Some(T::min_size()))
396
}
397
398
pub fn storage_buffer_read_only_sized(
399
has_dynamic_offset: bool,
400
min_binding_size: Option<NonZero<u64>>,
401
) -> BindGroupLayoutEntryBuilder {
402
BindingType::Buffer {
403
ty: BufferBindingType::Storage { read_only: true },
404
has_dynamic_offset,
405
min_binding_size,
406
}
407
.into_bind_group_layout_entry_builder()
408
}
409
410
pub fn uniform_buffer<T: ShaderType>(has_dynamic_offset: bool) -> BindGroupLayoutEntryBuilder {
411
uniform_buffer_sized(has_dynamic_offset, Some(T::min_size()))
412
}
413
414
pub fn uniform_buffer_sized(
415
has_dynamic_offset: bool,
416
min_binding_size: Option<NonZero<u64>>,
417
) -> BindGroupLayoutEntryBuilder {
418
BindingType::Buffer {
419
ty: BufferBindingType::Uniform,
420
has_dynamic_offset,
421
min_binding_size,
422
}
423
.into_bind_group_layout_entry_builder()
424
}
425
426
pub fn texture_1d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
427
BindingType::Texture {
428
sample_type,
429
view_dimension: TextureViewDimension::D1,
430
multisampled: false,
431
}
432
.into_bind_group_layout_entry_builder()
433
}
434
435
pub fn texture_2d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
436
BindingType::Texture {
437
sample_type,
438
view_dimension: TextureViewDimension::D2,
439
multisampled: false,
440
}
441
.into_bind_group_layout_entry_builder()
442
}
443
444
pub fn texture_2d_multisampled(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
445
BindingType::Texture {
446
sample_type,
447
view_dimension: TextureViewDimension::D2,
448
multisampled: true,
449
}
450
.into_bind_group_layout_entry_builder()
451
}
452
453
pub fn texture_2d_array(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
454
BindingType::Texture {
455
sample_type,
456
view_dimension: TextureViewDimension::D2Array,
457
multisampled: false,
458
}
459
.into_bind_group_layout_entry_builder()
460
}
461
462
pub fn texture_2d_array_multisampled(
463
sample_type: TextureSampleType,
464
) -> BindGroupLayoutEntryBuilder {
465
BindingType::Texture {
466
sample_type,
467
view_dimension: TextureViewDimension::D2Array,
468
multisampled: true,
469
}
470
.into_bind_group_layout_entry_builder()
471
}
472
473
pub fn texture_depth_2d() -> BindGroupLayoutEntryBuilder {
474
texture_2d(TextureSampleType::Depth).into_bind_group_layout_entry_builder()
475
}
476
477
pub fn texture_depth_2d_multisampled() -> BindGroupLayoutEntryBuilder {
478
texture_2d_multisampled(TextureSampleType::Depth).into_bind_group_layout_entry_builder()
479
}
480
481
pub fn texture_cube(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
482
BindingType::Texture {
483
sample_type,
484
view_dimension: TextureViewDimension::Cube,
485
multisampled: false,
486
}
487
.into_bind_group_layout_entry_builder()
488
}
489
490
pub fn texture_cube_multisampled(
491
sample_type: TextureSampleType,
492
) -> BindGroupLayoutEntryBuilder {
493
BindingType::Texture {
494
sample_type,
495
view_dimension: TextureViewDimension::Cube,
496
multisampled: true,
497
}
498
.into_bind_group_layout_entry_builder()
499
}
500
501
pub fn texture_cube_array(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
502
BindingType::Texture {
503
sample_type,
504
view_dimension: TextureViewDimension::CubeArray,
505
multisampled: false,
506
}
507
.into_bind_group_layout_entry_builder()
508
}
509
510
pub fn texture_cube_array_multisampled(
511
sample_type: TextureSampleType,
512
) -> BindGroupLayoutEntryBuilder {
513
BindingType::Texture {
514
sample_type,
515
view_dimension: TextureViewDimension::CubeArray,
516
multisampled: true,
517
}
518
.into_bind_group_layout_entry_builder()
519
}
520
521
pub fn texture_3d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
522
BindingType::Texture {
523
sample_type,
524
view_dimension: TextureViewDimension::D3,
525
multisampled: false,
526
}
527
.into_bind_group_layout_entry_builder()
528
}
529
530
pub fn texture_3d_multisampled(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {
531
BindingType::Texture {
532
sample_type,
533
view_dimension: TextureViewDimension::D3,
534
multisampled: true,
535
}
536
.into_bind_group_layout_entry_builder()
537
}
538
539
pub fn sampler(sampler_binding_type: SamplerBindingType) -> BindGroupLayoutEntryBuilder {
540
BindingType::Sampler(sampler_binding_type).into_bind_group_layout_entry_builder()
541
}
542
543
pub fn texture_storage_2d(
544
format: TextureFormat,
545
access: StorageTextureAccess,
546
) -> BindGroupLayoutEntryBuilder {
547
BindingType::StorageTexture {
548
access,
549
format,
550
view_dimension: TextureViewDimension::D2,
551
}
552
.into_bind_group_layout_entry_builder()
553
}
554
555
pub fn texture_storage_2d_array(
556
format: TextureFormat,
557
access: StorageTextureAccess,
558
) -> BindGroupLayoutEntryBuilder {
559
BindingType::StorageTexture {
560
access,
561
format,
562
view_dimension: TextureViewDimension::D2Array,
563
}
564
.into_bind_group_layout_entry_builder()
565
}
566
567
pub fn texture_storage_3d(
568
format: TextureFormat,
569
access: StorageTextureAccess,
570
) -> BindGroupLayoutEntryBuilder {
571
BindingType::StorageTexture {
572
access,
573
format,
574
view_dimension: TextureViewDimension::D3,
575
}
576
.into_bind_group_layout_entry_builder()
577
}
578
579
pub fn acceleration_structure() -> BindGroupLayoutEntryBuilder {
580
BindingType::AccelerationStructure {
581
vertex_return: false,
582
}
583
.into_bind_group_layout_entry_builder()
584
}
585
586
pub fn acceleration_structure_vertex_return() -> BindGroupLayoutEntryBuilder {
587
BindingType::AccelerationStructure {
588
vertex_return: true,
589
}
590
.into_bind_group_layout_entry_builder()
591
}
592
}
593
594