[cogl/wip/pbo-read-pixels: 8/18] _cogl_bitmap_convert: Also handle premult conversions



commit 089cb33603fc3cde5a6af4139249c5e735b0474d
Author: Neil Roberts <neil linux intel com>
Date:   Thu Mar 1 13:55:39 2012 +0000

    _cogl_bitmap_convert: Also handle premult conversions
    
    If we are going to unpack the data into a known format anyway we might
    as well do the premult conversion instead of delaying it to do
    in-place. This helps because not all formats with alpha channels are
    handled by the in-place premult conversion code. This removes the
    _cogl_bitmap_convert_format_and_premult function so that now
    _cogl_bitmap_convert is a completely general purpose function that can
    convert from anything to anything. _cogl_bitmap_convert now includes a
    fast path for when the base formats are the same and the premult
    conversion can be handled with the in-place code so that we don't need
    to unpack and can just copy the bitmap instead.

 cogl/cogl-bitmap-conversion.c |  158 +++++++++++++++++++++++++++++++----------
 cogl/cogl-bitmap-private.h    |    4 -
 cogl/cogl-bitmap.c            |   55 --------------
 cogl/cogl-texture.c           |   18 ++---
 cogl/cogl.c                   |    3 +-
 5 files changed, 127 insertions(+), 111 deletions(-)
---
diff --git a/cogl/cogl-bitmap-conversion.c b/cogl/cogl-bitmap-conversion.c
index b9a0d36..5bdb7cc 100644
--- a/cogl/cogl-bitmap-conversion.c
+++ b/cogl/cogl-bitmap-conversion.c
@@ -191,6 +191,81 @@ _cogl_premult_alpha_last_four_pixels_sse2 (guint8 *p)
 
 #endif /* COGL_USE_PREMULT_SSE2 */
 
+static void
+_cogl_bitmap_premult_unpacked_span_guint8 (guint8 *data,
+                                           int width)
+{
+#ifdef COGL_USE_PREMULT_SSE2
+
+  /* Process 4 pixels at a time */
+  while (width >= 4)
+    {
+      _cogl_premult_alpha_last_four_pixels_sse2 (data);
+      data += 4 * 4;
+      width -= 4;
+    }
+
+  /* If there are any pixels left we will fall through and
+     handle them below */
+
+#endif /* COGL_USE_PREMULT_SSE2 */
+
+  while (width-- > 0)
+    {
+      _cogl_premult_alpha_last (data);
+      data += 4;
+    }
+}
+
+static void
+_cogl_bitmap_unpremult_unpacked_span_guint8 (guint8 *data,
+                                             int width)
+{
+  int x;
+
+  for (x = 0; x < width; x++)
+    {
+      if (data[3] == 0)
+        _cogl_unpremult_alpha_0 (data);
+      else
+        _cogl_unpremult_alpha_last (data);
+      data += 4;
+    }
+}
+
+static void
+_cogl_bitmap_unpremult_unpacked_span_guint16 (guint16 *data,
+                                              int width)
+{
+  while (width-- > 0)
+    {
+      guint16 alpha = data[3];
+
+      if (alpha == 0)
+        memset (data, 0, sizeof (guint16) * 3);
+      else
+        {
+          data[0] = (data[0] * 65535) / alpha;
+          data[1] = (data[1] * 65535) / alpha;
+          data[2] = (data[2] * 65535) / alpha;
+        }
+    }
+}
+
+static void
+_cogl_bitmap_premult_unpacked_span_guint16 (guint16 *data,
+                                            int width)
+{
+  while (width-- > 0)
+    {
+      guint16 alpha = data[3];
+
+      data[0] = (data[0] * alpha) / 65535;
+      data[1] = (data[1] * alpha) / 65535;
+      data[2] = (data[2] * alpha) / 65535;
+    }
+}
+
 static gboolean
 _cogl_bitmap_can_premult (CoglPixelFormat format)
 {
@@ -223,12 +298,36 @@ _cogl_bitmap_convert (CoglBitmap      *src_bmp,
   int              width, height;
   CoglPixelFormat  src_format;
   gboolean         use_16;
+  gboolean         need_premult;
 
   src_format = _cogl_bitmap_get_format (src_bmp);
   src_rowstride = _cogl_bitmap_get_rowstride (src_bmp);
   width = _cogl_bitmap_get_width (src_bmp);
   height = _cogl_bitmap_get_height (src_bmp);
 
+  need_premult
+    = ((src_format & COGL_PREMULT_BIT) != (dst_format & COGL_PREMULT_BIT) &&
+       src_format != COGL_PIXEL_FORMAT_A_8 &&
+       dst_format != COGL_PIXEL_FORMAT_A_8 &&
+       (src_format & dst_format & COGL_A_BIT));
+
+  /* If the base format is the same then we can just copy the bitmap
+     instead */
+  if ((src_format & ~COGL_PREMULT_BIT) == (dst_format & ~COGL_PREMULT_BIT) &&
+      (!need_premult || _cogl_bitmap_can_premult (dst_format)))
+    {
+      CoglBitmap *dst_bmp = _cogl_bitmap_copy (src_bmp);
+
+      if (need_premult &&
+          !_cogl_bitmap_convert_premult_status (dst_bmp, dst_format))
+        {
+          cogl_object_unref (dst_bmp);
+          return NULL;
+        }
+
+      return dst_bmp;
+    }
+
   src_data = _cogl_bitmap_map (src_bmp, COGL_BUFFER_ACCESS_READ, 0);
   if (src_data == NULL)
     return NULL;
@@ -245,10 +344,6 @@ _cogl_bitmap_convert (CoglBitmap      *src_bmp,
 
   /* Initialize destination bitmap */
   dst_rowstride = (sizeof(guint8) * dst_bpp * width + 3) & ~3;
-  /* Copy the premult bit if the new format has an alpha channel */
-  if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (dst_format))
-    dst_format = ((src_format & COGL_PREMULT_BIT) |
-                  (dst_format & ~COGL_PREMULT_BIT));
 
   /* Allocate a new buffer to hold converted data */
   dst_data = g_malloc (height * dst_rowstride);
@@ -267,6 +362,25 @@ _cogl_bitmap_convert (CoglBitmap      *src_bmp,
       else
         _cogl_unpack_guint8 (src_format, src, tmp_row, width);
 
+      /* Handle premultiplication */
+      if (need_premult)
+        {
+          if (dst_format & COGL_PREMULT_BIT)
+            {
+              if (use_16)
+                _cogl_bitmap_premult_unpacked_span_guint16 (tmp_row, width);
+              else
+                _cogl_bitmap_premult_unpacked_span_guint8 (tmp_row, width);
+            }
+          else
+            {
+              if (use_16)
+                _cogl_bitmap_unpremult_unpacked_span_guint16 (tmp_row, width);
+              else
+                _cogl_bitmap_unpremult_unpacked_span_guint8 (tmp_row, width);
+            }
+        }
+
       if (use_16)
         _cogl_pack_guint16 (dst_format, tmp_row, dst, width);
       else
@@ -324,16 +438,7 @@ _cogl_bitmap_unpremult (CoglBitmap *bmp)
             }
         }
       else
-        {
-          for (x = 0; x < width; x++)
-            {
-              if (p[3] == 0)
-                _cogl_unpremult_alpha_0 (p);
-              else
-                _cogl_unpremult_alpha_last (p);
-              p += 4;
-            }
-        }
+        _cogl_bitmap_unpremult_unpacked_span_guint8 (p, width);
     }
 
   _cogl_bitmap_unmap (bmp);
