[Cogl] [PATCH] Don't cache inverse within CoglMatrix

Robert Bragg robert at sixbynine.org
Tue Aug 28 08:47:47 PDT 2012


From: Robert Bragg <robert at linux.intel.com>

This removes the padding within CoglMatrix for storing a cache of the
inverse. Applications can quite easily cache there own inverse matrices
and that avoids us bloating the size of CoglMatrix.
---
 cogl/cogl-matrix-private.h |    4 -
 cogl/cogl-matrix-stack.c   |    5 +-
 cogl/cogl-matrix.c         |  189 +++++++++++++++++++-------------------------
 cogl/cogl-matrix.h         |   11 +--
 4 files changed, 86 insertions(+), 123 deletions(-)

diff --git a/cogl/cogl-matrix-private.h b/cogl/cogl-matrix-private.h
index ef39e84..f6f6cb8 100644
--- a/cogl/cogl-matrix-private.h
+++ b/cogl/cogl-matrix-private.h
@@ -44,10 +44,6 @@ _cogl_matrix_print (const CoglMatrix *matrix);
 void
 _cogl_matrix_prefix_print (const char *prefix, const CoglMatrix *matrix);
 
-void
-_cogl_matrix_init_from_matrix_without_inverse (CoglMatrix *matrix,
-                                               const CoglMatrix *src);
-
 G_END_DECLS
 
 #endif /* __COGL_MATRIX_PRIVATE_H */
diff --git a/cogl/cogl-matrix-stack.c b/cogl/cogl-matrix-stack.c
index 2d61a5e..22afd7c 100644
--- a/cogl/cogl-matrix-stack.c
+++ b/cogl/cogl-matrix-stack.c
@@ -444,8 +444,7 @@ _cogl_matrix_entry_get (CoglMatrixEntry *entry,
         case COGL_MATRIX_OP_LOAD:
           {
             CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)current;
-            _cogl_matrix_init_from_matrix_without_inverse (matrix,
-                                                           load->matrix);
+            *matrix = *load->matrix;
             goto initialized;
           }
         case COGL_MATRIX_OP_SAVE:
@@ -459,7 +458,7 @@ _cogl_matrix_entry_get (CoglMatrixEntry *entry,
                 _cogl_matrix_entry_get (current->parent, save->cache);
                 save->cache_valid = TRUE;
               }
-            _cogl_matrix_init_from_matrix_without_inverse (matrix, save->cache);
+            *matrix = *save->cache;
             goto initialized;
           }
         default:
diff --git a/cogl/cogl-matrix.c b/cogl/cogl-matrix.c
index 6c7118b..ba71d26 100644
--- a/cogl/cogl-matrix.c
+++ b/cogl/cogl-matrix.c
@@ -49,16 +49,13 @@
  *
  * - instead of allocating matrix->m and matrix->inv using malloc, our
  *   public CoglMatrix typedef is large enough to directly contain the
- *   matrix, its inverse, a type and a set of flags.
+ *   matrix, a type and a set of flags and although we originally also
+ *   had a type large enough to hold the inverse we since decided to
+ *   leave caching the inverse to applications.
  * - instead of having a _cogl_matrix_analyse which updates the type,
