mew/bindgroup.rs
1use std::{
2 marker::PhantomData,
3 ops::Deref,
4};
5
6
7/// Define a bind group, with internal buffer types (and their field names), and
8/// their shader visibility (see
9/// [`wgpu::ShaderStages`](https://docs.rs/wgpu/latest/wgpu/struct.ShaderStages.html)).
10/// All members are taken ownership of in the struct - good to note that they
11/// are reference-counted (`Arc`'d) by *wgpu* internally.
12///
13/// You need to number each field, tuples are used and counting is hard in
14/// macros.
15///
16/// ```
17/// bind_group! { StuffBindGroup [
18/// 0 matrix_buffer @ VERTEX | COMPUTE => MatrixBuffer,
19/// 1 something_else_buffer @ FRAGMENT => SomethingElseBuffer,
20/// 2 another_matrix_buffer @ VERTEX_FRAGMENT => MatrixBuffer,
21/// ] }
22///
23/// // TODO: Create buffers (see buffer docs)
24/// let bind_group: StuffBindGroup = render_context.new_bind_group((matrix_buffer, ..));
25///
26/// queue.write_buffer(&bind_group.something_else_buffer, 0, &[1, 2, 3, ..]);
27/// ```
28#[macro_export]
29macro_rules! bind_group {
30 /*
31 { @bufferout $ty:ty } => {
32 $ty
33 };
34 { @bufferout $out:ty as $in:ty } => {
35 $out
36 };
37
38 { @bufferin $ty:ty } => {
39 $ty
40 };
41 { @bufferin $out:ty as $in:ty } => {
42 $in
43 };
44 */
45
46 { $struct:ident [
47 $( $num:tt $name:ident @ $( $shaderstage:ident )|+ => $buffer:ty /* $( as $bufferinner:ty )? */ ),* $(,)?
48 ] } => {
49 #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
50 pub struct $struct {
51 bind_group: $crate::wgpu::BindGroup,
52 //$( pub $name : $crate::bind_group! { @bufferout $buffer $( as $bufferinner )? } , )*
53 $( pub $name : $buffer , )*
54 }
55
56 impl ::std::ops::Deref for $struct {
57 type Target = $crate::wgpu::BindGroup;
58 fn deref(&self) -> &Self::Target {
59 &self.bind_group
60 }
61 }
62
63 impl $crate::bindgroup::MewBindGroup for $struct {
64 //type BufferSet = ( $( $crate::bind_group! { @bufferout $buffer $( as $bufferinner)? } , )* );
65 type BufferSet = ( $( $buffer , )* );
66 type BufferArray<T> = [T; $crate::len! { $( $num )* }];
67
68 fn new(bind_group: $crate::wgpu::BindGroup, buffers: Self::BufferSet) -> Self {
69 Self {
70 bind_group,
71 $( $name : buffers.$num , )*
72 }
73 }
74
75 fn layout_entries() -> &'static Self::BufferArray<$crate::wgpu::BindGroupLayoutEntry> {
76 use ::std::sync::LazyLock;
77 #[allow(unused_imports)]
78 use $crate::{
79 buffer::{ MewBuffer, MewBufferBinding, },
80 sampler::MewSampler,
81 texture::MewTexture,
82 };
83
84 static ARRAY: LazyLock<<$struct as $crate::bindgroup::MewBindGroup>::BufferArray<$crate::wgpu::BindGroupLayoutEntry>> = LazyLock::new(|| [ $(
85 $crate::wgpu::BindGroupLayoutEntry {
86 binding: $num,
87 visibility: $( $crate::wgpu::ShaderStages::$shaderstage )|+,
88 //ty: <$crate::bind_group! { @bufferin $buffer $( as $bufferinner )? }>::binding_type(),
89 ty: <$buffer>::binding_type(),
90 count: None,
91 },
92 )* ]);
93
94 &*ARRAY
95 }
96
97 fn layout_desc() -> $crate::wgpu::BindGroupLayoutDescriptor<'static> {
98 $crate::wgpu::BindGroupLayoutDescriptor {
99 label: Some(concat!(stringify!($struct), " Layout Descriptor")),
100 entries: Self::layout_entries(),
101 }
102 }
103
104 /*
105 fn layout_desc_with(entries: &Self::BufferArray<$crate::wgpu::BindGroupLayoutEntry>) -> $crate::wgpu::BindGroupLayoutDescriptor<'_> {
106 $crate::wgpu::BindGroupLayoutDescriptor {
107 label: Some(concat!(stringify!($struct), " Layout Descriptor")),
108 entries,
109 }
110 }
111 */
112
113 fn bind_group_entries(buffers: &Self::BufferSet) -> Self::BufferArray<$crate::wgpu::BindGroupEntry<'_>> {
114 #[allow(unused_imports)]
115 use $crate::{
116 buffer::{ MewBuffer, MewBufferBinding, },
117 sampler::MewSampler,
118 texture::MewTexture,
119 };
120
121 [ $(
122 $crate::wgpu::BindGroupEntry {
123 binding: $num,
124 resource: buffers.$num.as_binding(),
125 },
126 )* ]
127 }
128
129 fn bind_group_desc<'a>(layout: &'a $crate::bindgroup::MewBindGroupLayout<Self>, entries: &'a Self::BufferArray<$crate::wgpu::BindGroupEntry>) -> $crate::wgpu::BindGroupDescriptor<'a> {
130 $crate::wgpu::BindGroupDescriptor {
131 label: Some(stringify!($struct)),
132 layout,
133 entries,
134 }
135 }
136 }
137 };
138}
139pub use bind_group;
140
141
142/// Trait for internal use to work with bind groups - getting their layouts and
143/// descriptors and whatnot.
144///
145/// The number of internal buffers must be defined in the generic parameter,
146/// because associated `const`s are "uNsTAbLe", apparently.
147pub trait MewBindGroup {
148 /// A tuple of all the bind group's internal buffers.
149 type BufferSet;
150 /// A generic array the length of the number of buffers (literally `[T; N]`).
151 type BufferArray<T>;
152 /// Build this bind group type from a
153 /// [`wgpu::BindGroup`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroup.html)
154 /// and all its internal buffers in a tuple.
155 ///
156 /// Technically the buffers don't need to be stored with the bind group they're
157 /// used in - or at all, it should even be safe to drop them as they'll be kept
158 /// around on the GPU side - but as an abstraction, they exist as members of the
159 /// bind group.
160 fn new(bind_group: wgpu::BindGroup, buffers: Self::BufferSet) -> Self;
161 /// Get an array of
162 /// [`wgpu::BindGroupLayoutEntry`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupLayoutEntry.html)s
163 /// for all internal buffers.
164 fn layout_entries() -> &'static Self::BufferArray<wgpu::BindGroupLayoutEntry>;
165 /// Get a
166 /// [`wgpu::BindGroupLayoutDescriptor`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupLayoutDescriptor.html)
167 /// to build this type of bind group.
168 fn layout_desc() -> wgpu::BindGroupLayoutDescriptor<'static>;
169 /*
170 /// Get a layout descriptor using dynamic layout entries (not recommended, I
171 /// forgor why I put this in).
172 fn layout_desc_with<'a>(entries: &'a Self::BufferArray<wgpu::BindGroupLayoutEntry>) -> wgpu::BindGroupLayoutDescriptor<'a>;
173 */
174 /// Get an array of
175 /// [`wgpu::BindGroupEntry`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupEntry.html)s,
176 /// for use with [`Self::bind_group_desc`].
177 ///
178 /// Necessary to put this in a separate function to keep the borrow checker
179 /// happy - _wgpu_ needs a reference to owned entries, which we can't return
180 /// in a struct later.
181 fn bind_group_entries(buffers: &Self::BufferSet) -> Self::BufferArray<wgpu::BindGroupEntry<'_>>;
182 /// Get a
183 /// [`wgpu::BindGroupDescriptor`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupDescriptor.html)
184 /// to build this bind group, using its layout and a reference to its
185 /// [`wgpu::BindGroupEntry`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupEntry.html)s
186 /// from [`Self::bind_group_entries`].
187 fn bind_group_desc<'a>(layout: &'a MewBindGroupLayout<Self>, entries: &'a Self::BufferArray<wgpu::BindGroupEntry<'_>>) -> wgpu::BindGroupDescriptor<'a>;
188
189 //fn dyn_descriptor() -> Box<dyn MewBindGroupDescriptor>;
190}
191
192/*
193pub trait MewBindGroupDescriptor {
194 fn type_id(&self) -> TypeId;
195 fn layout_desc(&self) -> wgpu::BindGroupLayoutDescriptor<'static>;
196}
197*/
198
199
200/// Wrapper for the layout of some bind group, so that the compiler will scream
201/// at you if you mix up layouts.
202pub struct MewBindGroupLayout<BIND: ?Sized> {
203 layout: wgpu::BindGroupLayout,
204 _marker: PhantomData<BIND>,
205}
206impl<BIND: ?Sized> Deref for MewBindGroupLayout<BIND> {
207 type Target = wgpu::BindGroupLayout;
208 fn deref(&self) -> &Self::Target {
209 &self.layout
210 }
211}
212impl<BIND> MewBindGroupLayout<BIND> {
213 /// Wrap a
214 /// [`wgpu::BindGroupLayout`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupLayout.html).
215 pub fn new(layout: wgpu::BindGroupLayout) -> Self {
216 Self {
217 layout,
218 _marker: PhantomData,
219 }
220 }
221}