[cairo-commit] 30 commits - src/cairo-gl-composite.c src/cairo-gl-device.c src/cairo-gl-glyphs.c src/cairo-gl-private.h src/cairo-gl-shaders.c src/cairo-gl-surface.c src/cairo-xlib-surface.c src/Makefile.sources

Benjamin Otte company at kemper.freedesktop.org
Sun May 16 16:17:08 PDT 2010


 src/Makefile.sources     |    3 
 src/cairo-gl-composite.c | 1392 ++++++++++++++++++++++++++++++++++++++++
 src/cairo-gl-device.c    |   31 
 src/cairo-gl-glyphs.c    |  344 +--------
 src/cairo-gl-private.h   |  224 ++++--
 src/cairo-gl-shaders.c   |  880 +++++++++++++------------
 src/cairo-gl-surface.c   | 1624 +++--------------------------------------------
 src/cairo-xlib-surface.c |    4 
 8 files changed, 2195 insertions(+), 2307 deletions(-)

New commits:
commit 7ef1bd22ded512f4fad3959796d7f40c4ddc5824
Author: Benjamin Otte <otte at redhat.com>
Date:   Mon May 17 01:12:34 2010 +0200

    gl: Update copyright statements
    
    - add 2010 Red Hat copyright for my code
    - include myself as author
    - update contributors list

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 02afe2f..91f94f9 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -2,7 +2,7 @@
  *
  * Copyright © 2009 Eric Anholt
  * Copyright © 2009 Chris Wilson
- * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2005,2010 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -32,7 +32,10 @@
  * The Initial Developer of the Original Code is Red Hat, Inc.
  *
  * Contributor(s):
+ *	Benjamin Otte <otte at gnome.org>
  *	Carl Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ *	Eric Anholt <eric at anholt.net>
  */
 
 #include "cairoint.h"
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 99dfa18..e506ca7 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -2,7 +2,7 @@
  *
  * Copyright © 2009 Eric Anholt
  * Copyright © 2009 Chris Wilson
- * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2005,2010 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -32,7 +32,10 @@
  * The Initial Developer of the Original Code is Red Hat, Inc.
  *
  * Contributor(s):
+ *	Benjamin Otte <otte at gnome.org>
  *	Carl Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ *	Eric Anholt <eric at anholt.net>
  */
 
 #include "cairoint.h"
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index d0aae23..d9107bc 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -2,6 +2,7 @@
  *
  * Copyright © 2009 Chris Wilson
  * Copyright © 2010 Intel Corporation
+ * Copyright © 2010 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -29,6 +30,10 @@
  * The Original Code is the cairo graphics library.
  *
  * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributors:
+ *      Benjamin Otte <otte at gnome.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
  */
 
 #include "cairoint.h"
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index e9aeeb0..77d0ef7 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -2,7 +2,7 @@
  *
  * Copyright © 2009 Eric Anholt
  * Copyright © 2009 Chris Wilson
- * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2005,2010 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -32,9 +32,11 @@
  * The Initial Developer of the Original Code is Red Hat, Inc.
  *
  * Contributor(s):
+ *	Benjamin Otte <otte at gnome.org>
  *	Carl Worth <cworth at cworth.org>
  *	Chris Wilson <chris at chris-wilson.co.uk>
- *      T. Zachary Laine <whatwasthataddress at gmail.com>
+ *	Eric Anholt <eric at anholt.net>
+ *	T. Zachary Laine <whatwasthataddress at gmail.com>
  */
 
 #ifndef CAIRO_GL_PRIVATE_H
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index c3de05a..403f76f 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -1,7 +1,8 @@
 /* cairo - a vector graphics library with display and print output
  *
- * Copyright © 2010 Eric Anholt
  * Copyright © 2009 T. Zachary Laine
+ * Copyright © 2010 Eric Anholt
+ * Copyright © 2010 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -29,6 +30,11 @@
  * The Original Code is the cairo graphics library.
  *
  * The Initial Developer of the Original Code is T. Zachary Laine.
+ *
+ * Contributor(s):
+ *	Benjamin Otte <otte at gnome.org>
+ *	Eric Anholt <eric at anholt.net>
+ *	T. Zachary Laine <whatwasthataddress at gmail.com>
  */
 
 #include "cairoint.h"
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 154b925..f485682 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -2,7 +2,7 @@
  *
  * Copyright © 2009 Eric Anholt
  * Copyright © 2009 Chris Wilson
- * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2005,2010 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -32,7 +32,10 @@
  * The Initial Developer of the Original Code is Red Hat, Inc.
  *
  * Contributor(s):
+ *	Benjamin Otte <otte at gnome.org>
  *	Carl Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ *	Eric Anholt <eric at anholt.net>
  */
 
 #include "cairoint.h"
