Skip to main content

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}