From 2eef0c7ac18d6fc6489a68d40f93dc955f1c5517 Mon Sep 17 00:00:00 2001 From: Robert Swain Date: Sat, 27 Nov 2021 16:24:53 +0100 Subject: [PATCH 1/3] bevy_render2: Add support for #else for shader defs --- .../src/render_resource/shader.rs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/pipelined/bevy_render2/src/render_resource/shader.rs b/pipelined/bevy_render2/src/render_resource/shader.rs index a2781513792f8..7803c9a51e0c6 100644 --- a/pipelined/bevy_render2/src/render_resource/shader.rs +++ b/pipelined/bevy_render2/src/render_resource/shader.rs @@ -325,6 +325,7 @@ pub static SHADER_IMPORT_PROCESSOR: Lazy = pub struct ShaderProcessor { ifdef_regex: Regex, ifndef_regex: Regex, + else_regex: Regex, endif_regex: Regex, } @@ -333,6 +334,7 @@ impl Default for ShaderProcessor { Self { ifdef_regex: Regex::new(r"^\s*#\s*ifdef\s*([\w|\d|_]+)").unwrap(), ifndef_regex: Regex::new(r"^\s*#\s*ifndef\s*([\w|\d|_]+)").unwrap(), + else_regex: Regex::new(r"^\s*#\s*else").unwrap(), endif_regex: Regex::new(r"^\s*#\s*endif").unwrap(), } } @@ -368,6 +370,10 @@ impl ShaderProcessor { } else if let Some(cap) = self.ifndef_regex.captures(line) { let def = cap.get(1).unwrap(); scopes.push(*scopes.last().unwrap() && !shader_defs.contains(def.as_str())); + } else if self.else_regex.is_match(line) { + if let Some(last) = scopes.last_mut() { + *last = !*last; + } } else if self.endif_regex.is_match(line) { scopes.pop(); if scopes.is_empty() { @@ -481,6 +487,41 @@ fn vertex( return out; } "; + +const WGSL_ELSE: &str = r" +[[block]] +struct View { + view_proj: mat4x4; + world_position: vec3; +}; +[[group(0), binding(0)]] +var view: View; + +#ifdef TEXTURE +[[group(1), binding(0)]] +var sprite_texture: texture_2d; +#else +[[group(1), binding(0)]] +var sprite_texture: texture_2d_array; +#endif + +struct VertexOutput { + [[location(0)]] uv: vec2; + [[builtin(position)]] position: vec4; +}; + +[[stage(vertex)]] +fn vertex( + [[location(0)]] vertex_position: vec3, + [[location(1)]] vertex_uv: vec2 +) -> VertexOutput { + var out: VertexOutput; + out.uv = vertex_uv; + out.position = view.view_proj * vec4(vertex_position, 1.0); + return out; +} +"; + const WGSL_NESTED_IFDEF: &str = r" [[block]] struct View { @@ -598,6 +639,49 @@ fn vertex( assert_eq!(result.get_wgsl_source().unwrap(), EXPECTED); } + #[test] + fn process_shader_def_else() { + #[rustfmt::skip] + const EXPECTED: &str = r" +[[block]] +struct View { + view_proj: mat4x4; + world_position: vec3; +}; +[[group(0), binding(0)]] +var view: View; + +[[group(1), binding(0)]] +var sprite_texture: texture_2d_array; + +struct VertexOutput { + [[location(0)]] uv: vec2; + [[builtin(position)]] position: vec4; +}; + +[[stage(vertex)]] +fn vertex( + [[location(0)]] vertex_position: vec3, + [[location(1)]] vertex_uv: vec2 +) -> VertexOutput { + var out: VertexOutput; + out.uv = vertex_uv; + out.position = view.view_proj * vec4(vertex_position, 1.0); + return out; +} +"; + let processor = ShaderProcessor::default(); + let result = processor + .process( + &Shader::from_wgsl(WGSL_ELSE), + &[], + &HashMap::default(), + &HashMap::default(), + ) + .unwrap(); + assert_eq!(result.get_wgsl_source().unwrap(), EXPECTED); + } + #[test] fn process_shader_def_unclosed() { #[rustfmt::skip] From 5593accf639ca965d397b3bbec48259d17649863 Mon Sep 17 00:00:00 2001 From: Robert Swain Date: Sat, 27 Nov 2021 16:36:49 +0100 Subject: [PATCH 2/3] bevy_render2: Handle nested #if[n]def #else --- .../src/render_resource/shader.rs | 126 +++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/pipelined/bevy_render2/src/render_resource/shader.rs b/pipelined/bevy_render2/src/render_resource/shader.rs index 7803c9a51e0c6..11e14ea120fb9 100644 --- a/pipelined/bevy_render2/src/render_resource/shader.rs +++ b/pipelined/bevy_render2/src/render_resource/shader.rs @@ -371,8 +371,12 @@ impl ShaderProcessor { let def = cap.get(1).unwrap(); scopes.push(*scopes.last().unwrap() && !shader_defs.contains(def.as_str())); } else if self.else_regex.is_match(line) { + let mut is_parent_scope_truthy = true; + if scopes.len() > 1 { + is_parent_scope_truthy = scopes[scopes.len() - 2]; + } if let Some(last) = scopes.last_mut() { - *last = !*last; + *last = is_parent_scope_truthy && !*last; } } else if self.endif_regex.is_match(line) { scopes.pop(); @@ -543,6 +547,42 @@ struct VertexOutput { [[builtin(position)]] position: vec4; }; +[[stage(vertex)]] +fn vertex( + [[location(0)]] vertex_position: vec3, + [[location(1)]] vertex_uv: vec2 +) -> VertexOutput { + var out: VertexOutput; + out.uv = vertex_uv; + out.position = view.view_proj * vec4(vertex_position, 1.0); + return out; +} +"; + + const WGSL_NESTED_IFDEF_ELSE: &str = r" +[[block]] +struct View { + view_proj: mat4x4; + world_position: vec3; +}; +[[group(0), binding(0)]] +var view: View; + +# ifdef TEXTURE +# ifdef ATTRIBUTE +[[group(1), binding(0)]] +var sprite_texture: texture_2d; +#else +[[group(1), binding(0)]] +var sprite_texture: texture_2d_array; +# endif +# endif + +struct VertexOutput { + [[location(0)]] uv: vec2; + [[builtin(position)]] position: vec4; +}; + [[stage(vertex)]] fn vertex( [[location(0)]] vertex_position: vec3, @@ -846,6 +886,49 @@ fn vertex( assert_eq!(result.get_wgsl_source().unwrap(), EXPECTED); } + #[test] + fn process_nested_shader_def_outer_defined_inner_else() { + #[rustfmt::skip] + const EXPECTED: &str = r" +[[block]] +struct View { + view_proj: mat4x4; + world_position: vec3; +}; +[[group(0), binding(0)]] +var view: View; + +[[group(1), binding(0)]] +var sprite_texture: texture_2d_array; + +struct VertexOutput { + [[location(0)]] uv: vec2; + [[builtin(position)]] position: vec4; +}; + +[[stage(vertex)]] +fn vertex( + [[location(0)]] vertex_position: vec3, + [[location(1)]] vertex_uv: vec2 +) -> VertexOutput { + var out: VertexOutput; + out.uv = vertex_uv; + out.position = view.view_proj * vec4(vertex_position, 1.0); + return out; +} +"; + let processor = ShaderProcessor::default(); + let result = processor + .process( + &Shader::from_wgsl(WGSL_NESTED_IFDEF_ELSE), + &["TEXTURE".to_string()], + &HashMap::default(), + &HashMap::default(), + ) + .unwrap(); + assert_eq!(result.get_wgsl_source().unwrap(), EXPECTED); + } + #[test] fn process_nested_shader_def_neither_defined() { #[rustfmt::skip] @@ -887,6 +970,47 @@ fn vertex( assert_eq!(result.get_wgsl_source().unwrap(), EXPECTED); } + #[test] + fn process_nested_shader_def_neither_defined_else() { + #[rustfmt::skip] + const EXPECTED: &str = r" +[[block]] +struct View { + view_proj: mat4x4; + world_position: vec3; +}; +[[group(0), binding(0)]] +var view: View; + + +struct VertexOutput { + [[location(0)]] uv: vec2; + [[builtin(position)]] position: vec4; +}; + +[[stage(vertex)]] +fn vertex( + [[location(0)]] vertex_position: vec3, + [[location(1)]] vertex_uv: vec2 +) -> VertexOutput { + var out: VertexOutput; + out.uv = vertex_uv; + out.position = view.view_proj * vec4(vertex_position, 1.0); + return out; +} +"; + let processor = ShaderProcessor::default(); + let result = processor + .process( + &Shader::from_wgsl(WGSL_NESTED_IFDEF_ELSE), + &[], + &HashMap::default(), + &HashMap::default(), + ) + .unwrap(); + assert_eq!(result.get_wgsl_source().unwrap(), EXPECTED); + } + #[test] fn process_nested_shader_def_inner_defined_outer_not() { #[rustfmt::skip] From 04e5a39b3c8d2f6d6564e58fd041d9d90759e805 Mon Sep 17 00:00:00 2001 From: Robert Swain Date: Sat, 27 Nov 2021 16:48:29 +0100 Subject: [PATCH 3/3] cargo fmt --- pipelined/bevy_render2/src/render_resource/shader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pipelined/bevy_render2/src/render_resource/shader.rs b/pipelined/bevy_render2/src/render_resource/shader.rs index 11e14ea120fb9..6dd84961111e5 100644 --- a/pipelined/bevy_render2/src/render_resource/shader.rs +++ b/pipelined/bevy_render2/src/render_resource/shader.rs @@ -492,7 +492,7 @@ fn vertex( } "; -const WGSL_ELSE: &str = r" + const WGSL_ELSE: &str = r" [[block]] struct View { view_proj: mat4x4;