[cairo] [PATCH] gl: Add BGRA download support for GLES2

Martin Robinson mrobinson at igalia.com
Wed Dec 5 16:28:03 PST 2012


>From 18d6453c59f1a774e7a8435354e3cec9ccf1114a Mon Sep 17 00:00:00 2001
From: Martin Robinson <mrobinson at igalia.com>
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



More information about the cairo mailing list