[PATCH] gl: Add BGRA download support for GLES2
Martin Robinson <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <[email protected]> |
From 18d6453c59f1a774e7a8435354e3cec9ccf1114a Mon Sep 17 00:00:00 2001 From: Martin Robinson <[email protected]> Date: Mon, 3 Dec 2012 16:08:23 -0800 Subject: [PATCH] gl: Add BGRA download support for GLES2 Some OpenGLES2 drivers support downloading BGRA data. On little-endian systems BGRA and GL_UNSIGNED_BYTE is equivalent to the typical cairo_image_t format, so this can prevent CPU bit swizzling for operations that involve images. --- src/cairo-gl-device.c | 10 ++++++++++ src/cairo-gl-private.h | 1 + src/cairo-gl-surface.c | 51 ++++++++++++++++++++++++------------------------ 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c index 6563b3b..99b10f4 100644 --- a/src/cairo-gl-device.c +++ b/src/cairo-gl-device.c @@ -225,6 +225,16 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) (gl_flavor == CAIRO_GL_FLAVOR_ES && _cairo_gl_has_extension ("GL_OES_mapbuffer"))); + /* CAIRO_FORMAT_ARGB32 is stored based on the endianness of the CPU. For + * desktop GL we can always read this format directly since glReadPixels + * with GL_UNSIGNED_INT_8_8_8_8_REV + GL_BGRA will produce this. OpenGLES2 + * does not support GL_UNSIGNED_INT_8_8_8_8_REV and GL_UNSIGNED_BYTE orders + * the components similarly regardless of endianness. Thus, GL_BGRA + * is only equivalent to CAIRO_FORMAT_ARGB32 on little-endian CPUs. */ + ctx->can_read_bgra = gl_flavor == CAIRO_GL_FLAVOR_DESKTOP || + (_cairo_is_little_endian () && gl_flavor == CAIRO_GL_FLAVOR_ES && + _cairo_gl_has_extension ("EXT_read_format_bgra")); + ctx->has_mesa_pack_invert = _cairo_gl_has_extension ("GL_MESA_pack_invert"); diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 7c97c49..f174674 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -350,6 +350,7 @@ struct _cairo_gl_context { cairo_bool_t has_map_buffer; cairo_bool_t has_packed_depth_stencil; cairo_bool_t has_npot_repeat; + cairo_bool_t can_read_bgra; cairo_bool_t thread_aware; diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index c0ee79f..83efa17 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -999,6 +999,11 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, cairo_status_t status; int y; + status = _cairo_gl_context_acquire (surface->base.device, &ctx); + if (unlikely (status)) { + return _cairo_image_surface_create_in_error (status); + } + /* Want to use a switch statement here but the compiler gets whiny. */ if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) { format = GL_BGRA; @@ -1020,25 +1025,26 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, return NULL; } - /* - * GLES2 supports only RGBA, UNSIGNED_BYTE so use that. - * We are also using this format for ALPHA as GLES2 does not - * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the - * pixman image that is created has row_stride = row_width * bpp. - */ if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) { - format = GL_RGBA; - if (! _cairo_is_little_endian ()) { - if (surface->base.content == CAIRO_CONTENT_COLOR) - pixman_format = PIXMAN_r8g8b8x8; - else - pixman_format = PIXMAN_r8g8b8a8; - } else { - if (surface->base.content == CAIRO_CONTENT_COLOR) - pixman_format = PIXMAN_x8b8g8r8; - else - pixman_format = PIXMAN_a8b8g8r8; + /* If only RGBA is supported, we must download data in a compatible + * format. This means that pixman will convert the data on the CPU when + * interacting with other image surfaces. For ALPHA, GLES2 does not + * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the + * pixman image that is created has row_stride = row_width * bpp. */ + if (surface->base.content == CAIRO_CONTENT_ALPHA || !ctx->can_read_bgra) { + cairo_bool_t little_endian = _cairo_is_little_endian (); + format = GL_RGBA; + + if (surface->base.content == CAIRO_CONTENT_COLOR) { + pixman_format = little_endian ? + PIXMAN_x8b8g8r8 : PIXMAN_r8g8b8x8; + } else { + pixman_format = little_endian ? + PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8; + } } + + /* GLES2 only supports GL_UNSIGNED_BYTE. */ type = GL_UNSIGNED_BYTE; cpp = 4; } @@ -1049,16 +1055,9 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, extents->width, extents->height, -1); - if (unlikely (image->base.status)) - return image; - - if (surface->base.serial == 0) + if (unlikely (image->base.status) || surface->base.serial == 0) { + status = _cairo_gl_context_release (ctx, status); return image; - - status = _cairo_gl_context_acquire (surface->base.device, &ctx); - if (unlikely (status)) { - cairo_surface_destroy (&image->base); - return _cairo_image_surface_create_in_error (status); } cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y); -- 1.7.10.4 -- cairo mailing list [email protected] http://lists.cairographics.org/mailman/listinfo/cairo