summaryrefslogtreecommitdiffstats
path: root/src/compiler/glsl/builtin_functions.cpp
diff options
context:
space:
mode:
authorJason Ekstrand <[email protected]>2016-12-09 09:33:05 -0800
committerJason Ekstrand <[email protected]>2016-12-09 18:38:21 -0800
commit9807f502eb7a023be619a14119388b2a43271b0e (patch)
treec1e87001a380e6bd56608799a5ef7fe849923a27 /src/compiler/glsl/builtin_functions.cpp
parentefe9d1cde3340d3a9d17e5560b609a4fb839d43d (diff)
glsl: Use a simpler formula for tanh
The formula we have used in the past is a trivial reduction from the definition by simply multiplying both the numerator and denominator of the formula by 2. However, multiplying by e^x, you can further reduce it. This allows us to get rid of one side of the clamp and two of exponential functions which should make it faster. The new formula still passes the dEQP precision tests for tanh so it should be fine. Reviewed-by: Roland Scheidegger <[email protected]> Reviewed-by: Kenneth Graunke <[email protected]>
Diffstat (limited to 'src/compiler/glsl/builtin_functions.cpp')
-rw-r--r--src/compiler/glsl/builtin_functions.cpp18
1 files changed, 10 insertions, 8 deletions
diff --git a/src/compiler/glsl/builtin_functions.cpp b/src/compiler/glsl/builtin_functions.cpp
index 3dead1af00f..17f03a3fa27 100644
--- a/src/compiler/glsl/builtin_functions.cpp
+++ b/src/compiler/glsl/builtin_functions.cpp
@@ -3563,17 +3563,19 @@ builtin_builder::_tanh(const glsl_type *type)
ir_variable *x = in_var(type, "x");
MAKE_SIG(type, v130, 1, x);
- /* Clamp x to [-10, +10] to avoid precision problems.
- * When x > 10, e^(-x) is so small relative to e^x that it gets flushed to
- * zero in the computation e^x + e^(-x). The same happens in the other
- * direction when x < -10.
+ /* tanh(x) := (0.5 * (e^x - e^(-x))) / (0.5 * (e^x + e^(-x)))
+ *
+ * With a little algebra this reduces to (e^2x - 1) / (e^2x + 1)
+ *
+ * Clamp x to (-inf, +10] to avoid precision problems. When x > 10, e^2x
+ * is so much larger than 1.0 that 1.0 gets flushed to zero in the
+ * computation e^2x +/- 1 so it can be ignored.
*/
ir_variable *t = body.make_temp(type, "tmp");
- body.emit(assign(t, min2(max2(x, imm(-10.0f)), imm(10.0f))));
+ body.emit(assign(t, min2(x, imm(10.0f))));
- /* (e^x - e^(-x)) / (e^x + e^(-x)) */
- body.emit(ret(div(sub(exp(t), exp(neg(t))),
- add(exp(t), exp(neg(t))))));
+ body.emit(ret(div(sub(exp(mul(t, imm(2.0f))), imm(1.0f)),
+ add(exp(mul(t, imm(2.0f))), imm(1.0f)))));
return sig;
}