[Mesa-dev] [PATCH v2] nir/spirv/glsl450: rewrite atan2 to deal with infinities

Juan A. Suarez Romero jasuarez at igalia.com
Wed Jan 18 12:47:11 UTC 2017


Rewrite atan2(y,x) to cover (+/-)INF values.

This fixes several test cases in Vulkan CTS
(dEQP-VK.glsl.builtin.precision.atan2.*)

v2: do not flush denorms to 0 (jasuarez)
---
 src/compiler/spirv/vtn_glsl450.c | 48 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 6 deletions(-)

diff --git a/src/compiler/spirv/vtn_glsl450.c b/src/compiler/spirv/vtn_glsl450.c
index 0d32fddbef..d52a22c0c3 100644
--- a/src/compiler/spirv/vtn_glsl450.c
+++ b/src/compiler/spirv/vtn_glsl450.c
@@ -299,18 +299,47 @@ build_atan(nir_builder *b, nir_ssa_def *y_over_x)
    return nir_fmul(b, tmp, nir_fsign(b, y_over_x));
 }
 
+/*
+ * Computes atan2(y,x)
+ */
 static nir_ssa_def *
 build_atan2(nir_builder *b, nir_ssa_def *y, nir_ssa_def *x)
 {
    nir_ssa_def *zero = nir_imm_float(b, 0.0f);
-
-   /* If |x| >= 1.0e-8 * |y|: */
-   nir_ssa_def *condition =
-      nir_fge(b, nir_fabs(b, x),
-              nir_fmul(b, nir_imm_float(b, 1.0e-8f), nir_fabs(b, y)));
+   nir_ssa_def *inf = nir_imm_float(b, INFINITY);
+   nir_ssa_def *minus_inf = nir_imm_float(b, -INFINITY);
+   nir_ssa_def *m_3_pi_4 = nir_fmul(b, nir_imm_float(b, 3.0f),
+                                       nir_imm_float(b, M_PI_4f));
+
+   /* if y == +-INF */
+   nir_ssa_def *y_is_inf = nir_feq(b, nir_fabs(b, y), inf);
+
+   /* if x == +-INF */
+   nir_ssa_def *x_is_inf = nir_feq(b, nir_fabs(b, x), inf);
+
+   /* Case: y is +-INF */
+   nir_ssa_def *y_is_inf_then =
+      nir_fmul(b, nir_fsign(b, y),
+                  nir_bcsel(b, nir_feq(b, x, inf),
+                               nir_imm_float(b, M_PI_4f),
+                               nir_bcsel(b, nir_feq(b, x, minus_inf),
+                                            m_3_pi_4,
+                                            nir_imm_float(b, M_PI_2f))));
+
+   /* Case: x is +-INF */
+   nir_ssa_def *x_is_inf_then =
+      nir_fmul(b, nir_fsign(b, y),
+                  nir_bcsel(b, nir_feq(b, x, inf),
+                               zero,
+                               nir_imm_float(b, M_PIf)));
+
+   /* If x > 0 */
+   nir_ssa_def *x_not_zero =
+      nir_fne(b, x, zero);
 
    /* Then...call atan(y/x) and fix it up: */
    nir_ssa_def *atan1 = build_atan(b, nir_fdiv(b, y, x));
+
    nir_ssa_def *r_then =
       nir_bcsel(b, nir_flt(b, x, zero),
                    nir_fadd(b, atan1,
@@ -323,7 +352,14 @@ build_atan2(nir_builder *b, nir_ssa_def *y, nir_ssa_def *x)
    nir_ssa_def *r_else =
       nir_fmul(b, nir_fsign(b, y), nir_imm_float(b, M_PI_2f));
 
-   return nir_bcsel(b, condition, r_then, r_else);
+   /* Everything together */
+   return nir_bcsel(b, y_is_inf,
+                       y_is_inf_then,
+                       nir_bcsel(b, x_is_inf,
+                                    x_is_inf_then,
+                                    nir_bcsel(b, x_not_zero,
+                                                 r_then,
+                                                 r_else)));
 }
 
 static nir_ssa_def *
-- 
2.11.0



More information about the mesa-dev mailing list