@@ -380,30 +485,7 @@ _cogl_bitmap_premult (CoglBitmap *bmp)
             }
         }
       else
-        {
-          x = width;
-
-#ifdef COGL_USE_PREMULT_SSE2
-
-          /* Process 4 pixels at a time */
-          while (x >= 4)
-            {
-              _cogl_premult_alpha_last_four_pixels_sse2 (p);
-              p += 4 * 4;
-              x -= 4;
-            }
-
-          /* If there are any pixels left we will fall through and
-             handle them below */
-
-#endif /* COGL_USE_PREMULT_SSE2 */
-
-          while (x-- > 0)
-            {
-              _cogl_premult_alpha_last (p);
-              p += 4;
-            }
-        }
+        _cogl_bitmap_premult_unpacked_span_guint8 (p, width);
     }
 
   _cogl_bitmap_unmap (bmp);
diff --git a/cogl/cogl-bitmap-private.h b/cogl/cogl-bitmap-private.h
index 7bbdc73..d393041 100644
--- a/cogl/cogl-bitmap-private.h
+++ b/cogl/cogl-bitmap-private.h
@@ -101,10 +101,6 @@ gboolean
 _cogl_bitmap_convert_premult_status (CoglBitmap      *bmp,
                                      CoglPixelFormat  dst_format);
 
