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