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.
This commit is contained in:
parent
72fba19eac
commit
e83ffb1fa3
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user