[cairo-commit] 21 commits - boilerplate/cairo-boilerplate-egl.c boilerplate/Makefile.win32.features build/configure.ac.features build/Makefile.win32.features build/Makefile.win32.features-h configure.ac src/cairo-gl-composite.c src/cairo-gl-device.c src/cairo-gl-dispatch.c src/cairo-gl-dispatch-private.h src/cairo-gl-ext-def-private.h src/cairo-gl-gradient.c src/cairo-gl-gradient-private.h src/cairo-gl.h src/cairo-gl-info.c src/cairo-gl-private.h src/cairo-gl-shaders.c src/cairo-gl-surface.c src/cairoint.h src/cairo-xcb-surface-render.c src/cairo-xlib-surface.c src/Makefile.sources src/Makefile.win32.features

Chris Wilson ickle at kemper.freedesktop.org
Tue May 10 00:38:53 PDT 2011


 boilerplate/Makefile.win32.features |   12 +
 boilerplate/cairo-boilerplate-egl.c |   22 ++
 build/Makefile.win32.features       |    1 
 build/Makefile.win32.features-h     |    3 
 build/configure.ac.features         |    1 
 configure.ac                        |   25 +++
 src/Makefile.sources                |    4 
 src/Makefile.win32.features         |   16 +
 src/cairo-gl-composite.c            |  122 +++++++++++++-
 src/cairo-gl-device.c               |   51 +++++-
 src/cairo-gl-dispatch-private.h     |   30 ++-
 src/cairo-gl-dispatch.c             |  160 +++++++++++++++----
 src/cairo-gl-ext-def-private.h      |   44 +++++
 src/cairo-gl-gradient-private.h     |    5 
 src/cairo-gl-gradient.c             |   60 +++++--
 src/cairo-gl-info.c                 |   22 ++
 src/cairo-gl-private.h              |   37 ++++
 src/cairo-gl-shaders.c              |  279 +++++++++++++++++++++++++++-------
 src/cairo-gl-surface.c              |  295 ++++++++++++++++++++++++++++++++----
 src/cairo-gl.h                      |    2 
 src/cairo-xcb-surface-render.c      |   12 -
 src/cairo-xlib-surface.c            |   19 --
 src/cairoint.h                      |    7 
 23 files changed, 1027 insertions(+), 202 deletions(-)

New commits:
commit 4d96859ba5eb6018ae257ef6bfead228583908cf
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Mon Mar 21 16:23:30 2011 +0200

    gl: Add fallback path for GLES2 implementations not supporting GL_OES_mapbuffer
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 575719b..bb88f59 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1014,7 +1014,12 @@ _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
 
     count = ctx->vb_offset / ctx->vertex_size;
 
-    ctx->dispatch.UnmapBuffer (GL_ARRAY_BUFFER);
+    if (ctx->has_map_buffer)
+	ctx->dispatch.UnmapBuffer (GL_ARRAY_BUFFER);
+    else
+	ctx->dispatch.BufferData (GL_ARRAY_BUFFER, ctx->vb_offset,
+				  ctx->vb, GL_STREAM_DRAW);
+
     ctx->vb = NULL;
     ctx->vb_offset = 0;
 
@@ -1044,9 +1049,14 @@ _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
 	_cairo_gl_composite_flush (ctx);
 
     if (ctx->vb == NULL) {
-	dispatch->BufferData (GL_ARRAY_BUFFER, CAIRO_GL_VBO_SIZE,
-			      NULL, GL_STREAM_DRAW);
-	ctx->vb = dispatch->MapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+	if (ctx->has_map_buffer) {
+	    dispatch->BufferData (GL_ARRAY_BUFFER, CAIRO_GL_VBO_SIZE,
+				  NULL, GL_STREAM_DRAW);
+	    ctx->vb = dispatch->MapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+	}
+	else {
+	    ctx->vb = ctx->vb_mem;
+	}
     }
 }
 
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index c94e36f..170cf96 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -132,6 +132,8 @@ _gl_destroy (void *device)
 
     cairo_region_destroy (ctx->clip_region);
 
+    free (ctx->vb_mem);
+
     ctx->destroy (ctx);
 
     free (ctx);
@@ -191,6 +193,10 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 	! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
 	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 
+    ctx->has_map_buffer = (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
+			   (gl_flavor == CAIRO_GL_FLAVOR_ES &&
+			    _cairo_gl_has_extension ("GL_OES_mapbuffer")));
+
     ctx->has_mesa_pack_invert =
 	_cairo_gl_has_extension ("GL_MESA_pack_invert");
 
@@ -209,6 +215,14 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     if (unlikely (status))
         return status;
 
+    if (! ctx->has_map_buffer) {
+	ctx->vb_mem = _cairo_malloc_ab (CAIRO_GL_VBO_SIZE, 1);
+	if (unlikely (ctx->vb_mem == NULL)) {
+	    _cairo_cache_fini (&ctx->gradients);
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
+    }
+
     /* PBO for any sort of texture upload */
     dispatch->GenBuffers (1, &ctx->texture_load_pbo);
     dispatch->GenBuffers (1, &ctx->vbo);
diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c
index 344b0eb..5bffddd 100644
--- a/src/cairo-gl-dispatch.c
+++ b/src/cairo-gl-dispatch.c
@@ -125,8 +125,7 @@ _cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch,
 	    return CAIRO_STATUS_DEVICE_ERROR;
     }
     else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
-	     gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0) &&
-	     _cairo_gl_has_extension ("GL_OES_mapbuffer"))
+	     gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
     {
 	dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
     }
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 3f3153e..edd1355 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -285,6 +285,7 @@ struct _cairo_gl_context {
     cairo_gl_operand_t operands[2];
 
     char *vb;
+    char *vb_mem;
     unsigned int vb_offset;
     unsigned int vertex_size;
     cairo_region_t *clip_region;
@@ -293,6 +294,7 @@ struct _cairo_gl_context {
     cairo_gl_dispatch_t dispatch;
     GLfloat modelviewprojection_matrix[16];
     cairo_gl_flavor_t gl_flavor;
+    cairo_bool_t has_map_buffer;
 
     void (*acquire) (void *ctx);
     void (*release) (void *ctx);
commit c2b4bc6dead3e1fd0aacd9d767a299259f895e4d
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Mon Mar 21 16:12:00 2011 +0200

    gl: Fall back to dlsym() if *GetProcAddress() fails
    
    In strictly conforming EGL implementations, eglGetProcAddress() can be used
    only to get extension functions, but some of the functions we want belong to
    core GL(ES). If the *GetProcAddress function provided by the context fails,
    try to get the address of the wanted GL function using standard system
    facilities (eg dlsym() in *nix systems).
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/configure.ac b/configure.ac
index 9107b3e..72caa0d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,6 +49,9 @@ if test "x$have_dlsym" = "xno"; then
 fi
 AC_CHECK_HEADERS(dlfcn.h, [have_dlsym=yes], [have_dlsym=no])
 AM_CONDITIONAL(CAIRO_HAS_DL, test "x$have_dl" = "xyes")
+if test "x$have_dlsym" = "xyes"; then
+  AC_DEFINE([CAIRO_HAS_DLSYM], 1, [Define to 1 if dlsym is available])
+fi
 
 dnl ===========================================================================
 
@@ -317,6 +320,10 @@ CAIRO_ENABLE_SURFACE_BACKEND(gl, OpenGL, no, [
 	      gl_NONPKGCONFIG_LIBS="-lGL"
 	  fi])
 
+  if test "x$have_dl" = "xyes" -a "x$have_dlsym" = "xyes"; then
+    gl_LIBS="$gl_LIBS -ldl"
+  fi
+
   need_glx_functions=yes
   need_wgl_functions=yes
   need_egl_functions=yes
@@ -333,6 +340,10 @@ CAIRO_ENABLE_SURFACE_BACKEND(glesv2, OpenGLESv2, no, [
 	      glesv2_NONPKGCONFIG_LIBS="-lGLESv2"
 	  fi])
 
+  if test "x$have_dl" = "xyes" -a "x$have_dlsym" = "xyes"; then
+    glesv2_LIBS="$glesv2_LIBS -ldl"
+  fi
+
   need_egl_functions=yes
 ])
 
diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c
index 6277f53..344b0eb 100644
--- a/src/cairo-gl-dispatch.c
+++ b/src/cairo-gl-dispatch.c
@@ -32,6 +32,48 @@
 #include "cairoint.h"
 #include "cairo-gl-private.h"
 #include "cairo-gl-dispatch-private.h"
+#if CAIRO_HAS_DLSYM
+#include <dlfcn.h>
+#endif
+
+#if CAIRO_HAS_DLSYM
+static void *
+_cairo_gl_dispatch_open_lib (void)
+{
+    return dlopen (NULL, RTLD_LAZY);
+}
+
+static void
+_cairo_gl_dispatch_close_lib (void *handle)
+{
+    dlclose (handle);
+}
+
+static cairo_gl_generic_func_t
+_cairo_gl_dispatch_get_proc_addr (void *handle, const char *name)
+{
+    return (cairo_gl_generic_func_t) dlsym (handle, name);
+}
+#else
+static void *
+_cairo_gl_dispatch_open_lib (void)
+{
+    return NULL;
+}
+
+static void
+_cairo_gl_dispatch_close_lib (void *handle)
+{
+    return;
+}
+
+static cairo_gl_generic_func_t
+_cairo_gl_dispatch_get_proc_addr (void *handle, const char *name)
+{
+    return NULL;
+}
+#endif /* CAIRO_HAS_DLSYM */
+
 
 static void
 _cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch,
@@ -40,18 +82,30 @@ _cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch,
 				 cairo_gl_dispatch_name_t dispatch_name)
 {
     cairo_gl_dispatch_entry_t *entry = entries;
+    void *handle = _cairo_gl_dispatch_open_lib ();
 
     while (entry->name[CAIRO_GL_DISPATCH_NAME_CORE] != NULL) {
 	void *dispatch_ptr = &((char *) dispatch)[entry->offset];
 	const char *name = entry->name[dispatch_name];
 
+	/*
+	 * In strictly conforming EGL implementations, eglGetProcAddress() can
+	 * be used only to get extension functions, but some of the functions
+	 * we want belong to core GL(ES). If the *GetProcAddress function
+	 * provided by the context fails, try to get the address of the wanted
+	 * GL function using standard system facilities (eg dlsym() in *nix
+	 * systems).
+	 */
 	cairo_gl_generic_func_t func = get_proc_addr (name);
+	if (func == NULL)
+	    func = _cairo_gl_dispatch_get_proc_addr (handle, name);
 
 	*((cairo_gl_generic_func_t *) dispatch_ptr) = func;
 
 	++entry;
     }
 
+    _cairo_gl_dispatch_close_lib (handle);
 }
 
 static cairo_status_t
