Add ability to generate named expressions

This commit is contained in:
Gordon-F
2021-06-02 18:28:41 +03:00
committed by Dzmitry Malyshau
parent 98769c642d
commit 90c2cf6aa6
24 changed files with 263 additions and 153 deletions

View File

@@ -194,9 +194,11 @@ struct FunctionCtx<'a> {
info: &'a FunctionInfo,
/// The expression arena of the current function being written
expressions: &'a Arena<Expression>,
/// 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<LocalVariable>) -> 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<NameKey, String>,
@@ -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<Handle<Expression>, 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<Expression>, 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<Expression>,
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

View File

@@ -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<Slot>,
}

View File

@@ -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<Expression>,
/// 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<LocalVariable>) -> NameKey {
match self.ty {
FunctionType::Function(handle) => NameKey::FunctionLocal(handle, local),
FunctionType::EntryPoint(idx) => NameKey::EntryPointLocal(idx, local),
}
}
}
pub struct Writer<W> {
out: W,
names: FastHashMap<NameKey, String>,
namer: Namer,
named_expressions: BitSet,
named_expressions: crate::NamedExpressions,
ep_results: Vec<(ShaderStage, Handle<Type>)>,
}
@@ -69,7 +80,7 @@ impl<W: Write> Writer<W> {
out,
names: FastHashMap::default(),
namer: Namer::default(),
named_expressions: BitSet::new(),
named_expressions: crate::NamedExpressions::default(),
ep_results: vec![],
}
}
@@ -78,6 +89,7 @@ impl<W: Write> Writer<W> {
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<W: Write> Writer<W> {
ty: FunctionType::Function(handle),
info: fun_info,
expressions: &function.expressions,
named_expressions: &function.named_expressions,
};
// Write the function
@@ -154,6 +167,7 @@ impl<W: Write> Writer<W> {
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<W: Write> Writer<W> {
// 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<W: Write> Writer<W> {
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<W: Write> Writer<W> {
};
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<W: Write> Writer<W> {
} => {
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<W: Write> Writer<W> {
Ok(())
}
fn start_baking_expr(
fn start_named_expr(
&mut self,
module: &Module,
handle: Handle<Expression>,
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<W: Write> Writer<W> {
Ok(())
}
fn write_baking_expr(
&mut self,
module: &Module,
handle: Handle<Expression>,
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<W: Write> Writer<W> {
expr: Handle<Expression>,
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<W: Write> Writer<W> {
}
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<W: Write> Writer<W> {
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(())

View File

@@ -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,

View File

@@ -28,7 +28,7 @@ pub enum Terminator {
///
/// switch(SELECTOR) {
/// case TARGET_LITERAL#: {
/// TARGET_BLOCK#
/// TARGET_BLOCK#
/// }
/// default: {
/// DEFAULT
@@ -90,6 +90,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
},
local_variables: Arena::new(),
expressions: self.make_expression_storage(),
named_expressions: crate::FastHashMap::default(),
body: Vec::new(),
}
};
@@ -194,6 +195,7 @@ impl<I: Iterator<Item = u32>> super::Parser<I> {
result: None,
local_variables: Arena::new(),
expressions: Arena::new(),
named_expressions: crate::FastHashMap::default(),
body: Vec::new(),
};

View File

@@ -589,6 +589,7 @@ struct StatementContext<'input, 'temp, 'out> {
typifier: &'temp mut super::Typifier,
variables: &'out mut Arena<crate::LocalVariable>,
expressions: &'out mut Arena<crate::Expression>,
named_expressions: &'out mut FastHashMap<Handle<crate::Expression>, String>,
types: &'out mut Arena<crate::Type>,
constants: &'out mut Arena<crate::Constant>,
global_vars: &'out Arena<crate::GlobalVariable>,
@@ -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))
}

View File

@@ -151,6 +151,9 @@ pub type FastHashMap<K, T> = HashMap<K, T, BuildHasherDefault<fxhash::FxHasher>>
/// Hash set that is faster but not resilient to DoS attacks.
pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<fxhash::FxHasher>>;
/// Map of expressions that have associated variable names
pub(crate) type NamedExpressions = FastHashMap<Handle<Expression>, 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<LocalVariable>,
/// Expressions used inside this function.
pub expressions: Arena<Expression>,
/// Map of expressions that have associated variable names
pub named_expressions: NamedExpressions,
/// Block of instructions comprising the body of the function.
pub body: Block,
}

View File

@@ -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) {

View File

@@ -9,5 +9,9 @@ var<storage> bar: [[access(read_write)]] Bar;
[[stage(vertex)]]
fn foo([[builtin(vertex_index)]] vi: u32) -> [[builtin(position)]] vec4<f32> {
return vec4<f32>(vec4<i32>(array<i32,5>(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<i32,5> = array<i32,5>(a, i32(b), 3, 4, 5);
let value: i32 = array[vi];
return vec4<f32>(vec4<i32>(value));
}

View File

@@ -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;
}

View File

@@ -41,11 +41,12 @@ fn main([[builtin(global_invocation_id)]] global_invocation_id: vec3<u32>) {
var vel1: vec2<f32>;
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<f32>(0.0, 0.0);
cVel = vec2<f32>(0.0, 0.0);
colVel = vec2<f32>(0.0, 0.0);
@@ -53,7 +54,7 @@ fn main([[builtin(global_invocation_id)]] global_invocation_id: vec3<u32>) {
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<u32>) {
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;
}

View File

@@ -181,6 +181,7 @@
pointer: 5,
),
],
named_expressions: {},
body: [
Store(
pointer: 3,
@@ -320,6 +321,7 @@
),
Call(1),
],
named_expressions: {},
body: [
Emit((
start: 2,

View File

@@ -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<u32>) {
let _e3: vec2<i32> = textureDimensions(image_src);
let _e10: vec2<i32> = ((_e3 * vec2<i32>(local_id.xy)) % vec2<i32>(10, 20));
let _e11: vec4<u32> = textureLoad(image_src, _e10);
textureStore(image_dst, _e10.x, _e11);
let dim: vec2<i32> = textureDimensions(image_src);
let itc: vec2<i32> = ((dim * vec2<i32>(local_id.xy)) % vec2<i32>(10, 20));
let value: vec4<u32> = textureLoad(image_src, itc);
textureStore(image_dst, itc.x, value);
return;
}
[[stage(vertex)]]
fn queries() -> [[builtin(position)]] vec4<f32> {
let _e9: i32 = textureDimensions(image_1d);
let _e10: vec2<i32> = textureDimensions(image_2d);
let _e11: i32 = textureNumLevels(image_2d);
let _e13: vec2<i32> = textureDimensions(image_2d, 1);
let _e14: vec2<i32> = textureDimensions(image_2d_array);
let _e15: i32 = textureNumLevels(image_2d_array);
let _e17: vec2<i32> = textureDimensions(image_2d_array, 1);
let _e18: i32 = textureNumLayers(image_2d_array);
let _e19: vec3<i32> = textureDimensions(image_cube);
let _e20: i32 = textureNumLevels(image_cube);
let _e22: vec3<i32> = textureDimensions(image_cube, 1);
let _e23: vec3<i32> = textureDimensions(image_cube_array);
let _e24: i32 = textureNumLevels(image_cube_array);
let _e26: vec3<i32> = textureDimensions(image_cube_array, 1);
let _e27: i32 = textureNumLayers(image_cube_array);
let _e28: vec3<i32> = textureDimensions(image_3d);
let _e29: i32 = textureNumLevels(image_3d);
let _e31: vec3<i32> = textureDimensions(image_3d, 1);
let _e32: i32 = textureNumSamples(image_aa);
return vec4<f32>(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<i32> = textureDimensions(image_2d);
let num_levels_2d: i32 = textureNumLevels(image_2d);
let dim_2d_lod: vec2<i32> = textureDimensions(image_2d, 1);
let dim_2d_array: vec2<i32> = textureDimensions(image_2d_array);
let num_levels_2d_array: i32 = textureNumLevels(image_2d_array);
let dim_2d_array_lod: vec2<i32> = textureDimensions(image_2d_array, 1);
let num_layers_2d: i32 = textureNumLayers(image_2d_array);
let dim_cube: vec3<i32> = textureDimensions(image_cube);
let num_levels_cube: i32 = textureNumLevels(image_cube);
let dim_cube_lod: vec3<i32> = textureDimensions(image_cube, 1);
let dim_cube_array: vec3<i32> = textureDimensions(image_cube_array);
let num_levels_cube_array: i32 = textureNumLevels(image_cube_array);
let dim_cube_array_lod: vec3<i32> = textureDimensions(image_cube_array, 1);
let num_layers_cube: i32 = textureNumLayers(image_cube_array);
let dim_3d: vec3<i32> = textureDimensions(image_3d);
let num_levels_3d: i32 = textureNumLevels(image_3d);
let dim_3d_lod: vec3<i32> = 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>(f32(sum));
}
[[stage(fragment)]]
fn sample_comparison() -> [[location(0)]] f32 {
let _e12: vec2<f32> = vec2<f32>(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<f32> = vec2<f32>(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);
}

View File

@@ -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<f32>(1.0), f32(((vertex_index + instance_index) + color1)));
let tmp: u32 = ((vertex_index + instance_index) + color1);
return VertexOutput(vec4<f32>(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)]]

View File

@@ -1,5 +1,7 @@
fn splat() -> vec4<f32> {
return ((((vec2<f32>(1.0) + vec2<f32>(2.0)) - vec2<f32>(3.0)) / vec2<f32>(4.0)).xyxy + vec4<f32>((vec4<i32>(5) % vec4<i32>(2))));
let a: vec2<f32> = (((vec2<f32>(1.0) + vec2<f32>(2.0)) - vec2<f32>(3.0)) / vec2<f32>(4.0));
let b: vec4<i32> = (vec4<i32>(5) % vec4<i32>(2));
return (a.xyxy + vec4<f32>(b));
}
fn unary() -> i32 {

View File

@@ -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;
}

View File

@@ -17,9 +17,10 @@ fn main([[location(0)]] pos: vec2<f32>, [[location(1)]] uv1: vec2<f32>) -> Verte
[[stage(fragment)]]
fn main1([[location(0), interpolate(perspective)]] uv2: vec2<f32>) -> [[location(0)]] vec4<f32> {
let _e4: vec4<f32> = textureSample(u_texture, u_sampler, uv2);
if ((_e4.w == 0.0)) {
let color: vec4<f32> = textureSample(u_texture, u_sampler, uv2);
if ((color.w == 0.0)) {
discard;
}
return (_e4.w * _e4);
let premultiplied: vec4<f32> = (color.w * color);
return premultiplied;
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -30,7 +30,9 @@ fn fetch_shadow(light_id: u32, homogeneous_coords: vec4<f32>) -> f32 {
if ((homogeneous_coords.w <= 0.0)) {
return 1.0;
}
let _e26: f32 = textureSampleCompareLevel(t_shadow, sampler_shadow, (((homogeneous_coords.xy * vec2<f32>(0.5, -0.5)) / vec2<f32>(homogeneous_coords.w)) + vec2<f32>(0.5, 0.5)), i32(light_id), (homogeneous_coords.z / homogeneous_coords.w));
let flip_correction: vec2<f32> = vec2<f32>(0.5, -0.5);
let light_local: vec2<f32> = (((homogeneous_coords.xy * flip_correction) / vec2<f32>(homogeneous_coords.w)) + vec2<f32>(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<f32>, [[lo
var color1: vec3<f32> = vec3<f32>(0.05, 0.05, 0.05);
var i: u32 = 0u;
let normal: vec3<f32> = 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<f32> = 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);
}

View File

@@ -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;

View File

@@ -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<f32> = vec4<f32>(((f32(tmp1_) * 4.0) - 1.0), ((f32(tmp2_) * 4.0) - 1.0), 0.0, 1.0);
return VertexOutput(_e24, (transpose(mat3x3<f32>(r_data.view[0].xyz, r_data.view[1].xyz, r_data.view[2].xyz)) * (r_data.proj_inv * _e24).xyz));
let pos: vec4<f32> = vec4<f32>(((f32(tmp1_) * 4.0) - 1.0), ((f32(tmp2_) * 4.0) - 1.0), 0.0, 1.0);
let inv_model_view: mat3x3<f32> = transpose(mat3x3<f32>(r_data.view[0].xyz, r_data.view[1].xyz, r_data.view[2].xyz));
let unprojected: vec4<f32> = (r_data.proj_inv * pos);
return VertexOutput(pos, (inv_model_view * unprojected.xyz));
}
[[stage(fragment)]]

View File

@@ -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;
}

View File

@@ -1,7 +1,7 @@
[[stage(fragment)]]
fn derivatives([[builtin(position)]] foo: vec4<f32>) -> [[location(0)]] vec4<f32> {
let _e1: vec4<f32> = dpdx(foo);
let _e2: vec4<f32> = dpdy(foo);
let _e3: vec4<f32> = fwidth(foo);
return ((_e1 + _e2) * _e3);
let x: vec4<f32> = dpdx(foo);
let y: vec4<f32> = dpdy(foo);
let z: vec4<f32> = fwidth(foo);
return ((x + y) * z);
}