- *   flags and inverse, we have _cogl_matrix_update_inverse which
- *   essentially does the same thing (internally making use of
- *   _cogl_matrix_update_type_and_flags()) but with additional guards in
- *   place to bail out when the inverse matrix is still valid.
- * - when initializing a matrix with the identity matrix we don't
- *   immediately initialize the inverse matrix; rather we just set the
- *   dirty flag for the inverse (since it's likely the user won't request
- *   the inverse of the identity matrix)
+ *   flags and inverse, we have _cogl_matrix_get_inverse which will
+ *   use _cogl_matrix_update_type_and_flags() and calculate an
+ *   inverse.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -155,7 +152,6 @@ do { \
 #define MAT_FLAG_SINGULAR       0x80  /*< is a singular matrix flag */
 #define MAT_DIRTY_TYPE          0x100  /*< matrix type is dirty */
 #define MAT_DIRTY_FLAGS         0x200  /*< matrix flags are dirty */
-#define MAT_DIRTY_INVERSE       0x400  /*< matrix inverse is dirty */
 
 /* angle preserving matrix flags mask */
 #define MAT_FLAGS_ANGLE_PRESERVING (MAT_FLAG_ROTATION | \
@@ -186,8 +182,7 @@ do { \
 
 /* dirty matrix flags mask */
 #define MAT_DIRTY_ALL      (MAT_DIRTY_TYPE | \
-			    MAT_DIRTY_FLAGS | \
-			    MAT_DIRTY_INVERSE)
+			    MAT_DIRTY_FLAGS)
 
 
 /*
@@ -301,7 +296,7 @@ matrix_multiply_array_with_flags (CoglMatrix *result,
                                   const float *array,
                                   unsigned int flags)
 {
-  result->flags |= (flags | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);
+  result->flags |= (flags | MAT_DIRTY_TYPE);
 
   if (TEST_MAT_FLAGS (result, MAT_FLAGS_3D))
     matrix_multiply3x4 ((float *)result, (float *)result, array);
@@ -320,8 +315,7 @@ _cogl_matrix_multiply (CoglMatrix *result,
 {
   result->flags = (a->flags |
                    b->flags |
-                   MAT_DIRTY_TYPE |
-                   MAT_DIRTY_INVERSE);
+                   MAT_DIRTY_TYPE);
 
   if (TEST_MAT_FLAGS(result, MAT_FLAGS_3D))
     matrix_multiply3x4 ((float *)result, (float *)a, (float *)b);
@@ -347,7 +341,6 @@ _cogl_matrix_multiply_array (CoglMatrix *result, const float *array)
 {
   result->flags |= (MAT_FLAG_GENERAL |
                   MAT_DIRTY_TYPE |
-                  MAT_DIRTY_INVERSE |
                   MAT_DIRTY_FLAGS);
 
   matrix_multiply4x4 ((float *)result, (float *)result, (float *)array);
@@ -381,17 +374,6 @@ _cogl_matrix_prefix_print (const char *prefix, const CoglMatrix *matrix)
              prefix, (int)matrix->flags);
 
   print_matrix_floats (prefix, (float *)matrix);
-  g_print ("%sInverse: \n", prefix);
-  if (!(matrix->flags & MAT_DIRTY_INVERSE))
-    {
-      float prod[16];
-      print_matrix_floats (prefix, matrix->inv);
-      matrix_multiply4x4 (prod, (float *)matrix, matrix->inv);
-      g_print ("%sMat * Inverse:\n", prefix);
-      print_matrix_floats (prefix, prod);
-    }
-  else
-    g_print ("%s  - not available\n", prefix);
 }
 
 /*
@@ -404,6 +386,31 @@ _cogl_matrix_print (const CoglMatrix *matrix)
 }
 
 /*
+ * Set a matrix to the identity matrix.
+ *
+ * @mat matrix.
+ *
+ * Copies ::identity into \p CoglMatrix::m, and into CoglMatrix::inv if
+ * not NULL. Sets the matrix type to identity, resets the flags. It
+ * doesn't initialize the inverse matrix, it just marks it dirty.
+ */
+static void
+_cogl_matrix_init_identity (CoglMatrix *matrix)
+{
+  memcpy (matrix, identity, 16 * sizeof (float));
+
+  matrix->type = COGL_MATRIX_TYPE_IDENTITY;
+  matrix->flags = 0;
+}
+
+void
+cogl_matrix_init_identity (CoglMatrix *matrix)
+{
+  _cogl_matrix_init_identity (matrix);
+  _COGL_MATRIX_DEBUG_PRINT (matrix);
+}
+
+/*
  * References an element of 4x4 matrix.
  *
  * @m matrix array.
@@ -439,10 +446,11 @@ _cogl_matrix_print (const CoglMatrix *matrix)
  * unrolled.
  */
 static CoglBool
-invert_matrix_general (CoglMatrix *matrix)
+invert_matrix_general (CoglMatrix *matrix,
+                       CoglMatrix *inverse)
 {
   const float *m = (float *)matrix;
-  float *out = matrix->inv;
+  float *out = (float *)inverse;
   float wtmp[4][8];
   float m0, m1, m2, m3, s;
   float *r0, *r1, *r2, *r3;
@@ -558,6 +566,8 @@ invert_matrix_general (CoglMatrix *matrix)
     MAT (out, 3, 0) = r3[4]; MAT (out, 3, 1) = r3[5],
     MAT (out, 3, 2) = r3[6]; MAT (out, 3, 3) = r3[7];
 
+  inverse->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL);
+
   return TRUE;
 }
 #undef SWAP_ROWS
