bevy_render/render_resource/
bind_group_entries.rs

1use bevy_utils::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/// ```
95
96pub struct BindGroupEntries<'b, const N: usize = 1> {
97    entries: [BindGroupEntry<'b>; N],
98}
99
100impl<'b, const N: usize> BindGroupEntries<'b, N> {
101    #[inline]
102    pub fn sequential(resources: impl IntoBindingArray<'b, N>) -> Self {
103        let mut i = 0;
104        Self {
105            entries: resources.into_array().map(|resource| {
106                let binding = i;
107                i += 1;
108                BindGroupEntry { binding, resource }
109            }),
110        }
111    }
112
113    #[inline]
114    pub fn with_indices(indexed_resources: impl IntoIndexedBindingArray<'b, N>) -> Self {
115        Self {
116            entries: indexed_resources
117                .into_array()
118                .map(|(binding, resource)| BindGroupEntry { binding, resource }),
119        }
120    }
121}
122
123impl<'b> BindGroupEntries<'b, 1> {
124    pub fn single(resource: impl IntoBinding<'b>) -> [BindGroupEntry<'b>; 1] {
125        [BindGroupEntry {
126            binding: 0,
127            resource: resource.into_binding(),
128        }]
129    }
130}
131
132impl<'b, const N: usize> std::ops::Deref for BindGroupEntries<'b, N> {
133    type Target = [BindGroupEntry<'b>];
134
135    fn deref(&self) -> &[BindGroupEntry<'b>] {
136        &self.entries
137    }
138}
139
140pub trait IntoBinding<'a> {
141    fn into_binding(self) -> BindingResource<'a>;
142}
143
144impl<'a> IntoBinding<'a> for &'a TextureView {
145    #[inline]
146    fn into_binding(self) -> BindingResource<'a> {
147        BindingResource::TextureView(self)
148    }
149}
150
151impl<'a> IntoBinding<'a> for &'a [&'a wgpu::TextureView] {
152    #[inline]
153    fn into_binding(self) -> BindingResource<'a> {
154        BindingResource::TextureViewArray(self)
155    }
156}
157
158impl<'a> IntoBinding<'a> for &'a Sampler {
159    #[inline]
160    fn into_binding(self) -> BindingResource<'a> {
161        BindingResource::Sampler(self)
162    }
163}
164
165impl<'a> IntoBinding<'a> for BindingResource<'a> {
166    #[inline]
167    fn into_binding(self) -> BindingResource<'a> {
168        self
169    }
170}
171
172impl<'a> IntoBinding<'a> for wgpu::BufferBinding<'a> {
173    #[inline]
174    fn into_binding(self) -> BindingResource<'a> {
175        BindingResource::Buffer(self)
176    }
177}
178
179pub trait IntoBindingArray<'b, const N: usize> {
180    fn into_array(self) -> [BindingResource<'b>; N];
181}
182
183macro_rules! impl_to_binding_slice {
184    ($N: expr, $(($T: ident, $I: ident)),*) => {
185        impl<'b, $($T: IntoBinding<'b>),*> IntoBindingArray<'b, $N> for ($($T,)*) {
186            #[inline]
187            fn into_array(self) -> [BindingResource<'b>; $N] {
188                let ($($I,)*) = self;
189                [$($I.into_binding(), )*]
190            }
191        }
192    }
193}
194
195all_tuples_with_size!(impl_to_binding_slice, 1, 32, T, s);
196
197pub trait IntoIndexedBindingArray<'b, const N: usize> {
198    fn into_array(self) -> [(u32, BindingResource<'b>); N];
199}
200
201macro_rules! impl_to_indexed_binding_slice {
202    ($N: expr, $(($T: ident, $S: ident, $I: ident)),*) => {
203        impl<'b, $($T: IntoBinding<'b>),*> IntoIndexedBindingArray<'b, $N> for ($((u32, $T),)*) {
204            #[inline]
205            fn into_array(self) -> [(u32, BindingResource<'b>); $N] {
206                let ($(($S, $I),)*) = self;
207                [$(($S, $I.into_binding())), *]
208            }
209        }
210    }
211}
212
213all_tuples_with_size!(impl_to_indexed_binding_slice, 1, 32, T, n, s);
214
215pub struct DynamicBindGroupEntries<'b> {
216    entries: Vec<BindGroupEntry<'b>>,
217}
218
219impl<'b> DynamicBindGroupEntries<'b> {
220    pub fn sequential<const N: usize>(entries: impl IntoBindingArray<'b, N>) -> Self {
221        Self {
222            entries: entries
223                .into_array()
224                .into_iter()
225                .enumerate()
226                .map(|(ix, resource)| BindGroupEntry {
227                    binding: ix as u32,
228                    resource,
229                })
230                .collect(),
231        }
232    }
233
234    pub fn extend_sequential<const N: usize>(
235        mut self,
236        entries: impl IntoBindingArray<'b, N>,
237    ) -> Self {
238        let start = self.entries.last().unwrap().binding + 1;
239        self.entries.extend(
240            entries
241                .into_array()
242                .into_iter()
243                .enumerate()
244                .map(|(ix, resource)| BindGroupEntry {
245                    binding: start + ix as u32,
246                    resource,
247                }),
248        );
249        self
250    }
251
252    pub fn new_with_indices<const N: usize>(entries: impl IntoIndexedBindingArray<'b, N>) -> Self {
253        Self {
254            entries: entries
255                .into_array()
256                .into_iter()
257                .map(|(binding, resource)| BindGroupEntry { binding, resource })
258                .collect(),
259        }
260    }
261
262    pub fn extend_with_indices<const N: usize>(
263        mut self,
264        entries: impl IntoIndexedBindingArray<'b, N>,
265    ) -> Self {
266        self.entries.extend(
267            entries
268                .into_array()
269                .into_iter()
270                .map(|(binding, resource)| BindGroupEntry { binding, resource }),
271        );
272        self
273    }
274}
275
276impl<'b> std::ops::Deref for DynamicBindGroupEntries<'b> {
277    type Target = [BindGroupEntry<'b>];
278
279    fn deref(&self) -> &[BindGroupEntry<'b>] {
280        &self.entries
281    }
282}