diff --git a/crates/bevy_render/macros/src/as_bind_group.rs b/crates/bevy_render/macros/src/as_bind_group.rs index 5c24c608ea05b..06f58aea2db88 100644 --- a/crates/bevy_render/macros/src/as_bind_group.rs +++ b/crates/bevy_render/macros/src/as_bind_group.rs @@ -6,7 +6,7 @@ use syn::{ parse::{Parse, ParseStream}, punctuated::Punctuated, token::Comma, - Data, DataStruct, Error, Fields, LitInt, LitStr, Meta, Result, + Data, DataStruct, Error, Fields, LitInt, LitStr, Meta, MetaList, Result, }; const UNIFORM_ATTRIBUTE_NAME: Symbol = Symbol("uniform"); @@ -636,39 +636,46 @@ const VISIBILITY_COMPUTE: Symbol = Symbol("compute"); const VISIBILITY_ALL: Symbol = Symbol("all"); const VISIBILITY_NONE: Symbol = Symbol("none"); -fn get_visibility_flag_value(meta: Meta) -> Result { - let mut visibility = VisibilityFlags::vertex_fragment(); +fn get_visibility_flag_value(meta_list: &MetaList) -> Result { + let mut flags = Vec::new(); - use syn::Meta::Path; - match meta { - // Parse `#[visibility(all)]`. - Path(path) if path == VISIBILITY_ALL => { - return Ok(ShaderStageVisibility::All) - } - // Parse `#[visibility(none)]`. - Path(path) if path == VISIBILITY_NONE => { - return Ok(ShaderStageVisibility::None) + meta_list.parse_nested_meta(|meta| { + flags.push(meta.path); + Ok(()) + })?; + + if flags.is_empty() { + return Err(Error::new_spanned( + meta_list, + "Invalid visibility format. Must be `visibility(flags)`, flags can be `all`, `none`, or a list-combination of `vertex`, `fragment` and/or `compute`." + )); + } + + if flags.len() == 1 { + if let Some(flag) = flags.get(0) { + if flag == VISIBILITY_ALL { + return Ok(ShaderStageVisibility::All); + } else if flag == VISIBILITY_NONE { + return Ok(ShaderStageVisibility::None); + } } - // Parse `#[visibility(vertex, ...)]`. - Path(path) if path == VISIBILITY_VERTEX => { + } + + let mut visibility = VisibilityFlags::default(); + + for flag in flags { + if flag == VISIBILITY_VERTEX { visibility.vertex = true; - } - // Parse `#[visibility(fragment, ...)]`. - Path(path) if path == VISIBILITY_FRAGMENT => { + } else if flag == VISIBILITY_FRAGMENT { visibility.fragment = true; - } - // Parse `#[visibility(compute, ...)]`. - Path(path) if path == VISIBILITY_COMPUTE => { + } else if flag == VISIBILITY_COMPUTE { visibility.compute = true; + } else { + return Err(Error::new_spanned( + flag, + "Not a valid visibility flag. Must be `all`, `none`, or a list-combination of `vertex`, `fragment` and/or `compute`." + )); } - Path(path) => return Err(Error::new_spanned( - path, - "Not a valid visibility flag. Must be `all`, `none`, or a list-combination of `vertex`, `fragment` and/or `compute`." - )), - _ => return Err(Error::new_spanned( - meta, - "Invalid visibility format: `visibility(...)`.", - )), } Ok(ShaderStageVisibility::Flags(visibility)) @@ -794,7 +801,7 @@ fn get_texture_attrs(metas: Vec) -> Result { } // Parse #[texture(0, visibility(...))]. List(m) if m.path == VISIBILITY => { - visibility = get_visibility_flag_value(Meta::Path(m.path))?; + visibility = get_visibility_flag_value(&m)?; } NameValue(m) => { return Err(Error::new_spanned( @@ -910,7 +917,7 @@ fn get_sampler_attrs(metas: Vec) -> Result { } // Parse #[sampler(0, visibility(...))]. List(m) if m.path == VISIBILITY => { - visibility = get_visibility_flag_value(Meta::Path(m.path))?; + visibility = get_visibility_flag_value(&m)?; } NameValue(m) => { return Err(Error::new_spanned( @@ -966,7 +973,7 @@ fn get_storage_binding_attr(metas: Vec) -> Result { match meta { // Parse #[storage(0, visibility(...))]. List(m) if m.path == VISIBILITY => { - visibility = get_visibility_flag_value(Meta::Path(m.path))?; + visibility = get_visibility_flag_value(&m)?; } Path(path) if path == READ_ONLY => { read_only = true; diff --git a/crates/bevy_render/src/render_resource/bind_group.rs b/crates/bevy_render/src/render_resource/bind_group.rs index 15d87a969f2f6..47c893da28551 100644 --- a/crates/bevy_render/src/render_resource/bind_group.rs +++ b/crates/bevy_render/src/render_resource/bind_group.rs @@ -334,3 +334,35 @@ where self.into() } } + +#[cfg(test)] +mod test { + use super::*; + use crate as bevy_render; + use bevy_asset::Handle; + + #[test] + fn texture_visibility() { + #[derive(AsBindGroup)] + pub struct TextureVisibilityTest { + #[texture(0, visibility(all))] + pub all: Handle, + #[texture(1, visibility(none))] + pub none: Handle, + #[texture(2, visibility(fragment))] + pub fragment: Handle, + #[texture(3, visibility(vertex))] + pub vertex: Handle, + #[texture(4, visibility(compute))] + pub compute: Handle, + #[texture(5, visibility(vertex, fragment))] + pub vertex_fragment: Handle, + #[texture(6, visibility(vertex, compute))] + pub vertex_compute: Handle, + #[texture(7, visibility(fragment, compute))] + pub fragment_compute: Handle, + #[texture(8, visibility(vertex, fragment, compute))] + pub vertex_fragment_compute: Handle, + } + } +}