[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.