commit 0b69e51b526a609a2dc5f1d2fb9c49f240feb57b
Author: Benjamin Otte <otte at redhat.com>
Date:   Mon May 17 00:56:21 2010 +0200

    gl: Assert that binding values to shaders never fails
    
    As that would  be a programming error, we can use an assert and get rid
    of return values that we weren't checking anyway.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index a8ae084..02afe2f 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -556,21 +556,19 @@ _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx,
 {
     if (setup->shader) {
 	const char *uniform_name;
-        cairo_status_t status;
 
 	if (tex_unit == 0)
 	    uniform_name = "source_constant";
 	else
 	    uniform_name = "mask_constant";
 
-	status = bind_vec4_to_shader (ctx,
-                                      setup->shader->program,
-                                      uniform_name,
-                                      color[0],
-                                      color[1],
-                                      color[2],
-                                      color[3]);
-        assert (! _cairo_status_is_error (status));
+	bind_vec4_to_shader (ctx,
+                             setup->shader->program,
+                             uniform_name,
+                             color[0],
+                             color[1],
+                             color[2],
+                             color[3]);
 
 	return;
     }
@@ -612,7 +610,6 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 {
     cairo_surface_attributes_t *src_attributes;
     GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
-    cairo_status_t status;
 
     src_attributes = &setup->src.operand.texture.attributes;
 
@@ -652,16 +649,14 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
 	glEnable (GL_TEXTURE_1D);
 
-	status = bind_matrix_to_shader (ctx, setup->shader->program,
-					"source_matrix",
-					&setup->src.operand.linear.m);
-	assert (!_cairo_status_is_error (status));
+	bind_matrix_to_shader (ctx, setup->shader->program,
+			       "source_matrix",
+			       &setup->src.operand.linear.m);
 
-	status = bind_vec2_to_shader (ctx, setup->shader->program,
-				      "source_segment",
-				      setup->src.operand.linear.segment_x,
-				      setup->src.operand.linear.segment_y);
-	assert (!_cairo_status_is_error (status));
+	bind_vec2_to_shader (ctx, setup->shader->program,
+			     "source_segment",
+			     setup->src.operand.linear.segment_x,
+			     setup->src.operand.linear.segment_y);
 	break;
 
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
@@ -669,26 +664,22 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
 	glEnable (GL_TEXTURE_1D);
 
-        status = bind_matrix_to_shader (ctx, setup->shader->program,
-					"source_matrix",
-					&setup->src.operand.radial.m);
-	assert (!_cairo_status_is_error (status));
-
-        status = bind_vec2_to_shader (ctx, setup->shader->program,
-				      "source_circle_1",
-				      setup->src.operand.radial.circle_1_x,
-				      setup->src.operand.radial.circle_1_y);
-	assert (!_cairo_status_is_error (status));
-
-        status = bind_float_to_shader (ctx, setup->shader->program,
-				       "source_radius_0",
-				       setup->src.operand.radial.radius_0);
-	assert (!_cairo_status_is_error (status));
-
-        status = bind_float_to_shader (ctx, setup->shader->program,
-				       "source_radius_1",
-				       setup->src.operand.radial.radius_1);
-	assert (!_cairo_status_is_error (status));
+        bind_matrix_to_shader (ctx, setup->shader->program,
+			       "source_matrix",
+			       &setup->src.operand.radial.m);
+
+        bind_vec2_to_shader (ctx, setup->shader->program,
+                             "source_circle_1",
+                             setup->src.operand.radial.circle_1_x,
+                             setup->src.operand.radial.circle_1_y);
+
+        bind_float_to_shader (ctx, setup->shader->program,
+                              "source_radius_0",
+                              setup->src.operand.radial.radius_0);
+
+        bind_float_to_shader (ctx, setup->shader->program,
+                              "source_radius_1",
+                              setup->src.operand.radial.radius_1);
 	break;
     default:
     case CAIRO_GL_OPERAND_COUNT:
@@ -751,57 +742,47 @@ static void
 _cairo_gl_set_linear_gradient_mask_operand (cairo_gl_context_t *ctx,
                                             cairo_gl_composite_t *setup)
 {
-    cairo_status_t status;
-
     assert(setup->shader);
 
     glActiveTexture (GL_TEXTURE1);
     glBindTexture (GL_TEXTURE_1D, setup->mask.operand.linear.tex);
     glEnable (GL_TEXTURE_1D);
 
-    status = bind_matrix_to_shader (ctx, setup->shader->program,
+    bind_matrix_to_shader (ctx, setup->shader->program,
 			   "mask_matrix", &setup->mask.operand.linear.m);
-    assert (!_cairo_status_is_error (status));
 
-    status = bind_vec2_to_shader (ctx, setup->shader->program,
+    bind_vec2_to_shader (ctx, setup->shader->program,
 			 "mask_segment",
 			 setup->mask.operand.linear.segment_x,
 			 setup->mask.operand.linear.segment_y);
-    assert (!_cairo_status_is_error (status));
 }
 
 static void
 _cairo_gl_set_radial_gradient_mask_operand (cairo_gl_context_t *ctx,
                                             cairo_gl_composite_t *setup)
 {
-    cairo_status_t status;
-
     assert(setup->shader);
 
     glActiveTexture (GL_TEXTURE1);
     glBindTexture (GL_TEXTURE_1D, setup->mask.operand.radial.tex);
     glEnable (GL_TEXTURE_1D);
 
-    status = bind_matrix_to_shader (ctx, setup->shader->program,
-				    "mask_matrix",
-				    &setup->mask.operand.radial.m);
-    assert (!_cairo_status_is_error (status));
-
-    status = bind_vec2_to_shader (ctx, setup->shader->program,
-				  "mask_circle_1",
-				  setup->mask.operand.radial.circle_1_x,
-				  setup->mask.operand.radial.circle_1_y);
-    assert (!_cairo_status_is_error (status));
-
-    status = bind_float_to_shader (ctx, setup->shader->program,
-				   "mask_radius_0",
-				   setup->mask.operand.radial.radius_0);
-    assert (!_cairo_status_is_error (status));
-
-    status = bind_float_to_shader (ctx, setup->shader->program,
-				   "mask_radius_1",
-				   setup->mask.operand.radial.radius_1);
-    assert (!_cairo_status_is_error (status));
+    bind_matrix_to_shader (ctx, setup->shader->program,
+                           "mask_matrix",
+                           &setup->mask.operand.radial.m);
+
+    bind_vec2_to_shader (ctx, setup->shader->program,
+                         "mask_circle_1",
+                         setup->mask.operand.radial.circle_1_x,
+                         setup->mask.operand.radial.circle_1_y);
+
+    bind_float_to_shader (ctx, setup->shader->program,
+                          "mask_radius_0",
+                          setup->mask.operand.radial.radius_0);
+
+    bind_float_to_shader (ctx, setup->shader->program,
+                          "mask_radius_1",
+                          setup->mask.operand.radial.radius_1);
 }
 
 /* This is like _cairo_gl_set_src_alpha_operand, for component alpha setup
@@ -831,14 +812,12 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
     case CAIRO_GL_OPERAND_CONSTANT:
 	/* Have to have a dummy texture bound in order to use the combiner unit. */
 	if (setup->shader) {
-            cairo_status_t status;
-	    status = bind_vec4_to_shader (ctx, setup->shader->program,
-                                          "mask_constant",
-                                          setup->src.operand.constant.color[0],
-                                          setup->src.operand.constant.color[1],
-                                          setup->src.operand.constant.color[2],
-                                          setup->src.operand.constant.color[3]);
-            assert (! _cairo_status_is_error (status));
+	    bind_vec4_to_shader (ctx, setup->shader->program,
+                                 "mask_constant",
+                                 setup->src.operand.constant.color[0],
+                                 setup->src.operand.constant.color[1],
+                                 setup->src.operand.constant.color[2],
+                                 setup->src.operand.constant.color[3]);
 	} else {
 	    glBindTexture (ctx->tex_target, ctx->dummy_tex);
 	    glActiveTexture (GL_TEXTURE1);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 3f53220..e9aeeb0 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -420,33 +420,33 @@ create_shader_program (cairo_gl_context_t *ctx,
                        cairo_gl_var_type_t mask,
                        const char *fragment_text);
 
-cairo_private cairo_status_t
+cairo_private void
 bind_float_to_shader (cairo_gl_context_t *ctx,
                       GLuint program, const char *name,
                       float value);
 
-cairo_private cairo_status_t
+cairo_private void
 bind_vec2_to_shader (cairo_gl_context_t *ctx,
                      GLuint program, const char *name,
                      float value0, float value1);
 
-cairo_private cairo_status_t
+cairo_private void
 bind_vec3_to_shader (cairo_gl_context_t *ctx,
                      GLuint program, const char *name,
                      float value0, float value1,
                      float value2);
 
-cairo_private cairo_status_t
+cairo_private void
 bind_vec4_to_shader (cairo_gl_context_t *ctx,
                      GLuint program, const char *name,
                      float value0, float value1,
                      float value2, float value3);
 
-cairo_private cairo_status_t
+cairo_private void
 bind_matrix_to_shader (cairo_gl_context_t *ctx,
                        GLuint program, const char *name, cairo_matrix_t* m);
 
-cairo_private cairo_status_t
+cairo_private void
 bind_texture_to_shader (cairo_gl_context_t *ctx,
                         GLuint program, const char *name, GLuint tex_unit);
 
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 7511b4e..c3de05a 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -49,28 +49,28 @@ typedef struct cairo_gl_shader_impl {
     void
     (*destroy_program) (GLuint program);
 
-    cairo_status_t
+    void
     (*bind_float_to_shader) (GLuint program, const char *name,
                              float value);
 
-    cairo_status_t
+    void
     (*bind_vec2_to_shader) (GLuint program, const char *name,
                             float value0, float value1);
 
-    cairo_status_t
+    void
     (*bind_vec3_to_shader) (GLuint program, const char *name,
                             float value0, float value1,
                             float value2);
 
-    cairo_status_t
+    void
     (*bind_vec4_to_shader) (GLuint program, const char *name,
                             float value0, float value1,
                             float value2, float value3);
 
-    cairo_status_t
+    void
     (*bind_matrix_to_shader) (GLuint program, const char *name, cairo_matrix_t* m);
 
-    cairo_status_t
+    void
     (*bind_texture_to_shader) (GLuint program, const char *name, GLuint tex_unit);
 
     void
@@ -159,53 +159,45 @@ destroy_program_arb (GLuint shader)
   glDeleteObjectARB (shader);
 }
 
-static cairo_status_t
+static void
 bind_float_to_shader_arb (GLuint program, const char *name,
                                float value)
 {
     GLint location = glGetUniformLocationARB (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform1fARB (location, value);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_vec2_to_shader_arb (GLuint program, const char *name,
                               float value0, float value1)
 {
     GLint location = glGetUniformLocationARB (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform2fARB (location, value0, value1);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_vec3_to_shader_arb (GLuint program, const char *name,
                               float value0, float value1,
                               float value2)
 {
     GLint location = glGetUniformLocationARB (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform3fARB (location, value0, value1, value2);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_vec4_to_shader_arb (GLuint program, const char *name,
                               float value0, float value1,
                               float value2, float value3)
 {
     GLint location = glGetUniformLocationARB (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform4fARB (location, value0, value1, value2, value3);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_matrix_to_shader_arb (GLuint program, const char *name, cairo_matrix_t* m)
 {
     GLint location = glGetUniformLocationARB (program, name);
@@ -215,20 +207,16 @@ bind_matrix_to_shader_arb (GLuint program, const char *name, cairo_matrix_t* m)
         0,     0,     1,     0,
         0,     0,     0,     1
     };
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniformMatrix4fvARB (location, 1, GL_TRUE, gl_m);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_texture_to_shader_arb (GLuint program, const char *name, GLuint tex_unit)
 {
     GLint location = glGetUniformLocationARB (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform1iARB (location, tex_unit);
-    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -321,53 +309,45 @@ destroy_program_core_2_0 (GLuint shader)
   glDeleteProgram (shader);
 }
 
-static cairo_status_t
+static void
 bind_float_to_shader_core_2_0 (GLuint program, const char *name,
                                float value)
 {
     GLint location = glGetUniformLocation (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform1f (location, value);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_vec2_to_shader_core_2_0 (GLuint program, const char *name,
                               float value0, float value1)
 {
     GLint location = glGetUniformLocation (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform2f (location, value0, value1);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_vec3_to_shader_core_2_0 (GLuint program, const char *name,
                               float value0, float value1,
                               float value2)
 {
     GLint location = glGetUniformLocation (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform3f (location, value0, value1, value2);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_vec4_to_shader_core_2_0 (GLuint program, const char *name,
                               float value0, float value1,
                               float value2, float value3)
 {
     GLint location = glGetUniformLocation (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform4f (location, value0, value1, value2, value3);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_matrix_to_shader_core_2_0 (GLuint program, const char *name, cairo_matrix_t* m)
 {
     GLint location = glGetUniformLocation (program, name);
@@ -377,20 +357,16 @@ bind_matrix_to_shader_core_2_0 (GLuint program, const char *name, cairo_matrix_t
         0,     0,     1,     0,
         0,     0,     0,     1
     };
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniformMatrix4fv (location, 1, GL_TRUE, gl_m);
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 bind_texture_to_shader_core_2_0 (GLuint program, const char *name, GLuint tex_unit)
 {
     GLint location = glGetUniformLocation (program, name);
-    if (location == -1)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (location != -1);
     glUniform1i (location, tex_unit);
-    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -826,52 +802,52 @@ create_shader_program (cairo_gl_context_t *ctx,
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
-cairo_status_t
+void
 bind_float_to_shader (cairo_gl_context_t *ctx,
                       GLuint program, const char *name,
                       float value)
 {
-    return ctx->shader_impl->bind_float_to_shader(program, name, value);
+    ctx->shader_impl->bind_float_to_shader(program, name, value);
 }
 
-cairo_status_t
+void
 bind_vec2_to_shader (cairo_gl_context_t *ctx,
                      GLuint program, const char *name,
                      float value0, float value1)
 {
-    return ctx->shader_impl->bind_vec2_to_shader(program, name, value0, value1);
+    ctx->shader_impl->bind_vec2_to_shader(program, name, value0, value1);
 }
 
-cairo_status_t
+void
 bind_vec3_to_shader (cairo_gl_context_t *ctx,
                      GLuint program, const char *name,
                      float value0, float value1,
                      float value2)
 {
-    return ctx->shader_impl->bind_vec3_to_shader(program, name, value0, value1, value2);
+    ctx->shader_impl->bind_vec3_to_shader(program, name, value0, value1, value2);
 }
 
-cairo_status_t
+void
 bind_vec4_to_shader (cairo_gl_context_t *ctx,
                      GLuint program, const char *name,
                      float value0, float value1,
                      float value2, float value3)
 {
-    return ctx->shader_impl->bind_vec4_to_shader(program, name, value0, value1, value2, value3);
+    ctx->shader_impl->bind_vec4_to_shader(program, name, value0, value1, value2, value3);
 }
 
-cairo_status_t
+void
 bind_matrix_to_shader (cairo_gl_context_t *ctx,
                        GLuint program, const char *name, cairo_matrix_t* m)
 {
-    return ctx->shader_impl->bind_matrix_to_shader(program, name, m);
+    ctx->shader_impl->bind_matrix_to_shader(program, name, m);
 }
 
-cairo_status_t
+void
 bind_texture_to_shader (cairo_gl_context_t *ctx,
                         GLuint program, const char *name, GLuint tex_unit)
 {
-    return ctx->shader_impl->bind_texture_to_shader(program, name, tex_unit);
+    ctx->shader_impl->bind_texture_to_shader(program, name, tex_unit);
 }
 
 void
@@ -952,14 +928,12 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
 
     _cairo_gl_use_program (ctx, &entry->program);
     if (source != CAIRO_GL_OPERAND_CONSTANT) {
-	status = bind_texture_to_shader (ctx, entry->program.program, "source_sampler", 0);
-	assert (!_cairo_status_is_error (status));
+	bind_texture_to_shader (ctx, entry->program.program, "source_sampler", 0);
     }
     if (mask != CAIRO_GL_OPERAND_CONSTANT &&
 	mask != CAIRO_GL_OPERAND_SPANS &&
 	mask != CAIRO_GL_OPERAND_NONE) {
-	status = bind_texture_to_shader (ctx, entry->program.program, "mask_sampler", 1);
-	assert (!_cairo_status_is_error (status));
+	bind_texture_to_shader (ctx, entry->program.program, "mask_sampler", 1);
     }
 
     status = _cairo_cache_insert (&ctx->shaders, &entry->base);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index eeeac59..154b925 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1200,14 +1200,13 @@ _cairo_gl_surface_fill_rectangles_glsl (void                  *abstract_surface,
     _cairo_gl_context_set_destination (ctx, surface);
     _cairo_gl_set_operator (surface, op, FALSE);
 
-    status = bind_vec4_to_shader (ctx,
-                                  ctx->fill_rectangles_shader.program,
-                                  "color",
-                                  color->red * color->alpha,
-                                  color->green * color->alpha,
-                                  color->blue * color->alpha,
-                                  color->alpha);
-    assert (! _cairo_status_is_error (status));
+    bind_vec4_to_shader (ctx,
+                         ctx->fill_rectangles_shader.program,
+                         "color",
+                         color->red * color->alpha,
+                         color->green * color->alpha,
+                         color->blue * color->alpha,
+                         color->alpha);
 
     for (i = 0; i < num_rects; i++) {
 	vertices[i * 8 + 0] = rects[i].x;
commit 0bb11e8f5bcdc8a6f8384197b39c2ad48eaab1cd
Author: Benjamin Otte <otte at redhat.com>
Date:   Mon May 17 00:49:01 2010 +0200

    gl: Use GL_TRIANGLES instead of GL_QUADS
    
    It seems to increase performance by 1-2% on average and up to 30% in
    some cases (on i965).

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index a9c7e25..a8ae084 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1158,19 +1158,19 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
     unsigned int count = setup->vb_offset / setup->vertex_size;
 
     if (! setup->pre_shader) {
-        glDrawArrays (GL_QUADS, 0, count);
+        glDrawArrays (GL_TRIANGLES, 0, count);
     } else {
         _cairo_gl_use_program (ctx, setup->pre_shader);
         _cairo_gl_set_operator (setup->dst, CAIRO_OPERATOR_DEST_OUT, TRUE);
         _cairo_gl_set_src_alpha_operand (ctx, setup);
         _cairo_gl_set_component_alpha_mask_operand (ctx, setup);
-        glDrawArrays (GL_QUADS, 0, count);
+        glDrawArrays (GL_TRIANGLES, 0, count);
 
         _cairo_gl_use_program (ctx, setup->shader);
         _cairo_gl_set_operator (setup->dst, setup->op, TRUE);
         _cairo_gl_set_src_operand (ctx, setup);
         _cairo_gl_set_component_alpha_mask_operand (ctx, setup);
-        glDrawArrays (GL_QUADS, 0, count);
+        glDrawArrays (GL_TRIANGLES, 0, count);
     }
 }
 
@@ -1284,10 +1284,13 @@ _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
                                GLfloat y2,
                                uint32_t color)
 {
-    _cairo_gl_composite_prepare_buffer (ctx, setup, 4);
+    _cairo_gl_composite_prepare_buffer (ctx, setup, 6);
 
     _cairo_gl_composite_emit_vertex (ctx, setup, x1, y1, color);
     _cairo_gl_composite_emit_vertex (ctx, setup, x2, y1, color);
+    _cairo_gl_composite_emit_vertex (ctx, setup, x1, y2, color);
+
+    _cairo_gl_composite_emit_vertex (ctx, setup, x2, y1, color);
     _cairo_gl_composite_emit_vertex (ctx, setup, x2, y2, color);
     _cairo_gl_composite_emit_vertex (ctx, setup, x1, y2, color);
 }
@@ -1325,10 +1328,13 @@ _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
                                 GLfloat glyph_x2,
                                 GLfloat glyph_y2)
 {
-    _cairo_gl_composite_prepare_buffer (ctx, setup, 4);
+    _cairo_gl_composite_prepare_buffer (ctx, setup, 6);
 
     _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x1, y1, glyph_x1, glyph_y1);
     _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x2, y1, glyph_x2, glyph_y1);
+    _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x1, y2, glyph_x1, glyph_y2);
+
+    _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x2, y1, glyph_x2, glyph_y1);
     _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x2, y2, glyph_x2, glyph_y2);
     _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x1, y2, glyph_x1, glyph_y2);
 }
commit 2b771da47a87f86f378314bfe8033874d9444914
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 23:58:47 2010 +0200

    xlib: ensure variable isn't uninitialized

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 3b01fde..ebc45b2 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1067,6 +1067,8 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
         ret = _pixman_format_from_masks (&image_masks, &intermediate_format);
         assert (ret);
 
+	own_data = FALSE;
+
         pixman_image = pixman_image_create_bits (intermediate_format,
                                                  image->width,
                                                  image->height,
@@ -1089,7 +1091,6 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 	ximage.bits_per_pixel = image_masks.bpp;
 	ximage.data = (char *) pixman_image_get_data (pixman_image);
 	ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
-	own_data = FALSE;
 
 	ret = XInitImage (&ximage);
 	assert (ret != 0);
@@ -1135,6 +1136,7 @@ _draw_image_surface (cairo_xlib_surface_t   *surface,
 	ximage.bytes_per_line = stride;
 	ximage.data = _cairo_malloc_ab (stride, ximage.height);
 	if (unlikely (ximage.data == NULL)) {
+            own_data = FALSE;
 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
             goto BAIL;
         }
commit b768a33a602942825e5ec651ae7bafd6d5fc33ac
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 21:10:45 2010 +0200

    gl: Set composite->has_component_alpha based on mask
    
    Previously it was set when initing the composite structure, but that
    doesn't allow resetting it when a new mask is used.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index eae83b2..a9c7e25 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -507,6 +507,7 @@ _cairo_gl_composite_set_mask (cairo_gl_context_t *ctx,
                               int width, int height)
 {
     _cairo_gl_operand_destroy (&setup->mask);
+    setup->has_component_alpha = pattern && pattern->has_component_alpha;
     return _cairo_gl_operand_init (ctx, &setup->mask, pattern,
                                    setup->dst,
                                    src_x, src_y,
@@ -520,6 +521,7 @@ _cairo_gl_composite_set_mask_spans (cairo_gl_context_t *ctx,
 {
     _cairo_gl_operand_destroy (&setup->mask);
     setup->mask.type = CAIRO_GL_OPERAND_SPANS;
+    setup->has_component_alpha = FALSE;
 }
 
 void
@@ -1379,12 +1381,12 @@ _cairo_gl_composite_init (cairo_gl_context_t *ctx,
                           cairo_gl_surface_t *dst,
                           const cairo_pattern_t *src,
                           const cairo_pattern_t *mask,
-                          cairo_bool_t has_component_alpha,
+                          cairo_bool_t assume_component_alpha,
                           const cairo_rectangle_int_t *rect)
 {
     memset (setup, 0, sizeof (cairo_gl_composite_t));
 
-    if (has_component_alpha) {
+    if (assume_component_alpha) {
         if (op != CAIRO_OPERATOR_CLEAR &&
             op != CAIRO_OPERATOR_OVER &&
             op != CAIRO_OPERATOR_ADD)
@@ -1395,7 +1397,6 @@ _cairo_gl_composite_init (cairo_gl_context_t *ctx,
     }
 
     setup->dst = dst;
-    setup->has_component_alpha = has_component_alpha;
     setup->op = op;
 
     return CAIRO_STATUS_SUCCESS;
commit 1cde4601df8a3689450e2a0e15888c53aff12983
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 21:05:16 2010 +0200

    gl: Replace _cairo_gl_operand_init() with setters for src/mask
    
    Now cairo_gl_operand_t is no longer exposed outside of
    cairo-gl-composite.c

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 99c60bf..eae83b2 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -447,7 +447,7 @@ _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
     operand->type = CAIRO_GL_OPERAND_NONE;
 }
 
-cairo_int_status_t
+static cairo_int_status_t
 _cairo_gl_operand_init (cairo_gl_context_t *ctx,
                         cairo_gl_operand_t *operand,
 		        const cairo_pattern_t *pattern,
@@ -482,6 +482,38 @@ _cairo_gl_operand_init (cairo_gl_context_t *ctx,
     }
 }
 
+cairo_int_status_t
+_cairo_gl_composite_set_source (cairo_gl_context_t *ctx,
+                                cairo_gl_composite_t *setup,
+			        const cairo_pattern_t *pattern,
+                                int src_x, int src_y,
+                                int dst_x, int dst_y,
+                                int width, int height)
+{
+    _cairo_gl_operand_destroy (&setup->src);
+    return _cairo_gl_operand_init (ctx, &setup->src, pattern,
+                                   setup->dst,
+                                   src_x, src_y,
+                                   dst_x, dst_y,
+                                   width, height);
+}
+
+cairo_int_status_t
+_cairo_gl_composite_set_mask (cairo_gl_context_t *ctx,
+                              cairo_gl_composite_t *setup,
+			      const cairo_pattern_t *pattern,
+                              int src_x, int src_y,
+                              int dst_x, int dst_y,
+                              int width, int height)
+{
+    _cairo_gl_operand_destroy (&setup->mask);
+    return _cairo_gl_operand_init (ctx, &setup->mask, pattern,
+                                   setup->dst,
+                                   src_x, src_y,
+                                   dst_x, dst_y,
+                                   width, height);
+}
+
 void
 _cairo_gl_composite_set_mask_spans (cairo_gl_context_t *ctx,
                                     cairo_gl_composite_t *setup)
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index e4c819b..d0aae23 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -293,11 +293,11 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	goto FINISH;
     }
 
-    status = _cairo_gl_operand_init (ctx, &setup.src, source, dst,
-				     glyph_extents->x, glyph_extents->y,
-				     dst_x, dst_y,
-				     glyph_extents->width,
-				     glyph_extents->height);
+    status = _cairo_gl_composite_set_source (ctx, &setup, source,
+                                             glyph_extents->x, glyph_extents->y,
+                                             dst_x, dst_y,
+                                             glyph_extents->width,
+                                             glyph_extents->height);
     if (unlikely (status))
 	goto FINISH;
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 65ef22a..3f53220 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -230,15 +230,6 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 			      int width, int height,
 			      int dst_x, int dst_y);
 
-cairo_private cairo_int_status_t
-_cairo_gl_operand_init (cairo_gl_context_t *ctx,
-                        cairo_gl_operand_t *operand,
-			const cairo_pattern_t *pattern,
-			cairo_gl_surface_t *dst,
-			int src_x, int src_y,
-			int dst_x, int dst_y,
-			int width, int height);
-
 static cairo_always_inline cairo_bool_t
 _cairo_gl_device_has_glsl (cairo_device_t *device)
 {
@@ -296,6 +287,22 @@ _cairo_gl_composite_set_clip_region (cairo_gl_context_t *ctx,
                                      cairo_gl_composite_t *setup,
                                      cairo_region_t *clip_region);
 
+cairo_private cairo_int_status_t
+_cairo_gl_composite_set_source (cairo_gl_context_t *ctx,
+                                cairo_gl_composite_t *setup,
+			        const cairo_pattern_t *pattern,
+                                int src_x, int src_y,
+                                int dst_x, int dst_y,
+                                int width, int height);
+
+cairo_private cairo_int_status_t
+_cairo_gl_composite_set_mask (cairo_gl_context_t *ctx,
+                              cairo_gl_composite_t *setup,
+			      const cairo_pattern_t *pattern,
+                              int src_x, int src_y,
+                              int dst_x, int dst_y,
+                              int width, int height);
+
 cairo_private void
 _cairo_gl_composite_set_mask_spans (cairo_gl_context_t *ctx,
                                     cairo_gl_composite_t *setup);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index ee319db..eeeac59 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -956,18 +956,18 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     if (unlikely (status))
         goto CLEANUP;
 
-    status = _cairo_gl_operand_init (ctx, &setup.src, src, dst,
-				     src_x, src_y,
-				     dst_x, dst_y,
-				     width, height);
+    status = _cairo_gl_composite_set_source (ctx, &setup, src,
+                                             src_x, src_y,
+                                             dst_x, dst_y,
+                                             width, height);
     if (unlikely (status))
         goto CLEANUP;
 
     if (mask != NULL) {
-	status = _cairo_gl_operand_init (ctx, &setup.mask, mask, dst,
-					 mask_x, mask_y,
-					 dst_x, dst_y,
-					 width, height);
+	status = _cairo_gl_composite_set_mask (ctx, &setup, mask,
+                                               mask_x, mask_y,
+                                               dst_x, dst_y,
+                                               width, height);
 	if (unlikely (status))
             goto CLEANUP;
     }
@@ -1426,11 +1426,11 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     if (unlikely (status))
         goto FAIL;
 
-    status = _cairo_gl_operand_init (renderer->ctx,
-                                     &renderer->setup.src, src, dst,
-				     rects->source.x, rects->source.y,
-				     extents->x, extents->y,
-				     extents->width, extents->height);
+    status = _cairo_gl_composite_set_source (renderer->ctx,
+                                             &renderer->setup, src,
+                                             rects->source.x, rects->source.y,
+                                             extents->x, extents->y,
+                                             extents->width, extents->height);
     if (unlikely (status))
         goto FAIL;
 
commit 6575cb7a95e109ab39eda58603ed6a76581a41b0
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 20:39:00 2010 +0200

    gl: Convert glyphs path to use cairo_gl_composite_t

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index fccb989..99c60bf 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -415,6 +415,38 @@ _cairo_gl_gradient_operand_init (cairo_gl_context_t *ctx,
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
+static void
+_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
+{
+    switch (operand->type) {
+    case CAIRO_GL_OPERAND_CONSTANT:
+	break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+	glDeleteTextures (1, &operand->operand.linear.tex);
+	break;
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+	glDeleteTextures (1, &operand->operand.radial.tex);
+	break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+	if (operand->operand.texture.surface != NULL) {
+	    cairo_gl_surface_t *surface = operand->operand.texture.surface;
+
+	    _cairo_pattern_release_surface (operand->pattern,
+					    &surface->base,
+					    &operand->operand.texture.attributes);
+	}
+	break;
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+        break;
+    }
+
+    operand->type = CAIRO_GL_OPERAND_NONE;
+}
+
 cairo_int_status_t
 _cairo_gl_operand_init (cairo_gl_context_t *ctx,
                         cairo_gl_operand_t *operand,
@@ -454,10 +486,27 @@ void
 _cairo_gl_composite_set_mask_spans (cairo_gl_context_t *ctx,
                                     cairo_gl_composite_t *setup)
 {
+    _cairo_gl_operand_destroy (&setup->mask);
     setup->mask.type = CAIRO_GL_OPERAND_SPANS;
 }
 
 void
+_cairo_gl_composite_set_mask_texture (cairo_gl_context_t *ctx,
+                                      cairo_gl_composite_t *setup,
+                                      GLuint tex,
+                                      cairo_bool_t has_component_alpha)
+{
+    _cairo_gl_operand_destroy (&setup->mask);
+
+    setup->has_component_alpha = has_component_alpha;
+
+    setup->mask.type = CAIRO_GL_OPERAND_TEXTURE;
+    setup->mask.operand.texture.tex = tex;
+    setup->mask.operand.texture.surface = NULL;
+    cairo_matrix_init_identity (&setup->mask.operand.texture.attributes.matrix);
+}
+
+void
 _cairo_gl_composite_set_clip_region (cairo_gl_context_t *ctx,
                                      cairo_gl_composite_t *setup,
                                      cairo_region_t *clip_region)
@@ -466,36 +515,6 @@ _cairo_gl_composite_set_clip_region (cairo_gl_context_t *ctx,
 }
 
 static void
-_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
-{
-    switch (operand->type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-	break;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-	glDeleteTextures (1, &operand->operand.linear.tex);
-	break;
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
-	glDeleteTextures (1, &operand->operand.radial.tex);
-	break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-	if (operand->operand.texture.surface != NULL) {
-	    cairo_gl_surface_t *surface = operand->operand.texture.surface;
-
-	    _cairo_pattern_release_surface (operand->pattern,
-					    &surface->base,
-					    &operand->operand.texture.attributes);
-	}
-	break;
-    default:
-    case CAIRO_GL_OPERAND_COUNT:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_SPANS:
-        break;
-    }
-}
-
-static void
 _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx,
 					  cairo_gl_composite_t *setup,
 					  int tex_unit,
@@ -1121,7 +1140,7 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
     }
 }
 
-static inline void
+void
 _cairo_gl_composite_flush (cairo_gl_context_t *ctx,
                            cairo_gl_composite_t *setup)
 {
@@ -1239,6 +1258,47 @@ _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
     _cairo_gl_composite_emit_vertex (ctx, setup, x1, y2, color);
 }
 
+static inline void
+_cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
+                                       cairo_gl_composite_t *setup,
+                                       GLfloat x,
+                                       GLfloat y,
+                                       GLfloat glyph_x,
+                                       GLfloat glyph_y)
+{
+    GLfloat *vb = (GLfloat *) (void *) &setup->vb[setup->vb_offset];
+
+    *vb++ = x;
+    *vb++ = y;
+
+    _cairo_gl_operand_emit (&setup->src, &vb, x, y, 0);
+
+    *vb++ = glyph_x;
+    *vb++ = glyph_y;
+
+    setup->vb_offset += setup->vertex_size;
+}
+
+void
+_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
+                                cairo_gl_composite_t *setup,
+                                GLfloat x1,
+                                GLfloat y1,
+                                GLfloat x2,
+                                GLfloat y2,
+                                GLfloat glyph_x1,
+                                GLfloat glyph_y1,
+                                GLfloat glyph_x2,
+                                GLfloat glyph_y2)
+{
+    _cairo_gl_composite_prepare_buffer (ctx, setup, 4);
+
+    _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x1, y1, glyph_x1, glyph_y1);
+    _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x2, y1, glyph_x2, glyph_y1);
+    _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x2, y2, glyph_x2, glyph_y2);
+    _cairo_gl_composite_emit_glyph_vertex (ctx, setup, x1, y2, glyph_x1, glyph_y2);
+}
+
 void
 _cairo_gl_composite_end (cairo_gl_context_t *ctx,
                          cairo_gl_composite_t *setup)
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 23ac40e..e4c819b 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -106,6 +106,9 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
     if (status)
 	return status;
 
+    glActiveTexture (GL_TEXTURE1);
+    glBindTexture (ctx->tex_target, cache->tex);
+
     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
     glPixelStorei (GL_UNPACK_ROW_LENGTH,
 		   glyph_surface->stride /
@@ -250,211 +253,6 @@ _cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
     }
 }
 
-typedef struct _cairo_gl_glyphs_setup
-{
-    unsigned int vbo_size; /* units of floats */
-    unsigned int vb_offset; /* units of floats */
-    unsigned int vertex_size; /* units of floats */
-    unsigned int num_prims;
-    float *vb;
-    cairo_gl_composite_t *composite;
-    cairo_region_t *clip;
-    cairo_gl_surface_t *dst;
-    cairo_operator_t op;
-    cairo_bool_t component_alpha;
-    cairo_gl_shader_in_t in;
-} cairo_gl_glyphs_setup_t;
-
-static void
-_cairo_gl_glyphs_set_shader_fixed (cairo_gl_context_t *ctx,
-				   cairo_gl_glyphs_setup_t *setup,
-				   cairo_gl_shader_in_t in)
-{
-    if (setup->in == in)
-	return;
-
-    setup->in = in;
-
-    if (in != CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA)
-	_cairo_gl_set_src_operand (ctx, setup->composite);
-    else
-	_cairo_gl_set_src_alpha_operand (ctx, setup->composite);
-
-    /* Set up the IN operator for source IN mask.
-     *
-     * IN (normal, any op): dst.argb = src.argb * mask.aaaa
-     * IN (component, ADD): dst.argb = src.argb * mask.argb
-     *
-     * The mask channel selection for component alpha ADD will be updated in
-     * the loop over glyphs below.
-     */
-    glActiveTexture (GL_TEXTURE1);
-    glEnable (ctx->tex_target);
-    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
-    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
-
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
-    if (in == CAIRO_GL_SHADER_IN_NORMAL)
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
-    else
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
-}
-
-static void
-_cairo_gl_glyphs_set_shader (cairo_gl_context_t *ctx,
-			     cairo_gl_glyphs_setup_t *setup,
-			     cairo_gl_shader_in_t in)
-{
-    if (setup->in == in)
-	return;
-
-    if (_cairo_gl_device_has_glsl (&ctx->base)) {
-	cairo_status_t status;
-
-	status = _cairo_gl_get_program (ctx,
-					setup->composite->src.type,
-					CAIRO_GL_OPERAND_TEXTURE,
-					in,
-					&setup->composite->shader);
-	if (!_cairo_status_is_error (status)) {
-	    setup->in = in;
-	    _cairo_gl_use_program (ctx, setup->composite->shader);
-	    _cairo_gl_set_src_operand (ctx, setup->composite);
-	    return;
-	}
-    }
-
-    _cairo_gl_glyphs_set_shader_fixed (ctx, setup, in);
-}
-
-static void
-_cairo_gl_glyphs_draw (cairo_gl_context_t *ctx,
-		       cairo_gl_glyphs_setup_t *setup)
-{
-    if (!setup->component_alpha || setup->op != CAIRO_OPERATOR_OVER) {
-	glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
-    } else {
-	_cairo_gl_set_operator (setup->dst, CAIRO_OPERATOR_DEST_OUT, TRUE);
-	_cairo_gl_glyphs_set_shader(ctx, setup,
-				    CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA);
-	glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
-
-	_cairo_gl_set_operator (setup->dst, CAIRO_OPERATOR_ADD, TRUE);
-	_cairo_gl_glyphs_set_shader(ctx, setup,
-				    CAIRO_GL_SHADER_IN_CA_SOURCE);
-	glDrawArrays (GL_QUADS, 0, 4 * setup->num_prims);
-    }
-}
-
-static void
-_cairo_gl_flush_glyphs (cairo_gl_context_t *ctx,
-			cairo_gl_glyphs_setup_t *setup)
-{
-    int i;
-
-    if (setup->vb == NULL)
-	return;
-
-    glUnmapBufferARB (GL_ARRAY_BUFFER_ARB);
-    setup->vb = NULL;
-
-    if (setup->num_prims == 0)
-	return;
-
-    if (!setup->component_alpha) {
-	_cairo_gl_set_operator (setup->dst, setup->op, FALSE);
-	_cairo_gl_glyphs_set_shader(ctx, setup, CAIRO_GL_SHADER_IN_NORMAL);
-    } else if (setup->op == CAIRO_OPERATOR_ADD) {
-	_cairo_gl_set_operator (setup->dst, setup->op, FALSE);
-	_cairo_gl_glyphs_set_shader(ctx, setup, CAIRO_GL_SHADER_IN_CA_SOURCE);
-    }
-
-    if (setup->clip) {
-	int num_rectangles = cairo_region_num_rectangles (setup->clip);
-
-	glEnable (GL_SCISSOR_TEST);
-	for (i = 0; i < num_rectangles; i++) {
-	    cairo_rectangle_int_t rect;
-
-	    cairo_region_get_rectangle (setup->clip, i, &rect);
-
-	    glScissor (rect.x,
-		       _cairo_gl_y_flip (setup->dst, rect.y),
-		       rect.x + rect.width,
-		       _cairo_gl_y_flip (setup->dst,
-					 rect.y + rect.height));
-	    _cairo_gl_glyphs_draw (ctx, setup);
-	}
-	glDisable (GL_SCISSOR_TEST);
-    } else {
-	_cairo_gl_glyphs_draw (ctx, setup);
-    }
-    setup->num_prims = 0;
-}
-
-static void
-_cairo_gl_glyphs_emit_vertex (cairo_gl_glyphs_setup_t *setup,
-			      int x, int y, float glyph_x, float glyph_y)
-{
-    int i = 0;
-    float *vb = &setup->vb[setup->vb_offset];
-    cairo_surface_attributes_t *src_attributes;
-
-    src_attributes = &setup->composite->src.operand.texture.attributes;
-
-    vb[i++] = x;
-    vb[i++] = y;
-
-    vb[i++] = glyph_x;
-    vb[i++] = glyph_y;
-
-    if (setup->composite->src.type == CAIRO_GL_OPERAND_TEXTURE) {
-	double s = x;
-	double t = y;
-	cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
-	vb[i++] = s;
-	vb[i++] = t;
-    }
-
-    setup->vb_offset += setup->vertex_size;
-}
-
-
-static void
-_cairo_gl_emit_glyph_rectangle (cairo_gl_context_t *ctx,
-				cairo_gl_glyphs_setup_t *setup,
-				int x1, int y1,
-				int x2, int y2,
-				cairo_gl_glyph_private_t *glyph)
-{
-    if (setup->vb != NULL &&
-	setup->vb_offset + 4 * setup->vertex_size > setup->vbo_size) {
-	_cairo_gl_flush_glyphs (ctx, setup);
-    }
-
-    if (setup->vb == NULL) {
-	glBufferDataARB (GL_ARRAY_BUFFER_ARB,
-			 setup->vbo_size * sizeof (GLfloat),
-			 NULL, GL_STREAM_DRAW_ARB);
-	setup->vb = glMapBufferARB (GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
-	setup->vb_offset = 0;
-    }
-
-    _cairo_gl_glyphs_emit_vertex (setup, x1, y1, glyph->p1.x, glyph->p1.y);
-    _cairo_gl_glyphs_emit_vertex (setup, x2, y1, glyph->p2.x, glyph->p1.y);
-    _cairo_gl_glyphs_emit_vertex (setup, x2, y2, glyph->p2.x, glyph->p2.y);
-    _cairo_gl_glyphs_emit_vertex (setup, x1, y2, glyph->p1.x, glyph->p2.y);
-    setup->num_prims++;
-}
-
 static cairo_status_t
 _render_glyphs (cairo_gl_surface_t	*dst,
 	        int dst_x, int dst_y,
@@ -468,11 +266,10 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 		cairo_region_t		*clip_region,
 		int			*remaining_glyphs)
 {
-    cairo_format_t last_format = (cairo_format_t) -1;
+    cairo_format_t last_format = CAIRO_FORMAT_INVALID;
     cairo_gl_glyph_cache_t *cache = NULL;
     cairo_gl_context_t *ctx;
-    cairo_gl_glyphs_setup_t setup;
-    cairo_gl_composite_t composite_setup;
+    cairo_gl_composite_t setup;
     cairo_status_t status;
     int i = 0;
 
@@ -482,28 +279,27 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_gl_composite_init (ctx, &composite_setup,
+    _cairo_scaled_font_freeze_cache (scaled_font);
+
+    status = _cairo_gl_composite_init (ctx, &setup,
                                        op, dst, source, NULL,
-                                       FALSE, glyph_extents);
+                                       TRUE, glyph_extents);
 
     if (unlikely (status))
-	goto CLEANUP_FONT;
+	goto FINISH;
 
-    status = _cairo_gl_operand_init (ctx, &composite_setup.src, source, dst,
+    if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	goto FINISH;
+    }
+
+    status = _cairo_gl_operand_init (ctx, &setup.src, source, dst,
 				     glyph_extents->x, glyph_extents->y,
 				     dst_x, dst_y,
 				     glyph_extents->width,
 				     glyph_extents->height);
     if (unlikely (status))
-	goto CLEANUP_FONT;
-
-    _cairo_gl_context_set_destination (ctx, dst);
-
-    _cairo_scaled_font_freeze_cache (scaled_font);
-    if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
-	goto CLEANUP_FONT;
-    }
+	goto FINISH;
 
     if (scaled_font->surface_private == NULL) {
 	scaled_font->surface_private = ctx;
@@ -511,43 +307,11 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	cairo_list_add (&scaled_font->link, &ctx->fonts);
     }
 
-    /* Create our VBO so that we can accumulate a bunch of glyph primitives
-     * into one giant DrawArrays.
-     */
-    memset(&setup, 0, sizeof(setup));
-    setup.composite = &composite_setup;
-    setup.clip = clip_region;
-    setup.dst = dst;
-    setup.vertex_size = 4;
-    if (composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE)
-	setup.vertex_size += 2;
-    setup.vbo_size = num_glyphs * 4 * setup.vertex_size;
-    if (setup.vbo_size > 4096)
-	setup.vbo_size = 4096;
-    setup.op = op;
-    setup.in = CAIRO_GL_SHADER_IN_COUNT; /* unset */
-
-    glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
-
-    glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
-		     (void *)(uintptr_t)(0));
-    glEnableClientState (GL_VERTEX_ARRAY);
-    if (composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
-	/* Note that we're packing texcoord 0 after texcoord 1, for
-	 * convenience.
-	 */
-	glClientActiveTexture (GL_TEXTURE0);
-	glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
-			   (void *)(uintptr_t)(4 * sizeof (GLfloat)));
-	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
-    }
-    glClientActiveTexture (GL_TEXTURE1);
-    glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
-		       (void *)(uintptr_t)(2 * sizeof (GLfloat)));
-    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+    _cairo_gl_composite_set_clip_region (ctx, &setup, clip_region);
 
     for (i = 0; i < num_glyphs; i++) {
 	cairo_scaled_glyph_t *scaled_glyph;
+	cairo_gl_glyph_private_t *glyph;
 	double x_offset, y_offset;
 	double x1, x2, y1, y2;
 
@@ -571,26 +335,23 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	}
 
 	if (scaled_glyph->surface->format != last_format) {
-	    /* Switching textures, so flush any queued prims. */
-	    _cairo_gl_flush_glyphs (ctx, &setup);
+            if (last_format != CAIRO_FORMAT_INVALID)
+                _cairo_gl_composite_end (ctx, &setup);
 
-	    glActiveTexture (GL_TEXTURE1);
 	    cache = cairo_gl_context_get_glyph_cache (ctx,
 						      scaled_glyph->surface->format);
 
-	    glBindTexture (ctx->tex_target, cache->tex);
-
 	    last_format = scaled_glyph->surface->format;
-	    /* If we're doing component alpha in this function, it should
-	     * only be in the case of CAIRO_OPERATOR_ADD.  In that case, we just
-	     * need to make sure we send the rgb bits down to the destination.
-	     */
-	    if (last_format == CAIRO_FORMAT_ARGB32) {
+
+            _cairo_gl_composite_set_mask_texture (ctx,
+                                                  &setup,
+                                                  cache->tex, 
+                                                  last_format == CAIRO_FORMAT_ARGB32);
+
+	    if (last_format == CAIRO_FORMAT_ARGB32)
 		*has_component_alpha = TRUE;
-		setup.component_alpha = TRUE;
-	    } else {
-		setup.component_alpha = FALSE;
-	    }
+
+            status = _cairo_gl_composite_begin (ctx, &setup);
 	}
 
 	if (scaled_glyph->surface_private == NULL) {
@@ -598,7 +359,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
 	    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
 		/* Cache is full, so flush existing prims and try again. */
-		_cairo_gl_flush_glyphs (ctx, &setup);
+                _cairo_gl_composite_flush (ctx, &setup);
 		_cairo_gl_glyph_cache_unlock (cache);
 		status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
 	    }
@@ -615,37 +376,19 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	x2 = x1 + scaled_glyph->surface->width;
 	y2 = y1 + scaled_glyph->surface->height;
 
-	_cairo_gl_emit_glyph_rectangle (ctx, &setup,
+	glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
+	_cairo_gl_composite_emit_glyph (ctx, &setup,
 					x1, y1, x2, y2,
-					_cairo_gl_glyph_cache_lock (cache, scaled_glyph));
+                                        glyph->p1.x, glyph->p1.y,
+                                        glyph->p2.x, glyph->p2.y);
     }
 
     status = CAIRO_STATUS_SUCCESS;
   FINISH:
-    _cairo_gl_flush_glyphs (ctx, &setup);
-  CLEANUP_FONT:
+    _cairo_gl_composite_end (ctx, &setup);
     _cairo_scaled_font_thaw_cache (scaled_font);
 
-    glDisable (GL_BLEND);
-    glDisable (GL_SCISSOR_TEST);
-
-    glDisableClientState (GL_VERTEX_ARRAY);
-
-    glClientActiveTexture (GL_TEXTURE0);
-    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-    glActiveTexture (GL_TEXTURE0);
-    glDisable (GL_TEXTURE_1D);
-    glDisable (ctx->tex_target);
-
-    glClientActiveTexture (GL_TEXTURE1);
-    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-    glActiveTexture (GL_TEXTURE1);
-    glDisable (ctx->tex_target);
-    _cairo_gl_use_program (ctx, NULL);
-
-    glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
-
-    _cairo_gl_composite_fini (ctx, &composite_setup);
+    _cairo_gl_composite_fini (ctx, &setup);
 
     _cairo_gl_context_release (ctx);
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index c24dd6f..65ef22a 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -300,6 +300,12 @@ cairo_private void
 _cairo_gl_composite_set_mask_spans (cairo_gl_context_t *ctx,
                                     cairo_gl_composite_t *setup);
 
+cairo_private void
+_cairo_gl_composite_set_mask_texture (cairo_gl_context_t *ctx,
+                                      cairo_gl_composite_t *setup,
+                                      GLuint tex,
+                                      cairo_bool_t has_component_alpha);
+
 cairo_private cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
                            cairo_gl_composite_t *setup);
@@ -314,6 +320,22 @@ _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
                                uint32_t color);
 
 cairo_private void
+_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
+                                cairo_gl_composite_t *setup,
+                                GLfloat x1,
+                                GLfloat y1,
+                                GLfloat x2,
+                                GLfloat y2,
+                                GLfloat glyph_x1,
+                                GLfloat glyph_y1,
+                                GLfloat glyph_x2,
+                                GLfloat glyph_y2);
+
+cairo_private void
+_cairo_gl_composite_flush (cairo_gl_context_t *ctx,
+                           cairo_gl_composite_t *setup);
+
+cairo_private void
 _cairo_gl_composite_end (cairo_gl_context_t *ctx,
                          cairo_gl_composite_t *setup);
 
commit 8937f2b4b5e4bcb8ada1e478df6a7329c0b80a5a
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 13:19:48 2010 +0200

    gl: Require ARB_vertex_buffer_object extension unconditionally
    
    <anholt> we shouldn't bother with non-vbo support. there's no
    justification for a driver not supporting it.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index a93267c..fccb989 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1292,7 +1292,6 @@ _cairo_gl_composite_init (cairo_gl_context_t *ctx,
 {
     memset (setup, 0, sizeof (cairo_gl_composite_t));
 
-    
     if (has_component_alpha) {
         if (op != CAIRO_OPERATOR_CLEAR &&
             op != CAIRO_OPERATOR_OVER &&
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 2bfeb51..99dfa18 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -134,6 +134,9 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 	    fprintf (stderr, "    GL_EXT_framebuffer_object\n");
 	if (! GLEW_ARB_texture_env_combine)
 	    fprintf (stderr, "    GL_ARB_texture_env_combine\n");
+        if (! GLEW_ARB_vertex_buffer_object)
+	    fprintf (stderr, "    GL_ARB_vertex_buffer_object\n");
+
 	/* EXT_bgra is used in two places:
 	 * - draw_image to upload common pixman formats without hand-swizzling.
 	 * - get_image to download common pixman formats without hand-swizzling.
@@ -156,8 +159,6 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     else
 	ctx->tex_target = GL_TEXTURE_2D;
 
-    ctx->has_span_renderer = GLEW_ARB_vertex_buffer_object;
-
     _cairo_gl_context_init_shaders (ctx);
 
     init_shader_program (&ctx->fill_rectangles_shader);
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 76ac5aa..23ac40e 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -740,9 +740,6 @@ _cairo_gl_surface_show_glyphs (void			*abstract_dst,
     cairo_status_t status;
     int i;
 
-    if (! GLEW_ARB_vertex_buffer_object)
-	return UNSUPPORTED ("requires ARB_vertex_buffer_object");
-
     if (! _cairo_gl_operator_is_supported (op))
 	return UNSUPPORTED ("unsupported operator");
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index aad11a0..c24dd6f 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -132,7 +132,6 @@ typedef struct _cairo_gl_context {
     GLint max_framebuffer_size;
     GLint max_texture_size;
     GLenum tex_target;
-    cairo_bool_t has_span_renderer;
 
     const cairo_gl_shader_impl_t *shader_impl;
 
@@ -246,12 +245,6 @@ _cairo_gl_device_has_glsl (cairo_device_t *device)
     return ((cairo_gl_context_t *) device)->shader_impl != NULL;
 }
 
-static cairo_always_inline cairo_bool_t
-cairo_gl_device_check_span_renderer (cairo_device_t *device)
-{
-  return ((cairo_gl_context_t *) device)->has_span_renderer;
-}
-
 static cairo_always_inline cairo_status_t cairo_warn
 _cairo_gl_context_acquire (cairo_device_t *device,
 			   cairo_gl_context_t **ctx)
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index e898120..ee319db 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1369,22 +1369,18 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
 }
 
 static cairo_bool_t
-_cairo_gl_surface_check_span_renderer (cairo_operator_t	  op,
+_cairo_gl_surface_check_span_renderer (cairo_operator_t	       op,
 				       const cairo_pattern_t  *pattern,
-				       void			 *abstract_dst,
-				       cairo_antialias_t	  antialias)
+				       void		      *abstract_dst,
+				       cairo_antialias_t       antialias)
 {
-    cairo_surface_t *surface = abstract_dst;
-
     if (! _cairo_gl_operator_is_supported (op))
 	return FALSE;
 
-    if (! cairo_gl_device_check_span_renderer (surface->device))
-	return FALSE;
-
     return TRUE;
 
     (void) pattern;
+    (void) abstract_dst;
     (void) antialias;
 }
 
commit 29dfd5b488e16ec8be879b2415635df93b874afc
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 03:36:05 2010 +0200

    gl: Remove unused variables

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 4e6976b..e898120 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -939,8 +939,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 			     unsigned int		  height,
 			     cairo_region_t		 *clip_region)
 {
-    cairo_gl_surface_t	*dst = abstract_dst;
-    cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL;
+    cairo_gl_surface_t *dst = abstract_dst;
     cairo_gl_context_t *ctx;
     cairo_status_t status;
     cairo_gl_composite_t setup;
@@ -964,8 +963,6 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     if (unlikely (status))
         goto CLEANUP;
 
-    src_attributes = &setup.src.operand.texture.attributes;
-
     if (mask != NULL) {
 	status = _cairo_gl_operand_init (ctx, &setup.mask, mask, dst,
 					 mask_x, mask_y,
@@ -973,8 +970,6 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 					 width, height);
 	if (unlikely (status))
             goto CLEANUP;
-
-	mask_attributes = &setup.mask.operand.texture.attributes;
     }
 
     status = _cairo_gl_composite_begin (ctx, &setup);
commit 4144488f516214b675d25d48add8cbd83fd17025
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 03:29:04 2010 +0200

    gl: Convert span renderer to use cairo_gl_composite_begin/end()
    
    Adds two new APIs to the composite API:
    - _cairo_gl_composite_set_mask_spans()
      Tells the composite renderer to use the color values for spans.
    - _cairo_gl_composite_set_clip_region()
      Tells the composite renderer to use GL_SCISSORS_TEST to clip when
      drawing. This function is very unperformant, so if it can be avoided,
      it probably shouldn't be used.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index c32c89b..a93267c 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -450,6 +450,21 @@ _cairo_gl_operand_init (cairo_gl_context_t *ctx,
     }
 }
 
+void
+_cairo_gl_composite_set_mask_spans (cairo_gl_context_t *ctx,
+                                    cairo_gl_composite_t *setup)
+{
+    setup->mask.type = CAIRO_GL_OPERAND_SPANS;
+}
+
+void
+_cairo_gl_composite_set_clip_region (cairo_gl_context_t *ctx,
+                                     cairo_gl_composite_t *setup,
+                                     cairo_region_t *clip_region)
+{
+    setup->clip_region = clip_region;
+}
+
 static void
 _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
 {
@@ -864,6 +879,27 @@ _cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
     case CAIRO_GL_OPERAND_NONE:
         break;
     case CAIRO_GL_OPERAND_SPANS:
+        if (! setup->shader) {
+            /* Set up the mask to source from the incoming vertex color. */
+            glActiveTexture (GL_TEXTURE1);
+            /* Have to have a dummy texture bound in order to use the combiner unit. */
+            glBindTexture (ctx->tex_target, ctx->dummy_tex);
+            glEnable (ctx->tex_target);
+            glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+            glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+            glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PRIMARY_COLOR);
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+        }
+        break;
     case CAIRO_GL_OPERAND_COUNT:
     default:
         ASSERT_NOT_REACHED;
@@ -1050,8 +1086,15 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
 	glTexCoordPointer (2, GL_FLOAT, setup->vertex_size,
                            (void *) (uintptr_t) (dst_size + src_size));
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+    } else if (setup->mask.type == CAIRO_GL_OPERAND_SPANS) {
+	glColorPointer (4, GL_UNSIGNED_BYTE, setup->vertex_size,
+                        (void *) (uintptr_t) (dst_size + src_size));
+	glEnableClientState (GL_COLOR_ARRAY);
     }
 
+    if (setup->clip_region)
+	glEnable (GL_SCISSOR_TEST);
+
     return status;
 }
 
@@ -1085,7 +1128,20 @@ _cairo_gl_composite_flush (cairo_gl_context_t *ctx,
     if (setup->vb_offset == 0)
         return;
 
-    _cairo_gl_composite_draw (ctx, setup);
+    if (setup->clip_region) {
+	int i, num_rectangles = cairo_region_num_rectangles (setup->clip_region);
+
+	for (i = 0; i < num_rectangles; i++) {
+	    cairo_rectangle_int_t rect;
+
+	    cairo_region_get_rectangle (setup->clip_region, i, &rect);
+
+	    glScissor (rect.x, rect.y, rect.width, rect.height);
+            _cairo_gl_composite_draw (ctx, setup);
+	}
+    } else {
+        _cairo_gl_composite_draw (ctx, setup);
+    }
 
     glUnmapBufferARB (GL_ARRAY_BUFFER_ARB);
     setup->vb = NULL;
@@ -1124,7 +1180,15 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
         break;
     case CAIRO_GL_OPERAND_SPANS:
-        ASSERT_NOT_REACHED;
+        {
+            union fi {
+                float f;
+                uint32_t u;
+            } fi;
+
+            fi.u = color;
+            *(*vb)++ = fi.f;
+        }
         break;
     case CAIRO_GL_OPERAND_TEXTURE:
         {
@@ -1181,12 +1245,16 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
 {
     _cairo_gl_composite_flush (ctx, setup);
 
+    if (setup->clip_region)
+	glDisable (GL_SCISSOR_TEST);
+
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
 
     _cairo_gl_use_program (ctx, NULL);
     glDisable (GL_BLEND);
 
     glDisableClientState (GL_VERTEX_ARRAY);
+    glDisableClientState (GL_COLOR_ARRAY);
 
     glClientActiveTexture (GL_TEXTURE0);
     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 870d80c..aad11a0 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -189,6 +189,7 @@ typedef struct _cairo_gl_composite {
     cairo_gl_surface_t *dst;
     cairo_operator_t op;
     cairo_bool_t has_component_alpha;
+    cairo_region_t *clip_region;
 
     cairo_gl_operand_t src;
     cairo_gl_operand_t mask;
@@ -297,6 +298,15 @@ cairo_private void
 _cairo_gl_composite_fini (cairo_gl_context_t *ctx,
                           cairo_gl_composite_t *setup);
 
+cairo_private void
+_cairo_gl_composite_set_clip_region (cairo_gl_context_t *ctx,
+                                     cairo_gl_composite_t *setup,
+                                     cairo_region_t *clip_region);
+
+cairo_private void
+_cairo_gl_composite_set_mask_spans (cairo_gl_context_t *ctx,
+                                    cairo_gl_composite_t *setup);
+
 cairo_private cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
                            cairo_gl_composite_t *setup);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 6f91dbd..4e6976b 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -50,18 +50,6 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
 
 #define BIAS .375
 
-static inline float
-int_as_float (uint32_t val)
-{
-    union fi {
-	float f;
-	uint32_t u;
-    } fi;
-
-    fi.u = val;
-    return fi.f;
-}
-
 static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
 {
     return surface->backend == &_cairo_gl_surface_backend;
@@ -1287,138 +1275,8 @@ typedef struct _cairo_gl_surface_span_renderer {
     int xmin, xmax;
 
     cairo_gl_context_t *ctx;
-    cairo_region_t *clip;
-
-    void *vbo_base;
-    unsigned int vbo_size;
-    unsigned int vbo_offset;
-    unsigned int vertex_size;
 } cairo_gl_surface_span_renderer_t;
 
-static void
-_cairo_gl_span_renderer_flush (cairo_gl_surface_span_renderer_t *renderer)
-{
-    int count;
-
-    if (renderer->vbo_offset == 0)
-	return;
-
-    glUnmapBufferARB (GL_ARRAY_BUFFER_ARB);
-
-    count = renderer->vbo_offset / renderer->vertex_size;
-    renderer->vbo_offset = 0;
-
-    if (renderer->clip) {
-	int i, num_rectangles = cairo_region_num_rectangles (renderer->clip);
-
-	glEnable (GL_SCISSOR_TEST);
-	for (i = 0; i < num_rectangles; i++) {
-	    cairo_rectangle_int_t rect;
-
-	    cairo_region_get_rectangle (renderer->clip, i, &rect);
-
-	    glScissor (rect.x, rect.y, rect.width, rect.height);
-	    glDrawArrays (GL_QUADS, 0, count);
-	}
-	glDisable (GL_SCISSOR_TEST);
-    } else {
-	glDrawArrays (GL_QUADS, 0, count);
-    }
-}
-
-static void *
-_cairo_gl_span_renderer_get_vbo (cairo_gl_surface_span_renderer_t *renderer,
-				 unsigned int num_vertices)
-{
-    unsigned int offset;
-
-    if (renderer->vbo_size == 0) {
-	renderer->vbo_size = 16384;
-	glBindBufferARB (GL_ARRAY_BUFFER_ARB, renderer->ctx->vbo);
-
-	if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE)
-	    renderer->vertex_size = 4 * sizeof (float) + sizeof (uint32_t);
-	else
-	    renderer->vertex_size = 2 * sizeof (float) + sizeof (uint32_t);
-
-	glVertexPointer (2, GL_FLOAT, renderer->vertex_size, 0);
-	glEnableClientState (GL_VERTEX_ARRAY);
-
-	glColorPointer (4, GL_UNSIGNED_BYTE, renderer->vertex_size,
-			(void *) (uintptr_t) (2 * sizeof (float)));
-	glEnableClientState (GL_COLOR_ARRAY);
-
-	if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
-	    glClientActiveTexture (GL_TEXTURE0);
-	    glTexCoordPointer (2, GL_FLOAT, renderer->vertex_size,
-			       (void *) (uintptr_t) (2 * sizeof (float) +
-						     sizeof (uint32_t)));
-	    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
-	}
-    }
-
-    if (renderer->vbo_offset + num_vertices * renderer->vertex_size >
-	renderer->vbo_size) {
-	_cairo_gl_span_renderer_flush (renderer);
-    }
-
-    if (renderer->vbo_offset == 0) {
-	/* We'll only be using these vertices once. */
-	glBufferDataARB (GL_ARRAY_BUFFER_ARB, renderer->vbo_size, NULL,
-		      GL_STREAM_DRAW_ARB);
-	renderer->vbo_base = glMapBufferARB (GL_ARRAY_BUFFER_ARB,
-					     GL_WRITE_ONLY_ARB);
-    }
-
-    offset = renderer->vbo_offset;
-    renderer->vbo_offset += num_vertices * renderer->vertex_size;
-
-    return (char *) renderer->vbo_base + offset;
-}
-
-static void
-_cairo_gl_emit_span_vertex (cairo_gl_surface_span_renderer_t *renderer,
-			    int dst_x, int dst_y, uint8_t alpha,
-			    float *vertices)
-{
-    cairo_surface_attributes_t *src_attributes;
-    int v = 0;
-
-    src_attributes = &renderer->setup.src.operand.texture.attributes;
-
-    vertices[v++] = dst_x + BIAS;
-    vertices[v++] = dst_y + BIAS;
-    vertices[v++] = int_as_float (alpha << 24);
-    if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
-	double s, t;
-
-	s = dst_x + BIAS;
-	t = dst_y + BIAS;
-	cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
-	vertices[v++] = s;
-	vertices[v++] = t;
-    }
-}
-
-static void
-_cairo_gl_emit_rectangle (cairo_gl_surface_span_renderer_t *renderer,
-			  int x1, int y1,
-			  int x2, int y2,
-			  int coverage)
-{
-    float *vertices = _cairo_gl_span_renderer_get_vbo (renderer, 4);
-    int vsize = renderer->vertex_size / 4;
-
-    _cairo_gl_emit_span_vertex (renderer, x1, y1, coverage,
-				vertices + vsize * 0);
-    _cairo_gl_emit_span_vertex (renderer, x1, y2, coverage,
-				vertices + vsize * 1);
-    _cairo_gl_emit_span_vertex (renderer, x2, y2, coverage,
-				vertices + vsize * 2);
-    _cairo_gl_emit_span_vertex (renderer, x2, y1, coverage,
-				vertices + vsize * 3);
-}
-
 static cairo_status_t
 _cairo_gl_render_bounded_spans (void *abstract_renderer,
 				int y, int height,
@@ -1432,10 +1290,11 @@ _cairo_gl_render_bounded_spans (void *abstract_renderer,
 
     do {
 	if (spans[0].coverage) {
-	    _cairo_gl_emit_rectangle (renderer,
-				      spans[0].x, y,
-				      spans[1].x, y + height,
-				      spans[0].coverage);
+            _cairo_gl_composite_emit_rect (renderer->ctx,
+                                           &renderer->setup,
+                                           spans[0].x, y,
+                                           spans[1].x, y + height,
+                                           spans[0].coverage << 24);
 	}
 
 	spans++;
@@ -1453,33 +1312,37 @@ _cairo_gl_render_unbounded_spans (void *abstract_renderer,
     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
 
     if (num_spans == 0) {
-	_cairo_gl_emit_rectangle (renderer,
-				  renderer->xmin, y,
-				  renderer->xmax, y + height,
-				  0);
+        _cairo_gl_composite_emit_rect (renderer->ctx,
+                                       &renderer->setup,
+                                       renderer->xmin, y,
+                                       renderer->xmax, y + height,
+                                       0);
 	return CAIRO_STATUS_SUCCESS;
     }
 
     if (spans[0].x != renderer->xmin) {
-	_cairo_gl_emit_rectangle (renderer,
-				  renderer->xmin, y,
-				  spans[0].x, y + height,
-				  0);
+        _cairo_gl_composite_emit_rect (renderer->ctx,
+                                       &renderer->setup,
+                                       renderer->xmin, y,
+                                       spans[0].x,     y + height,
+                                       0);
     }
 
     do {
-	_cairo_gl_emit_rectangle (renderer,
-				  spans[0].x, y,
-				  spans[1].x, y + height,
-				  spans[0].coverage);
+        _cairo_gl_composite_emit_rect (renderer->ctx,
+                                       &renderer->setup,
+                                       spans[0].x, y,
+                                       spans[1].x, y + height,
+                                       spans[0].coverage << 24);
 	spans++;
     } while (--num_spans > 1);
 
     if (spans[0].x != renderer->xmax) {
-	_cairo_gl_emit_rectangle (renderer,
-				  spans[0].x, y,
-				  renderer->xmax, y + height,
-				  0);
+        _cairo_gl_composite_emit_rect (renderer->ctx,
+                                       &renderer->setup,
+                                       spans[0].x,     y,
+                                       renderer->xmax, y + height,
+                                       0);
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -1505,25 +1368,7 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
 {
     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
 
-    _cairo_gl_span_renderer_flush (renderer);
-
-    glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
-    glDisableClientState (GL_VERTEX_ARRAY);
-    glDisableClientState (GL_COLOR_ARRAY);
-
-    glClientActiveTexture (GL_TEXTURE0);
-    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-    glActiveTexture (GL_TEXTURE0);
-    glDisable (GL_TEXTURE_1D);
-    glDisable (renderer->ctx->tex_target);
-
-    if (!renderer->setup.shader) {
-	glActiveTexture (GL_TEXTURE1);
-	glDisable (renderer->ctx->tex_target);
-    }
-
-    glDisable (GL_BLEND);
-    _cairo_gl_use_program (renderer->ctx, NULL);
+    _cairo_gl_composite_end (renderer->ctx, &renderer->setup);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1559,7 +1404,6 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     cairo_gl_surface_t *dst = abstract_dst;
     cairo_gl_surface_span_renderer_t *renderer;
     cairo_status_t status;
-    cairo_surface_attributes_t *src_attributes;
     const cairo_rectangle_int_t *extents;
 
     renderer = calloc (1, sizeof (*renderer));
@@ -1577,7 +1421,6 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     }
     renderer->xmin = extents->x;
     renderer->xmax = extents->x + extents->width;
-    renderer->clip = clip_region;
 
     status = _cairo_gl_context_acquire (dst->base.device, &renderer->ctx);
     if (unlikely (status)) {
@@ -1600,43 +1443,13 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     if (unlikely (status))
         goto FAIL;
 
-    _cairo_gl_context_set_destination (renderer->ctx, dst);
+    _cairo_gl_composite_set_mask_spans (renderer->ctx, &renderer->setup);
+    _cairo_gl_composite_set_clip_region (renderer->ctx, &renderer->setup, clip_region);
 
-    status = _cairo_gl_get_program (renderer->ctx,
-				    renderer->setup.src.type,
-				    CAIRO_GL_OPERAND_SPANS,
-				    CAIRO_GL_SHADER_IN_NORMAL,
-				    &renderer->setup.shader);
-    if (_cairo_status_is_error (status))
+    status = _cairo_gl_composite_begin (renderer->ctx, &renderer->setup);
+    if (unlikely (status))
         goto FAIL;
 
-    src_attributes = &renderer->setup.src.operand.texture.attributes;
-
-    _cairo_gl_use_program (renderer->ctx, renderer->setup.shader);
-    _cairo_gl_set_operator (dst, op, FALSE);
-    _cairo_gl_set_src_operand (renderer->ctx, &renderer->setup);
-
-    if (!renderer->setup.shader) {
-	/* Set up the mask to source from the incoming vertex color. */
-	glActiveTexture (GL_TEXTURE1);
-	/* Have to have a dummy texture bound in order to use the combiner unit. */
-	glBindTexture (renderer->ctx->tex_target, renderer->ctx->dummy_tex);
-	glEnable (renderer->ctx->tex_target);
-	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
-
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PRIMARY_COLOR);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
-    }
-
     return &renderer->base;
 
 
commit 6e81d85e3682f14e1c5dbe97dda2cc1fcd32df3a
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 03:27:28 2010 +0200

    gl: Change _cairo_gl_composite_emit_rect()
    
    Two changes:
    - The function now takes x1/y1,x2/y2 instead of x,y,width,height
    - The function takes a color uint32_t. This will be used by spans.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 272ebe2..c32c89b 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1111,7 +1111,8 @@ static inline void
 _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
                         GLfloat ** vb,
                         GLfloat x,
-                        GLfloat y)
+                        GLfloat y,
+                        uint32_t color)
 {
     switch (operand->type) {
     default:
@@ -1143,15 +1144,16 @@ static inline void
 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
                                  cairo_gl_composite_t *setup,
                                  GLfloat x,
-                                 GLfloat y)
+                                 GLfloat y,
+                                 uint32_t color)
 {
     GLfloat *vb = (GLfloat *) (void *) &setup->vb[setup->vb_offset];
 
     *vb++ = x;
     *vb++ = y;
 
-    _cairo_gl_operand_emit (&setup->src, &vb, x, y);
-    _cairo_gl_operand_emit (&setup->mask, &vb, x, y);
+    _cairo_gl_operand_emit (&setup->src, &vb, x, y, color);
+    _cairo_gl_operand_emit (&setup->mask, &vb, x, y, color);
 
     setup->vb_offset += setup->vertex_size;
 }
@@ -1159,17 +1161,18 @@ _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
 void
 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
                                cairo_gl_composite_t *setup,
-                               GLfloat x,
-                               GLfloat y,
-                               GLfloat width,
-                               GLfloat height)
+                               GLfloat x1,
+                               GLfloat y1,
+                               GLfloat x2,
+                               GLfloat y2,
+                               uint32_t color)
 {
     _cairo_gl_composite_prepare_buffer (ctx, setup, 4);
 
-    _cairo_gl_composite_emit_vertex (ctx, setup, x,         y);
-    _cairo_gl_composite_emit_vertex (ctx, setup, x + width, y);
-    _cairo_gl_composite_emit_vertex (ctx, setup, x + width, y + height);
-    _cairo_gl_composite_emit_vertex (ctx, setup, x,         y + height);
+    _cairo_gl_composite_emit_vertex (ctx, setup, x1, y1, color);
+    _cairo_gl_composite_emit_vertex (ctx, setup, x2, y1, color);
+    _cairo_gl_composite_emit_vertex (ctx, setup, x2, y2, color);
+    _cairo_gl_composite_emit_vertex (ctx, setup, x1, y2, color);
 }
 
 void
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index e926689..870d80c 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -304,10 +304,11 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
 cairo_private void
 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
                                cairo_gl_composite_t *setup,
-                               GLfloat x,
-                               GLfloat y,
-                               GLfloat width,
-                               GLfloat height);
+                               GLfloat x1,
+                               GLfloat y1,
+                               GLfloat x2,
+                               GLfloat y2,
+                               uint32_t color);
 
 cairo_private void
 _cairo_gl_composite_end (cairo_gl_context_t *ctx,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 4bec4ee..6f91dbd 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1001,13 +1001,15 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 
 	    cairo_region_get_rectangle (clip_region, i, &rect);
             _cairo_gl_composite_emit_rect (ctx, &setup,
-                                           rect.x, rect.y,
-                                           rect.width, rect.height);
+                                           rect.x,              rect.y,
+                                           rect.x + rect.width, rect.y + rect.height,
+                                           0);
 	}
     } else {
         _cairo_gl_composite_emit_rect (ctx, &setup,
-                                       dst_x, dst_y,
-                                       width, height);
+                                       dst_x,         dst_y,
+                                       dst_x + width, dst_y + height,
+                                       0);
     }
 
     _cairo_gl_composite_end (ctx, &setup);
commit f8398cc2d83eb9ac37874f71d4f8805dbf0df412
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 02:34:18 2010 +0200

    gl: remove unused variables from span renderer

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 24abb90..4bec4ee 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1284,10 +1284,6 @@ typedef struct _cairo_gl_surface_span_renderer {
 
     int xmin, xmax;
 
-    cairo_operator_t op;
-    cairo_antialias_t antialias;
-
-    cairo_gl_surface_t *dst;
     cairo_gl_context_t *ctx;
     cairo_region_t *clip;
 
@@ -1579,9 +1575,6 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     }
     renderer->xmin = extents->x;
     renderer->xmax = extents->x + extents->width;
-    renderer->op = op;
-    renderer->antialias = antialias;
-    renderer->dst = dst;
     renderer->clip = clip_region;
 
     status = _cairo_gl_context_acquire (dst->base.device, &renderer->ctx);
commit f5c5077def47b91b57dfbc8c2622b4aaf5ca8fbb
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 02:06:43 2010 +0200

    gl: Support component alpha in gl_composite_t
    
    Use that to get rid of cairo_gl_surface_composite_component_alpha()

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 8be453e..272ebe2 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -890,6 +890,100 @@ _cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
     }
 }
 
+static cairo_status_t
+_cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
+                                            cairo_gl_composite_t *setup)
+{
+    cairo_status_t status;
+
+    /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
+     * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
+     * is:
+     *     mask IN clip ? src OP dest : dest
+     * or more simply:
+     *     mask IN CLIP ? 0 : dest
+     *
+     * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
+     *
+     * The model we use in _cairo_gl_set_operator() is Render's:
+     *     src IN mask IN clip OP dest
+     * which would boil down to:
+     *     0 (bounded by the extents of the drawing).
+     *
+     * However, we can do a Render operation using an opaque source
+     * and DEST_OUT to produce:
+     *    1 IN mask IN clip DEST_OUT dest
+     * which is
+     *    mask IN clip ? 0 : dest
+     */
+    if (setup->op == CAIRO_OPERATOR_CLEAR) {
+        _cairo_gl_solid_operand_init (&setup->src, CAIRO_COLOR_WHITE);
+	setup->op = CAIRO_OPERATOR_DEST_OUT;
+    }
+
+    /**
+     * implements component-alpha %CAIRO_OPERATOR_OVER using two passes of
+     * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
+     *
+     * From http://anholt.livejournal.com/32058.html:
+     *
+     * The trouble is that component-alpha rendering requires two different sources
+     * for blending: one for the source value to the blender, which is the
+     * per-channel multiplication of source and mask, and one for the source alpha
+     * for multiplying with the destination channels, which is the multiplication
+     * of the source channels by the mask alpha. So the equation for Over is:
+     *
+     * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
+     * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
+     * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
+     * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
+     *
+     * But we can do some simpler operations, right? How about PictOpOutReverse,
+     * which has a source factor of 0 and dest factor of (1 - source alpha). We
+     * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
+     * blenders pretty easily. So we can do a component-alpha OutReverse, which
+     * gets us:
+     *
+     * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
+     * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
+     * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
+     * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
+     *
+     * OK. And if an op doesn't use the source alpha value for the destination
+     * factor, then we can do the channel multiplication in the texture blenders
+     * to get the source value, and ignore the source alpha that we wouldn't use.
+     * We've supported this in the Radeon driver for a long time. An example would
+     * be PictOpAdd, which does:
+     *
+     * dst.A = src.A * mask.A + dst.A
+     * dst.R = src.R * mask.R + dst.R
+     * dst.G = src.G * mask.G + dst.G
+     * dst.B = src.B * mask.B + dst.B
+     *
+     * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
+     * after it, we get:
+     *
+     * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
+     * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
+     * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
+     * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
+     *
+     * This two-pass trickery could be avoided using a new GL extension that
+     * lets two values come out of the shader and into the blend unit.
+     */
+    if (setup->op == CAIRO_OPERATOR_OVER) {
+	setup->op = CAIRO_OPERATOR_ADD;
+        status = _cairo_gl_get_program (ctx,
+                                        setup->src.type,
+                                        setup->mask.type,
+                                        CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
+                                        &setup->pre_shader);
+        if (unlikely (_cairo_status_is_error (status)))
+            return status;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
 
 cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
@@ -898,13 +992,23 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
     unsigned int dst_size, src_size, mask_size;
     cairo_status_t status;
 
+    /* Do various magic for component alpha */
+    if (setup->has_component_alpha) {
+        status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
+        if (unlikely (status))
+            return status;
+    }
+
     status = _cairo_gl_get_program (ctx,
                                     setup->src.type,
                                     setup->mask.type,
-				    CAIRO_GL_SHADER_IN_NORMAL,
+				    setup->has_component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
+                                                               : CAIRO_GL_SHADER_IN_NORMAL,
 				    &setup->shader);
-    if (_cairo_status_is_error (status))
+    if (_cairo_status_is_error (status)) {
+        setup->pre_shader = NULL;
 	return status;
+    }
 
     status = CAIRO_STATUS_SUCCESS;
 
@@ -915,7 +1019,9 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
     setup->vertex_size = dst_size + src_size + mask_size;
 
     _cairo_gl_context_set_destination (ctx, setup->dst);
-    _cairo_gl_set_operator (setup->dst, setup->op, FALSE);
+    _cairo_gl_set_operator (setup->dst,
+                            setup->op,
+                            setup->has_component_alpha);
 
     _cairo_gl_use_program (ctx, setup->shader);
 
@@ -924,14 +1030,21 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
     glVertexPointer (2, GL_FLOAT, setup->vertex_size, NULL);
     glEnableClientState (GL_VERTEX_ARRAY);
 
-    _cairo_gl_set_src_operand (ctx, setup);
+    if (! setup->pre_shader)
+        _cairo_gl_set_src_operand (ctx, setup);
     if (setup->src.type == CAIRO_GL_OPERAND_TEXTURE) {
 	glClientActiveTexture (GL_TEXTURE0);
 	glTexCoordPointer (2, GL_FLOAT, setup->vertex_size,
                            (void *) (uintptr_t) dst_size);
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
     }
-    _cairo_gl_set_mask_operand (ctx, setup);
+    if (! setup->pre_shader) {
+        if (setup->has_component_alpha)
+            _cairo_gl_set_component_alpha_mask_operand (ctx, setup);
+        else
+            _cairo_gl_set_mask_operand (ctx, setup);
+    }
+
     if (setup->mask.type == CAIRO_GL_OPERAND_TEXTURE) {
 	glClientActiveTexture (GL_TEXTURE1);
 	glTexCoordPointer (2, GL_FLOAT, setup->vertex_size,
@@ -943,13 +1056,36 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
 }
 
 static inline void
+_cairo_gl_composite_draw (cairo_gl_context_t *ctx,
+                          cairo_gl_composite_t *setup)
+{
+    unsigned int count = setup->vb_offset / setup->vertex_size;
+
+    if (! setup->pre_shader) {
+        glDrawArrays (GL_QUADS, 0, count);
+    } else {
+        _cairo_gl_use_program (ctx, setup->pre_shader);
+        _cairo_gl_set_operator (setup->dst, CAIRO_OPERATOR_DEST_OUT, TRUE);
+        _cairo_gl_set_src_alpha_operand (ctx, setup);
+        _cairo_gl_set_component_alpha_mask_operand (ctx, setup);
+        glDrawArrays (GL_QUADS, 0, count);
+
+        _cairo_gl_use_program (ctx, setup->shader);
+        _cairo_gl_set_operator (setup->dst, setup->op, TRUE);
+        _cairo_gl_set_src_operand (ctx, setup);
+        _cairo_gl_set_component_alpha_mask_operand (ctx, setup);
+        glDrawArrays (GL_QUADS, 0, count);
+    }
+}
+
+static inline void
 _cairo_gl_composite_flush (cairo_gl_context_t *ctx,
                            cairo_gl_composite_t *setup)
 {
     if (setup->vb_offset == 0)
         return;
 
-    glDrawArrays (GL_QUADS, 0, setup->vb_offset / setup->vertex_size);
+    _cairo_gl_composite_draw (ctx, setup);
 
     glUnmapBufferARB (GL_ARRAY_BUFFER_ARB);
     setup->vb = NULL;
@@ -1060,6 +1196,9 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
     glActiveTexture (GL_TEXTURE1);
     glDisable (GL_TEXTURE_1D);
     glDisable (ctx->tex_target);
+
+    setup->shader = NULL;
+    setup->pre_shader = NULL;
 }
 
 void
@@ -1077,14 +1216,24 @@ _cairo_gl_composite_init (cairo_gl_context_t *ctx,
                           cairo_gl_surface_t *dst,
                           const cairo_pattern_t *src,
                           const cairo_pattern_t *mask,
+                          cairo_bool_t has_component_alpha,
                           const cairo_rectangle_int_t *rect)
 {
     memset (setup, 0, sizeof (cairo_gl_composite_t));
 
-    if (! _cairo_gl_operator_is_supported (op))
-	return UNSUPPORTED ("unsupported operator");
     
+    if (has_component_alpha) {
+        if (op != CAIRO_OPERATOR_CLEAR &&
+            op != CAIRO_OPERATOR_OVER &&
+            op != CAIRO_OPERATOR_ADD)
+            return UNSUPPORTED ("unsupported component alpha operator");
+    } else {
+        if (! _cairo_gl_operator_is_supported (op))
+            return UNSUPPORTED ("unsupported operator");
+    }
+
     setup->dst = dst;
+    setup->has_component_alpha = has_component_alpha;
     setup->op = op;
 
     return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index c3ded41..76ac5aa 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -484,7 +484,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
     status = _cairo_gl_composite_init (ctx, &composite_setup,
                                        op, dst, source, NULL,
-                                       glyph_extents);
+                                       FALSE, glyph_extents);
 
     if (unlikely (status))
 	goto CLEANUP_FONT;
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 0cf0556..e926689 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -188,9 +188,12 @@ typedef struct cairo_gl_operand {
 typedef struct _cairo_gl_composite {
     cairo_gl_surface_t *dst;
     cairo_operator_t op;
+    cairo_bool_t has_component_alpha;
+
     cairo_gl_operand_t src;
     cairo_gl_operand_t mask;
     cairo_gl_shader_program_t *shader;
+    cairo_gl_shader_program_t *pre_shader; /* for component alpha */
 
     char *vb;
     unsigned int vb_offset;
@@ -287,6 +290,7 @@ _cairo_gl_composite_init (cairo_gl_context_t *ctx,
                           cairo_gl_surface_t *dst,
                           const cairo_pattern_t *src,
                           const cairo_pattern_t *mask,
+                          cairo_bool_t has_component_alpha,
                           const cairo_rectangle_int_t *rect);
 
 cairo_private void
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 3852fba..24abb90 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -936,262 +936,6 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
     return CAIRO_STATUS_SUCCESS;
 }
 
-/**
- * implements component-alpha %CAIRO_OPERATOR_SOURCE using two passes of
- * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
- *
- * From http://anholt.livejournal.com/32058.html:
- *
- * The trouble is that component-alpha rendering requires two different sources
- * for blending: one for the source value to the blender, which is the
- * per-channel multiplication of source and mask, and one for the source alpha
- * for multiplying with the destination channels, which is the multiplication
- * of the source channels by the mask alpha. So the equation for Over is:
- *
- * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
- * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
- * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
- * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
- *
- * But we can do some simpler operations, right? How about PictOpOutReverse,
- * which has a source factor of 0 and dest factor of (1 - source alpha). We
- * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
- * blenders pretty easily. So we can do a component-alpha OutReverse, which
- * gets us:
- *
- * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
- * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
- * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
- * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
- *
- * OK. And if an op doesn't use the source alpha value for the destination
- * factor, then we can do the channel multiplication in the texture blenders
- * to get the source value, and ignore the source alpha that we wouldn't use.
- * We've supported this in the Radeon driver for a long time. An example would
- * be PictOpAdd, which does:
- *
- * dst.A = src.A * mask.A + dst.A
- * dst.R = src.R * mask.R + dst.R
- * dst.G = src.G * mask.G + dst.G
- * dst.B = src.B * mask.B + dst.B
- *
- * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
- * after it, we get:
- *
- * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
- * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
- * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
- * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
- *
- * This two-pass trickery could be avoided using a new GL extension that
- * lets two values come out of the shader and into the blend unit.
- */
-static cairo_int_status_t
-_cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
-					     const cairo_pattern_t *src,
-					     const cairo_pattern_t *mask,
-					     void *abstract_dst,
-					     int src_x,
-					     int src_y,
-					     int mask_x,
-					     int mask_y,
-					     int dst_x,
-					     int dst_y,
-					     unsigned int width,
-					     unsigned int height,
-					     cairo_region_t *clip_region)
-{
-    cairo_gl_surface_t	*dst = abstract_dst;
-    cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL;
-    cairo_gl_context_t *ctx;
-    struct gl_point {
-	GLfloat x, y;
-    } vertices_stack[8], texcoord_src_stack[8], texcoord_mask_stack[8];
-    struct gl_point *vertices = vertices_stack;
-    struct gl_point *texcoord_src = texcoord_src_stack;
-    struct gl_point *texcoord_mask = texcoord_mask_stack;
-    cairo_status_t status;
-    int num_vertices, i;
-    cairo_gl_composite_t setup;
-    cairo_gl_shader_program_t *ca_source_program = NULL;
-    cairo_gl_shader_program_t *ca_source_alpha_program = NULL;
-    cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
-
-    if (op != CAIRO_OPERATOR_OVER && op != CAIRO_OPERATOR_ADD)
-	return UNSUPPORTED ("unsupported component alpha operator");
-
-    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
-    if (unlikely (status))
-	return status;
-
-    status = _cairo_gl_composite_init (ctx, &setup, op, dst, src, mask, &rect);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    status = _cairo_gl_operand_init (ctx, &setup.src, src, dst,
-				     src_x, src_y,
-				     dst_x, dst_y,
-				     width, height);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    src_attributes = &setup.src.operand.texture.attributes;
-
-    status = _cairo_gl_operand_init (ctx, &setup.mask, mask, dst,
-				     mask_x, mask_y,
-				     dst_x, dst_y,
-				     width, height);
-    if (unlikely (status))
-        goto CLEANUP;
-
-    mask_attributes = &setup.mask.operand.texture.attributes;
-
-    /* We'll fall back to fixed function instead. */
-    ca_source_program = NULL;
-    ca_source_alpha_program = NULL;
-
-    status = _cairo_gl_get_program (ctx,
-				    setup.src.type,
-				    setup.mask.type,
-				    CAIRO_GL_SHADER_IN_CA_SOURCE,
-				    &ca_source_program);
-    if (_cairo_status_is_error (status))
-	goto CLEANUP;
-
-    status = _cairo_gl_get_program (ctx,
-				    setup.src.type,
-				    setup.mask.type,
-				    CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
-				    &ca_source_alpha_program);
-    if (_cairo_status_is_error (status))
-	goto CLEANUP;
-
-    status = CAIRO_STATUS_SUCCESS;
-
-    _cairo_gl_context_set_destination (ctx, dst);
-
-    if (clip_region != NULL) {
-	int num_rectangles;
-
-	num_rectangles = cairo_region_num_rectangles (clip_region);
-	if (num_rectangles * 4 > ARRAY_LENGTH (vertices_stack)) {
-	    vertices = _cairo_malloc_ab (num_rectangles,
-					 4*3*sizeof (vertices[0]));
-	    if (unlikely (vertices == NULL)) {
-		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-		goto CLEANUP;
-	    }
-
-	    texcoord_src = vertices + num_rectangles * 4;
-	    texcoord_mask = texcoord_src + num_rectangles * 4;
-	}
-
-	for (i = 0; i < num_rectangles; i++) {
-	    cairo_rectangle_int_t rect;
-
-	    cairo_region_get_rectangle (clip_region, i, &rect);
-	    vertices[4*i + 0].x = rect.x;
-	    vertices[4*i + 0].y = rect.y;
-	    vertices[4*i + 1].x = rect.x + rect.width;
-	    vertices[4*i + 1].y = rect.y;
-	    vertices[4*i + 2].x = rect.x + rect.width;
-	    vertices[4*i + 2].y = rect.y + rect.height;
-	    vertices[4*i + 3].x = rect.x;
-	    vertices[4*i + 3].y = rect.y + rect.height;
-	}
-
-	num_vertices = 4 * num_rectangles;
-    } else {
-	vertices[0].x = dst_x;
-	vertices[0].y = dst_y;
-	vertices[1].x = dst_x + width;
-	vertices[1].y = dst_y;
-	vertices[2].x = dst_x + width;
-	vertices[2].y = dst_y + height;
-	vertices[3].x = dst_x;
-	vertices[3].y = dst_y + height;
-
-	num_vertices = 4;
-    }
-
-    glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
-    glEnableClientState (GL_VERTEX_ARRAY);
-
-    if (setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
-	for (i = 0; i < num_vertices; i++) {
-	    double s, t;
-
-	    s = vertices[i].x;
-	    t = vertices[i].y;
-	    cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
-	    texcoord_src[i].x = s;
-	    texcoord_src[i].y = t;
-	}
-
-	glClientActiveTexture (GL_TEXTURE0);
-	glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_src);
-	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
-    }
-
-    if (setup.mask.type == CAIRO_GL_OPERAND_TEXTURE) {
-	for (i = 0; i < num_vertices; i++) {
-	    double s, t;
-
-	    s = vertices[i].x;
-	    t = vertices[i].y;
-	    cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t);
-	    texcoord_mask[i].x = s;
-	    texcoord_mask[i].y = t;
-	}
-
-	glClientActiveTexture (GL_TEXTURE1);
-	glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_mask);
-	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
-    }
-
-    if (op == CAIRO_OPERATOR_OVER) {
-	setup.shader = ca_source_alpha_program;
-	_cairo_gl_use_program (ctx, setup.shader);
-	_cairo_gl_set_operator (dst, CAIRO_OPERATOR_DEST_OUT, TRUE);
-	_cairo_gl_set_src_alpha_operand (ctx, &setup);
-	_cairo_gl_set_component_alpha_mask_operand (ctx, &setup);
-	glDrawArrays (GL_QUADS, 0, num_vertices);
-    }
-
-    setup.shader = ca_source_program;
-    _cairo_gl_use_program (ctx, setup.shader);
-    _cairo_gl_set_operator (dst, CAIRO_OPERATOR_ADD, TRUE);
-    _cairo_gl_set_src_operand (ctx, &setup);
-    _cairo_gl_set_component_alpha_mask_operand (ctx, &setup);
-    glDrawArrays (GL_QUADS, 0, num_vertices);
-
-    glDisable (GL_BLEND);
-    _cairo_gl_use_program (ctx, NULL);
-
-    glDisableClientState (GL_VERTEX_ARRAY);
-
-    glClientActiveTexture (GL_TEXTURE0);
-    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-    glActiveTexture (GL_TEXTURE0);
-    glDisable (GL_TEXTURE_1D);
-    glDisable (ctx->tex_target);
-
-    glClientActiveTexture (GL_TEXTURE1);
-    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-    glActiveTexture (GL_TEXTURE1);
-    glDisable (GL_TEXTURE_1D);
-    glDisable (ctx->tex_target);
-
-  CLEANUP:
-    _cairo_gl_composite_fini (ctx, &setup);
-    _cairo_gl_context_release (ctx);
-
-    if (vertices != vertices_stack)
-	free (vertices);
-
-    return status;
-}
-
 static cairo_int_status_t
 _cairo_gl_surface_composite (cairo_operator_t		  op,
 			     const cairo_pattern_t	 *src,
@@ -1214,28 +958,14 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     cairo_gl_composite_t setup;
     cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
 
-    if (mask && mask->has_component_alpha) {
-	/* Try two-pass component alpha support, or bail. */
-	return _cairo_gl_surface_composite_component_alpha(op,
-							   src,
-							   mask,
-							   abstract_dst,
-							   src_x,
-							   src_y,
-							   mask_x,
-							   mask_y,
-							   dst_x,
-							   dst_y,
-							   width,
-							   height,
-							   clip_region);
-    }
-
     status = _cairo_gl_context_acquire (dst->base.device, &ctx);
     if (unlikely (status))
 	return status;
 
-    status = _cairo_gl_composite_init (ctx, &setup, op, dst, src, mask, &rect);
+    status = _cairo_gl_composite_init (ctx, &setup,
+                                       op, dst, src, mask,
+                                       mask && mask->has_component_alpha,
+                                       &rect);
     if (unlikely (status))
         goto CLEANUP;
 
@@ -1863,7 +1593,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     status = _cairo_gl_composite_init (renderer->ctx,
                                        &renderer->setup,
                                        op, dst, src, NULL,
-                                       extents);
+                                       FALSE, extents);
     if (unlikely (status))
         goto FAIL;
 
commit 88c118f891ca9ba472b8acff33829de845bb507c
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 16 00:24:17 2010 +0200

    gl: Implement _composite_emit_rect() and _composite_end()
    
    And use it in cairo_gl_surface_composite()

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 4991194..8be453e 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -871,10 +871,31 @@ _cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
     }
 }
 
+static unsigned int
+_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
+{
+    switch (type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_CONSTANT:
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+        return 0;
+    case CAIRO_GL_OPERAND_SPANS:
+        return 4 * sizeof (GLbyte);
+    case CAIRO_GL_OPERAND_TEXTURE:
+        return 2 * sizeof (GLfloat);
+    }
+}
+
+
 cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
                            cairo_gl_composite_t *setup)
 {
+    unsigned int dst_size, src_size, mask_size;
     cairo_status_t status;
 
     status = _cairo_gl_get_program (ctx,
@@ -887,17 +908,160 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
 
     status = CAIRO_STATUS_SUCCESS;
 
+    dst_size  = 2 * sizeof (GLfloat);
+    src_size  = _cairo_gl_operand_get_vertex_size (setup->src.type);
+    mask_size = _cairo_gl_operand_get_vertex_size (setup->mask.type);
+
+    setup->vertex_size = dst_size + src_size + mask_size;
+
     _cairo_gl_context_set_destination (ctx, setup->dst);
     _cairo_gl_set_operator (setup->dst, setup->op, FALSE);
 
     _cairo_gl_use_program (ctx, setup->shader);
 
+    glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
+
+    glVertexPointer (2, GL_FLOAT, setup->vertex_size, NULL);
+    glEnableClientState (GL_VERTEX_ARRAY);
+
     _cairo_gl_set_src_operand (ctx, setup);
+    if (setup->src.type == CAIRO_GL_OPERAND_TEXTURE) {
+	glClientActiveTexture (GL_TEXTURE0);
+	glTexCoordPointer (2, GL_FLOAT, setup->vertex_size,
+                           (void *) (uintptr_t) dst_size);
+	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+    }
     _cairo_gl_set_mask_operand (ctx, setup);
+    if (setup->mask.type == CAIRO_GL_OPERAND_TEXTURE) {
+	glClientActiveTexture (GL_TEXTURE1);
+	glTexCoordPointer (2, GL_FLOAT, setup->vertex_size,
+                           (void *) (uintptr_t) (dst_size + src_size));
+	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+    }
 
     return status;
 }
 
+static inline void
+_cairo_gl_composite_flush (cairo_gl_context_t *ctx,
+                           cairo_gl_composite_t *setup)
+{
+    if (setup->vb_offset == 0)
+        return;
+
+    glDrawArrays (GL_QUADS, 0, setup->vb_offset / setup->vertex_size);
+
+    glUnmapBufferARB (GL_ARRAY_BUFFER_ARB);
+    setup->vb = NULL;
+}
+
+static void
+_cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
+                                    cairo_gl_composite_t *setup,
+                                    unsigned int n_vertices)
+{
+    if (setup->vb_offset + n_vertices * setup->vertex_size > CAIRO_GL_VBO_SIZE)
+	_cairo_gl_composite_flush (ctx, setup);
+
+    if (setup->vb == NULL) {
+	glBufferDataARB (GL_ARRAY_BUFFER_ARB, CAIRO_GL_VBO_SIZE,
+			 NULL, GL_STREAM_DRAW_ARB);
+	setup->vb = glMapBufferARB (GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+	setup->vb_offset = 0;
+    }
+}
+
+static inline void
+_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
+                        GLfloat ** vb,
+                        GLfloat x,
+                        GLfloat y)
+{
+    switch (operand->type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_CONSTANT:
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+        break;
+    case CAIRO_GL_OPERAND_SPANS:
+        ASSERT_NOT_REACHED;
+        break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+        {
+            cairo_surface_attributes_t *src_attributes = &operand->operand.texture.attributes;
+            double s = x;
+            double t = y;
+
+            cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
+            *(*vb)++ = s;
+            *(*vb)++ = t;
+        }
+        break;
+    }
+}
+
+static inline void
+_cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
+                                 cairo_gl_composite_t *setup,
+                                 GLfloat x,
+                                 GLfloat y)
+{
+    GLfloat *vb = (GLfloat *) (void *) &setup->vb[setup->vb_offset];
+
+    *vb++ = x;
+    *vb++ = y;
+
+    _cairo_gl_operand_emit (&setup->src, &vb, x, y);
+    _cairo_gl_operand_emit (&setup->mask, &vb, x, y);
+
+    setup->vb_offset += setup->vertex_size;
+}
+
+void
+_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
+                               cairo_gl_composite_t *setup,
+                               GLfloat x,
+                               GLfloat y,
+                               GLfloat width,
+                               GLfloat height)
+{
+    _cairo_gl_composite_prepare_buffer (ctx, setup, 4);
+
+    _cairo_gl_composite_emit_vertex (ctx, setup, x,         y);
+    _cairo_gl_composite_emit_vertex (ctx, setup, x + width, y);
+    _cairo_gl_composite_emit_vertex (ctx, setup, x + width, y + height);
+    _cairo_gl_composite_emit_vertex (ctx, setup, x,         y + height);
+}
+
+void
+_cairo_gl_composite_end (cairo_gl_context_t *ctx,
+                         cairo_gl_composite_t *setup)
+{
+    _cairo_gl_composite_flush (ctx, setup);
+
+    glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
+
+    _cairo_gl_use_program (ctx, NULL);
+    glDisable (GL_BLEND);
+
+    glDisableClientState (GL_VERTEX_ARRAY);
+
+    glClientActiveTexture (GL_TEXTURE0);
+    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+    glActiveTexture (GL_TEXTURE0);
+    glDisable (GL_TEXTURE_1D);
+    glDisable (ctx->tex_target);
+
+    glClientActiveTexture (GL_TEXTURE1);
+    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+    glActiveTexture (GL_TEXTURE1);
+    glDisable (GL_TEXTURE_1D);
+    glDisable (ctx->tex_target);
+}
+
 void
 _cairo_gl_composite_fini (cairo_gl_context_t *ctx,
                           cairo_gl_composite_t *setup)
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index fac4260..0cf0556 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -69,6 +69,9 @@
  * Random number that is hopefully big enough to not cause many cache evictions. */
 #define CAIRO_GL_MAX_SHADERS_PER_CONTEXT 64
 
