From 30aae06bd6a927b1e6fed21cd0b7b16e8d252d80 Mon Sep 17 00:00:00 2001 From: IceSentry Date: Tue, 3 Jan 2023 13:56:39 -0500 Subject: [PATCH 1/2] add storage buffers support --- .../bevy_render/macros/src/as_bind_group.rs | 82 ++++++++++++++++++- crates/bevy_render/macros/src/lib.rs | 5 +- .../src/render_resource/bind_group.rs | 13 +++ 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/crates/bevy_render/macros/src/as_bind_group.rs b/crates/bevy_render/macros/src/as_bind_group.rs index bbc3c3850cf0b..ee8a048758d12 100644 --- a/crates/bevy_render/macros/src/as_bind_group.rs +++ b/crates/bevy_render/macros/src/as_bind_group.rs @@ -11,6 +11,7 @@ use syn::{ const UNIFORM_ATTRIBUTE_NAME: Symbol = Symbol("uniform"); const TEXTURE_ATTRIBUTE_NAME: Symbol = Symbol("texture"); const SAMPLER_ATTRIBUTE_NAME: Symbol = Symbol("sampler"); +const STORAGE_ATTRIBUTE_NAME: Symbol = Symbol("storage"); const BIND_GROUP_DATA_ATTRIBUTE_NAME: Symbol = Symbol("bind_group_data"); #[derive(Copy, Clone, Debug)] @@ -18,6 +19,7 @@ enum BindingType { Uniform, Texture, Sampler, + Storage, } #[derive(Clone)] @@ -55,7 +57,6 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { } } else if attr_ident == UNIFORM_ATTRIBUTE_NAME { let (binding_index, converted_shader_type) = get_uniform_binding_attr(attr)?; - binding_impls.push(quote! {{ use #render_path::render_resource::AsBindGroupShaderType; 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 { BindingType::Texture } else if attr_ident == SAMPLER_ATTRIBUTE_NAME { BindingType::Sampler + } else if attr_ident == STORAGE_ATTRIBUTE_NAME { + BindingType::Storage } else { continue; }; @@ -190,7 +193,45 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { } match binding_type { - BindingType::Uniform => { /* uniform codegen is deferred to account for combined uniform bindings */ + BindingType::Uniform => { + // uniform codegen is deferred to account for combined uniform bindings + } + BindingType::Storage => { + let StorageAttrs { + visibility, + read_only, + } = get_storage_binding_attr(nested_meta_items)?; + let visibility = + visibility.hygenic_quote("e! { #render_path::render_resource }); + + let field_name = field.ident.as_ref().unwrap(); + let field_ty = &field.ty; + + binding_impls.push(quote! {{ + use #render_path::render_resource::AsBindGroupShaderType; + let mut buffer = #render_path::render_resource::encase::StorageBuffer::new(Vec::new()); + buffer.write(&self.#field_name).unwrap(); + #render_path::render_resource::OwnedBindingResource::Buffer(render_device.create_buffer_with_data( + &#render_path::render_resource::BufferInitDescriptor { + label: None, + usage: #render_path::render_resource::BufferUsages::COPY_DST | #render_path::render_resource::BufferUsages::STORAGE, + contents: buffer.as_ref(), + }, + )) + }}); + + binding_layouts.push(quote! { + #render_path::render_resource::BindGroupLayoutEntry { + binding: #binding_index, + visibility: #visibility, + ty: #render_path::render_resource::BindingType::Buffer { + ty: #render_path::render_resource::BufferBindingType::Storage { read_only: #read_only }, + has_dynamic_offset: false, + min_binding_size: Some(<#field_ty as #render_path::render_resource::ShaderType>::min_size()), + }, + count: None, + } + }); } BindingType::Texture => { let TextureAttrs { @@ -861,3 +902,40 @@ fn get_sampler_binding_type_value(lit_str: &LitStr) -> Result) -> Result { + let mut visibility = ShaderStageVisibility::vertex_fragment(); + let mut read_only = false; + + for meta in metas { + use syn::{Meta::List, Meta::Path, NestedMeta::Meta}; + match meta { + // Parse #[storage(0, visibility(...))]. + Meta(List(m)) if m.path == VISIBILITY => { + visibility = get_visibility_flag_value(&m.nested)?; + } + Meta(Path(path)) if path == READ_ONLY => { + read_only = true; + } + _ => { + return Err(Error::new_spanned( + meta, + "Not a valid attribute. Available attributes: `read_only`, `visibility`", + )); + } + } + } + + Ok(StorageAttrs { + visibility, + read_only, + }) +} diff --git a/crates/bevy_render/macros/src/lib.rs b/crates/bevy_render/macros/src/lib.rs index 863b48baf5fa0..e8da33ad3c48b 100644 --- a/crates/bevy_render/macros/src/lib.rs +++ b/crates/bevy_render/macros/src/lib.rs @@ -17,7 +17,10 @@ pub fn derive_extract_resource(input: TokenStream) -> TokenStream { extract_resource::derive_extract_resource(input) } -#[proc_macro_derive(AsBindGroup, attributes(uniform, texture, sampler, bind_group_data))] +#[proc_macro_derive( + AsBindGroup, + attributes(uniform, texture, sampler, bind_group_data, storage) +)] pub fn derive_as_bind_group(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); diff --git a/crates/bevy_render/src/render_resource/bind_group.rs b/crates/bevy_render/src/render_resource/bind_group.rs index 5bc13b1d1f47a..6fe52324847fd 100644 --- a/crates/bevy_render/src/render_resource/bind_group.rs +++ b/crates/bevy_render/src/render_resource/bind_group.rs @@ -82,6 +82,8 @@ impl Deref for BindGroup { /// #[texture(1)] /// #[sampler(2)] /// color_texture: Handle, +/// #[storage(3, read_only)] +/// values: Vec, /// } /// ``` /// @@ -94,6 +96,8 @@ impl Deref for BindGroup { /// var color_texture: texture_2d; /// @group(1) @binding(2) /// var color_sampler: sampler; +/// @gropu(1) @binding(3) +/// var values: array; /// ``` /// Note that the "group" index is determined by the usage context. It is not defined in [`AsBindGroup`]. For example, in Bevy material bind groups /// are generally bound to group 1. @@ -132,6 +136,15 @@ impl Deref for BindGroup { /// | `sampler_type` = "..." | `"filtering"`, `"non_filtering"`, `"comparison"`. | `"filtering"` | /// | `visibility(...)` | `all`, `none`, or a list-combination of `vertex`, `fragment`, `compute` | `vertex`, `fragment` | /// +/// * `storage(BINDING_INDEX, arguments)` +/// * The field will be converted to a shader-compatible type using the [`ShaderType`] trait, written to a [`Buffer`], and bound as a storage buffer. +/// * It supports and optional `read_only` parameter. Defaults to false if not present. +/// +/// | Arguments | Values | Default | +/// |------------------------|-------------------------------------------------------------------------|----------------------| +/// | `visibility(...)` | `all`, `none`, or a list-combination of `vertex`, `fragment`, `compute` | `vertex`, `fragment` | +/// | `read_only` | if present then value is true, otherwise false | `false` | +/// /// Note that fields without field-level binding attributes will be ignored. /// ``` /// # use bevy_render::{color::Color, render_resource::AsBindGroup}; From ad3dca145d0a70b129811bd2c57b0fd0cedee368 Mon Sep 17 00:00:00 2001 From: IceSentry Date: Tue, 3 Jan 2023 16:22:24 -0500 Subject: [PATCH 2/2] Update crates/bevy_render/src/render_resource/bind_group.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François --- crates/bevy_render/src/render_resource/bind_group.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/render_resource/bind_group.rs b/crates/bevy_render/src/render_resource/bind_group.rs index 6fe52324847fd..46e30771b03bd 100644 --- a/crates/bevy_render/src/render_resource/bind_group.rs +++ b/crates/bevy_render/src/render_resource/bind_group.rs @@ -96,7 +96,7 @@ impl Deref for BindGroup { /// var color_texture: texture_2d; /// @group(1) @binding(2) /// var color_sampler: sampler; -/// @gropu(1) @binding(3) +/// @group(1) @binding(3) /// var values: array; /// ``` /// Note that the "group" index is determined by the usage context. It is not defined in [`AsBindGroup`]. For example, in Bevy material bind groups