From 90c2cf6aa6ea2b595098a27b148e3ad2f91317cb Mon Sep 17 00:00:00 2001 From: Gordon-F Date: Wed, 2 Jun 2021 18:28:41 +0300 Subject: [PATCH] Add ability to generate named expressions --- src/back/glsl/mod.rs | 86 ++++++++++++++-------- src/back/msl/mod.rs | 2 +- src/back/wgsl/writer.rs | 118 ++++++++++++++++++------------- src/front/glsl/parser.rs | 1 + src/front/spv/function.rs | 4 +- src/front/wgsl/mod.rs | 11 +++ src/lib.rs | 5 ++ src/proc/namer.rs | 16 +++++ tests/out/access.wgsl | 6 +- tests/out/boids.Compute.glsl | 13 ++-- tests/out/boids.wgsl | 13 ++-- tests/out/collatz.ron | 2 + tests/out/image.wgsl | 57 +++++++-------- tests/out/interface.wgsl | 7 +- tests/out/operators.wgsl | 4 +- tests/out/quad.Fragment.glsl | 7 +- tests/out/quad.wgsl | 7 +- tests/out/shadow.Fragment.glsl | 13 ++-- tests/out/shadow.ron | 3 + tests/out/shadow.wgsl | 13 ++-- tests/out/skybox.Vertex.glsl | 6 +- tests/out/skybox.wgsl | 6 +- tests/out/standard.Fragment.glsl | 8 +-- tests/out/standard.wgsl | 8 +-- 24 files changed, 263 insertions(+), 153 deletions(-) diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index 6a41471497..fc7847e77a 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -194,9 +194,11 @@ struct FunctionCtx<'a> { info: &'a FunctionInfo, /// The expression arena of the current function being written expressions: &'a Arena, + /// Map of expressions that have associated variable names + named_expressions: &'a crate::NamedExpressions, } -impl<'a> FunctionCtx<'a> { +impl<'a> FunctionCtx<'_> { /// Helper method that generates a [`NameKey`](crate::proc::NameKey) for a local in the current function fn name_key(&self, local: Handle) -> NameKey { match self.func { @@ -295,9 +297,6 @@ pub enum Error { /// A scalar with an unsupported width was requested #[error("A scalar with an unsupported width was requested: {0:?} {1:?}")] UnsupportedScalar(ScalarKind, Bytes), - /// [`Interpolation::Patch`](crate::Interpolation::Patch) isn't supported - #[error("Patch interpolation isn't supported")] - PatchInterpolationNotSupported, /// A image was used with multiple samplers, this isn't supported #[error("A image was used with multiple samplers")] ImageMultipleSamplers, @@ -320,6 +319,7 @@ pub struct Writer<'a, W> { // Internal State /// Features manager used to store all the needed features and write them features: FeaturesManager, + namer: Namer, /// A map with all the names needed for writing the module /// (generated by a [`Namer`](crate::proc::Namer)) names: FastHashMap, @@ -332,7 +332,7 @@ pub struct Writer<'a, W> { /// Used to generate a unique number for blocks block_id: IdGenerator, /// Set of expressions that have associated temporary variables - cached_expressions: FastHashMap, String>, + named_expressions: crate::NamedExpressions, } impl<'a, W: Write> Writer<'a, W> { @@ -363,7 +363,8 @@ impl<'a, W: Write> Writer<'a, W> { // Generate a map with names required to write the module let mut names = FastHashMap::default(); - Namer::default().reset(module, keywords::RESERVED_KEYWORDS, &["gl_"], &mut names); + let mut namer = Namer::default(); + namer.reset(module, keywords::RESERVED_KEYWORDS, &["gl_"], &mut names); // Build the instance let mut this = Self { @@ -371,7 +372,7 @@ impl<'a, W: Write> Writer<'a, W> { info, out, options, - + namer, features: FeaturesManager::new(), names, reflection_names: FastHashMap::default(), @@ -379,7 +380,7 @@ impl<'a, W: Write> Writer<'a, W> { entry_point_idx: ep_idx as u16, block_id: IdGenerator::default(), - cached_expressions: FastHashMap::default(), + named_expressions: crate::NamedExpressions::default(), }; // Find all features required to print this module @@ -884,9 +885,10 @@ impl<'a, W: Write> Writer<'a, W> { func: ty, info, expressions: &func.expressions, + named_expressions: &func.named_expressions, }; - self.cached_expressions.clear(); + self.named_expressions.clear(); // Write the function header // @@ -1189,30 +1191,23 @@ impl<'a, W: Write> Writer<'a, W> { // This is where we can generate intermediate constants for some expression types. Statement::Emit(ref range) => { for handle in range.clone() { + if let Some(name) = ctx.named_expressions.get(&handle) { + write!(self.out, "{}", INDENT.repeat(indent))?; + + // Front end provides names for all variables at the start of writing. + // But we write them to step by step. We need to recache them inside `write_named_expr` + // Otherwise, we could accidentally write variable name instead of full expression. + // Also, we use sanitized names! It defense backend from generating variable with name from reserved keywords. + let sanitized_name = self.namer.call_unique(name); + self.write_named_expr(handle, sanitized_name, ctx)?; + continue; + } + let min_ref_count = ctx.expressions[handle].bake_ref_count(); if min_ref_count <= ctx.info[handle].ref_count { write!(self.out, "{}", INDENT.repeat(indent))?; - match ctx.info[handle].ty { - TypeResolution::Handle(ty_handle) => { - match self.module.types[ty_handle].inner { - TypeInner::Struct { .. } => { - let ty_name = &self.names[&NameKey::Type(ty_handle)]; - write!(self.out, "{}", ty_name)?; - } - _ => { - self.write_type(ty_handle)?; - } - } - } - TypeResolution::Value(ref inner) => { - self.write_value_type(inner)?; - } - } let name = format!("_expr{}", handle.index()); - write!(self.out, " {} = ", name)?; - self.write_expr(handle, ctx)?; - writeln!(self.out, ";")?; - self.cached_expressions.insert(handle, name); + self.write_named_expr(handle, name, ctx)?; } } } @@ -1491,7 +1486,7 @@ impl<'a, W: Write> Writer<'a, W> { let result = self.module.functions[function].result.as_ref().unwrap(); self.write_type(result.ty)?; write!(self.out, " {} = ", name)?; - self.cached_expressions.insert(expr, name); + self.named_expressions.insert(expr, name); } write!(self.out, "{}(", &self.names[&NameKey::Function(function)])?; self.write_slice(arguments, |this, _, arg| this.write_expr(*arg, ctx))?; @@ -1507,10 +1502,11 @@ impl<'a, W: Write> Writer<'a, W> { /// # Notes /// Doesn't add any newlines or leading/trailing spaces fn write_expr(&mut self, expr: Handle, ctx: &FunctionCtx<'_>) -> BackendResult { - if let Some(name) = self.cached_expressions.get(&expr) { + if let Some(name) = self.named_expressions.get(&expr) { write!(self.out, "{}", name)?; return Ok(()); } + match ctx.expressions[expr] { // `Access` is applied to arrays, vectors and matrices and is written as indexing Expression::Access { base, index } => { @@ -2114,6 +2110,34 @@ impl<'a, W: Write> Writer<'a, W> { Ok(()) } + fn write_named_expr( + &mut self, + handle: Handle, + name: String, + ctx: &FunctionCtx, + ) -> BackendResult { + match ctx.info[handle].ty { + TypeResolution::Handle(ty_handle) => match self.module.types[ty_handle].inner { + TypeInner::Struct { .. } => { + let ty_name = &self.names[&NameKey::Type(ty_handle)]; + write!(self.out, "{}", ty_name)?; + } + _ => { + self.write_type(ty_handle)?; + } + }, + TypeResolution::Value(ref inner) => { + self.write_value_type(inner)?; + } + } + write!(self.out, " {} = ", name)?; + self.write_expr(handle, ctx)?; + writeln!(self.out, ";")?; + self.named_expressions.insert(handle, name); + + Ok(()) + } + /// Helper method used to produce the reflection info that's returned to the user /// /// It takes an iterator of [`Function`](crate::Function) references instead of diff --git a/src/back/msl/mod.rs b/src/back/msl/mod.rs index 54cfd91ab6..738eb9c93b 100644 --- a/src/back/msl/mod.rs +++ b/src/back/msl/mod.rs @@ -77,7 +77,7 @@ pub struct PerStageResources { /// The slot of a buffer that contains an array of `u32`, /// one for the size of each bound buffer that contains a runtime array, - /// in order of [`GlobalVariable`] declarations. + /// in order of [`crate::GlobalVariable`] declarations. #[cfg_attr(feature = "deserialize", serde(default))] pub sizes_buffer: Option, } diff --git a/src/back/wgsl/writer.rs b/src/back/wgsl/writer.rs index 417fbe585b..488d0256b0 100644 --- a/src/back/wgsl/writer.rs +++ b/src/back/wgsl/writer.rs @@ -4,11 +4,10 @@ use crate::{ proc::{EntryPointIndex, NameKey, Namer, TypeResolution}, valid::{FunctionInfo, ModuleInfo}, Arena, ArraySize, Binding, Constant, ConstantInner, Expression, FastHashMap, Function, - GlobalVariable, Handle, ImageClass, ImageDimension, Interpolation, Module, SampleLevel, - Sampling, ScalarKind, ScalarValue, ShaderStage, Statement, StorageClass, StorageFormat, - StructMember, Type, TypeInner, + GlobalVariable, Handle, ImageClass, ImageDimension, Interpolation, LocalVariable, Module, + SampleLevel, Sampling, ScalarKind, ScalarValue, ShaderStage, Statement, StorageClass, + StorageFormat, StructMember, Type, TypeInner, }; -use bit_set::BitSet; use std::fmt::Write; const INDENT: &str = " "; @@ -53,13 +52,25 @@ struct FunctionCtx<'a> { info: &'a FunctionInfo, /// The expression arena of the current function being written expressions: &'a Arena, + /// Map of expressions that have associated variable names + named_expressions: &'a crate::NamedExpressions, +} + +impl<'a> FunctionCtx<'_> { + /// Helper method that generates a [`NameKey`](crate::proc::NameKey) for a local in the current function + fn name_key(&self, local: Handle) -> NameKey { + match self.ty { + FunctionType::Function(handle) => NameKey::FunctionLocal(handle, local), + FunctionType::EntryPoint(idx) => NameKey::EntryPointLocal(idx, local), + } + } } pub struct Writer { out: W, names: FastHashMap, namer: Namer, - named_expressions: BitSet, + named_expressions: crate::NamedExpressions, ep_results: Vec<(ShaderStage, Handle)>, } @@ -69,7 +80,7 @@ impl Writer { out, names: FastHashMap::default(), namer: Namer::default(), - named_expressions: BitSet::new(), + named_expressions: crate::NamedExpressions::default(), ep_results: vec![], } } @@ -78,6 +89,7 @@ impl Writer { self.names.clear(); self.namer.reset(module, RESERVED, &[], &mut self.names); self.named_expressions.clear(); + self.ep_results.clear(); } pub fn write(&mut self, module: &Module, info: &ModuleInfo) -> BackendResult { @@ -128,6 +140,7 @@ impl Writer { ty: FunctionType::Function(handle), info: fun_info, expressions: &function.expressions, + named_expressions: &function.named_expressions, }; // Write the function @@ -154,6 +167,7 @@ impl Writer { ty: FunctionType::EntryPoint(index as u16), info: &info.get_entry_point(index), expressions: &ep.function.expressions, + named_expressions: &ep.function.named_expressions, }; self.write_function(&module, &ep.function, &func_ctx)?; @@ -271,11 +285,7 @@ impl Writer { // Write the local name // The leading space is important - let name_key = match func_ctx.ty { - FunctionType::Function(func_handle) => NameKey::FunctionLocal(func_handle, handle), - FunctionType::EntryPoint(idx) => NameKey::EntryPointLocal(idx, handle), - }; - write!(self.out, "var {}: ", self.names[&name_key])?; + write!(self.out, "var {}: ", self.names[&func_ctx.name_key(handle)])?; // Write the local type self.write_type(&module, local.ty)?; @@ -570,6 +580,21 @@ impl Writer { match *stmt { Statement::Emit(ref range) => { for handle in range.clone() { + if let Some(name) = func_ctx.named_expressions.get(&handle) { + write!(self.out, "{}", INDENT.repeat(indent))?; + let sanitized_name = self.namer.call_unique(name); + self.start_named_expr(module, handle, &func_ctx, &sanitized_name)?; + self.write_expr(module, handle, &func_ctx)?; + writeln!(self.out, ";")?; + + // Front end provides names for all variables at the start of writing. + // But we write them to step by step. We need to recache them. + // Otherwise, we could accidentally write variable name instead of full expression. + // Also, we use sanitized names! It defense backend from generating variable with name from reserved keywords. + self.named_expressions.insert(handle, sanitized_name); + continue; + } + let expr = &func_ctx.expressions[handle]; let min_ref_count = expr.bake_ref_count(); // Forcefully creating baking expressions in some cases to help with readability @@ -581,10 +606,8 @@ impl Writer { }; if min_ref_count <= func_ctx.info[handle].ref_count || required_baking_expr { write!(self.out, "{}", INDENT.repeat(indent))?; - self.start_baking_expr(module, handle, &func_ctx)?; - self.write_expr(module, handle, &func_ctx)?; + self.write_baking_expr(module, handle, &func_ctx)?; writeln!(self.out, ";")?; - self.named_expressions.insert(handle.index()); } } } @@ -654,8 +677,7 @@ impl Writer { } => { write!(self.out, "{}", INDENT.repeat(indent))?; if let Some(expr) = result { - self.start_baking_expr(module, expr, &func_ctx)?; - self.named_expressions.insert(expr.index()); + self.write_baking_expr(module, expr, &func_ctx)?; } let func_name = &self.names[&NameKey::Function(function)]; write!(self.out, "{}(", func_name)?; @@ -793,33 +815,23 @@ impl Writer { Ok(()) } - fn start_baking_expr( + fn start_named_expr( &mut self, module: &Module, handle: Handle, - context: &FunctionCtx, + func_ctx: &FunctionCtx, + name: &str, ) -> BackendResult { // Write variable name - write!(self.out, "let {}{}: ", BAKE_PREFIX, handle.index())?; - let ty = &context.info[handle].ty; + write!(self.out, "let {}: ", name)?; + let ty = &func_ctx.info[handle].ty; // Write variable type match *ty { - TypeResolution::Handle(ty_handle) => { - self.write_type(module, ty_handle)?; + TypeResolution::Handle(handle) => { + self.write_type(module, handle)?; } - TypeResolution::Value(crate::TypeInner::Scalar { kind, .. }) => { - write!(self.out, "{}", scalar_kind_str(kind))?; - } - TypeResolution::Value(crate::TypeInner::Vector { size, kind, .. }) => { - write!( - self.out, - "vec{}<{}>", - vector_size_str(size), - scalar_kind_str(kind), - )?; - } - _ => { - return Err(Error::Unimplemented(format!("start_baking_expr {:?}", ty))); + TypeResolution::Value(ref inner) => { + self.write_value_type(module, inner)?; } } @@ -827,6 +839,20 @@ impl Writer { Ok(()) } + fn write_baking_expr( + &mut self, + module: &Module, + handle: Handle, + func_ctx: &FunctionCtx, + ) -> BackendResult { + let name = format!("{}{}", BAKE_PREFIX, handle.index()); + self.start_named_expr(module, handle, func_ctx, &name)?; + self.write_expr(module, handle, func_ctx)?; + self.named_expressions.insert(handle, name); + + Ok(()) + } + /// Helper method to write expressions /// /// # Notes @@ -837,13 +863,13 @@ impl Writer { expr: Handle, func_ctx: &FunctionCtx<'_>, ) -> BackendResult { - let expression = &func_ctx.expressions[expr]; - - if self.named_expressions.contains(expr.index()) { - write!(self.out, "{}{}", BAKE_PREFIX, expr.index())?; + if let Some(name) = self.named_expressions.get(&expr) { + write!(self.out, "{}", name)?; return Ok(()); } + let expression = &func_ctx.expressions[expr]; + match *expression { Expression::Constant(constant) => self.write_constant(module, constant)?, Expression::Compose { ty, ref components } => { @@ -1110,13 +1136,7 @@ impl Writer { } Expression::Load { pointer } => self.write_expr(module, pointer, func_ctx)?, Expression::LocalVariable(handle) => { - let name_key = match func_ctx.ty { - FunctionType::Function(func_handle) => { - NameKey::FunctionLocal(func_handle, handle) - } - FunctionType::EntryPoint(idx) => NameKey::EntryPointLocal(idx, handle), - }; - write!(self.out, "{}", self.names[&name_key])? + write!(self.out, "{}", self.names[&func_ctx.name_key(handle)])? } Expression::ArrayLength(expr) => { write!(self.out, "arrayLength(")?; @@ -1273,10 +1293,8 @@ impl Writer { write!(self.out, ")")? } - Expression::Call(function) => { - let func_name = &self.names[&NameKey::Function(function)]; - write!(self.out, "{}(", func_name)? - } + // Nothing to do here, since call expression already cached + Expression::Call(_) => {} } Ok(()) diff --git a/src/front/glsl/parser.rs b/src/front/glsl/parser.rs index 81439e30e6..d97333dabd 100644 --- a/src/front/glsl/parser.rs +++ b/src/front/glsl/parser.rs @@ -630,6 +630,7 @@ impl<'source, 'program, 'options> Parser<'source, 'program, 'options> { name: Some(name), result, expressions, + named_expressions: crate::FastHashMap::default(), local_variables, arguments, body, diff --git a/src/front/spv/function.rs b/src/front/spv/function.rs index 47dd75b195..7c05546543 100644 --- a/src/front/spv/function.rs +++ b/src/front/spv/function.rs @@ -28,7 +28,7 @@ pub enum Terminator { /// /// switch(SELECTOR) { /// case TARGET_LITERAL#: { - /// TARGET_BLOCK# + /// TARGET_BLOCK# /// } /// default: { /// DEFAULT @@ -90,6 +90,7 @@ impl> super::Parser { }, local_variables: Arena::new(), expressions: self.make_expression_storage(), + named_expressions: crate::FastHashMap::default(), body: Vec::new(), } }; @@ -194,6 +195,7 @@ impl> super::Parser { result: None, local_variables: Arena::new(), expressions: Arena::new(), + named_expressions: crate::FastHashMap::default(), body: Vec::new(), }; diff --git a/src/front/wgsl/mod.rs b/src/front/wgsl/mod.rs index cc522b41fb..caabe96734 100644 --- a/src/front/wgsl/mod.rs +++ b/src/front/wgsl/mod.rs @@ -589,6 +589,7 @@ struct StatementContext<'input, 'temp, 'out> { typifier: &'temp mut super::Typifier, variables: &'out mut Arena, expressions: &'out mut Arena, + named_expressions: &'out mut FastHashMap, String>, types: &'out mut Arena, constants: &'out mut Arena, global_vars: &'out Arena, @@ -603,6 +604,7 @@ impl<'a, 'temp> StatementContext<'a, 'temp, '_> { typifier: self.typifier, variables: self.variables, expressions: self.expressions, + named_expressions: self.named_expressions, types: self.types, constants: self.constants, global_vars: self.global_vars, @@ -2563,6 +2565,9 @@ impl Parser { } block.extend(emitter.finish(context.expressions)); context.lookup_ident.insert(name, expr_id); + context + .named_expressions + .insert(expr_id, String::from(name)); } "var" => { enum Init { @@ -2985,11 +2990,13 @@ impl Parser { result, local_variables: Arena::new(), expressions, + named_expressions: crate::NamedExpressions::default(), body: Vec::new(), }; // read body let mut typifier = super::Typifier::new(); + let mut named_expressions = crate::FastHashMap::default(); fun.body = self.parse_block( lexer, StatementContext { @@ -2997,6 +3004,7 @@ impl Parser { typifier: &mut typifier, variables: &mut fun.local_variables, expressions: &mut fun.expressions, + named_expressions: &mut named_expressions, types: &mut module.types, constants: &mut module.constants, global_vars: &module.global_variables, @@ -3010,6 +3018,9 @@ impl Parser { // done self.scopes.pop(); + // Set named expressions after block parsing ends + fun.named_expressions = named_expressions; + Ok((fun, fun_name)) } diff --git a/src/lib.rs b/src/lib.rs index 9dc6c0b229..ad48cd4e7a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,6 +151,9 @@ pub type FastHashMap = HashMap> /// Hash set that is faster but not resilient to DoS attacks. pub type FastHashSet = HashSet>; +/// Map of expressions that have associated variable names +pub(crate) type NamedExpressions = FastHashMap, String>; + /// Early fragment tests. In a standard situation if a driver determines that it is possible to /// switch on early depth test it will. Typical situations when early depth test is switched off: /// - Calling ```discard``` in a shader. @@ -1043,6 +1046,8 @@ pub struct Function { pub local_variables: Arena, /// Expressions used inside this function. pub expressions: Arena, + /// Map of expressions that have associated variable names + pub named_expressions: NamedExpressions, /// Block of instructions comprising the body of the function. pub body: Block, } diff --git a/src/proc/namer.rs b/src/proc/namer.rs index 5e8ba61329..c339c4cf95 100644 --- a/src/proc/namer.rs +++ b/src/proc/namer.rs @@ -48,6 +48,22 @@ impl Namer { base } + /// Helper function that return unique name without cache update. + /// This function should be used **after** [`Namer`](crate::proc::Namer) initialization by [`reset`](Self::reset()) function. + pub fn call_unique(&mut self, string: &str) -> String { + let base = self.sanitize(string); + match self.unique.entry(base) { + Entry::Occupied(mut e) => { + *e.get_mut() += 1; + format!("{}{}", e.key(), e.get()) + } + Entry::Vacant(e) => { + let name = e.key().to_string(); + name + } + } + } + pub fn call(&mut self, label_raw: &str) -> String { let base = self.sanitize(label_raw); match self.unique.entry(base) { diff --git a/tests/out/access.wgsl b/tests/out/access.wgsl index dfbbb1b7dd..9a75615ab4 100644 --- a/tests/out/access.wgsl +++ b/tests/out/access.wgsl @@ -9,5 +9,9 @@ var bar: [[access(read_write)]] Bar; [[stage(vertex)]] fn foo([[builtin(vertex_index)]] vi: u32) -> [[builtin(position)]] vec4 { - return vec4(vec4(array(bar.data[(arrayLength(&bar.data) - 1u)], i32(bar.matrix[3u].x), 3, 4, 5)[vi])); + let b: f32 = bar.matrix[3u].x; + let a: i32 = bar.data[(arrayLength(&bar.data) - 1u)]; + let array: array = array(a, i32(b), 3, 4, 5); + let value: i32 = array[vi]; + return vec4(vec4(value)); } diff --git a/tests/out/boids.Compute.glsl b/tests/out/boids.Compute.glsl index e54432d5cc..9f32dbf808 100644 --- a/tests/out/boids.Compute.glsl +++ b/tests/out/boids.Compute.glsl @@ -37,11 +37,12 @@ void main() { vec2 pos1; vec2 vel1; uint i = 0u; - if((global_invocation_id.x >= 1500u)) { + uint index = global_invocation_id.x; + if((index >= 1500u)) { return; } - vPos = _group_0_binding_1.particles[global_invocation_id.x].pos; - vVel = _group_0_binding_1.particles[global_invocation_id.x].vel; + vPos = _group_0_binding_1.particles[index].pos; + vVel = _group_0_binding_1.particles[index].vel; cMass = vec2(0.0, 0.0); cVel = vec2(0.0, 0.0); colVel = vec2(0.0, 0.0); @@ -49,7 +50,7 @@ void main() { if((i >= 1500u)) { break; } - if((i == global_invocation_id.x)) { + if((i == index)) { continue; } pos1 = _group_0_binding_1.particles[i].pos; @@ -88,8 +89,8 @@ void main() { if((vPos.y > 1.0)) { vPos.y = -1.0; } - _group_0_binding_2.particles[global_invocation_id.x].pos = vPos; - _group_0_binding_2.particles[global_invocation_id.x].vel = vVel; + _group_0_binding_2.particles[index].pos = vPos; + _group_0_binding_2.particles[index].vel = vVel; return; } diff --git a/tests/out/boids.wgsl b/tests/out/boids.wgsl index b1437ab8f8..a3591c6a71 100644 --- a/tests/out/boids.wgsl +++ b/tests/out/boids.wgsl @@ -41,11 +41,12 @@ fn main([[builtin(global_invocation_id)]] global_invocation_id: vec3) { var vel1: vec2; var i: u32 = 0u; - if ((global_invocation_id.x >= NUM_PARTICLES)) { + let index: u32 = global_invocation_id.x; + if ((index >= NUM_PARTICLES)) { return; } - vPos = particlesSrc.particles[global_invocation_id.x].pos; - vVel = particlesSrc.particles[global_invocation_id.x].vel; + vPos = particlesSrc.particles[index].pos; + vVel = particlesSrc.particles[index].vel; cMass = vec2(0.0, 0.0); cVel = vec2(0.0, 0.0); colVel = vec2(0.0, 0.0); @@ -53,7 +54,7 @@ fn main([[builtin(global_invocation_id)]] global_invocation_id: vec3) { if ((i >= NUM_PARTICLES)) { break; } - if ((i == global_invocation_id.x)) { + if ((i == index)) { continue; } pos1 = particlesSrc.particles[i].pos; @@ -94,7 +95,7 @@ fn main([[builtin(global_invocation_id)]] global_invocation_id: vec3) { if ((vPos.y > 1.0)) { vPos.y = -1.0; } - particlesDst.particles[global_invocation_id.x].pos = vPos; - particlesDst.particles[global_invocation_id.x].vel = vVel; + particlesDst.particles[index].pos = vPos; + particlesDst.particles[index].vel = vVel; return; } diff --git a/tests/out/collatz.ron b/tests/out/collatz.ron index 7fe6a38eff..df144444c9 100644 --- a/tests/out/collatz.ron +++ b/tests/out/collatz.ron @@ -181,6 +181,7 @@ pointer: 5, ), ], + named_expressions: {}, body: [ Store( pointer: 3, @@ -320,6 +321,7 @@ ), Call(1), ], + named_expressions: {}, body: [ Emit(( start: 2, diff --git a/tests/out/image.wgsl b/tests/out/image.wgsl index 4d1ead8261..f7e682c93f 100644 --- a/tests/out/image.wgsl +++ b/tests/out/image.wgsl @@ -23,41 +23,42 @@ var image_2d_depth: texture_depth_2d; [[stage(compute), workgroup_size(16, 1, 1)]] fn main([[builtin(local_invocation_id)]] local_id: vec3) { - let _e3: vec2 = textureDimensions(image_src); - let _e10: vec2 = ((_e3 * vec2(local_id.xy)) % vec2(10, 20)); - let _e11: vec4 = textureLoad(image_src, _e10); - textureStore(image_dst, _e10.x, _e11); + let dim: vec2 = textureDimensions(image_src); + let itc: vec2 = ((dim * vec2(local_id.xy)) % vec2(10, 20)); + let value: vec4 = textureLoad(image_src, itc); + textureStore(image_dst, itc.x, value); return; } [[stage(vertex)]] fn queries() -> [[builtin(position)]] vec4 { - let _e9: i32 = textureDimensions(image_1d); - let _e10: vec2 = textureDimensions(image_2d); - let _e11: i32 = textureNumLevels(image_2d); - let _e13: vec2 = textureDimensions(image_2d, 1); - let _e14: vec2 = textureDimensions(image_2d_array); - let _e15: i32 = textureNumLevels(image_2d_array); - let _e17: vec2 = textureDimensions(image_2d_array, 1); - let _e18: i32 = textureNumLayers(image_2d_array); - let _e19: vec3 = textureDimensions(image_cube); - let _e20: i32 = textureNumLevels(image_cube); - let _e22: vec3 = textureDimensions(image_cube, 1); - let _e23: vec3 = textureDimensions(image_cube_array); - let _e24: i32 = textureNumLevels(image_cube_array); - let _e26: vec3 = textureDimensions(image_cube_array, 1); - let _e27: i32 = textureNumLayers(image_cube_array); - let _e28: vec3 = textureDimensions(image_3d); - let _e29: i32 = textureNumLevels(image_3d); - let _e31: vec3 = textureDimensions(image_3d, 1); - let _e32: i32 = textureNumSamples(image_aa); - return vec4(f32(((((((((((((((((((_e9 + _e10.y) + _e13.y) + _e14.y) + _e17.y) + _e18) + _e19.y) + _e22.y) + _e23.y) + _e26.y) + _e27) + _e28.z) + _e31.z) + _e32) + _e11) + _e15) + _e29) + _e20) + _e24))); + let dim_1d: i32 = textureDimensions(image_1d); + let dim_2d: vec2 = textureDimensions(image_2d); + let num_levels_2d: i32 = textureNumLevels(image_2d); + let dim_2d_lod: vec2 = textureDimensions(image_2d, 1); + let dim_2d_array: vec2 = textureDimensions(image_2d_array); + let num_levels_2d_array: i32 = textureNumLevels(image_2d_array); + let dim_2d_array_lod: vec2 = textureDimensions(image_2d_array, 1); + let num_layers_2d: i32 = textureNumLayers(image_2d_array); + let dim_cube: vec3 = textureDimensions(image_cube); + let num_levels_cube: i32 = textureNumLevels(image_cube); + let dim_cube_lod: vec3 = textureDimensions(image_cube, 1); + let dim_cube_array: vec3 = textureDimensions(image_cube_array); + let num_levels_cube_array: i32 = textureNumLevels(image_cube_array); + let dim_cube_array_lod: vec3 = textureDimensions(image_cube_array, 1); + let num_layers_cube: i32 = textureNumLayers(image_cube_array); + let dim_3d: vec3 = textureDimensions(image_3d); + let num_levels_3d: i32 = textureNumLevels(image_3d); + let dim_3d_lod: vec3 = textureDimensions(image_3d, 1); + let num_samples_aa: i32 = textureNumSamples(image_aa); + let sum: i32 = ((((((((((((((((((dim_1d + dim_2d.y) + dim_2d_lod.y) + dim_2d_array.y) + dim_2d_array_lod.y) + num_layers_2d) + dim_cube.y) + dim_cube_lod.y) + dim_cube_array.y) + dim_cube_array_lod.y) + num_layers_cube) + dim_3d.z) + dim_3d_lod.z) + num_samples_aa) + num_levels_2d) + num_levels_2d_array) + num_levels_3d) + num_levels_cube) + num_levels_cube_array); + return vec4(f32(sum)); } [[stage(fragment)]] fn sample_comparison() -> [[location(0)]] f32 { - let _e12: vec2 = vec2(0.5); - let _e14: f32 = textureSampleCompare(image_2d_depth, sampler_cmp, _e12, 0.5); - let _e15: f32 = textureSampleCompareLevel(image_2d_depth, sampler_cmp, _e12, 0.5); - return (_e14 + _e15); + let tc: vec2 = vec2(0.5); + let s2d_depth: f32 = textureSampleCompare(image_2d_depth, sampler_cmp, tc, 0.5); + let s2d_depth_level: f32 = textureSampleCompareLevel(image_2d_depth, sampler_cmp, tc, 0.5); + return (s2d_depth + s2d_depth_level); } diff --git a/tests/out/interface.wgsl b/tests/out/interface.wgsl index 90b76ff7bc..74dbe30be2 100644 --- a/tests/out/interface.wgsl +++ b/tests/out/interface.wgsl @@ -11,12 +11,15 @@ struct FragmentOutput { [[stage(vertex)]] fn vertex([[builtin(vertex_index)]] vertex_index: u32, [[builtin(instance_index)]] instance_index: u32, [[location(10)]] color1: u32) -> VertexOutput { - return VertexOutput(vec4(1.0), f32(((vertex_index + instance_index) + color1))); + let tmp: u32 = ((vertex_index + instance_index) + color1); + return VertexOutput(vec4(1.0), f32(tmp)); } [[stage(fragment)]] fn fragment(in: VertexOutput, [[builtin(front_facing)]] front_facing: bool, [[builtin(sample_index)]] sample_index: u32, [[builtin(sample_mask)]] sample_mask1: u32) -> FragmentOutput { - return FragmentOutput(in.varying, (sample_mask1 & (1u << sample_index)), select(0.0, 1.0, front_facing)); + let mask: u32 = (sample_mask1 & (1u << sample_index)); + let color2: f32 = select(0.0, 1.0, front_facing); + return FragmentOutput(in.varying, mask, color2); } [[stage(compute), workgroup_size(1, 1, 1)]] diff --git a/tests/out/operators.wgsl b/tests/out/operators.wgsl index aad7a5c03a..cacefc7242 100644 --- a/tests/out/operators.wgsl +++ b/tests/out/operators.wgsl @@ -1,5 +1,7 @@ fn splat() -> vec4 { - return ((((vec2(1.0) + vec2(2.0)) - vec2(3.0)) / vec2(4.0)).xyxy + vec4((vec4(5) % vec4(2)))); + let a: vec2 = (((vec2(1.0) + vec2(2.0)) - vec2(3.0)) / vec2(4.0)); + let b: vec4 = (vec4(5) % vec4(2)); + return (a.xyxy + vec4(b)); } fn unary() -> i32 { diff --git a/tests/out/quad.Fragment.glsl b/tests/out/quad.Fragment.glsl index ff24336cf6..4cb26d2a48 100644 --- a/tests/out/quad.Fragment.glsl +++ b/tests/out/quad.Fragment.glsl @@ -14,11 +14,12 @@ layout(location = 0) out vec4 _fs2p_location0; void main() { vec2 uv2 = _vs2fs_location0; - vec4 _expr4 = texture(_group_0_binding_0, vec2(uv2)); - if((_expr4.w == 0.0)) { + vec4 color = texture(_group_0_binding_0, vec2(uv2)); + if((color.w == 0.0)) { discard; } - _fs2p_location0 = (_expr4.w * _expr4); + vec4 premultiplied = (color.w * color); + _fs2p_location0 = premultiplied; return; } diff --git a/tests/out/quad.wgsl b/tests/out/quad.wgsl index b853f09e33..63d94b5a3c 100644 --- a/tests/out/quad.wgsl +++ b/tests/out/quad.wgsl @@ -17,9 +17,10 @@ fn main([[location(0)]] pos: vec2, [[location(1)]] uv1: vec2) -> Verte [[stage(fragment)]] fn main1([[location(0), interpolate(perspective)]] uv2: vec2) -> [[location(0)]] vec4 { - let _e4: vec4 = textureSample(u_texture, u_sampler, uv2); - if ((_e4.w == 0.0)) { + let color: vec4 = textureSample(u_texture, u_sampler, uv2); + if ((color.w == 0.0)) { discard; } - return (_e4.w * _e4); + let premultiplied: vec4 = (color.w * color); + return premultiplied; } diff --git a/tests/out/shadow.Fragment.glsl b/tests/out/shadow.Fragment.glsl index df9f71c644..fa7ab0ca38 100644 --- a/tests/out/shadow.Fragment.glsl +++ b/tests/out/shadow.Fragment.glsl @@ -24,7 +24,9 @@ float fetch_shadow(uint light_id, vec4 homogeneous_coords) { if((homogeneous_coords.w <= 0.0)) { return 1.0; } - float _expr26 = textureGrad(_group_0_binding_2, vec4((((homogeneous_coords.xy * vec2(0.5, -0.5)) / vec2(homogeneous_coords.w)) + vec2(0.5, 0.5)), int(light_id), (homogeneous_coords.z / homogeneous_coords.w)), vec2(0, 0), vec2(0,0)); + vec2 flip_correction = vec2(0.5, -0.5); + vec2 light_local = (((homogeneous_coords.xy * flip_correction) / vec2(homogeneous_coords.w)) + vec2(0.5, 0.5)); + float _expr26 = textureGrad(_group_0_binding_2, vec4(light_local, int(light_id), (homogeneous_coords.z / homogeneous_coords.w)), vec2(0, 0), vec2(0,0)); return _expr26; } @@ -33,13 +35,16 @@ void main() { vec4 position = _vs2fs_location1; vec3 color1 = vec3(0.05, 0.05, 0.05); uint i = 0u; + vec3 normal = normalize(raw_normal); while(true) { if((i >= min(_group_0_binding_0.num_lights.x, 10u))) { break; } - Light _expr21 = _group_0_binding_1.data[i]; - float _expr25 = fetch_shadow(i, (_expr21.proj * position)); - color1 = (color1 + ((_expr25 * max(0.0, dot(normalize(raw_normal), normalize((_expr21.pos.xyz - position.xyz))))) * _expr21.color.xyz)); + Light light = _group_0_binding_1.data[i]; + float _expr25 = fetch_shadow(i, (light.proj * position)); + vec3 light_dir = normalize((light.pos.xyz - position.xyz)); + float diffuse = max(0.0, dot(normal, light_dir)); + color1 = (color1 + ((_expr25 * diffuse) * light.color.xyz)); i = (i + 1u); } _fs2p_location0 = vec4(color1, 1.0); diff --git a/tests/out/shadow.ron b/tests/out/shadow.ron index fd91f99af8..9ea27083a4 100644 --- a/tests/out/shadow.ron +++ b/tests/out/shadow.ron @@ -1054,6 +1054,7 @@ depth_ref: Some(69), ), ], + named_expressions: {}, body: [ Emit(( start: 48, @@ -1443,6 +1444,7 @@ ], ), ], + named_expressions: {}, body: [ Loop( body: [ @@ -1550,6 +1552,7 @@ pointer: 5, ), ], + named_expressions: {}, body: [ Store( pointer: 2, diff --git a/tests/out/shadow.wgsl b/tests/out/shadow.wgsl index c5ca9f0a55..5325cf9fa9 100644 --- a/tests/out/shadow.wgsl +++ b/tests/out/shadow.wgsl @@ -30,7 +30,9 @@ fn fetch_shadow(light_id: u32, homogeneous_coords: vec4) -> f32 { if ((homogeneous_coords.w <= 0.0)) { return 1.0; } - let _e26: f32 = textureSampleCompareLevel(t_shadow, sampler_shadow, (((homogeneous_coords.xy * vec2(0.5, -0.5)) / vec2(homogeneous_coords.w)) + vec2(0.5, 0.5)), i32(light_id), (homogeneous_coords.z / homogeneous_coords.w)); + let flip_correction: vec2 = vec2(0.5, -0.5); + let light_local: vec2 = (((homogeneous_coords.xy * flip_correction) / vec2(homogeneous_coords.w)) + vec2(0.5, 0.5)); + let _e26: f32 = textureSampleCompareLevel(t_shadow, sampler_shadow, light_local, i32(light_id), (homogeneous_coords.z / homogeneous_coords.w)); return _e26; } @@ -39,13 +41,16 @@ fn fs_main([[location(0), interpolate(perspective)]] raw_normal: vec3, [[lo var color1: vec3 = vec3(0.05, 0.05, 0.05); var i: u32 = 0u; + let normal: vec3 = normalize(raw_normal); loop { if ((i >= min(u_globals.num_lights.x, c_max_lights))) { break; } - let _e21: Light = s_lights.data[i]; - let _e25: f32 = fetch_shadow(i, (_e21.proj * position)); - color1 = (color1 + ((_e25 * max(0.0, dot(normalize(raw_normal), normalize((_e21.pos.xyz - position.xyz))))) * _e21.color.xyz)); + let light: Light = s_lights.data[i]; + let _e25: f32 = fetch_shadow(i, (light.proj * position)); + let light_dir: vec3 = normalize((light.pos.xyz - position.xyz)); + let diffuse: f32 = max(0.0, dot(normal, light_dir)); + color1 = (color1 + ((_e25 * diffuse) * light.color.xyz)); continuing { i = (i + 1u); } diff --git a/tests/out/skybox.Vertex.glsl b/tests/out/skybox.Vertex.glsl index 1b7b6167c3..dd00b450e0 100644 --- a/tests/out/skybox.Vertex.glsl +++ b/tests/out/skybox.Vertex.glsl @@ -19,8 +19,10 @@ void main() { int tmp2_; tmp1_ = (int(vertex_index) / 2); tmp2_ = (int(vertex_index) & 1); - vec4 _expr24 = vec4(((float(tmp1_) * 4.0) - 1.0), ((float(tmp2_) * 4.0) - 1.0), 0.0, 1.0); - VertexOutput _tmp_return = VertexOutput(_expr24, (transpose(mat3x3(_group_0_binding_0.view[0].xyz, _group_0_binding_0.view[1].xyz, _group_0_binding_0.view[2].xyz)) * (_group_0_binding_0.proj_inv * _expr24).xyz)); + vec4 pos = vec4(((float(tmp1_) * 4.0) - 1.0), ((float(tmp2_) * 4.0) - 1.0), 0.0, 1.0); + mat3x3 inv_model_view = transpose(mat3x3(_group_0_binding_0.view[0].xyz, _group_0_binding_0.view[1].xyz, _group_0_binding_0.view[2].xyz)); + vec4 unprojected = (_group_0_binding_0.proj_inv * pos); + VertexOutput _tmp_return = VertexOutput(pos, (inv_model_view * unprojected.xyz)); gl_Position = _tmp_return.position; _vs2fs_location0 = _tmp_return.uv; return; diff --git a/tests/out/skybox.wgsl b/tests/out/skybox.wgsl index a0e0112e9c..3df95a61c7 100644 --- a/tests/out/skybox.wgsl +++ b/tests/out/skybox.wgsl @@ -23,8 +23,10 @@ fn vs_main([[builtin(vertex_index)]] vertex_index: u32) -> VertexOutput { tmp1_ = (i32(vertex_index) / 2); tmp2_ = (i32(vertex_index) & 1); - let _e24: vec4 = vec4(((f32(tmp1_) * 4.0) - 1.0), ((f32(tmp2_) * 4.0) - 1.0), 0.0, 1.0); - return VertexOutput(_e24, (transpose(mat3x3(r_data.view[0].xyz, r_data.view[1].xyz, r_data.view[2].xyz)) * (r_data.proj_inv * _e24).xyz)); + let pos: vec4 = vec4(((f32(tmp1_) * 4.0) - 1.0), ((f32(tmp2_) * 4.0) - 1.0), 0.0, 1.0); + let inv_model_view: mat3x3 = transpose(mat3x3(r_data.view[0].xyz, r_data.view[1].xyz, r_data.view[2].xyz)); + let unprojected: vec4 = (r_data.proj_inv * pos); + return VertexOutput(pos, (inv_model_view * unprojected.xyz)); } [[stage(fragment)]] diff --git a/tests/out/standard.Fragment.glsl b/tests/out/standard.Fragment.glsl index d39147bfb5..54d962ce9e 100644 --- a/tests/out/standard.Fragment.glsl +++ b/tests/out/standard.Fragment.glsl @@ -6,10 +6,10 @@ layout(location = 0) out vec4 _fs2p_location0; void main() { vec4 foo = gl_FragCoord; - vec4 _expr1 = dFdx(foo); - vec4 _expr2 = dFdy(foo); - vec4 _expr3 = fwidth(foo); - _fs2p_location0 = ((_expr1 + _expr2) * _expr3); + vec4 x = dFdx(foo); + vec4 y = dFdy(foo); + vec4 z = fwidth(foo); + _fs2p_location0 = ((x + y) * z); return; } diff --git a/tests/out/standard.wgsl b/tests/out/standard.wgsl index 90f74e8715..3aa0277dfa 100644 --- a/tests/out/standard.wgsl +++ b/tests/out/standard.wgsl @@ -1,7 +1,7 @@ [[stage(fragment)]] fn derivatives([[builtin(position)]] foo: vec4) -> [[location(0)]] vec4 { - let _e1: vec4 = dpdx(foo); - let _e2: vec4 = dpdy(foo); - let _e3: vec4 = fwidth(foo); - return ((_e1 + _e2) * _e3); + let x: vec4 = dpdx(foo); + let y: vec4 = dpdy(foo); + let z: vec4 = fwidth(foo); + return ((x + y) * z); }