commit 2001d2074723c64b1e5a6cb4c550d6a0a8cea812
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Wed Mar 9 18:17:42 2011 +0200

    gl: Define the float precision in the fragment shader for GLES2
    
    According to the GLSL ES standard, the precision of variables in the fragment
    shader should be explicitly defined (although mesa's compiler is not that
    strict).
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 77a28aa..7d60c0f 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -385,6 +385,9 @@ cairo_status_t
 _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
 {
     static const char *fill_fs_source =
+	"#ifdef GL_ES\n"
+	"precision mediump float;\n"
+	"#endif\n"
 	"uniform vec4 color;\n"
 	"void main()\n"
 	"{\n"
@@ -847,6 +850,11 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
     unsigned long length;
     cairo_status_t status;
 
+    _cairo_output_stream_printf (stream,
+	"#ifdef GL_ES\n"
+	"precision mediump float;\n"
+	"#endif\n");
+
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
 	if (_cairo_gl_shader_needs_border_fade (src))
 	    _cairo_gl_shader_emit_border_fade (stream, src, CAIRO_GL_TEX_SOURCE);
commit 1595f20bb70ebba8d192500d4de455170c8d81a0
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Fri Mar 4 18:09:44 2011 +0200

    boilerplate/egl: Add GLES2 support
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/boilerplate/cairo-boilerplate-egl.c b/boilerplate/cairo-boilerplate-egl.c
index 1a5abec..6ecb8a8 100644
--- a/boilerplate/cairo-boilerplate-egl.c
+++ b/boilerplate/cairo-boilerplate-egl.c
@@ -33,6 +33,11 @@
 #include "cairo-boilerplate-private.h"
 
 #include <cairo-gl.h>
+#if CAIRO_HAS_GL_SURFACE
+#include <GL/gl.h>
+#elif CAIRO_HAS_GLESV2_SURFACE
+#include <GLES2/gl2.h>
+#endif
 
 static const cairo_user_data_key_t gl_closure_key;
 
@@ -81,7 +86,17 @@ _cairo_boilerplate_egl_create_surface (const char		 *name,
 	EGL_BLUE_SIZE, 8,
 	EGL_ALPHA_SIZE, 8,
 	EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+#if CAIRO_HAS_GL_SURFACE
 	EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+#elif CAIRO_HAS_GLESV2_SURFACE
+	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+#endif
+	EGL_NONE
+    };
+    const EGLint ctx_attribs[] = {
+#if CAIRO_HAS_GLESV2_SURFACE
+	EGL_CONTEXT_CLIENT_VERSION, 2,
+#endif
 	EGL_NONE
     };
 
@@ -101,9 +116,14 @@ _cairo_boilerplate_egl_create_surface (const char		 *name,
 	return NULL;
     }
 
+#if CAIRO_HAS_GL_SURFACE
     eglBindAPI (EGL_OPENGL_API);
+#elif CAIRO_HAS_GLESV2_SURFACE
+    eglBindAPI (EGL_OPENGL_ES_API);
+#endif
 
-    gltc->ctx = eglCreateContext (gltc->dpy, config, EGL_NO_CONTEXT, NULL);
+    gltc->ctx = eglCreateContext (gltc->dpy, config, EGL_NO_CONTEXT,
+				  ctx_attribs);
     if (gltc->ctx == EGL_NO_CONTEXT) {
 	eglTerminate (gltc->dpy);
 	free (gltc);
commit 2472ed899cc8bfd97b3cec1f322b601038d28731
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Thu Mar 3 23:11:06 2011 +0200

    gl: Fix build issues for GLES2
    
    The glReadBuffer/glDrawBuffer functions are not present in GLES2, only
    a single buffer is supported.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 3b60a54..c94e36f 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -261,8 +261,10 @@ _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
 				    ctx->tex_target,
 				    surface->tex,
 				    0);
+#if CAIRO_HAS_GL_SURFACE
     glDrawBuffer (GL_COLOR_ATTACHMENT0);
     glReadBuffer (GL_COLOR_ATTACHMENT0);
+#endif
 
     status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
     if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -342,8 +344,10 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
     } else {
         ctx->make_current (ctx, surface);
         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
+#if CAIRO_HAS_GL_SURFACE
         glDrawBuffer (GL_BACK_LEFT);
         glReadBuffer (GL_BACK_LEFT);
+#endif
     }
 
     glViewport (0, 0, surface->width, surface->height);
diff --git a/src/cairo-gl-ext-def-private.h b/src/cairo-gl-ext-def-private.h
index 97e42c1..a261947 100644
--- a/src/cairo-gl-ext-def-private.h
+++ b/src/cairo-gl-ext-def-private.h
@@ -136,4 +136,8 @@
 #define GL_UNPACK_ROW_LENGTH 0x0CF2
 #endif
 
+#ifndef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+#endif
+
 #endif /* CAIRO_GL_EXT_DEF_PRIVATE_H */
diff --git a/src/cairo-gl-gradient-private.h b/src/cairo-gl-gradient-private.h
index 9e34847..3d7b047 100644
--- a/src/cairo-gl-gradient-private.h
+++ b/src/cairo-gl-gradient-private.h
@@ -50,8 +50,13 @@
 
 #include "cairo-gl.h"
 
+#if CAIRO_HAS_GL_SURFACE
 #include <GL/gl.h>
 #include <GL/glext.h>
+#elif CAIRO_HAS_GLESV2_SURFACE
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#endif
 
 #define CAIRO_GL_GRADIENT_CACHE_SIZE 4096
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 433a40b..3f3153e 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -58,8 +58,14 @@
 
 #include "cairo-gl.h"
 
+#if CAIRO_HAS_GL_SURFACE
 #include <GL/gl.h>
 #include <GL/glext.h>
+#elif CAIRO_HAS_GLESV2_SURFACE
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#endif
+
 #include "cairo-gl-ext-def-private.h"
 
 #define DEBUG_GL 0
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
index d23cea7..d23b8a5 100644
--- a/src/cairo-gl.h
+++ b/src/cairo-gl.h
@@ -62,7 +62,7 @@
 
 #include "cairo.h"
 
-#if CAIRO_HAS_GL_SURFACE
+#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV2_SURFACE
 
 CAIRO_BEGIN_DECLS
 
commit f84653422a79aec98299ac7c9f989fe4dfa8b973
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Thu Mar 3 23:17:31 2011 +0200

    gl: Add GLESv2 backend to build system
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index b97f6d0..d0b184d 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -259,6 +259,18 @@ enabled_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_gl_cxx_sources)
 enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_sources)
 endif
 
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_glesv2_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_glesv2_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_glesv2_private)
+all_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_glesv2_cxx_sources)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_glesv2_sources)
+ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_glesv2_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_glesv2_private)
+enabled_cairo_boilerplate_cxx_sources += $(cairo_boilerplate_glesv2_cxx_sources)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glesv2_sources)
+endif
+
 unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_directfb_headers)
 all_cairo_boilerplate_headers += $(cairo_boilerplate_directfb_headers)
 all_cairo_boilerplate_private += $(cairo_boilerplate_directfb_private)
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index d76cf0e..0d0261d 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -20,6 +20,7 @@ CAIRO_HAS_GALLIUM_SURFACE=0
 CAIRO_HAS_XCB_DRM_FUNCTIONS=0
 CAIRO_HAS_PNG_FUNCTIONS=1
 CAIRO_HAS_GL_SURFACE=0
+CAIRO_HAS_GLESV2_SURFACE=0
 CAIRO_HAS_DIRECTFB_SURFACE=0
 CAIRO_HAS_VG_SURFACE=0
 CAIRO_HAS_EGL_FUNCTIONS=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index f5cbcf1..ce39de3 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -65,6 +65,9 @@ endif
 ifeq ($(CAIRO_HAS_GL_SURFACE),1)
 	@echo "#define CAIRO_HAS_GL_SURFACE 1" >> src/cairo-features.h
 endif
+ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
+	@echo "#define CAIRO_HAS_GLESV2_SURFACE 1" >> src/cairo-features.h
+endif
 ifeq ($(CAIRO_HAS_DIRECTFB_SURFACE),1)
 	@echo "#define CAIRO_HAS_DIRECTFB_SURFACE 1" >> src/cairo-features.h
 endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index 343442a..e1651d8 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -381,6 +381,7 @@ AC_DEFUN([CAIRO_REPORT],
 	echo "  PDF:           $use_pdf"
 	echo "  SVG:           $use_svg"
 	echo "  OpenGL:        $use_gl"
+	echo "  OpenGL ES 2.0: $use_glesv2"
 	echo "  BeOS:          $use_beos"
 	echo "  DirectFB:      $use_directfb"
 	echo "  OpenVG:        $use_vg"
diff --git a/configure.ac b/configure.ac
index 951e960..9107b3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -323,6 +323,20 @@ CAIRO_ENABLE_SURFACE_BACKEND(gl, OpenGL, no, [
 ])
 
 dnl ===========================================================================
+CAIRO_ENABLE_SURFACE_BACKEND(glesv2, OpenGLESv2, no, [
+  glesv2_REQUIRES="glesv2"
+  PKG_CHECK_MODULES(glesv2, $glesv2_REQUIRES,, [
+	  dnl Fallback to searching for headers
+	  AC_CHECK_HEADER(GLES2/gl2.h,, [use_glesv2="no (glesv2.pc nor OpenGL ES 2.0 headers not found)"])
+	  if test "x$use_glesv2" = "xyes"; then
+	      glesv2_NONPKGCONFIG_CFLAGS=
+	      glesv2_NONPKGCONFIG_LIBS="-lGLESv2"
+	  fi])
+
+  need_egl_functions=yes
+])
+
+dnl ===========================================================================
 
 CAIRO_ENABLE_SURFACE_BACKEND(directfb, directfb, no, [
   directfb_REQUIRES=directfb
diff --git a/src/Makefile.sources b/src/Makefile.sources
index c4ca001..474e092 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -328,6 +328,10 @@ cairo_gl_sources = cairo-gl-composite.c \
 		   cairo-gl-shaders.c \
 		   cairo-gl-surface.c
 
+cairo_glesv2_headers = $(cairo_gl_headers)
+cairo_glesv2_private = $(cairo_gl_private)
+cairo_glesv2_sources = $(cairo_gl_sources)
+
 cairo_egl_sources += cairo-egl-context.c
 cairo_glx_sources += cairo-glx-context.c
 cairo_wgl_sources += cairo-wgl-context.c
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index e1701e7..d7cc77e 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -341,6 +341,22 @@ ifeq ($(CAIRO_HAS_GL_SURFACE),1)
 enabled_cairo_pkgconf += cairo-gl.pc
 endif
 
+unsupported_cairo_headers += $(cairo_glesv2_headers)
+all_cairo_headers += $(cairo_glesv2_headers)
+all_cairo_private += $(cairo_glesv2_private)
+all_cairo_cxx_sources += $(cairo_glesv2_cxx_sources)
+all_cairo_sources += $(cairo_glesv2_sources)
+ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
+enabled_cairo_headers += $(cairo_glesv2_headers)
+enabled_cairo_private += $(cairo_glesv2_private)
+enabled_cairo_cxx_sources += $(cairo_glesv2_cxx_sources)
+enabled_cairo_sources += $(cairo_glesv2_sources)
+endif
+all_cairo_pkgconf += cairo-glesv2.pc
+ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
+enabled_cairo_pkgconf += cairo-glesv2.pc
+endif
+
 unsupported_cairo_headers += $(cairo_directfb_headers)
 all_cairo_headers += $(cairo_directfb_headers)
 all_cairo_private += $(cairo_directfb_private)
commit b990dfb06774864ab33dcb195d3442b8f5f3715b
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Thu Mar 3 23:07:12 2011 +0200

    gl: Require the GL_OES_texture_npot extension for GLES2
    
    The default support for GLES2 NPOT textures is very limited. We need the
    additional features provided by the GL_OES_texture_npot extension.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index fb0a7dd..3b60a54 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -167,12 +167,20 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 
     /* Check for required extensions */
-    if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two"))
-	ctx->tex_target = GL_TEXTURE_2D;
-    else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle"))
-	ctx->tex_target = GL_TEXTURE_RECTANGLE;
-    else
-	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
+	if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two"))
+	    ctx->tex_target = GL_TEXTURE_2D;
+	else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle"))
+	    ctx->tex_target = GL_TEXTURE_RECTANGLE;
+	else
+	    return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+    }
+    else {
+	if (_cairo_gl_has_extension ("GL_OES_texture_npot"))
+	    ctx->tex_target = GL_TEXTURE_2D;
+	else
+	    return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+    }
 
     if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
 	gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
commit faa031f6d5660b1ce5cc29f58db0ba2f675dc283
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Thu Mar 3 23:05:04 2011 +0200

    gl: Use GL_MAX_TEXTURE_IMAGE_UNITS to query the maximum texture units
    
    The previous used value, GL_MAX_TEXTURE_UNITS, is only appropriate for the
    fixed pipeline. It is replaced with GL_MAX_TEXTURE_IMAGE_UNITS that refers to
    the number of texture units available in the fragment shader.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 6dcf835..fb0a7dd 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -210,7 +210,7 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     ctx->max_texture_size = 0;
     glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
     ctx->max_textures = 0;
-    glGetIntegerv (GL_MAX_TEXTURE_UNITS, &ctx->max_textures);
+    glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures);
 
     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
 	_cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
commit 1f1255689b7469193eb7bc0efbd5248b748164ad
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Thu Mar 3 23:01:36 2011 +0200

    gl: Remove unnecessary call to glDisableClientState()
    
    This function has no effect when using shaders and is not supported at all in
    GLES2.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 92cd82a..6dcf835 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -89,8 +89,6 @@ _gl_flush (void *device)
 
     ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0);
 