+/* VBO size that we allocate, smaller size means we gotta flush more often */
+#define CAIRO_GL_VBO_SIZE 16384
+
 typedef struct _cairo_gl_surface {
     cairo_surface_t base;
 
@@ -188,6 +191,10 @@ typedef struct _cairo_gl_composite {
     cairo_gl_operand_t src;
     cairo_gl_operand_t mask;
     cairo_gl_shader_program_t *shader;
+
+    char *vb;
+    unsigned int vb_offset;
+    unsigned int vertex_size;
 } cairo_gl_composite_t;
 
 cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
@@ -291,6 +298,18 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
                            cairo_gl_composite_t *setup);
 
 cairo_private void
+_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
+                               cairo_gl_composite_t *setup,
+                               GLfloat x,
+                               GLfloat y,
+                               GLfloat width,
+                               GLfloat height);
+
+cairo_private void
+_cairo_gl_composite_end (cairo_gl_context_t *ctx,
+                         cairo_gl_composite_t *setup);
+
+cairo_private void
 _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 			   cairo_gl_composite_t *setup);
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 49bc92c..3852fba 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1210,14 +1210,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     cairo_gl_surface_t	*dst = abstract_dst;
     cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL;
     cairo_gl_context_t *ctx;
-    struct gl_point {
-	GLfloat x, y;
-    } vertices_stack[8], texcoord_src_stack[8], texcoord_mask_stack[8];
-    struct gl_point *vertices = vertices_stack;
-    struct gl_point *texcoord_src = texcoord_src_stack;
-    struct gl_point *texcoord_mask = texcoord_mask_stack;
     cairo_status_t status;