@@ -578,10 +588,11 @@ invert_matrix_general (CoglMatrix *matrix)
  * original translation vector using by the calculated submatrix inverse.
  */
 static CoglBool
-invert_matrix_3d_general (CoglMatrix *matrix)
+invert_matrix_3d_general (CoglMatrix *matrix,
+                          CoglMatrix *inverse)
 {
   const float *in = (float *)matrix;
-  float *out = matrix->inv;
+  float *out = (float *)inverse;
   float pos, neg, t;
   float det;
 
@@ -643,6 +654,8 @@ invert_matrix_3d_general (CoglMatrix *matrix)
                     MAT (in, 1, 3) * MAT (out, 2, 1) +
                     MAT (in, 2, 3) * MAT (out, 2, 2) );
 
+  inverse->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL);
+
   return TRUE;
 }
 
@@ -660,15 +673,16 @@ invert_matrix_3d_general (CoglMatrix *matrix)
  * translation parts.
  */
 static CoglBool
-invert_matrix_3d (CoglMatrix *matrix)
+invert_matrix_3d (CoglMatrix *matrix,
+                  CoglMatrix *inverse)
 {
   const float *in = (float *)matrix;
-  float *out = matrix->inv;
+  float *out = (float *)inverse;
 
   memcpy (out, identity, 16 * sizeof (float));
 
   if (!TEST_MAT_FLAGS(matrix, MAT_FLAGS_ANGLE_PRESERVING))
-    return invert_matrix_3d_general (matrix);
+    return invert_matrix_3d_general (matrix, inverse);
 
   if (matrix->flags & MAT_FLAG_UNIFORM_SCALE)
     {
@@ -731,6 +745,8 @@ invert_matrix_3d (CoglMatrix *matrix)
   else
     MAT (out, 0, 3) = MAT (out, 1, 3) = MAT (out, 2, 3) = 0.0;
 
+  inverse->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL);
+
   return TRUE;
 }
 
@@ -745,9 +761,10 @@ invert_matrix_3d (CoglMatrix *matrix)
  * Simply copies identity into CoglMatrix::inv.
  */
 static CoglBool
-invert_matrix_identity (CoglMatrix *matrix)
+invert_matrix_identity (CoglMatrix *matrix,
+                        CoglMatrix *inverse)
 {
-  memcpy (matrix->inv, identity, 16 * sizeof (float));
+  _cogl_matrix_init_identity (inverse);
   return TRUE;
 }
 
@@ -762,10 +779,11 @@ invert_matrix_identity (CoglMatrix *matrix)
  * Calculates the
  */
 static CoglBool
-invert_matrix_3d_no_rotation (CoglMatrix *matrix)
+invert_matrix_3d_no_rotation (CoglMatrix *matrix,
+                              CoglMatrix *inverse)
 {
   const float *in = (float *)matrix;
-  float *out = matrix->inv;
+  float *out = (float *)inverse;
 
   if (MAT (in,0,0) == 0 || MAT (in,1,1) == 0 || MAT (in,2,2) == 0)
     return FALSE;
@@ -782,6 +800,8 @@ invert_matrix_3d_no_rotation (CoglMatrix *matrix)
       MAT (out,2,3) = - (MAT (in,2,3) * MAT (out,2,2));
     }
 
+  inverse->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL);
+
   return TRUE;
 }
 
@@ -797,10 +817,11 @@ invert_matrix_3d_no_rotation (CoglMatrix *matrix)
  * translation to the identity matrix.
  */
 static CoglBool
-invert_matrix_2d_no_rotation (CoglMatrix *matrix)
+invert_matrix_2d_no_rotation (CoglMatrix *matrix,
+                              CoglMatrix *inverse)
 {
   const float *in = (float *)matrix;
-  float *out = matrix->inv;
+  float *out = (float *)inverse;
 
   if (MAT (in, 0, 0) == 0 || MAT (in, 1, 1) == 0)
     return FALSE;
@@ -815,6 +836,8 @@ invert_matrix_2d_no_rotation (CoglMatrix *matrix)
       MAT (out, 1, 3) = - (MAT (in, 1, 3) * MAT (out, 1, 1));
     }
 