-    glDisableClientState (GL_VERTEX_ARRAY);
-
     glDisable (GL_SCISSOR_TEST);
     glDisable (GL_BLEND);
 
commit bbb244c7f2fe632cfee453f01dbde64e71dd3c88
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Thu Mar 3 22:48:51 2011 +0200

    gl: Add GLES2 support for drawing image surfaces on gl surfaces
    
    Work around GLES2 limitations in texture pixel formats and options for
    pixel packing/unpacking.
    
    Depending on the endianness and the image pixel format, we may need to
    manually swap the elements in a pixel group. This is not currently
    implemented, but for little-endian architectures the common pixman BGRA
    formats don't need a swap.
    
    Due to GL_UNPACK_ROW_LENGTH missing in GLES2 we have to extract the image
    data ourselves in some cases, so we can provide it to glTexSubImage2D
    using a layout it can understand. We must extract the pixels if:
    a. we don't want full-length lines or
    b. the row stride cannot be handled by GL itself using a 4 byte
       alignment constraint
    
    We use GL_PACK_ALIGNMENT 4 by default because that is the default pixman
    alignment value and in some cases it allows us to avoid the manual pixel
    extraction. However, when we extract image data manually we use an alignment
    of 1.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-ext-def-private.h b/src/cairo-gl-ext-def-private.h
index a4b7d34..97e42c1 100644
--- a/src/cairo-gl-ext-def-private.h
+++ b/src/cairo-gl-ext-def-private.h
@@ -100,6 +100,10 @@
 #define GL_CLAMP_TO_BORDER 0x812D
 #endif
 
+#ifndef GL_BGR
+#define GL_BGR 0x80E0
+#endif
+
 #ifndef GL_BGRA
 #define GL_BGRA 0x80E1
 #endif
@@ -108,6 +112,18 @@
 #define GL_RGBA8 0x8058
 #endif
 
+#ifndef GL_UNSIGNED_INT_8_8_8_8
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#endif
+
+#ifndef GL_UNSIGNED_SHORT_5_6_5_REV
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#endif
+
+#ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#endif
+
 #ifndef GL_UNSIGNED_INT_8_8_8_8_REV
 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
 #endif
@@ -116,4 +132,8 @@
 #define GL_PACK_ROW_LENGTH 0x0D02
 #endif
 
+#ifndef GL_UNPACK_ROW_LENGTH
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#endif
+
 #endif /* CAIRO_GL_EXT_DEF_PRIVATE_H */
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 6f1d410..433a40b 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -466,9 +466,11 @@ _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
                                    cairo_gl_tex_t tex_unit);
 
 cairo_private cairo_bool_t
-_cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
+_cairo_gl_get_image_format_and_type (cairo_gl_flavor_t flavor,
+				     pixman_format_code_t pixman_format,
 				     GLenum *internal_format, GLenum *format,
-				     GLenum *type, cairo_bool_t *has_alpha);
+				     GLenum *type, cairo_bool_t *has_alpha,
+				     cairo_bool_t *needs_swap);
 
 cairo_private void
 _cairo_gl_surface_scaled_font_fini ( cairo_scaled_font_t  *scaled_font);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index b67a1ea..813e354 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -74,12 +74,125 @@ static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
     return surface->backend == &_cairo_gl_surface_backend;
 }
 
-cairo_bool_t
-_cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
-				     GLenum *internal_format, GLenum *format,
-				     GLenum *type, cairo_bool_t *has_alpha)
+static cairo_bool_t
+_cairo_gl_get_image_format_and_type_gles2 (pixman_format_code_t pixman_format,
+					   GLenum *internal_format, GLenum *format,
+					   GLenum *type, cairo_bool_t *has_alpha,
+					   cairo_bool_t *needs_swap)
+{
+    cairo_bool_t is_little_endian = _cairo_is_little_endian ();
+
+    *has_alpha = TRUE;
+
+    switch ((int) pixman_format) {
+    case PIXMAN_a8r8g8b8:
+	*internal_format = GL_BGRA;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_BYTE;
+	*needs_swap = !is_little_endian;
+	return TRUE;
+
+    case PIXMAN_x8r8g8b8:
+	*internal_format = GL_BGRA;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_BYTE;
+	*has_alpha = FALSE;
+	*needs_swap = !is_little_endian;
+	return TRUE;
+
+    case PIXMAN_a8b8g8r8:
+	*internal_format = GL_RGBA;
+	*format = GL_RGBA;
+	*type = GL_UNSIGNED_BYTE;
+	*needs_swap = !is_little_endian;
+	return TRUE;
+
+    case PIXMAN_x8b8g8r8:
+	*internal_format = GL_RGBA;
+	*format = GL_RGBA;
+	*type = GL_UNSIGNED_BYTE;
+	*has_alpha = FALSE;
+	*needs_swap = !is_little_endian;
+	return TRUE;
+
+    case PIXMAN_b8g8r8a8:
+	*internal_format = GL_BGRA;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_BYTE;
+	*needs_swap = is_little_endian;
+	return TRUE;
+
+    case PIXMAN_b8g8r8x8:
+	*internal_format = GL_BGRA;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_BYTE;
+	*has_alpha = FALSE;
+	*needs_swap = is_little_endian;
+	return TRUE;
+
+    case PIXMAN_r8g8b8:
+	*internal_format = GL_RGB;
+	*format = GL_RGB;
+	*type = GL_UNSIGNED_BYTE;
+	*needs_swap = is_little_endian;
+	return TRUE;
+
+    case PIXMAN_b8g8r8:
+	*internal_format = GL_RGB;
+	*format = GL_RGB;
+	*type = GL_UNSIGNED_BYTE;
+	*needs_swap = !is_little_endian;
+	return TRUE;
+
+    case PIXMAN_r5g6b5:
+	*internal_format = GL_RGB;
+	*format = GL_RGB;
+	*type = GL_UNSIGNED_SHORT_5_6_5;
+	*needs_swap = FALSE;
+	return TRUE;
+
+    case PIXMAN_b5g6r5:
+	*internal_format = GL_RGB;
+	*format = GL_RGB;
+	*type = GL_UNSIGNED_SHORT_5_6_5;
+	*needs_swap = TRUE;
+	return TRUE;
+
+    case PIXMAN_a1b5g5r5:
+	*internal_format = GL_RGBA;
+	*format = GL_RGBA;
+	*type = GL_UNSIGNED_SHORT_5_5_5_1;
+	*needs_swap = TRUE;
+	return TRUE;
+
+    case PIXMAN_x1b5g5r5:
+	*internal_format = GL_RGBA;
+	*format = GL_RGBA;
+	*type = GL_UNSIGNED_SHORT_5_5_5_1;
+	*has_alpha = FALSE;
+	*needs_swap = TRUE;
+	return TRUE;
+
+    case PIXMAN_a8:
+	*internal_format = GL_ALPHA;
+	*format = GL_ALPHA;
+	*type = GL_UNSIGNED_BYTE;
+	*needs_swap = FALSE;
+	return TRUE;
+
+    default:
+	return FALSE;
+    }
+}
+
+static cairo_bool_t
+_cairo_gl_get_image_format_and_type_gl (pixman_format_code_t pixman_format,
+					GLenum *internal_format, GLenum *format,
+					GLenum *type, cairo_bool_t *has_alpha,
+					cairo_bool_t *needs_swap)
 {
     *has_alpha = TRUE;
+    *needs_swap = FALSE;
 
     switch (pixman_format) {
     case PIXMAN_a8r8g8b8:
@@ -195,6 +308,55 @@ _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
     }
 }
 
+/*
+ * Extracts pixel data from an image surface.
+ */
+static cairo_status_t
+_cairo_gl_surface_extract_image_data (cairo_image_surface_t *image,
+				      int x, int y,
+				      int width, int height,
+				      void **output)
+{
+    int cpp = PIXMAN_FORMAT_BPP (image->pixman_format) / 8;
+    char *data = _cairo_malloc_ab (width * height, cpp);
+    char *dst = data;
+    unsigned char *src = image->data + y * image->stride + x * cpp;
+    int i;
+
+    if (unlikely (data == NULL))
+	return CAIRO_STATUS_NO_MEMORY;
+
+    for (i = 0; i < height; i++) {
+	memcpy (dst, src, width * cpp);
+	src += image->stride;
+	dst += width * cpp;
+    }
+
+    *output = data;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_bool_t
+_cairo_gl_get_image_format_and_type (cairo_gl_flavor_t flavor,
+				     pixman_format_code_t pixman_format,
+				     GLenum *internal_format, GLenum *format,
+				     GLenum *type, cairo_bool_t *has_alpha,
+				     cairo_bool_t *needs_swap)
+{
+    if (flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	return _cairo_gl_get_image_format_and_type_gl (pixman_format,
+						       internal_format, format,
+						       type, has_alpha,
+						       needs_swap);
+    else
+	return _cairo_gl_get_image_format_and_type_gles2 (pixman_format,
+							  internal_format, format,
+							  type, has_alpha,
+							  needs_swap);
+
+}
+
 cairo_bool_t
 _cairo_gl_operator_is_supported (cairo_operator_t op)
 {
@@ -578,47 +740,79 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 			      int dst_x, int dst_y)
 {
     GLenum internal_format, format, type;
-    cairo_bool_t has_alpha;
+    cairo_bool_t has_alpha, needs_swap;
     cairo_image_surface_t *clone = NULL;
     cairo_gl_context_t *ctx;
     int cpp;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
-    if (! _cairo_gl_get_image_format_and_type (src->pixman_format,
+    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
+    if (unlikely (status))
+	return status;
+
+    if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
+					       src->pixman_format,
 					       &internal_format,
 					       &format,
 					       &type,
-					       &has_alpha))
+					       &has_alpha,
+					       &needs_swap))
     {
 	cairo_bool_t is_supported;
 
 	clone = _cairo_image_surface_coerce (src);
-	if (unlikely (clone->base.status))
-	    return clone->base.status;
+	if (unlikely (status = clone->base.status))
+	    goto FAIL;
 
 	is_supported =
-	    _cairo_gl_get_image_format_and_type (clone->pixman_format,
+	    _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
+						 clone->pixman_format,
 		                                 &internal_format,
 						 &format,
 						 &type,
-						 &has_alpha);
+						 &has_alpha,
+						 &needs_swap);
 	assert (is_supported);
+	assert (!needs_swap);
 	src = clone;
     }
 
     cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
 
-    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
-    if (unlikely (status))
-	return status;
-
     status = _cairo_gl_surface_flush (&dst->base);
     if (unlikely (status))
 	goto FAIL;
 
