cogl: Do the premult conversion in-place rather than copying to a new buffer
authorNeil Roberts <neil@linux.intel.com>
Fri, 29 Jan 2010 15:15:08 +0000 (15:15 +0000)
committerNeil Roberts <neil@linux.intel.com>
Mon, 1 Feb 2010 13:27:34 +0000 (13:27 +0000)
The premult part of _cogl_convert_premult has now been split out as
_cogl_convert_premult_status. _cogl_convert_premult has been renamed
to _cogl_convert_format to make it less confusing. The premult
conversion is now done in-place instead of copying the
buffer. Previously it was copying the buffer once for the format
conversion and then copying it again for the premult conversion. The
premult conversion never changes the size of the buffer so it's quite
easy to do in place. We can also use the separated out function
independently.

clutter/cogl/cogl/cogl-atlas-texture.c
clutter/cogl/cogl/cogl-bitmap-fallback.c
clutter/cogl/cogl/cogl-bitmap-pixbuf.c
clutter/cogl/cogl/cogl-bitmap-private.h
clutter/cogl/cogl/cogl-bitmap.c
clutter/cogl/cogl/cogl-texture-2d-sliced.c
clutter/cogl/cogl/cogl-texture-2d.c
clutter/cogl/cogl/cogl-texture.c

index 545c68d..efd8052 100644 (file)
@@ -543,9 +543,9 @@ _cogl_atlas_texture_set_region (CoglTexture    *tex,
       if (closest_format != format)
         {
           /* Convert to required format */
-          success = _cogl_bitmap_convert_and_premult (&source_bmp,
-                                                      &temp_bmp,
-                                                      closest_format);
+          success = _cogl_bitmap_convert_format_and_premult (&source_bmp,
+                                                             &temp_bmp,
+                                                             closest_format);
 
           /* Swap bitmaps if succeeded */
           if (!success) return FALSE;
index ddff6ea..097cc52 100644 (file)
@@ -150,7 +150,7 @@ _cogl_rgba_to_abgr (const guchar *src, guchar *dst)
 /* (Un)Premultiplication */
 
 inline static void
-_cogl_unpremult_alpha_0 (const guchar *src, guchar *dst)
+_cogl_unpremult_alpha_0 (guchar *dst)
 {
   dst[0] = 0;
   dst[1] = 0;
@@ -159,58 +159,58 @@ _cogl_unpremult_alpha_0 (const guchar *src, guchar *dst)
 }
 
 inline static void
-_cogl_unpremult_alpha_last (const guchar *src, guchar *dst)
+_cogl_unpremult_alpha_last (guchar *dst)
 {
-  guchar alpha = src[3];
+  guchar alpha = dst[3];
 
-  dst[0] = (src[0] * 255) / alpha;
-  dst[1] = (src[1] * 255) / alpha;
-  dst[2] = (src[2] * 255) / alpha;
-  dst[3] = alpha;
+  dst[0] = (dst[0] * 255) / alpha;
+  dst[1] = (dst[1] * 255) / alpha;
+  dst[2] = (dst[2] * 255) / alpha;
 }
 
 inline static void
-_cogl_unpremult_alpha_first (const guchar *src, guchar *dst)
+_cogl_unpremult_alpha_first (guchar *dst)
 {
-  guchar alpha = src[0];
+  guchar alpha = dst[0];
 
-  dst[0] = alpha;
-  dst[1] = (src[1] * 255) / alpha;
-  dst[2] = (src[2] * 255) / alpha;
-  dst[3] = (src[3] * 255) / alpha;
+  dst[1] = (dst[1] * 255) / alpha;
+  dst[2] = (dst[2] * 255) / alpha;
+  dst[3] = (dst[3] * 255) / alpha;
 }
 
 /* No division form of floor((c*a + 128)/255) (I first encountered
  * this in the RENDER implementation in the X server.) Being exact
  * is important for a == 255 - we want to get exactly c.
  */
-#define MULT(d,c,a,t) G_STMT_START { t = c * a + 128; d = ((t >> 8) + t) >> 8; } G_STMT_END
+#define MULT(d,a,t)                             \
+  G_STMT_START {                                \
+    t = d * a + 128;                            \
+    d = ((t >> 8) + t) >> 8;                    \
+  } G_STMT_END
 
 inline static void
-_cogl_premult_alpha_last (const guchar *src, guchar *dst)
+_cogl_premult_alpha_last (guchar *dst)
 {
-  guchar alpha = src[3];
+  guchar alpha = dst[3];
   /* Using a separate temporary per component has given slightly better
    * code generation with GCC in the past; it shouldn't do any worse in
    * any case.
    */
   guint t1, t2, t3;
-  MULT(dst[0], src[0], alpha, t1);
-  MULT(dst[1], src[1], alpha, t2);
-  MULT(dst[2], src[2], alpha, t3);
-  dst[3] = alpha;
+  MULT(dst[0], alpha, t1);
+  MULT(dst[1], alpha, t2);
+  MULT(dst[2], alpha, t3);
 }
 
 inline static void
-_cogl_premult_alpha_first (const guchar *src, guchar *dst)
+_cogl_premult_alpha_first (guchar *dst)
 {
-  guchar alpha = src[0];
+  guchar alpha = dst[0];
   guint t1, t2, t3;
 
-  dst[0] = alpha;
-  MULT(dst[1], src[1], alpha, t1);
-  MULT(dst[2], src[2], alpha, t2);
-  MULT(dst[3], src[3], alpha, t3);
+  MULT(dst[1], alpha, t1);
+  MULT(dst[2], alpha, t2);
+  MULT(dst[3], alpha, t3);
 }
 
 #undef MULT
@@ -342,56 +342,39 @@ _cogl_bitmap_fallback_convert (const CoglBitmap *bmp,
 }
 
 gboolean
-_cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp,
-                                CoglBitmap       *dst_bmp)
+_cogl_bitmap_fallback_unpremult (CoglBitmap *bmp)
 {
-  guchar  *src;
-  guchar  *dst;
-  gint     bpp;
+  guchar  *p;
   gint     x,y;
 
   /* Make sure format supported for un-premultiplication */
   if (!_cogl_bitmap_fallback_can_unpremult (bmp->format))
     return FALSE;
 
-  bpp = _cogl_get_format_bpp (bmp->format);
-
-  /* Initialize destination bitmap */
-  *dst_bmp = *bmp;
-  dst_bmp->format = (bmp->format & COGL_UNPREMULT_MASK);
-
-  /* Allocate a new buffer to hold converted data */
-  dst_bmp->data = g_malloc (sizeof(guchar)
-                           * dst_bmp->height
-                           * dst_bmp->rowstride);
-
   for (y = 0; y < bmp->height; y++)
     {
-      src = (guchar*)bmp->data      + y * bmp->rowstride;
-      dst = (guchar*)dst_bmp->data  + y * dst_bmp->rowstride;
+      p = (guchar*) bmp->data + y * bmp->rowstride;
 
       if (bmp->format & COGL_AFIRST_BIT)
         {
           for (x = 0; x < bmp->width; x++)
             {
-              if (src[0] == 0)
-                _cogl_unpremult_alpha_0 (src, dst);
+              if (p[0] == 0)
+                _cogl_unpremult_alpha_0 (p);
               else
-                _cogl_unpremult_alpha_first (src, dst);
-              src += bpp;
-              dst += bpp;
+                _cogl_unpremult_alpha_first (p);
+              p += 4;
             }
         }
       else
         {
           for (x = 0; x < bmp->width; x++)
             {
-              if (src[0] == 0)
-                _cogl_unpremult_alpha_0 (src, dst);
+              if (p[3] == 0)
+                _cogl_unpremult_alpha_0 (p);
               else
-                _cogl_unpremult_alpha_last (src, dst);
-              src += bpp;
-              dst += bpp;
+                _cogl_unpremult_alpha_last (p);
+              p += 4;
             }
         }
     }
@@ -400,52 +383,35 @@ _cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp,
 }
 
 gboolean
-_cogl_bitmap_fallback_premult (const CoglBitmap *bmp,
-                              CoglBitmap       *dst_bmp)
+_cogl_bitmap_fallback_premult (CoglBitmap *bmp)
 {
-  guchar  *src;
-  guchar  *dst;
-  gint     bpp;
+  guchar  *p;
   gint     x,y;
 
   /* Make sure format supported for un-premultiplication */
   if (!_cogl_bitmap_fallback_can_premult (bmp->format))
     return FALSE;
 
-  bpp = _cogl_get_format_bpp (bmp->format);
-
-  /* Initialize destination bitmap */
-  *dst_bmp = *bmp;
-  dst_bmp->format |= COGL_PREMULT_BIT;
-
-  /* Allocate a new buffer to hold converted data */
-  dst_bmp->data = g_malloc (sizeof(guchar)
-                           * dst_bmp->height
-                           * dst_bmp->rowstride);
-
   for (y = 0; y < bmp->height; y++)
     {
-      src = (guchar*)bmp->data      + y * bmp->rowstride;
-      dst = (guchar*)dst_bmp->data  + y * dst_bmp->rowstride;
+      p = (guchar*) bmp->data + y * bmp->rowstride;
 
       if (bmp->format & COGL_AFIRST_BIT)
-       {
-         for (x = 0; x < bmp->width; x++)
-           {
-             _cogl_premult_alpha_first (src, dst);
-             src += bpp;
-             dst += bpp;
-           }
-       }
+        {
+          for (x = 0; x < bmp->width; x++)
+            {
+              _cogl_premult_alpha_first (p);
+              p += 4;
+            }
+        }
       else
-       {
-         for (x = 0; x < bmp->width; x++)
-           {
-             _cogl_premult_alpha_last (src, dst);
-             src += bpp;
-             dst += bpp;
-           }
-       }
+        {
+          for (x = 0; x < bmp->width; x++)
+            {
+              _cogl_premult_alpha_last (p);
+              p += 4;
+            }
+        }
     }
 
   return TRUE;
index 79ed62a..b1a756a 100644 (file)
@@ -64,15 +64,13 @@ _cogl_bitmap_convert (const CoglBitmap *bmp,
 }
 
 gboolean
-_cogl_bitmap_unpremult (const CoglBitmap *bmp,
-                       CoglBitmap       *dst_bmp)
+_cogl_bitmap_unpremult (CoglBitmap *dst_bmp)
 {
   return FALSE;
 }
 
 gboolean
-_cogl_bitmap_premult (const CoglBitmap *bmp,
-                     CoglBitmap       *dst_bmp)
+_cogl_bitmap_premult (CoglBitmap *dst_bmp)
 {
   return FALSE;
 }
index b6e4257..803e10b 100644 (file)
@@ -68,20 +68,16 @@ _cogl_bitmap_fallback_convert (const CoglBitmap *bmp,
                               CoglPixelFormat   dst_format);
 
 gboolean
-_cogl_bitmap_unpremult (const CoglBitmap *bmp,
-                       CoglBitmap       *dst_bmp);
+_cogl_bitmap_unpremult (CoglBitmap *dst_bmp);
 
 gboolean
-_cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp,
-                                CoglBitmap       *dst_bmp);
+_cogl_bitmap_fallback_unpremult (CoglBitmap *dst_bmp);
 
 gboolean
-_cogl_bitmap_premult (const CoglBitmap *bmp,
-                     CoglBitmap       *dst_bmp);
+_cogl_bitmap_premult (CoglBitmap *dst_bmp);
 
 gboolean
-_cogl_bitmap_fallback_premult (const CoglBitmap *bmp,
-                              CoglBitmap       *dst_bmp);
+_cogl_bitmap_fallback_premult (CoglBitmap *dst_bmp);
 
 gboolean
 _cogl_bitmap_from_file (CoglBitmap  *bmp,
@@ -93,9 +89,13 @@ _cogl_bitmap_fallback_from_file (CoglBitmap  *bmp,
                                 const gchar *filename);
 
 gboolean
-_cogl_bitmap_convert_and_premult (const CoglBitmap *bmp,
-                                 CoglBitmap       *dst_bmp,
-                                 CoglPixelFormat   dst_format);
+_cogl_bitmap_convert_premult_status (CoglBitmap      *bmp,
+                                     CoglPixelFormat  dst_format);
+
+gboolean
+_cogl_bitmap_convert_format_and_premult (const CoglBitmap *bmp,
+                                         CoglBitmap       *dst_bmp,
+                                         CoglPixelFormat   dst_format);
 
 void
 _cogl_bitmap_copy_subregion (CoglBitmap *src,
index 3dc7fd5..fe3cbdb 100644 (file)
@@ -61,84 +61,58 @@ _cogl_get_format_bpp (CoglPixelFormat format)
 }
 
 gboolean
-_cogl_bitmap_convert_and_premult (const CoglBitmap *bmp,
-                                 CoglBitmap       *dst_bmp,
-                                 CoglPixelFormat   dst_format)
+_cogl_bitmap_convert_premult_status (CoglBitmap      *bmp,
+                                     CoglPixelFormat  dst_format)
 {
-  CoglBitmap  tmp_bmp = *bmp;
-  CoglBitmap  new_bmp = *bmp;
-  gboolean    new_bmp_owner = FALSE;
+  /* Do we need to unpremultiply? */
+  if ((bmp->format & COGL_PREMULT_BIT) > 0 &&
+      (dst_format & COGL_PREMULT_BIT) == 0)
+    /* Try unpremultiplying using imaging library */
+    return (_cogl_bitmap_unpremult (bmp)
+            /* ... or try fallback */
+            || _cogl_bitmap_fallback_unpremult (bmp));
+
+  /* Do we need to premultiply? */
+  if ((bmp->format & COGL_PREMULT_BIT) == 0 &&
+      (dst_format & COGL_PREMULT_BIT) > 0)
+    /* Try premultiplying using imaging library */
+    return (_cogl_bitmap_premult (bmp)
+            /* ... or try fallback */
+            || _cogl_bitmap_fallback_premult (bmp));
+
+  return TRUE;
+}
 
+gboolean
+_cogl_bitmap_convert_format_and_premult (const CoglBitmap *bmp,
+                                         CoglBitmap       *dst_bmp,
+                                         CoglPixelFormat   dst_format)
+{
   /* Is base format different (not considering premult status)? */
   if ((bmp->format & COGL_UNPREMULT_MASK) !=
       (dst_format & COGL_UNPREMULT_MASK))
     {
       /* Try converting using imaging library */
-      if (!_cogl_bitmap_convert (&new_bmp, &tmp_bmp, dst_format))
-       {
-         /* ... or try fallback */
-         if (!_cogl_bitmap_fallback_convert (&new_bmp, &tmp_bmp, dst_format))
-           return FALSE;
-       }
-
-      /* Update bitmap with new data */
-      new_bmp = tmp_bmp;
-      new_bmp_owner = TRUE;
+      if (!_cogl_bitmap_convert (bmp, dst_bmp, dst_format))
+        {
+          /* ... or try fallback */
+          if (!_cogl_bitmap_fallback_convert (bmp, dst_bmp, dst_format))
+            return FALSE;
+        }
     }
-
-  /* Do we need to unpremultiply */
-  if ((bmp->format & COGL_PREMULT_BIT) > 0 &&
-      (dst_format & COGL_PREMULT_BIT) == 0)
+  else
     {
-      /* Try unpremultiplying using imaging library */
-      if (!_cogl_bitmap_unpremult (&new_bmp, &tmp_bmp))
-       {
-         /* ... or try fallback */
-         if (!_cogl_bitmap_fallback_unpremult (&new_bmp, &tmp_bmp))
-           {
-             if (new_bmp_owner)
-               g_free (new_bmp.data);
-
-             return FALSE;
-           }
-       }
-
-      /* Update bitmap with new data */
-      if (new_bmp_owner)
-       g_free (new_bmp.data);
-
-      new_bmp = tmp_bmp;
-      new_bmp_owner = TRUE;
+      /* Copy the bitmap so that we can premultiply in-place */
+      *dst_bmp = *bmp;
+      dst_bmp->data = g_memdup (bmp->data, bmp->rowstride * bmp->height);
     }
 
-  /* Do we need to premultiply */
-  if ((bmp->format & COGL_PREMULT_BIT) == 0 &&
-      (dst_format & COGL_PREMULT_BIT) > 0)
+  if (!_cogl_bitmap_convert_premult_status (dst_bmp, dst_format))
     {
-      /* Try premultiplying using imaging library */
-      if (!_cogl_bitmap_premult (&new_bmp, &tmp_bmp))
-       {
-         /* ... or try fallback */
-         if (!_cogl_bitmap_fallback_premult (&new_bmp, &tmp_bmp))
-           {
-             if (new_bmp_owner)
-               g_free (new_bmp.data);
-
-             return FALSE;
-           }
-       }
-
-      /* Update bitmap with new data */
-      if (new_bmp_owner)
-       g_free (new_bmp.data);
-
-      new_bmp = tmp_bmp;
-      new_bmp_owner = TRUE;
+      g_free (dst_bmp->data);
+      return FALSE;
     }
 
-  /* Output new bitmap info */
-  *dst_bmp = new_bmp;
-
   return TRUE;
 }
 
index 7743f9f..9716062 100644 (file)
@@ -1433,9 +1433,9 @@ _cogl_texture_2d_sliced_set_region (CoglTexture    *tex,
   if (closest_format != format)
     {
       /* Convert to required format */
-      success = _cogl_bitmap_convert_and_premult (&source_bmp,
-                                                  &temp_bmp,
-                                                  closest_format);
+      success = _cogl_bitmap_convert_format_and_premult (&source_bmp,
+                                                         &temp_bmp,
+                                                         closest_format);
 
       /* Swap bitmaps if succeeded */
       if (!success) return FALSE;
@@ -1635,9 +1635,9 @@ _cogl_texture_2d_sliced_get_data (CoglTexture     *tex,
   if (closest_format != format)
     {
       /* Convert to requested format */
-      success = _cogl_bitmap_convert_and_premult (&target_bmp,
-                                                  &new_bmp,
-                                                  format);
+      success = _cogl_bitmap_convert_format_and_premult (&target_bmp,
+                                                         &new_bmp,
+                                                         format);
 
       /* Free intermediate data and return if failed */
       g_free (target_bmp.data);
index cd3f3a1..8c8a31c 100644 (file)
@@ -466,9 +466,9 @@ _cogl_texture_2d_set_region (CoglTexture    *tex,
   if (closest_format != format)
     {
       /* Convert to required format */
-      success = _cogl_bitmap_convert_and_premult (&source_bmp,
-                                                  &temp_bmp,
-                                                  closest_format);
+      success = _cogl_bitmap_convert_format_and_premult (&source_bmp,
+                                                         &temp_bmp,
+                                                         closest_format);
 
       /* Swap bitmaps if succeeded */
       if (!success) return FALSE;
@@ -570,9 +570,9 @@ _cogl_texture_2d_get_data (CoglTexture     *tex,
   if (closest_format != format)
     {
       /* Convert to requested format */
-      success = _cogl_bitmap_convert_and_premult (&target_bmp,
-                                                  &new_bmp,
-                                                  format);
+      success = _cogl_bitmap_convert_format_and_premult (&target_bmp,
+                                                         &new_bmp,
+                                                         format);
 
       /* Free intermediate data and return if failed */
       g_free (target_bmp.data);
index 09acb01..fe349f7 100644 (file)
@@ -193,9 +193,9 @@ _cogl_texture_upload_data_convert (CoglTextureUploadData *data,
   /* Convert to internal format */
   if (internal_format != data->bitmap.format)
     {
-      success = _cogl_bitmap_convert_and_premult (&data->bitmap,
-                                                 &new_bitmap,
-                                                 internal_format);
+      success = _cogl_bitmap_convert_format_and_premult (&data->bitmap,
+                                                         &new_bitmap,
+                                                         internal_format);
 
       if (!success)
        return FALSE;