mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 19:42:05 +00: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 */
|
||||
|
||||
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);
|
||||
|
@ -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,
|
||||
|
@ -99,61 +99,6 @@ _cogl_bitmap_convert_premult_status (CoglBitmap *bmp,
|
||||
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 *
|
||||
_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,
|
||||
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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user