-    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
-    glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
     if (_cairo_gl_surface_is_texture (dst)) {
+	void *data_start = src->data + src_y * src->stride + src_x * cpp;
+	void *data_start_gles2 = NULL;
+
+	/*
+	 * Due to GL_UNPACK_ROW_LENGTH missing in GLES2 we have to extract the
+	 * image data ourselves in some cases. In particular, we must extract
+	 * the pixels if:
+	 * a. we don't want full-length lines or
+	 * b. the row stride cannot be handled by GL itself using a 4 byte alignment
+	 *    constraint
+	 */
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	    (src->width * cpp < src->stride - 3 ||
+	     width != src->width))
+	{
+	    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+	    status = _cairo_gl_surface_extract_image_data (src, src_x, src_y,
+							   width, height,
+							   &data_start_gles2);
+	    if (unlikely (status))
+		goto FAIL;
+	}
+	else
+	{
+	    glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+	}
+
         _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
 	glBindTexture (ctx->tex_target, dst->tex);
 	glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -626,7 +820,12 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	glTexSubImage2D (ctx->tex_target, 0,
 			 dst_x, dst_y, width, height,
 			 format, type,
-			 src->data + src_y * src->stride + src_x * cpp);
+			 data_start_gles2 != NULL ? data_start_gles2 :
+						    data_start);
+
+
+	if (data_start_gles2)
+	    free (data_start_gles2);
 
 	/* If we just treated some rgb-only data as rgba, then we have to
 	 * go back and fix up the alpha channel where we filled in this
@@ -684,7 +883,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
     }
 
 FAIL:
-    glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
 
     status = _cairo_gl_context_release (ctx, status);
 
@@ -775,7 +975,7 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
     _cairo_gl_composite_flush (ctx);
     _cairo_gl_context_set_destination (ctx, surface);
 
-    glPixelStorei (GL_PACK_ALIGNMENT, 1);
+    glPixelStorei (GL_PACK_ALIGNMENT, 4);
     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
 	glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
     if (! _cairo_gl_surface_is_texture (surface) &&
commit 14db3d23c7d7862fe335a94f24962b715ad30c85
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Thu Mar 3 15:55:22 2011 +0200

    gl: Add support for creating image surfaces for GLES2
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-ext-def-private.h b/src/cairo-gl-ext-def-private.h
index 0701c5b..a4b7d34 100644
--- a/src/cairo-gl-ext-def-private.h
+++ b/src/cairo-gl-ext-def-private.h
@@ -112,4 +112,8 @@
 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
 #endif
 
+#ifndef GL_PACK_ROW_LENGTH
+#define GL_PACK_ROW_LENGTH 0x0D02
+#endif
+
 #endif /* CAIRO_GL_EXT_DEF_PRIVATE_H */
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 211fe02..b67a1ea 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -703,24 +703,24 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
     cairo_image_surface_t *image;
     cairo_gl_context_t *ctx;
     GLenum format, type;
-    cairo_format_t cairo_format;
+    pixman_format_code_t pixman_format;
     unsigned int cpp;
     cairo_status_t status;
 
     /* Want to use a switch statement here but the compiler gets whiny. */
     if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
 	format = GL_BGRA;
-	cairo_format = CAIRO_FORMAT_ARGB32;
+	pixman_format = PIXMAN_a8r8g8b8;
 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 	cpp = 4;
     } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
 	format = GL_BGRA;
-	cairo_format = CAIRO_FORMAT_RGB24;
+	pixman_format = PIXMAN_x8r8g8b8;
 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 	cpp = 4;
     } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
 	format = GL_ALPHA;
-	cairo_format = CAIRO_FORMAT_A8;
+	pixman_format = PIXMAN_a8;
 	type = GL_UNSIGNED_BYTE;
 	cpp = 1;
     } else {
@@ -728,25 +728,56 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
+    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+    if (unlikely (status))
+        return status;
+
+    /*
+     * 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 (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
+	format = GL_RGBA;
+	if (!_cairo_is_little_endian ()) {
+	    ASSERT_NOT_REACHED;
+	    /* TODO: Add r8g8b8a8 support to pixman and enable this
+	       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;
+	}
+	type = GL_UNSIGNED_BYTE;
+	cpp = 4;
+    }
+
     image = (cairo_image_surface_t*)
-	cairo_image_surface_create (cairo_format,
-				    interest->width, interest->height);
+	_cairo_image_surface_create_with_pixman_format (NULL,
+							pixman_format,
+							interest->width,
+							interest->height,
+							-1);
     if (unlikely (image->base.status))
-	return image->base.status;
+	return _cairo_gl_context_release (ctx, image->base.status);
 
     /* This is inefficient, as we'd rather just read the thing without making
      * it the destination.  But then, this is the fallback path, so let's not
      * fall back instead.
      */
-    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
-    if (unlikely (status))
-        return status;
-
     _cairo_gl_composite_flush (ctx);
     _cairo_gl_context_set_destination (ctx, surface);
 
     glPixelStorei (GL_PACK_ALIGNMENT, 1);
-    glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
     if (! _cairo_gl_surface_is_texture (surface) &&
 	ctx->has_mesa_pack_invert)
 	glPixelStorei (GL_PACK_INVERT_MESA, 1);
commit 0e41145a75fa957fc3813fc1cae0b937ad5e77e1
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Wed Mar 2 18:16:56 2011 +0200

    gl: Use conventional texture upload for GLES2
    
    GLES2 doesn't support Pixel Buffer Objects. Use conventional texture upload
    for GLES2 (using client-side memory).
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index ca7b6e8..92cd82a 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -176,7 +176,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     else
 	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 
-    if (gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
+    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
+	gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
 	! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
 	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 
diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
index 0718c75..862430e 100644
--- a/src/cairo-gl-gradient.c
+++ b/src/cairo-gl-gradient.c
@@ -234,33 +234,42 @@ _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
     gradient->stops = gradient->stops_embedded;
     memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t));
 
-    dispatch->BindBuffer (GL_PIXEL_UNPACK_BUFFER, ctx->texture_load_pbo);
-    dispatch->BufferData (GL_PIXEL_UNPACK_BUFFER,
-			  tex_width * sizeof (uint32_t), 0, GL_STREAM_DRAW);
-    data = dispatch->MapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
+    glGenTextures (1, &gradient->tex);
+    _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
+    glBindTexture (ctx->tex_target, gradient->tex);
 
-    status = _cairo_gl_gradient_render (ctx, n_stops, stops, data, tex_width);
+    /* GL_PIXEL_UNPACK_BUFFER is only available in Desktop GL */
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
+	dispatch->BindBuffer (GL_PIXEL_UNPACK_BUFFER, ctx->texture_load_pbo);
+	dispatch->BufferData (GL_PIXEL_UNPACK_BUFFER,
+			      tex_width * sizeof (uint32_t), 0, GL_STREAM_DRAW);
+	data = dispatch->MapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
 
-    dispatch->UnmapBuffer (GL_PIXEL_UNPACK_BUFFER);
+	status = _cairo_gl_gradient_render (ctx, n_stops, stops, data, tex_width);
 
-    if (unlikely (status)) {
-        dispatch->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
-        free (gradient);
-        return status;
-    }
+	dispatch->UnmapBuffer (GL_PIXEL_UNPACK_BUFFER);
 
-    glGenTextures (1, &gradient->tex);
-    _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
-    glBindTexture (ctx->tex_target, gradient->tex);
+	if (unlikely (status)) {
+	    dispatch->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
+	    free (gradient);
+	    return status;
+	}
 
-    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
 	glTexImage2D (ctx->tex_target, 0, GL_RGBA8, tex_width, 1, 0,
 		      GL_BGRA, GL_UNSIGNED_BYTE, 0);
-    else
+
+	dispatch->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
+    }
+    else {
+	data = _cairo_malloc_ab (tex_width, sizeof (uint32_t));
+
+	status = _cairo_gl_gradient_render (ctx, n_stops, stops, data, tex_width);
+
 	glTexImage2D (ctx->tex_target, 0, GL_BGRA, tex_width, 1, 0,
 		      GL_BGRA, GL_UNSIGNED_BYTE, data);
 
-    dispatch->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
+	free (data);
+    }
 
     /* we ignore errors here and just return an uncached gradient */
     if (likely (! _cairo_cache_insert (&ctx->gradients, &gradient->cache_entry)))
commit d20f66608c030f52cad5575cca5d1bdd7c31ac20
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Wed Mar 2 02:10:05 2011 +0200

    gl: Require the GL_EXT_texture_format_BGRA8888 extension for GLES2
    
    This extension adds limited BGRA support to GLES2. It is better than
    nothing...
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 35339aa..ca7b6e8 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -156,6 +156,7 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     cairo_status_t status;
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
     int gl_version = _cairo_gl_get_version ();
+    cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor ();
     int n;
 
     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
@@ -179,11 +180,15 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 	! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
 	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 
+    if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
+	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+
     ctx->has_mesa_pack_invert =
 	_cairo_gl_has_extension ("GL_MESA_pack_invert");
 
     ctx->current_operator = -1;
-    ctx->gl_flavor = _cairo_gl_get_flavor ();
+    ctx->gl_flavor = gl_flavor;
 
     status = _cairo_gl_context_init_shaders (ctx);
     if (unlikely (status))
diff --git a/src/cairo-gl-ext-def-private.h b/src/cairo-gl-ext-def-private.h
index 389d356..0701c5b 100644
--- a/src/cairo-gl-ext-def-private.h
+++ b/src/cairo-gl-ext-def-private.h
@@ -100,4 +100,16 @@
 #define GL_CLAMP_TO_BORDER 0x812D
 #endif
 
+#ifndef GL_BGRA
+#define GL_BGRA 0x80E1
+#endif
+
+#ifndef GL_RGBA8
+#define GL_RGBA8 0x8058
+#endif
+
+#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#endif
+
 #endif /* CAIRO_GL_EXT_DEF_PRIVATE_H */
diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
index ef7fd53..0718c75 100644
--- a/src/cairo-gl-gradient.c
+++ b/src/cairo-gl-gradient.c
@@ -44,6 +44,7 @@
 #include "cairo-gl-gradient-private.h"
 #include "cairo-gl-private.h"
 
+
 static int
 _cairo_gl_gradient_sample_width (unsigned int                 n_stops,
                                  const cairo_gradient_stop_t *stops)
