1use std::{
2 marker::PhantomData,
3 ops::Deref,
4};
5
6
7#[macro_export]
27macro_rules! bind_group {
28 { @len } => {
29 0
30 };
31 { @len $last:tt } => {
32 $last + 1
33 };
34 { @len $first:tt $( $rest:tt )+ } => {
35 $crate::bind_group! { @len $( $rest )+ }
36 };
37
38 { @bufferout $ty:ty } => {
39 $ty
40 };
41 { @bufferout $out:ty as $in:ty } => {
42 $out
43 };
44
45 { @bufferin $ty:ty } => {
46 $ty
47 };
48 { @bufferin $out:ty as $in:ty } => {
49 $in
50 };
51
52 { $struct:ident [
53 $( $num:tt $name:ident @ $( $shaderstage:ident )|+ => $buffer:ty $( as $bufferinner:ty )? ),* $(,)?
54 ] } => {
55 pub struct $struct {
56 bind_group: $crate::wgpu::BindGroup,
57 $( pub $name : $crate::bind_group! { @bufferout $buffer $( as $bufferinner )? } , )*
58 }
59
60 impl ::std::ops::Deref for $struct {
61 type Target = $crate::wgpu::BindGroup;
62 fn deref(&self) -> &Self::Target {
63 &self.bind_group
64 }
65 }
66
67 impl $crate::bindgroup::MewBindGroup for $struct {
68 type BufferSet = ( $( $crate::bind_group! { @bufferout $buffer $( as $bufferinner)? } , )* );
69 type BufferArray<T> = [T; $crate::bind_group! { @len $( $num )* }];
70
71 fn new(bind_group: $crate::wgpu::BindGroup, buffers: Self::BufferSet) -> Self {
72 Self {
73 bind_group,
74 $( $name : buffers.$num , )*
75 }
76 }
77
78 fn layout_entries() -> &'static Self::BufferArray<$crate::wgpu::BindGroupLayoutEntry> {
79 use ::std::sync::LazyLock;
80
81 static ARRAY: LazyLock<<$struct as $crate::bindgroup::MewBindGroup>::BufferArray<$crate::wgpu::BindGroupLayoutEntry>> = LazyLock::new(|| [ $(
82 $crate::wgpu::BindGroupLayoutEntry {
83 binding: $num,
84 visibility: $( $crate::wgpu::ShaderStages::$shaderstage )|+,
85 ty: <$crate::bind_group! { @bufferin $buffer $( as $bufferinner )? }>::binding_type(),
86 count: None,
87 },
88 )* ]);
89
90 &*ARRAY
91 }
92
93 fn layout_desc() -> $crate::wgpu::BindGroupLayoutDescriptor<'static> {
94 $crate::wgpu::BindGroupLayoutDescriptor {
95 label: Some(concat!(stringify!($struct), " Layout Descriptor")),
96 entries: Self::layout_entries(),
97 }
98 }
99
100 fn layout_desc_with(entries: &Self::BufferArray<$crate::wgpu::BindGroupLayoutEntry>) -> $crate::wgpu::BindGroupLayoutDescriptor {
101 $crate::wgpu::BindGroupLayoutDescriptor {
102 label: Some(concat!(stringify!($struct), " Layout Descriptor")),
103 entries,
104 }
105 }
106
107 fn bind_group_entries(buffers: &Self::BufferSet) -> Self::BufferArray<$crate::wgpu::BindGroupEntry> {
108 [ $(
109 $crate::wgpu::BindGroupEntry {
110 binding: $num,
111 resource: buffers.$num.as_binding(),
112 },
113 )* ]
114 }
115
116 fn bind_group_desc<'a>(layout: &'a $crate::bindgroup::MewBindGroupLayout<Self>, entries: &'a Self::BufferArray<$crate::wgpu::BindGroupEntry>) -> $crate::wgpu::BindGroupDescriptor<'a> {
117 $crate::wgpu::BindGroupDescriptor {
118 label: Some(stringify!($struct)),
119 layout,
120 entries,
121 }
122 }
123 }
124 };
125}
126pub use bind_group;
127
128
129pub trait MewBindGroup {
138 type BufferSet;
140 type BufferArray<T>;
141
142 fn new(bind_group: wgpu::BindGroup, buffers: Self::BufferSet) -> Self;
143 fn layout_entries() -> &'static Self::BufferArray<wgpu::BindGroupLayoutEntry>;
144 fn layout_desc_with<'a>(entries: &'a Self::BufferArray<wgpu::BindGroupLayoutEntry>) -> wgpu::BindGroupLayoutDescriptor<'a>;
145 fn layout_desc() -> wgpu::BindGroupLayoutDescriptor<'static>;
146 fn bind_group_entries(buffers: &Self::BufferSet) -> Self::BufferArray<wgpu::BindGroupEntry>;
147 fn bind_group_desc<'a>(layout: &'a MewBindGroupLayout<Self>, entries: &'a Self::BufferArray<wgpu::BindGroupEntry>) -> wgpu::BindGroupDescriptor<'a>;
148}
149
150
151pub struct MewBindGroupLayout<BIND: ?Sized> {
154 layout: wgpu::BindGroupLayout,
155 _marker: PhantomData<BIND>,
156}
157impl<BIND: ?Sized> Deref for MewBindGroupLayout<BIND> {
158 type Target = wgpu::BindGroupLayout;
159 fn deref(&self) -> &Self::Target {
160 &self.layout
161 }
162}
163impl<BIND> MewBindGroupLayout<BIND> {
164 pub fn new(layout: wgpu::BindGroupLayout) -> Self {
166 Self {
167 layout,
168 _marker: PhantomData,
169 }
170 }
171}