From eedec80e890e7a53d2fe7c6a44c331e2515ce17d Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 10 Feb 2020 19:26:04 -0800 Subject: [PATCH] add shader def fields / proc macro --- bevy_derive/src/lib.rs | 44 +++++++++++-------- examples/simple_new.rs | 2 + src/render/passes/forward/forward_pipeline.rs | 4 +- src/render/passes/forward_instanced/mod.rs | 2 + src/render/passes/forward_shadow/mod.rs | 2 + src/render/passes/shadow/shadow_pipeline.rs | 4 +- src/render/passes/ui/mod.rs | 4 +- .../pipelines/forward/forward.frag | 4 ++ src/render/render_graph_2/uniform.rs | 16 ++++++- .../render_graph_2/uniforms/local_to_world.rs | 4 +- .../uniforms/standard_material.rs | 6 +-- src/render/shader.rs | 11 +++-- 12 files changed, 70 insertions(+), 33 deletions(-) diff --git a/bevy_derive/src/lib.rs b/bevy_derive/src/lib.rs index fc212c5e98..672ecc8b72 100644 --- a/bevy_derive/src/lib.rs +++ b/bevy_derive/src/lib.rs @@ -35,7 +35,7 @@ struct UniformAttributeArgs { #[darling(default)] pub ignore: Option, #[darling(default)] - pub shader_def: Option, + pub shader_def: Option, } #[proc_macro_derive(Uniforms, attributes(uniform))] @@ -81,28 +81,29 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { .map(|(f, _attr)| *f) .collect::>(); - let shader_defs = uniform_fields + let shader_def_fields = uniform_fields .iter() - .filter(|(_f, attrs)| match attrs { - Some(attrs) => attrs.shader_def.is_some(), - None => false, - }) - .map(|(f, attrs)| { - // attrs is guaranteed to be set because we checked in filter - let shader_def = attrs.as_ref().unwrap().shader_def.as_ref().unwrap(); - if shader_def.len() == 0 { - f.ident.as_ref().unwrap().to_string() - } else { - shader_def.to_string() + .filter(|(_field, attrs)| { + match attrs { + Some(attrs) => match attrs.shader_def { + Some(shader_def) => shader_def, + None => false, + }, + None => false, } }) - .collect::>(); + .map(|(f, _attr)| *f) + .collect::>(); + + let shader_def_field_names = shader_def_fields.iter().map(|field| &field.ident); + let shader_def_field_name_strs = shader_def_fields.iter().map(|field| field.ident.as_ref().unwrap().to_string()); let struct_name = &ast.ident; let struct_name_screaming_snake = struct_name.to_string().to_screaming_snake_case(); let info_ident = format_ident!("{}_UNIFORM_INFO", struct_name_screaming_snake); let layout_ident = format_ident!("{}_UNIFORM_LAYOUTS", struct_name_screaming_snake); let layout_arrays = (0..active_uniform_fields.len()).map(|_| quote!(&[])); + let uniform_name_uniform_info = active_uniform_fields .iter() .map(|field| format!("{}_{}", struct_name, field.ident.as_ref().unwrap())) @@ -151,10 +152,17 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { } } - fn get_shader_defs(&self) -> Vec<&'static str> { - vec![ - #(#shader_defs,)* - ] + // 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> { + let mut potential_shader_defs: Vec<(&'static str, Option<&'static str>)> = vec![ + #((#shader_def_field_name_strs, 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!("{}{}", f, shader_def.unwrap())) + .collect::>()) } } }) diff --git a/examples/simple_new.rs b/examples/simple_new.rs index 17daf6d47e..2eaff4c31d 100644 --- a/examples/simple_new.rs +++ b/examples/simple_new.rs @@ -23,6 +23,7 @@ fn setup(world: &mut World) { mesh: plane_handle.clone(), material: StandardMaterial { albedo: math::vec4(0.1, 0.2, 0.1, 1.0), + everything_is_red: true, }, shader_uniforms: ShaderUniforms::new(), local_to_world: LocalToWorld::identity(), @@ -33,6 +34,7 @@ fn setup(world: &mut World) { mesh: cube_handle.clone(), material: StandardMaterial { albedo: math::vec4(0.5, 0.3, 0.3, 1.0), + everything_is_red: true, }, shader_uniforms: ShaderUniforms::new(), local_to_world: LocalToWorld::identity(), diff --git a/src/render/passes/forward/forward_pipeline.rs b/src/render/passes/forward/forward_pipeline.rs index af6394f69b..c312392146 100644 --- a/src/render/passes/forward/forward_pipeline.rs +++ b/src/render/passes/forward/forward_pipeline.rs @@ -23,9 +23,9 @@ impl ForwardPipeline { impl Pipeline for ForwardPipeline { fn initialize(&mut self, render_graph: &mut RenderGraphData, _: &mut World) { let vs_bytes = - shader::glsl_to_spirv(include_str!("forward.vert"), shader::ShaderStage::Vertex); + shader::glsl_to_spirv(include_str!("forward.vert"), shader::ShaderStage::Vertex, None); let fs_bytes = - shader::glsl_to_spirv(include_str!("forward.frag"), shader::ShaderStage::Fragment); + shader::glsl_to_spirv(include_str!("forward.frag"), shader::ShaderStage::Fragment, None); let bind_group_layout = render_graph diff --git a/src/render/passes/forward_instanced/mod.rs b/src/render/passes/forward_instanced/mod.rs index 5a19cfc673..ca66974f92 100644 --- a/src/render/passes/forward_instanced/mod.rs +++ b/src/render/passes/forward_instanced/mod.rs @@ -139,10 +139,12 @@ impl Pipeline for ForwardInstancedPipeline { let vs_bytes = shader::glsl_to_spirv( include_str!("forward_instanced.vert"), shader::ShaderStage::Vertex, + None, ); let fs_bytes = shader::glsl_to_spirv( include_str!("forward_instanced.frag"), shader::ShaderStage::Fragment, + None, ); let bind_group_layout = diff --git a/src/render/passes/forward_shadow/mod.rs b/src/render/passes/forward_shadow/mod.rs index b07d988ccf..cd7f233ea4 100644 --- a/src/render/passes/forward_shadow/mod.rs +++ b/src/render/passes/forward_shadow/mod.rs @@ -26,10 +26,12 @@ impl Pipeline for ForwardShadowPassNew { let vs_bytes = shader::glsl_to_spirv( include_str!("forward_shadow.vert"), shader::ShaderStage::Vertex, + None, ); let fs_bytes = shader::glsl_to_spirv( include_str!("forward_shadow.frag"), shader::ShaderStage::Fragment, + None, ); let bind_group_layout = diff --git a/src/render/passes/shadow/shadow_pipeline.rs b/src/render/passes/shadow/shadow_pipeline.rs index e1bf17bb43..5eaa85d3bf 100644 --- a/src/render/passes/shadow/shadow_pipeline.rs +++ b/src/render/passes/shadow/shadow_pipeline.rs @@ -103,9 +103,9 @@ impl Pipeline for ShadowPipeline { // Create the render pipeline let vs_bytes = - shader::glsl_to_spirv(include_str!("shadow.vert"), shader::ShaderStage::Vertex); + shader::glsl_to_spirv(include_str!("shadow.vert"), shader::ShaderStage::Vertex, None); let fs_bytes = - shader::glsl_to_spirv(include_str!("shadow.frag"), shader::ShaderStage::Fragment); + shader::glsl_to_spirv(include_str!("shadow.frag"), shader::ShaderStage::Fragment, None); let vs_module = render_graph.device.create_shader_module(&vs_bytes); let fs_module = render_graph.device.create_shader_module(&fs_bytes); diff --git a/src/render/passes/ui/mod.rs b/src/render/passes/ui/mod.rs index c0f1d198ca..5e08333845 100644 --- a/src/render/passes/ui/mod.rs +++ b/src/render/passes/ui/mod.rs @@ -95,9 +95,9 @@ impl UiPipeline { impl Pipeline for UiPipeline { fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World) { - let vs_bytes = shader::glsl_to_spirv(include_str!("ui.vert"), shader::ShaderStage::Vertex); + let vs_bytes = shader::glsl_to_spirv(include_str!("ui.vert"), shader::ShaderStage::Vertex, None); let fs_bytes = - shader::glsl_to_spirv(include_str!("ui.frag"), shader::ShaderStage::Fragment); + shader::glsl_to_spirv(include_str!("ui.frag"), shader::ShaderStage::Fragment, None); let bind_group_layout = render_graph diff --git a/src/render/render_graph_2/pipelines/forward/forward.frag b/src/render/render_graph_2/pipelines/forward/forward.frag index 05e2ecd7c6..5f175e37ff 100644 --- a/src/render/render_graph_2/pipelines/forward/forward.frag +++ b/src/render/render_graph_2/pipelines/forward/forward.frag @@ -43,4 +43,8 @@ void main() { } // multiply the light by material color o_Target = vec4(color, 1.0) * Albedo; + +# ifdef everything_is_red + o_Target = vec4(1.0, 0.0, 0.0, 1.0); +# endif } diff --git a/src/render/render_graph_2/uniform.rs b/src/render/render_graph_2/uniform.rs index ba530bdd10..80f1dcfc38 100644 --- a/src/render/render_graph_2/uniform.rs +++ b/src/render/render_graph_2/uniform.rs @@ -41,9 +41,23 @@ pub trait AsUniforms { fn get_uniform_info(&self, name: &str) -> Option<&UniformInfo>; fn get_uniform_layouts(&self) -> &[&[UniformPropertyType]]; fn get_uniform_bytes(&self, name: &str) -> Option>; - fn get_shader_defs(&self) -> Vec<&'static str>; + fn get_shader_defs(&self) -> Option>; // TODO: support zero-copy uniforms // fn get_uniform_bytes_ref(&self, name: &str) -> Option<&[u8]>; + +} + +pub trait ShaderDefSuffixProvider { + fn get_shader_def(&self) -> Option<&'static str>; +} + +impl ShaderDefSuffixProvider for bool { + fn get_shader_def(&self) -> Option<&'static str> { + match *self { + true => Some(""), + false => None, + } + } } // pub struct UniformInfo<'a> { diff --git a/src/render/render_graph_2/uniforms/local_to_world.rs b/src/render/render_graph_2/uniforms/local_to_world.rs index 500681d5b0..8b836465f7 100644 --- a/src/render/render_graph_2/uniforms/local_to_world.rs +++ b/src/render/render_graph_2/uniforms/local_to_world.rs @@ -41,7 +41,7 @@ impl AsUniforms for bevy_transform::prelude::LocalToWorld { } } - fn get_shader_defs(&self) -> std::vec::Vec<&'static str> { - Vec::new() + fn get_shader_defs(&self) -> Option> { + None } } \ No newline at end of file diff --git a/src/render/render_graph_2/uniforms/standard_material.rs b/src/render/render_graph_2/uniforms/standard_material.rs index 23d911fa14..2685e1fdd2 100644 --- a/src/render/render_graph_2/uniforms/standard_material.rs +++ b/src/render/render_graph_2/uniforms/standard_material.rs @@ -2,7 +2,7 @@ use crate::{ math::Vec4, render::render_graph_2::{ uniform::{AsUniforms, GetBytes, UniformInfo}, - BindType, UniformPropertyType, + BindType, UniformPropertyType, ShaderDefSuffixProvider }, }; @@ -11,6 +11,6 @@ use bevy_derive::Uniforms; #[derive(Uniforms)] pub struct StandardMaterial { pub albedo: Vec4, - // #[uniform(ignore,shader_def="Hi")] - // pub enable_thing: bool, + #[uniform(ignore,shader_def)] + pub everything_is_red: bool, } \ No newline at end of file diff --git a/src/render/shader.rs b/src/render/shader.rs index 667cf75499..c5a1f9c05b 100644 --- a/src/render/shader.rs +++ b/src/render/shader.rs @@ -17,10 +17,15 @@ impl Into for ShaderStage { } } -pub fn glsl_to_spirv(glsl_source: &str, stage: ShaderStage) -> Vec { +pub fn glsl_to_spirv(glsl_source: &str, stage: ShaderStage, shader_defs: Option<&Vec>) -> Vec { let shader_kind: shaderc::ShaderKind = stage.into(); let mut compiler = shaderc::Compiler::new().unwrap(); - let options = shaderc::CompileOptions::new().unwrap(); + let mut options = shaderc::CompileOptions::new().unwrap(); + if let Some(shader_defs) = shader_defs { + for shader_def in shader_defs.iter() { + options.add_macro_definition(shader_def.as_str(), None); + } + } let binary_result = compiler .compile_into_spirv( glsl_source, @@ -59,7 +64,7 @@ impl Shader { pub fn get_spirv(&self) -> Vec { match self.source { ShaderSource::Spirv(ref bytes) => bytes.clone(), - ShaderSource::Glsl(ref source) => glsl_to_spirv(&source, self.stage), + ShaderSource::Glsl(ref source) => glsl_to_spirv(&source, self.stage, self.macros.as_ref()), } }