From d1f0ab63431cfa9b558afd026db87a59b841db40 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 20 Jan 2012 10:47:57 +0200 Subject: [PATCH] compositor: simplify the matrix inversion API The compositor will likely do an order of magnitude less matrix inversions than point transformations with an inverse, hence we do not really need the optimised path for single-shot invert-and-transform. Expose only the computing of the explicit inverse matrix in the API. However, the matrix inversion tests need access to the internal functions. Designate a unit test build by #defining UNIT_TEST, and export the internal functions in that case. Signed-off-by: Pekka Paalanen --- src/compositor.c | 2 +- src/compositor.h | 2 +- src/matrix.c | 61 ++++++++++++++++++++++++++++++--------------- src/matrix.h | 21 ++++++++++------ tests/Makefile.am | 2 +- tests/matrix-test.c | 60 ++++++++++++++++++-------------------------- 6 files changed, 81 insertions(+), 67 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index cb19f342..69ad60e4 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -545,7 +545,7 @@ static void weston_surface_update_transform(struct weston_surface *surface) { struct weston_matrix *matrix = &surface->transform.matrix; - struct weston_inverse_matrix *inverse = &surface->transform.inverse; + struct weston_matrix *inverse = &surface->transform.inverse; struct weston_transform *tform; if (!surface->transform.dirty) diff --git a/src/compositor.h b/src/compositor.h index 2064d676..53126651 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -230,7 +230,7 @@ struct weston_surface { /* derived state, set up by weston_surface_update_transform */ struct weston_matrix matrix; - struct weston_inverse_matrix inverse; + struct weston_matrix inverse; int enabled; } transform; diff --git a/src/matrix.c b/src/matrix.c index 46ce56a8..98ccf4ca 100644 --- a/src/matrix.c +++ b/src/matrix.c @@ -29,6 +29,7 @@ #include "matrix.h" + /* * Matrices are stored in column-major order, that is the array indices are: * 0 4 8 12 @@ -116,6 +117,16 @@ swap_rows(double *a, double *b) } } +static inline void +swap_unsigned(unsigned *a, unsigned *b) +{ + unsigned tmp; + + tmp = *a; + *a = *b; + *b = tmp; +} + static inline unsigned find_pivot(double *column, unsigned k) { @@ -133,16 +144,15 @@ find_pivot(double *column, unsigned k) * LU decomposition, forward and back substitution: Chapter 3. */ -WL_EXPORT int -weston_matrix_invert(struct weston_inverse_matrix *inverse, - const struct weston_matrix *matrix) +MATRIX_TEST_EXPORT inline int +matrix_invert(double *A, unsigned *p, const struct weston_matrix *matrix) { - double A[16]; - unsigned p[4] = { 0, 1, 2, 3 }; unsigned i, j, k; unsigned pivot; double pv; + for (i = 0; i < 4; ++i) + p[i] = i; for (i = 16; i--; ) A[i] = matrix->d[i]; @@ -150,9 +160,7 @@ weston_matrix_invert(struct weston_inverse_matrix *inverse, for (k = 0; k < 4; ++k) { pivot = find_pivot(&A[k * 4], k); if (pivot != k) { - unsigned tmp = p[k]; - p[k] = p[pivot]; - p[pivot] = tmp; + swap_unsigned(&p[k], &p[pivot]); swap_rows(&A[k], &A[pivot]); } @@ -168,30 +176,25 @@ weston_matrix_invert(struct weston_inverse_matrix *inverse, } } - memcpy(inverse->LU, A, sizeof(A)); - memcpy(inverse->p, p, sizeof(p)); return 0; } -WL_EXPORT void -weston_matrix_inverse_transform(struct weston_inverse_matrix *inverse, - struct weston_vector *v) +MATRIX_TEST_EXPORT inline void +inverse_transform(const double *LU, const unsigned *p, GLfloat *v) { /* Solve A * x = v, when we have P * A = L * U. * P * A * x = P * v => L * U * x = P * v * Let U * x = b, then L * b = P * v. */ - unsigned *p = inverse->p; - double *LU = inverse->LU; double b[4]; unsigned j; /* Forward substitution, column version, solves L * b = P * v */ /* The diagonal of L is all ones, and not explicitly stored. */ - b[0] = v->f[p[0]]; - b[1] = (double)v->f[p[1]] - b[0] * LU[1 + 0 * 4]; - b[2] = (double)v->f[p[2]] - b[0] * LU[2 + 0 * 4]; - b[3] = (double)v->f[p[3]] - b[0] * LU[3 + 0 * 4]; + b[0] = v[p[0]]; + b[1] = (double)v[p[1]] - b[0] * LU[1 + 0 * 4]; + b[2] = (double)v[p[2]] - b[0] * LU[2 + 0 * 4]; + b[3] = (double)v[p[3]] - b[0] * LU[3 + 0 * 4]; b[2] -= b[1] * LU[2 + 1 * 4]; b[3] -= b[1] * LU[3 + 1 * 4]; b[3] -= b[2] * LU[3 + 2 * 4]; @@ -225,5 +228,23 @@ weston_matrix_inverse_transform(struct weston_inverse_matrix *inverse, /* the result */ for (j = 0; j < 4; ++j) - v->f[j] = b[j]; + v[j] = b[j]; +} + +WL_EXPORT int +weston_matrix_invert(struct weston_matrix *inverse, + const struct weston_matrix *matrix) +{ + double LU[16]; /* column-major */ + unsigned perm[4]; /* permutation */ + unsigned c; + + if (matrix_invert(LU, perm, matrix) < 0) + return -1; + + weston_matrix_init(inverse); + for (c = 0; c < 4; ++c) + inverse_transform(LU, perm, &inverse->d[c * 4]); + + return 0; } diff --git a/src/matrix.h b/src/matrix.h index 21c1e785..04b179ff 100644 --- a/src/matrix.h +++ b/src/matrix.h @@ -28,11 +28,6 @@ struct weston_matrix { GLfloat d[16]; }; -struct weston_inverse_matrix { - double LU[16]; /* column-major */ - unsigned p[4]; /* permutation */ -}; - struct weston_vector { GLfloat f[4]; }; @@ -50,10 +45,20 @@ void weston_matrix_transform(struct weston_matrix *matrix, struct weston_vector *v); int -weston_matrix_invert(struct weston_inverse_matrix *inverse, +weston_matrix_invert(struct weston_matrix *inverse, const struct weston_matrix *matrix); + +#ifdef UNIT_TEST +# define MATRIX_TEST_EXPORT WL_EXPORT + +int +matrix_invert(double *A, unsigned *p, const struct weston_matrix *matrix); + void -weston_matrix_inverse_transform(struct weston_inverse_matrix *inverse, - struct weston_vector *v); +inverse_transform(const double *LU, const unsigned *p, GLfloat *v); + +#else +# define MATRIX_TEST_EXPORT static +#endif #endif /* WESTON_MATRIX_H */ diff --git a/tests/Makefile.am b/tests/Makefile.am index e9d96acd..a1f361e1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,7 +6,7 @@ endif AM_CFLAGS = $(GCC_CFLAGS) -AM_CPPFLAGS = -I../src +AM_CPPFLAGS = -I../src -DUNIT_TEST matrix_test_SOURCES = \ matrix-test.c \ diff --git a/tests/matrix-test.c b/tests/matrix-test.c index 76d93ada..6fdab839 100644 --- a/tests/matrix-test.c +++ b/tests/matrix-test.c @@ -30,6 +30,11 @@ #include "matrix.h" +struct inverse_matrix { + double LU[16]; /* column-major */ + unsigned perm[4]; /* permutation */ +}; + static struct timespec begin_time; static void @@ -81,9 +86,9 @@ determinant(const struct weston_matrix *m) } static void -print_permutation_matrix(const struct weston_inverse_matrix *m) +print_permutation_matrix(const struct inverse_matrix *m) { - const unsigned *p = m->p; + const unsigned *p = m->perm; const char *row[4] = { "1 0 0 0\n", "0 1 0 0\n", @@ -95,7 +100,7 @@ print_permutation_matrix(const struct weston_inverse_matrix *m) } static void -print_LU_decomposition(const struct weston_inverse_matrix *m) +print_LU_decomposition(const struct inverse_matrix *m) { unsigned r, c; @@ -128,7 +133,7 @@ print_LU_decomposition(const struct weston_inverse_matrix *m) } static void -print_inverse_data_matrix(const struct weston_inverse_matrix *m) +print_inverse_data_matrix(const struct inverse_matrix *m) { unsigned r, c; @@ -140,7 +145,7 @@ print_inverse_data_matrix(const struct weston_inverse_matrix *m) printf("permutation: "); for (r = 0; r < 4; ++r) - printf(" %u", m->p[r]); + printf(" %u", m->perm[r]); printf("\n"); } @@ -175,22 +180,6 @@ randomize_matrix(struct weston_matrix *m) #endif } -static void -invert_matrix(struct weston_matrix *m) -{ - struct weston_inverse_matrix q; - unsigned i; - - if (weston_matrix_invert(&q, m) != 0) { - m->d[0] = NAN; - return; - } - - for (i = 0; i < 4; ++i) - weston_matrix_inverse_transform(&q, - (struct weston_vector *)&m->d[i * 4]); -} - /* Take a matrix, compute inverse, multiply together * and subtract the identity matrix to get the error matrix. * Return the largest absolute value from the error matrix. @@ -199,15 +188,14 @@ static double test_inverse(struct weston_matrix *m) { unsigned i; - struct weston_inverse_matrix q; + struct inverse_matrix q; double errsup = 0.0; - if (weston_matrix_invert(&q, m) != 0) + if (matrix_invert(q.LU, q.perm, m) != 0) return INFINITY; for (i = 0; i < 4; ++i) - weston_matrix_inverse_transform(&q, - (struct weston_vector *)&m->d[i * 4]); + inverse_transform(q.LU, q.perm, &m->d[i * 4]); m->d[0] -= 1.0f; m->d[5] -= 1.0f; @@ -309,21 +297,21 @@ static void __attribute__((noinline)) test_loop_speed_inversetransform(void) { struct weston_matrix m; - struct weston_inverse_matrix inv; + struct inverse_matrix inv; struct weston_vector v = { { 0.5, 0.5, 0.5, 1.0 } }; unsigned long count = 0; double t; - printf("\nRunning 3 s test on weston_matrix_inverse_transform()...\n"); + printf("\nRunning 3 s test on inverse_transform()...\n"); weston_matrix_init(&m); - weston_matrix_invert(&inv, &m); + matrix_invert(inv.LU, inv.perm, &m); running = 1; alarm(3); reset_timer(); while (running) { - weston_matrix_inverse_transform(&inv, &v); + inverse_transform(inv.LU, inv.perm, v.f); count++; } t = read_timer(); @@ -336,11 +324,11 @@ static void __attribute__((noinline)) test_loop_speed_invert(void) { struct weston_matrix m; - struct weston_inverse_matrix inv; + struct inverse_matrix inv; unsigned long count = 0; double t; - printf("\nRunning 3 s test on weston_matrix_invert()...\n"); + printf("\nRunning 3 s test on matrix_invert()...\n"); weston_matrix_init(&m); @@ -348,7 +336,7 @@ test_loop_speed_invert(void) alarm(3); reset_timer(); while (running) { - weston_matrix_invert(&inv, &m); + matrix_invert(inv.LU, inv.perm, &m); count++; } t = read_timer(); @@ -364,7 +352,7 @@ test_loop_speed_invert_explicit(void) unsigned long count = 0; double t; - printf("\nRunning 3 s test on computing the explicit inverse matrix...\n"); + printf("\nRunning 3 s test on weston_matrix_invert()...\n"); weston_matrix_init(&m); @@ -372,7 +360,7 @@ test_loop_speed_invert_explicit(void) alarm(3); reset_timer(); while (running) { - invert_matrix(&m); + weston_matrix_invert(&m, &m); count++; } t = read_timer(); @@ -385,7 +373,7 @@ int main(void) { struct sigaction ding; struct weston_matrix M; - struct weston_inverse_matrix Q; + struct inverse_matrix Q; int ret; double errsup; double det; @@ -402,7 +390,7 @@ int main(void) M.d[2] = 6.0; M.d[6] = 18.0; M.d[10] = -12; M.d[14] = 0.0; M.d[3] = 0.0; M.d[7] = 0.0; M.d[11] = 0.0; M.d[15] = 1.0; - ret = weston_matrix_invert(&Q, &M); + ret = matrix_invert(Q.LU, Q.perm, &M); printf("ret = %d\n", ret); printf("det = %g\n\n", determinant(&M));