@@ -11,6 +11,7 @@ use syn::{
11
11
12
12
const UNIFORM_ATTRIBUTE_NAME : Symbol = Symbol ( "uniform" ) ;
13
13
const TEXTURE_ATTRIBUTE_NAME : Symbol = Symbol ( "texture" ) ;
14
+ const STORAGE_TEXTURE_ATTRIBUTE_NAME : Symbol = Symbol ( "storage_texture" ) ;
14
15
const SAMPLER_ATTRIBUTE_NAME : Symbol = Symbol ( "sampler" ) ;
15
16
const STORAGE_ATTRIBUTE_NAME : Symbol = Symbol ( "storage" ) ;
16
17
const BIND_GROUP_DATA_ATTRIBUTE_NAME : Symbol = Symbol ( "bind_group_data" ) ;
@@ -19,6 +20,7 @@ const BIND_GROUP_DATA_ATTRIBUTE_NAME: Symbol = Symbol("bind_group_data");
19
20
enum BindingType {
20
21
Uniform ,
21
22
Texture ,
23
+ StorageTexture ,
22
24
Sampler ,
23
25
Storage ,
24
26
}
@@ -133,6 +135,8 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
133
135
BindingType :: Uniform
134
136
} else if attr_ident == TEXTURE_ATTRIBUTE_NAME {
135
137
BindingType :: Texture
138
+ } else if attr_ident == STORAGE_TEXTURE_ATTRIBUTE_NAME {
139
+ BindingType :: StorageTexture
136
140
} else if attr_ident == SAMPLER_ATTRIBUTE_NAME {
137
141
BindingType :: Sampler
138
142
} else if attr_ident == STORAGE_ATTRIBUTE_NAME {
@@ -255,6 +259,45 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
255
259
}
256
260
} ) ;
257
261
}
262
+ BindingType :: StorageTexture => {
263
+ let StorageTextureAttrs {
264
+ dimension,
265
+ image_format,
266
+ access,
267
+ visibility,
268
+ } = get_storage_texture_binding_attr ( nested_meta_items) ?;
269
+
270
+ let visibility =
271
+ visibility. hygienic_quote ( & quote ! { #render_path:: render_resource } ) ;
272
+
273
+ let fallback_image = get_fallback_image ( & render_path, dimension) ;
274
+
275
+ binding_impls. push ( quote ! {
276
+ ( #binding_index,
277
+ #render_path:: render_resource:: OwnedBindingResource :: TextureView ( {
278
+ let handle: Option <& #asset_path:: Handle <#render_path:: texture:: Image >> = ( & self . #field_name) . into( ) ;
279
+ if let Some ( handle) = handle {
280
+ images. get( handle) . ok_or_else( || #render_path:: render_resource:: AsBindGroupError :: RetryNextUpdate ) ?. texture_view. clone( )
281
+ } else {
282
+ #fallback_image. texture_view. clone( )
283
+ }
284
+ } )
285
+ )
286
+ } ) ;
287
+
288
+ binding_layouts. push ( quote ! {
289
+ #render_path:: render_resource:: BindGroupLayoutEntry {
290
+ binding: #binding_index,
291
+ visibility: #visibility,
292
+ ty: #render_path:: render_resource:: BindingType :: StorageTexture {
293
+ access: #render_path:: render_resource:: StorageTextureAccess :: #access,
294
+ format: #render_path:: render_resource:: TextureFormat :: #image_format,
295
+ view_dimension: #render_path:: render_resource:: #dimension,
296
+ } ,
297
+ count: None ,
298
+ }
299
+ } ) ;
300
+ }
258
301
BindingType :: Texture => {
259
302
let TextureAttrs {
260
303
dimension,
@@ -585,6 +628,10 @@ impl ShaderStageVisibility {
585
628
fn vertex_fragment ( ) -> Self {
586
629
Self :: Flags ( VisibilityFlags :: vertex_fragment ( ) )
587
630
}
631
+
632
+ fn compute ( ) -> Self {
633
+ Self :: Flags ( VisibilityFlags :: compute ( ) )
634
+ }
588
635
}
589
636
590
637
impl VisibilityFlags {
@@ -595,6 +642,13 @@ impl VisibilityFlags {
595
642
..Default :: default ( )
596
643
}
597
644
}
645
+
646
+ fn compute ( ) -> Self {
647
+ Self {
648
+ compute : true ,
649
+ ..Default :: default ( )
650
+ }
651
+ }
598
652
}
599
653
600
654
impl ShaderStageVisibility {
@@ -741,7 +795,72 @@ impl Default for TextureAttrs {
741
795
}
742
796
}
743
797
798
+ struct StorageTextureAttrs {
799
+ dimension : BindingTextureDimension ,
800
+ // Parsing of the image_format parameter is deferred to the type checker,
801
+ // which will error if the format is not member of the TextureFormat enum.
802
+ image_format : proc_macro2:: TokenStream ,
803
+ // Parsing of the access parameter is deferred to the type checker,
804
+ // which will error if the access is not member of the StorageTextureAccess enum.
805
+ access : proc_macro2:: TokenStream ,
806
+ visibility : ShaderStageVisibility ,
807
+ }
808
+
809
+ impl Default for StorageTextureAttrs {
810
+ fn default ( ) -> Self {
811
+ Self {
812
+ dimension : Default :: default ( ) ,
813
+ image_format : quote ! { Rgba8Unorm } ,
814
+ access : quote ! { ReadWrite } ,
815
+ visibility : ShaderStageVisibility :: compute ( ) ,
816
+ }
817
+ }
818
+ }
819
+
820
+ fn get_storage_texture_binding_attr ( metas : Vec < Meta > ) -> Result < StorageTextureAttrs > {
821
+ let mut storage_texture_attrs = StorageTextureAttrs :: default ( ) ;
822
+
823
+ for meta in metas {
824
+ use syn:: Meta :: { List , NameValue } ;
825
+ match meta {
826
+ // Parse #[storage_texture(0, dimension = "...")].
827
+ NameValue ( m) if m. path == DIMENSION => {
828
+ let value = get_lit_str ( DIMENSION , & m. value ) ?;
829
+ storage_texture_attrs. dimension = get_texture_dimension_value ( value) ?;
830
+ }
831
+ // Parse #[storage_texture(0, format = ...))].
832
+ NameValue ( m) if m. path == IMAGE_FORMAT => {
833
+ storage_texture_attrs. image_format = m. value . into_token_stream ( ) ;
834
+ }
835
+ // Parse #[storage_texture(0, access = ...))].
836
+ NameValue ( m) if m. path == ACCESS => {
837
+ storage_texture_attrs. access = m. value . into_token_stream ( ) ;
838
+ }
839
+ // Parse #[storage_texture(0, visibility(...))].
840
+ List ( m) if m. path == VISIBILITY => {
841
+ storage_texture_attrs. visibility = get_visibility_flag_value ( & m) ?;
842
+ }
843
+ NameValue ( m) => {
844
+ return Err ( Error :: new_spanned (
845
+ m. path ,
846
+ "Not a valid name. Available attributes: `dimension`, `image_format`, `access`." ,
847
+ ) ) ;
848
+ }
849
+ _ => {
850
+ return Err ( Error :: new_spanned (
851
+ meta,
852
+ "Not a name value pair: `foo = \" ...\" `" ,
853
+ ) ) ;
854
+ }
855
+ }
856
+ }
857
+
858
+ Ok ( storage_texture_attrs)
859
+ }
860
+
744
861
const DIMENSION : Symbol = Symbol ( "dimension" ) ;
862
+ const IMAGE_FORMAT : Symbol = Symbol ( "image_format" ) ;
863
+ const ACCESS : Symbol = Symbol ( "access" ) ;
745
864
const SAMPLE_TYPE : Symbol = Symbol ( "sample_type" ) ;
746
865
const FILTERABLE : Symbol = Symbol ( "filterable" ) ;
747
866
const MULTISAMPLED : Symbol = Symbol ( "multisampled" ) ;
0 commit comments