+  inverse->flags = (MAT_FLAG_GENERAL | MAT_DIRTY_ALL);
+
   return TRUE;
 }
 
@@ -850,7 +873,7 @@ invert_matrix_perspective (CoglMatrix *matrix)
 /*
  * Matrix inversion function pointer type.
  */
-typedef CoglBool (*inv_mat_func)(CoglMatrix *matrix);
+typedef CoglBool (*inv_mat_func)(CoglMatrix *matrix, CoglMatrix *inverse);
 
 /*
  * Table of the matrix inversion functions according to the matrix type.
@@ -1109,22 +1132,18 @@ _cogl_matrix_update_type_and_flags (CoglMatrix *matrix)
  * and copies the identity matrix into CoglMatrix::inv.
  */
 static CoglBool
-_cogl_matrix_update_inverse (CoglMatrix *matrix)
+_cogl_matrix_get_inverse (CoglMatrix *matrix,
+                          CoglMatrix *inverse)
 {
-  if (matrix->flags & MAT_DIRTY_FLAGS ||
-      matrix->flags & MAT_DIRTY_INVERSE)
-    {
-      _cogl_matrix_update_type_and_flags (matrix);
-
-      if (inv_mat_tab[matrix->type](matrix))
-        matrix->flags &= ~MAT_FLAG_SINGULAR;
-      else
-        {
-          matrix->flags |= MAT_FLAG_SINGULAR;
-          memcpy (matrix->inv, identity, 16 * sizeof (float));
-        }
+  if (matrix->flags & (MAT_DIRTY_TYPE | MAT_DIRTY_FLAGS))
+    _cogl_matrix_update_type_and_flags (matrix);
 
-      matrix->flags &= ~MAT_DIRTY_INVERSE;
+  if (inv_mat_tab[matrix->type](matrix, inverse))
+    matrix->flags &= ~MAT_FLAG_SINGULAR;
+  else
+    {
+      _cogl_matrix_init_identity (inverse);
+      matrix->flags |= MAT_FLAG_SINGULAR;
     }
 
   if (matrix->flags & MAT_FLAG_SINGULAR)
@@ -1136,16 +1155,7 @@ _cogl_matrix_update_inverse (CoglMatrix *matrix)
 CoglBool
 cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse)
 {
-  if (_cogl_matrix_update_inverse ((CoglMatrix *)matrix))
-    {
-      cogl_matrix_init_from_array (inverse, matrix->inv);
-      return TRUE;
-    }
-  else
-    {
-      cogl_matrix_init_identity (inverse);
-      return FALSE;
-    }
+  return _cogl_matrix_get_inverse ((CoglMatrix *)matrix, inverse);
 }
 
 /*
@@ -1516,8 +1526,7 @@ cogl_matrix_orthographic (CoglMatrix *matrix,
  *
  * Multiplies in-place the elements of matrix by the scale factors. Checks if
  * the scales factors are roughly the same, marking the MAT_FLAG_UNIFORM_SCALE
- * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE and
- * MAT_DIRTY_INVERSE dirty flags.
+ * flag, or MAT_FLAG_GENERAL_SCALE. Marks the MAT_DIRTY_TYPE flag.
  */
 static void
 _cogl_matrix_scale (CoglMatrix *matrix, float x, float y, float z)
@@ -1533,7 +1542,7 @@ _cogl_matrix_scale (CoglMatrix *matrix, float x, float y, float z)
   else
     matrix->flags |= MAT_FLAG_GENERAL_SCALE;
 
-  matrix->flags |= (MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);
+  matrix->flags |= (MAT_DIRTY_TYPE);
 }
 
 void
@@ -1550,8 +1559,7 @@ cogl_matrix_scale (CoglMatrix *matrix,
  * Multiply a matrix with a translation matrix.
  *
  * Adds the translation coordinates to the elements of matrix in-place.  Marks
- * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and MAT_DIRTY_INVERSE
- * dirty flags.
+ * the MAT_FLAG_TRANSLATION flag, and the MAT_DIRTY_TYPE and dirty flag.
  */
 static void
 _cogl_matrix_translate (CoglMatrix *matrix, float x, float y, float z)
@@ -1563,8 +1571,7 @@ _cogl_matrix_translate (CoglMatrix *matrix, float x, float y, float z)
   m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
 
   matrix->flags |= (MAT_FLAG_TRANSLATION |
-                    MAT_DIRTY_TYPE |
-                    MAT_DIRTY_INVERSE);
+                    MAT_DIRTY_TYPE);
 }
 
 void
