From 9d9aa04b60e24542b6b2a4c6bf87115db7736c2f Mon Sep 17 00:00:00 2001 From: Martin Robinson 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 | 18 +++++++++++++++ src/cairo-gl-private.h | 1 + src/cairo-gl-surface.c | 51 +++++++++++++++++++++--------------------- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c index b6a9c15f3..5fbce5dfb 100644 --- a/src/cairo-gl-device.c +++ b/src/cairo-gl-device.c @@ -169,6 +169,22 @@ _cairo_gl_msaa_compositor_enabled (void) return env && strcmp(env, "msaa") == 0; } +static cairo_bool_t +test_can_read_bgra (cairo_gl_flavor_t gl_flavor) +{ + /* Desktop GL always supports BGRA formats. */ + if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) + return TRUE; + + assert (gl_flavor == CAIRO_GL_FLAVOR_ES); + + /* For OpenGL ES we have to look for the specific extension and BGRA only + * matches cairo's integer packed bytes on little-endian machines. */ + if (!_cairo_is_little_endian()) + return FALSE; + return _cairo_gl_has_extension ("EXT_read_format_bgra"); +} + cairo_status_t _cairo_gl_context_init (cairo_gl_context_t *ctx) { @@ -230,6 +246,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) (gl_flavor == CAIRO_GL_FLAVOR_ES && _cairo_gl_has_extension ("GL_OES_mapbuffer"))); + ctx->can_read_bgra = test_can_read_bgra (gl_flavor); + 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 088a87444..538de5704 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -357,6 +357,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 7c9332270..9cecbb60d 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -1022,6 +1022,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; @@ -1043,25 +1048,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; } @@ -1072,16 +1078,9 @@ _cairo_gl_surface_map_to_image (void *abstract_surface, extents->width, extents->height, -1); - if (unlikely (image->base.status)) + if (unlikely (image->base.status) || surface->base.serial == 0) { + status = _cairo_gl_context_release (ctx, status); return image; - - if (surface->base.serial == 0) - 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);