Skip to content

Commit

Permalink
Support raw buffers in AsBindGroup macro (bevyengine#7701)
Browse files Browse the repository at this point in the history
# Objective

There was PR that introduced support for storage buffer is `AsBindGroup` macro [bevyengine#6129](bevyengine#6129), but it does not give more granular control over storage buffer, it will always copy all the data no matter which part of it was updated. There is also currently another open PR bevyengine#6669 that tries to achieve exactly that, it is just not up to date and seems abandoned (Sorry if that is not right). In this PR I'm proposing a solution for both of these approaches to co-exist using `#[storage(n, buffer)]` and `#[storage(n)]` to distinguish between the cases.

We could also discuss in this PR if there is a need to extend this support to DynamicBuffers as well.
  • Loading branch information
Andrii Borziak authored and Shfty committed Mar 19, 2023
1 parent b69c0c1 commit 25399a1
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 13 deletions.
48 changes: 35 additions & 13 deletions crates/bevy_render/macros/src/as_bind_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,25 +200,40 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
let StorageAttrs {
visibility,
read_only,
buffer,
} = get_storage_binding_attr(nested_meta_items)?;
let visibility =
visibility.hygenic_quote(&quote! { #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(),
},
))
}});
let min_binding_size = if buffer {
quote! {None}
} else {
quote! {Some(<#field_ty as #render_path::render_resource::ShaderType>::min_size())}
};

if buffer {
binding_impls.push(quote! {
#render_path::render_resource::OwnedBindingResource::Buffer({
self.#field_name.clone()
})
});
} else {
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 {
Expand All @@ -227,7 +242,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
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()),
min_binding_size: #min_binding_size,
},
count: None,
}
Expand Down Expand Up @@ -907,13 +922,16 @@ fn get_sampler_binding_type_value(lit_str: &LitStr) -> Result<SamplerBindingType
struct StorageAttrs {
visibility: ShaderStageVisibility,
read_only: bool,
buffer: bool,
}

const READ_ONLY: Symbol = Symbol("read_only");
const BUFFER: Symbol = Symbol("buffer");

fn get_storage_binding_attr(metas: Vec<NestedMeta>) -> Result<StorageAttrs> {
let mut visibility = ShaderStageVisibility::vertex_fragment();
let mut read_only = false;
let mut buffer = false;

for meta in metas {
use syn::{Meta::List, Meta::Path, NestedMeta::Meta};
Expand All @@ -925,6 +943,9 @@ fn get_storage_binding_attr(metas: Vec<NestedMeta>) -> Result<StorageAttrs> {
Meta(Path(path)) if path == READ_ONLY => {
read_only = true;
}
Meta(Path(path)) if path == BUFFER => {
buffer = true;
}
_ => {
return Err(Error::new_spanned(
meta,
Expand All @@ -937,5 +958,6 @@ fn get_storage_binding_attr(metas: Vec<NestedMeta>) -> Result<StorageAttrs> {
Ok(StorageAttrs {
visibility,
read_only,
buffer,
})
}
2 changes: 2 additions & 0 deletions crates/bevy_render/src/render_resource/bind_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ impl Deref for BindGroup {
/// color_texture: Handle<Image>,
/// #[storage(3, read_only)]
/// values: Vec<f32>,
/// #[storage(4, read_only, buffer)]
/// buffer: Buffer,
/// }
/// ```
///
Expand Down

0 comments on commit 25399a1

Please sign in to comment.