-    int num_vertices, i;
     cairo_gl_composite_t setup;
     cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
 
@@ -1269,107 +1262,25 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     status = _cairo_gl_composite_begin (ctx, &setup);
 
     if (clip_region != NULL) {
-	int num_rectangles;
-
-	num_rectangles = cairo_region_num_rectangles (clip_region);
-	if (num_rectangles * 4 > ARRAY_LENGTH (vertices_stack)) {
-	    vertices = _cairo_malloc_ab (num_rectangles,
-					 4*3*sizeof (vertices[0]));
-	    if (unlikely (vertices == NULL)) {
-		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-		goto CLEANUP;
-	    }
+        int i, num_rectangles;
 
-	    texcoord_src = vertices + num_rectangles * 4;
-	    texcoord_mask = texcoord_src + num_rectangles * 4;
-	}
+        num_rectangles = cairo_region_num_rectangles (clip_region);
 
 	for (i = 0; i < num_rectangles; i++) {
 	    cairo_rectangle_int_t rect;
 
 	    cairo_region_get_rectangle (clip_region, i, &rect);
-	    vertices[4*i + 0].x = rect.x;
-	    vertices[4*i + 0].y = rect.y;
-	    vertices[4*i + 1].x = rect.x + rect.width;
-	    vertices[4*i + 1].y = rect.y;
-	    vertices[4*i + 2].x = rect.x + rect.width;
-	    vertices[4*i + 2].y = rect.y + rect.height;
-	    vertices[4*i + 3].x = rect.x;
-	    vertices[4*i + 3].y = rect.y + rect.height;
+            _cairo_gl_composite_emit_rect (ctx, &setup,
+                                           rect.x, rect.y,
+                                           rect.width, rect.height);
 	}
-
-	num_vertices = 4 * num_rectangles;
     } else {
-	vertices[0].x = dst_x;
-	vertices[0].y = dst_y;
-	vertices[1].x = dst_x + width;
-	vertices[1].y = dst_y;
-	vertices[2].x = dst_x + width;
-	vertices[2].y = dst_y + height;
-	vertices[3].x = dst_x;
-	vertices[3].y = dst_y + height;
-
-	num_vertices = 4;
+        _cairo_gl_composite_emit_rect (ctx, &setup,
+                                       dst_x, dst_y,
+                                       width, height);
     }
 
-    glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
-    glEnableClientState (GL_VERTEX_ARRAY);
-
-    if (setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
-	for (i = 0; i < num_vertices; i++) {
-	    double s, t;
-
-	    s = vertices[i].x;
-	    t = vertices[i].y;
-	    cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
-	    texcoord_src[i].x = s;
-	    texcoord_src[i].y = t;
-	}
-
-	glClientActiveTexture (GL_TEXTURE0);
-	glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_src);
-	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
-    }
-
-    if (mask != NULL) {
-        if (setup.mask.type == CAIRO_GL_OPERAND_TEXTURE) {
-	    for (i = 0; i < num_vertices; i++) {
-		double s, t;
-
-		s = vertices[i].x;
-		t = vertices[i].y;
-		cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t);
-		texcoord_mask[i].x = s;
-		texcoord_mask[i].y = t;
-	    }
-
-	    glClientActiveTexture (GL_TEXTURE1);
-	    glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_mask);
-	    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
-	}
-    }
-
-    glDrawArrays (GL_QUADS, 0, num_vertices);
-
-    _cairo_gl_use_program (ctx, NULL);
-    glDisable (GL_BLEND);
-
-    glDisableClientState (GL_VERTEX_ARRAY);
-
-    glClientActiveTexture (GL_TEXTURE0);
-    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-    glActiveTexture (GL_TEXTURE0);
-    glDisable (GL_TEXTURE_1D);
-    glDisable (ctx->tex_target);
-
-    glClientActiveTexture (GL_TEXTURE1);
-    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-    glActiveTexture (GL_TEXTURE1);
-    glDisable (GL_TEXTURE_1D);
-    glDisable (ctx->tex_target);
-
-    if (vertices != vertices_stack)
-	free (vertices);
+    _cairo_gl_composite_end (ctx, &setup);
 
   CLEANUP:
     _cairo_gl_composite_fini (ctx, &setup);
commit b96735f7b465a16182c4c8555878ba16b947e8f9
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat May 15 22:12:12 2010 +0200

    gl: Add _cairo_gl_composite_begin() function
    
    This is the first step at adding the following function set:
    _cairo_gl_composite_begin()
    _cairo_gl_composite_emit_*()
    _cairo_gl_composite_end()
    which will take care of proiding a unified model for emitting vertexes
    using vbos instead of the 5 different methods we currently have.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index e12770a..4991194 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -871,6 +871,33 @@ _cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
     }
 }
 
+cairo_status_t
+_cairo_gl_composite_begin (cairo_gl_context_t *ctx,
+                           cairo_gl_composite_t *setup)
+{
+    cairo_status_t status;
+
+    status = _cairo_gl_get_program (ctx,
+                                    setup->src.type,
+                                    setup->mask.type,
+				    CAIRO_GL_SHADER_IN_NORMAL,
+				    &setup->shader);
+    if (_cairo_status_is_error (status))
+	return status;
+
+    status = CAIRO_STATUS_SUCCESS;
+
+    _cairo_gl_context_set_destination (ctx, setup->dst);
+    _cairo_gl_set_operator (setup->dst, setup->op, FALSE);
+
+    _cairo_gl_use_program (ctx, setup->shader);
+
+    _cairo_gl_set_src_operand (ctx, setup);
+    _cairo_gl_set_mask_operand (ctx, setup);
+
+    return status;
+}
+
 void
 _cairo_gl_composite_fini (cairo_gl_context_t *ctx,
                           cairo_gl_composite_t *setup)
@@ -893,6 +920,9 @@ _cairo_gl_composite_init (cairo_gl_context_t *ctx,
     if (! _cairo_gl_operator_is_supported (op))
 	return UNSUPPORTED ("unsupported operator");
     
+    setup->dst = dst;
+    setup->op = op;
+
     return CAIRO_STATUS_SUCCESS;
 }
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 627bcac..fac4260 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -183,6 +183,8 @@ typedef struct cairo_gl_operand {
 } cairo_gl_operand_t;
 
 typedef struct _cairo_gl_composite {
+    cairo_gl_surface_t *dst;
+    cairo_operator_t op;
     cairo_gl_operand_t src;
     cairo_gl_operand_t mask;
     cairo_gl_shader_program_t *shader;
@@ -284,6 +286,10 @@ cairo_private void
 _cairo_gl_composite_fini (cairo_gl_context_t *ctx,
                           cairo_gl_composite_t *setup);
 
+cairo_private cairo_status_t
+_cairo_gl_composite_begin (cairo_gl_context_t *ctx,
+                           cairo_gl_composite_t *setup);
+
 cairo_private void
 _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 			   cairo_gl_composite_t *setup);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 661f177..49bc92c 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1266,27 +1266,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	mask_attributes = &setup.mask.operand.texture.attributes;
     }
 
-    /* We'll fall back to fixed function instead. */
-    setup.shader = NULL;
-    status = _cairo_gl_get_program (ctx,
-                                    setup.src.type,
-                                    setup.mask.type,
-				    CAIRO_GL_SHADER_IN_NORMAL,
-				    &setup.shader);
-    if (_cairo_status_is_error (status))
-	goto CLEANUP;
-
-    status = CAIRO_STATUS_SUCCESS;
-
-    _cairo_gl_context_set_destination (ctx, dst);
-    _cairo_gl_set_operator (dst, op, FALSE);
-
-    _cairo_gl_use_program (ctx, setup.shader);
-    _cairo_gl_set_src_operand (ctx, &setup);
-
-    if (mask != NULL) {
-        _cairo_gl_set_mask_operand (ctx, &setup);
-    }
+    status = _cairo_gl_composite_begin (ctx, &setup);
 
     if (clip_region != NULL) {
 	int num_rectangles;
commit 211a8b8234d24dd8e00332cb0b0e625ac1ffef58
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat May 15 21:27:58 2010 +0200

    gl: make _cairo_operand_destroy private

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index d61f70f..e12770a 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -450,7 +450,7 @@ _cairo_gl_operand_init (cairo_gl_context_t *ctx,
     }
 }
 
-void
+static void
 _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
 {
     switch (operand->type) {
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 6da413c..627bcac 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -300,9 +300,6 @@ cairo_private void
 _cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
 			    cairo_gl_composite_t *setup);
 
-cairo_private void
-_cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
-
 cairo_private cairo_bool_t
 _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
 				     GLenum *internal_format, GLenum *format,
commit bf1060252abaa97eb5ce149f8b99055b42096c67
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat May 15 21:26:55 2010 +0200

    gl: make show_glyphs use the cairo_composite_t API

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index aee9235..c3ded41 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -478,21 +478,24 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
     *has_component_alpha = FALSE;
 
-    memset (&composite_setup, 0, sizeof(composite_setup));
-
     status = _cairo_gl_context_acquire (dst->base.device, &ctx);
     if (unlikely (status))
 	return status;
 
+    status = _cairo_gl_composite_init (ctx, &composite_setup,
+                                       op, dst, source, NULL,
+                                       glyph_extents);
+
+    if (unlikely (status))
+	goto CLEANUP_FONT;
+
     status = _cairo_gl_operand_init (ctx, &composite_setup.src, source, dst,
 				     glyph_extents->x, glyph_extents->y,
 				     dst_x, dst_y,
 				     glyph_extents->width,
 				     glyph_extents->height);
-    if (unlikely (status)) {
-        _cairo_gl_context_release (ctx);
-	return status;
-    }
+    if (unlikely (status))
+	goto CLEANUP_FONT;
 
     _cairo_gl_context_set_destination (ctx, dst);
 
@@ -642,7 +645,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
 
-    _cairo_gl_operand_destroy (&composite_setup.src);
+    _cairo_gl_composite_fini (ctx, &composite_setup);
 
     _cairo_gl_context_release (ctx);
 
commit 948290de12c5f451d361903f0f52e0cde5527180
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat May 15 20:33:00 2010 +0200

    gl: Make the span renderer use the new composite APIs

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 16deaab..661f177 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1874,7 +1874,8 @@ _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
     if (!renderer)
 	return;
 
-    _cairo_gl_operand_destroy (&renderer->setup.src);
+    _cairo_gl_composite_fini (renderer->ctx, &renderer->setup);
+
     _cairo_gl_context_release (renderer->ctx);
 
     free (renderer);
@@ -1968,16 +1969,20 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 	return _cairo_span_renderer_create_in_error (status);
     }
 
+    status = _cairo_gl_composite_init (renderer->ctx,
+                                       &renderer->setup,
+                                       op, dst, src, NULL,
+                                       extents);
+    if (unlikely (status))
+        goto FAIL;
+
     status = _cairo_gl_operand_init (renderer->ctx,
                                      &renderer->setup.src, src, dst,
 				     rects->source.x, rects->source.y,
 				     extents->x, extents->y,
 				     extents->width, extents->height);
-    if (unlikely (status)) {
-        _cairo_gl_context_release (renderer->ctx);
-	free (renderer);
-	return _cairo_span_renderer_create_in_error (status);
-    }
+    if (unlikely (status))
+        goto FAIL;
 
     _cairo_gl_context_set_destination (renderer->ctx, dst);
 
@@ -1986,12 +1991,8 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 				    CAIRO_GL_OPERAND_SPANS,
 				    CAIRO_GL_SHADER_IN_NORMAL,
 				    &renderer->setup.shader);
-    if (_cairo_status_is_error (status)) {
-	_cairo_gl_operand_destroy (&renderer->setup.src);
-	_cairo_gl_context_release (renderer->ctx);
-	free (renderer);
-	return _cairo_span_renderer_create_in_error (status);
-    }
+    if (_cairo_status_is_error (status))
+        goto FAIL;
 
     src_attributes = &renderer->setup.src.operand.texture.attributes;
 
@@ -2021,6 +2022,13 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     }
 
     return &renderer->base;
+
+
+FAIL:
+    _cairo_gl_composite_fini (renderer->ctx, &renderer->setup);
+    _cairo_gl_context_release (renderer->ctx);
+    free (renderer);
+    return _cairo_span_renderer_create_in_error (status);
 }
 
 static cairo_bool_t
commit 7ad8c3b45691ce0c8a86180bb3c1117b9a9980c0
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat May 15 20:07:44 2010 +0200

    gl: Move composite code into own file
    
    This allows designing a cleaner interface for cairo_composite_t as there
    will not be static functions that get called outside of the "published"
    interfaces.

diff --git a/src/Makefile.sources b/src/Makefile.sources
index c45e339..24f15c5 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -313,7 +313,8 @@ cairo_beos_headers = cairo-beos.h
 
 cairo_gl_headers = cairo-gl.h
 cairo_gl_private = cairo-gl-private.h
-cairo_gl_sources = cairo-gl-device.c \
+cairo_gl_sources = cairo-gl-composite.c \
+		   cairo-gl-device.c \
 		   cairo-gl-glyphs.c \
 		   cairo-gl-shaders.c \
 		   cairo-gl-surface.c
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
new file mode 100644
index 0000000..d61f70f
--- /dev/null
+++ b/src/cairo-gl-composite.c
@@ -0,0 +1,898 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Carl Worth <cworth at cworth.org>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-gl-private.h"
+
+static void
+_cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
+			       cairo_surface_attributes_t *attributes,
+			       GLint tex_target)
+{
+
+    if (tex_target == GL_TEXTURE_RECTANGLE_EXT) {
+	assert (attributes->extend != CAIRO_EXTEND_REPEAT &&
+		attributes->extend != CAIRO_EXTEND_REFLECT);
+    }
+
+    glActiveTexture (GL_TEXTURE0 + tex_unit);
+    glBindTexture (tex_target, tex);
+    switch (attributes->extend) {
+    case CAIRO_EXTEND_NONE:
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+	break;
+    case CAIRO_EXTEND_PAD:
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	break;
+    case CAIRO_EXTEND_REPEAT:
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_REPEAT);
+	break;
+    case CAIRO_EXTEND_REFLECT:
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+	break;
+    }
+    switch (attributes->filter) {
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+	glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri (tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	break;
+    case CAIRO_FILTER_GOOD:
+    case CAIRO_FILTER_BEST:
+    case CAIRO_FILTER_BILINEAR:
+	glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri (tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	break;
+    default:
+    case CAIRO_FILTER_GAUSSIAN:
+	ASSERT_NOT_REACHED;
+    }
+    glEnable (tex_target);
+}
+
+static int
+_cairo_gl_gradient_sample_width (const cairo_gradient_pattern_t *gradient)
+{
+    unsigned int n;
+    int width;
+
+    width = 8;
+    for (n = 1; n < gradient->n_stops; n++) {
+	double dx = gradient->stops[n].offset - gradient->stops[n-1].offset;
+	double delta, max;
+	int ramp;
+
+	if (dx == 0)
+	    continue;
+
+	max = gradient->stops[n].color.red -
+	      gradient->stops[n-1].color.red;
+
+	delta = gradient->stops[n].color.green -
+	        gradient->stops[n-1].color.green;
+	if (delta > max)
+	    max = delta;
+
+	delta = gradient->stops[n].color.blue -
+	        gradient->stops[n-1].color.blue;
+	if (delta > max)
+	    max = delta;
+
+	delta = gradient->stops[n].color.alpha -
+	        gradient->stops[n-1].color.alpha;
+	if (delta > max)
+	    max = delta;
+
+	ramp = 128 * max / dx;
+	if (ramp > width)
+	    width = ramp;
+    }
+
+    width = (width + 7) & -8;
+    return MIN (width, 1024);
+}
+
+static cairo_status_t
+_render_gradient (const cairo_gl_context_t *ctx,
+		  cairo_gradient_pattern_t *pattern,
+		  void *bytes,
+		  int width)
+{
+    pixman_image_t *gradient, *image;
+    pixman_gradient_stop_t pixman_stops_stack[32];
+    pixman_gradient_stop_t *pixman_stops;
+    pixman_point_fixed_t p1, p2;
+    unsigned int i;
+
+    pixman_stops = pixman_stops_stack;
+    if (unlikely (pattern->n_stops > ARRAY_LENGTH (pixman_stops_stack))) {
+	pixman_stops = _cairo_malloc_ab (pattern->n_stops,
+					 sizeof (pixman_gradient_stop_t));
+	if (unlikely (pixman_stops == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    for (i = 0; i < pattern->n_stops; i++) {
+	pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
+	pixman_stops[i].color.red   = pattern->stops[i].color.red_short;
+	pixman_stops[i].color.green = pattern->stops[i].color.green_short;
+	pixman_stops[i].color.blue  = pattern->stops[i].color.blue_short;
+	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
+    }
+
+    p1.x = 0;
+    p1.y = 0;
+    p2.x = width << 16;
+    p2.y = 0;
+
+    gradient = pixman_image_create_linear_gradient (&p1, &p2,
+						    pixman_stops,
+						    pattern->n_stops);
+    if (pixman_stops != pixman_stops_stack)
+	free (pixman_stops);
+
+    if (unlikely (gradient == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    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,
+				      bytes, sizeof(uint32_t)*width);
+    if (unlikely (image == NULL)) {
+	pixman_image_unref (gradient);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    pixman_image_composite32 (PIXMAN_OP_SRC,
+                              gradient, NULL, image,
+                              0, 0,
+                              0, 0,
+                              0, 0,
+                              width, 1);
+
+    pixman_image_unref (gradient);
+    pixman_image_unref (image);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_gl_create_gradient_texture (const cairo_gl_context_t *ctx,
+				   cairo_gl_surface_t *surface,
+				   cairo_gradient_pattern_t *pattern,
+				   GLuint *tex)
+{
+    int tex_width;
+    GLubyte *data;
+
+    assert (pattern->n_stops != 0);
+
+    tex_width = _cairo_gl_gradient_sample_width (pattern);
+
+    glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, ctx->texture_load_pbo);
+    glBufferDataARB (GL_PIXEL_UNPACK_BUFFER_ARB, tex_width * sizeof (uint32_t), 0, GL_STREAM_DRAW);
+    data = glMapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
+
+    _render_gradient (ctx, pattern, data, tex_width);
+
+    glUnmapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB);
+
+    glGenTextures (1, tex);
+    glBindTexture (GL_TEXTURE_1D, *tex);
+    glTexImage1D (GL_TEXTURE_1D, 0, GL_RGBA8, tex_width, 0,
+                  GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
+
+    glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+
+    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+    switch (pattern->base.extend) {
+    case CAIRO_EXTEND_NONE:
+	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+	break;
+    case CAIRO_EXTEND_PAD:
+	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	break;
+    case CAIRO_EXTEND_REPEAT:
+	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	break;
+    case CAIRO_EXTEND_REFLECT:
+	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+	break;
+    }
+}
+
+/**
+ * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
+ * from dest to src coords.
+ */
+static cairo_status_t
+_cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
+                                 cairo_gl_operand_t *operand,
+				 const cairo_pattern_t *src,
+				 cairo_gl_surface_t *dst,
+				 int src_x, int src_y,
+				 int dst_x, int dst_y,
+				 int width, int height)
+{
+    cairo_status_t status;
+    cairo_matrix_t m;
+    cairo_gl_surface_t *surface;
+    cairo_surface_attributes_t *attributes;
+    attributes = &operand->operand.texture.attributes;
+
+    status = _cairo_pattern_acquire_surface (src, &dst->base,
+					     src_x, src_y,
+					     width, height,
+					     CAIRO_PATTERN_ACQUIRE_NONE,
+					     (cairo_surface_t **)
+					     &surface,
+					     attributes);
+    if (unlikely (status))
+	return status;
+
+    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT &&
+	(attributes->extend == CAIRO_EXTEND_REPEAT ||
+	 attributes->extend == CAIRO_EXTEND_REFLECT))
+    {
+	_cairo_pattern_release_surface (operand->pattern,
+					&surface->base,
+					attributes);
+	return UNSUPPORTED ("EXT_texture_rectangle with repeat/reflect");
+    }
+
+    assert (surface->base.backend == &_cairo_gl_surface_backend);
+
+    operand->type = CAIRO_GL_OPERAND_TEXTURE;
+    operand->operand.texture.surface = surface;
+    operand->operand.texture.tex = surface->tex;
+    /* Translate the matrix from
+     * (unnormalized src -> unnormalized src) to
+     * (unnormalized dst -> unnormalized src)
+     */
+    cairo_matrix_init_translate (&m,
+				 src_x - dst_x + attributes->x_offset,
+				 src_y - dst_y + attributes->y_offset);
+    cairo_matrix_multiply (&attributes->matrix,
+			   &m,
+			   &attributes->matrix);
+
+
+    /* Translate the matrix from
+     * (unnormalized dst -> unnormalized src) to
+     * (unnormalized dst -> normalized src)
+     */
+    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT) {
+	cairo_matrix_init_scale (&m,
+				 1.0,
+				 1.0);
+    } else {
+	cairo_matrix_init_scale (&m,
+				 1.0 / surface->width,
+				 1.0 / surface->height);
+    }
+    cairo_matrix_multiply (&attributes->matrix,
+			   &attributes->matrix,
+			   &m);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
+	                      const cairo_color_t *color)
+{
+    operand->type = CAIRO_GL_OPERAND_CONSTANT;
+    operand->operand.constant.color[0] = color->red   * color->alpha;
+    operand->operand.constant.color[1] = color->green * color->alpha;
+    operand->operand.constant.color[2] = color->blue  * color->alpha;
+    operand->operand.constant.color[3] = color->alpha;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_gradient_operand_init (cairo_gl_context_t *ctx,
+                                 cairo_gl_operand_t *operand,
+				 cairo_gl_surface_t *dst)
+{
+    cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *)operand->pattern;
+
+    if (! _cairo_gl_device_has_glsl (&ctx->base))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
+	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
+        double x0, y0, x1, y1;
+
+	x0 = _cairo_fixed_to_double (linear->p1.x);
+	x1 = _cairo_fixed_to_double (linear->p2.x);
+	y0 = _cairo_fixed_to_double (linear->p1.y);
+	y1 = _cairo_fixed_to_double (linear->p2.y);
+
+        if ((unsigned int)ctx->max_texture_size / 2 <= gradient->n_stops) {
+            return CAIRO_INT_STATUS_UNSUPPORTED;
+        }
+
+        _cairo_gl_create_gradient_texture (ctx,
+					   dst,
+					   gradient,
+					   &operand->operand.linear.tex);
+
+	/* Translation matrix from the destination fragment coordinates
+	 * (pixels from lower left = 0,0) to the coordinates in the
+	 */
+	cairo_matrix_init_translate (&operand->operand.linear.m, -x0, -y0);
+	cairo_matrix_multiply (&operand->operand.linear.m,
+			       &operand->pattern->matrix,
+			       &operand->operand.linear.m);
+	cairo_matrix_translate (&operand->operand.linear.m, 0, dst->height);
+	cairo_matrix_scale (&operand->operand.linear.m, 1.0, -1.0);
+
+	operand->operand.linear.segment_x = x1 - x0;
+	operand->operand.linear.segment_y = y1 - y0;
+
+	operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
+        return CAIRO_STATUS_SUCCESS;
+    } else {
+	cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
+        double x0, y0, r0, x1, y1, r1;
+
+	x0 = _cairo_fixed_to_double (radial->c1.x);
+	x1 = _cairo_fixed_to_double (radial->c2.x);
+	y0 = _cairo_fixed_to_double (radial->c1.y);
+	y1 = _cairo_fixed_to_double (radial->c2.y);
+	r0 = _cairo_fixed_to_double (radial->r1);
+	r1 = _cairo_fixed_to_double (radial->r2);
+
+        if ((unsigned int)ctx->max_texture_size / 2 <= gradient->n_stops)
+            return CAIRO_INT_STATUS_UNSUPPORTED;
+
+        _cairo_gl_create_gradient_texture (ctx,
+					   dst,
+					   gradient,
+					   &operand->operand.radial.tex);
+
+	/* Translation matrix from the destination fragment coordinates
+	 * (pixels from lower left = 0,0) to the coordinates in the
+	 */
+	cairo_matrix_init_translate (&operand->operand.radial.m, -x0, -y0);
+	cairo_matrix_multiply (&operand->operand.radial.m,
+			       &operand->pattern->matrix,
+			       &operand->operand.radial.m);
+	cairo_matrix_translate (&operand->operand.radial.m, 0, dst->height);
+	cairo_matrix_scale (&operand->operand.radial.m, 1.0, -1.0);
+
+	operand->operand.radial.circle_1_x = x1 - x0;
+	operand->operand.radial.circle_1_y = y1 - y0;
+	operand->operand.radial.radius_0 = r0;
+	operand->operand.radial.radius_1 = r1;
+
+	operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT;
+        return CAIRO_STATUS_SUCCESS;
+    }
+
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_gl_operand_init (cairo_gl_context_t *ctx,
+                        cairo_gl_operand_t *operand,
+		        const cairo_pattern_t *pattern,
+		        cairo_gl_surface_t *dst,
+		        int src_x, int src_y,
+		        int dst_x, int dst_y,
+		        int width, int height)
+{
+    cairo_status_t status;
+
+    operand->pattern = pattern;
+
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
+	return _cairo_gl_solid_operand_init (operand,
+		                             &((cairo_solid_pattern_t *) pattern)->color);
+    case CAIRO_PATTERN_TYPE_LINEAR:
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	status = _cairo_gl_gradient_operand_init (ctx, operand, dst);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+
+	/* fall through */
+
+    default:
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	return _cairo_gl_pattern_texture_setup (ctx, operand,
+						pattern, dst,
+						src_x, src_y,
+						dst_x, dst_y,
+						width, height);
+    }
+}
+
+void
+_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
+{
+    switch (operand->type) {
+    case CAIRO_GL_OPERAND_CONSTANT:
+	break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+	glDeleteTextures (1, &operand->operand.linear.tex);
+	break;
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+	glDeleteTextures (1, &operand->operand.radial.tex);
+	break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+	if (operand->operand.texture.surface != NULL) {
+	    cairo_gl_surface_t *surface = operand->operand.texture.surface;
+
+	    _cairo_pattern_release_surface (operand->pattern,
+					    &surface->base,
+					    &operand->operand.texture.attributes);
+	}
+	break;
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+        break;
+    }
+}
+
+static void
+_cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx,
+					  cairo_gl_composite_t *setup,
+					  int tex_unit,
+					  GLfloat *color)
+{
+    if (setup->shader) {
+	const char *uniform_name;
+        cairo_status_t status;
+
+	if (tex_unit == 0)
+	    uniform_name = "source_constant";
+	else
+	    uniform_name = "mask_constant";
+
+	status = bind_vec4_to_shader (ctx,
+                                      setup->shader->program,
+                                      uniform_name,
+                                      color[0],
+                                      color[1],
+                                      color[2],
+                                      color[3]);
+        assert (! _cairo_status_is_error (status));
+
+	return;
+    }
+
+    /* Fall back to fixed function */
+    glActiveTexture (GL_TEXTURE0 + tex_unit);
+    /* Have to have a dummy texture bound in order to use the combiner unit. */
+    glBindTexture (ctx->tex_target, ctx->dummy_tex);
+    glEnable (ctx->tex_target);
+
+    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
+    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+    if (tex_unit == 0) {
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+    } else {
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+    }
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
+    if (tex_unit == 0) {
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+    } else {
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+    }
+}
+
+void
+_cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
+			   cairo_gl_composite_t *setup)
+{
+    cairo_surface_attributes_t *src_attributes;
+    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
+    cairo_status_t status;
+
+    src_attributes = &setup->src.operand.texture.attributes;
+
+    switch (setup->src.type) {
+    case CAIRO_GL_OPERAND_CONSTANT:
+	_cairo_gl_set_tex_combine_constant_color (ctx, setup, 0,
+						  setup->src.operand.constant.color);
+	break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
+				       src_attributes, ctx->tex_target);
+	if (!setup->shader) {
+	    /* Set up the constant color we use to set color to 0 if needed. */
+	    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
+	    /* Set up the combiner to just set color to the sampled texture. */
+	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+
+	    /* Force the src color to 0 if the surface should be
+	     * alpha-only.  We may have a teximage with color bits if
+	     * the implementation doesn't support GL_ALPHA FBOs.
+	     */
+	    if (setup->src.operand.texture.surface->base.content !=
+		CAIRO_CONTENT_ALPHA)
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
+	    else
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+	}
+	break;
+
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+	glActiveTexture (GL_TEXTURE0);
+	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
+	glEnable (GL_TEXTURE_1D);
+
+	status = bind_matrix_to_shader (ctx, setup->shader->program,
+					"source_matrix",
+					&setup->src.operand.linear.m);
+	assert (!_cairo_status_is_error (status));
+
+	status = bind_vec2_to_shader (ctx, setup->shader->program,
+				      "source_segment",
+				      setup->src.operand.linear.segment_x,
+				      setup->src.operand.linear.segment_y);
+	assert (!_cairo_status_is_error (status));
+	break;
+
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+	glActiveTexture (GL_TEXTURE0);
+	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
+	glEnable (GL_TEXTURE_1D);
+
+        status = bind_matrix_to_shader (ctx, setup->shader->program,
+					"source_matrix",
+					&setup->src.operand.radial.m);
+	assert (!_cairo_status_is_error (status));
+
+        status = bind_vec2_to_shader (ctx, setup->shader->program,
+				      "source_circle_1",
+				      setup->src.operand.radial.circle_1_x,
+				      setup->src.operand.radial.circle_1_y);
+	assert (!_cairo_status_is_error (status));
+
+        status = bind_float_to_shader (ctx, setup->shader->program,
+				       "source_radius_0",
+				       setup->src.operand.radial.radius_0);
+	assert (!_cairo_status_is_error (status));
+
+        status = bind_float_to_shader (ctx, setup->shader->program,
+				       "source_radius_1",
+				       setup->src.operand.radial.radius_1);
+	assert (!_cairo_status_is_error (status));
+	break;
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+        break;
+    }
+}
+
+/* This is like _cairo_gl_set_src_operand, but instead swizzles the source
+ * for creating the "source alpha" value (src.aaaa * mask.argb) required by
+ * component alpha rendering.
+ */
+void
+_cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
+				 cairo_gl_composite_t *setup)
+{
+    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
+    cairo_surface_attributes_t *src_attributes;
+
+    src_attributes = &setup->src.operand.texture.attributes;
+
+    switch (setup->src.type) {
+    case CAIRO_GL_OPERAND_CONSTANT:
+	constant_color[0] = setup->src.operand.constant.color[3];
+	constant_color[1] = setup->src.operand.constant.color[3];
+	constant_color[2] = setup->src.operand.constant.color[3];
+	constant_color[3] = setup->src.operand.constant.color[3];
+	_cairo_gl_set_tex_combine_constant_color (ctx, setup, 0,
+						  constant_color);
+	break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
+				       src_attributes, ctx->tex_target);
+	if (!setup->shader) {
+	    /* Set up the combiner to just set color to the sampled texture. */
+	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+	}
+	break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+    case CAIRO_GL_OPERAND_COUNT:
+    default:
+        ASSERT_NOT_REACHED;
+        break;
+    }
+}
+
+static void
+_cairo_gl_set_linear_gradient_mask_operand (cairo_gl_context_t *ctx,
+                                            cairo_gl_composite_t *setup)
+{
+    cairo_status_t status;
+
+    assert(setup->shader);
+
+    glActiveTexture (GL_TEXTURE1);
+    glBindTexture (GL_TEXTURE_1D, setup->mask.operand.linear.tex);
+    glEnable (GL_TEXTURE_1D);
+
+    status = bind_matrix_to_shader (ctx, setup->shader->program,
+			   "mask_matrix", &setup->mask.operand.linear.m);
+    assert (!_cairo_status_is_error (status));
+
+    status = bind_vec2_to_shader (ctx, setup->shader->program,
+			 "mask_segment",
+			 setup->mask.operand.linear.segment_x,
+			 setup->mask.operand.linear.segment_y);
+    assert (!_cairo_status_is_error (status));
+}
+
+static void
+_cairo_gl_set_radial_gradient_mask_operand (cairo_gl_context_t *ctx,
+                                            cairo_gl_composite_t *setup)
+{
+    cairo_status_t status;
+
+    assert(setup->shader);
+
+    glActiveTexture (GL_TEXTURE1);
+    glBindTexture (GL_TEXTURE_1D, setup->mask.operand.radial.tex);
+    glEnable (GL_TEXTURE_1D);
+
+    status = bind_matrix_to_shader (ctx, setup->shader->program,
+				    "mask_matrix",
+				    &setup->mask.operand.radial.m);
+    assert (!_cairo_status_is_error (status));
+
+    status = bind_vec2_to_shader (ctx, setup->shader->program,
+				  "mask_circle_1",
+				  setup->mask.operand.radial.circle_1_x,
+				  setup->mask.operand.radial.circle_1_y);
+    assert (!_cairo_status_is_error (status));
+
+    status = bind_float_to_shader (ctx, setup->shader->program,
+				   "mask_radius_0",
+				   setup->mask.operand.radial.radius_0);
+    assert (!_cairo_status_is_error (status));
+
+    status = bind_float_to_shader (ctx, setup->shader->program,
+				   "mask_radius_1",
+				   setup->mask.operand.radial.radius_1);
+    assert (!_cairo_status_is_error (status));
+}
+
+/* This is like _cairo_gl_set_src_alpha_operand, for component alpha setup
+ * of the mask part of IN to produce a "source alpha" value.
+ */
+void
+_cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
+					    cairo_gl_composite_t *setup)
+{
+    cairo_surface_attributes_t *mask_attributes;
+    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
+
+    mask_attributes = &setup->mask.operand.texture.attributes;
+
+    if (!setup->shader) {
+	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+    }
+
+    switch (setup->mask.type) {
+    case CAIRO_GL_OPERAND_CONSTANT:
+	/* Have to have a dummy texture bound in order to use the combiner unit. */
+	if (setup->shader) {
+            cairo_status_t status;
+	    status = bind_vec4_to_shader (ctx, setup->shader->program,
+                                          "mask_constant",
+                                          setup->src.operand.constant.color[0],
+                                          setup->src.operand.constant.color[1],
+                                          setup->src.operand.constant.color[2],
+                                          setup->src.operand.constant.color[3]);
+            assert (! _cairo_status_is_error (status));
+	} else {
+	    glBindTexture (ctx->tex_target, ctx->dummy_tex);
+	    glActiveTexture (GL_TEXTURE1);
+	    glEnable (ctx->tex_target);
+
+	    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
+			setup->mask.operand.constant.color);
+
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+	}
+	break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+	_cairo_gl_set_texture_surface (1, setup->mask.operand.texture.tex,
+				       mask_attributes, ctx->tex_target);
+	if (!setup->shader) {
+	    /* Set up the constant color we use to set color to 0 if needed. */
+	    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
+
+	    /* Force the mask color to 0 if the surface should be
+	     * alpha-only.  We may have a teximage with color bits if
+	     * the implementation doesn't support GL_ALPHA FBOs.
+	     */
+	    if (setup->mask.operand.texture.surface->base.content !=
+		CAIRO_CONTENT_ALPHA)
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
+	    else
+		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+	}
+	break;
+
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+	_cairo_gl_set_linear_gradient_mask_operand (ctx, setup);
+	break;
+
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+	_cairo_gl_set_radial_gradient_mask_operand (ctx, setup);
+	break;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+    case CAIRO_GL_OPERAND_COUNT:
+    default:
+        ASSERT_NOT_REACHED;
+        break;
+    }
+}
+
+void
+_cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
+			    cairo_gl_composite_t *setup)
+{
+    switch (setup->mask.type) {
+    case CAIRO_GL_OPERAND_CONSTANT:
+        _cairo_gl_set_tex_combine_constant_color (ctx, setup, 1,
+                                                  setup->mask.operand.constant.color);
+        break;
+
+    case CAIRO_GL_OPERAND_TEXTURE:
+        _cairo_gl_set_texture_surface (1, setup->mask.operand.texture.tex,
+                                       &setup->mask.operand.texture.attributes,
+                                       ctx->tex_target);
+
+        if (! setup->shader) {
+            glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+            glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+            glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+            /* IN: dst.argb = src.argb * mask.aaaa */
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+        }
+        break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+        _cairo_gl_set_linear_gradient_mask_operand (ctx, setup);
+        break;
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+        _cairo_gl_set_radial_gradient_mask_operand (ctx, setup);
+        break;
+    case CAIRO_GL_OPERAND_NONE:
+        break;
+    case CAIRO_GL_OPERAND_SPANS:
+    case CAIRO_GL_OPERAND_COUNT:
+    default:
+        ASSERT_NOT_REACHED;
+        break;
+    }
+}
+
+void
+_cairo_gl_composite_fini (cairo_gl_context_t *ctx,
+                          cairo_gl_composite_t *setup)
+{
+    _cairo_gl_operand_destroy (&setup->src);
+    _cairo_gl_operand_destroy (&setup->mask);
+}
+
+cairo_status_t
+_cairo_gl_composite_init (cairo_gl_context_t *ctx,
+                          cairo_gl_composite_t *setup,
+                          cairo_operator_t op,
+                          cairo_gl_surface_t *dst,
+                          const cairo_pattern_t *src,
+                          const cairo_pattern_t *mask,
+                          const cairo_rectangle_int_t *rect)
+{
+    memset (setup, 0, sizeof (cairo_gl_composite_t));
+
+    if (! _cairo_gl_operator_is_supported (op))
+	return UNSUPPORTED ("unsupported operator");
+    
+    return CAIRO_STATUS_SUCCESS;
+}
+
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index c5944e7..6da413c 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -293,6 +293,14 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
 				 cairo_gl_composite_t *setup);
 
 cairo_private void