@@ -95,6 +96,17 @@ _cairo_gl_gradient_render (const cairo_gl_context_t    *ctx,
     pixman_gradient_stop_t *pixman_stops;
     pixman_point_fixed_t p1, p2;
     unsigned int i;
+    pixman_format_code_t gradient_pixman_format;
+
+    /*
+     * Ensure that the order of the gradient's components in memory is BGRA.
+     * This is done so that the gradient's pixel data is always suitable for
+     * texture upload using format=GL_BGRA and type=GL_UNSIGNED_BYTE.
+     */
+    if (_cairo_is_little_endian ())
+	gradient_pixman_format = PIXMAN_a8r8g8b8;
+    else
+	gradient_pixman_format = PIXMAN_b8g8r8a8;
 
     pixman_stops = pixman_stops_stack;
     if (unlikely (n_stops > ARRAY_LENGTH (pixman_stops_stack))) {
@@ -129,7 +141,7 @@ _cairo_gl_gradient_render (const cairo_gl_context_t    *ctx,
     pixman_image_set_filter (gradient, PIXMAN_FILTER_BILINEAR, NULL, 0);
     pixman_image_set_repeat (gradient, PIXMAN_REPEAT_PAD);
 
-    image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, 1,
+    image = pixman_image_create_bits (gradient_pixman_format, width, 1,
 				      bytes, sizeof(uint32_t)*width);
     if (unlikely (image == NULL)) {
 	pixman_image_unref (gradient);
@@ -240,8 +252,13 @@ _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
     glGenTextures (1, &gradient->tex);
     _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
     glBindTexture (ctx->tex_target, gradient->tex);
-    glTexImage2D (ctx->tex_target, 0, GL_RGBA8, tex_width, 1, 0,
-		  GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
+
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	glTexImage2D (ctx->tex_target, 0, GL_RGBA8, tex_width, 1, 0,
+		      GL_BGRA, GL_UNSIGNED_BYTE, 0);
+    else
+	glTexImage2D (ctx->tex_target, 0, GL_BGRA, tex_width, 1, 0,
+		      GL_BGRA, GL_UNSIGNED_BYTE, data);
 
     dispatch->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
 
commit 777ed8b4c4bf7a099041a16c079e22b68dae70ad
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Tue Mar 8 12:05:48 2011 +0200

    Extract function to query endianness from xlib/xcb and make it common
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 9c377e3..8e9acf5 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -3820,14 +3820,6 @@ _cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
     }
 }
 
-static cairo_bool_t
-_native_byte_order_lsb (void)
-{
-    int	x = 1;
-
-    return *((char *) &x) == 1;
-}
-
 static int
 _cairo_xcb_get_glyphset_index_for_format (cairo_format_t format)
 {
@@ -4016,7 +4008,7 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
     switch (_cairo_xcb_get_glyphset_index_for_format (scaled_glyph->surface->format)) {
     case GLYPHSET_INDEX_A1:
 	/* local bitmaps are always stored with bit == byte */
-	if (_native_byte_order_lsb() != (connection->root->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
+	if (_cairo_is_little_endian() != (connection->root->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
 	    int		    c = glyph_surface->stride * glyph_surface->height;
 	    const uint8_t *d;
 	    uint8_t *new, *n;
@@ -4044,7 +4036,7 @@ _cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
 	break;
 
     case GLYPHSET_INDEX_ARGB32:
-	if (_native_byte_order_lsb() != (connection->root->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
+	if (_cairo_is_little_endian() != (connection->root->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
 	    unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
 	    const uint32_t *d;
 	    uint32_t *new, *n;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 3f5d0ea..90db7d3 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -164,9 +164,6 @@ _cairo_xlib_surface_create_internal (cairo_xlib_screen_t	*screen,
 static cairo_bool_t
 _cairo_surface_is_xlib (cairo_surface_t *surface);
 
-static cairo_bool_t
-_native_byte_order_lsb (void);
-
 static cairo_int_status_t
 _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
 				 cairo_operator_t     op,
@@ -644,7 +641,7 @@ static void
 _swap_ximage_to_native (XImage *ximage)
 {
     int unit_bytes = 0;
-    int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
+    int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
 
     if (ximage->bits_per_pixel == 1 &&
 	ximage->bitmap_bit_order != native_byte_order)
@@ -1151,7 +1148,7 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
     cairo_xlib_display_t *display;
     XImage ximage;
     cairo_format_masks_t image_masks;
-    int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
+    int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
     pixman_image_t *pixman_image = NULL;
     cairo_status_t status;
     cairo_bool_t own_data;
@@ -4025,14 +4022,6 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
     }
 }
 
-static cairo_bool_t
-_native_byte_order_lsb (void)
-{
-    int	x = 1;
-
-    return *((char *) &x) == 1;
-}
-
 static int
 _cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
 {
@@ -4254,7 +4243,7 @@ _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
     switch (_cairo_xlib_get_glyphset_index_for_format (scaled_glyph->surface->format)) {
     case GLYPHSET_INDEX_A1:
 	/* local bitmaps are always stored with bit == byte */
-	if (_native_byte_order_lsb() != (BitmapBitOrder (display->display) == LSBFirst)) {
+	if (_cairo_is_little_endian() != (BitmapBitOrder (display->display) == LSBFirst)) {
 	    int		    c = glyph_surface->stride * glyph_surface->height;
 	    unsigned char   *d;
 	    unsigned char   *new, *n;
@@ -4279,7 +4268,7 @@ _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
     case GLYPHSET_INDEX_A8:
 	break;
     case GLYPHSET_INDEX_ARGB32:
-	if (_native_byte_order_lsb() != (ImageByteOrder (display->display) == LSBFirst)) {
+	if (_cairo_is_little_endian() != (ImageByteOrder (display->display) == LSBFirst)) {
 	    unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
 	    const uint32_t *d;
 	    uint32_t *new, *n;
diff --git a/src/cairoint.h b/src/cairoint.h
index efe9424..1d658c8 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -182,6 +182,13 @@ _cairo_popcount (uint32_t mask)
 #endif
 }
 
+static cairo_always_inline cairo_bool_t
+_cairo_is_little_endian (void)
+{
+    static const int i = 1;
+    return *((char *) &i) == 0x01;
+}
+
 #ifdef WORDS_BIGENDIAN
 #define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) (c)
 #else
commit 7bfcf1deaf572dcc948e4093dcb864aeaa65e6b4
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Wed Mar 2 01:28:13 2011 +0200

    gl: Store gradients in 2D textures of height 1 instead of 1D textures
    
    1D textures are not available in GLES2. We use 2D textures with height 1
    instead, which are equivalent to 1D textures and exist across all GL flavors.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 4b0ead8..575719b 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -652,9 +652,9 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
         _cairo_gl_gradient_reference (operand->gradient.gradient);
         glActiveTexture (GL_TEXTURE0 + tex_unit);
-        glBindTexture (GL_TEXTURE_1D, operand->gradient.gradient->tex);
-        _cairo_gl_texture_set_extend (ctx, GL_TEXTURE_1D, operand->gradient.extend);
-        _cairo_gl_texture_set_filter (ctx, GL_TEXTURE_1D, CAIRO_FILTER_BILINEAR);
+        glBindTexture (ctx->tex_target, operand->gradient.gradient->tex);
+        _cairo_gl_texture_set_extend (ctx, ctx->tex_target, operand->gradient.extend);
+        _cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR);
 
 	dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
 				       GL_FLOAT, GL_FALSE, vertex_size,
diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
index a48e156..ef7fd53 100644
--- a/src/cairo-gl-gradient.c
+++ b/src/cairo-gl-gradient.c
@@ -239,9 +239,9 @@ _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
 
     glGenTextures (1, &gradient->tex);
     _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
-    glBindTexture (GL_TEXTURE_1D, gradient->tex);
-    glTexImage1D (GL_TEXTURE_1D, 0, GL_RGBA8, tex_width, 0,
-                  GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
+    glBindTexture (ctx->tex_target, gradient->tex);
+    glTexImage2D (ctx->tex_target, 0, GL_RGBA8, tex_width, 1, 0,
+		  GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
 
     dispatch->BindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
 
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index e35c256..77a28aa 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -638,34 +638,34 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	_cairo_output_stream_printf (stream,
 	    "varying vec2 %s_texcoords;\n"
 	    "uniform vec2 %s_texdims;\n"
-	    "uniform sampler1D %s_sampler;\n"
+	    "uniform sampler2D%s %s_sampler;\n"
 	    "\n"
 	    "vec4 get_%s()\n"
 	    "{\n",
-	    namestr, namestr, namestr, namestr);
+	    namestr, namestr, rectstr, namestr, namestr);
 	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
 	    _cairo_gl_shader_needs_border_fade (op))
 	{
 	    _cairo_output_stream_printf (stream,
 		"    float border_fade = %s_border_fade (%s_texcoords.x, %s_texdims.x);\n"
-		"    vec4 texel = texture1D (%s_sampler, %s_texcoords.x);\n"
+		"    vec4 texel = texture2D%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n"
 		"    return texel * border_fade;\n"
 		"}\n",
-		namestr, namestr, namestr, namestr, namestr);
+		namestr, namestr, namestr, rectstr, namestr, namestr);
 	}
 	else
 	{
 	    _cairo_output_stream_printf (stream,
-		"    return texture1D (%s_sampler, %s_texcoords.x);\n"
+		"    return texture2D%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n"
 		"}\n",
-		namestr, namestr);
+		rectstr, namestr, namestr);
 	}
 	break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
 	_cairo_output_stream_printf (stream,
 	    "varying vec2 %s_texcoords;\n"
 	    "uniform vec2 %s_texdims;\n"
-	    "uniform sampler1D %s_sampler;\n"
+	    "uniform sampler2D%s %s_sampler;\n"
 	    "uniform vec3 %s_circle_d;\n"
 	    "uniform float %s_radius_0;\n"
 	    "\n"
@@ -678,31 +678,31 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	    "    \n"
 	    "    float t = 0.5 * C / B;\n"
 	    "    float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n",
-	    namestr, namestr, namestr, namestr, namestr, namestr,
+	    namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
 	    namestr, namestr, namestr, namestr, namestr);
 	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
 	    _cairo_gl_shader_needs_border_fade (op))
 	{
 	    _cairo_output_stream_printf (stream,
 		"    float border_fade = %s_border_fade (t, %s_texdims.x);\n"
-		"    vec4 texel = texture1D (%s_sampler, t);\n"
+		"    vec4 texel = texture2D%s (%s_sampler, vec2 (t, 0.5));\n"
 		"    return mix (vec4 (0.0), texel * border_fade, is_valid);\n"
 		"}\n",
-		namestr, namestr, namestr);
+		namestr, namestr, rectstr, namestr);
 	}
 	else
 	{
 	    _cairo_output_stream_printf (stream,
-		"    return mix (vec4 (0.0), texture1D (%s_sampler, t), is_valid);\n"
+		"    return mix (vec4 (0.0), texture2D%s (%s_sampler, vec2(t, 0.5)), is_valid);\n"
 		"}\n",
-		namestr);
+		rectstr, namestr);
 	}
 	break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
 	_cairo_output_stream_printf (stream,
 	    "varying vec2 %s_texcoords;\n"
 	    "uniform vec2 %s_texdims;\n"
-	    "uniform sampler1D %s_sampler;\n"
+	    "uniform sampler2D%s %s_sampler;\n"
 	    "uniform vec3 %s_circle_d;\n"
 	    "uniform float %s_a;\n"
 	    "uniform float %s_radius_0;\n"
@@ -722,30 +722,30 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	    "    float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
 	    "    \n"
 	    "    float upper_t = mix (t.y, t.x, is_valid.x);\n",
-	    namestr, namestr, namestr, namestr, namestr, namestr,
+	    namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
 	    namestr, namestr, namestr, namestr, namestr, namestr);
 	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
 	    _cairo_gl_shader_needs_border_fade (op))
 	{
 	    _cairo_output_stream_printf (stream,
 		"    float border_fade = %s_border_fade (upper_t, %s_texdims.x);\n"
-		"    vec4 texel = texture1D (%s_sampler, upper_t);\n"
+		"    vec4 texel = texture2D%s (%s_sampler, vec2 (upper_t, 0.5));\n"
 		"    return mix (vec4 (0.0), texel * border_fade, has_color);\n"
 		"}\n",
-		namestr, namestr, namestr);
+		namestr, namestr, rectstr, namestr);
 	}
 	else
 	{
 	    _cairo_output_stream_printf (stream,
-		"    return mix (vec4 (0.0), texture1D (%s_sampler, upper_t), has_color);\n"
+		"    return mix (vec4 (0.0), texture2D%s (%s_sampler, vec2 (upper_t, 0.5)), has_color);\n"
 		"}\n",
-		namestr);
+		rectstr, namestr);
 	}
 	break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
 	_cairo_output_stream_printf (stream,
 	    "varying vec2 %s_texcoords;\n"
-	    "uniform sampler1D %s_sampler;\n"
+	    "uniform sampler2D%s %s_sampler;\n"
 	    "uniform vec3 %s_circle_d;\n"
 	    "uniform float %s_a;\n"
 	    "uniform float %s_radius_0;\n"
@@ -765,11 +765,11 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	    "    float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
 	    "    \n"
 	    "    float upper_t = mix (t.y, t.x, is_valid.x);\n"
-	    "    return mix (vec4 (0.0), texture1D (%s_sampler, upper_t), has_color);\n"
+	    "    return mix (vec4 (0.0), texture2D%s (%s_sampler, vec2 (upper_t, 0.5)), has_color);\n"
 	    "}\n",
+	    namestr, rectstr, namestr, namestr, namestr, namestr,
 	    namestr, namestr, namestr, namestr, namestr,
-	    namestr, namestr, namestr, namestr, namestr,
-	    namestr, namestr, namestr, namestr);
+	    namestr, namestr, namestr, rectstr, namestr);
 	break;
     case CAIRO_GL_OPERAND_SPANS:
         _cairo_output_stream_printf (stream, 
commit d308eee918f569227d289208e3ef1b5152bbd3f5
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Tue Mar 1 16:41:21 2011 +0200

    gl: Provide a shader implementation of GL_CLAMP_TO_BORDER for GLES2
    
    The GL_CLAMP_TO_BORDER wrapping method (used with CAIRO_EXTEND_NONE) is not
    available in GLES2. We use shaders to implement similar functionality for
    GLES2.
    
    If bilinear filtering is used, the shader performs a linear fade to
    transparency effect in the texel coordinate intervals [-1/2n, 1/2n]
    and [1 - 1/2n, 1 + 1/2n] (n: texture size).
    
    If nearest filtering is used, the shader ensures that a clear color is
    used for all texel coordinate values outside [0, 1).
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 1a4467e..4b0ead8 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -458,9 +458,30 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
 	_cairo_gl_shader_bind_float  (ctx,
 				      uniform_name,
 				      operand->gradient.radius_0);
-        break;
+        /* fall through */
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
     case CAIRO_GL_OPERAND_TEXTURE:
+	/*
+	 * For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
+	 * with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
+	 * these shaders need the texture dimensions for their calculations.
+	 */
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	    _cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
+	    _cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
+	{
+	    float width, height;
+	    if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
+		width = operand->texture.surface->width;
+		height = operand->texture.surface->height;
+	    }
+	    else {
+		width = operand->gradient.gradient->cache_entry.size,
+		height = 1;
+	    }
+	    strcpy (custom_part, "_texdims");
+	    _cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
+	}
         break;
     }
 }
@@ -485,8 +506,14 @@ _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
 
     switch (extend) {
     case CAIRO_EXTEND_NONE:
-	glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
-	glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
+	    glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	    glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	}
+	else {
+	    glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+	    glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+	}
 	break;
     case CAIRO_EXTEND_PAD:
 	glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
diff --git a/src/cairo-gl-ext-def-private.h b/src/cairo-gl-ext-def-private.h
index 1653791..389d356 100644
--- a/src/cairo-gl-ext-def-private.h
+++ b/src/cairo-gl-ext-def-private.h
@@ -96,4 +96,8 @@
 #define GL_PACK_INVERT_MESA 0x8758
 #endif
 
+#ifndef GL_CLAMP_TO_BORDER
+#define GL_CLAMP_TO_BORDER 0x812D
+#endif
+
 #endif /* CAIRO_GL_EXT_DEF_PRIVATE_H */
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index c59f4f7..e35c256 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -315,13 +315,17 @@ typedef struct _cairo_shader_cache_entry {
     cairo_gl_operand_type_t mask;
     cairo_gl_operand_type_t dest;
     cairo_gl_shader_in_t in;
+    GLint src_gl_filter;
+    cairo_bool_t src_border_fade;
+    GLint mask_gl_filter;
+    cairo_bool_t mask_border_fade;
 
     cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */
     cairo_gl_shader_t shader;
 } cairo_shader_cache_entry_t;
 
 static cairo_bool_t
-_cairo_gl_shader_cache_equal (const void *key_a, const void *key_b)
+_cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b)
 {
     const cairo_shader_cache_entry_t *a = key_a;
     const cairo_shader_cache_entry_t *b = key_b;
@@ -332,6 +336,27 @@ _cairo_gl_shader_cache_equal (const void *key_a, const void *key_b)
            a->in   == b->in;
 }
 
+/*
+ * For GLES2 we use more complicated shaders to implement missing GL
+ * features. In this case we need more parameters to uniquely identify
+ * a shader (vs _cairo_gl_shader_cache_equal_desktop()).
+ */
+static cairo_bool_t
+_cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
+{
+    const cairo_shader_cache_entry_t *a = key_a;
+    const cairo_shader_cache_entry_t *b = key_b;
+
+    return a->src  == b->src  &&
+	   a->mask == b->mask &&
+	   a->dest == b->dest &&
+	   a->in   == b->in   &&
+	   a->src_gl_filter == b->src_gl_filter &&
+	   a->src_border_fade == b->src_border_fade &&
+	   a->mask_gl_filter == b->mask_gl_filter &&
+	   a->mask_border_fade == b->mask_border_fade;
+}
+
 static unsigned long
 _cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry)
 {
@@ -384,7 +409,9 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
     memset (ctx->vertex_shaders, 0, sizeof (ctx->vertex_shaders));
 
     status = _cairo_cache_init (&ctx->shaders,
-                                _cairo_gl_shader_cache_equal,
+                                ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ?
+				    _cairo_gl_shader_cache_equal_desktop :
+				    _cairo_gl_shader_cache_equal_gles2,
                                 NULL,
                                 _cairo_gl_shader_cache_destroy,
                                 CAIRO_GL_MAX_SHADERS_PER_CONTEXT);
@@ -534,6 +561,22 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
     return CAIRO_STATUS_SUCCESS;
 }
 
+/*
+ * Returns whether an operand needs a special border fade fragment shader
+ * to simulate the GL_CLAMP_TO_BORDER wrapping method that is missing in GLES2.
+ */
+static cairo_bool_t
+_cairo_gl_shader_needs_border_fade (cairo_gl_operand_t *operand)
+{
+    cairo_extend_t extend =_cairo_gl_operand_get_extend (operand);
+
+    return extend == CAIRO_EXTEND_NONE &&
+	   (operand->type == CAIRO_GL_OPERAND_TEXTURE ||
+	    operand->type == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
+	    operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE ||
+	    operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0);
+}
+
 static void
 cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                             cairo_gl_context_t *ctx,
@@ -566,29 +609,62 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
             namestr, namestr, namestr);
         break;
     case CAIRO_GL_OPERAND_TEXTURE:
-        _cairo_output_stream_printf (stream, 
-            "uniform sampler2D%s %s_sampler;\n"
-            "varying vec2 %s_texcoords;\n"
-            "vec4 get_%s()\n"
-            "{\n"
-            "    return texture2D%s(%s_sampler, %s_texcoords);\n"
-            "}\n",
-            rectstr, namestr, namestr, namestr, rectstr, namestr, namestr);
+	_cairo_output_stream_printf (stream,
+	     "uniform sampler2D%s %s_sampler;\n"
+	     "uniform vec2 %s_texdims;\n"
+	     "varying vec2 %s_texcoords;\n"
+	     "vec4 get_%s()\n"
+	     "{\n",
+	     rectstr, namestr, namestr, namestr, namestr);
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	    _cairo_gl_shader_needs_border_fade (op))
+	{
+	    _cairo_output_stream_printf (stream,
+		"    vec2 border_fade = %s_border_fade (%s_texcoords, %s_texdims);\n"
+		"    vec4 texel = texture2D%s (%s_sampler, %s_texcoords);\n"
+		"    return texel * border_fade.x * border_fade.y;\n"
+		"}\n",
+		namestr, namestr, namestr, rectstr, namestr, namestr);
+	}
+	else
+	{
+	    _cairo_output_stream_printf (stream,
+	        "    return texture2D%s (%s_sampler, %s_texcoords);\n"
+		"}\n",
+		rectstr, namestr, namestr);
+	}
         break;
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-        _cairo_output_stream_printf (stream, 
-            "varying vec2 %s_texcoords;\n"
-            "uniform sampler1D %s_sampler;\n"
-            "\n"
-            "vec4 get_%s()\n"
-            "{\n"
-            "    return texture1D (%s_sampler, %s_texcoords.x);\n"
-            "}\n",
-	     namestr, namestr, namestr, namestr, namestr);
-        break;
+	_cairo_output_stream_printf (stream,
+	    "varying vec2 %s_texcoords;\n"
+	    "uniform vec2 %s_texdims;\n"
+	    "uniform sampler1D %s_sampler;\n"
+	    "\n"
+	    "vec4 get_%s()\n"
+	    "{\n",
+	    namestr, namestr, namestr, namestr);
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	    _cairo_gl_shader_needs_border_fade (op))
+	{
+	    _cairo_output_stream_printf (stream,
+		"    float border_fade = %s_border_fade (%s_texcoords.x, %s_texdims.x);\n"
+		"    vec4 texel = texture1D (%s_sampler, %s_texcoords.x);\n"
+		"    return texel * border_fade;\n"
+		"}\n",
+		namestr, namestr, namestr, namestr, namestr);
+	}
+	else
+	{
+	    _cairo_output_stream_printf (stream,
+		"    return texture1D (%s_sampler, %s_texcoords.x);\n"
+		"}\n",
+		namestr, namestr);
+	}
+	break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
 	_cairo_output_stream_printf (stream,
 	    "varying vec2 %s_texcoords;\n"
+	    "uniform vec2 %s_texdims;\n"
 	    "uniform sampler1D %s_sampler;\n"
 	    "uniform vec3 %s_circle_d;\n"
 	    "uniform float %s_radius_0;\n"
@@ -601,15 +677,31 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	    "    float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
 	    "    \n"
 	    "    float t = 0.5 * C / B;\n"
-	    "    float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n"
-	    "    return mix (vec4 (0.0), texture1D (%s_sampler, t), is_valid);\n"
-	    "}\n",
+	    "    float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n",
 	    namestr, namestr, namestr, namestr, namestr, namestr,
 	    namestr, namestr, namestr, namestr, namestr);
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	    _cairo_gl_shader_needs_border_fade (op))
+	{
+	    _cairo_output_stream_printf (stream,
+		"    float border_fade = %s_border_fade (t, %s_texdims.x);\n"
+		"    vec4 texel = texture1D (%s_sampler, t);\n"
+		"    return mix (vec4 (0.0), texel * border_fade, is_valid);\n"
+		"}\n",
+		namestr, namestr, namestr);
+	}
+	else
+	{
+	    _cairo_output_stream_printf (stream,
+		"    return mix (vec4 (0.0), texture1D (%s_sampler, t), is_valid);\n"
+		"}\n",
+		namestr);
+	}
 	break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
 	_cairo_output_stream_printf (stream,
 	    "varying vec2 %s_texcoords;\n"
+	    "uniform vec2 %s_texdims;\n"
 	    "uniform sampler1D %s_sampler;\n"
 	    "uniform vec3 %s_circle_d;\n"
 	    "uniform float %s_a;\n"
@@ -629,11 +721,26 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 	    "    vec2 is_valid = step (vec2 (0.0), t) * step (t, vec2(1.0));\n"
 	    "    float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
 	    "    \n"
-	    "    float upper_t = mix (t.y, t.x, is_valid.x);\n"
-	    "    return mix (vec4 (0.0), texture1D (%s_sampler, upper_t), has_color);\n"
-	    "}\n",
+	    "    float upper_t = mix (t.y, t.x, is_valid.x);\n",
 	    namestr, namestr, namestr, namestr, namestr, namestr,
 	    namestr, namestr, namestr, namestr, namestr, namestr);
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	    _cairo_gl_shader_needs_border_fade (op))
+	{
+	    _cairo_output_stream_printf (stream,
+		"    float border_fade = %s_border_fade (upper_t, %s_texdims.x);\n"
+		"    vec4 texel = texture1D (%s_sampler, upper_t);\n"
+		"    return mix (vec4 (0.0), texel * border_fade, has_color);\n"
+		"}\n",
+		namestr, namestr, namestr);
+	}
+	else
+	{
+	    _cairo_output_stream_printf (stream,
+		"    return mix (vec4 (0.0), texture1D (%s_sampler, upper_t), has_color);\n"
+		"}\n",
+		namestr);
+	}
 	break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
 	_cairo_output_stream_printf (stream,
@@ -676,6 +783,57 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
     }
 }
 
