mirror of
https://github.com/brl/mutter.git
synced 2024-11-23 00:20:42 -05:00
_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>
This commit is contained in:
parent
8ce5f5ade8
commit
f4cd5aceb9
@ -203,6 +203,81 @@ _cogl_premult_alpha_last_four_pixels_sse2 (guint8 *p)
|
|||||||
|
|
||||||
#endif /* COGL_USE_PREMULT_SSE2 */
|
#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
|
static gboolean
|
||||||
_cogl_bitmap_can_premult (CoglPixelFormat format)
|
_cogl_bitmap_can_premult (CoglPixelFormat format)
|
||||||
{
|
{
|
||||||
@ -283,12 +358,36 @@ _cogl_bitmap_convert (CoglBitmap *src_bmp,
|
|||||||
int width, height;
|
int width, height;
|
||||||
CoglPixelFormat src_format;
|
CoglPixelFormat src_format;
|
||||||
gboolean use_16;
|
gboolean use_16;
|
||||||
|
gboolean need_premult;
|
||||||
|
|
||||||
src_format = _cogl_bitmap_get_format (src_bmp);
|
src_format = _cogl_bitmap_get_format (src_bmp);
|
||||||
src_rowstride = _cogl_bitmap_get_rowstride (src_bmp);
|
src_rowstride = _cogl_bitmap_get_rowstride (src_bmp);
|
||||||
width = _cogl_bitmap_get_width (src_bmp);
|
width = _cogl_bitmap_get_width (src_bmp);
|
||||||
height = _cogl_bitmap_get_height (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);
|
src_data = _cogl_bitmap_map (src_bmp, COGL_BUFFER_ACCESS_READ, 0);
|
||||||
if (src_data == NULL)
|
if (src_data == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -299,10 +398,6 @@ _cogl_bitmap_convert (CoglBitmap *src_bmp,
|
|||||||
|
|
||||||
/* Initialize destination bitmap */
|
/* Initialize destination bitmap */
|
||||||
dst_rowstride = (sizeof(guint8) * dst_bpp * width + 3) & ~3;
|
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 */
|
/* Allocate a new buffer to hold converted data */
|
||||||
dst_data = g_malloc (height * dst_rowstride);
|
dst_data = g_malloc (height * dst_rowstride);
|
||||||
@ -321,6 +416,25 @@ _cogl_bitmap_convert (CoglBitmap *src_bmp,
|
|||||||
else
|
else
|
||||||
_cogl_unpack_guint8 (src_format, src, tmp_row, width);
|
_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)
|
if (use_16)
|
||||||
_cogl_pack_guint16 (dst_format, tmp_row, dst, width);
|
_cogl_pack_guint16 (dst_format, tmp_row, dst, width);
|
||||||
else
|
else
|
||||||
@ -378,16 +492,7 @@ _cogl_bitmap_unpremult (CoglBitmap *bmp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
_cogl_bitmap_unpremult_unpacked_span_guint8 (p, width);
|
||||||
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_unmap (bmp);
|
_cogl_bitmap_unmap (bmp);
|
||||||
@ -434,30 +539,7 @@ _cogl_bitmap_premult (CoglBitmap *bmp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
_cogl_bitmap_premult_unpacked_span_guint8 (p, width);
|
||||||
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_unmap (bmp);
|
_cogl_bitmap_unmap (bmp);
|
||||||
|
@ -101,10 +101,6 @@ gboolean
|
|||||||
_cogl_bitmap_convert_premult_status (CoglBitmap *bmp,
|
_cogl_bitmap_convert_premult_status (CoglBitmap *bmp,
|
||||||
CoglPixelFormat dst_format);
|
CoglPixelFormat dst_format);
|
||||||
|
|
||||||
CoglBitmap *
|
|
||||||
_cogl_bitmap_convert_format_and_premult (CoglBitmap *bmp,
|
|
||||||
CoglPixelFormat dst_format);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_cogl_bitmap_copy_subregion (CoglBitmap *src,
|
_cogl_bitmap_copy_subregion (CoglBitmap *src,
|
||||||
CoglBitmap *dst,
|
CoglBitmap *dst,
|
||||||
|
@ -99,61 +99,6 @@ _cogl_bitmap_convert_premult_status (CoglBitmap *bmp,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 *
|
CoglBitmap *
|
||||||
_cogl_bitmap_copy (CoglBitmap *src_bmp)
|
_cogl_bitmap_copy (CoglBitmap *src_bmp)
|
||||||
{
|
{
|
||||||
|
@ -200,15 +200,11 @@ _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
|
|||||||
if (_cogl_texture_needs_premult_conversion (src_format,
|
if (_cogl_texture_needs_premult_conversion (src_format,
|
||||||
dst_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,
|
if (dst_bmp == NULL)
|
||||||
src_format ^
|
return NULL;
|
||||||
COGL_PREMULT_BIT))
|
|
||||||
{
|
|
||||||
cogl_object_unref (dst_bmp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
dst_bmp = cogl_object_ref (src_bmp);
|
dst_bmp = cogl_object_ref (src_bmp);
|
||||||
@ -236,8 +232,7 @@ _cogl_texture_prepare_for_upload (CoglBitmap *src_bmp,
|
|||||||
out_gltype);
|
out_gltype);
|
||||||
|
|
||||||
if (closest_format != src_format)
|
if (closest_format != src_format)
|
||||||
dst_bmp = _cogl_bitmap_convert_format_and_premult (src_bmp,
|
dst_bmp = _cogl_bitmap_convert (src_bmp, closest_format);
|
||||||
closest_format);
|
|
||||||
else
|
else
|
||||||
dst_bmp = cogl_object_ref (src_bmp);
|
dst_bmp = cogl_object_ref (src_bmp);
|
||||||
}
|
}
|
||||||
@ -1302,8 +1297,7 @@ cogl_texture_get_data (CoglTexture *texture,
|
|||||||
int new_bmp_rowstride;
|
int new_bmp_rowstride;
|
||||||
|
|
||||||
/* Convert to requested format */
|
/* Convert to requested format */
|
||||||
new_bmp = _cogl_bitmap_convert_format_and_premult (target_bmp,
|
new_bmp = _cogl_bitmap_convert (target_bmp, format);
|
||||||
format);
|
|
||||||
|
|
||||||
/* Free intermediate data and return if failed */
|
/* Free intermediate data and return if failed */
|
||||||
cogl_object_unref (target_bmp);
|
cogl_object_unref (target_bmp);
|
||||||
|
@ -503,8 +503,7 @@ _cogl_read_pixels_with_rowstride (int x,
|
|||||||
/* CoglBitmap doesn't currently have a way to convert without
|
/* CoglBitmap doesn't currently have a way to convert without
|
||||||
allocating its own buffer so we have to copy the data
|
allocating its own buffer so we have to copy the data
|
||||||
again */
|
again */
|
||||||
if ((dst_bmp = _cogl_bitmap_convert_format_and_premult (tmp_bmp,
|
if ((dst_bmp = _cogl_bitmap_convert (tmp_bmp, format)))
|
||||||
format)))
|
|
||||||
{
|
{
|
||||||
_cogl_bitmap_copy_subregion (dst_bmp,
|
_cogl_bitmap_copy_subregion (dst_bmp,
|
||||||
bmp,
|
bmp,
|
||||||
|
Loading…
Reference in New Issue
Block a user