+_cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
+				            cairo_gl_composite_t *setup);
+
+cairo_private void
+_cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
+			    cairo_gl_composite_t *setup);
+
+cairo_private void
 _cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
 
 cairo_private cairo_bool_t
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index ac8e881..16deaab 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -251,56 +251,6 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
     }
 }
 
-static void
-_cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
-			       cairo_surface_attributes_t *attributes,
-			       GLint tex_target)
-{
-
-    if (tex_target == GL_TEXTURE_RECTANGLE_EXT) {
-	assert (attributes->extend != CAIRO_EXTEND_REPEAT &&
-		attributes->extend != CAIRO_EXTEND_REFLECT);
-    }
-
-    glActiveTexture (GL_TEXTURE0 + tex_unit);
-    glBindTexture (tex_target, tex);
-    switch (attributes->extend) {
-    case CAIRO_EXTEND_NONE:
-	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
-	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
-	break;
-    case CAIRO_EXTEND_PAD:
-	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-	break;
-    case CAIRO_EXTEND_REPEAT:
-	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_REPEAT);
-	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_REPEAT);
-	break;
-    case CAIRO_EXTEND_REFLECT:
-	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
-	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
-	break;
-    }
-    switch (attributes->filter) {
-    case CAIRO_FILTER_FAST:
-    case CAIRO_FILTER_NEAREST:
-	glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri (tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-	break;
-    case CAIRO_FILTER_GOOD:
-    case CAIRO_FILTER_BEST:
-    case CAIRO_FILTER_BILINEAR:
-	glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameteri (tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	break;
-    default:
-    case CAIRO_FILTER_GAUSSIAN:
-	ASSERT_NOT_REACHED;
-    }
-    glEnable (tex_target);
-}
-
 void
 _cairo_gl_surface_init (cairo_device_t *device,
 			cairo_gl_surface_t *surface,
@@ -986,764 +936,6 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static int
-_cairo_gl_gradient_sample_width (const cairo_gradient_pattern_t *gradient)
-{
-    unsigned int n;
-    int width;
-
-    width = 8;
-    for (n = 1; n < gradient->n_stops; n++) {
-	double dx = gradient->stops[n].offset - gradient->stops[n-1].offset;
-	double delta, max;
-	int ramp;
-
-	if (dx == 0)
-	    continue;
-
-	max = gradient->stops[n].color.red -
-	      gradient->stops[n-1].color.red;
-
-	delta = gradient->stops[n].color.green -
-	        gradient->stops[n-1].color.green;
-	if (delta > max)
-	    max = delta;
-
-	delta = gradient->stops[n].color.blue -
-	        gradient->stops[n-1].color.blue;
-	if (delta > max)
-	    max = delta;
-
-	delta = gradient->stops[n].color.alpha -
-	        gradient->stops[n-1].color.alpha;
-	if (delta > max)
-	    max = delta;
-
-	ramp = 128 * max / dx;
-	if (ramp > width)
-	    width = ramp;
-    }
-
-    width = (width + 7) & -8;
-    return MIN (width, 1024);
-}
-
-static cairo_status_t
-_render_gradient (const cairo_gl_context_t *ctx,
-		  cairo_gradient_pattern_t *pattern,
-		  void *bytes,
-		  int width)
-{
-    pixman_image_t *gradient, *image;
-    pixman_gradient_stop_t pixman_stops_stack[32];
-    pixman_gradient_stop_t *pixman_stops;
-    pixman_point_fixed_t p1, p2;
-    unsigned int i;
-
-    pixman_stops = pixman_stops_stack;
-    if (unlikely (pattern->n_stops > ARRAY_LENGTH (pixman_stops_stack))) {
-	pixman_stops = _cairo_malloc_ab (pattern->n_stops,
-					 sizeof (pixman_gradient_stop_t));
-	if (unlikely (pixman_stops == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    for (i = 0; i < pattern->n_stops; i++) {
-	pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
-	pixman_stops[i].color.red   = pattern->stops[i].color.red_short;
-	pixman_stops[i].color.green = pattern->stops[i].color.green_short;
-	pixman_stops[i].color.blue  = pattern->stops[i].color.blue_short;
-	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
-    }
-
-    p1.x = 0;
-    p1.y = 0;
-    p2.x = width << 16;
-    p2.y = 0;
-
-    gradient = pixman_image_create_linear_gradient (&p1, &p2,
-						    pixman_stops,
-						    pattern->n_stops);
-    if (pixman_stops != pixman_stops_stack)
-	free (pixman_stops);
-
-    if (unlikely (gradient == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    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,
-				      bytes, sizeof(uint32_t)*width);
-    if (unlikely (image == NULL)) {
-	pixman_image_unref (gradient);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
-
-    pixman_image_composite32 (PIXMAN_OP_SRC,
-                              gradient, NULL, image,
-                              0, 0,
-                              0, 0,
-                              0, 0,
-                              width, 1);
-
-    pixman_image_unref (gradient);
-    pixman_image_unref (image);
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_gl_create_gradient_texture (const cairo_gl_context_t *ctx,
-				   cairo_gl_surface_t *surface,
-				   cairo_gradient_pattern_t *pattern,
-				   GLuint *tex)
-{
-    int tex_width;
-    GLubyte *data;
-
-    assert (pattern->n_stops != 0);
-
-    tex_width = _cairo_gl_gradient_sample_width (pattern);
-
-    glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, ctx->texture_load_pbo);
-    glBufferDataARB (GL_PIXEL_UNPACK_BUFFER_ARB, tex_width * sizeof (uint32_t), 0, GL_STREAM_DRAW);
-    data = glMapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
-
-    _render_gradient (ctx, pattern, data, tex_width);
-
-    glUnmapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB);
-
-    glGenTextures (1, tex);
-    glBindTexture (GL_TEXTURE_1D, *tex);
-    glTexImage1D (GL_TEXTURE_1D, 0, GL_RGBA8, tex_width, 0,
-                  GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
-
-    glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, 0);
-
-    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-    switch (pattern->base.extend) {
-    case CAIRO_EXTEND_NONE:
-	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
-	break;
-    case CAIRO_EXTEND_PAD:
-	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	break;
-    case CAIRO_EXTEND_REPEAT:
-	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-	break;
-    case CAIRO_EXTEND_REFLECT:
-	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
-	break;
-    }
-}
-
-/**
- * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
- * from dest to src coords.
- */
-static cairo_status_t
-_cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
-                                 cairo_gl_operand_t *operand,
-				 const cairo_pattern_t *src,
-				 cairo_gl_surface_t *dst,
-				 int src_x, int src_y,
-				 int dst_x, int dst_y,
-				 int width, int height)
-{
-    cairo_status_t status;
-    cairo_matrix_t m;
-    cairo_gl_surface_t *surface;
-    cairo_surface_attributes_t *attributes;
-    attributes = &operand->operand.texture.attributes;
-
-    status = _cairo_pattern_acquire_surface (src, &dst->base,
-					     src_x, src_y,
-					     width, height,
-					     CAIRO_PATTERN_ACQUIRE_NONE,
-					     (cairo_surface_t **)
-					     &surface,
-					     attributes);
-    if (unlikely (status))
-	return status;
-
-    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT &&
-	(attributes->extend == CAIRO_EXTEND_REPEAT ||
-	 attributes->extend == CAIRO_EXTEND_REFLECT))
-    {
-	_cairo_pattern_release_surface (operand->pattern,
-					&surface->base,
-					attributes);
-	return UNSUPPORTED ("EXT_texture_rectangle with repeat/reflect");
-    }
-
-    assert (surface->base.backend == &_cairo_gl_surface_backend);
-
-    operand->type = CAIRO_GL_OPERAND_TEXTURE;
-    operand->operand.texture.surface = surface;
-    operand->operand.texture.tex = surface->tex;
-    /* Translate the matrix from
-     * (unnormalized src -> unnormalized src) to
-     * (unnormalized dst -> unnormalized src)
-     */
-    cairo_matrix_init_translate (&m,
-				 src_x - dst_x + attributes->x_offset,
-				 src_y - dst_y + attributes->y_offset);
-    cairo_matrix_multiply (&attributes->matrix,
-			   &m,
-			   &attributes->matrix);
-
-
-    /* Translate the matrix from
-     * (unnormalized dst -> unnormalized src) to
-     * (unnormalized dst -> normalized src)
-     */
-    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT) {
-	cairo_matrix_init_scale (&m,
-				 1.0,
-				 1.0);
-    } else {
-	cairo_matrix_init_scale (&m,
-				 1.0 / surface->width,
-				 1.0 / surface->height);
-    }
-    cairo_matrix_multiply (&attributes->matrix,
-			   &attributes->matrix,
-			   &m);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
-	                      const cairo_color_t *color)
-{
-    operand->type = CAIRO_GL_OPERAND_CONSTANT;
-    operand->operand.constant.color[0] = color->red   * color->alpha;
-    operand->operand.constant.color[1] = color->green * color->alpha;
-    operand->operand.constant.color[2] = color->blue  * color->alpha;
-    operand->operand.constant.color[3] = color->alpha;
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_gradient_operand_init(cairo_gl_context_t *ctx,
-                                cairo_gl_operand_t *operand,
-				cairo_gl_surface_t *dst)
-{
-    cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *)operand->pattern;
-
-    if (! _cairo_gl_device_has_glsl (&ctx->base))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
-	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
-        double x0, y0, x1, y1;
-
-	x0 = _cairo_fixed_to_double (linear->p1.x);
-	x1 = _cairo_fixed_to_double (linear->p2.x);
-	y0 = _cairo_fixed_to_double (linear->p1.y);
-	y1 = _cairo_fixed_to_double (linear->p2.y);
-
-        if ((unsigned int)ctx->max_texture_size / 2 <= gradient->n_stops) {
-            return CAIRO_INT_STATUS_UNSUPPORTED;
-        }
-
-        _cairo_gl_create_gradient_texture (ctx,
-					   dst,
-					   gradient,
-					   &operand->operand.linear.tex);
-
-	/* Translation matrix from the destination fragment coordinates
-	 * (pixels from lower left = 0,0) to the coordinates in the
-	 */
-	cairo_matrix_init_translate (&operand->operand.linear.m, -x0, -y0);
-	cairo_matrix_multiply (&operand->operand.linear.m,
-			       &operand->pattern->matrix,
-			       &operand->operand.linear.m);
-	cairo_matrix_translate (&operand->operand.linear.m, 0, dst->height);
-	cairo_matrix_scale (&operand->operand.linear.m, 1.0, -1.0);
-
-	operand->operand.linear.segment_x = x1 - x0;
-	operand->operand.linear.segment_y = y1 - y0;
-
-	operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
-        return CAIRO_STATUS_SUCCESS;
-    } else {
-	cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
-        double x0, y0, r0, x1, y1, r1;
-
-	x0 = _cairo_fixed_to_double (radial->c1.x);
-	x1 = _cairo_fixed_to_double (radial->c2.x);
-	y0 = _cairo_fixed_to_double (radial->c1.y);
-	y1 = _cairo_fixed_to_double (radial->c2.y);
-	r0 = _cairo_fixed_to_double (radial->r1);
-	r1 = _cairo_fixed_to_double (radial->r2);
-
-        if ((unsigned int)ctx->max_texture_size / 2 <= gradient->n_stops)
-            return CAIRO_INT_STATUS_UNSUPPORTED;
-
-        _cairo_gl_create_gradient_texture (ctx,
-					   dst,
-					   gradient,
-					   &operand->operand.radial.tex);
-
-	/* Translation matrix from the destination fragment coordinates
-	 * (pixels from lower left = 0,0) to the coordinates in the
-	 */
-	cairo_matrix_init_translate (&operand->operand.radial.m, -x0, -y0);
-	cairo_matrix_multiply (&operand->operand.radial.m,
-			       &operand->pattern->matrix,
-			       &operand->operand.radial.m);
-	cairo_matrix_translate (&operand->operand.radial.m, 0, dst->height);
-	cairo_matrix_scale (&operand->operand.radial.m, 1.0, -1.0);
-
-	operand->operand.radial.circle_1_x = x1 - x0;
-	operand->operand.radial.circle_1_y = y1 - y0;
-	operand->operand.radial.radius_0 = r0;
-	operand->operand.radial.radius_1 = r1;
-
-	operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT;
-        return CAIRO_STATUS_SUCCESS;
-    }
-
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-cairo_int_status_t
-_cairo_gl_operand_init (cairo_gl_context_t *ctx,
-                       cairo_gl_operand_t *operand,
-		       const cairo_pattern_t *pattern,
-		       cairo_gl_surface_t *dst,
-		       int src_x, int src_y,
-		       int dst_x, int dst_y,
-		       int width, int height)
-{
-    cairo_status_t status;
-
-    operand->pattern = pattern;
-
-    switch (pattern->type) {
-    case CAIRO_PATTERN_TYPE_SOLID:
-	return _cairo_gl_solid_operand_init (operand,
-		                             &((cairo_solid_pattern_t *) pattern)->color);
-    case CAIRO_PATTERN_TYPE_LINEAR:
-    case CAIRO_PATTERN_TYPE_RADIAL:
-	status = _cairo_gl_gradient_operand_init (ctx, operand, dst);
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-
-	/* fall through */
-
-    default:
-    case CAIRO_PATTERN_TYPE_SURFACE:
-	return _cairo_gl_pattern_texture_setup (ctx, operand,
-						pattern, dst,
-						src_x, src_y,
-						dst_x, dst_y,
-						width, height);
-    }
-}
-
-void
-_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
-{
-    switch (operand->type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-	break;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-	glDeleteTextures (1, &operand->operand.linear.tex);
-	break;
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
-	glDeleteTextures (1, &operand->operand.radial.tex);
-	break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-	if (operand->operand.texture.surface != NULL) {
-	    cairo_gl_surface_t *surface = operand->operand.texture.surface;
-
-	    _cairo_pattern_release_surface (operand->pattern,
-					    &surface->base,
-					    &operand->operand.texture.attributes);
-	}
-	break;
-    default:
-    case CAIRO_GL_OPERAND_COUNT:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_SPANS:
-        break;
-    }
-}
-
-static void
-_cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx,
-					  cairo_gl_composite_t *setup,
-					  int tex_unit,
-					  GLfloat *color)
-{
-    if (setup->shader) {
-	const char *uniform_name;
-        cairo_status_t status;
-
-	if (tex_unit == 0)
-	    uniform_name = "source_constant";
-	else
-	    uniform_name = "mask_constant";
-
-	status = bind_vec4_to_shader (ctx,
-                                      setup->shader->program,
-                                      uniform_name,
-                                      color[0],
-                                      color[1],
-                                      color[2],
-                                      color[3]);
-        assert (! _cairo_status_is_error (status));
-
-	return;
-    }
-
-    /* Fall back to fixed function */
-    glActiveTexture (GL_TEXTURE0 + tex_unit);
-    /* Have to have a dummy texture bound in order to use the combiner unit. */
-    glBindTexture (ctx->tex_target, ctx->dummy_tex);
-    glEnable (ctx->tex_target);
-
-    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
-    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-    if (tex_unit == 0) {
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
-    } else {
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
-    }
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
-    if (tex_unit == 0) {
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-    } else {
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
-    }
-}
-
-void
-_cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
-			   cairo_gl_composite_t *setup)
-{
-    cairo_surface_attributes_t *src_attributes;
-    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
-    cairo_status_t status;
-
-    src_attributes = &setup->src.operand.texture.attributes;
-
-    switch (setup->src.type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-	_cairo_gl_set_tex_combine_constant_color (ctx, setup, 0,
-						  setup->src.operand.constant.color);
-	break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
-				       src_attributes, ctx->tex_target);
-	if (!setup->shader) {
-	    /* Set up the constant color we use to set color to 0 if needed. */
-	    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
-	    /* Set up the combiner to just set color to the sampled texture. */
-	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
-
-	    /* Force the src color to 0 if the surface should be
-	     * alpha-only.  We may have a teximage with color bits if
-	     * the implementation doesn't support GL_ALPHA FBOs.
-	     */
-	    if (setup->src.operand.texture.surface->base.content !=
-		CAIRO_CONTENT_ALPHA)
-		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
-	    else
-		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-	}
-	break;
-
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-	glActiveTexture (GL_TEXTURE0);
-	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
-	glEnable (GL_TEXTURE_1D);
-
-	status = bind_matrix_to_shader (ctx, setup->shader->program,
-					"source_matrix",
-					&setup->src.operand.linear.m);
-	assert (!_cairo_status_is_error (status));
-
-	status = bind_vec2_to_shader (ctx, setup->shader->program,
-				      "source_segment",
-				      setup->src.operand.linear.segment_x,
-				      setup->src.operand.linear.segment_y);
-	assert (!_cairo_status_is_error (status));
-	break;
-
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
-	glActiveTexture (GL_TEXTURE0);
-	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
-	glEnable (GL_TEXTURE_1D);
-
-        status = bind_matrix_to_shader (ctx, setup->shader->program,
-					"source_matrix",
-					&setup->src.operand.radial.m);
-	assert (!_cairo_status_is_error (status));
-
-        status = bind_vec2_to_shader (ctx, setup->shader->program,
-				      "source_circle_1",
-				      setup->src.operand.radial.circle_1_x,
-				      setup->src.operand.radial.circle_1_y);
-	assert (!_cairo_status_is_error (status));
-
-        status = bind_float_to_shader (ctx, setup->shader->program,
-				       "source_radius_0",
-				       setup->src.operand.radial.radius_0);
-	assert (!_cairo_status_is_error (status));
-
-        status = bind_float_to_shader (ctx, setup->shader->program,
-				       "source_radius_1",
-				       setup->src.operand.radial.radius_1);
-	assert (!_cairo_status_is_error (status));
-	break;
-    default:
-    case CAIRO_GL_OPERAND_COUNT:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_SPANS:
-        break;
-    }
-}
-
-/* This is like _cairo_gl_set_src_operand, but instead swizzles the source
- * for creating the "source alpha" value (src.aaaa * mask.argb) required by
- * component alpha rendering.
- */
-void
-_cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
-				 cairo_gl_composite_t *setup)
-{
-    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
-    cairo_surface_attributes_t *src_attributes;
-
-    src_attributes = &setup->src.operand.texture.attributes;
-
-    switch (setup->src.type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-	constant_color[0] = setup->src.operand.constant.color[3];
-	constant_color[1] = setup->src.operand.constant.color[3];
-	constant_color[2] = setup->src.operand.constant.color[3];
-	constant_color[3] = setup->src.operand.constant.color[3];
-	_cairo_gl_set_tex_combine_constant_color (ctx, setup, 0,
-						  constant_color);
-	break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
-				       src_attributes, ctx->tex_target);
-	if (!setup->shader) {
-	    /* Set up the combiner to just set color to the sampled texture. */
-	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
-
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-	}
-	break;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_SPANS:
-    case CAIRO_GL_OPERAND_COUNT:
-    default:
-        ASSERT_NOT_REACHED;
-        break;
-    }
-}
-
-static void
-_cairo_gl_set_linear_gradient_mask_operand (cairo_gl_context_t *ctx,
-                                            cairo_gl_composite_t *setup)
-{
-    cairo_status_t status;
-
-    assert(setup->shader);
-
-    glActiveTexture (GL_TEXTURE1);
-    glBindTexture (GL_TEXTURE_1D, setup->mask.operand.linear.tex);
-    glEnable (GL_TEXTURE_1D);
-
-    status = bind_matrix_to_shader (ctx, setup->shader->program,
-			   "mask_matrix", &setup->mask.operand.linear.m);
-    assert (!_cairo_status_is_error (status));
-
-    status = bind_vec2_to_shader (ctx, setup->shader->program,
-			 "mask_segment",
-			 setup->mask.operand.linear.segment_x,
-			 setup->mask.operand.linear.segment_y);
-    assert (!_cairo_status_is_error (status));
-}
-
-static void
-_cairo_gl_set_radial_gradient_mask_operand (cairo_gl_context_t *ctx,
-                                            cairo_gl_composite_t *setup)
-{
-    cairo_status_t status;
-
-    assert(setup->shader);
-
-    glActiveTexture (GL_TEXTURE1);
-    glBindTexture (GL_TEXTURE_1D, setup->mask.operand.radial.tex);
-    glEnable (GL_TEXTURE_1D);
-
-    status = bind_matrix_to_shader (ctx, setup->shader->program,
-				    "mask_matrix",
-				    &setup->mask.operand.radial.m);
-    assert (!_cairo_status_is_error (status));
-
-    status = bind_vec2_to_shader (ctx, setup->shader->program,
-				  "mask_circle_1",
-				  setup->mask.operand.radial.circle_1_x,
-				  setup->mask.operand.radial.circle_1_y);
-    assert (!_cairo_status_is_error (status));
-
-    status = bind_float_to_shader (ctx, setup->shader->program,
-				   "mask_radius_0",
-				   setup->mask.operand.radial.radius_0);
-    assert (!_cairo_status_is_error (status));
-
-    status = bind_float_to_shader (ctx, setup->shader->program,
-				   "mask_radius_1",
-				   setup->mask.operand.radial.radius_1);
-    assert (!_cairo_status_is_error (status));
-}
-
-/* This is like _cairo_gl_set_src_alpha_operand, for component alpha setup
- * of the mask part of IN to produce a "source alpha" value.
- */
-static void
-_cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
-					    cairo_gl_composite_t *setup)
-{
-    cairo_surface_attributes_t *mask_attributes;
-    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
-
-    mask_attributes = &setup->mask.operand.texture.attributes;
-
-    if (!setup->shader) {
-	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
-
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
-    }
-
-    switch (setup->mask.type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-	/* Have to have a dummy texture bound in order to use the combiner unit. */
-	if (setup->shader) {
-            cairo_status_t status;
-	    status = bind_vec4_to_shader (ctx, setup->shader->program,
-                                          "mask_constant",
-                                          setup->src.operand.constant.color[0],
-                                          setup->src.operand.constant.color[1],
-                                          setup->src.operand.constant.color[2],
-                                          setup->src.operand.constant.color[3]);
-            assert (! _cairo_status_is_error (status));
-	} else {
-	    glBindTexture (ctx->tex_target, ctx->dummy_tex);
-	    glActiveTexture (GL_TEXTURE1);
-	    glEnable (ctx->tex_target);
-
-	    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
-			setup->mask.operand.constant.color);
-
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-	}
-	break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-	_cairo_gl_set_texture_surface (1, setup->mask.operand.texture.tex,
-				       mask_attributes, ctx->tex_target);
-	if (!setup->shader) {
-	    /* Set up the constant color we use to set color to 0 if needed. */
-	    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
-
-	    /* Force the mask color to 0 if the surface should be
-	     * alpha-only.  We may have a teximage with color bits if
-	     * the implementation doesn't support GL_ALPHA FBOs.
-	     */
-	    if (setup->mask.operand.texture.surface->base.content !=
-		CAIRO_CONTENT_ALPHA)
-		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
-	    else
-		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-	}
-	break;
-
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-	_cairo_gl_set_linear_gradient_mask_operand (ctx, setup);
-	break;
-
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
-	_cairo_gl_set_radial_gradient_mask_operand (ctx, setup);
-	break;
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_SPANS:
-    case CAIRO_GL_OPERAND_COUNT:
-    default:
-        ASSERT_NOT_REACHED;
-        break;
-    }
-}
-
-void
-_cairo_gl_composite_fini (cairo_gl_context_t *ctx,
-                          cairo_gl_composite_t *setup)
-{
-    _cairo_gl_operand_destroy (&setup->src);
-    _cairo_gl_operand_destroy (&setup->mask);
-}
-
-cairo_status_t
-_cairo_gl_composite_init (cairo_gl_context_t *ctx,
-                          cairo_gl_composite_t *setup,
-                          cairo_operator_t op,
-                          cairo_gl_surface_t *dst,
-                          const cairo_pattern_t *src,
-                          const cairo_pattern_t *mask,
-                          const cairo_rectangle_int_t *rect)
-{
-    memset (setup, 0, sizeof (cairo_gl_composite_t));
-
-    if (! _cairo_gl_operator_is_supported (op))
-	return UNSUPPORTED ("unsupported operator");
-    
-    return CAIRO_STATUS_SUCCESS;
-}
-
 /**
  * implements component-alpha %CAIRO_OPERATOR_SOURCE using two passes of
  * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
@@ -2093,46 +1285,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     _cairo_gl_set_src_operand (ctx, &setup);
 
     if (mask != NULL) {
-	switch (setup.mask.type) {
-	case CAIRO_GL_OPERAND_CONSTANT:
-	    _cairo_gl_set_tex_combine_constant_color (ctx, &setup, 1,
-						      setup.mask.operand.constant.color);
-	    break;
-
-	case CAIRO_GL_OPERAND_TEXTURE:
-	    _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex,
-					   mask_attributes, ctx->tex_target);
-
-	    if (!setup.shader) {
-		glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-		glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
-		glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
-
-		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
-		glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
-		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-		/* IN: dst.argb = src.argb * mask.aaaa */
-		glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
-		glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
-		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
-		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
-	    }
-	    break;
-	case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-	    _cairo_gl_set_linear_gradient_mask_operand (ctx, &setup);
-	    break;
-	case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
-	    _cairo_gl_set_radial_gradient_mask_operand (ctx, &setup);
-	    break;
-        case CAIRO_GL_OPERAND_NONE:
-        case CAIRO_GL_OPERAND_SPANS:
-        case CAIRO_GL_OPERAND_COUNT:
-        default:
-            ASSERT_NOT_REACHED;
-            break;
-	}
+        _cairo_gl_set_mask_operand (ctx, &setup);
     }
 
     if (clip_region != NULL) {
@@ -2838,7 +1991,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 	_cairo_gl_context_release (renderer->ctx);
 	free (renderer);
 	return _cairo_span_renderer_create_in_error (status);
-}
+    }
 
     src_attributes = &renderer->setup.src.operand.texture.attributes;
 
commit 3ff32b00f0f85a853163c20b101ac5dd6a07da77
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat May 15 18:20:56 2010 +0200

    gl: cairo_gl_compsite_setup_t => cairo_gl_composite_t

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index cba1dff..aee9235 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -257,7 +257,7 @@ typedef struct _cairo_gl_glyphs_setup
     unsigned int vertex_size; /* units of floats */
     unsigned int num_prims;
     float *vb;
-    cairo_gl_composite_setup_t *composite;
+    cairo_gl_composite_t *composite;
     cairo_region_t *clip;
     cairo_gl_surface_t *dst;
     cairo_operator_t op;
@@ -472,7 +472,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     cairo_gl_glyph_cache_t *cache = NULL;
     cairo_gl_context_t *ctx;
     cairo_gl_glyphs_setup_t setup;
-    cairo_gl_composite_setup_t composite_setup;
+    cairo_gl_composite_t composite_setup;
     cairo_status_t status;
     int i = 0;
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index bc7ace4..c5944e7 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -182,11 +182,11 @@ typedef struct cairo_gl_operand {
     const cairo_pattern_t *pattern;
 } cairo_gl_operand_t;
 
-typedef struct _cairo_gl_composite_setup {
+typedef struct _cairo_gl_composite {
     cairo_gl_operand_t src;
     cairo_gl_operand_t mask;
     cairo_gl_shader_program_t *shader;
-} cairo_gl_composite_setup_t;
+} cairo_gl_composite_t;
 
 cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
 
@@ -272,25 +272,25 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
 			cairo_bool_t component_alpha);
 
 cairo_private cairo_status_t
-_cairo_gl_composite_setup_init (cairo_gl_context_t *ctx,
-                                cairo_gl_composite_setup_t *setup,
-                                cairo_operator_t op,
-                                cairo_gl_surface_t *dst,
-                                const cairo_pattern_t *src,
-                                const cairo_pattern_t *mask,
-                                const cairo_rectangle_int_t *rect);
+_cairo_gl_composite_init (cairo_gl_context_t *ctx,
+                          cairo_gl_composite_t *setup,
+                          cairo_operator_t op,
+                          cairo_gl_surface_t *dst,
+                          const cairo_pattern_t *src,
+                          const cairo_pattern_t *mask,
+                          const cairo_rectangle_int_t *rect);
 
 cairo_private void
-_cairo_gl_composite_setup_fini (cairo_gl_context_t *ctx,
-                                  cairo_gl_composite_setup_t *setup);
+_cairo_gl_composite_fini (cairo_gl_context_t *ctx,
+                          cairo_gl_composite_t *setup);
 
 cairo_private void
 _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
-			   cairo_gl_composite_setup_t *setup);
+			   cairo_gl_composite_t *setup);
 
 cairo_private void
 _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
-				 cairo_gl_composite_setup_t *setup);
+				 cairo_gl_composite_t *setup);
 
 cairo_private void
 _cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index dc70436..ac8e881 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1378,7 +1378,7 @@ _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
 
 static void
 _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx,
