vc4: Improve the accuracy of SIN and COS.
authorEric Anholt <eric@anholt.net>
Mon, 13 Oct 2014 13:11:28 +0000 (14:11 +0100)
committerEric Anholt <eric@anholt.net>
Mon, 13 Oct 2014 16:15:47 +0000 (17:15 +0100)
This gets them to pass glsl-sin/cos.  There was an obvious problem that I
was using the FRC code on the scaled input value, which means that we had
a range in [0, 1], while our taylor is most accurate across [-0.5, 0.5].
We can just slide things over, but that means flipping the sign of the
coefficients.  After that, it was just a matter of stuffing more
coefficients in.

src/gallium/drivers/vc4/vc4_program.c

index 455b5d7f117d0a29c104760a051e854fece90c78..1bbdba5e7c958135466d212f337d7937f8947144 100644 (file)
@@ -766,10 +766,11 @@ tgsi_to_qir_sin(struct vc4_compile *c,
                 enum qop op, struct qreg *src, int i)
 {
         float coeff[] = {
-                2.0 * M_PI,
-                -pow(2.0 * M_PI, 3) / (3 * 2 * 1),
-                pow(2.0 * M_PI, 5) / (5 * 4 * 3 * 2 * 1),
-                -pow(2.0 * M_PI, 7) / (7 * 6 * 5 * 4 * 3 * 2 * 1),
+                -2.0 * M_PI,
+                pow(2.0 * M_PI, 3) / (3 * 2 * 1),
+                -pow(2.0 * M_PI, 5) / (5 * 4 * 3 * 2 * 1),
+                pow(2.0 * M_PI, 7) / (7 * 6 * 5 * 4 * 3 * 2 * 1),
+                -pow(2.0 * M_PI, 9) / (9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1),
         };
 
         struct qreg scaled_x =
@@ -777,8 +778,9 @@ tgsi_to_qir_sin(struct vc4_compile *c,
                          src[0 * 4 + 0],
                          qir_uniform_f(c, 1.0f / (M_PI * 2.0f)));
 
-
-        struct qreg x = tgsi_to_qir_frc(c, NULL, 0, &scaled_x, 0);
+        struct qreg x = qir_FADD(c,
+                                 tgsi_to_qir_frc(c, NULL, 0, &scaled_x, 0),
+                                 qir_uniform_f(c, -0.5));
         struct qreg x2 = qir_FMUL(c, x, x);
         struct qreg sum = qir_FMUL(c, x, qir_uniform_f(c, coeff[0]));
         for (int i = 1; i < ARRAY_SIZE(coeff); i++) {
@@ -799,16 +801,20 @@ tgsi_to_qir_cos(struct vc4_compile *c,
                 enum qop op, struct qreg *src, int i)
 {
         float coeff[] = {
-                1.0f,
-                -pow(2.0 * M_PI, 2) / (2 * 1),
-                pow(2.0 * M_PI, 4) / (4 * 3 * 2 * 1),
-                -pow(2.0 * M_PI, 6) / (6 * 5 * 4 * 3 * 2 * 1),
+                -1.0f,
+                pow(2.0 * M_PI, 2) / (2 * 1),
+                -pow(2.0 * M_PI, 4) / (4 * 3 * 2 * 1),
+                pow(2.0 * M_PI, 6) / (6 * 5 * 4 * 3 * 2 * 1),
+                -pow(2.0 * M_PI, 8) / (8 * 7 * 6 * 5 * 4 * 3 * 2 * 1),
+                pow(2.0 * M_PI, 10) / (10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1),
         };
 
         struct qreg scaled_x =
                 qir_FMUL(c, src[0 * 4 + 0],
                          qir_uniform_f(c, 1.0f / (M_PI * 2.0f)));
-        struct qreg x_frac = tgsi_to_qir_frc(c, NULL, 0, &scaled_x, 0);
+        struct qreg x_frac = qir_FADD(c,
+                                      tgsi_to_qir_frc(c, NULL, 0, &scaled_x, 0),
+                                      qir_uniform_f(c, -0.5));
 
         struct qreg sum = qir_uniform_f(c, coeff[0]);
         struct qreg x2 = qir_FMUL(c, x_frac, x_frac);