Home | History | Annotate | Download | only in test
      1 /*
      2  * Copyright  2012 Siarhei Siamashka <siarhei.siamashka (at) gmail.com>
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 #include "utils.h"
     25 #include <assert.h>
     26 #include <stdlib.h>
     27 #include <stdio.h>
     28 #include <math.h>
     29 
     30 #ifdef HAVE_FLOAT128
     31 
     32 #define pixman_fixed_to_float128(x) (((__float128)(x)) / 65536.0Q)
     33 
     34 typedef struct { __float128 v[3]; } pixman_vector_f128_t;
     35 typedef struct { __float128 m[3][3]; } pixman_transform_f128_t;
     36 
     37 pixman_bool_t
     38 pixman_transform_point_f128 (const pixman_transform_f128_t *t,
     39                              const pixman_vector_f128_t    *v,
     40                              pixman_vector_f128_t          *result)
     41 {
     42     int i;
     43     for (i = 0; i < 3; i++)
     44     {
     45         result->v[i] = t->m[i][0] * v->v[0] +
     46                        t->m[i][1] * v->v[1] +
     47                        t->m[i][2] * v->v[2];
     48     }
     49     if (result->v[2] != 0)
     50     {
     51         result->v[0] /= result->v[2];
     52         result->v[1] /= result->v[2];
     53         result->v[2] = 1;
     54         return TRUE;
     55     }
     56     else
     57     {
     58         return FALSE;
     59     }
     60 }
     61 
     62 pixman_bool_t does_it_fit_fixed_48_16 (__float128 x)
     63 {
     64     if (x >= 65536.0Q * 65536.0Q * 32768.0Q)
     65         return FALSE;
     66     if (x <= -65536.0Q * 65536.0Q * 32768.0Q)
     67         return FALSE;
     68     return TRUE;
     69 }
     70 
     71 #endif
     72 
     73 uint32_t
     74 test_matrix (int testnum, int verbose)
     75 {
     76     uint32_t crc32 = 0;
     77     int i, j, k;
     78     pixman_bool_t is_affine;
     79 
     80     prng_srand (testnum);
     81 
     82     for (i = 0; i < 100; i++)
     83     {
     84         pixman_bool_t           transform_ok;
     85         pixman_transform_t      ti;
     86         pixman_vector_48_16_t   vi, result_i;
     87 #ifdef HAVE_FLOAT128
     88         pixman_transform_f128_t tf;
     89         pixman_vector_f128_t    vf, result_f;
     90 #endif
     91         prng_randmemset (&ti, sizeof(ti), 0);
     92         prng_randmemset (&vi, sizeof(vi), 0);
     93 
     94         for (j = 0; j < 3; j++)
     95         {
     96             /* make sure that "vi" contains 31.16 fixed point data */
     97             vi.v[j] >>= 17;
     98             /* and apply random shift */
     99             if (prng_rand_n (3) == 0)
    100                 vi.v[j] >>= prng_rand_n (46);
    101         }
    102 
    103         if (prng_rand_n (2))
    104         {
    105             /* random shift for the matrix */
    106             for (j = 0; j < 3; j++)
    107                 for (k = 0; k < 3; k++)
    108                     ti.matrix[j][k] >>= prng_rand_n (30);
    109         }
    110 
    111         if (prng_rand_n (2))
    112         {
    113             /* affine matrix */
    114             ti.matrix[2][0] = 0;
    115             ti.matrix[2][1] = 0;
    116             ti.matrix[2][2] = pixman_fixed_1;
    117         }
    118 
    119         if (prng_rand_n (2))
    120         {
    121             /* cartesian coordinates */
    122             vi.v[2] = pixman_fixed_1;
    123         }
    124 
    125         is_affine = (ti.matrix[2][0] == 0 && ti.matrix[2][1] == 0 &&
    126                      ti.matrix[2][2] == pixman_fixed_1 &&
    127                      vi.v[2] == pixman_fixed_1);
    128 
    129         transform_ok = TRUE;
    130         if (is_affine && prng_rand_n (2))
    131             pixman_transform_point_31_16_affine (&ti, &vi, &result_i);
    132         else
    133             transform_ok = pixman_transform_point_31_16 (&ti, &vi, &result_i);
    134 
    135         crc32 = compute_crc32 (crc32, &result_i, sizeof(result_i));
    136 
    137 #ifdef HAVE_FLOAT128
    138         /* compare with a reference 128-bit floating point implementation */
    139         for (j = 0; j < 3; j++)
    140         {
    141             vf.v[j] = pixman_fixed_to_float128 (vi.v[j]);
    142             for (k = 0; k < 3; k++)
    143             {
    144                 tf.m[j][k] = pixman_fixed_to_float128 (ti.matrix[j][k]);
    145             }
    146         }
    147 
    148         if (pixman_transform_point_f128 (&tf, &vf, &result_f))
    149         {
    150             if (transform_ok ||
    151                 (does_it_fit_fixed_48_16 (result_f.v[0]) &&
    152                  does_it_fit_fixed_48_16 (result_f.v[1]) &&
    153                  does_it_fit_fixed_48_16 (result_f.v[2])))
    154             {
    155                 for (j = 0; j < 3; j++)
    156                 {
    157                     double diff = fabs (result_f.v[j] -
    158                                         pixman_fixed_to_float128 (result_i.v[j]));
    159 
    160                     if (is_affine && diff > (0.51 / 65536.0))
    161                     {
    162                         printf ("%d:%d: bad precision for affine (%.12f)\n",
    163                                testnum, i, diff);
    164                         abort ();
    165                     }
    166                     else if (diff > (0.71 / 65536.0))
    167                     {
    168                         printf ("%d:%d: bad precision for projective (%.12f)\n",
    169                                testnum, i, diff);
    170                         abort ();
    171                     }
    172                 }
    173             }
    174         }
    175 #endif
    176     }
    177     return crc32;
    178 }
    179 
    180 int
    181 main (int argc, const char *argv[])
    182 {
    183     return fuzzer_test_main ("matrix", 20000,
    184 			     0xBEBF98C3,
    185 			     test_matrix, argc, argv);
    186 }
    187