-					  cairo_gl_composite_setup_t *setup,
+					  cairo_gl_composite_t *setup,
 					  int tex_unit,
 					  GLfloat *color)
 {
@@ -1436,7 +1436,7 @@ _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx,
 
 void
 _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
-			   cairo_gl_composite_setup_t *setup)
+			   cairo_gl_composite_t *setup)
 {
     cairo_surface_attributes_t *src_attributes;
     GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
@@ -1533,7 +1533,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
  */
 void
 _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
-				 cairo_gl_composite_setup_t *setup)
+				 cairo_gl_composite_t *setup)
 {
     GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
     cairo_surface_attributes_t *src_attributes;
@@ -1577,7 +1577,7 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
 
 static void
 _cairo_gl_set_linear_gradient_mask_operand (cairo_gl_context_t *ctx,
-                                            cairo_gl_composite_setup_t *setup)
+                                            cairo_gl_composite_t *setup)
 {
     cairo_status_t status;
 
@@ -1600,7 +1600,7 @@ _cairo_gl_set_linear_gradient_mask_operand (cairo_gl_context_t *ctx,
 
 static void
 _cairo_gl_set_radial_gradient_mask_operand (cairo_gl_context_t *ctx,
-                                            cairo_gl_composite_setup_t *setup)
+                                            cairo_gl_composite_t *setup)
 {
     cairo_status_t status;
 
@@ -1637,7 +1637,7 @@ _cairo_gl_set_radial_gradient_mask_operand (cairo_gl_context_t *ctx,
  */
 static void
 _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
-					    cairo_gl_composite_setup_t *setup)
+					    cairo_gl_composite_t *setup)
 {
     cairo_surface_attributes_t *mask_attributes;
     GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
@@ -1720,23 +1720,23 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
 }
 
 void
-_cairo_gl_composite_setup_fini (cairo_gl_context_t *ctx,
-                                cairo_gl_composite_setup_t *setup)
+_cairo_gl_composite_fini (cairo_gl_context_t *ctx,
+                          cairo_gl_composite_t *setup)
 {
     _cairo_gl_operand_destroy (&setup->src);
     _cairo_gl_operand_destroy (&setup->mask);
 }
 
 cairo_status_t
-cairo_gl_composite_setup_init (cairo_gl_context_t *ctx,
-                               cairo_gl_composite_setup_t *setup,
-                               cairo_operator_t op,
-                               cairo_gl_surface_t *dst,
-                               const cairo_pattern_t *src,
-                               const cairo_pattern_t *mask,
-                               const cairo_rectangle_int_t *rect)
+_cairo_gl_composite_init (cairo_gl_context_t *ctx,
+                          cairo_gl_composite_t *setup,
+                          cairo_operator_t op,
+                          cairo_gl_surface_t *dst,
+                          const cairo_pattern_t *src,
+                          const cairo_pattern_t *mask,
+                          const cairo_rectangle_int_t *rect)
 {
-    memset (setup, 0, sizeof (cairo_gl_composite_setup_t));
+    memset (setup, 0, sizeof (cairo_gl_composite_t));
 
     if (! _cairo_gl_operator_is_supported (op))
 	return UNSUPPORTED ("unsupported operator");
@@ -1820,7 +1820,7 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
     struct gl_point *texcoord_mask = texcoord_mask_stack;
     cairo_status_t status;
     int num_vertices, i;
-    cairo_gl_composite_setup_t setup;
+    cairo_gl_composite_t setup;
     cairo_gl_shader_program_t *ca_source_program = NULL;
     cairo_gl_shader_program_t *ca_source_alpha_program = NULL;
     cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
@@ -1832,7 +1832,7 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_gl_composite_setup_init (ctx, &setup, op, dst, src, mask, &rect);
+    status = _cairo_gl_composite_init (ctx, &setup, op, dst, src, mask, &rect);
     if (unlikely (status))
         goto CLEANUP;
 
@@ -1991,7 +1991,7 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
     glDisable (ctx->tex_target);
 
   CLEANUP:
-    _cairo_gl_composite_setup_fini (ctx, &setup);
+    _cairo_gl_composite_fini (ctx, &setup);
     _cairo_gl_context_release (ctx);
 
     if (vertices != vertices_stack)
@@ -2026,7 +2026,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     struct gl_point *texcoord_mask = texcoord_mask_stack;
     cairo_status_t status;
     int num_vertices, i;
-    cairo_gl_composite_setup_t setup;
+    cairo_gl_composite_t setup;
     cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
 
     if (mask && mask->has_component_alpha) {
@@ -2050,7 +2050,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_gl_composite_setup_init (ctx, &setup, op, dst, src, mask, &rect);
+    status = _cairo_gl_composite_init (ctx, &setup, op, dst, src, mask, &rect);
     if (unlikely (status))
         goto CLEANUP;
 
@@ -2239,7 +2239,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	free (vertices);
 
   CLEANUP:
-    _cairo_gl_composite_setup_fini (ctx, &setup);
+    _cairo_gl_composite_fini (ctx, &setup);
     _cairo_gl_context_release (ctx);
 
     return status;
@@ -2506,7 +2506,7 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
 typedef struct _cairo_gl_surface_span_renderer {
     cairo_span_renderer_t base;
 
-    cairo_gl_composite_setup_t setup;
+    cairo_gl_composite_t setup;
 
     int xmin, xmax;
 
commit c16edee26fb9f1669ee0ce1a61f0c54d802c6c7b
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat May 15 17:33:24 2010 +0200

    gl: use glBlendFuncSeparate()
    
    This way we can treat alpha-only textures correctly and don't have to
    emit different shaders for it. Also gets rid of
    GL_OPERAND_TEXTURE_ALPHA.

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 4f4e865..cba1dff 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -416,8 +416,7 @@ _cairo_gl_glyphs_emit_vertex (cairo_gl_glyphs_setup_t *setup,
     vb[i++] = glyph_x;
     vb[i++] = glyph_y;
 
-    if (setup->composite->src.type == CAIRO_GL_OPERAND_TEXTURE ||
-        setup->composite->src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
+    if (setup->composite->src.type == CAIRO_GL_OPERAND_TEXTURE) {
 	double s = x;
 	double t = y;
 	cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
@@ -517,8 +516,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     setup.clip = clip_region;
     setup.dst = dst;
     setup.vertex_size = 4;
-    if (composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
-        composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA)
+    if (composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE)
 	setup.vertex_size += 2;
     setup.vbo_size = num_glyphs * 4 * setup.vertex_size;
     if (setup.vbo_size > 4096)
@@ -531,8 +529,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
 		     (void *)(uintptr_t)(0));
     glEnableClientState (GL_VERTEX_ARRAY);
-    if (composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
-        composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
+    if (composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
 	/* Note that we're packing texcoord 0 after texcoord 1, for
 	 * convenience.
 	 */
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index fa8b87b..bc7ace4 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -88,7 +88,6 @@ typedef enum cairo_gl_operand_type {
     CAIRO_GL_OPERAND_NONE,
     CAIRO_GL_OPERAND_CONSTANT,
     CAIRO_GL_OPERAND_TEXTURE,
-    CAIRO_GL_OPERAND_TEXTURE_ALPHA,
     CAIRO_GL_OPERAND_LINEAR_GRADIENT,
     CAIRO_GL_OPERAND_RADIAL_GRADIENT,
     CAIRO_GL_OPERAND_SPANS,
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index f1f0bec..7511b4e 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -540,7 +540,6 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
         return CAIRO_GL_VAR_NONE;
     case CAIRO_GL_OPERAND_TEXTURE:
-    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
         return CAIRO_GL_VAR_TEXCOORDS;
     case CAIRO_GL_OPERAND_SPANS:
         return CAIRO_GL_VAR_COVERAGE;
@@ -665,16 +664,6 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
             "}\n",
             rectstr, namestr, namestr, namestr, rectstr, namestr, namestr);
         break;
-    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
-        _cairo_output_stream_printf (stream, 
-            "uniform sampler2D%s %s_sampler;\n"
-            "varying vec2 %s_texcoords;\n"
-            "vec4 get_%s()\n"
-            "{\n"
-            "    return vec4 (0, 0, 0, texture2D%s(%s_sampler, %s_texcoords).a);\n"
-            "}\n",
-            rectstr, namestr, namestr, namestr, rectstr, namestr, namestr);
-        break;
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
         _cairo_output_stream_printf (stream, 
             "uniform sampler1D %s_sampler;\n"
@@ -895,32 +884,6 @@ _cairo_gl_use_program (cairo_gl_context_t *ctx,
     ctx->shader_impl->use_program (program);
 }
 
-#if 0
-/**
- * This function reduces the GLSL program combinations we compile when
- * there are non-functional differences.
- */
-static cairo_gl_shader_program_t *
-_cairo_gl_select_program (cairo_gl_context_t *ctx,
-			  cairo_gl_operand_type_t source,
-			  cairo_gl_operand_type_t mask,
-			  cairo_gl_shader_in_t in)
-{
-    if (in == CAIRO_GL_SHADER_IN_NORMAL &&
-	mask == CAIRO_GL_OPERAND_TEXTURE_ALPHA)
-    {
-	mask = CAIRO_GL_OPERAND_TEXTURE;
-    }
-    if (in == CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA &&
-	source == CAIRO_GL_OPERAND_TEXTURE_ALPHA)
-    {
-	source = CAIRO_GL_OPERAND_TEXTURE;
-    }
-
-    return &ctx->shaders[source][mask][in];
-}
-#endif
-
 cairo_status_t
 _cairo_gl_get_program (cairo_gl_context_t *ctx,
 		       cairo_gl_operand_type_t source,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index fad0050..dc70436 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -244,7 +244,11 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
     }
 
     glEnable (GL_BLEND);
-    glBlendFunc (src_factor, dst_factor);
+    if (dst->base.content == CAIRO_CONTENT_ALPHA) {
+        glBlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
+    } else {
+        glBlendFunc (src_factor, dst_factor);
+    }
 }
 
 static void
@@ -1176,10 +1180,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
 
     assert (surface->base.backend == &_cairo_gl_surface_backend);
 
-    if (surface->base.content == CAIRO_CONTENT_ALPHA)
-        operand->type = CAIRO_GL_OPERAND_TEXTURE_ALPHA;
-    else
-        operand->type = CAIRO_GL_OPERAND_TEXTURE;
+    operand->type = CAIRO_GL_OPERAND_TEXTURE;
     operand->operand.texture.surface = surface;
     operand->operand.texture.tex = surface->tex;
     /* Translate the matrix from
@@ -1358,7 +1359,6 @@ _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
 	glDeleteTextures (1, &operand->operand.radial.tex);
 	break;
     case CAIRO_GL_OPERAND_TEXTURE:
-    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	if (operand->operand.texture.surface != NULL) {
 	    cairo_gl_surface_t *surface = operand->operand.texture.surface;
 
@@ -1450,7 +1450,6 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 						  setup->src.operand.constant.color);
 	break;
     case CAIRO_GL_OPERAND_TEXTURE:
-    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
 				       src_attributes, ctx->tex_target);
 	if (!setup->shader) {
@@ -1551,7 +1550,6 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
 						  constant_color);
 	break;
     case CAIRO_GL_OPERAND_TEXTURE:
-    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
 				       src_attributes, ctx->tex_target);
 	if (!setup->shader) {
@@ -1684,7 +1682,6 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
 	}
 	break;
     case CAIRO_GL_OPERAND_TEXTURE:
-    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	_cairo_gl_set_texture_surface (1, setup->mask.operand.texture.tex,
 				       mask_attributes, ctx->tex_target);
 	if (!setup->shader) {
@@ -1928,8 +1925,7 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
     glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
     glEnableClientState (GL_VERTEX_ARRAY);
 
-    if (setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
-        setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
+    if (setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
 	for (i = 0; i < num_vertices; i++) {
 	    double s, t;
 
@@ -1945,8 +1941,7 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
     }
 
-    if (setup.mask.type == CAIRO_GL_OPERAND_TEXTURE ||
-        setup.mask.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
+    if (setup.mask.type == CAIRO_GL_OPERAND_TEXTURE) {
 	for (i = 0; i < num_vertices; i++) {
 	    double s, t;
 
@@ -2105,7 +2100,6 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	    break;
 
 	case CAIRO_GL_OPERAND_TEXTURE:
-	case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	    _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex,
 					   mask_attributes, ctx->tex_target);
 
@@ -2188,8 +2182,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
     glEnableClientState (GL_VERTEX_ARRAY);
 
-    if (setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
-        setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
+    if (setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
 	for (i = 0; i < num_vertices; i++) {
 	    double s, t;
 
@@ -2206,8 +2199,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     }
 
     if (mask != NULL) {
-        if (setup.mask.type == CAIRO_GL_OPERAND_TEXTURE ||
-	    setup.mask.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
+        if (setup.mask.type == CAIRO_GL_OPERAND_TEXTURE) {
 	    for (i = 0; i < num_vertices; i++) {
 		double s, t;
 
@@ -2572,8 +2564,7 @@ _cairo_gl_span_renderer_get_vbo (cairo_gl_surface_span_renderer_t *renderer,
 	renderer->vbo_size = 16384;
 	glBindBufferARB (GL_ARRAY_BUFFER_ARB, renderer->ctx->vbo);
 
-	if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
-	    renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA)
+	if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE)
 	    renderer->vertex_size = 4 * sizeof (float) + sizeof (uint32_t);
 	else
 	    renderer->vertex_size = 2 * sizeof (float) + sizeof (uint32_t);
@@ -2585,8 +2576,7 @@ _cairo_gl_span_renderer_get_vbo (cairo_gl_surface_span_renderer_t *renderer,
 			(void *) (uintptr_t) (2 * sizeof (float)));
 	glEnableClientState (GL_COLOR_ARRAY);
 
-	if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
-	    renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
+	if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
 	    glClientActiveTexture (GL_TEXTURE0);
 	    glTexCoordPointer (2, GL_FLOAT, renderer->vertex_size,
 			       (void *) (uintptr_t) (2 * sizeof (float) +
@@ -2627,8 +2617,7 @@ _cairo_gl_emit_span_vertex (cairo_gl_surface_span_renderer_t *renderer,
     vertices[v++] = dst_x + BIAS;
     vertices[v++] = dst_y + BIAS;
     vertices[v++] = int_as_float (alpha << 24);
-    if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
-        renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
+    if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE) {
 	double s, t;
 
 	s = dst_x + BIAS;
commit 4f5221a834a883262cce607d247f607d6c200363
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 12 21:12:37 2010 +0200

    gl: acquire device manually in finish, as the default way will error
    
    We'll get CAIRO_STATUS_DEVICE_FINISHED, d'oh

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 7d873dc..2bfeb51 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -60,18 +60,18 @@ _gl_unlock (void *device)
 static void
 _gl_finish (void *device)
 {
-    cairo_gl_context_t *ctx;
+    cairo_gl_context_t *ctx = device;
     int i;
 
-    if (_cairo_gl_context_acquire (device, &ctx) == CAIRO_STATUS_SUCCESS) {
-        for (i = 0; i <= CAIRO_GL_VAR_TYPE_MAX; i++) {
-            destroy_shader (ctx, ctx->vertex_shaders[i]);
-        }
-
-        _cairo_cache_fini (&ctx->shaders);
+    _gl_lock (device);
 
-        _cairo_gl_context_release (ctx);
+    for (i = 0; i <= CAIRO_GL_VAR_TYPE_MAX; i++) {
+        destroy_shader (ctx, ctx->vertex_shaders[i]);
     }
+
+    _cairo_cache_fini (&ctx->shaders);
+
+    _gl_unlock (device);
 }
 
 static void
commit 3f6300444928d12bf4a6e2f6f2c5fec1de7dba8e
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 12 20:53:20 2010 +0200

    gl: Put shaders into a cache
    
    This allows to grow the complexity of the shaders without enlarging the
    static array to unreasonable sizes.
    
    The cache size of 64 is essentially random.

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index ed9b91e..7d873dc 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -68,6 +68,8 @@ _gl_finish (void *device)
             destroy_shader (ctx, ctx->vertex_shaders[i]);
         }
 
+        _cairo_cache_fini (&ctx->shaders);
+
         _cairo_gl_context_release (ctx);
     }
 }
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 347735c..fa8b87b 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -65,6 +65,10 @@
 #define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
 #endif
 
+/* maximal number of shaders we keep in the cache.
+ * Random number that is hopefully big enough to not cause many cache evictions. */
+#define CAIRO_GL_MAX_SHADERS_PER_CONTEXT 64
+
 typedef struct _cairo_gl_surface {
     cairo_surface_t base;
 
@@ -132,9 +136,7 @@ typedef struct _cairo_gl_context {
 
     GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1];
     cairo_gl_shader_program_t fill_rectangles_shader;
-    cairo_gl_shader_program_t shaders[CAIRO_GL_OPERAND_COUNT]
-				     [CAIRO_GL_OPERAND_COUNT]
-				     [CAIRO_GL_SHADER_IN_COUNT];
+    cairo_cache_t shaders;
 
     cairo_gl_surface_t *current_target;
     cairo_gl_glyph_cache_t glyph_cache[2];
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 1a4c9a0..f1f0bec 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -430,9 +430,50 @@ static const cairo_gl_shader_impl_t shader_impl_arb = {
     use_program_arb,
 };
 
+typedef struct _cairo_shader_cache_entry {
+    cairo_cache_entry_t base;
+
+    cairo_gl_operand_type_t src;
+    cairo_gl_operand_type_t mask;
+    cairo_gl_operand_type_t dest;
+    cairo_gl_shader_in_t in;
+
+    cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */
+    cairo_gl_shader_program_t program;
+} cairo_shader_cache_entry_t;
+
+static cairo_bool_t
+_cairo_gl_shader_cache_equal (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;
+}
+
+static unsigned long
+_cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry)
+{
+    return (entry->src << 24) | (entry->mask << 16) | (entry->dest << 8) | (entry->in);
+}
+
+static void
+_cairo_gl_shader_cache_destroy (void *data)
+{
+    cairo_shader_cache_entry_t *entry = data;
+
+    destroy_shader_program (entry->ctx, &entry->program);
+    free (entry);
+}
+
 void
 _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
 {
+    cairo_status_t status;
+
     /* XXX multiple device support? */
     if (GLEW_VERSION_2_0) {
         ctx->shader_impl = &shader_impl_core_2_0;
@@ -445,6 +486,12 @@ _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,
+                                NULL,
+                                _cairo_gl_shader_cache_destroy,
+                                CAIRO_GL_MAX_SHADERS_PER_CONTEXT);
 }
 
 void
@@ -848,6 +895,7 @@ _cairo_gl_use_program (cairo_gl_context_t *ctx,
     ctx->shader_impl->use_program (program);
 }
 
+#if 0
 /**
  * This function reduces the GLSL program combinations we compile when
  * there are non-functional differences.
@@ -871,6 +919,7 @@ _cairo_gl_select_program (cairo_gl_context_t *ctx,
 
     return &ctx->shaders[source][mask][in];
 }
+#endif
 
 cairo_status_t
 _cairo_gl_get_program (cairo_gl_context_t *ctx,
@@ -879,22 +928,30 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
 		       cairo_gl_shader_in_t in,
 		       cairo_gl_shader_program_t **out_program)
 {
-    cairo_gl_shader_program_t *program;
+    cairo_shader_cache_entry_t lookup, *entry;
     char *fs_source;
     cairo_status_t status;
 
-    program = _cairo_gl_select_program(ctx, source, mask, in);
-    if (program->program) {
-	*out_program = program;
-	return CAIRO_STATUS_SUCCESS;
-    }
-
-    if (program->build_failure)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
     if (ctx->shader_impl == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    lookup.src = source;
+    lookup.mask = mask;
+    lookup.dest = CAIRO_GL_OPERAND_NONE;
+    lookup.in = in;
+    lookup.base.hash = _cairo_gl_shader_cache_hash (&lookup);
+    lookup.base.size = 1;
+
+    entry = _cairo_cache_lookup (&ctx->shaders, &lookup.base);
+    if (entry) {
+        if (entry->program.build_failure)
+            return CAIRO_INT_STATUS_UNSUPPORTED;
+
+        assert (entry->program.program);
+	*out_program = &entry->program;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     fs_source = cairo_gl_shader_get_fragment_source (ctx->tex_target,
                                                      in,
                                                      source,
@@ -903,31 +960,49 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     if (unlikely (fs_source == NULL))
 	return CAIRO_STATUS_NO_MEMORY;
 
-    init_shader_program (program);
+    entry = malloc (sizeof (cairo_shader_cache_entry_t));
+    if (unlikely (entry == NULL)) {
+        free (fs_source);
+        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    memcpy (entry, &lookup, sizeof (cairo_shader_cache_entry_t));
+
+    entry->ctx = ctx;
+    init_shader_program (&entry->program);
     status = create_shader_program (ctx,
-                                    program,
+                                    &entry->program,
 				    cairo_gl_operand_get_var_type (source),
 				    cairo_gl_operand_get_var_type (mask),
 				    fs_source);
     free (fs_source);
 
-    if (_cairo_status_is_error (status))
+    if (unlikely (status)) {
+        /* still add to cache, so we know we got a build failure */
+        if (_cairo_status_is_error (status) ||
+            _cairo_cache_insert (&ctx->shaders, &entry->base)) {
+            free (entry);
+        }
+
 	return status;
+    }
 
-    _cairo_gl_use_program (ctx, program);
+    _cairo_gl_use_program (ctx, &entry->program);
     if (source != CAIRO_GL_OPERAND_CONSTANT) {
-	status = bind_texture_to_shader (ctx, program->program, "source_sampler", 0);
+	status = bind_texture_to_shader (ctx, entry->program.program, "source_sampler", 0);
 	assert (!_cairo_status_is_error (status));
     }
     if (mask != CAIRO_GL_OPERAND_CONSTANT &&
 	mask != CAIRO_GL_OPERAND_SPANS &&
 	mask != CAIRO_GL_OPERAND_NONE) {
-	status = bind_texture_to_shader (ctx, program->program, "mask_sampler", 1);
+	status = bind_texture_to_shader (ctx, entry->program.program, "mask_sampler", 1);
 	assert (!_cairo_status_is_error (status));
     }
 
+    status = _cairo_cache_insert (&ctx->shaders, &entry->base);
+
     _cairo_gl_use_program (ctx, NULL);
 
-    *out_program = program;
-    return CAIRO_STATUS_SUCCESS;
+    *out_program = &entry->program;
+    return status;
 }
commit 08b04caf52518f1672694341355b5f5418008e78
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 12 18:10:04 2010 +0200

    gl: Add cairo_gl_composite_setup_init/fini() functions
    
    Simplifies the main code paths, and can be extended to do dest copies.

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 6ea8fb2..347735c 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -270,6 +270,19 @@ cairo_private void
 _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
 			cairo_bool_t component_alpha);
 
+cairo_private cairo_status_t
+_cairo_gl_composite_setup_init (cairo_gl_context_t *ctx,
+                                cairo_gl_composite_setup_t *setup,
+                                cairo_operator_t op,
+                                cairo_gl_surface_t *dst,
+                                const cairo_pattern_t *src,
+                                const cairo_pattern_t *mask,
+                                const cairo_rectangle_int_t *rect);
+
+cairo_private void
+_cairo_gl_composite_setup_fini (cairo_gl_context_t *ctx,
+                                  cairo_gl_composite_setup_t *setup);
+
 cairo_private void
 _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 			   cairo_gl_composite_setup_t *setup);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 69fcc8c..fad0050 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1722,6 +1722,31 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
     }
 }
 
+void
+_cairo_gl_composite_setup_fini (cairo_gl_context_t *ctx,
+                                cairo_gl_composite_setup_t *setup)
+{
+    _cairo_gl_operand_destroy (&setup->src);
+    _cairo_gl_operand_destroy (&setup->mask);
+}
+
+cairo_status_t
+cairo_gl_composite_setup_init (cairo_gl_context_t *ctx,
+                               cairo_gl_composite_setup_t *setup,
+                               cairo_operator_t op,
+                               cairo_gl_surface_t *dst,
+                               const cairo_pattern_t *src,
+                               const cairo_pattern_t *mask,
+                               const cairo_rectangle_int_t *rect)
+{
+    memset (setup, 0, sizeof (cairo_gl_composite_setup_t));
+
+    if (! _cairo_gl_operator_is_supported (op))
+	return UNSUPPORTED ("unsupported operator");
+    
+    return CAIRO_STATUS_SUCCESS;
+}
+
 /**
  * implements component-alpha %CAIRO_OPERATOR_SOURCE using two passes of
  * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
@@ -1801,35 +1826,35 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
     cairo_gl_composite_setup_t setup;
     cairo_gl_shader_program_t *ca_source_program = NULL;
     cairo_gl_shader_program_t *ca_source_alpha_program = NULL;
+    cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
 
     if (op != CAIRO_OPERATOR_OVER && op != CAIRO_OPERATOR_ADD)
 	return UNSUPPORTED ("unsupported component alpha operator");
 
-    memset (&setup, 0, sizeof (setup));
-
     status = _cairo_gl_context_acquire (dst->base.device, &ctx);
     if (unlikely (status))
 	return status;
 
+    status = _cairo_gl_composite_setup_init (ctx, &setup, op, dst, src, mask, &rect);
+    if (unlikely (status))
+        goto CLEANUP;
+
     status = _cairo_gl_operand_init (ctx, &setup.src, src, dst,
 				     src_x, src_y,
 				     dst_x, dst_y,
 				     width, height);
-    if (unlikely (status)) {
-        _cairo_gl_context_release (ctx);
-	return status;
-    }
+    if (unlikely (status))
+        goto CLEANUP;
+
     src_attributes = &setup.src.operand.texture.attributes;
 
     status = _cairo_gl_operand_init (ctx, &setup.mask, mask, dst,
 				     mask_x, mask_y,
 				     dst_x, dst_y,
 				     width, height);
-    if (unlikely (status)) {
-        _cairo_gl_context_release (ctx);
-	_cairo_gl_operand_destroy (&setup.src);
-	return status;
-    }
+    if (unlikely (status))
+        goto CLEANUP;
+
     mask_attributes = &setup.mask.operand.texture.attributes;
 
     /* We'll fall back to fixed function instead. */
@@ -1971,10 +1996,7 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
     glDisable (ctx->tex_target);
 
   CLEANUP:
-    _cairo_gl_operand_destroy (&setup.src);
-    if (mask != NULL)
-	_cairo_gl_operand_destroy (&setup.mask);
-
+    _cairo_gl_composite_setup_fini (ctx, &setup);
     _cairo_gl_context_release (ctx);
 
     if (vertices != vertices_stack)
@@ -2010,6 +2032,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     cairo_status_t status;
     int num_vertices, i;
     cairo_gl_composite_setup_t setup;
+    cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
 
     if (mask && mask->has_component_alpha) {
 	/* Try two-pass component alpha support, or bail. */
@@ -2028,23 +2051,21 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 							   clip_region);
     }
 
-    if (! _cairo_gl_operator_is_supported (op))
-	return UNSUPPORTED ("unsupported operator");
-
-    memset (&setup, 0, sizeof (setup));
-
     status = _cairo_gl_context_acquire (dst->base.device, &ctx);
     if (unlikely (status))
 	return status;
 
+    status = _cairo_gl_composite_setup_init (ctx, &setup, op, dst, src, mask, &rect);
+    if (unlikely (status))
+        goto CLEANUP;
+
     status = _cairo_gl_operand_init (ctx, &setup.src, src, dst,
 				     src_x, src_y,
 				     dst_x, dst_y,
 				     width, height);
-    if (unlikely (status)) {
-        _cairo_gl_context_release (ctx);
-	return status;
-    }
+    if (unlikely (status))
+        goto CLEANUP;
+
     src_attributes = &setup.src.operand.texture.attributes;
 
     if (mask != NULL) {
@@ -2052,14 +2073,10 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 					 mask_x, mask_y,
 					 dst_x, dst_y,
 					 width, height);
-	if (unlikely (status)) {
-	    _cairo_gl_operand_destroy (&setup.src);
-            _cairo_gl_context_release (ctx);
-	    return status;
-	}
+	if (unlikely (status))
+            goto CLEANUP;
+
 	mask_attributes = &setup.mask.operand.texture.attributes;
-    } else {
-        setup.mask.type = CAIRO_GL_OPERAND_NONE;
     }
 
     /* We'll fall back to fixed function instead. */
@@ -2070,7 +2087,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 				    CAIRO_GL_SHADER_IN_NORMAL,
 				    &setup.shader);
     if (_cairo_status_is_error (status))
-	goto CLEANUP_SHADER;
+	goto CLEANUP;
 
     status = CAIRO_STATUS_SUCCESS;
 
@@ -2133,7 +2150,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 					 4*3*sizeof (vertices[0]));
 	    if (unlikely (vertices == NULL)) {
 		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-		goto CLEANUP_SHADER;
+		goto CLEANUP;
 	    }
 
 	    texcoord_src = vertices + num_rectangles * 4;
@@ -2229,14 +2246,10 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     if (vertices != vertices_stack)
 	free (vertices);
 
-  CLEANUP_SHADER:
-    _cairo_gl_operand_destroy (&setup.src);
-    if (mask != NULL)
-	_cairo_gl_operand_destroy (&setup.mask);
-
+  CLEANUP:
+    _cairo_gl_composite_setup_fini (ctx, &setup);
     _cairo_gl_context_release (ctx);
 
-    assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
     return status;
 }
 
commit aa14df0db5e4f236a9668ceda4e148e7d3ba0e9f
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 12 17:01:47 2010 +0200

    gl: move operator check
    
    component alpha compositing checks the operator itself

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 889e41d..69fcc8c 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -2011,9 +2011,6 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     int num_vertices, i;
     cairo_gl_composite_setup_t setup;
 
-    if (! _cairo_gl_operator_is_supported (op))
-	return UNSUPPORTED ("unsupported operator");
-
     if (mask && mask->has_component_alpha) {
 	/* Try two-pass component alpha support, or bail. */
 	return _cairo_gl_surface_composite_component_alpha(op,
@@ -2031,6 +2028,9 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 							   clip_region);
     }
 
+    if (! _cairo_gl_operator_is_supported (op))
+	return UNSUPPORTED ("unsupported operator");
+
     memset (&setup, 0, sizeof (setup));
 
     status = _cairo_gl_context_acquire (dst->base.device, &ctx);
commit a3ee0a7f113ed38df66580ff7e38a79759b0c933
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 12 16:57:32 2010 +0200

    gl: Programmatically generate fragment shaders

diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 240054d..1a4c9a0 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -551,30 +551,187 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
                                    cairo_gl_var_type_t mask,
                                    cairo_gl_var_type_t dest)
 {
-  cairo_output_stream_t *stream = _cairo_memory_stream_create ();
-  unsigned char *source;
-  unsigned int length;
+    cairo_output_stream_t *stream = _cairo_memory_stream_create ();
+    unsigned char *source;
+    unsigned int length;
 
-  cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_OPERAND_SOURCE);
-  cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_OPERAND_MASK);
-  cairo_gl_shader_emit_variable (stream, dest, CAIRO_GL_OPERAND_DEST);
-  
-  _cairo_output_stream_printf (stream, 
-                               "void main()\n"
-                               "{\n"
-                               "    gl_Position = ftransform();\n");
+    cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_OPERAND_SOURCE);
+    cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_OPERAND_MASK);
+    cairo_gl_shader_emit_variable (stream, dest, CAIRO_GL_OPERAND_DEST);
+    
+    _cairo_output_stream_printf (stream, 
+                                 "void main()\n"
+                                 "{\n"
+                                 "    gl_Position = ftransform();\n");
 
-  cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_OPERAND_SOURCE);
-  cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_OPERAND_MASK);
-  cairo_gl_shader_emit_vertex (stream, dest, CAIRO_GL_OPERAND_DEST);
-  
-  _cairo_output_stream_write (stream, 
-                              "}\n\0", 3);
+    cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_OPERAND_SOURCE);
+    cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_OPERAND_MASK);
+    cairo_gl_shader_emit_vertex (stream, dest, CAIRO_GL_OPERAND_DEST);
+    
+    _cairo_output_stream_write (stream, 
+                                "}\n\0", 3);
 
-  if (_cairo_memory_stream_destroy (stream, &source, &length))
-      return NULL;
+    if (_cairo_memory_stream_destroy (stream, &source, &length))
+        return NULL;
 
-  return (char *) source;
+    return (char *) source;
+}
+
+static void
+cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
+                            GLuint tex_target,
+                            cairo_gl_operand_type_t type,
+                            cairo_gl_operand_name_t name)
+{
+    const char *namestr = operand_names[name];
+    const char *rectstr = (tex_target == GL_TEXTURE_RECTANGLE_EXT ? "Rect" : "");
+
+    switch (type) {
+    case CAIRO_GL_OPERAND_COUNT:
+    default:
+        ASSERT_NOT_REACHED;
+        break;
+    case CAIRO_GL_OPERAND_NONE:
+        _cairo_output_stream_printf (stream, 
+            "vec4 get_%s()\n"
+            "{\n"
+            "    return vec4 (0, 0, 0, 1);\n"
+            "}\n",
+            namestr);
+        break;
+    case CAIRO_GL_OPERAND_CONSTANT:
+        _cairo_output_stream_printf (stream, 
+            "uniform vec4 %s_constant;\n"
+            "vec4 get_%s()\n"
+            "{\n"
+            "    return %s_constant;\n"
+            "}\n",
+            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);
+        break;
+    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
+        _cairo_output_stream_printf (stream, 
+            "uniform sampler2D%s %s_sampler;\n"
+            "varying vec2 %s_texcoords;\n"
+            "vec4 get_%s()\n"
+            "{\n"
+            "    return vec4 (0, 0, 0, texture2D%s(%s_sampler, %s_texcoords).a);\n"
+            "}\n",
+            rectstr, namestr, namestr, namestr, rectstr, namestr, namestr);
+        break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+        _cairo_output_stream_printf (stream, 
+            "uniform sampler1D %s_sampler;\n"
+            "uniform mat4 %s_matrix;\n"
+            "uniform vec2 %s_segment;\n"
+            "\n"
+            "vec4 get_%s()\n"
+            "{\n"
+            "    vec2 pos = (%s_matrix * vec4 (gl_FragCoord.xy, 0.0, 1.0)).xy;\n"
+            "    float t = dot (pos, %s_segment) / dot (%s_segment, %s_segment);\n"
+            "    return texture1D (%s_sampler, t);\n"
+            "}\n",
+            namestr, namestr, namestr, namestr, namestr, 
+            namestr, namestr, namestr, namestr);
+        break;
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+        _cairo_output_stream_printf (stream, 
+            "uniform sampler1D %s_sampler;\n"
+            "uniform mat4 %s_matrix;\n"
+            "uniform vec2 %s_circle_1;\n"
+            "uniform float %s_radius_0;\n"
+            "uniform float %s_radius_1;\n"
+            "\n"
+            "vec4 get_%s()\n"
+            "{\n"
+            "    vec2 pos = (%s_matrix * vec4 (gl_FragCoord.xy, 0.0, 1.0)).xy;\n"
+            "    \n"
+            "    float dr = %s_radius_1 - %s_radius_0;\n"
+            "    float dot_circle_1 = dot (%s_circle_1, %s_circle_1);\n"
+            "    float dot_pos_circle_1 = dot (pos, %s_circle_1);\n"
+            "    \n"
+            "    float A = dot_circle_1 - dr * dr;\n"
+            "    float B = -2.0 * (dot_pos_circle_1 + %s_radius_0 * dr);\n"
+            "    float C = dot (pos, pos) - %s_radius_0 * %s_radius_0;\n"
+            "    float det = B * B - 4.0 * A * C;\n"
+            "    det = max (det, 0.0);\n"
+            "    \n"
+            "    float sqrt_det = sqrt (det);\n"
+            "    sqrt_det *= sign(A);\n"
+            "    \n"
+            "    float t = (-B + sqrt_det) / (2.0 * A);\n"
+            "    return texture1D (%s_sampler, t);\n"
+            "}\n",
+            namestr, namestr, namestr, namestr, namestr, 
+            namestr, namestr, namestr, namestr, namestr, 
+            namestr, namestr, namestr, namestr, namestr, 
+            namestr);
+        break;
+    case CAIRO_GL_OPERAND_SPANS:
+        _cairo_output_stream_printf (stream, 
+            "varying float %s_coverage;\n"
+            "vec4 get_%s()\n"
+            "{\n"
+            "    return vec4(0, 0, 0, %s_coverage);\n"
+            "}\n",
+            namestr, namestr, namestr);
+        break;
+    }
+}
+
+static char *
+cairo_gl_shader_get_fragment_source (GLuint tex_target,
+                                     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_output_stream_t *stream = _cairo_memory_stream_create ();
+    unsigned char *source;
+    unsigned int length;
+
+    cairo_gl_shader_emit_color (stream, tex_target, src, CAIRO_GL_OPERAND_SOURCE);
+    cairo_gl_shader_emit_color (stream, tex_target, mask, CAIRO_GL_OPERAND_MASK);
+    if (dest != CAIRO_GL_OPERAND_NONE)
+      cairo_gl_shader_emit_color (stream, tex_target, dest, CAIRO_GL_OPERAND_DEST);
+
+    _cairo_output_stream_printf (stream, 
+        "void main()\n"
+        "{\n");
+    switch (in) {
+    case CAIRO_GL_SHADER_IN_COUNT:
+    default:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_SHADER_IN_NORMAL:
+        _cairo_output_stream_printf (stream, 
+            "    gl_FragColor = get_source() * get_mask().a;\n");
+        break;
+    case CAIRO_GL_SHADER_IN_CA_SOURCE:
+        _cairo_output_stream_printf (stream, 
+            "    gl_FragColor = get_source() * get_mask();\n");
+        break;
+    case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA:
+        _cairo_output_stream_printf (stream, 
+            "    gl_FragColor = get_source().a * get_mask();\n");
+        break;
+    }
+
+    _cairo_output_stream_write (stream, 
+                                "}\n\0", 3);
+
+    if (_cairo_memory_stream_destroy (stream, &source, &length))
+        return NULL;
+
+    return (char *) source;
 }
 
 cairo_status_t
@@ -691,177 +848,6 @@ _cairo_gl_use_program (cairo_gl_context_t *ctx,
     ctx->shader_impl->use_program (program);
 }
 