-CoglBitmap *
-_cogl_bitmap_convert_format_and_premult (CoglBitmap *bmp,
-                                         CoglPixelFormat   dst_format);
-
 void
 _cogl_bitmap_copy_subregion (CoglBitmap *src,
 			     CoglBitmap *dst,
diff --git a/cogl/cogl-bitmap.c b/cogl/cogl-bitmap.c
index 46930de..c165e36 100644
--- a/cogl/cogl-bitmap.c
+++ b/cogl/cogl-bitmap.c
@@ -100,61 +100,6 @@ _cogl_bitmap_convert_premult_status (CoglBitmap      *bmp,
 }
 
 CoglBitmap *
-_cogl_bitmap_convert_format_and_premult (CoglBitmap *bmp,
-                                         CoglPixelFormat   dst_format)
-{
-  CoglPixelFormat src_format = _cogl_bitmap_get_format (bmp);
-  CoglBitmap *dst_bmp;
-
-  /* Is base format different (not considering premult status)? */
-  if ((src_format & ~COGL_PREMULT_BIT) !=
-      (dst_format & ~COGL_PREMULT_BIT))
-    {
-      if ((dst_bmp = _cogl_bitmap_convert (bmp, dst_format)) == NULL)
-        return NULL;
-    }
-  else
-    {
-      int rowstride = _cogl_bitmap_get_rowstride (bmp);
-      int height = _cogl_bitmap_get_height (bmp);
-      guint8 *data;
-
-      /* Copy the bitmap so that we can premultiply in-place */
-
-      if ((data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0)) == NULL)
-        return NULL;
-
-      dst_bmp = _cogl_bitmap_new_from_data (g_memdup (data, height * rowstride),
-                                            src_format,
-                                            _cogl_bitmap_get_width (bmp),
-                                            height,
-                                            rowstride,
-                                            (CoglBitmapDestroyNotify) g_free,
-                                            NULL);
-
-      _cogl_bitmap_unmap (bmp);
-    }
-
-  src_format = _cogl_bitmap_get_format (dst_bmp);
-
-  /* We only need to do a premult conversion if both formats have an
-     alpha channel. If we're converting from RGB to RGBA then the
-     alpha will have been filled with 255 so the premult won't do
-     anything or if we are converting from RGBA to RGB we're losing
-     information so either converting or not will be wrong for
-     transparent pixels */
-  if ((src_format & COGL_A_BIT) == COGL_A_BIT &&
-      (dst_format & COGL_A_BIT) == COGL_A_BIT &&
-      !_cogl_bitmap_convert_premult_status (dst_bmp, dst_format))
-    {
-      cogl_object_unref (dst_bmp);
-      return NULL;
-    }
-
-  return dst_bmp;
-}
-
-CoglBitmap *
 _cogl_bitmap_copy (CoglBitmap *src_bmp)
 {
   CoglBitmap *dst_bmp;
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index d9eec4a..38e9232 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -200,15 +200,11 @@ _cogl_texture_prepare_for_upload (CoglBitmap      *src_bmp,
       if (_cogl_texture_needs_premult_conversion (src_format,
                                                   dst_format))
         {
-          dst_bmp = _cogl_bitmap_copy (src_bmp);
+          dst_bmp = _cogl_bitmap_convert (src_bmp,
+                                          src_format ^ COGL_PREMULT_BIT);
 
-          if (!_cogl_bitmap_convert_premult_status (dst_bmp,
-                                                    src_format ^
-                                                    COGL_PREMULT_BIT))
-            {
-              cogl_object_unref (dst_bmp);
-              return NULL;
-            }
+          if (dst_bmp == NULL)
+            return NULL;
         }
       else
         dst_bmp = cogl_object_ref (src_bmp);
@@ -236,8 +232,7 @@ _cogl_texture_prepare_for_upload (CoglBitmap      *src_bmp,
                                                                 out_gltype);
 
       if (closest_format != src_format)
-        dst_bmp = _cogl_bitmap_convert_format_and_premult (src_bmp,
-                                                           closest_format);
+        dst_bmp = _cogl_bitmap_convert (src_bmp, closest_format);
       else
         dst_bmp = cogl_object_ref (src_bmp);
     }
@@ -1302,8 +1297,7 @@ cogl_texture_get_data (CoglTexture     *texture,
       int new_bmp_rowstride;
 
       /* Convert to requested format */
-      new_bmp = _cogl_bitmap_convert_format_and_premult (target_bmp,
-                                                         format);
+      new_bmp = _cogl_bitmap_convert (target_bmp, format);
 
       /* Free intermediate data and return if failed */
       cogl_object_unref (target_bmp);
diff --git a/cogl/cogl.c b/cogl/cogl.c
index f9aa3ca..9764578 100644
--- a/cogl/cogl.c
+++ b/cogl/cogl.c
@@ -503,8 +503,7 @@ _cogl_read_pixels_with_rowstride (int x,
       /* CoglBitmap doesn't currently have a way to convert without
          allocating its own buffer so we have to copy the data
          again */
-      if ((dst_bmp = _cogl_bitmap_convert_format_and_premult (tmp_bmp,
-                                                              format)))
+      if ((dst_bmp = _cogl_bitmap_convert (tmp_bmp, format)))
         {
           _cogl_bitmap_copy_subregion (dst_bmp,
                                        bmp,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]