blob: 76d93adab2f6d2a165dcd90fd9ef7cfd3192d75d [file] [log] [blame]
Pekka Paalanen4520d5c2012-01-16 15:04:28 +02001/*
2 * Copyright © 2012 Collabora, Ltd.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <GLES2/gl2.h>
26#include <math.h>
27#include <unistd.h>
28#include <signal.h>
29#include <time.h>
30
31#include "matrix.h"
32
33static struct timespec begin_time;
34
35static void
36reset_timer(void)
37{
38 clock_gettime(CLOCK_MONOTONIC, &begin_time);
39}
40
41static double
42read_timer(void)
43{
44 struct timespec t;
45
46 clock_gettime(CLOCK_MONOTONIC, &t);
47 return (double)(t.tv_sec - begin_time.tv_sec) +
48 1e-9 * (t.tv_nsec - begin_time.tv_nsec);
49}
50
51static double
52det3x3(const GLfloat *c0, const GLfloat *c1, const GLfloat *c2)
53{
54 return (double)
55 c0[0] * c1[1] * c2[2] +
56 c1[0] * c2[1] * c0[2] +
57 c2[0] * c0[1] * c1[2] -
58 c0[2] * c1[1] * c2[0] -
59 c1[2] * c2[1] * c0[0] -
60 c2[2] * c0[1] * c1[0];
61}
62
63static double
64determinant(const struct weston_matrix *m)
65{
66 double det = 0;
67#if 1
68 /* develop on last row */
69 det -= m->d[3 + 0 * 4] * det3x3(&m->d[4], &m->d[8], &m->d[12]);
70 det += m->d[3 + 1 * 4] * det3x3(&m->d[0], &m->d[8], &m->d[12]);
71 det -= m->d[3 + 2 * 4] * det3x3(&m->d[0], &m->d[4], &m->d[12]);
72 det += m->d[3 + 3 * 4] * det3x3(&m->d[0], &m->d[4], &m->d[8]);
73#else
74 /* develop on first row */
75 det += m->d[0 + 0 * 4] * det3x3(&m->d[5], &m->d[9], &m->d[13]);
76 det -= m->d[0 + 1 * 4] * det3x3(&m->d[1], &m->d[9], &m->d[13]);
77 det += m->d[0 + 2 * 4] * det3x3(&m->d[1], &m->d[5], &m->d[13]);
78 det -= m->d[0 + 3 * 4] * det3x3(&m->d[1], &m->d[5], &m->d[9]);
79#endif
80 return det;
81}
82
83static void
84print_permutation_matrix(const struct weston_inverse_matrix *m)
85{
86 const unsigned *p = m->p;
87 const char *row[4] = {
88 "1 0 0 0\n",
89 "0 1 0 0\n",
90 "0 0 1 0\n",
91 "0 0 0 1\n"
92 };
93
94 printf(" P =\n%s%s%s%s", row[p[0]], row[p[1]], row[p[2]], row[p[3]]);
95}
96
97static void
98print_LU_decomposition(const struct weston_inverse_matrix *m)
99{
100 unsigned r, c;
101
102 printf(" L "
103 " U\n");
104 for (r = 0; r < 4; ++r) {
105 double v;
106
107 for (c = 0; c < 4; ++c) {
108 if (c < r)
109 v = m->LU[r + c * 4];
110 else if (c == r)
111 v = 1.0;
112 else
113 v = 0.0;
114 printf(" %12.6f", v);
115 }
116
117 printf(" | ");
118
119 for (c = 0; c < 4; ++c) {
120 if (c >= r)
121 v = m->LU[r + c * 4];
122 else
123 v = 0.0;
124 printf(" %12.6f", v);
125 }
126 printf("\n");
127 }
128}
129
130static void
131print_inverse_data_matrix(const struct weston_inverse_matrix *m)
132{
133 unsigned r, c;
134
135 for (r = 0; r < 4; ++r) {
136 for (c = 0; c < 4; ++c)
137 printf(" %12.6f", m->LU[r + c * 4]);
138 printf("\n");
139 }
140
141 printf("permutation: ");
142 for (r = 0; r < 4; ++r)
143 printf(" %u", m->p[r]);
144 printf("\n");
145}
146
147static void
148print_matrix(const struct weston_matrix *m)
149{
150 unsigned r, c;
151
152 for (r = 0; r < 4; ++r) {
153 for (c = 0; c < 4; ++c)
154 printf(" %14.6e", m->d[r + c * 4]);
155 printf("\n");
156 }
157}
158
159static double
160frand(void)
161{
162 double r = random();
163 return r / (double)(RAND_MAX / 2) - 1.0f;
164}
165
166static void
167randomize_matrix(struct weston_matrix *m)
168{
169 unsigned i;
170 for (i = 0; i < 16; ++i)
171#if 1
172 m->d[i] = frand() * exp(10.0 * frand());
173#else
174 m->d[i] = frand();
175#endif
176}
177
178static void
179invert_matrix(struct weston_matrix *m)
180{
181 struct weston_inverse_matrix q;
182 unsigned i;
183
184 if (weston_matrix_invert(&q, m) != 0) {
185 m->d[0] = NAN;
186 return;
187 }
188
189 for (i = 0; i < 4; ++i)
190 weston_matrix_inverse_transform(&q,
191 (struct weston_vector *)&m->d[i * 4]);
192}
193
194/* Take a matrix, compute inverse, multiply together
195 * and subtract the identity matrix to get the error matrix.
196 * Return the largest absolute value from the error matrix.
197 */
198static double
199test_inverse(struct weston_matrix *m)
200{
201 unsigned i;
202 struct weston_inverse_matrix q;
203 double errsup = 0.0;
204
205 if (weston_matrix_invert(&q, m) != 0)
206 return INFINITY;
207
208 for (i = 0; i < 4; ++i)
209 weston_matrix_inverse_transform(&q,
210 (struct weston_vector *)&m->d[i * 4]);
211
212 m->d[0] -= 1.0f;
213 m->d[5] -= 1.0f;
214 m->d[10] -= 1.0f;
215 m->d[15] -= 1.0f;
216
217 for (i = 0; i < 16; ++i) {
218 double err = fabs(m->d[i]);
219 if (err > errsup)
220 errsup = err;
221 }
222
223 return errsup;
224}
225
226enum {
227 TEST_OK,
228 TEST_NOT_INVERTIBLE_OK,
229 TEST_FAIL,
230 TEST_COUNT
231};
232
233static int
234test(void)
235{
236 struct weston_matrix m;
237 struct weston_matrix n;
238 double det, errsup;
239
240 randomize_matrix(&m);
241 n = m;
242 det = determinant(&m);
243
244 errsup = test_inverse(&m);
245 if (errsup < 1e-6)
246 return TEST_OK;
247
248 if (fabs(det) < 1e-5 && isinf(errsup))
249 return TEST_NOT_INVERTIBLE_OK;
250
251 printf("test fail, det: %g, error sup: %g\n", det, errsup);
252/* print_matrix(&n);*/
253 return TEST_FAIL;
254}
255
256static int running;
257static void
258stopme(int n)
259{
260 running = 0;
261}
262
263static void
264test_loop_precision(void)
265{
266 int counts[TEST_COUNT] = { 0 };
267
268 printf("\nRunning a test loop for 10 seconds...\n");
269 running = 1;
270 alarm(10);
271 while (running) {
272 counts[test()]++;
273 }
274
275 printf("tests: %d ok, %d not invertible but ok, %d failed.\n"
276 "Total: %d iterations.\n",
277 counts[TEST_OK], counts[TEST_NOT_INVERTIBLE_OK],
278 counts[TEST_FAIL],
279 counts[TEST_OK] + counts[TEST_NOT_INVERTIBLE_OK] +
280 counts[TEST_FAIL]);
281}
282
283static void __attribute__((noinline))
284test_loop_speed_matrixvector(void)
285{
286 struct weston_matrix m;
287 struct weston_vector v = { { 0.5, 0.5, 0.5, 1.0 } };
288 unsigned long count = 0;
289 double t;
290
291 printf("\nRunning 3 s test on weston_matrix_transform()...\n");
292
293 weston_matrix_init(&m);
294
295 running = 1;
296 alarm(3);
297 reset_timer();
298 while (running) {
299 weston_matrix_transform(&m, &v);
300 count++;
301 }
302 t = read_timer();
303
304 printf("%lu iterations in %f seconds, avg. %.1f us/iter.\n",
305 count, t, 1e9 * t / count);
306}
307
308static void __attribute__((noinline))
309test_loop_speed_inversetransform(void)
310{
311 struct weston_matrix m;
312 struct weston_inverse_matrix inv;
313 struct weston_vector v = { { 0.5, 0.5, 0.5, 1.0 } };
314 unsigned long count = 0;
315 double t;
316
317 printf("\nRunning 3 s test on weston_matrix_inverse_transform()...\n");
318
319 weston_matrix_init(&m);
320 weston_matrix_invert(&inv, &m);
321
322 running = 1;
323 alarm(3);
324 reset_timer();
325 while (running) {
326 weston_matrix_inverse_transform(&inv, &v);
327 count++;
328 }
329 t = read_timer();
330
331 printf("%lu iterations in %f seconds, avg. %.1f us/iter.\n",
332 count, t, 1e9 * t / count);
333}
334
335static void __attribute__((noinline))
336test_loop_speed_invert(void)
337{
338 struct weston_matrix m;
339 struct weston_inverse_matrix inv;
340 unsigned long count = 0;
341 double t;
342
343 printf("\nRunning 3 s test on weston_matrix_invert()...\n");
344
345 weston_matrix_init(&m);
346
347 running = 1;
348 alarm(3);
349 reset_timer();
350 while (running) {
351 weston_matrix_invert(&inv, &m);
352 count++;
353 }
354 t = read_timer();
355
356 printf("%lu iterations in %f seconds, avg. %.1f ns/iter.\n",
357 count, t, 1e9 * t / count);
358}
359
360static void __attribute__((noinline))
361test_loop_speed_invert_explicit(void)
362{
363 struct weston_matrix m;
364 unsigned long count = 0;
365 double t;
366
367 printf("\nRunning 3 s test on computing the explicit inverse matrix...\n");
368
369 weston_matrix_init(&m);
370
371 running = 1;
372 alarm(3);
373 reset_timer();
374 while (running) {
375 invert_matrix(&m);
376 count++;
377 }
378 t = read_timer();
379
380 printf("%lu iterations in %f seconds, avg. %.1f ns/iter.\n",
381 count, t, 1e9 * t / count);
382}
383
384int main(void)
385{
386 struct sigaction ding;
387 struct weston_matrix M;
388 struct weston_inverse_matrix Q;
389 int ret;
390 double errsup;
391 double det;
392
393 ding.sa_handler = stopme;
394 sigemptyset(&ding.sa_mask);
395 ding.sa_flags = 0;
396 sigaction(SIGALRM, &ding, NULL);
397
398 srandom(13);
399
400 M.d[0] = 3.0; M.d[4] = 17.0; M.d[8] = 10.0; M.d[12] = 0.0;
401 M.d[1] = 2.0; M.d[5] = 4.0; M.d[9] = -2.0; M.d[13] = 0.0;
402 M.d[2] = 6.0; M.d[6] = 18.0; M.d[10] = -12; M.d[14] = 0.0;
403 M.d[3] = 0.0; M.d[7] = 0.0; M.d[11] = 0.0; M.d[15] = 1.0;
404
405 ret = weston_matrix_invert(&Q, &M);
406 printf("ret = %d\n", ret);
407 printf("det = %g\n\n", determinant(&M));
408
409 if (ret != 0)
410 return 1;
411
412 print_inverse_data_matrix(&Q);
413 printf("P * A = L * U\n");
414 print_permutation_matrix(&Q);
415 print_LU_decomposition(&Q);
416
417
418 printf("a random matrix:\n");
419 randomize_matrix(&M);
420 det = determinant(&M);
421 print_matrix(&M);
422 errsup = test_inverse(&M);
423 printf("\nThe matrix multiplied by its inverse, error:\n");
424 print_matrix(&M);
425 printf("max abs error: %g, original determinant %g\n", errsup, det);
426
427 test_loop_precision();
428 test_loop_speed_matrixvector();
429 test_loop_speed_inversetransform();
430 test_loop_speed_invert();
431 test_loop_speed_invert_explicit();
432
433 return 0;
434}