+/*
+ * Emits the border fade functions used by an operand.
+ *
+ * If bilinear filtering is used, the emitted function performs a linear
+ * fade to transparency effect in the intervals [-1/2n, 1/2n] and
+ * [1 - 1/2n, 1 + 1/2n] (n: texture size).
+ *
+ * If nearest filtering is used, the emitted function just returns
+ * 0.0 for all values outside [0, 1).
+ */
+static void
+_cairo_gl_shader_emit_border_fade (cairo_output_stream_t *stream,
+				   cairo_gl_operand_t *operand,
+				   cairo_gl_tex_t name)
+{
+    const char *namestr = operand_names[name];
+    GLint gl_filter = _cairo_gl_operand_get_gl_filter (operand);
+
+    /* 2D version */
+    _cairo_output_stream_printf (stream,
+	"vec2 %s_border_fade (vec2 coords, vec2 dims)\n"
+	"{\n",
+	namestr);
+
+    if (gl_filter == GL_LINEAR)
+	_cairo_output_stream_printf (stream,
+	    "    return clamp(-abs(dims * (coords - 0.5)) + (dims + vec2(1.0)) * 0.5, 0.0, 1.0);\n");
+    else
+	_cairo_output_stream_printf (stream,
+	    "    bvec2 in_tex1 = greaterThanEqual (coords, vec2 (0.0));\n"
+	    "    bvec2 in_tex2 = lessThan (coords, vec2 (1.0));\n"
+	    "    return vec2 (float (all (in_tex1) && all (in_tex2)));\n");
+
+    _cairo_output_stream_printf (stream, "}\n");
+
+    /* 1D version */
+    _cairo_output_stream_printf (stream,
+	"float %s_border_fade (float x, float dim)\n"
+	"{\n",
+	namestr);
+    if (gl_filter == GL_LINEAR)
+	_cairo_output_stream_printf (stream,
+	    "    return clamp(-abs(dim * (x - 0.5)) + (dim + 1.0) * 0.5, 0.0, 1.0);\n");
+    else
+	_cairo_output_stream_printf (stream,
+	    "    bool in_tex = x >= 0.0 && x < 1.0;\n"
+	    "    return float (in_tex);\n");
+
+    _cairo_output_stream_printf (stream, "}\n");
+}
+
 static cairo_status_t
 cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
                                      cairo_gl_shader_in_t in,
