mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[glsl-in] Implement MathFunction::Clamp (#1502)
* Implement Clamp function.
* Fix the return error type.
Change `ConstantSolvingError::InvalidMathArg` to `ConstantSolvingError::NotImplemented`
for the clamp function with the input of unimplemented types.
Unimplemented types:
- vec2
- vec3
- vec4
* [glsl-in] Add helpers that implement the glsl's `max` and `min` functions.
Co-authored-by: JCapucho <jcapucho7@gmail.com>
* Fix grammar.
Co-authored-by: JCapucho <jcapucho7@gmail.com>
This commit is contained in:
@@ -164,12 +164,20 @@ impl<'a> ConstantSolver<'a> {
|
||||
|
||||
self.binary_op(op, left_constant, right_constant, span)
|
||||
}
|
||||
Expression::Math { fun, arg, arg1, .. } => {
|
||||
Expression::Math {
|
||||
fun,
|
||||
arg,
|
||||
arg1,
|
||||
arg2,
|
||||
..
|
||||
} => {
|
||||
let arg = self.solve(arg)?;
|
||||
let arg1 = arg1.map(|arg| self.solve(arg)).transpose()?;
|
||||
let arg2 = arg2.map(|arg| self.solve(arg)).transpose()?;
|
||||
|
||||
let const0 = &self.constants[arg].inner;
|
||||
let const1 = arg1.map(|arg| &self.constants[arg].inner);
|
||||
let const2 = arg2.map(|arg| &self.constants[arg].inner);
|
||||
|
||||
match fun {
|
||||
crate::MathFunction::Pow => {
|
||||
@@ -201,6 +209,49 @@ impl<'a> ConstantSolver<'a> {
|
||||
let inner = ConstantInner::Scalar { width, value };
|
||||
Ok(self.register_constant(inner, span))
|
||||
}
|
||||
crate::MathFunction::Clamp => {
|
||||
let (value, width) = match (const0, const1.unwrap(), const2.unwrap()) {
|
||||
(
|
||||
&ConstantInner::Scalar {
|
||||
width,
|
||||
value: value0,
|
||||
},
|
||||
&ConstantInner::Scalar { value: value1, .. },
|
||||
&ConstantInner::Scalar { value: value2, .. },
|
||||
) => (
|
||||
match (value0, value1, value2) {
|
||||
(
|
||||
ScalarValue::Sint(a),
|
||||
ScalarValue::Sint(b),
|
||||
ScalarValue::Sint(c),
|
||||
) => ScalarValue::Sint(a.max(b).min(c)),
|
||||
(
|
||||
ScalarValue::Uint(a),
|
||||
ScalarValue::Uint(b),
|
||||
ScalarValue::Uint(c),
|
||||
) => ScalarValue::Uint(a.max(b).min(c)),
|
||||
(
|
||||
ScalarValue::Float(a),
|
||||
ScalarValue::Float(b),
|
||||
ScalarValue::Float(c),
|
||||
) => {
|
||||
ScalarValue::Float(glsl_float_min(glsl_float_max(a, b), c))
|
||||
}
|
||||
_ => return Err(ConstantSolvingError::InvalidMathArg),
|
||||
},
|
||||
width,
|
||||
),
|
||||
_ => {
|
||||
return Err(ConstantSolvingError::NotImplemented(format!(
|
||||
"{:?} applied to vector values",
|
||||
fun
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let inner = ConstantInner::Scalar { width, value };
|
||||
Ok(self.register_constant(inner, span))
|
||||
}
|
||||
_ => Err(ConstantSolvingError::NotImplemented(format!("{:?}", fun))),
|
||||
}
|
||||
}
|
||||
@@ -506,6 +557,48 @@ impl<'a> ConstantSolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to implement the GLSL `max` function for floats.
|
||||
///
|
||||
/// While Rust does provide a `f64::max` method, it has a different behavior than the
|
||||
/// GLSL `max` for NaNs. In Rust, if any of the arguments is a NaN, then the other
|
||||
/// is returned.
|
||||
///
|
||||
/// This leads to different results in the following example
|
||||
/// ```
|
||||
/// use std::cmp::max;
|
||||
/// std::f64::NAN.max(1.0);
|
||||
/// ```
|
||||
///
|
||||
/// Rust will return `1.0` while GLSL should return NaN.
|
||||
fn glsl_float_max(x: f64, y: f64) -> f64 {
|
||||
if x < y {
|
||||
y
|
||||
} else {
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to implement the GLSL `min` function for floats.
|
||||
///
|
||||
/// While Rust does provide a `f64::min` method, it has a different behavior than the
|
||||
/// GLSL `min` for NaNs. In Rust, if any of the arguments is a NaN, then the other
|
||||
/// is returned.
|
||||
///
|
||||
/// This leads to different results in the following example
|
||||
/// ```
|
||||
/// use std::cmp::min;
|
||||
/// std::f64::NAN.min(1.0);
|
||||
/// ```
|
||||
///
|
||||
/// Rust will return `1.0` while GLSL should return NaN.
|
||||
fn glsl_float_min(x: f64, y: f64) -> f64 {
|
||||
if y < x {
|
||||
y
|
||||
} else {
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::vec;
|
||||
|
||||
Reference in New Issue
Block a user