[cairo] [patch 1/2] gl: create BGRA texture if driver supports

Henry (Yu) Song - SISA hsong at sisa.samsung.com
Fri Feb 1 14:09:22 PST 2013


>From 9ed43276f513c0e818948227029b739faf22c4e0 Mon Sep 17 00:00:00 2001
From: Henry Song <henry.song at samsung.com>
Date: Fri, 1 Feb 2013 11:50:49 -0800
Subject: [PATCH 1/2] gl: Create BGRA texture if driver supports it

GLES2 drivers can create BGRA format texture if the driver supports
GL_EXT_texture_format_BGRA8888.  In addition, GLES2 can also read
BGRA data if the driver supports GL_EXT_read_bgra.  If both extensions
are present, we can create BGRA texture to avoid image conversion
during upload and download. Also add a function that does BGRA to RGBA
conversion during _cairo_gl_surface_draw_image().
---
 src/cairo-gl-private.h          |    2 +
 src/cairo-gl-surface.c          |   92 +++++++++++++++++++++++++++++++++++++--
 src/cairo-gl-traps-compositor.c |   30 -------------
 3 files changed, 90 insertions(+), 34 deletions(-)

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index a75afa7..fcaf973 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -183,6 +183,8 @@ struct _cairo_gl_surface {
     cairo_bool_t needs_update;
 
     cairo_region_t *clip_region;
+
+    GLenum texture_format;
 };
 
 typedef struct cairo_gl_glyph_cache {
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 922f234..73129e3 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -391,6 +391,7 @@ _cairo_gl_surface_init (cairo_device_t *device,
     surface->width = width;
     surface->height = height;
     surface->needs_update = FALSE;
+    surface->texture_format = GL_RGBA;
 
     _cairo_gl_surface_embedded_operand_init (surface);
 }
@@ -434,6 +435,9 @@ _create_scratch_internal (cairo_gl_context_t *ctx,
     cairo_gl_surface_t *surface;
     GLenum format;
     GLuint tex;
+    cairo_bool_t can_create_bgra_texture = 
+	( ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	  ctx->can_read_bgra );
 
     glGenTextures (1, &tex);
     surface = (cairo_gl_surface_t *)
@@ -454,7 +458,11 @@ _create_scratch_internal (cairo_gl_context_t *ctx,
     default:
 	ASSERT_NOT_REACHED;
     case CAIRO_CONTENT_COLOR_ALPHA:
-	format = GL_RGBA;
+	/* Create BGRA format if the driver supports that */
+	if (can_create_bgra_texture)
+	    format = GL_BGRA;
+	else
+	    format = GL_RGBA;
 	break;
     case CAIRO_CONTENT_ALPHA:
 	/* When using GL_ALPHA, compositing doesn't work properly, but for
@@ -462,8 +470,12 @@ _create_scratch_internal (cairo_gl_context_t *ctx,
 	 * an issue. */
 	if (for_caching)
 	    format = GL_ALPHA;
-	else
-	    format = GL_RGBA;
+	else {
+	    if (can_create_bgra_texture)
+		format = GL_BGRA;
+	    else
+		format = GL_RGBA;
+	}
 	break;
     case CAIRO_CONTENT_COLOR:
 	/* GL_RGB is almost what we want here -- sampling 1 alpha when
@@ -474,10 +486,14 @@ _create_scratch_internal (cairo_gl_context_t *ctx,
 	 * specified.  So, we have to store RGBA, and fill the alpha
 	 * channel with 1 when blending.
 	 */
-	format = GL_RGBA;
+	if (can_create_bgra_texture)
+	    format = GL_BGRA;
+	else
+	    format = GL_RGBA;
 	break;
     }
 
+    surface->texture_format = format;
     glTexImage2D (ctx->tex_target, 0, format, width, height, 0,
 		  format, GL_UNSIGNED_BYTE, NULL);
 
@@ -835,6 +851,58 @@ _cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t *dst,
     return status;
 }
 
+static cairo_image_surface_t *
+_cairo_gl_convert_image (cairo_gl_context_t    *ctx,
+			 cairo_gl_surface_t    *dst,
+			 cairo_image_surface_t *src,
+			 int		       *src_x,
+			 int		       *src_y,
+			 int			width,
+			 int			height,
+			 GLenum		       *format)
+{
+    cairo_image_surface_t *bgra_src;
+    pixman_format_code_t pixman_format;
+    int stride = 4 * width;
+
+    /* There is no need to create BGRA format image if the driver can
+     * read BGRA/BGR data, this includes
+     * 1. GL drivers
+     * 2. GLES 2 drivers support GL_EXT_read_bgra AND the image is 
+     *    BGRA/BGR
+     */
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
+	(ctx->can_read_bgra 		     &&
+	 (src->format == CAIRO_FORMAT_ARGB32 ||
+	  src->format == CAIRO_FORMAT_RGB24)))
+	return (cairo_image_surface_t *) cairo_surface_reference (&src->base);
+    
+    /* if we have created the dst as GL_ALPHA and it is created for glyph
+     * cache, we don' need convert */
+    if (src->base.content == CAIRO_CONTENT_ALPHA &&
+	dst->texture_format == GL_ALPHA		 &&
+	dst->tex				 &&
+	dst->owns_tex)
+	return (cairo_image_surface_t *) cairo_surface_reference (&src->base);
+
+    pixman_format = _cairo_is_little_endian () ?
+	PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
+
+    bgra_src = _cairo_image_surface_create_from_image (src,
+						       pixman_format,
+						       *src_x, *src_y,
+						       width, height,
+						       stride);
+    if (unlikely (bgra_src->base.status))
+	return bgra_src;
+
+    *src_x = 0;
+    *src_y = 0;
+    *format = GL_RGBA;
+
+    return bgra_src;
+}
+
 cairo_status_t
 _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 			      cairo_image_surface_t *src,