@@ -689,6 +847,13 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
     unsigned long length;
     cairo_status_t status;
 
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
+	if (_cairo_gl_shader_needs_border_fade (src))
+	    _cairo_gl_shader_emit_border_fade (stream, src, CAIRO_GL_TEX_SOURCE);
+	if (_cairo_gl_shader_needs_border_fade (mask))
+	    _cairo_gl_shader_emit_border_fade (stream, mask, CAIRO_GL_TEX_MASK);
+    }
+
     cairo_gl_shader_emit_color (stream, ctx, src, CAIRO_GL_TEX_SOURCE);
     cairo_gl_shader_emit_color (stream, ctx, mask, CAIRO_GL_TEX_MASK);
 
@@ -880,6 +1045,10 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
     lookup.mask = mask->type;
     lookup.dest = CAIRO_GL_OPERAND_NONE;
     lookup.in = in;
+    lookup.src_gl_filter = _cairo_gl_operand_get_gl_filter (source);
+    lookup.src_border_fade = _cairo_gl_shader_needs_border_fade (source);
+    lookup.mask_gl_filter = _cairo_gl_operand_get_gl_filter (mask);
+    lookup.mask_border_fade = _cairo_gl_shader_needs_border_fade (mask);
     lookup.base.hash = _cairo_gl_shader_cache_hash (&lookup);
     lookup.base.size = 1;
 
commit 63aa65cfbb0fa25d679c24cd78139d2557bbed37
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Tue Mar 1 14:50:25 2011 +0200

    gl: Add functions to get the filter and extend of gl operands.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 05982c4..1a4467e 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -308,6 +308,63 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
     }
 }
 
+cairo_filter_t
+_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand)
+{
+    cairo_filter_t filter;
+
+    switch ((int) operand->type) {
+    case CAIRO_GL_OPERAND_TEXTURE:
+	filter = operand->texture.attributes.filter;
+	break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+	filter = CAIRO_FILTER_BILINEAR;
+	break;
+    default:
+	filter = CAIRO_FILTER_DEFAULT;
+	break;
+    }
+
+    return filter;
+}
+
+GLint
+_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand)
+{
+    cairo_filter_t filter = _cairo_gl_operand_get_filter (operand);
+
+    return filter != CAIRO_FILTER_FAST && filter != CAIRO_FILTER_NEAREST ?
+	   GL_LINEAR :
+	   GL_NEAREST;
+}
+
+cairo_extend_t
+_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand)
+{
+    cairo_extend_t extend;
+
+    switch ((int) operand->type) {
+    case CAIRO_GL_OPERAND_TEXTURE:
+	extend = operand->texture.attributes.extend;
+	break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+	extend = operand->gradient.extend;
+	break;
+    default:
+	extend = CAIRO_EXTEND_NONE;
+	break;
+    }
+
+    return extend;
+}
+
+
 cairo_int_status_t
 _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
 			        const cairo_pattern_t *pattern,
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index e4f1cce..6f1d410 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -575,6 +575,14 @@ cairo_private cairo_status_t
 _cairo_gl_dispatch_init(cairo_gl_dispatch_t *dispatch,
 			cairo_gl_get_proc_addr_func_t get_proc_addr);
 
+cairo_private cairo_filter_t
+_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand);
+
+cairo_private GLint
+_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand);
+
+cairo_private cairo_extend_t
+_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand);
 
 slim_hidden_proto (cairo_gl_surface_create);
 slim_hidden_proto (cairo_gl_surface_create_for_texture);
commit 7185ce4ddb0d291ecbecd31b5855be798cca2058
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Mon Feb 28 17:28:46 2011 +0200

    gl: Pass more information to the shader emitter functions
    
    This makes the shader emitter functions more versatile. It allows them to use
    all information provided by the operands and the context to decide what shader
    to produce.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index c8f84a9..05982c4 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -782,8 +782,8 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
     if (setup->op == CAIRO_OPERATOR_OVER) {
 	setup->op = CAIRO_OPERATOR_ADD;
 	status = _cairo_gl_get_shader_by_type (ctx,
-                                               setup->src.type,
-                                               setup->mask.type,
+                                               &setup->src,
+                                               &setup->mask,
                                                CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
                                                &pre_shader);
         if (unlikely (status))
@@ -831,8 +831,8 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     }
 
     status = _cairo_gl_get_shader_by_type (ctx,
-                                           setup->src.type,
-                                           setup->mask.type,
+                                           &setup->src,
+                                           &setup->mask,
                                            component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
                                                            : CAIRO_GL_SHADER_IN_NORMAL,
                                            &shader);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 602550f..e4f1cce 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -517,8 +517,8 @@ _cairo_gl_context_is_flushed (cairo_gl_context_t *ctx)
 
 cairo_private cairo_status_t
 _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
-                              cairo_gl_operand_type_t source,
-                              cairo_gl_operand_type_t mask,
+                              cairo_gl_operand_t *source,
+                              cairo_gl_operand_t *mask,
                               cairo_gl_shader_in_t in,
                               cairo_gl_shader_t **shader);
 
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 39e4e30..c59f4f7 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -536,14 +536,14 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
 
 static void
 cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
