bevy_render/render_resource/
bind_group_entries.rs

1use variadics_please::all_tuples_with_size;
2use wgpu::{BindGroupEntry, BindingResource};
3
4use super::{Sampler, TextureView};
5
6/// Helper for constructing bindgroups.
7///
8/// Allows constructing the descriptor's entries as:
9/// ```ignore (render_device cannot be easily accessed)
10/// render_device.create_bind_group(
11///     "my_bind_group",
12///     &my_layout,
13///     &BindGroupEntries::with_indices((
14///         (2, &my_sampler),
15///         (3, my_uniform),
16///     )),
17/// );
18/// ```
19///
20/// instead of
21///
22/// ```ignore (render_device cannot be easily accessed)
23/// render_device.create_bind_group(
24///     "my_bind_group",
25///     &my_layout,
26///     &[
27///         BindGroupEntry {
28///             binding: 2,
29///             resource: BindingResource::Sampler(&my_sampler),
30///         },
31///         BindGroupEntry {
32///             binding: 3,
33///             resource: my_uniform,
34///         },
35///     ],
36/// );
37/// ```
38///
39/// or
40///
41/// ```ignore (render_device cannot be easily accessed)
42/// render_device.create_bind_group(
43///     "my_bind_group",
44///     &my_layout,
45///     &BindGroupEntries::sequential((
46///         &my_sampler,
47///         my_uniform,
48///     )),
49/// );
50/// ```
51///
52/// instead of
53///
54/// ```ignore (render_device cannot be easily accessed)
55/// render_device.create_bind_group(
56///     "my_bind_group",
57///     &my_layout,
58///     &[
59///         BindGroupEntry {
60///             binding: 0,
61///             resource: BindingResource::Sampler(&my_sampler),
62///         },
63///         BindGroupEntry {
64///             binding: 1,
65///             resource: my_uniform,
66///         },
67///     ],
68/// );
69/// ```
70///
71/// or
72///
73/// ```ignore (render_device cannot be easily accessed)
74/// render_device.create_bind_group(
75///     "my_bind_group",
76///     &my_layout,
77///     &BindGroupEntries::single(my_uniform),
78/// );
79/// ```
80///
81/// instead of
82///
83/// ```ignore (render_device cannot be easily accessed)
84/// render_device.create_bind_group(
85///     "my_bind_group",
86///     &my_layout,
87///     &[
88///         BindGroupEntry {
89///             binding: 0,
90///             resource: my_uniform,
91///         },
92///     ],
93/// );
94/// ```
95pub struct BindGroupEntries<'b, const N: usize = 1> {
96    entries: [BindGroupEntry<'b>; N],
97}
98
99impl<'b, const N: usize> BindGroupEntries<'b, N> {
100    #[inline]
101    pub fn sequential(resources: impl IntoBindingArray<'b, N>) -> Self {
102        let mut i = 0;
103        Self {
104            entries: resources.into_array().map(|resource| {
105                let binding = i;
106                i += 1;
107                BindGroupEntry { binding, resource }
108            }),
109        }
110    }
111
112    #[inline]
113    pub fn with_indices(indexed_resources: impl IntoIndexedBindingArray<'b, N>) -> Self {
114        Self {
115            entries: indexed_resources
116                .into_array()
117                .map(|(binding, resource)| BindGroupEntry { binding, resource }),
118        }
119    }
120}
121
122impl<'b> BindGroupEntries<'b, 1> {
123    pub fn single(resource: impl IntoBinding<'b>) -> [BindGroupEntry<'b>; 1] {
124        [BindGroupEntry {
125            binding: 0,
126            resource: resource.into_binding(),
127        }]
128    }
129}
130
131impl<'b, const N: usize> core::ops::Deref for BindGroupEntries<'b, N> {
132    type Target = [BindGroupEntry<'b>];
133
134    fn deref(&self) -> &[BindGroupEntry<'b>] {
135        &self.entries
136    }
137}
138
139pub trait IntoBinding<'a> {
140    fn into_binding(self) -> BindingResource<'a>;
141}
142
143impl<'a> IntoBinding<'a> for &'a TextureView {
144    #[inline]
145    fn into_binding(self) -> BindingResource<'a> {
146        BindingResource::TextureView(self)
147    }
148}
149
150impl<'a> IntoBinding<'a> for &'a wgpu::TextureView {
151    #[inline]
152    fn into_binding(self) -> BindingResource<'a> {
153        BindingResource::TextureView(self)
154    }
155}
156
157impl<'a> IntoBinding<'a> for &'a [&'a wgpu::TextureView] {
158    #[inline]
159    fn into_binding(self) -> BindingResource<'a> {
160        BindingResource::TextureViewArray(self)
161    }
162}
163
164impl<'a> IntoBinding<'a> for &'a Sampler {
165    #[inline]
166    fn into_binding(self) -> BindingResource<'a> {
167        BindingResource::Sampler(self)
168    }
169}
170
171impl<'a> IntoBinding<'a> for &'a [&'a wgpu::Sampler] {
172    #[inline]
173    fn into_binding(self) -> BindingResource<'a> {
174        BindingResource::SamplerArray(self)
175    }
176}
177
178impl<'a> IntoBinding<'a> for BindingResource<'a> {
179    #[inline]
180    fn into_binding(self) -> BindingResource<'a> {
181        self
182    }
183}
184
185impl<'a> IntoBinding<'a> for wgpu::BufferBinding<'a> {
186    #[inline]
187    fn into_binding(self) -> BindingResource<'a> {
188        BindingResource::Buffer(self)
189    }
190}
191
192impl<'a> IntoBinding<'a> for &'a [wgpu::BufferBinding<'a>] {
193    #[inline]
194    fn into_binding(self) -> BindingResource<'a> {
195        BindingResource::BufferArray(self)
196    }
197}
198
199pub trait IntoBindingArray<'b, const N: usize> {
200    fn into_array(self) -> [BindingResource<'b>; N];
201}
202
203macro_rules! impl_to_binding_slice {
204    ($N: expr, $(#[$meta:meta])* $(($T: ident, $I: ident)),*) => {
205        $(#[$meta])*
206        impl<'b, $($T: IntoBinding<'b>),*> IntoBindingArray<'b, $N> for ($($T,)*) {
207            #[inline]
208            fn into_array(self) -> [BindingResource<'b>; $N] {
209                let ($($I,)*) = self;
210                [$($I.into_binding(), )*]
211            }
212        }
213    }
214}
215
216all_tuples_with_size!(
217    #[doc(fake_variadic)]
218    impl_to_binding_slice,
219    1,
220    32,
221    T,
222    s
223);
224
225pub trait IntoIndexedBindingArray<'b, const N: usize> {
226    fn into_array(self) -> [(u32, BindingResource<'b>); N];
227}
228
229macro_rules! impl_to_indexed_binding_slice {
230    ($N: expr, $(($T: ident, $S: ident, $I: ident)),*) => {
231        impl<'b, $($T: IntoBinding<'b>),*> IntoIndexedBindingArray<'b, $N> for ($((u32, $T),)*) {
232            #[inline]
233            fn into_array(self) -> [(u32, BindingResource<'b>); $N] {
234                let ($(($S, $I),)*) = self;
235                [$(($S, $I.into_binding())), *]
236            }
237        }
238    }
239}
240
241all_tuples_with_size!(impl_to_indexed_binding_slice, 1, 32, T, n, s);
242
243pub struct DynamicBindGroupEntries<'b> {
244    entries: Vec<BindGroupEntry<'b>>,
245}
246
247impl<'b> Default for DynamicBindGroupEntries<'b> {
248    fn default() -> Self {
249        Self::new()
250    }
251}
252
253impl<'b> DynamicBindGroupEntries<'b> {
254    pub fn sequential<const N: usize>(entries: impl IntoBindingArray<'b, N>) -> Self {
255        Self {
256            entries: entries
257                .into_array()
258                .into_iter()
259                .enumerate()
260                .map(|(ix, resource)| BindGroupEntry {
261                    binding: ix as u32,
262                    resource,
263                })
264                .collect(),
265        }
266    }
267
268    pub fn extend_sequential<const N: usize>(
269        mut self,
270        entries: impl IntoBindingArray<'b, N>,
271    ) -> Self {
272        let start = self.entries.last().unwrap().binding + 1;
273        self.entries.extend(
274            entries
275                .into_array()
276                .into_iter()
277                .enumerate()
278                .map(|(ix, resource)| BindGroupEntry {
279                    binding: start + ix as u32,
280                    resource,
281                }),
282        );
283        self
284    }
285
286    pub fn new_with_indices<const N: usize>(entries: impl IntoIndexedBindingArray<'b, N>) -> Self {
287        Self {
288            entries: entries
289                .into_array()
290                .into_iter()
291                .map(|(binding, resource)| BindGroupEntry { binding, resource })
292                .collect(),
293        }
294    }
295
296    pub fn new() -> Self {
297        Self {
298            entries: Vec::new(),
299        }
300    }
301
302    pub fn extend_with_indices<const N: usize>(
303        mut self,
304        entries: impl IntoIndexedBindingArray<'b, N>,
305    ) -> Self {
306        self.entries.extend(
307            entries
308                .into_array()
309                .into_iter()
310                .map(|(binding, resource)| BindGroupEntry { binding, resource }),
311        );
312        self
313    }
314}
315
316impl<'b> core::ops::Deref for DynamicBindGroupEntries<'b> {
317    type Target = [BindGroupEntry<'b>];
318
319    fn deref(&self) -> &[BindGroupEntry<'b>] {
320        &self.entries
321    }
322}