[cogl] _cogl_bitmap_convert: Also handle premult conversions
- From: Neil Roberts <nroberts src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [cogl] _cogl_bitmap_convert: Also handle premult conversions
- Date: Mon, 5 Mar 2012 19:41:15 +0000 (UTC)
commit f4cd5aceb923bc984a97f73a7ac4a5a9c588bb28
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.
Reviewed-by: Robert Bragg <robert linux intel com>
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 b085f6e..b9bcf75 100644
--- a/cogl/cogl-bitmap-conversion.c
+++ b/cogl/cogl-bitmap-conversion.c
@@ -203,6 +203,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)
{
@@ -283,12 +358,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;
@@ -299,10 +398,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);
@@ -321,6 +416,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
@@ -378,16 +492,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);
@@ -434,30 +539,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]