From: Neil Roberts Date: Fri, 29 Jan 2010 15:15:08 +0000 (+0000) Subject: cogl: Do the premult conversion in-place rather than copying to a new buffer X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e83ffb1fa3436bf1506c32856b2a3ba23254e068;p=profile%2Fivi%2Fclutter.git cogl: Do the premult conversion in-place rather than copying to a new buffer 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. --- diff --git a/clutter/cogl/cogl/cogl-atlas-texture.c b/clutter/cogl/cogl/cogl-atlas-texture.c index 545c68d..efd8052 100644 --- a/clutter/cogl/cogl/cogl-atlas-texture.c +++ b/clutter/cogl/cogl/cogl-atlas-texture.c @@ -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; diff --git a/clutter/cogl/cogl/cogl-bitmap-fallback.c b/clutter/cogl/cogl/cogl-bitmap-fallback.c index ddff6ea..097cc52 100644 --- a/clutter/cogl/cogl/cogl-bitmap-fallback.c +++ b/clutter/cogl/cogl/cogl-bitmap-fallback.c @@ -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; diff --git a/clutter/cogl/cogl/cogl-bitmap-pixbuf.c b/clutter/cogl/cogl/cogl-bitmap-pixbuf.c index 79ed62a..b1a756a 100644 --- a/clutter/cogl/cogl/cogl-bitmap-pixbuf.c +++ b/clutter/cogl/cogl/cogl-bitmap-pixbuf.c @@ -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; } diff --git a/clutter/cogl/cogl/cogl-bitmap-private.h b/clutter/cogl/cogl/cogl-bitmap-private.h index b6e4257..803e10b 100644 --- a/clutter/cogl/cogl/cogl-bitmap-private.h +++ b/clutter/cogl/cogl/cogl-bitmap-private.h @@ -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, diff --git a/clutter/cogl/cogl/cogl-bitmap.c b/clutter/cogl/cogl/cogl-bitmap.c index 3dc7fd5..fe3cbdb 100644 --- a/clutter/cogl/cogl/cogl-bitmap.c +++ b/clutter/cogl/cogl/cogl-bitmap.c @@ -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; } diff --git a/clutter/cogl/cogl/cogl-texture-2d-sliced.c b/clutter/cogl/cogl/cogl-texture-2d-sliced.c index 7743f9f..9716062 100644 --- a/clutter/cogl/cogl/cogl-texture-2d-sliced.c +++ b/clutter/cogl/cogl/cogl-texture-2d-sliced.c @@ -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); diff --git a/clutter/cogl/cogl/cogl-texture-2d.c b/clutter/cogl/cogl/cogl-texture-2d.c index cd3f3a1..8c8a31c 100644 --- a/clutter/cogl/cogl/cogl-texture-2d.c +++ b/clutter/cogl/cogl/cogl-texture-2d.c @@ -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); diff --git a/clutter/cogl/cogl/cogl-texture.c b/clutter/cogl/cogl/cogl-texture.c index 09acb01..fe349f7 100644 --- a/clutter/cogl/cogl/cogl-texture.c +++ b/clutter/cogl/cogl/cogl-texture.c @@ -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;