@@ -11,13 +11,15 @@ use syn::{
11
11
const UNIFORM_ATTRIBUTE_NAME : Symbol = Symbol ( "uniform" ) ;
12
12
const TEXTURE_ATTRIBUTE_NAME : Symbol = Symbol ( "texture" ) ;
13
13
const SAMPLER_ATTRIBUTE_NAME : Symbol = Symbol ( "sampler" ) ;
14
+ const STORAGE_ATTRIBUTE_NAME : Symbol = Symbol ( "storage" ) ;
14
15
const BIND_GROUP_DATA_ATTRIBUTE_NAME : Symbol = Symbol ( "bind_group_data" ) ;
15
16
16
17
#[ derive( Copy , Clone , Debug ) ]
17
18
enum BindingType {
18
19
Uniform ,
19
20
Texture ,
20
21
Sampler ,
22
+ Storage ,
21
23
}
22
24
23
25
#[ derive( Clone ) ]
@@ -55,7 +57,6 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
55
57
}
56
58
} else if attr_ident == UNIFORM_ATTRIBUTE_NAME {
57
59
let ( binding_index, converted_shader_type) = get_uniform_binding_attr ( attr) ?;
58
-
59
60
binding_impls. push ( quote ! { {
60
61
use #render_path:: render_resource:: AsBindGroupShaderType ;
61
62
let mut buffer = #render_path:: render_resource:: encase:: UniformBuffer :: new( Vec :: new( ) ) ;
@@ -126,6 +127,8 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
126
127
BindingType :: Texture
127
128
} else if attr_ident == SAMPLER_ATTRIBUTE_NAME {
128
129
BindingType :: Sampler
130
+ } else if attr_ident == STORAGE_ATTRIBUTE_NAME {
131
+ BindingType :: Storage
129
132
} else {
130
133
continue ;
131
134
} ;
@@ -190,7 +193,45 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
190
193
}
191
194
192
195
match binding_type {
193
- BindingType :: Uniform => { /* uniform codegen is deferred to account for combined uniform bindings */
196
+ BindingType :: Uniform => {
197
+ // uniform codegen is deferred to account for combined uniform bindings
198
+ }
199
+ BindingType :: Storage => {
200
+ let StorageAttrs {
201
+ visibility,
202
+ read_only,
203
+ } = get_storage_binding_attr ( nested_meta_items) ?;
204
+ let visibility =
205
+ visibility. hygenic_quote ( & quote ! { #render_path:: render_resource } ) ;
206
+
207
+ let field_name = field. ident . as_ref ( ) . unwrap ( ) ;
208
+ let field_ty = & field. ty ;
209
+
210
+ binding_impls. push ( quote ! { {
211
+ use #render_path:: render_resource:: AsBindGroupShaderType ;
212
+ let mut buffer = #render_path:: render_resource:: encase:: StorageBuffer :: new( Vec :: new( ) ) ;
213
+ buffer. write( & self . #field_name) . unwrap( ) ;
214
+ #render_path:: render_resource:: OwnedBindingResource :: Buffer ( render_device. create_buffer_with_data(
215
+ & #render_path:: render_resource:: BufferInitDescriptor {
216
+ label: None ,
217
+ usage: #render_path:: render_resource:: BufferUsages :: COPY_DST | #render_path:: render_resource:: BufferUsages :: STORAGE ,
218
+ contents: buffer. as_ref( ) ,
219
+ } ,
220
+ ) )
221
+ } } ) ;
222
+
223
+ binding_layouts. push ( quote ! {
224
+ #render_path:: render_resource:: BindGroupLayoutEntry {
225
+ binding: #binding_index,
226
+ visibility: #visibility,
227
+ ty: #render_path:: render_resource:: BindingType :: Buffer {
228
+ ty: #render_path:: render_resource:: BufferBindingType :: Storage { read_only: #read_only } ,
229
+ has_dynamic_offset: false ,
230
+ min_binding_size: Some ( <#field_ty as #render_path:: render_resource:: ShaderType >:: min_size( ) ) ,
231
+ } ,
232
+ count: None ,
233
+ }
234
+ } ) ;
194
235
}
195
236
BindingType :: Texture => {
196
237
let TextureAttrs {
@@ -861,3 +902,40 @@ fn get_sampler_binding_type_value(lit_str: &LitStr) -> Result<SamplerBindingType
861
902
) ) ,
862
903
}
863
904
}
905
+
906
+ #[ derive( Default ) ]
907
+ struct StorageAttrs {
908
+ visibility : ShaderStageVisibility ,
909
+ read_only : bool ,
910
+ }
911
+
912
+ const READ_ONLY : Symbol = Symbol ( "read_only" ) ;
913
+
914
+ fn get_storage_binding_attr ( metas : Vec < NestedMeta > ) -> Result < StorageAttrs > {
915
+ let mut visibility = ShaderStageVisibility :: vertex_fragment ( ) ;
916
+ let mut read_only = false ;
917
+
918
+ for meta in metas {
919
+ use syn:: { Meta :: List , Meta :: Path , NestedMeta :: Meta } ;
920
+ match meta {
921
+ // Parse #[storage(0, visibility(...))].
922
+ Meta ( List ( m) ) if m. path == VISIBILITY => {
923
+ visibility = get_visibility_flag_value ( & m. nested ) ?;
924
+ }
925
+ Meta ( Path ( path) ) if path == READ_ONLY => {
926
+ read_only = true ;
927
+ }
928
+ _ => {
929
+ return Err ( Error :: new_spanned (
930
+ meta,
931
+ "Not a valid attribute. Available attributes: `read_only`, `visibility`" ,
932
+ ) ) ;
933
+ }
934
+ }
935
+ }
936
+
937
+ Ok ( StorageAttrs {
938
+ visibility,
939
+ read_only,
940
+ } )
941
+ }
0 commit comments