Fix AsBindGroup derive, texture attribute, visibility flag parsing (#8868)

# Objective

- Fix the AsBindGroup texture attribute visibility flag parsing
- This appears to have been caused by a syn crate update which then the
visibility code got updated
- Also I noticed that by default the vertex and fragment flags were on,
so visibility(compute) would actually make the texture visible to
vertex, fragment and compute shaders, I fixed this too

## Solution

- Update flag parsing to use MetaList.parse_nested_meta function, which
loads the flags into a Vec then loop through those flags
- Change initial visibility flags to use VisibilityFlags::default()
rather than VisibilityFlags::vertex_fragment()
This commit is contained in:
loganbenjamin 2023-06-22 11:58:55 +12:00 committed by GitHub
parent c39e02cefb
commit ee1368a032
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 31 deletions

View File

@ -6,7 +6,7 @@ use syn::{
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
punctuated::Punctuated, punctuated::Punctuated,
token::Comma, 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"); 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_ALL: Symbol = Symbol("all");
const VISIBILITY_NONE: Symbol = Symbol("none"); const VISIBILITY_NONE: Symbol = Symbol("none");
fn get_visibility_flag_value(meta: Meta) -> Result<ShaderStageVisibility> { fn get_visibility_flag_value(meta_list: &MetaList) -> Result<ShaderStageVisibility> {
let mut visibility = VisibilityFlags::vertex_fragment(); let mut flags = Vec::new();
use syn::Meta::Path; meta_list.parse_nested_meta(|meta| {
match meta { flags.push(meta.path);
// Parse `#[visibility(all)]`. Ok(())
Path(path) if path == VISIBILITY_ALL => { })?;
return Ok(ShaderStageVisibility::All)
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`."
));
} }
// Parse `#[visibility(none)]`.
Path(path) if path == VISIBILITY_NONE => { if flags.len() == 1 {
return Ok(ShaderStageVisibility::None) 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; visibility.vertex = true;
} } else if flag == VISIBILITY_FRAGMENT {
// Parse `#[visibility(fragment, ...)]`.
Path(path) if path == VISIBILITY_FRAGMENT => {
visibility.fragment = true; visibility.fragment = true;
} } else if flag == VISIBILITY_COMPUTE {
// Parse `#[visibility(compute, ...)]`.
Path(path) if path == VISIBILITY_COMPUTE => {
visibility.compute = true; visibility.compute = true;
} } else {
Path(path) => return Err(Error::new_spanned( return Err(Error::new_spanned(
path, flag,
"Not a valid visibility flag. Must be `all`, `none`, or a list-combination of `vertex`, `fragment` and/or `compute`." "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)) Ok(ShaderStageVisibility::Flags(visibility))
@ -794,7 +801,7 @@ fn get_texture_attrs(metas: Vec<Meta>) -> Result<TextureAttrs> {
} }
// Parse #[texture(0, visibility(...))]. // Parse #[texture(0, visibility(...))].
List(m) if m.path == VISIBILITY => { List(m) if m.path == VISIBILITY => {
visibility = get_visibility_flag_value(Meta::Path(m.path))?; visibility = get_visibility_flag_value(&m)?;
} }
NameValue(m) => { NameValue(m) => {
return Err(Error::new_spanned( return Err(Error::new_spanned(
@ -910,7 +917,7 @@ fn get_sampler_attrs(metas: Vec<Meta>) -> Result<SamplerAttrs> {
} }
// Parse #[sampler(0, visibility(...))]. // Parse #[sampler(0, visibility(...))].
List(m) if m.path == VISIBILITY => { List(m) if m.path == VISIBILITY => {
visibility = get_visibility_flag_value(Meta::Path(m.path))?; visibility = get_visibility_flag_value(&m)?;
} }
NameValue(m) => { NameValue(m) => {
return Err(Error::new_spanned( return Err(Error::new_spanned(
@ -966,7 +973,7 @@ fn get_storage_binding_attr(metas: Vec<Meta>) -> Result<StorageAttrs> {
match meta { match meta {
// Parse #[storage(0, visibility(...))]. // Parse #[storage(0, visibility(...))].
List(m) if m.path == 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 => { Path(path) if path == READ_ONLY => {
read_only = true; read_only = true;

View File

@ -334,3 +334,35 @@ where
self.into() 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<Image>,
#[texture(1, visibility(none))]
pub none: Handle<Image>,
#[texture(2, visibility(fragment))]
pub fragment: Handle<Image>,
#[texture(3, visibility(vertex))]
pub vertex: Handle<Image>,
#[texture(4, visibility(compute))]
pub compute: Handle<Image>,
#[texture(5, visibility(vertex, fragment))]
pub vertex_fragment: Handle<Image>,
#[texture(6, visibility(vertex, compute))]
pub vertex_compute: Handle<Image>,
#[texture(7, visibility(fragment, compute))]
pub fragment_compute: Handle<Image>,
#[texture(8, visibility(vertex, fragment, compute))]
pub vertex_fragment_compute: Handle<Image>,
}
}
}