@@ -1601,31 +1608,6 @@ _cogl_matrix_viewport (CoglMatrix *matrix,
 #endif
 
 /*
- * Set a matrix to the identity matrix.
- *
- * @mat matrix.
- *
- * Copies ::identity into \p CoglMatrix::m, and into CoglMatrix::inv if
- * not NULL. Sets the matrix type to identity, resets the flags. It
- * doesn't initialize the inverse matrix, it just marks it dirty.
- */
-static void
-_cogl_matrix_init_identity (CoglMatrix *matrix)
-{
-  memcpy (matrix, identity, 16 * sizeof (float));
-
-  matrix->type = COGL_MATRIX_TYPE_IDENTITY;
-  matrix->flags = MAT_DIRTY_INVERSE;
-}
-
-void
-cogl_matrix_init_identity (CoglMatrix *matrix)
-{
-  _cogl_matrix_init_identity (matrix);
-  _COGL_MATRIX_DEBUG_PRINT (matrix);
-}
-
-/*
  * Set a matrix to the (tx, ty, tz) translation matrix.
  *
  * @matix matrix.
@@ -1646,7 +1628,7 @@ _cogl_matrix_init_translation (CoglMatrix *matrix,
   matrix->zw = tz;
 
   matrix->type = COGL_MATRIX_TYPE_3D;
-  matrix->flags = MAT_FLAG_TRANSLATION | MAT_DIRTY_INVERSE;
+  matrix->flags = MAT_FLAG_TRANSLATION;
 }
 
 void
@@ -1722,15 +1704,6 @@ cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array)
   _COGL_MATRIX_DEBUG_PRINT (matrix);
 }
 
-void
-_cogl_matrix_init_from_matrix_without_inverse (CoglMatrix *matrix,
-                                               const CoglMatrix *src)
-{
-  memcpy (matrix, src, 16 * sizeof (float));
-  matrix->type = src->type;
-  matrix->flags = src->flags | MAT_DIRTY_INVERSE;
-}
-
 static void
 _cogl_matrix_init_from_quaternion (CoglMatrix *matrix,
                                    const CoglQuaternion *quaternion)
@@ -2276,7 +2249,7 @@ cogl_matrix_look_at (CoglMatrix *matrix,
   tmp.zw = 0;
   tmp.ww = 1;
 
-  tmp.flags = (MAT_FLAG_GENERAL_3D | MAT_DIRTY_TYPE | MAT_DIRTY_INVERSE);
+  tmp.flags = (MAT_FLAG_GENERAL_3D | MAT_DIRTY_TYPE);
 
   cogl_matrix_translate (&tmp, -eye_position_x, -eye_position_y, -eye_position_z);
 
diff --git a/cogl/cogl-matrix.h b/cogl/cogl-matrix.h
index dac9209..62e5243 100644
--- a/cogl/cogl-matrix.h
+++ b/cogl/cogl-matrix.h
@@ -100,15 +100,10 @@ struct _CoglMatrix
   float ww;
 
   /*< private >*/
-
-  /* Note: we may want to extend this later with private flags
-   * and a cache of the inverse transform matrix. */
-  float          COGL_PRIVATE (inv)[16];
-  unsigned long  COGL_PRIVATE (type);
-  unsigned long  COGL_PRIVATE (flags);
-  unsigned long  COGL_PRIVATE (_padding3);
+  unsigned int COGL_PRIVATE (type) : 16;
+  unsigned int COGL_PRIVATE (flags) : 16;
 };
-COGL_STRUCT_SIZE_ASSERT (CoglMatrix, 128 + sizeof (unsigned long) * 3);
+COGL_STRUCT_SIZE_ASSERT (CoglMatrix, sizeof (float) * 16 + 4);
 
 /**
  * cogl_matrix_init_identity:
-- 
1.7.7.6



More information about the Cogl mailing list