-                            GLuint tex_target,
-                            cairo_gl_operand_type_t type,
+                            cairo_gl_context_t *ctx,
+                            cairo_gl_operand_t *op,
                             cairo_gl_tex_t name)
 {
     const char *namestr = operand_names[name];
-    const char *rectstr = (tex_target == GL_TEXTURE_RECTANGLE ? "Rect" : "");
+    const char *rectstr = (ctx->tex_target == GL_TEXTURE_RECTANGLE ? "Rect" : "");
 
-    switch (type) {
+    switch (op->type) {
     case CAIRO_GL_OPERAND_COUNT:
     default:
         ASSERT_NOT_REACHED;
@@ -677,11 +677,11 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
 }
 
 static cairo_status_t
-cairo_gl_shader_get_fragment_source (GLuint tex_target,
+cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
                                      cairo_gl_shader_in_t in,
-                                     cairo_gl_operand_type_t src,
-                                     cairo_gl_operand_type_t mask,
-                                     cairo_gl_operand_type_t dest,
+                                     cairo_gl_operand_t *src,
+                                     cairo_gl_operand_t *mask,
+                                     cairo_gl_operand_type_t dest_type,
 				     char **out)
 {
     cairo_output_stream_t *stream = _cairo_memory_stream_create ();
@@ -689,8 +689,8 @@ cairo_gl_shader_get_fragment_source (GLuint tex_target,
     unsigned long length;
     cairo_status_t status;
 
-    cairo_gl_shader_emit_color (stream, tex_target, src, CAIRO_GL_TEX_SOURCE);
-    cairo_gl_shader_emit_color (stream, tex_target, mask, CAIRO_GL_TEX_MASK);
+    cairo_gl_shader_emit_color (stream, ctx, src, CAIRO_GL_TEX_SOURCE);
+    cairo_gl_shader_emit_color (stream, ctx, mask, CAIRO_GL_TEX_MASK);
 
     _cairo_output_stream_printf (stream,
         "void main()\n"
@@ -867,8 +867,8 @@ _cairo_gl_set_shader (cairo_gl_context_t *ctx,
 
 cairo_status_t
 _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
-                              cairo_gl_operand_type_t source,
-                              cairo_gl_operand_type_t mask,
+                              cairo_gl_operand_t *source,
+                              cairo_gl_operand_t *mask,
                               cairo_gl_shader_in_t in,
                               cairo_gl_shader_t **shader)
 {
@@ -876,8 +876,8 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
     char *fs_source;
     cairo_status_t status;
 
-    lookup.src = source;
-    lookup.mask = mask;
+    lookup.src = source->type;
+    lookup.mask = mask->type;
     lookup.dest = CAIRO_GL_OPERAND_NONE;
     lookup.in = in;
     lookup.base.hash = _cairo_gl_shader_cache_hash (&lookup);
@@ -890,7 +890,7 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    status = cairo_gl_shader_get_fragment_source (ctx->tex_target,
+    status = cairo_gl_shader_get_fragment_source (ctx,
 						  in,
 						  source,
 						  mask,
@@ -911,8 +911,8 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
     _cairo_gl_shader_init (&entry->shader);
     status = _cairo_gl_shader_compile (ctx,
 				       &entry->shader,
-				       cairo_gl_operand_get_var_type (source),
-				       cairo_gl_operand_get_var_type (mask),
+				       cairo_gl_operand_get_var_type (source->type),
+				       cairo_gl_operand_get_var_type (mask->type),
 				       fs_source);
     free (fs_source);
 
commit 1f9200ffbf19e73ec2f11a56ec77a104f07c7ec0
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Mon Feb 14 16:36:09 2011 +0200

    gl: Add GLES2 support to dispatch table initialization
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-dispatch-private.h b/src/cairo-gl-dispatch-private.h
index 0795e70..751913c 100644
--- a/src/cairo-gl-dispatch-private.h
+++ b/src/cairo-gl-dispatch-private.h
@@ -35,26 +35,34 @@
 #include "cairo-gl-private.h"
 #include <stddef.h>
 
+typedef enum _cairo_gl_dispatch_name {
+    CAIRO_GL_DISPATCH_NAME_CORE,
+    CAIRO_GL_DISPATCH_NAME_EXT,
+    CAIRO_GL_DISPATCH_NAME_ES,
+    CAIRO_GL_DISPATCH_NAME_COUNT
+} cairo_gl_dispatch_name_t;
+
 typedef struct _cairo_gl_dispatch_entry {
-    const char *name_core;
-    const char *name_ext;
+    const char *name[CAIRO_GL_DISPATCH_NAME_COUNT];
     size_t offset;
 } cairo_gl_dispatch_entry_t;
 
-#define DISPATCH_ENTRY_ARB(name) { "gl"#name, "gl"#name"ARB", \
+#define DISPATCH_ENTRY_ARB(name) { { "gl"#name, "gl"#name"ARB", "gl"#name }, \
 				   offsetof(cairo_gl_dispatch_t, name) }
-#define DISPATCH_ENTRY_EXT(name) { "gl"#name, "gl"#name"EXT", \
+#define DISPATCH_ENTRY_EXT(name) { { "gl"#name, "gl"#name"EXT", "gl"#name }, \
 				   offsetof(cairo_gl_dispatch_t, name) }
-#define DISPATCH_ENTRY_CUSTOM(name, name2) { "gl"#name, "gl"#name2, \
+#define DISPATCH_ENTRY_ARB_OES(name) { { "gl"#name, "gl"#name"ARB", "gl"#name"OES" }, \
+				       offsetof(cairo_gl_dispatch_t, name) }
+#define DISPATCH_ENTRY_CUSTOM(name, name2) { { "gl"#name, "gl"#name2, "gl"#name }, \
 			                     offsetof(cairo_gl_dispatch_t, name)}
-#define DISPATCH_ENTRY_LAST { NULL, NULL, 0 }
+#define DISPATCH_ENTRY_LAST { { NULL, NULL, NULL }, 0 }
 
 cairo_private cairo_gl_dispatch_entry_t dispatch_buffers_entries[] = {
-    DISPATCH_ENTRY_ARB (GenBuffers),
-    DISPATCH_ENTRY_ARB (BindBuffer),
-    DISPATCH_ENTRY_ARB (BufferData),
-    DISPATCH_ENTRY_ARB (MapBuffer),
-    DISPATCH_ENTRY_ARB (UnmapBuffer),
+    DISPATCH_ENTRY_ARB     (GenBuffers),
+    DISPATCH_ENTRY_ARB     (BindBuffer),
+    DISPATCH_ENTRY_ARB     (BufferData),
+    DISPATCH_ENTRY_ARB_OES (MapBuffer),
+    DISPATCH_ENTRY_ARB_OES (UnmapBuffer),
     DISPATCH_ENTRY_LAST
 };
 
diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c
index 0f64731..6277f53 100644
--- a/src/cairo-gl-dispatch.c
+++ b/src/cairo-gl-dispatch.c
@@ -37,14 +37,13 @@ static void
 _cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch,
 				 cairo_gl_get_proc_addr_func_t get_proc_addr,
 				 cairo_gl_dispatch_entry_t *entries,
-				 cairo_bool_t use_ext)
+				 cairo_gl_dispatch_name_t dispatch_name)
 {
     cairo_gl_dispatch_entry_t *entry = entries;
 
-    while (entry->name_core != NULL) {
+    while (entry->name[CAIRO_GL_DISPATCH_NAME_CORE] != NULL) {
 	void *dispatch_ptr = &((char *) dispatch)[entry->offset];
-	const char *name = use_ext ? entry->name_ext :
-				     entry->name_core;
+	const char *name = entry->name[dispatch_name];
 
 	cairo_gl_generic_func_t func = get_proc_addr (name);
 
@@ -58,19 +57,32 @@ _cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch,
 static cairo_status_t
 _cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch,
 				 cairo_gl_get_proc_addr_func_t get_proc_addr,
-				 int gl_version)
+				 int gl_version, cairo_gl_flavor_t gl_flavor)
 {
-    cairo_bool_t use_ext;
-
-    if (gl_version >= CAIRO_GL_VERSION_ENCODE (1, 5))
-	use_ext = 0;
-    else if (_cairo_gl_has_extension ("GL_ARB_vertex_buffer_object"))
-	use_ext = 1;
+    cairo_gl_dispatch_name_t dispatch_name;
+
+    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+    {
+	if (gl_version >= CAIRO_GL_VERSION_ENCODE (1, 5))
+	    dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
+	else if (_cairo_gl_has_extension ("GL_ARB_vertex_buffer_object"))
+	    dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
+	else
+	    return CAIRO_STATUS_DEVICE_ERROR;
+    }
+    else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	     gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0) &&
+	     _cairo_gl_has_extension ("GL_OES_mapbuffer"))
+    {
+	dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
+    }
     else
+    {
 	return CAIRO_STATUS_DEVICE_ERROR;
+    }
 
     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
-				     dispatch_buffers_entries, use_ext);
+				     dispatch_buffers_entries, dispatch_name);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -78,20 +90,31 @@ _cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch,
 static cairo_status_t
 _cairo_gl_dispatch_init_shaders (cairo_gl_dispatch_t *dispatch,
 				 cairo_gl_get_proc_addr_func_t get_proc_addr,
-				 int gl_version)
+				 int gl_version, cairo_gl_flavor_t gl_flavor)
 {
-    cairo_bool_t use_ext;
-
-    /* Note: shader support is not necessary at the moment */
-    if (gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
-	use_ext = 0;
-    else if (_cairo_gl_has_extension ("GL_ARB_shader_objects"))
-	use_ext = 1;
+    cairo_gl_dispatch_name_t dispatch_name;
+
+    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+    {
+	if (gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
+	    dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
+	else if (_cairo_gl_has_extension ("GL_ARB_shader_objects"))
+	    dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
+	else
+	    return CAIRO_STATUS_DEVICE_ERROR;
+    }
+    else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	     gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
+    {
+	dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
+    }
     else
-	return CAIRO_STATUS_SUCCESS;
+    {
+	return CAIRO_STATUS_DEVICE_ERROR;
+    }
 
     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
-				     dispatch_shaders_entries, use_ext);
+				     dispatch_shaders_entries, dispatch_name);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -99,20 +122,32 @@ _cairo_gl_dispatch_init_shaders (cairo_gl_dispatch_t *dispatch,
 static cairo_status_t
 _cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch,
 			     cairo_gl_get_proc_addr_func_t get_proc_addr,
-			     int gl_version)
+			     int gl_version, cairo_gl_flavor_t gl_flavor)
 {
-    cairo_bool_t use_ext;
-
-    if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
-	_cairo_gl_has_extension ("GL_ARB_framebuffer_object"))
-	use_ext = 0;
-    else if (_cairo_gl_has_extension ("GL_EXT_framebuffer_object"))
-	use_ext = 1;
+    cairo_gl_dispatch_name_t dispatch_name;
+
+    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+    {
+	if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
+	    _cairo_gl_has_extension ("GL_ARB_framebuffer_object"))
+	    dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
+	else if (_cairo_gl_has_extension ("GL_EXT_framebuffer_object"))
+	    dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
+	else
+	    return CAIRO_STATUS_DEVICE_ERROR;
+    }
+    else if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
+	     gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
+    {
+	dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
+    }
     else
+    {
 	return CAIRO_STATUS_DEVICE_ERROR;
+    }
 
     _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
-				     dispatch_fbo_entries, use_ext);
+				     dispatch_fbo_entries, dispatch_name);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -123,21 +158,23 @@ _cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
 {
     cairo_status_t status;
     int gl_version;
+    cairo_gl_flavor_t gl_flavor;
 
     gl_version = _cairo_gl_get_version ();
+    gl_flavor = _cairo_gl_get_flavor ();
 
     status = _cairo_gl_dispatch_init_buffers (dispatch, get_proc_addr,
-					      gl_version);
+					      gl_version, gl_flavor);
     if (status != CAIRO_STATUS_SUCCESS)
 	return status;
 
     status = _cairo_gl_dispatch_init_shaders (dispatch, get_proc_addr,
-					      gl_version);
+					      gl_version, gl_flavor);
     if (status != CAIRO_STATUS_SUCCESS)
 	return status;
 
     status = _cairo_gl_dispatch_init_fbo (dispatch, get_proc_addr,
-					  gl_version);
+					  gl_version, gl_flavor);
     if (status != CAIRO_STATUS_SUCCESS)
 	return status;
 
commit 4804160fd16912559acfaed55c8d4aeaecb18190
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Mon Feb 14 15:11:07 2011 +0200

    gl: Store the GL flavor (Desktop or ES) in the device struct
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index d206da8..35339aa 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -183,6 +183,7 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 	_cairo_gl_has_extension ("GL_MESA_pack_invert");
 
     ctx->current_operator = -1;
+    ctx->gl_flavor = _cairo_gl_get_flavor ();
 
     status = _cairo_gl_context_init_shaders (ctx);
     if (unlikely (status))
diff --git a/src/cairo-gl-info.c b/src/cairo-gl-info.c
index 168d194..12a618d 100644
--- a/src/cairo-gl-info.c
+++ b/src/cairo-gl-info.c
@@ -55,6 +55,22 @@ _cairo_gl_get_version (void)
     return CAIRO_GL_VERSION_ENCODE (major, minor);
 }
 
+cairo_gl_flavor_t
+_cairo_gl_get_flavor (void)
+{
+    const char *version = (const char *) glGetString (GL_VERSION);
+    cairo_gl_flavor_t flavor;
+
+    if (version == NULL)
+	flavor = CAIRO_GL_FLAVOR_NONE;
+    else if (strstr (version, "OpenGL ES") != NULL)
+	flavor = CAIRO_GL_FLAVOR_ES;
+    else
+	flavor = CAIRO_GL_FLAVOR_DESKTOP;
+
+    return flavor;
+}
+
 cairo_bool_t
 _cairo_gl_has_extension (const char *ext)
 {
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 73818b1..602550f 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -86,6 +86,13 @@
 /* VBO size that we allocate, smaller size means we gotta flush more often */
 #define CAIRO_GL_VBO_SIZE 16384
 
+/* GL flavor */
+typedef enum cairo_gl_flavor {
+    CAIRO_GL_FLAVOR_NONE = 0,
+    CAIRO_GL_FLAVOR_DESKTOP = 1,
+    CAIRO_GL_FLAVOR_ES = 2
+} cairo_gl_flavor_t;
+
 /* Indices for vertex attributes used by BindAttribLocation etc */
 enum {
     CAIRO_GL_VERTEX_ATTRIB_INDEX = 0,
@@ -279,6 +286,7 @@ struct _cairo_gl_context {
     cairo_bool_t has_mesa_pack_invert;
     cairo_gl_dispatch_t dispatch;
     GLfloat modelviewprojection_matrix[16];
+    cairo_gl_flavor_t gl_flavor;
 
     void (*acquire) (void *ctx);
     void (*release) (void *ctx);
@@ -557,6 +565,9 @@ _cairo_gl_shader_fini (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader);
 cairo_private int
 _cairo_gl_get_version (void);
 
+cairo_private cairo_gl_flavor_t
+_cairo_gl_get_flavor (void);
+
 cairo_private cairo_bool_t
 _cairo_gl_has_extension (const char *ext);
 
commit f1eef40c2a2c865999d29230c84cd709784ca294
Author: Alexandros Frantzis <alexandros.frantzis at linaro.org>
Date:   Mon Feb 14 14:45:52 2011 +0200

    gl: Correctly extract GL version from OpenGL ES version strings
    
    The GL version string returned by glGetString() for GLES doesn't have the
    version number at the beginning of the string.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-gl-info.c b/src/cairo-gl-info.c
index 5b4190e..168d194 100644
--- a/src/cairo-gl-info.c
+++ b/src/cairo-gl-info.c
@@ -38,13 +38,17 @@ _cairo_gl_get_version (void)
     int major, minor;
     const char *version = (const char *) glGetString (GL_VERSION);
     const char *dot = version == NULL ? NULL : strchr (version, '.');
+    const char *major_start = dot;
 
     /* Sanity check */
     if (dot == NULL || dot == version || *(dot + 1) == '\0') {
 	major = 0;
 	minor = 0;
     } else {
-	major = strtol (version, NULL, 10);
+	/* Find the start of the major version in the string */
+	while (major_start > version && *major_start != ' ')
+	    --major_start;
+	major = strtol (major_start, NULL, 10);
 	minor = strtol (dot + 1, NULL, 10);
     }
 


More information about the cairo-commit mailing list