matrix-test.c revision de17ff4a
1/* 2 * Copyright © 2012 Siarhei Siamashka <siarhei.siamashka@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 34typedef struct { __float128 v[3]; } pixman_vector_f128_t; 35typedef struct { __float128 m[3][3]; } pixman_transform_f128_t; 36 37pixman_bool_t 38pixman_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 62pixman_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 73static inline uint32_t 74byteswap32 (uint32_t x) 75{ 76 return ((x & ((uint32_t)0xFF << 24)) >> 24) | 77 ((x & ((uint32_t)0xFF << 16)) >> 8) | 78 ((x & ((uint32_t)0xFF << 8)) << 8) | 79 ((x & ((uint32_t)0xFF << 0)) << 24); 80} 81 82static inline uint64_t 83byteswap64 (uint64_t x) 84{ 85 return ((x & ((uint64_t)0xFF << 56)) >> 56) | 86 ((x & ((uint64_t)0xFF << 48)) >> 40) | 87 ((x & ((uint64_t)0xFF << 40)) >> 24) | 88 ((x & ((uint64_t)0xFF << 32)) >> 8) | 89 ((x & ((uint64_t)0xFF << 24)) << 8) | 90 ((x & ((uint64_t)0xFF << 16)) << 24) | 91 ((x & ((uint64_t)0xFF << 8)) << 40) | 92 ((x & ((uint64_t)0xFF << 0)) << 56); 93} 94 95static void 96byteswap_transform (pixman_transform_t *t) 97{ 98 int i, j; 99 100 if (is_little_endian ()) 101 return; 102 103 for (i = 0; i < 3; i++) 104 for (j = 0; j < 3; j++) 105 t->matrix[i][j] = byteswap32 (t->matrix[i][j]); 106} 107 108static void 109byteswap_vector_48_16 (pixman_vector_48_16_t *v) 110{ 111 int i; 112 113 if (is_little_endian ()) 114 return; 115 116 for (i = 0; i < 3; i++) 117 v->v[i] = byteswap64 (v->v[i]); 118} 119 120uint32_t 121test_matrix (int testnum, int verbose) 122{ 123 uint32_t crc32 = 0; 124 int i, j, k; 125 pixman_bool_t is_affine; 126 127 prng_srand (testnum); 128 129 for (i = 0; i < 100; i++) 130 { 131 pixman_bool_t transform_ok; 132 pixman_transform_t ti; 133 pixman_vector_48_16_t vi, result_i; 134#ifdef HAVE_FLOAT128 135 pixman_transform_f128_t tf; 136 pixman_vector_f128_t vf, result_f; 137#endif 138 prng_randmemset (&ti, sizeof(ti), 0); 139 prng_randmemset (&vi, sizeof(vi), 0); 140 byteswap_transform (&ti); 141 byteswap_vector_48_16 (&vi); 142 143 for (j = 0; j < 3; j++) 144 { 145 /* make sure that "vi" contains 31.16 fixed point data */ 146 vi.v[j] >>= 17; 147 /* and apply random shift */ 148 if (prng_rand_n (3) == 0) 149 vi.v[j] >>= prng_rand_n (46); 150 } 151 152 if (prng_rand_n (2)) 153 { 154 /* random shift for the matrix */ 155 for (j = 0; j < 3; j++) 156 for (k = 0; k < 3; k++) 157 ti.matrix[j][k] >>= prng_rand_n (30); 158 } 159 160 if (prng_rand_n (2)) 161 { 162 /* affine matrix */ 163 ti.matrix[2][0] = 0; 164 ti.matrix[2][1] = 0; 165 ti.matrix[2][2] = pixman_fixed_1; 166 } 167 168 if (prng_rand_n (2)) 169 { 170 /* cartesian coordinates */ 171 vi.v[2] = pixman_fixed_1; 172 } 173 174 is_affine = (ti.matrix[2][0] == 0 && ti.matrix[2][1] == 0 && 175 ti.matrix[2][2] == pixman_fixed_1 && 176 vi.v[2] == pixman_fixed_1); 177 178 transform_ok = TRUE; 179 if (is_affine && prng_rand_n (2)) 180 pixman_transform_point_31_16_affine (&ti, &vi, &result_i); 181 else 182 transform_ok = pixman_transform_point_31_16 (&ti, &vi, &result_i); 183 184#ifdef HAVE_FLOAT128 185 /* compare with a reference 128-bit floating point implementation */ 186 for (j = 0; j < 3; j++) 187 { 188 vf.v[j] = pixman_fixed_to_float128 (vi.v[j]); 189 for (k = 0; k < 3; k++) 190 { 191 tf.m[j][k] = pixman_fixed_to_float128 (ti.matrix[j][k]); 192 } 193 } 194 195 if (pixman_transform_point_f128 (&tf, &vf, &result_f)) 196 { 197 if (transform_ok || 198 (does_it_fit_fixed_48_16 (result_f.v[0]) && 199 does_it_fit_fixed_48_16 (result_f.v[1]) && 200 does_it_fit_fixed_48_16 (result_f.v[2]))) 201 { 202 for (j = 0; j < 3; j++) 203 { 204 double diff = fabs (result_f.v[j] - 205 pixman_fixed_to_float128 (result_i.v[j])); 206 207 if (is_affine && diff > (0.51 / 65536.0)) 208 { 209 printf ("%d:%d: bad precision for affine (%.12f)\n", 210 testnum, i, diff); 211 abort (); 212 } 213 else if (diff > (0.71 / 65536.0)) 214 { 215 printf ("%d:%d: bad precision for projective (%.12f)\n", 216 testnum, i, diff); 217 abort (); 218 } 219 } 220 } 221 } 222#endif 223 byteswap_vector_48_16 (&result_i); 224 crc32 = compute_crc32 (crc32, &result_i, sizeof (result_i)); 225 } 226 return crc32; 227} 228 229int 230main (int argc, const char *argv[]) 231{ 232 return fuzzer_test_main ("matrix", 20000, 233 0xBEBF98C3, 234 test_matrix, argc, argv); 235} 236