shader_defs: new leaner shader defs. they are now separate from uniforms
This commit is contained in:
		
							parent
							
								
									fd8f87400d
								
							
						
					
					
						commit
						62c434274f
					
				@ -8,6 +8,7 @@ mod modules;
 | 
			
		||||
mod render_resources;
 | 
			
		||||
mod render_resource;
 | 
			
		||||
mod resource;
 | 
			
		||||
mod shader_defs;
 | 
			
		||||
mod uniforms;
 | 
			
		||||
mod as_vertex_buffer_descriptor;
 | 
			
		||||
 | 
			
		||||
@ -43,6 +44,11 @@ pub fn derive_render_resource(input: TokenStream) -> TokenStream {
 | 
			
		||||
    render_resource::derive_render_resource(input)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[proc_macro_derive(ShaderDefs, attributes(shader_def, module))]
 | 
			
		||||
pub fn derive_shader_defs(input: TokenStream) -> TokenStream {
 | 
			
		||||
    shader_defs::derive_shader_defs(input)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[proc_macro_derive(AsVertexBufferDescriptor, attributes(vertex, module))]
 | 
			
		||||
pub fn derive_as_vertex_buffer_descriptor(input: TokenStream) -> TokenStream {
 | 
			
		||||
    as_vertex_buffer_descriptor::derive_as_vertex_buffer_descriptor(input)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										71
									
								
								crates/bevy_derive/src/shader_defs.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								crates/bevy_derive/src/shader_defs.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
			
		||||
use crate::modules::{get_modules, get_path};
 | 
			
		||||
use proc_macro::TokenStream;
 | 
			
		||||
use proc_macro2::Ident;
 | 
			
		||||
use inflector::Inflector;
 | 
			
		||||
use quote::quote;
 | 
			
		||||
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, Path};
 | 
			
		||||
 | 
			
		||||
static SHADER_DEF_ATTRIBUTE_NAME: &'static str = "shader_def";
 | 
			
		||||
 | 
			
		||||
pub fn derive_shader_defs(input: TokenStream) -> TokenStream {
 | 
			
		||||
    let ast = parse_macro_input!(input as DeriveInput);
 | 
			
		||||
    let modules = get_modules(&ast);
 | 
			
		||||
    let bevy_render_path: Path = get_path(&modules.bevy_render);
 | 
			
		||||
 | 
			
		||||
    let fields = match &ast.data {
 | 
			
		||||
        Data::Struct(DataStruct {
 | 
			
		||||
            fields: Fields::Named(fields),
 | 
			
		||||
            ..
 | 
			
		||||
        }) => &fields.named,
 | 
			
		||||
        _ => panic!("expected a struct with named fields"),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let shader_def_idents = fields
 | 
			
		||||
        .iter()
 | 
			
		||||
        .filter(|f| {
 | 
			
		||||
            f.attrs
 | 
			
		||||
                .iter()
 | 
			
		||||
                .find(|a| {
 | 
			
		||||
                    a.path.get_ident().as_ref().unwrap().to_string() == SHADER_DEF_ATTRIBUTE_NAME
 | 
			
		||||
                })
 | 
			
		||||
                .is_some()
 | 
			
		||||
        })
 | 
			
		||||
        .map(|f| f.ident.as_ref().unwrap())
 | 
			
		||||
        .collect::<Vec<&Ident>>();
 | 
			
		||||
    let struct_name = &ast.ident;
 | 
			
		||||
    let struct_name_pascal_case = ast.ident.to_string().to_pascal_case();
 | 
			
		||||
    let shader_defs = shader_def_idents
 | 
			
		||||
        .iter()
 | 
			
		||||
        .map(|i| format!("{}_{}", struct_name_pascal_case, i.to_string()).to_uppercase());
 | 
			
		||||
 | 
			
		||||
    let shader_defs_len = shader_defs.len();
 | 
			
		||||
    let shader_def_indices = 0..shader_defs_len;
 | 
			
		||||
 | 
			
		||||
    let generics = ast.generics;
 | 
			
		||||
    let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    TokenStream::from(quote! {
 | 
			
		||||
        impl #impl_generics #bevy_render_path::shader::ShaderDefs for #struct_name#ty_generics {
 | 
			
		||||
            fn shader_defs_len(&self) -> usize {
 | 
			
		||||
                #shader_defs_len
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn get_shader_def(&self, index: usize) -> Option<&str> {
 | 
			
		||||
                use #bevy_render_path::shader::ShaderDef;
 | 
			
		||||
                match index {
 | 
			
		||||
                    #(#shader_def_indices => if self.#shader_def_idents.is_defined() {
 | 
			
		||||
                        Some(#shader_defs)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        None
 | 
			
		||||
                    },)*
 | 
			
		||||
                    _ => None,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fn iter_shader_defs(&self) -> #bevy_render_path::shader::ShaderDefIterator {
 | 
			
		||||
                #bevy_render_path::shader::ShaderDefIterator::new(self)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
@ -138,15 +138,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream {
 | 
			
		||||
            // TODO: this will be very allocation heavy. find a way to either make this allocation free
 | 
			
		||||
            // or alternatively only run it when the shader_defs have changed
 | 
			
		||||
            fn get_shader_defs(&self) -> Option<Vec<String>> {
 | 
			
		||||
                use #bevy_render_path::shader::ShaderDefSuffixProvider;
 | 
			
		||||
                let mut potential_shader_defs: Vec<(&'static str, Option<&'static str>)> = vec![
 | 
			
		||||
                    #((#shader_def_field_names_screaming_snake, self.#shader_def_field_names.get_shader_def()),)*
 | 
			
		||||
                ];
 | 
			
		||||
 | 
			
		||||
                Some(potential_shader_defs.drain(..)
 | 
			
		||||
                    .filter(|(f, shader_def)| shader_def.is_some())
 | 
			
		||||
                    .map(|(f, shader_def)| format!("{}_{}{}", #struct_name_uppercase, f, shader_def.unwrap()))
 | 
			
		||||
                    .collect::<Vec<String>>())
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
use bevy_asset::{self, Handle};
 | 
			
		||||
use bevy_render::{render_resource::RenderResources, shader::Uniforms, texture::Texture, Color};
 | 
			
		||||
use bevy_render::{render_resource::RenderResources, shader::ShaderDefs, texture::Texture, Color};
 | 
			
		||||
 | 
			
		||||
#[derive(Uniforms, RenderResources)]
 | 
			
		||||
#[derive(RenderResources, ShaderDefs)]
 | 
			
		||||
pub struct StandardMaterial {
 | 
			
		||||
    pub albedo: Color,
 | 
			
		||||
    #[uniform(shader_def)]
 | 
			
		||||
    #[shader_def]
 | 
			
		||||
    pub albedo_texture: Option<Handle<Texture>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,10 @@
 | 
			
		||||
mod shader;
 | 
			
		||||
mod shader_defs;
 | 
			
		||||
mod shader_reflect;
 | 
			
		||||
mod uniform;
 | 
			
		||||
pub mod uniforms;
 | 
			
		||||
 | 
			
		||||
pub use shader::*;
 | 
			
		||||
pub use shader_defs::*;
 | 
			
		||||
pub use shader_reflect::*;
 | 
			
		||||
pub use uniform::*;
 | 
			
		||||
pub use uniform::*;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										92
									
								
								crates/bevy_render/src/shader/shader_defs.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								crates/bevy_render/src/shader/shader_defs.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,92 @@
 | 
			
		||||
 | 
			
		||||
use bevy_asset::{Assets, Handle};
 | 
			
		||||
use crate::{Renderable, texture::Texture};
 | 
			
		||||
use legion::prelude::{Res, Com, ComMut};
 | 
			
		||||
 | 
			
		||||
pub use bevy_derive::ShaderDefs;
 | 
			
		||||
 | 
			
		||||
pub trait ShaderDef {
 | 
			
		||||
    fn is_defined(&self) -> bool;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait ShaderDefs {
 | 
			
		||||
    fn shader_defs_len(&self) -> usize;
 | 
			
		||||
    fn get_shader_def(&self, index: usize) -> Option<&str>;
 | 
			
		||||
    fn iter_shader_defs(&self) -> ShaderDefIterator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pub struct ShaderDefIterator<'a> {
 | 
			
		||||
    shader_defs: &'a dyn ShaderDefs,
 | 
			
		||||
    index: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> ShaderDefIterator<'a> {
 | 
			
		||||
    pub fn new(shader_defs: &'a dyn ShaderDefs) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            shader_defs,
 | 
			
		||||
            index: 0,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl<'a> Iterator for ShaderDefIterator<'a> {
 | 
			
		||||
    type Item = &'a str;
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        loop {
 | 
			
		||||
            if self.index == self.shader_defs.shader_defs_len() {
 | 
			
		||||
                return None;
 | 
			
		||||
            } 
 | 
			
		||||
            let shader_def = self
 | 
			
		||||
                .shader_defs
 | 
			
		||||
                .get_shader_def(self.index);
 | 
			
		||||
            self.index += 1;
 | 
			
		||||
            if shader_def.is_some() {
 | 
			
		||||
               return shader_def; 
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ShaderDef for bool {
 | 
			
		||||
    fn is_defined(&self) -> bool {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ShaderDef for Option<Handle<Texture>> {
 | 
			
		||||
    fn is_defined(&self) -> bool {
 | 
			
		||||
        self.is_some()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn shader_def_system<T>(shader_defs: Com<T>, mut renderable: ComMut<Renderable>)
 | 
			
		||||
where
 | 
			
		||||
    T: ShaderDefs + Send + Sync + 'static,
 | 
			
		||||
{
 | 
			
		||||
    for shader_def in shader_defs.iter_shader_defs() {
 | 
			
		||||
        renderable
 | 
			
		||||
            .render_resource_assignments
 | 
			
		||||
            .pipeline_specialization
 | 
			
		||||
            .shader_specialization
 | 
			
		||||
            .shader_defs
 | 
			
		||||
            .insert(shader_def.to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn asset_shader_def_system<T>(
 | 
			
		||||
    assets: Res<Assets<T>>,
 | 
			
		||||
    asset_handle: Com<Handle<T>>,
 | 
			
		||||
    mut renderable: ComMut<Renderable>,
 | 
			
		||||
) where
 | 
			
		||||
    T: ShaderDefs + Send + Sync + 'static,
 | 
			
		||||
{
 | 
			
		||||
    let shader_defs = assets.get(&asset_handle).unwrap();
 | 
			
		||||
    for shader_def in shader_defs.iter_shader_defs() {
 | 
			
		||||
        renderable
 | 
			
		||||
            .render_resource_assignments
 | 
			
		||||
            .pipeline_specialization
 | 
			
		||||
            .shader_specialization
 | 
			
		||||
            .shader_defs
 | 
			
		||||
            .insert(shader_def.to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
use crate::{pipeline::BindType, texture::Texture, Renderable};
 | 
			
		||||
use bevy_asset::{Assets, Handle};
 | 
			
		||||
use legion::prelude::*;
 | 
			
		||||
use crate::{pipeline::BindType, texture::Texture};
 | 
			
		||||
use bevy_asset::Handle;
 | 
			
		||||
 | 
			
		||||
pub use bevy_derive::{Uniform, Uniforms};
 | 
			
		||||
 | 
			
		||||
@ -13,42 +12,6 @@ pub trait Uniforms: Send + Sync + 'static {
 | 
			
		||||
    fn get_field_bind_type(&self, name: &str) -> Option<FieldBindType>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn shader_def_system<T>(uniforms: Com<T>, mut renderable: ComMut<Renderable>)
 | 
			
		||||
where
 | 
			
		||||
    T: Uniforms + Send + Sync + 'static,
 | 
			
		||||
{
 | 
			
		||||
    if let Some(shader_defs) = uniforms.get_shader_defs() {
 | 
			
		||||
        renderable
 | 
			
		||||
            .render_resource_assignments
 | 
			
		||||
            .pipeline_specialization
 | 
			
		||||
            .shader_specialization
 | 
			
		||||
            .shader_defs
 | 
			
		||||
            .extend(shader_defs)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn asset_shader_def_system<T>(
 | 
			
		||||
    assets: Res<Assets<T>>,
 | 
			
		||||
    asset_handle: Com<Handle<T>>,
 | 
			
		||||
    mut renderable: ComMut<Renderable>,
 | 
			
		||||
) where
 | 
			
		||||
    T: Uniforms + Send + Sync + 'static,
 | 
			
		||||
{
 | 
			
		||||
    if !renderable.is_visible || renderable.is_instanced {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let uniforms = assets.get(&asset_handle).unwrap();
 | 
			
		||||
    if let Some(shader_defs) = uniforms.get_shader_defs() {
 | 
			
		||||
        renderable
 | 
			
		||||
            .render_resource_assignments
 | 
			
		||||
            .pipeline_specialization
 | 
			
		||||
            .shader_specialization
 | 
			
		||||
            .shader_defs
 | 
			
		||||
            .extend(shader_defs)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait ShaderDefSuffixProvider {
 | 
			
		||||
    fn get_shader_def(&self) -> Option<&'static str>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
use bevy_asset::{self, Handle};
 | 
			
		||||
use bevy_render::{texture::Texture, Color, render_resource::RenderResources, shader::Uniforms};
 | 
			
		||||
use bevy_render::{render_resource::RenderResources, shader::ShaderDefs, texture::Texture, Color};
 | 
			
		||||
 | 
			
		||||
#[derive(Uniforms, RenderResources)]
 | 
			
		||||
#[derive(RenderResources, ShaderDefs)]
 | 
			
		||||
pub struct ColorMaterial {
 | 
			
		||||
    pub color: Color,
 | 
			
		||||
    #[uniform(shader_def)]
 | 
			
		||||
    #[shader_def]
 | 
			
		||||
    pub texture: Option<Handle<Texture>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,26 +1,27 @@
 | 
			
		||||
use crate::Rect;
 | 
			
		||||
use bevy_asset::Handle;
 | 
			
		||||
use bevy_render::{texture::Texture, render_resource::{RenderResources, RenderResource}, shader::{Uniforms, Uniform}};
 | 
			
		||||
use bevy_core::bytes::Bytes;
 | 
			
		||||
use bevy_render::{
 | 
			
		||||
    render_resource::{RenderResource, RenderResources},
 | 
			
		||||
    texture::Texture,
 | 
			
		||||
};
 | 
			
		||||
use glam::{Vec2, Vec3};
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
#[derive(Uniforms, RenderResources)]
 | 
			
		||||
#[derive(RenderResources)]
 | 
			
		||||
pub struct TextureAtlas {
 | 
			
		||||
    pub texture: Handle<Texture>,
 | 
			
		||||
    // TODO: add support to Uniforms derive to write dimensions and sprites to the same buffer
 | 
			
		||||
    pub dimensions: Vec2,
 | 
			
		||||
    #[uniform(buffer)]
 | 
			
		||||
    #[render_resources(buffer)]
 | 
			
		||||
    pub textures: Vec<Rect>,
 | 
			
		||||
    #[uniform(ignore)]
 | 
			
		||||
    #[render_resources(ignore)]
 | 
			
		||||
    pub texture_handles: Option<HashMap<Handle<Texture>, usize>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NOTE: cannot do `unsafe impl Byteable` here because Vec3 takes up the space of a Vec4. If/when glam changes this we can swap out
 | 
			
		||||
// Bytes for Byteable as a micro-optimization. https://github.com/bitshifter/glam-rs/issues/36
 | 
			
		||||
#[derive(Uniform, Bytes, RenderResources, RenderResource, Default)]
 | 
			
		||||
#[derive(Bytes, RenderResources, RenderResource, Default)]
 | 
			
		||||
#[render_resources(from_self)]
 | 
			
		||||
pub struct TextureAtlasSprite {
 | 
			
		||||
    pub position: Vec3,
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ fn main() {
 | 
			
		||||
        .run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Uniforms, RenderResources, Default)]
 | 
			
		||||
#[derive(RenderResources, Default)]
 | 
			
		||||
struct MyMaterial {
 | 
			
		||||
    pub color: Color,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -12,11 +12,11 @@ fn main() {
 | 
			
		||||
        .run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Uniforms, RenderResources, Default)]
 | 
			
		||||
#[derive(RenderResources, ShaderDefs, Default)]
 | 
			
		||||
struct MyMaterial {
 | 
			
		||||
    pub color: Color,
 | 
			
		||||
    #[uniform(ignore, shader_def)]
 | 
			
		||||
    #[render_resources(ignore)]
 | 
			
		||||
    #[shader_def]
 | 
			
		||||
    pub always_red: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
pub use crate::{
 | 
			
		||||
    app::{
 | 
			
		||||
        schedule_runner::ScheduleRunnerPlugin, stage, App, AppBuilder, AppPlugin, EntityArchetype,
 | 
			
		||||
        EventReader, Events, FromResources, System, DynamicAppPlugin
 | 
			
		||||
        schedule_runner::ScheduleRunnerPlugin, stage, App, AppBuilder, AppPlugin, DynamicAppPlugin,
 | 
			
		||||
        EntityArchetype, EventReader, Events, FromResources, System,
 | 
			
		||||
    },
 | 
			
		||||
    asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle},
 | 
			
		||||
    core::{
 | 
			
		||||
@ -25,8 +25,10 @@ pub use crate::{
 | 
			
		||||
            },
 | 
			
		||||
            RenderGraph,
 | 
			
		||||
        },
 | 
			
		||||
        shader::{Shader, ShaderDefSuffixProvider, ShaderStage, ShaderStages, Uniforms},
 | 
			
		||||
        render_resource::RenderResources,
 | 
			
		||||
        shader::{
 | 
			
		||||
            Shader, ShaderDefSuffixProvider, ShaderDefs, ShaderStage, ShaderStages, Uniforms,
 | 
			
		||||
        },
 | 
			
		||||
        texture::Texture,
 | 
			
		||||
        Camera, Color, ColorSource, OrthographicProjection, PerspectiveProjection, Renderable,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user