-static const char *fs_source_constant =
-    "uniform vec4 constant_source;\n"
-    "vec4 get_source()\n"
-    "{\n"
-    "	return constant_source;\n"
-    "}\n";
-static const char *fs_source_texture =
-    "uniform sampler2D source_sampler;\n"
-    "varying vec2 source_texcoords;\n"
-    "vec4 get_source()\n"
-    "{\n"
-    "	return texture2D(source_sampler, source_texcoords);\n"
-    "}\n";
-static const char *fs_source_texture_rect =
-    "uniform sampler2DRect source_sampler;\n"
-    "varying vec2 source_texcoords;\n"
-    "vec4 get_source()\n"
-    "{\n"
-    "	return texture2DRect(source_sampler, source_texcoords);\n"
-    "}\n";
-static const char *fs_source_texture_alpha =
-    "uniform sampler2D source_sampler;\n"
-    "varying vec2 source_texcoords;\n"
-    "vec4 get_source()\n"
-    "{\n"
-    "	return vec4(0, 0, 0, texture2D(source_sampler, source_texcoords).a);\n"
-    "}\n";
-static const char *fs_source_texture_alpha_rect =
-    "uniform sampler2DRect source_sampler;\n"
-    "varying vec2 source_texcoords;\n"
-    "vec4 get_source()\n"
-    "{\n"
-    "	return vec4(0, 0, 0, texture2DRect(source_sampler, source_texcoords).a);\n"
-    "}\n";
-static const char *fs_source_linear_gradient =
-    "uniform sampler1D source_sampler;\n"
-    "uniform mat4 source_matrix;\n"
-    "uniform vec2 source_segment;\n"
-    "\n"
-    "vec4 get_source()\n"
-    "{\n"
-    "    vec2 pos = (source_matrix * vec4 (gl_FragCoord.xy, 0.0, 1.0)).xy;\n"
-    "    float t = dot (pos, source_segment) / dot (source_segment, source_segment);\n"
-    "    return texture1D (source_sampler, t);\n"
-    "}\n";
-static const char *fs_source_radial_gradient =
-    "uniform sampler1D source_sampler;\n"
-    "uniform mat4 source_matrix;\n"
-    "uniform vec2 source_circle_1;\n"
-    "uniform float source_radius_0;\n"
-    "uniform float source_radius_1;\n"
-    "\n"
-    "vec4 get_source()\n"
-    "{\n"
-    "    vec2 pos = (source_matrix * vec4 (gl_FragCoord.xy, 0.0, 1.0)).xy;\n"
-    "    \n"
-    "    float dr = source_radius_1 - source_radius_0;\n"
-    "    float dot_circle_1 = dot (source_circle_1, source_circle_1);\n"
-    "    float dot_pos_circle_1 = dot (pos, source_circle_1);\n"
-    "    \n"
-    "    float A = dot_circle_1 - dr * dr;\n"
-    "    float B = -2.0 * (dot_pos_circle_1 + source_radius_0 * dr);\n"
-    "    float C = dot (pos, pos) - source_radius_0 * source_radius_0;\n"
-    "    float det = B * B - 4.0 * A * C;\n"
-    "    det = max (det, 0.0);\n"
-    "    \n"
-    "    float sqrt_det = sqrt (det);\n"
-    "    sqrt_det *= sign(A);\n"
-    "    \n"
-    "    float t = (-B + sqrt_det) / (2.0 * A);\n"
-    "    return texture1D (source_sampler, t);\n"
-    "}\n";
-static const char *fs_mask_constant =
-    "uniform vec4 constant_mask;\n"
-    "vec4 get_mask()\n"
-    "{\n"
-    "	return constant_mask;\n"
-    "}\n";
-static const char *fs_mask_texture =
-    "uniform sampler2D mask_sampler;\n"
-    "varying vec2 mask_texcoords;\n"
-    "vec4 get_mask()\n"
-    "{\n"
-    "	return texture2D(mask_sampler, mask_texcoords);\n"
-    "}\n";
-static const char *fs_mask_texture_rect =
-    "uniform sampler2DRect mask_sampler;\n"
-    "varying vec2 mask_texcoords;\n"
-    "vec4 get_mask()\n"
-    "{\n"
-    "	return texture2DRect(mask_sampler, mask_texcoords);\n"
-    "}\n";
-static const char *fs_mask_texture_alpha =
-    "uniform sampler2D mask_sampler;\n"
-    "varying vec2 mask_texcoords;\n"
-    "vec4 get_mask()\n"
-    "{\n"
-    "	return vec4(0, 0, 0, texture2D(mask_sampler, mask_texcoords).a);\n"
-    "}\n";
-static const char *fs_mask_texture_alpha_rect =
-    "uniform sampler2DRect mask_sampler;\n"
-    "varying vec2 mask_texcoords;\n"
-    "vec4 get_mask()\n"
-    "{\n"
-    "	return vec4(0, 0, 0, texture2DRect(mask_sampler, mask_texcoords).a);\n"
-    "}\n";
-static const char *fs_mask_linear_gradient =
-    "uniform sampler1D mask_sampler;\n"
-    "uniform mat4 mask_matrix;\n"
-    "uniform vec2 mask_segment;\n"
-    "\n"
-    "vec4 get_mask()\n"
-    "{\n"
-    "    vec2 pos = (mask_matrix * vec4 (gl_FragCoord.xy, 0.0, 1.0)).xy;\n"
-    "    float t = dot (pos, mask_segment) / dot (mask_segment, mask_segment);\n"
-    "    return texture1D (mask_sampler, t);\n"
-    "}\n";
-static const char *fs_mask_radial_gradient =
-    "uniform sampler1D mask_sampler;\n"
-    "uniform mat4 mask_matrix;\n"
-    "uniform vec2 mask_circle_1;\n"
-    "uniform float mask_radius_0;\n"
-    "uniform float mask_radius_1;\n"
-    "\n"
-    "vec4 get_mask()\n"
-    "{\n"
-    "    vec2 pos = (mask_matrix * vec4 (gl_FragCoord.xy, 0.0, 1.0)).xy;\n"
-    "    \n"
-    "    float dr = mask_radius_1 - mask_radius_0;\n"
-    "    float dot_circle_1 = dot (mask_circle_1, mask_circle_1);\n"
-    "    float dot_pos_circle_1 = dot (pos, mask_circle_1);\n"
-    "    \n"
-    "    float A = dot_circle_1 - dr * dr;\n"
-    "    float B = -2.0 * (dot_pos_circle_1 + mask_radius_0 * dr);\n"
-    "    float C = dot (pos, pos) - mask_radius_0 * mask_radius_0;\n"
-    "    float det = B * B - 4.0 * A * C;\n"
-    "    det = max (det, 0.0);\n"
-    "    \n"
-    "    float sqrt_det = sqrt (det);\n"
-    "    sqrt_det *= sign(A);\n"
-    "    \n"
-    "    float t = (-B + sqrt_det) / (2.0 * A);\n"
-    "    return texture1D (mask_sampler, t);\n"
-    "}\n";
-static const char *fs_mask_none =
-    "vec4 get_mask()\n"
-    "{\n"
-    "	return vec4(0, 0, 0, 1);\n"
-    "}\n";
-static const char *fs_mask_spans =
-    "varying float mask_coverage;\n"
-    "vec4 get_mask()\n"
-    "{\n"
-    "	return vec4(0, 0, 0, mask_coverage);\n"
-    "}\n";
-static const char *fs_in_normal =
-    "void main()\n"
-    "{\n"
-    "	gl_FragColor = get_source() * get_mask().a;\n"
-    "}\n";
-static const char *fs_in_component_alpha_source =
-    "void main()\n"
-    "{\n"
-    "	gl_FragColor = get_source() * get_mask();\n"
-    "}\n";
-static const char *fs_in_component_alpha_alpha =
-    "void main()\n"
-    "{\n"
-    "	gl_FragColor = get_source().a * get_mask();\n"
-    "}\n";
-
 /**
  * This function reduces the GLSL program combinations we compile when
  * there are non-functional differences.
@@ -893,38 +879,10 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
 		       cairo_gl_shader_in_t in,
 		       cairo_gl_shader_program_t **out_program)
 {
-    const char *source_sources[CAIRO_GL_OPERAND_COUNT] = {
-        NULL,
-	fs_source_constant,
-	fs_source_texture,
-	fs_source_texture_alpha,
-	fs_source_linear_gradient,
-	fs_source_radial_gradient,
-        NULL
-    };
-    const char *mask_sources[CAIRO_GL_OPERAND_COUNT] = {
-	fs_mask_none,
-	fs_mask_constant,
-	fs_mask_texture,
-	fs_mask_texture_alpha,
-	fs_mask_linear_gradient,
-	fs_mask_radial_gradient,
-	fs_mask_spans
-    };
-    const char *in_sources[CAIRO_GL_SHADER_IN_COUNT] = {
-	fs_in_normal,
-	fs_in_component_alpha_source,
-	fs_in_component_alpha_alpha,
-    };
     cairo_gl_shader_program_t *program;
-    const char *source_source, *mask_source, *in_source;
     char *fs_source;
     cairo_status_t status;
 
-    assert (source < ARRAY_LENGTH (source_sources));
-    assert (source_sources[source] != NULL);
-    assert (mask < ARRAY_LENGTH (mask_sources));
-
     program = _cairo_gl_select_program(ctx, source, mask, in);
     if (program->program) {
 	*out_program = program;
@@ -937,33 +895,13 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     if (ctx->shader_impl == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    source_source = source_sources[source];
-    mask_source = mask_sources[mask];
-    in_source = in_sources[in];
-
-    /* For ARB_texture_rectangle, rewrite sampler2D and texture2D to
-     * sampler2DRect and texture2DRect.
-     */
-    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT) {
-	if (source_source == fs_source_texture)
-	    source_source = fs_source_texture_rect;
-	else if (source_source == fs_source_texture_alpha)
-	    source_source = fs_source_texture_alpha_rect;
-
-	if (mask_source == fs_mask_texture)
-	    mask_source = fs_mask_texture_rect;
-	else if (mask_source == fs_mask_texture_alpha)
-	    mask_source = fs_mask_texture_alpha_rect;
-    }
-
-    fs_source = _cairo_malloc (strlen(source_source) +
-			       strlen(mask_source) +
-			       strlen(in_source) +
-			       1);
+    fs_source = cairo_gl_shader_get_fragment_source (ctx->tex_target,
+                                                     in,
+                                                     source,
+                                                     mask,
+                                                     CAIRO_GL_OPERAND_NONE);
     if (unlikely (fs_source == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    sprintf(fs_source, "%s%s%s", source_source, mask_source, in_source);
+	return CAIRO_STATUS_NO_MEMORY;
 
     init_shader_program (program);
     status = create_shader_program (ctx,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 494a16b..889e41d 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1387,9 +1387,9 @@ _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx,
         cairo_status_t status;
 
 	if (tex_unit == 0)
-	    uniform_name = "constant_source";
+	    uniform_name = "source_constant";
 	else
-	    uniform_name = "constant_mask";
+	    uniform_name = "mask_constant";
 
 	status = bind_vec4_to_shader (ctx,
                                       setup->shader->program,
@@ -1663,7 +1663,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
 	if (setup->shader) {
             cairo_status_t status;
 	    status = bind_vec4_to_shader (ctx, setup->shader->program,
-                                          "constant_mask",
+                                          "mask_constant",
                                           setup->src.operand.constant.color[0],
                                           setup->src.operand.constant.color[1],
                                           setup->src.operand.constant.color[2],
commit fe43b13052f7063f880aeeebda1880a6a2097922
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 12 13:57:06 2010 +0200

    gl: Automatically generate the vertex shader source
    
    The idea is being able to generate shaders from the given input
    on-demand. This allows creating more advanced shaders, such as those
    that include the destination (for self-painting and
    unsupported-by-blending operator) or painting images in weird formats
    (extra translation step in shader, think YUV).

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 2dd225b..ed9b91e 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -64,7 +64,7 @@ _gl_finish (void *device)
     int i;
 
     if (_cairo_gl_context_acquire (device, &ctx) == CAIRO_STATUS_SUCCESS) {
-        for (i = 0; i < CAIRO_GL_VERTEX_SHADER_COUNT; i++) {
+        for (i = 0; i <= CAIRO_GL_VAR_TYPE_MAX; i++) {
             destroy_shader (ctx, ctx->vertex_shaders[i]);
         }
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 0683879..6ea8fb2 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -108,16 +108,14 @@ typedef enum cairo_gl_shader_in {
     CAIRO_GL_SHADER_IN_COUNT
 } cairo_gl_shader_in_t;
 
-typedef enum cairo_gl_vertex_shader {
-  CAIRO_GL_VERTEX_SHADER_EMPTY,
-  CAIRO_GL_VERTEX_SHADER_SOURCE,
-  CAIRO_GL_VERTEX_SHADER_MASK,
-  CAIRO_GL_VERTEX_SHADER_SOURCE_MASK,
-  CAIRO_GL_VERTEX_SHADER_SPANS,
-  CAIRO_GL_VERTEX_SHADER_SOURCE_SPANS,
+typedef enum cairo_gl_var_type {
+  CAIRO_GL_VAR_NONE,
+  CAIRO_GL_VAR_TEXCOORDS,
+  CAIRO_GL_VAR_COVERAGE
+} cairo_gl_var_type_t;
 
-  CAIRO_GL_VERTEX_SHADER_COUNT
-} cairo_gl_vertex_shader_t;
+#define cairo_gl_var_type_hash(src,mask,dest) ((mask) << 2 | (src << 1) | (dest))
+#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_COVERAGE << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
 
 typedef struct _cairo_gl_context {
     cairo_device_t base;
@@ -132,7 +130,7 @@ typedef struct _cairo_gl_context {
 
     const cairo_gl_shader_impl_t *shader_impl;
 
-    GLuint vertex_shaders[CAIRO_GL_VERTEX_SHADER_COUNT];
+    GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1];
     cairo_gl_shader_program_t fill_rectangles_shader;
     cairo_gl_shader_program_t shaders[CAIRO_GL_OPERAND_COUNT]
 				     [CAIRO_GL_OPERAND_COUNT]
@@ -337,7 +335,8 @@ destroy_shader_program (cairo_gl_context_t *ctx,
 cairo_private cairo_status_t
 create_shader_program (cairo_gl_context_t *ctx,
                        cairo_gl_shader_program_t *program,
-                       cairo_gl_vertex_shader_t vertex_shader,
+                       cairo_gl_var_type_t src,
+                       cairo_gl_var_type_t mask,
                        const char *fragment_text);
 
 cairo_private cairo_status_t
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 2e4f732..240054d 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -34,6 +34,7 @@
 #include "cairoint.h"
 #include "cairo-gl-private.h"
 #include "cairo-error-private.h"
+#include "cairo-output-stream-private.h"
 
 typedef struct cairo_gl_shader_impl {
     cairo_status_t
@@ -471,62 +472,120 @@ destroy_shader_program (cairo_gl_context_t *ctx,
         ctx->shader_impl->destroy_program (program->program);
 }
 
-static const char *vs_sources[] = {
-[CAIRO_GL_VERTEX_SHADER_EMPTY] =
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "}\n",
-[CAIRO_GL_VERTEX_SHADER_SOURCE] =
-    "varying vec2 source_texcoords;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "	source_texcoords = gl_MultiTexCoord0.xy;\n"
-    "}\n",
-[CAIRO_GL_VERTEX_SHADER_MASK] =
-    "varying vec2 mask_texcoords;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "	mask_texcoords = gl_MultiTexCoord1.xy;\n"
-    "}\n",
-[CAIRO_GL_VERTEX_SHADER_SOURCE_MASK] =
-    "varying vec2 source_texcoords;\n"
-    "varying vec2 mask_texcoords;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "	source_texcoords = gl_MultiTexCoord0.xy;\n"
-    "	mask_texcoords = gl_MultiTexCoord1.xy;\n"
-    "}\n",
-[CAIRO_GL_VERTEX_SHADER_SPANS] =
-    "varying float coverage;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "   coverage = gl_Color.a;\n"
-    "}\n",
-[CAIRO_GL_VERTEX_SHADER_SOURCE_SPANS] =
-    "varying vec2 source_texcoords;\n"
-    "varying float coverage;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "	source_texcoords = gl_MultiTexCoord0.xy;\n"
-    "   coverage = gl_Color.a;\n"
-    "}\n"
-};
+typedef enum cairo_gl_operand_target {
+  CAIRO_GL_OPERAND_SOURCE,
+  CAIRO_GL_OPERAND_MASK,
+  CAIRO_GL_OPERAND_DEST
+} cairo_gl_operand_name_t;
+
+static const char *operand_names[] = { "source", "mask", "dest" };
+
+static cairo_gl_var_type_t
+cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
+{
+    switch (type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_CONSTANT:
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+        return CAIRO_GL_VAR_NONE;
+    case CAIRO_GL_OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
+        return CAIRO_GL_VAR_TEXCOORDS;
+    case CAIRO_GL_OPERAND_SPANS:
+        return CAIRO_GL_VAR_COVERAGE;
+    }
+}
+
+static void
+cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
+                               cairo_gl_var_type_t type,
+                               cairo_gl_operand_name_t name)
+{
+    switch (type) {
+    default:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_VAR_NONE:
+        break;
+    case CAIRO_GL_VAR_TEXCOORDS:
+        _cairo_output_stream_printf (stream, 
+                                     "varying vec2 %s_texcoords;\n", 
+                                     operand_names[name]);
+        break;
+    case CAIRO_GL_VAR_COVERAGE:
+        _cairo_output_stream_printf (stream, 
+                                     "varying float %s_coverage;\n", 
+                                     operand_names[name]);
+        break;
+    }
+}
+
+static void
+cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
+                             cairo_gl_var_type_t type,
+                             cairo_gl_operand_name_t name)
+{
+    switch (type) {
+    default:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_VAR_NONE:
+        break;
+    case CAIRO_GL_VAR_TEXCOORDS:
+        _cairo_output_stream_printf (stream, 
+                                     "    %s_texcoords = gl_MultiTexCoord%d.xy;\n",
+                                     operand_names[name], name);
+        break;
+    case CAIRO_GL_VAR_COVERAGE:
+        _cairo_output_stream_printf (stream, 
+                                     "    %s_coverage = gl_Color.a;\n",
+                                     operand_names[name]);
+        break;
+    }
+}
+
+static char *
+cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
+                                   cairo_gl_var_type_t mask,
+                                   cairo_gl_var_type_t dest)
+{
+  cairo_output_stream_t *stream = _cairo_memory_stream_create ();
+  unsigned char *source;
+  unsigned int length;
+
+  cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_OPERAND_SOURCE);
+  cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_OPERAND_MASK);
+  cairo_gl_shader_emit_variable (stream, dest, CAIRO_GL_OPERAND_DEST);
+  
+  _cairo_output_stream_printf (stream, 
+                               "void main()\n"
+                               "{\n"
+                               "    gl_Position = ftransform();\n");
+
+  cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_OPERAND_SOURCE);
+  cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_OPERAND_MASK);
+  cairo_gl_shader_emit_vertex (stream, dest, CAIRO_GL_OPERAND_DEST);
+  
+  _cairo_output_stream_write (stream, 
+                              "}\n\0", 3);
+
+  if (_cairo_memory_stream_destroy (stream, &source, &length))
+      return NULL;
+
+  return (char *) source;
+}
 
 cairo_status_t
 create_shader_program (cairo_gl_context_t *ctx,
                        cairo_gl_shader_program_t *program,
-                       cairo_gl_vertex_shader_t vertex_shader,
+                       cairo_gl_var_type_t src,
+                       cairo_gl_var_type_t mask,
                        const char *fragment_text)
 {
     cairo_status_t status;
-
-    assert (vertex_shader < ARRAY_LENGTH (vs_sources));
+    unsigned int vertex_shader;
 
     if (program->program != 0)
         return CAIRO_STATUS_SUCCESS;
@@ -537,10 +596,16 @@ create_shader_program (cairo_gl_context_t *ctx,
     if (ctx->shader_impl == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    vertex_shader = cairo_gl_var_type_hash (src, mask, CAIRO_GL_VAR_NONE);
     if (ctx->vertex_shaders[vertex_shader] == 0) {
+        char *source = cairo_gl_shader_get_vertex_source (src, mask, CAIRO_GL_VAR_NONE);
+        if (unlikely (source == NULL))
+            goto FAILURE;
+
         status = ctx->shader_impl->compile_shader (&ctx->vertex_shaders[vertex_shader],
                                                    GL_VERTEX_SHADER,
-                                                   vs_sources[vertex_shader]);
+                                                   source);
+        free (source);
         if (unlikely (status))
             goto FAILURE;
     }
@@ -776,10 +841,10 @@ static const char *fs_mask_none =
     "	return vec4(0, 0, 0, 1);\n"
     "}\n";
 static const char *fs_mask_spans =
-    "varying float coverage;\n"
+    "varying float mask_coverage;\n"
     "vec4 get_mask()\n"
     "{\n"
-    "	return vec4(0, 0, 0, coverage);\n"
+    "	return vec4(0, 0, 0, mask_coverage);\n"
     "}\n";
 static const char *fs_in_normal =
     "void main()\n"
@@ -853,7 +918,6 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     };
     cairo_gl_shader_program_t *program;
     const char *source_source, *mask_source, *in_source;
-    cairo_gl_vertex_shader_t vs;
     char *fs_source;
     cairo_status_t status;
 
@@ -899,34 +963,13 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     if (unlikely (fs_source == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    if (source == CAIRO_GL_OPERAND_CONSTANT ||
-	source == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
-	source == CAIRO_GL_OPERAND_RADIAL_GRADIENT) {
-	if (mask == CAIRO_GL_OPERAND_SPANS)
-	    vs = CAIRO_GL_VERTEX_SHADER_SPANS;
-	else if (mask == CAIRO_GL_OPERAND_CONSTANT ||
-		 mask == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
-		 mask == CAIRO_GL_OPERAND_RADIAL_GRADIENT)
-	    vs = CAIRO_GL_VERTEX_SHADER_EMPTY;
-	else
-	    vs = CAIRO_GL_VERTEX_SHADER_MASK;
-    } else {
-	if (mask == CAIRO_GL_OPERAND_SPANS)
-	    vs = CAIRO_GL_VERTEX_SHADER_SOURCE_SPANS;
-	else if (mask == CAIRO_GL_OPERAND_CONSTANT ||
-		 mask == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
-		 mask == CAIRO_GL_OPERAND_RADIAL_GRADIENT)
-	    vs = CAIRO_GL_VERTEX_SHADER_SOURCE;
-	else
-	    vs = CAIRO_GL_VERTEX_SHADER_SOURCE_MASK;
-    }
-
     sprintf(fs_source, "%s%s%s", source_source, mask_source, in_source);
 
     init_shader_program (program);
     status = create_shader_program (ctx,
                                     program,
-				    vs,
+				    cairo_gl_operand_get_var_type (source),
+				    cairo_gl_operand_get_var_type (mask),
 				    fs_source);
     free (fs_source);
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index ad80632..494a16b 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -2412,7 +2412,8 @@ _cairo_gl_surface_fill_rectangles_glsl (void                  *abstract_surface,
 
     status = create_shader_program (ctx,
                                     &ctx->fill_rectangles_shader,
-                                    CAIRO_GL_VERTEX_SHADER_EMPTY,
+                                    CAIRO_GL_VAR_NONE,
+                                    CAIRO_GL_VAR_NONE,
 				    fill_fs_source);
     if (unlikely (status)) {
 	_cairo_gl_context_release (ctx);
commit 405eee07ad9a5bc325b339b8588facb905fb28f5
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 12 00:02:28 2010 +0200

    gl: Get rid of cairo_gl_shader_source/mask_t
    
    Use the cairo_gl_operand_type_t instead. Those enums are pretty much
    identical.

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 07bd698..4f4e865 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -320,8 +320,8 @@ _cairo_gl_glyphs_set_shader (cairo_gl_context_t *ctx,
 	cairo_status_t status;
 
 	status = _cairo_gl_get_program (ctx,
-					setup->composite->src.source,
-					CAIRO_GL_SHADER_MASK_TEXTURE,
+					setup->composite->src.type,
+					CAIRO_GL_OPERAND_TEXTURE,
 					in,
 					&setup->composite->shader);
 	if (!_cairo_status_is_error (status)) {
@@ -416,7 +416,8 @@ _cairo_gl_glyphs_emit_vertex (cairo_gl_glyphs_setup_t *setup,
     vb[i++] = glyph_x;
     vb[i++] = glyph_y;
 
-    if (setup->composite->src.type == OPERAND_TEXTURE) {
+    if (setup->composite->src.type == CAIRO_GL_OPERAND_TEXTURE ||
+        setup->composite->src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
 	double s = x;
 	double t = y;
 	cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
@@ -516,7 +517,8 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     setup.clip = clip_region;
     setup.dst = dst;
     setup.vertex_size = 4;
-    if (composite_setup.src.type == OPERAND_TEXTURE)
+    if (composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
+        composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA)
 	setup.vertex_size += 2;
     setup.vbo_size = num_glyphs * 4 * setup.vertex_size;
     if (setup.vbo_size > 4096)
@@ -529,7 +531,8 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
 		     (void *)(uintptr_t)(0));
     glEnableClientState (GL_VERTEX_ARRAY);
-    if (composite_setup.src.type == OPERAND_TEXTURE) {
+    if (composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
+        composite_setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
 	/* Note that we're packing texcoord 0 after texcoord 1, for
 	 * convenience.
 	 */
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 777f12c..0683879 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -80,6 +80,18 @@ typedef struct cairo_gl_glyph_cache {
     unsigned int width, height;
 } cairo_gl_glyph_cache_t;
 
+typedef enum cairo_gl_operand_type {
+    CAIRO_GL_OPERAND_NONE,
+    CAIRO_GL_OPERAND_CONSTANT,
+    CAIRO_GL_OPERAND_TEXTURE,
+    CAIRO_GL_OPERAND_TEXTURE_ALPHA,
+    CAIRO_GL_OPERAND_LINEAR_GRADIENT,
+    CAIRO_GL_OPERAND_RADIAL_GRADIENT,
+    CAIRO_GL_OPERAND_SPANS,
+
+    CAIRO_GL_OPERAND_COUNT
+} cairo_gl_operand_type_t;
+
 typedef struct cairo_gl_shader_impl cairo_gl_shader_impl_t;
 
 typedef struct cairo_gl_shader_program {
@@ -88,28 +100,6 @@ typedef struct cairo_gl_shader_program {
     cairo_bool_t build_failure;
 } cairo_gl_shader_program_t;
 
-typedef enum cairo_gl_shader_source {
-    CAIRO_GL_SHADER_SOURCE_CONSTANT,
-    CAIRO_GL_SHADER_SOURCE_TEXTURE,
-    CAIRO_GL_SHADER_SOURCE_TEXTURE_ALPHA,
-    CAIRO_GL_SHADER_SOURCE_LINEAR_GRADIENT,
-    CAIRO_GL_SHADER_SOURCE_RADIAL_GRADIENT,
-
-    CAIRO_GL_SHADER_SOURCE_COUNT
-} cairo_gl_shader_source_t;
-
-typedef enum cairo_gl_shader_mask {
-    CAIRO_GL_SHADER_MASK_CONSTANT,
-    CAIRO_GL_SHADER_MASK_TEXTURE,
-    CAIRO_GL_SHADER_MASK_TEXTURE_ALPHA,
-    CAIRO_GL_SHADER_MASK_LINEAR_GRADIENT,
-    CAIRO_GL_SHADER_MASK_RADIAL_GRADIENT,
-    CAIRO_GL_SHADER_MASK_NONE,
-    CAIRO_GL_SHADER_MASK_SPANS,
-
-    CAIRO_GL_SHADER_MASK_COUNT
-} cairo_gl_shader_mask_t;
-
 typedef enum cairo_gl_shader_in {
     CAIRO_GL_SHADER_IN_NORMAL,
     CAIRO_GL_SHADER_IN_CA_SOURCE,
@@ -144,9 +134,9 @@ typedef struct _cairo_gl_context {
 
     GLuint vertex_shaders[CAIRO_GL_VERTEX_SHADER_COUNT];
     cairo_gl_shader_program_t fill_rectangles_shader;
-    cairo_gl_shader_program_t shaders[CAIRO_GL_SHADER_SOURCE_COUNT]
-					[CAIRO_GL_SHADER_MASK_COUNT]
-					[CAIRO_GL_SHADER_IN_COUNT];
+    cairo_gl_shader_program_t shaders[CAIRO_GL_OPERAND_COUNT]
+				     [CAIRO_GL_OPERAND_COUNT]
+				     [CAIRO_GL_SHADER_IN_COUNT];
 
     cairo_gl_surface_t *current_target;
     cairo_gl_glyph_cache_t glyph_cache[2];
@@ -160,20 +150,11 @@ typedef struct _cairo_gl_context {
     void (*destroy) (void *ctx);
 } cairo_gl_context_t;
 
-enum cairo_gl_composite_operand_type {
-    OPERAND_CONSTANT,
-    OPERAND_TEXTURE,
-    OPERAND_LINEAR_GRADIENT,
-    OPERAND_RADIAL_GRADIENT,
-};
-
 /* This union structure describes a potential source or mask operand to the
  * compositing equation.
  */
-typedef struct cairo_gl_composite_operand {
-    enum cairo_gl_composite_operand_type type;
-    cairo_gl_shader_source_t source;
-    cairo_gl_shader_mask_t mask;
+typedef struct cairo_gl_operand {
+    cairo_gl_operand_type_t type;
     union {
 	struct {
 	    GLuint tex;
@@ -200,11 +181,11 @@ typedef struct cairo_gl_composite_operand {
     } operand;
 
     const cairo_pattern_t *pattern;
-} cairo_gl_composite_operand_t;
+} cairo_gl_operand_t;
 
 typedef struct _cairo_gl_composite_setup {
-    cairo_gl_composite_operand_t src;
-    cairo_gl_composite_operand_t mask;
+    cairo_gl_operand_t src;
+    cairo_gl_operand_t mask;
     cairo_gl_shader_program_t *shader;
 } cairo_gl_composite_setup_t;
 
@@ -240,7 +221,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 
 cairo_private cairo_int_status_t
 _cairo_gl_operand_init (cairo_gl_context_t *ctx,
-                        cairo_gl_composite_operand_t *operand,
+                        cairo_gl_operand_t *operand,
 			const cairo_pattern_t *pattern,
 			cairo_gl_surface_t *dst,
 			int src_x, int src_y,
@@ -300,7 +281,7 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
 				 cairo_gl_composite_setup_t *setup);
 
 cairo_private void
-_cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand);
+_cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
 
 cairo_private cairo_bool_t
 _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
@@ -395,8 +376,8 @@ _cairo_gl_use_program (cairo_gl_context_t *ctx,
 
 cairo_private cairo_status_t
 _cairo_gl_get_program (cairo_gl_context_t *ctx,
-		       cairo_gl_shader_source_t source,
-		       cairo_gl_shader_mask_t mask,
+		       cairo_gl_operand_type_t source,
+		       cairo_gl_operand_type_t mask,
 		       cairo_gl_shader_in_t in,
 		       cairo_gl_shader_program_t **out_program);
 
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index e454278..2e4f732 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -803,19 +803,19 @@ static const char *fs_in_component_alpha_alpha =
  */
 static cairo_gl_shader_program_t *
 _cairo_gl_select_program (cairo_gl_context_t *ctx,
-			  cairo_gl_shader_source_t source,
-			  cairo_gl_shader_mask_t mask,
+			  cairo_gl_operand_type_t source,
+			  cairo_gl_operand_type_t mask,
 			  cairo_gl_shader_in_t in)
 {
     if (in == CAIRO_GL_SHADER_IN_NORMAL &&
-	mask == CAIRO_GL_SHADER_MASK_TEXTURE_ALPHA)
+	mask == CAIRO_GL_OPERAND_TEXTURE_ALPHA)
     {
-	mask = CAIRO_GL_SHADER_MASK_TEXTURE;
+	mask = CAIRO_GL_OPERAND_TEXTURE;
     }
     if (in == CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA &&
-	source == CAIRO_GL_SHADER_SOURCE_TEXTURE_ALPHA)
+	source == CAIRO_GL_OPERAND_TEXTURE_ALPHA)
     {
-	source = CAIRO_GL_SHADER_SOURCE_TEXTURE;
+	source = CAIRO_GL_OPERAND_TEXTURE;
     }
 
     return &ctx->shaders[source][mask][in];
@@ -823,26 +823,28 @@ _cairo_gl_select_program (cairo_gl_context_t *ctx,
 
 cairo_status_t
 _cairo_gl_get_program (cairo_gl_context_t *ctx,
-		       cairo_gl_shader_source_t source,
-		       cairo_gl_shader_mask_t mask,
+		       cairo_gl_operand_type_t source,
+		       cairo_gl_operand_type_t mask,
 		       cairo_gl_shader_in_t in,
 		       cairo_gl_shader_program_t **out_program)
 {
-    const char *source_sources[CAIRO_GL_SHADER_SOURCE_COUNT] = {
+    const char *source_sources[CAIRO_GL_OPERAND_COUNT] = {
+        NULL,
 	fs_source_constant,
 	fs_source_texture,
 	fs_source_texture_alpha,
 	fs_source_linear_gradient,
 	fs_source_radial_gradient,
+        NULL
     };
-    const char *mask_sources[CAIRO_GL_SHADER_MASK_COUNT] = {
+    const char *mask_sources[CAIRO_GL_OPERAND_COUNT] = {
+	fs_mask_none,
 	fs_mask_constant,
 	fs_mask_texture,
 	fs_mask_texture_alpha,
 	fs_mask_linear_gradient,
 	fs_mask_radial_gradient,
-	fs_mask_none,
-	fs_mask_spans,
+	fs_mask_spans
     };
     const char *in_sources[CAIRO_GL_SHADER_IN_COUNT] = {
 	fs_in_normal,
@@ -855,6 +857,10 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     char *fs_source;
     cairo_status_t status;
 
+    assert (source < ARRAY_LENGTH (source_sources));
+    assert (source_sources[source] != NULL);
+    assert (mask < ARRAY_LENGTH (mask_sources));
+
     program = _cairo_gl_select_program(ctx, source, mask, in);
     if (program->program) {
 	*out_program = program;
@@ -893,23 +899,23 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     if (unlikely (fs_source == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    if (source == CAIRO_GL_SHADER_SOURCE_CONSTANT ||
-	source == CAIRO_GL_SHADER_SOURCE_LINEAR_GRADIENT ||
-	source == CAIRO_GL_SHADER_SOURCE_RADIAL_GRADIENT) {
-	if (mask == CAIRO_GL_SHADER_MASK_SPANS)
+    if (source == CAIRO_GL_OPERAND_CONSTANT ||
+	source == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
+	source == CAIRO_GL_OPERAND_RADIAL_GRADIENT) {
+	if (mask == CAIRO_GL_OPERAND_SPANS)
 	    vs = CAIRO_GL_VERTEX_SHADER_SPANS;
-	else if (mask == CAIRO_GL_SHADER_MASK_CONSTANT ||
-		 mask == CAIRO_GL_SHADER_MASK_LINEAR_GRADIENT ||
-		 mask == CAIRO_GL_SHADER_MASK_RADIAL_GRADIENT)
+	else if (mask == CAIRO_GL_OPERAND_CONSTANT ||
+		 mask == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
+		 mask == CAIRO_GL_OPERAND_RADIAL_GRADIENT)
 	    vs = CAIRO_GL_VERTEX_SHADER_EMPTY;
 	else
 	    vs = CAIRO_GL_VERTEX_SHADER_MASK;
     } else {
-	if (mask == CAIRO_GL_SHADER_MASK_SPANS)
+	if (mask == CAIRO_GL_OPERAND_SPANS)
 	    vs = CAIRO_GL_VERTEX_SHADER_SOURCE_SPANS;
-	else if (mask == CAIRO_GL_SHADER_MASK_CONSTANT ||
-		 mask == CAIRO_GL_SHADER_MASK_LINEAR_GRADIENT ||
-		 mask == CAIRO_GL_SHADER_MASK_RADIAL_GRADIENT)
+	else if (mask == CAIRO_GL_OPERAND_CONSTANT ||
+		 mask == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
+		 mask == CAIRO_GL_OPERAND_RADIAL_GRADIENT)
 	    vs = CAIRO_GL_VERTEX_SHADER_SOURCE;
 	else
 	    vs = CAIRO_GL_VERTEX_SHADER_SOURCE_MASK;
@@ -928,13 +934,13 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
 	return status;
 
     _cairo_gl_use_program (ctx, program);
-    if (source != CAIRO_GL_SHADER_SOURCE_CONSTANT) {
+    if (source != CAIRO_GL_OPERAND_CONSTANT) {
 	status = bind_texture_to_shader (ctx, program->program, "source_sampler", 0);
 	assert (!_cairo_status_is_error (status));
     }
-    if (mask != CAIRO_GL_SHADER_MASK_CONSTANT &&
-	mask != CAIRO_GL_SHADER_MASK_SPANS &&
-	mask != CAIRO_GL_SHADER_MASK_NONE) {
+    if (mask != CAIRO_GL_OPERAND_CONSTANT &&
+	mask != CAIRO_GL_OPERAND_SPANS &&
+	mask != CAIRO_GL_OPERAND_NONE) {
 	status = bind_texture_to_shader (ctx, program->program, "mask_sampler", 1);
 	assert (!_cairo_status_is_error (status));
     }
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 2ea6717..ad80632 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -644,8 +644,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	    cairo_gl_shader_program_t *program;
 
 	    status = _cairo_gl_get_program (ctx,
-					    CAIRO_GL_SHADER_SOURCE_TEXTURE,
-					    CAIRO_GL_SHADER_MASK_NONE,
+					    CAIRO_GL_OPERAND_TEXTURE,
+					    CAIRO_GL_OPERAND_NONE,
 					    CAIRO_GL_SHADER_IN_NORMAL,
 					    &program);
 	    if (_cairo_status_is_error (status)) {
@@ -1141,7 +1141,7 @@ _cairo_gl_create_gradient_texture (const cairo_gl_context_t *ctx,
  */
 static cairo_status_t
 _cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
-                                 cairo_gl_composite_operand_t *operand,
+                                 cairo_gl_operand_t *operand,
 				 const cairo_pattern_t *src,
 				 cairo_gl_surface_t *dst,
 				 int src_x, int src_y,
@@ -1176,15 +1176,12 @@ _cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
 
     assert (surface->base.backend == &_cairo_gl_surface_backend);
 
+    if (surface->base.content == CAIRO_CONTENT_ALPHA)
+        operand->type = CAIRO_GL_OPERAND_TEXTURE_ALPHA;
+    else
+        operand->type = CAIRO_GL_OPERAND_TEXTURE;
     operand->operand.texture.surface = surface;
     operand->operand.texture.tex = surface->tex;
-    if (surface->base.content != CAIRO_CONTENT_ALPHA) {
-	operand->source = CAIRO_GL_SHADER_SOURCE_TEXTURE;
-	operand->mask = CAIRO_GL_SHADER_MASK_TEXTURE;
-    } else {
-	operand->source = CAIRO_GL_SHADER_SOURCE_TEXTURE_ALPHA;
-	operand->mask = CAIRO_GL_SHADER_MASK_TEXTURE_ALPHA;
-    }
     /* Translate the matrix from
      * (unnormalized src -> unnormalized src) to
      * (unnormalized dst -> unnormalized src)
@@ -1218,12 +1215,10 @@ _cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
 }
 
 static cairo_status_t
-_cairo_gl_solid_operand_init (cairo_gl_composite_operand_t *operand,
+_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
 	                      const cairo_color_t *color)
 {
-    operand->type = OPERAND_CONSTANT;
-    operand->source = CAIRO_GL_SHADER_SOURCE_CONSTANT;
-    operand->mask = CAIRO_GL_SHADER_MASK_CONSTANT;
+    operand->type = CAIRO_GL_OPERAND_CONSTANT;
     operand->operand.constant.color[0] = color->red   * color->alpha;
     operand->operand.constant.color[1] = color->green * color->alpha;
     operand->operand.constant.color[2] = color->blue  * color->alpha;
@@ -1233,7 +1228,7 @@ _cairo_gl_solid_operand_init (cairo_gl_composite_operand_t *operand,
 
 static cairo_status_t
 _cairo_gl_gradient_operand_init(cairo_gl_context_t *ctx,
-                                cairo_gl_composite_operand_t *operand,
+                                cairo_gl_operand_t *operand,
 				cairo_gl_surface_t *dst)
 {
     cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *)operand->pattern;
@@ -1272,9 +1267,7 @@ _cairo_gl_gradient_operand_init(cairo_gl_context_t *ctx,
 	operand->operand.linear.segment_x = x1 - x0;
 	operand->operand.linear.segment_y = y1 - y0;
 
-	operand->type = OPERAND_LINEAR_GRADIENT;
-	operand->source = CAIRO_GL_SHADER_SOURCE_LINEAR_GRADIENT;
-	operand->mask = CAIRO_GL_SHADER_MASK_LINEAR_GRADIENT;
+	operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
         return CAIRO_STATUS_SUCCESS;
     } else {
 	cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
@@ -1310,9 +1303,7 @@ _cairo_gl_gradient_operand_init(cairo_gl_context_t *ctx,
 	operand->operand.radial.radius_0 = r0;
 	operand->operand.radial.radius_1 = r1;
 
-	operand->type = OPERAND_RADIAL_GRADIENT;
-	operand->source = CAIRO_GL_SHADER_SOURCE_RADIAL_GRADIENT;
-	operand->mask = CAIRO_GL_SHADER_MASK_RADIAL_GRADIENT;
+	operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT;
         return CAIRO_STATUS_SUCCESS;
     }
 
@@ -1321,7 +1312,7 @@ _cairo_gl_gradient_operand_init(cairo_gl_context_t *ctx,
 
 cairo_int_status_t
 _cairo_gl_operand_init (cairo_gl_context_t *ctx,
-                       cairo_gl_composite_operand_t *operand,
+                       cairo_gl_operand_t *operand,
 		       const cairo_pattern_t *pattern,
 		       cairo_gl_surface_t *dst,
 		       int src_x, int src_y,
@@ -1346,7 +1337,6 @@ _cairo_gl_operand_init (cairo_gl_context_t *ctx,
 
     default:
     case CAIRO_PATTERN_TYPE_SURFACE:
-	operand->type = OPERAND_TEXTURE;
 	return _cairo_gl_pattern_texture_setup (ctx, operand,
 						pattern, dst,
 						src_x, src_y,
@@ -1356,18 +1346,19 @@ _cairo_gl_operand_init (cairo_gl_context_t *ctx,
 }
 
 void
-_cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand)
+_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
 {
     switch (operand->type) {
-    case OPERAND_CONSTANT:
+    case CAIRO_GL_OPERAND_CONSTANT:
 	break;
-    case OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
 	glDeleteTextures (1, &operand->operand.linear.tex);
 	break;
-    case OPERAND_RADIAL_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
 	glDeleteTextures (1, &operand->operand.radial.tex);
 	break;
-    case OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	if (operand->operand.texture.surface != NULL) {
 	    cairo_gl_surface_t *surface = operand->operand.texture.surface;
 
@@ -1376,6 +1367,12 @@ _cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand)
 					    &operand->operand.texture.attributes);
 	}
 	break;
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+        break;
     }
 }
 
@@ -1448,11 +1445,12 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
     src_attributes = &setup->src.operand.texture.attributes;
 
     switch (setup->src.type) {
-    case OPERAND_CONSTANT:
+    case CAIRO_GL_OPERAND_CONSTANT:
 	_cairo_gl_set_tex_combine_constant_color (ctx, setup, 0,
 						  setup->src.operand.constant.color);
 	break;
-    case OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
 				       src_attributes, ctx->tex_target);
 	if (!setup->shader) {
@@ -1478,7 +1476,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 	}
 	break;
 
-    case OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
 	glActiveTexture (GL_TEXTURE0);
 	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
 	glEnable (GL_TEXTURE_1D);
@@ -1495,7 +1493,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 	assert (!_cairo_status_is_error (status));
 	break;
 
-    case OPERAND_RADIAL_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
 	glActiveTexture (GL_TEXTURE0);
 	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
 	glEnable (GL_TEXTURE_1D);
@@ -1521,6 +1519,12 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 				       setup->src.operand.radial.radius_1);
 	assert (!_cairo_status_is_error (status));
 	break;
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+        break;
     }
 }
 
@@ -1538,7 +1542,7 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
     src_attributes = &setup->src.operand.texture.attributes;
 
     switch (setup->src.type) {
-    case OPERAND_CONSTANT:
+    case CAIRO_GL_OPERAND_CONSTANT:
 	constant_color[0] = setup->src.operand.constant.color[3];
 	constant_color[1] = setup->src.operand.constant.color[3];
 	constant_color[2] = setup->src.operand.constant.color[3];
@@ -1546,7 +1550,8 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
 	_cairo_gl_set_tex_combine_constant_color (ctx, setup, 0,
 						  constant_color);
 	break;
-    case OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
 				       src_attributes, ctx->tex_target);
 	if (!setup->shader) {
@@ -1561,9 +1566,14 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
 	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 	}
 	break;
-    case OPERAND_LINEAR_GRADIENT:
-    case OPERAND_RADIAL_GRADIENT:
-	assert(0);
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+    case CAIRO_GL_OPERAND_COUNT:
+    default:
+        ASSERT_NOT_REACHED;
+        break;
     }
 }
 
@@ -1648,7 +1658,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
     }
 
     switch (setup->mask.type) {
-    case OPERAND_CONSTANT:
+    case CAIRO_GL_OPERAND_CONSTANT:
 	/* Have to have a dummy texture bound in order to use the combiner unit. */
 	if (setup->shader) {
             cairo_status_t status;
@@ -1673,7 +1683,8 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
 	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 	}
 	break;
-    case OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_TEXTURE:
+    case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	_cairo_gl_set_texture_surface (1, setup->mask.operand.texture.tex,
 				       mask_attributes, ctx->tex_target);
 	if (!setup->shader) {
@@ -1695,13 +1706,19 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
 	}
 	break;
 
-    case OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
 	_cairo_gl_set_linear_gradient_mask_operand (ctx, setup);
 	break;
 
-    case OPERAND_RADIAL_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
 	_cairo_gl_set_radial_gradient_mask_operand (ctx, setup);
 	break;
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+    case CAIRO_GL_OPERAND_COUNT:
+    default:
+        ASSERT_NOT_REACHED;
+        break;
     }
 }
 
@@ -1820,16 +1837,16 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
     ca_source_alpha_program = NULL;
 
     status = _cairo_gl_get_program (ctx,
-				    setup.src.source,
-				    setup.mask.mask,
+				    setup.src.type,
+				    setup.mask.type,
 				    CAIRO_GL_SHADER_IN_CA_SOURCE,
 				    &ca_source_program);
     if (_cairo_status_is_error (status))
 	goto CLEANUP;
 
     status = _cairo_gl_get_program (ctx,
-				    setup.src.source,
-				    setup.mask.mask,
+				    setup.src.type,
+				    setup.mask.type,
 				    CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
 				    &ca_source_alpha_program);
     if (_cairo_status_is_error (status))
@@ -1886,7 +1903,8 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
     glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
     glEnableClientState (GL_VERTEX_ARRAY);
 
-    if (setup.src.type == OPERAND_TEXTURE) {
+    if (setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
+        setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
 	for (i = 0; i < num_vertices; i++) {
 	    double s, t;
 
@@ -1902,7 +1920,8 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
     }
 
-    if (setup.mask.type == OPERAND_TEXTURE) {
+    if (setup.mask.type == CAIRO_GL_OPERAND_TEXTURE ||
+        setup.mask.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
 	for (i = 0; i < num_vertices; i++) {
 	    double s, t;
 
@@ -2040,14 +2059,14 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	}
 	mask_attributes = &setup.mask.operand.texture.attributes;
     } else {
-	setup.mask.mask = CAIRO_GL_SHADER_MASK_NONE;
+        setup.mask.type = CAIRO_GL_OPERAND_NONE;
     }
 
     /* We'll fall back to fixed function instead. */
     setup.shader = NULL;
     status = _cairo_gl_get_program (ctx,
-				    setup.src.source,
-				    setup.mask.mask,
+                                    setup.src.type,
+                                    setup.mask.type,
 				    CAIRO_GL_SHADER_IN_NORMAL,
 				    &setup.shader);
     if (_cairo_status_is_error (status))
@@ -2063,12 +2082,13 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 
     if (mask != NULL) {
 	switch (setup.mask.type) {
-	case OPERAND_CONSTANT:
+	case CAIRO_GL_OPERAND_CONSTANT:
 	    _cairo_gl_set_tex_combine_constant_color (ctx, &setup, 1,
 						      setup.mask.operand.constant.color);
 	    break;
 
-	case OPERAND_TEXTURE:
+	case CAIRO_GL_OPERAND_TEXTURE:
+	case CAIRO_GL_OPERAND_TEXTURE_ALPHA:
 	    _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex,
 					   mask_attributes, ctx->tex_target);
 
@@ -2089,12 +2109,18 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 		glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 	    }
 	    break;
-	case OPERAND_LINEAR_GRADIENT:
+	case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
 	    _cairo_gl_set_linear_gradient_mask_operand (ctx, &setup);
 	    break;
-	case OPERAND_RADIAL_GRADIENT:
+	case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
 	    _cairo_gl_set_radial_gradient_mask_operand (ctx, &setup);
 	    break;
+        case CAIRO_GL_OPERAND_NONE:
+        case CAIRO_GL_OPERAND_SPANS:
+        case CAIRO_GL_OPERAND_COUNT:
+        default:
+            ASSERT_NOT_REACHED;
+            break;
 	}
     }
 
@@ -2145,7 +2171,8 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
     glEnableClientState (GL_VERTEX_ARRAY);
 
-    if (setup.src.type == OPERAND_TEXTURE) {
+    if (setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
+        setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
 	for (i = 0; i < num_vertices; i++) {
 	    double s, t;
 
@@ -2162,7 +2189,8 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     }
 
     if (mask != NULL) {
-	if (setup.mask.type == OPERAND_TEXTURE) {
+        if (setup.mask.type == CAIRO_GL_OPERAND_TEXTURE ||
+	    setup.mask.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
 	    for (i = 0; i < num_vertices; i++) {
 		double s, t;
 
@@ -2530,7 +2558,8 @@ _cairo_gl_span_renderer_get_vbo (cairo_gl_surface_span_renderer_t *renderer,
 	renderer->vbo_size = 16384;
 	glBindBufferARB (GL_ARRAY_BUFFER_ARB, renderer->ctx->vbo);
 
-	if (renderer->setup.src.type == OPERAND_TEXTURE)
+	if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
+	    renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA)
 	    renderer->vertex_size = 4 * sizeof (float) + sizeof (uint32_t);
 	else
 	    renderer->vertex_size = 2 * sizeof (float) + sizeof (uint32_t);
@@ -2542,7 +2571,8 @@ _cairo_gl_span_renderer_get_vbo (cairo_gl_surface_span_renderer_t *renderer,
 			(void *) (uintptr_t) (2 * sizeof (float)));
 	glEnableClientState (GL_COLOR_ARRAY);
 
-	if (renderer->setup.src.type == OPERAND_TEXTURE) {
+	if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
+	    renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
 	    glClientActiveTexture (GL_TEXTURE0);
 	    glTexCoordPointer (2, GL_FLOAT, renderer->vertex_size,
 			       (void *) (uintptr_t) (2 * sizeof (float) +
@@ -2583,7 +2613,8 @@ _cairo_gl_emit_span_vertex (cairo_gl_surface_span_renderer_t *renderer,
     vertices[v++] = dst_x + BIAS;
     vertices[v++] = dst_y + BIAS;
     vertices[v++] = int_as_float (alpha << 24);
-    if (renderer->setup.src.type == OPERAND_TEXTURE) {
+    if (renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE ||
+        renderer->setup.src.type == CAIRO_GL_OPERAND_TEXTURE_ALPHA) {
 	double s, t;
 
 	s = dst_x + BIAS;
@@ -2795,8 +2826,8 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     _cairo_gl_context_set_destination (renderer->ctx, dst);
 
     status = _cairo_gl_get_program (renderer->ctx,
-				    renderer->setup.src.source,
-				    CAIRO_GL_SHADER_MASK_SPANS,
+				    renderer->setup.src.type,
+				    CAIRO_GL_OPERAND_SPANS,
 				    CAIRO_GL_SHADER_IN_NORMAL,
 				    &renderer->setup.shader);
     if (_cairo_status_is_error (status)) {
commit 5149bb87d7b547766ce6ff4976217454adbab562
Author: Benjamin Otte <otte at redhat.com>
Date:   Tue May 11 21:35:13 2010 +0200

    gl: s/_cairo_gl_set_destination/_cairo_gl_context_set_destination/
    
    It's an operation on the context, so name it accordingly

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 7455f96..2dd225b 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -182,7 +182,7 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 }
 
 void
-_cairo_gl_set_destination (cairo_gl_context_t *ctx,
+_cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
                            cairo_gl_surface_t *surface)
 {
     if (ctx->current_target != surface) {
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 217f4fb..07bd698 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -494,7 +494,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	return status;
     }
 
-    _cairo_gl_set_destination (ctx, dst);
+    _cairo_gl_context_set_destination (ctx, dst);
 
     _cairo_scaled_font_freeze_cache (scaled_font);
     if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 93aa830..777f12c 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -279,7 +279,7 @@ _cairo_gl_context_acquire (cairo_device_t *device,
 } while (0)
 
 cairo_private void
-_cairo_gl_set_destination (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface);
+_cairo_gl_context_set_destination (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface);
 
 cairo_private cairo_bool_t
 _cairo_gl_operator_is_supported (cairo_operator_t op);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index cf9547c..2ea6717 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -396,7 +396,7 @@ _cairo_gl_surface_clear (cairo_gl_surface_t *surface)
     if (unlikely (status))
 	return status;
 
-    _cairo_gl_set_destination (ctx, surface);
+    _cairo_gl_context_set_destination (ctx, surface);
     if (surface->base.content == CAIRO_CONTENT_COLOR)
 	glClearColor (0.0, 0.0, 0.0, 1.0);
     else
@@ -660,7 +660,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 
 	status = CAIRO_STATUS_SUCCESS;
 
-	_cairo_gl_set_destination (ctx, dst);
+	_cairo_gl_context_set_destination (ctx, dst);
 
 	glGenTextures (1, &tex);
 	glActiveTexture (GL_TEXTURE0);
@@ -779,7 +779,7 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
     if (unlikely (status))
         return status;
-    _cairo_gl_set_destination (ctx, surface);
+    _cairo_gl_context_set_destination (ctx, surface);
 
     glPixelStorei (GL_PACK_ALIGNMENT, 1);
     glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
@@ -1837,7 +1837,7 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
 
     status = CAIRO_STATUS_SUCCESS;
 
-    _cairo_gl_set_destination (ctx, dst);
+    _cairo_gl_context_set_destination (ctx, dst);
 
     if (clip_region != NULL) {
 	int num_rectangles;
@@ -2055,7 +2055,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 
     status = CAIRO_STATUS_SUCCESS;
 
-    _cairo_gl_set_destination (ctx, dst);
+    _cairo_gl_context_set_destination (ctx, dst);
     _cairo_gl_set_operator (dst, op, FALSE);
 
     _cairo_gl_use_program (ctx, setup.shader);
@@ -2291,7 +2291,7 @@ _cairo_gl_surface_fill_rectangles_fixed (void			 *abstract_surface,
     if (unlikely (status))
 	return status;
 
-    _cairo_gl_set_destination (ctx, surface);
+    _cairo_gl_context_set_destination (ctx, surface);
     _cairo_gl_set_operator (surface, op, FALSE);
 
     if (num_rects > N_STACK_RECTS) {
@@ -2404,7 +2404,7 @@ _cairo_gl_surface_fill_rectangles_glsl (void                  *abstract_surface,
 
     _cairo_gl_use_program (ctx, &ctx->fill_rectangles_shader);
 
-    _cairo_gl_set_destination (ctx, surface);
+    _cairo_gl_context_set_destination (ctx, surface);
     _cairo_gl_set_operator (surface, op, FALSE);
 
     status = bind_vec4_to_shader (ctx,
@@ -2792,7 +2792,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 	return _cairo_span_renderer_create_in_error (status);
     }
 
-    _cairo_gl_set_destination (renderer->ctx, dst);
+    _cairo_gl_context_set_destination (renderer->ctx, dst);
 
     status = _cairo_gl_get_program (renderer->ctx,
 				    renderer->setup.src.source,
commit 9f34e403f38192d711304fbde4dedbaa8e15fd6e
Author: Benjamin Otte <otte at redhat.com>
Date:   Tue May 11 13:15:16 2010 +0200

    gl: Share vertex shaders
    
    Previously, we created a new vertex shader for every shader program we
    used. Now the code shares identical vertex shaders between programs.

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index ab1010d..7455f96 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -58,6 +58,21 @@ _gl_unlock (void *device)
 }
 
 static void
+_gl_finish (void *device)
+{
+    cairo_gl_context_t *ctx;
+    int i;
+
+    if (_cairo_gl_context_acquire (device, &ctx) == CAIRO_STATUS_SUCCESS) {
+        for (i = 0; i < CAIRO_GL_VERTEX_SHADER_COUNT; i++) {
+            destroy_shader (ctx, ctx->vertex_shaders[i]);
+        }
+
+        _cairo_gl_context_release (ctx);
+    }
+}
+
+static void
 _gl_destroy (void *device)
 {
     cairo_gl_context_t *ctx = device;
@@ -90,7 +105,7 @@ static const cairo_device_backend_t _cairo_gl_device_backend = {
     _gl_unlock,
 
     NULL, /* flush */
-    NULL, /* finish */
+    _gl_finish,
     _gl_destroy,
 };
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 83836e7..93aa830 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -83,7 +83,6 @@ typedef struct cairo_gl_glyph_cache {
 typedef struct cairo_gl_shader_impl cairo_gl_shader_impl_t;
 
 typedef struct cairo_gl_shader_program {
-    GLuint vertex_shader;
     GLuint fragment_shader;
     GLuint program;
     cairo_bool_t build_failure;
@@ -95,7 +94,8 @@ typedef enum cairo_gl_shader_source {
     CAIRO_GL_SHADER_SOURCE_TEXTURE_ALPHA,
     CAIRO_GL_SHADER_SOURCE_LINEAR_GRADIENT,
     CAIRO_GL_SHADER_SOURCE_RADIAL_GRADIENT,
-    CAIRO_GL_SHADER_SOURCE_COUNT,
+
+    CAIRO_GL_SHADER_SOURCE_COUNT
 } cairo_gl_shader_source_t;
 
 typedef enum cairo_gl_shader_mask {
@@ -106,16 +106,29 @@ typedef enum cairo_gl_shader_mask {
     CAIRO_GL_SHADER_MASK_RADIAL_GRADIENT,
     CAIRO_GL_SHADER_MASK_NONE,
     CAIRO_GL_SHADER_MASK_SPANS,
-    CAIRO_GL_SHADER_MASK_COUNT,
+
+    CAIRO_GL_SHADER_MASK_COUNT
 } cairo_gl_shader_mask_t;
 
 typedef enum cairo_gl_shader_in {
     CAIRO_GL_SHADER_IN_NORMAL,
     CAIRO_GL_SHADER_IN_CA_SOURCE,
     CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
-    CAIRO_GL_SHADER_IN_COUNT,
+
+    CAIRO_GL_SHADER_IN_COUNT
 } cairo_gl_shader_in_t;
 
+typedef enum cairo_gl_vertex_shader {
+  CAIRO_GL_VERTEX_SHADER_EMPTY,
+  CAIRO_GL_VERTEX_SHADER_SOURCE,
+  CAIRO_GL_VERTEX_SHADER_MASK,
+  CAIRO_GL_VERTEX_SHADER_SOURCE_MASK,
+  CAIRO_GL_VERTEX_SHADER_SPANS,
+  CAIRO_GL_VERTEX_SHADER_SOURCE_SPANS,
+
+  CAIRO_GL_VERTEX_SHADER_COUNT
+} cairo_gl_vertex_shader_t;
+
 typedef struct _cairo_gl_context {
     cairo_device_t base;
 
@@ -129,6 +142,7 @@ typedef struct _cairo_gl_context {
 
     const cairo_gl_shader_impl_t *shader_impl;
 
+    GLuint vertex_shaders[CAIRO_GL_VERTEX_SHADER_COUNT];
     cairo_gl_shader_program_t fill_rectangles_shader;
     cairo_gl_shader_program_t shaders[CAIRO_GL_SHADER_SOURCE_COUNT]
 					[CAIRO_GL_SHADER_MASK_COUNT]
@@ -330,6 +344,9 @@ cairo_private void
 _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx);
 
 cairo_private void
+destroy_shader (cairo_gl_context_t *ctx, GLuint shader);
+
+cairo_private void
 init_shader_program (cairo_gl_shader_program_t *program);
 
 cairo_private void
@@ -339,7 +356,7 @@ destroy_shader_program (cairo_gl_context_t *ctx,
 cairo_private cairo_status_t
 create_shader_program (cairo_gl_context_t *ctx,
                        cairo_gl_shader_program_t *program,
-                       const char *vertex_text,
+                       cairo_gl_vertex_shader_t vertex_shader,
                        const char *fragment_text);
 
 cairo_private cairo_status_t
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 8aa464e..e454278 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -43,7 +43,10 @@ typedef struct cairo_gl_shader_impl {
     (*link_shader) (GLuint *program, GLuint vert, GLuint frag);
 
     void
-    (*destroy_shader_program) (cairo_gl_shader_program_t *program);
+    (*destroy_shader) (GLuint shader);
+
+    void
+    (*destroy_program) (GLuint program);
 
     cairo_status_t
     (*bind_float_to_shader) (GLuint program, const char *name,
@@ -144,14 +147,15 @@ link_shader_arb (GLuint *program, GLuint vert, GLuint frag)
 }
 
 static void
-destroy_shader_program_arb (cairo_gl_shader_program_t *program)
+destroy_shader_arb (GLuint shader)
 {
-    if (program->vertex_shader)
-        glDeleteObjectARB (program->vertex_shader);
-    if (program->fragment_shader)
-        glDeleteObjectARB (program->fragment_shader);
-    if (program->program)
-        glDeleteObjectARB (program->program);
+  glDeleteObjectARB (shader);
+}
+
+static void
+destroy_program_arb (GLuint shader)
+{
+  glDeleteObjectARB (shader);
 }
 
 static cairo_status_t
@@ -305,11 +309,15 @@ link_shader_core_2_0 (GLuint *program, GLuint vert, GLuint frag)
 }
 
 static void
-destroy_shader_program_core_2_0 (cairo_gl_shader_program_t *program)
+destroy_shader_core_2_0 (GLuint shader)
+{
+  glDeleteShader (shader);
+}
+
+static void
+destroy_program_core_2_0 (GLuint shader)
 {
-    glDeleteShader (program->vertex_shader);
-    glDeleteShader (program->fragment_shader);
-    glDeleteProgram (program->program);
+  glDeleteProgram (shader);
 }
 
 static cairo_status_t
@@ -396,7 +404,8 @@ use_program_core_2_0 (cairo_gl_shader_program_t *program)
 static const cairo_gl_shader_impl_t shader_impl_core_2_0 = {
     compile_shader_core_2_0,
     link_shader_core_2_0,
-    destroy_shader_program_core_2_0,
+    destroy_shader_core_2_0,
+    destroy_program_core_2_0,
     bind_float_to_shader_core_2_0,
     bind_vec2_to_shader_core_2_0,
     bind_vec3_to_shader_core_2_0,
@@ -409,7 +418,8 @@ static const cairo_gl_shader_impl_t shader_impl_core_2_0 = {
 static const cairo_gl_shader_impl_t shader_impl_arb = {
     compile_shader_arb,
     link_shader_arb,
-    destroy_shader_program_arb,
+    destroy_shader_arb,
+    destroy_program_arb,
     bind_float_to_shader_arb,
     bind_vec2_to_shader_arb,
     bind_vec3_to_shader_arb,
@@ -432,32 +442,92 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
     } else {
         ctx->shader_impl = NULL;
     }
+
+    memset (ctx->vertex_shaders, 0, sizeof (ctx->vertex_shaders));
 }
 
 void
 init_shader_program (cairo_gl_shader_program_t *program)
 {
-    program->vertex_shader = 0;
     program->fragment_shader = 0;
     program->program = 0;
     program->build_failure = FALSE;
 }
 
 void
+destroy_shader (cairo_gl_context_t *ctx, GLuint shader)
+{
+    if (shader)
+        ctx->shader_impl->destroy_shader (shader);
+}
+
+void
 destroy_shader_program (cairo_gl_context_t *ctx,
                         cairo_gl_shader_program_t *program)
 {
-    return ctx->shader_impl->destroy_shader_program (program);
+    destroy_shader (ctx, program->fragment_shader);
+
+    if (program->program)
+        ctx->shader_impl->destroy_program (program->program);
 }
 
+static const char *vs_sources[] = {
+[CAIRO_GL_VERTEX_SHADER_EMPTY] =
+    "void main()\n"
+    "{\n"
+    "	gl_Position = ftransform();\n"
+    "}\n",
+[CAIRO_GL_VERTEX_SHADER_SOURCE] =
+    "varying vec2 source_texcoords;\n"
+    "void main()\n"
+    "{\n"
+    "	gl_Position = ftransform();\n"
+    "	source_texcoords = gl_MultiTexCoord0.xy;\n"
+    "}\n",
+[CAIRO_GL_VERTEX_SHADER_MASK] =
+    "varying vec2 mask_texcoords;\n"
+    "void main()\n"
+    "{\n"
+    "	gl_Position = ftransform();\n"
+    "	mask_texcoords = gl_MultiTexCoord1.xy;\n"
+    "}\n",
+[CAIRO_GL_VERTEX_SHADER_SOURCE_MASK] =
+    "varying vec2 source_texcoords;\n"
+    "varying vec2 mask_texcoords;\n"
+    "void main()\n"
+    "{\n"
+    "	gl_Position = ftransform();\n"
+    "	source_texcoords = gl_MultiTexCoord0.xy;\n"
+    "	mask_texcoords = gl_MultiTexCoord1.xy;\n"
+    "}\n",
+[CAIRO_GL_VERTEX_SHADER_SPANS] =
+    "varying float coverage;\n"
+    "void main()\n"
+    "{\n"
+    "	gl_Position = ftransform();\n"
+    "   coverage = gl_Color.a;\n"
+    "}\n",
+[CAIRO_GL_VERTEX_SHADER_SOURCE_SPANS] =
+    "varying vec2 source_texcoords;\n"
+    "varying float coverage;\n"
+    "void main()\n"
+    "{\n"
+    "	gl_Position = ftransform();\n"
+    "	source_texcoords = gl_MultiTexCoord0.xy;\n"
+    "   coverage = gl_Color.a;\n"
+    "}\n"
+};
+
 cairo_status_t
 create_shader_program (cairo_gl_context_t *ctx,
                        cairo_gl_shader_program_t *program,
-                       const char *vertex_text,
+                       cairo_gl_vertex_shader_t vertex_shader,
                        const char *fragment_text)
 {
     cairo_status_t status;
 
+    assert (vertex_shader < ARRAY_LENGTH (vs_sources));
+
     if (program->program != 0)
         return CAIRO_STATUS_SUCCESS;
 
@@ -467,11 +537,13 @@ create_shader_program (cairo_gl_context_t *ctx,
     if (ctx->shader_impl == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = ctx->shader_impl->compile_shader (&program->vertex_shader,
-                                               GL_VERTEX_SHADER,
-                                               vertex_text);
-    if (unlikely (status))
-        goto FAILURE;
+    if (ctx->vertex_shaders[vertex_shader] == 0) {
+        status = ctx->shader_impl->compile_shader (&ctx->vertex_shaders[vertex_shader],
+                                                   GL_VERTEX_SHADER,
+                                                   vs_sources[vertex_shader]);
+        if (unlikely (status))
+            goto FAILURE;
+    }
 
     status = ctx->shader_impl->compile_shader (&program->fragment_shader,
                                                GL_FRAGMENT_SHADER,
@@ -480,7 +552,7 @@ create_shader_program (cairo_gl_context_t *ctx,
         goto FAILURE;
 
     status = ctx->shader_impl->link_shader (&program->program,
-                                            program->vertex_shader,
+                                            ctx->vertex_shaders[vertex_shader],
                                             program->fragment_shader);
     if (unlikely (status))
         goto FAILURE;
@@ -489,7 +561,6 @@ create_shader_program (cairo_gl_context_t *ctx,
 
  FAILURE:
     destroy_shader_program (ctx, program);
-    program->vertex_shader = 0;
     program->fragment_shader = 0;
     program->program = 0;
     program->build_failure = TRUE;
@@ -555,50 +626,6 @@ _cairo_gl_use_program (cairo_gl_context_t *ctx,
     ctx->shader_impl->use_program (program);
 }
 
-static const char *vs_no_coords =
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "}\n";
-static const char *vs_source_coords =
-    "varying vec2 source_texcoords;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "	source_texcoords = gl_MultiTexCoord0.xy;\n"
-    "}\n";
-static const char *vs_mask_coords =
-    "varying vec2 mask_texcoords;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "	mask_texcoords = gl_MultiTexCoord1.xy;\n"
-    "}\n";
-static const char *vs_source_mask_coords =
-    "varying vec2 source_texcoords;\n"
-    "varying vec2 mask_texcoords;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "	source_texcoords = gl_MultiTexCoord0.xy;\n"
-    "	mask_texcoords = gl_MultiTexCoord1.xy;\n"
-    "}\n";
-static const char *vs_spans_no_coords =
-    "varying float coverage;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "   coverage = gl_Color.a;\n"
-    "}\n";
-static const char *vs_spans_source_coords =
-    "varying vec2 source_texcoords;\n"
-    "varying float coverage;\n"
-    "void main()\n"
-    "{\n"
-    "	gl_Position = ftransform();\n"
-    "	source_texcoords = gl_MultiTexCoord0.xy;\n"
-    "   coverage = gl_Color.a;\n"
-    "}\n";
 static const char *fs_source_constant =
     "uniform vec4 constant_source;\n"
     "vec4 get_source()\n"
@@ -824,7 +851,7 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     };
     cairo_gl_shader_program_t *program;
     const char *source_source, *mask_source, *in_source;
-    const char *vs_source;
+    cairo_gl_vertex_shader_t vs;
     char *fs_source;
     cairo_status_t status;
 
@@ -870,22 +897,22 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
 	source == CAIRO_GL_SHADER_SOURCE_LINEAR_GRADIENT ||
 	source == CAIRO_GL_SHADER_SOURCE_RADIAL_GRADIENT) {
 	if (mask == CAIRO_GL_SHADER_MASK_SPANS)
-	    vs_source = vs_spans_no_coords;
+	    vs = CAIRO_GL_VERTEX_SHADER_SPANS;
 	else if (mask == CAIRO_GL_SHADER_MASK_CONSTANT ||
 		 mask == CAIRO_GL_SHADER_MASK_LINEAR_GRADIENT ||
 		 mask == CAIRO_GL_SHADER_MASK_RADIAL_GRADIENT)
-	    vs_source = vs_no_coords;
+	    vs = CAIRO_GL_VERTEX_SHADER_EMPTY;
 	else
-	    vs_source = vs_mask_coords;
+	    vs = CAIRO_GL_VERTEX_SHADER_MASK;
     } else {
 	if (mask == CAIRO_GL_SHADER_MASK_SPANS)
-	    vs_source = vs_spans_source_coords;
+	    vs = CAIRO_GL_VERTEX_SHADER_SOURCE_SPANS;
 	else if (mask == CAIRO_GL_SHADER_MASK_CONSTANT ||
 		 mask == CAIRO_GL_SHADER_MASK_LINEAR_GRADIENT ||
 		 mask == CAIRO_GL_SHADER_MASK_RADIAL_GRADIENT)
-	    vs_source = vs_source_coords;
+	    vs = CAIRO_GL_VERTEX_SHADER_SOURCE;
 	else
-	    vs_source = vs_source_mask_coords;
+	    vs = CAIRO_GL_VERTEX_SHADER_SOURCE_MASK;
     }
 
     sprintf(fs_source, "%s%s%s", source_source, mask_source, in_source);
@@ -893,7 +920,7 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     init_shader_program (program);
     status = create_shader_program (ctx,
                                     program,
-				    vs_source,
+				    vs,
 				    fs_source);
     free (fs_source);
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 9b17a53..cf9547c 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -2367,11 +2367,6 @@ _cairo_gl_surface_fill_rectangles_glsl (void                  *abstract_surface,
     cairo_gl_context_t *ctx;
     int i;
     GLfloat *vertices;
-    static const char *fill_vs_source =
-	"void main()\n"
-	"{\n"
-	"	gl_Position = ftransform();\n"
-	"}\n";
     static const char *fill_fs_source =
 	"uniform vec4 color;\n"
 	"void main()\n"
@@ -2389,7 +2384,7 @@ _cairo_gl_surface_fill_rectangles_glsl (void                  *abstract_surface,
 
     status = create_shader_program (ctx,
                                     &ctx->fill_rectangles_shader,
-				    fill_vs_source,
+                                    CAIRO_GL_VERTEX_SHADER_EMPTY,
 				    fill_fs_source);
     if (unlikely (status)) {
 	_cairo_gl_context_release (ctx);


More information about the cairo-commit mailing list