@@ -845,6 +913,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
     GLenum internal_format, format, type;
     cairo_bool_t has_alpha, needs_swap;
     cairo_image_surface_t *clone = NULL;
+    cairo_image_surface_t *converted_src = NULL;
     cairo_gl_context_t *ctx;
     int cpp;
     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
@@ -880,6 +949,19 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	src = clone;
     }
 
+    /* let's make sure the image src is the right format we can upload */
+    converted_src = _cairo_gl_convert_image (ctx, dst, src,
+					     &src_x, &src_y,
+					     width, height,
+					     &format);
+
+    if (unlikely (converted_src->base.status)) {
+	status = converted_src->base.status;
+	goto FAIL;
+    }
+
+    src = converted_src;
+
     cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
 
     status = _cairo_gl_surface_flush (&dst->base, 0);
@@ -982,6 +1064,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 FAIL:
     status = _cairo_gl_context_release (ctx, status);
 
+    cairo_surface_destroy (&converted_src->base);
+
     if (clone)
         cairo_surface_destroy (&clone->base);
 
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
index b6c2333..620b3fd 100644
--- a/src/cairo-gl-traps-compositor.c
+++ b/src/cairo-gl-traps-compositor.c
@@ -302,36 +302,6 @@ traps_to_operand (void *_dst,
 	return image->status;
     }
 
-    /* GLES2 only supports RGB/RGBA when uploading */
-    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) {
-	cairo_surface_pattern_t pattern;
-	cairo_surface_t *rgba_image;
-
-	/* XXX perform this fixup inside _cairo_gl_draw_image() */
-
-	rgba_image =
-	    _cairo_image_surface_create_with_pixman_format (NULL,
-							    _cairo_is_little_endian () ?  PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8,
-							    extents->width,
-							    extents->height,
-							    0);
-	if (unlikely (rgba_image->status))
-	    return rgba_image->status;
-
-	_cairo_pattern_init_for_surface (&pattern, image);
-	status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE,
-				       &pattern.base, NULL);
-	_cairo_pattern_fini (&pattern.base);
-
-	cairo_surface_destroy (image);
-	image = rgba_image;
-
-	if (unlikely (status)) {
-	    cairo_surface_destroy (image);
-	    return status;
-	}
-    }
-
     mask = _cairo_surface_create_similar_scratch (_dst,
 						  CAIRO_CONTENT_COLOR_ALPHA,
 						  extents->width,
-- 
1.7.9.5


More information about the cairo mailing list