[cairo-commit] 61 commits - src/cairo-device.c src/cairo-device-private.h src/cairo-gl-composite.c src/cairo-gl-device.c src/cairo-gl-glyphs.c src/cairo-gl-gradient.c src/cairo-gl-gradient-private.h src/cairo-gl-private.h src/cairo-gl-shaders.c src/cairo-gl-surface.c src/cairo-glx-context.c src/cairoint.h src/cairo-region.c src/cairo-spans.c src/cairo-spans-private.h src/cairo-surface.c src/cairo-xml-surface.c src/Makefile.sources

Benjamin Otte company at kemper.freedesktop.org
Mon Jun 7 08:11:39 PDT 2010


 src/Makefile.sources            |    4 
 src/cairo-device-private.h      |    2 
 src/cairo-device.c              |   13 
 src/cairo-gl-composite.c        |  926 ++++++++++++++++------------------------
 src/cairo-gl-device.c           |  129 ++++-
 src/cairo-gl-glyphs.c           |   42 -
 src/cairo-gl-gradient-private.h |   88 +++
 src/cairo-gl-gradient.c         |  275 +++++++++++
 src/cairo-gl-private.h          |  149 +++---
 src/cairo-gl-shaders.c          |   58 --
 src/cairo-gl-surface.c          |  413 ++++++++++++-----
 src/cairo-glx-context.c         |   16 
 src/cairo-region.c              |    9 
 src/cairo-spans-private.h       |   12 
 src/cairo-spans.c               |   75 ---
 src/cairo-surface.c             |    4 
 src/cairo-xml-surface.c         |    4 
 src/cairoint.h                  |   12 
 18 files changed, 1318 insertions(+), 913 deletions(-)

New commits:
commit 7d8359721b581845260c0442a174e48b061484a7
Author: Benjamin Otte <otte at redhat.com>
Date:   Mon Jun 7 16:46:46 2010 +0200

    gl: Fix span renderer doing bad stuff for CLEAR and SOURCE
    
    SOURCE will fallback now, CLEAR is identical to DEST_OUT with white.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 02278fb..8a2379f 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1342,6 +1342,13 @@ _cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
     if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias))
         return UNSUPPORTED ("no span renderer");
 
+    if (op == CAIRO_OPERATOR_SOURCE)
+        return UNSUPPORTED ("SOURCE compositing doesn't work in GL");
+    if (op == CAIRO_OPERATOR_CLEAR) {
+        op = CAIRO_OPERATOR_DEST_OUT;
+        src = &_cairo_pattern_white.base;
+    }
+
     status = _cairo_surface_composite_polygon (&dst->base,
                                                op,
                                                src,
commit ef8fd1355ea03b8566ef31642b32133d3543e4e8
Author: Benjamin Otte <otte at redhat.com>
Date:   Mon Jun 7 15:03:37 2010 +0200

    gl: Fix span renderer for unbounded spans
    
    The span renderer used to not output rects for the top and bottom rows
    when they didn't contain any spans.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index cb1f9c4..02278fb 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1068,6 +1068,7 @@ typedef struct _cairo_gl_surface_span_renderer {
     cairo_gl_composite_t setup;
 
     int xmin, xmax;
+    int ymin, ymax;
 
     cairo_gl_context_t *ctx;
 } cairo_gl_surface_span_renderer_t;
@@ -1105,39 +1106,67 @@ _cairo_gl_render_unbounded_spans (void *abstract_renderer,
 {
     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
 
-    if (num_spans == 0) {
+    if (y > renderer->ymin) {
         _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       renderer->xmin, y,
-                                       renderer->xmax, y + height,
+                                       renderer->xmin, renderer->ymin,
+                                       renderer->xmax, y,
                                        0);
-	return CAIRO_STATUS_SUCCESS;
     }
 
-    if (spans[0].x != renderer->xmin) {
+    if (num_spans == 0) {
         _cairo_gl_composite_emit_rect (renderer->ctx,
                                        renderer->xmin, y,
-                                       spans[0].x,     y + height,
+                                       renderer->xmax, y + height,
                                        0);
+    } else {
+        if (spans[0].x != renderer->xmin) {
+            _cairo_gl_composite_emit_rect (renderer->ctx,
+                                           renderer->xmin, y,
+                                           spans[0].x,     y + height,
+                                           0);
+        }
+
+        do {
+            _cairo_gl_composite_emit_rect (renderer->ctx,
+                                           spans[0].x, y,
+                                           spans[1].x, y + height,
+                                           spans[0].coverage);
+            spans++;
+        } while (--num_spans > 1);
+
+        if (spans[0].x != renderer->xmax) {
+            _cairo_gl_composite_emit_rect (renderer->ctx,
+                                           spans[0].x,     y,
+                                           renderer->xmax, y + height,
+                                           0);
+        }
     }
 
-    do {
-        _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       spans[0].x, y,
-                                       spans[1].x, y + height,
-                                       spans[0].coverage);
-	spans++;
-    } while (--num_spans > 1);
+    renderer->ymin = y + height;
+    return CAIRO_STATUS_SUCCESS;
+}
 
-    if (spans[0].x != renderer->xmax) {
+static cairo_status_t
+_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
+{
+    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
+
+    if (renderer->ymax > renderer->ymin) {
         _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       spans[0].x,     y,
-                                       renderer->xmax, y + height,
+                                       renderer->xmin, renderer->ymin,
+                                       renderer->xmax, renderer->ymax,
                                        0);
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_status_t
+_cairo_gl_finish_bounded_spans (void *abstract_renderer)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static void
 _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
 {
@@ -1153,12 +1182,6 @@ _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
     free (renderer);
 }
 
-static cairo_status_t
-_cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
-{
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static cairo_bool_t
 _cairo_gl_surface_check_span_renderer (cairo_operator_t	       op,
 				       const cairo_pattern_t  *pattern,
@@ -1193,16 +1216,19 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
 
     renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
-    renderer->base.finish = _cairo_gl_surface_span_renderer_finish;
     if (rects->is_bounded) {
 	renderer->base.render_rows = _cairo_gl_render_bounded_spans;
+        renderer->base.finish =      _cairo_gl_finish_bounded_spans;
 	extents = &rects->bounded;
     } else {
 	renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
+        renderer->base.finish =      _cairo_gl_finish_unbounded_spans;
 	extents = &rects->unbounded;
     }
     renderer->xmin = extents->x;
     renderer->xmax = extents->x + extents->width;
+    renderer->ymin = extents->y;
+    renderer->ymax = extents->y + extents->height;
 
     status = _cairo_gl_composite_init (&renderer->setup,
                                        op, dst,
commit 1d11af083f5368c88032a33ff40d0e21c139db18
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat Jun 5 15:22:44 2010 +0200

    gl: Add a simple spans renderer for stroke/fill
    
    It's very simple as clipped polygons or ANTIALIAS_NONE still return
    UNSUPPORTED. Also, no optimizations are done, so even pixel-aligned
    rectangles use the full span rendering.
    
    Still, there are no performance regressions in the benchmark traces and
    firefox-talos-svg and swfdec-giant-steps both got ~15% faster.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 9aa8852..cb1f9c4 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1211,7 +1211,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
         goto FAIL;
 
     status = _cairo_gl_composite_set_source (&renderer->setup, src,
-                                             rects->source.x, rects->source.y,
+                                             extents->x, extents->y,
                                              extents->x, extents->y,
                                              extents->width, extents->height);
     if (unlikely (status))
@@ -1299,6 +1299,178 @@ _cairo_gl_surface_paint (void *abstract_surface,
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
+static cairo_int_status_t
+_cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
+                           cairo_operator_t op,
+                           const cairo_pattern_t *src,
+                           cairo_polygon_t *polygon,
+                           cairo_fill_rule_t fill_rule,
+                           cairo_antialias_t antialias,
+                           const cairo_composite_rectangles_t *extents,
+                           cairo_clip_t *clip)
+{
+    cairo_status_t status;
+
+    if (clip)
+        return UNSUPPORTED ("a clip!");
+    if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias))
+        return UNSUPPORTED ("no span renderer");
+
+    status = _cairo_surface_composite_polygon (&dst->base,
+                                               op,
+                                               src,
+                                               fill_rule,
+                                               antialias,
+                                               extents,
+                                               polygon,
+                                               NULL);
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_stroke (void			        *abstract_surface,
+                          cairo_operator_t		 op,
+                          const cairo_pattern_t	        *source,
+                          cairo_path_fixed_t		*path,
+                          const cairo_stroke_style_t	*style,
+                          const cairo_matrix_t	        *ctm,
+                          const cairo_matrix_t	        *ctm_inverse,
+                          double			 tolerance,
+                          cairo_antialias_t		 antialias,
+                          cairo_clip_t		        *clip)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+    cairo_composite_rectangles_t extents;
+    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+    int num_boxes = ARRAY_LENGTH (boxes_stack);
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_polygon_t polygon;
+    cairo_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_stroke (&extents,
+							  surface->width,
+							  surface->height,
+							  op, source,
+							  path, style, ctm,
+							  clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    _cairo_polygon_init (&polygon);
+    _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+    status = _cairo_path_fixed_stroke_to_polygon (path,
+                                                  style,
+                                                  ctm, ctm_inverse,
+                                                  tolerance,
+                                                  &polygon);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+        status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
+                                            CAIRO_FILL_RULE_WINDING, antialias,
+                                            &extents, clip);
+    }
+
+    _cairo_polygon_fini (&polygon);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_fill (void			*abstract_surface,
+                        cairo_operator_t	 op,
+                        const cairo_pattern_t	*source,
+                        cairo_path_fixed_t	*path,
+                        cairo_fill_rule_t	 fill_rule,
+                        double			 tolerance,
+                        cairo_antialias_t	 antialias,
+                        cairo_clip_t		*clip)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+    cairo_composite_rectangles_t extents;
+    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    int num_boxes = ARRAY_LENGTH (boxes_stack);
+    cairo_polygon_t polygon;
+    cairo_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_fill (&extents,
+							surface->width,
+							surface->height,
+							op, source, path,
+							clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+#if 0
+    if (extents.is_bounded && clip != NULL) {
+	cairo_clip_path_t *clip_path;
+
+	if (((clip_path = _clip_get_single_path (clip)) != NULL) &&
+	    _cairo_path_fixed_equal (&clip_path->path, path))
+	{
+	    clip = NULL;
+	}
+    }
+#endif
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    _cairo_polygon_init (&polygon);
+    _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+    status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+        status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
+                                            fill_rule, antialias,
+                                            &extents, clip);
+    }
+
+    _cairo_polygon_fini (&polygon);
+
+    if (clip_boxes != boxes_stack)
+	free (clip_boxes);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
 const cairo_surface_backend_t _cairo_gl_surface_backend = {
     CAIRO_SURFACE_TYPE_GL,
     _cairo_gl_surface_create_similar,
@@ -1327,8 +1499,8 @@ const cairo_surface_backend_t _cairo_gl_surface_backend = {
     _cairo_gl_surface_scaled_glyph_fini,
     _cairo_gl_surface_paint,
     NULL, /* mask */
-    NULL, /* stroke */
-    NULL, /* fill */
+    _cairo_gl_surface_stroke,
+    _cairo_gl_surface_fill,
     _cairo_gl_surface_show_glyphs, /* show_glyphs */
     NULL  /* snapshot */
 };
commit 550335efeddf813c1bec493513254fdbd34a9ace
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat Jun 5 15:19:44 2010 +0200

    Remove _cairo_surface_composite_trapezoids_as_polygon()
    
    The function computed the composite rectangles wrong and was only used
    in a gl fallback anyway. So instead of trying to fix it, just remove it
    and make sure gl doesn't fallback.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index f7a16ae..9aa8852 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -985,20 +985,6 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
     if (! _cairo_gl_operator_is_supported (op))
 	return UNSUPPORTED ("unsupported operator");
 
-    if (_cairo_surface_check_span_renderer (op,pattern,&dst->base, antialias)) {
-	status =
-	    _cairo_surface_composite_trapezoids_as_polygon (&dst->base,
-							    op, pattern,
-							    antialias,
-							    src_x, src_y,
-							    dst_x, dst_y,
-							    width, height,
-							    traps, num_traps,
-							    clip_region);
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return status;
-    }
-
     status = _cairo_gl_get_traps_pattern (dst,
 					  dst_x, dst_y, width, height,
 					  traps, num_traps, antialias,
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
index e7e9656..00a4df8 100644
--- a/src/cairo-spans-private.h
+++ b/src/cairo-spans-private.h
@@ -186,16 +186,4 @@ _cairo_surface_composite_polygon (cairo_surface_t	*surface,
 				  cairo_polygon_t	*polygon,
 				  cairo_region_t	*clip_region);
 
-cairo_private cairo_status_t
-_cairo_surface_composite_trapezoids_as_polygon (cairo_surface_t	*surface,
-						cairo_operator_t	 op,
-						const cairo_pattern_t	*pattern,
-						cairo_antialias_t	antialias,
-						int src_x, int src_y,
-						int dst_x, int dst_y,
-						int width, int height,
-						cairo_trapezoid_t	*traps,
-						int num_traps,
-						cairo_region_t	*clip_region);
-
 #endif /* CAIRO_SPANS_PRIVATE_H */
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index 434fce0..a187b89 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -84,81 +84,6 @@ _cairo_surface_composite_polygon (cairo_surface_t	*surface,
     return status;
 }
 
-cairo_status_t
-_cairo_surface_composite_trapezoids_as_polygon (cairo_surface_t	*surface,
-						cairo_operator_t	 op,
-						const cairo_pattern_t	*pattern,
-						cairo_antialias_t	antialias,
-						int src_x, int src_y,
-						int dst_x, int dst_y,
-						int width, int height,
-						cairo_trapezoid_t	*traps,
-						int num_traps,
-						cairo_region_t	*clip_region)
-{
-    cairo_span_renderer_t *renderer;
-    cairo_scan_converter_t *converter;
-    cairo_composite_rectangles_t rects;
-    cairo_status_t status;
-
-    rects.source.x = src_x;
-    rects.source.y = src_y;
-    rects.source.width  = width;
-    rects.source.height = height;
-
-    rects.mask.x = dst_x;
-    rects.mask.y = dst_y;
-    rects.mask.width  = width;
-    rects.mask.height = height;
-
-    rects.bounded.x = dst_x;
-    rects.bounded.y = dst_y;
-    rects.bounded.width  = width;
-    rects.bounded.height = height;
-
-    rects.unbounded = rects.bounded;
-
-    rects.is_bounded = _cairo_operator_bounded_by_either (op);
-
-    converter = _create_scan_converter (CAIRO_FILL_RULE_WINDING,
-					antialias,
-					&rects);
-    status = converter->status;
-    if (unlikely (status))
-	goto CLEANUP_CONVERTER;
-
-    while (num_traps--) {
-	status = converter->add_edge (converter,
-				      &traps->left.p1, &traps->left.p2,
-				      traps->top, traps->bottom, 1);
-	if (unlikely (status))
-	    goto CLEANUP_CONVERTER;
-
-	status = converter->add_edge (converter,
-				      &traps->right.p1, &traps->right.p2,
-				      traps->top, traps->bottom, -1);
-	if (unlikely (status))
-	    goto CLEANUP_CONVERTER;
-
-	traps++;
-    }
-
-    renderer = _cairo_surface_create_span_renderer (op, pattern, surface,
-						    antialias, &rects,
-						    clip_region);
-    status = converter->generate (converter, renderer);
-    if (unlikely (status))
-	goto CLEANUP_RENDERER;
-
-    status = renderer->finish (renderer);
-
- CLEANUP_RENDERER:
-    renderer->destroy (renderer);
- CLEANUP_CONVERTER:
-    converter->destroy (converter);
-    return status;
-}
-
 static void
 _cairo_nil_destroy (void *abstract)
 {
diff --git a/src/cairoint.h b/src/cairoint.h
index 1f8643d..d8df10c 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1973,18 +1973,6 @@ _cairo_surface_composite_trapezoids (cairo_operator_t	op,
 				     int		ntraps,
 				     cairo_region_t	*clip_region);
 
-cairo_private cairo_status_t
-_cairo_surface_composite_trapezoids_as_polygon (cairo_surface_t	*surface,
-						cairo_operator_t	 op,
-						const cairo_pattern_t	*pattern,
-						cairo_antialias_t	antialias,
-						int src_x, int src_y,
-						int dst_x, int dst_y,
-						int width, int height,
-						cairo_trapezoid_t	*traps,
-						int num_traps,
-						cairo_region_t	*clip_region);
-
 cairo_private cairo_span_renderer_t *
 _cairo_surface_create_span_renderer (cairo_operator_t			 op,
 				     const cairo_pattern_t		*pattern,
commit 1e003fce8f7239aaf4608747d63287e0c715ee51
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat Jun 5 14:58:32 2010 +0200

    gl: Fix vertex size changes not causing updates of the operands
    
    Check vertex size stays identical when setting up vertices.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 1ca6509..ca96b6b 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -576,6 +576,7 @@ static void
 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
                                  cairo_gl_tex_t      tex_unit,
                                  cairo_gl_operand_t *operand,
+                                 unsigned int        vertex_size,
                                  unsigned int        vertex_offset,
                                  cairo_bool_t        use_shaders)
 {
@@ -583,7 +584,8 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
 
     /* XXX: we need to do setup when switching from shaders
      * to no shaders (or back) */
-    needs_setup = _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
+    needs_setup = ctx->vertex_size != vertex_size;
+    needs_setup |= _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
                                                  operand,
                                                  vertex_offset);
 
@@ -605,7 +607,7 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
     case CAIRO_GL_OPERAND_NONE:
         break;
     case CAIRO_GL_OPERAND_SPANS:
-	glColorPointer (4, GL_UNSIGNED_BYTE, ctx->vertex_size,
+	glColorPointer (4, GL_UNSIGNED_BYTE, vertex_size,
                         (void *) (uintptr_t) vertex_offset);
 	glEnableClientState (GL_COLOR_ARRAY);
         /* fall through */
@@ -627,7 +629,7 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
                                       operand->texture.attributes.filter);
 
 	glClientActiveTexture (GL_TEXTURE0 + tex_unit);
-	glTexCoordPointer (2, GL_FLOAT, ctx->vertex_size,
+	glTexCoordPointer (2, GL_FLOAT, vertex_size,
                            (void *) (uintptr_t) vertex_offset);
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
         break;
@@ -947,7 +949,6 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     vertex_size = dst_size + src_size + mask_size;
     if (ctx->vertex_size != vertex_size) {
         _cairo_gl_composite_flush (ctx);
-        ctx->vertex_size = vertex_size;
     }
 
     _cairo_gl_context_set_destination (ctx, setup->dst);
@@ -955,17 +956,19 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     if (_cairo_gl_context_is_flushed (ctx)) {
         glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
 
-        glVertexPointer (2, GL_FLOAT, ctx->vertex_size, NULL);
+        glVertexPointer (2, GL_FLOAT, vertex_size, NULL);
         glEnableClientState (GL_VERTEX_ARRAY);
     }
 
-    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size, shader != NULL);
-    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size, shader != NULL);
+    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size, shader != NULL);
+    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size, shader != NULL);
 
     _cairo_gl_set_operator (ctx,
                             setup->op,
                             component_alpha);
 
+    ctx->vertex_size = vertex_size;
+
     if (_cairo_gl_context_is_flushed (ctx)) {
         if (ctx->pre_shader) {
             _cairo_gl_set_shader (ctx, ctx->pre_shader);
commit 39143400ddd0d4e63a72ce91c423f764e466e405
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri Jun 4 12:25:52 2010 +0200

    gl: Add a gradient texture cache
    
    For firefox-planet-gnome, 19135 times a gradient gets rendered using
    only 10 different gradients. So we get a 100% hit rate in the cache.
    Unfortunately, texture upload is not the biggest problem of this test,
    as the performance increase is only moderate - at least on i965:
    34.3s => 33.5s

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 54a2fde..51b72e0 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -104,6 +104,8 @@ _gl_finish (void *device)
 
     _gl_lock (device);
 
+    _cairo_cache_fini (&ctx->gradients);
+
     _cairo_gl_context_fini_shaders (ctx);
 
     _gl_unlock (device);
@@ -201,7 +203,15 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 
     status = _cairo_gl_context_init_shaders (ctx);
     if (unlikely (status))
-	return status;
+        return status;
+
+    status = _cairo_cache_init (&ctx->gradients,
+                                _cairo_gl_gradient_equal,
+                                NULL,
+                                (cairo_destroy_func_t) _cairo_gl_gradient_destroy,
+                                CAIRO_GL_GRADIENT_CACHE_SIZE);
+    if (unlikely (status))
+        return status;
 
     /* Set up the dummy texture for tex_env_combine with constant color. */
     glGenTextures (1, &ctx->dummy_tex);
diff --git a/src/cairo-gl-gradient-private.h b/src/cairo-gl-gradient-private.h
index 3c3b52e..60e0525 100644
--- a/src/cairo-gl-gradient-private.h
+++ b/src/cairo-gl-gradient-private.h
@@ -41,6 +41,7 @@
 #ifndef CAIRO_GL_GRADIENT_PRIVATE_H
 #define CAIRO_GL_GRADIENT_PRIVATE_H
 
+#include "cairo-cache-private.h"
 #include "cairo-device-private.h"
 #include "cairo-reference-count-private.h"
 #include "cairo-types-private.h"
@@ -53,15 +54,19 @@
 #define GL_GLEXT_PROTOTYPES
 #include <GL/glext.h>
 
+#define CAIRO_GL_GRADIENT_CACHE_SIZE 4096
+
 /* XXX: Declare in a better place */
 typedef struct _cairo_gl_context cairo_gl_context_t;
 
 typedef struct _cairo_gl_gradient {
-    cairo_reference_count_t   ref_count;
-    cairo_device_t           *device; /* NB: we don't hold a reference */
-    GLuint                    tex;
-    unsigned int	      n_stops;
-    cairo_gradient_stop_t     stops[2];
+    cairo_cache_entry_t           cache_entry;
+    cairo_reference_count_t       ref_count;
+    cairo_device_t               *device; /* NB: we don't hold a reference */
+    GLuint                        tex;
+    unsigned int	          n_stops;
+    const cairo_gradient_stop_t  *stops;
+    cairo_gradient_stop_t         stops_embedded[2];
 } cairo_gl_gradient_t;
 
 cairo_private cairo_int_status_t
@@ -76,5 +81,8 @@ _cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient);
 cairo_private void
 _cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient);
 
+cairo_private cairo_bool_t
+_cairo_gl_gradient_equal (const void *key_a, const void *key_b);
+
 
 #endif /* CAIRO_GL_GRADIENT_PRIVATE_H */
diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
index 78d74f1..cad38d4 100644
--- a/src/cairo-gl-gradient.c
+++ b/src/cairo-gl-gradient.c
@@ -149,12 +149,49 @@ _cairo_gl_gradient_render (const cairo_gl_context_t    *ctx,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static unsigned long
+_cairo_gl_gradient_hash (unsigned int                  n_stops,
+                         const cairo_gradient_stop_t  *stops)
+{
+    return _cairo_hash_bytes (n_stops,
+                              stops,
+                              sizeof (cairo_gradient_stop_t) * n_stops);
+}
+
+static cairo_gl_gradient_t *
+_cairo_gl_gradient_lookup (cairo_gl_context_t           *ctx,
+                           unsigned long                 hash,
+                           unsigned int                  n_stops,
+                           const cairo_gradient_stop_t  *stops)
+{
+    cairo_gl_gradient_t lookup;
+
+    lookup.cache_entry.hash = hash,
+    lookup.n_stops = n_stops;
+    lookup.stops = stops;
+
+    return _cairo_cache_lookup (&ctx->gradients, &lookup.cache_entry);
+}
+
+cairo_bool_t
+_cairo_gl_gradient_equal (const void *key_a, const void *key_b)
+{
+    const cairo_gl_gradient_t *a = key_a;
+    const cairo_gl_gradient_t *b = key_b;
+
+    if (a->n_stops != b->n_stops)
+        return FALSE;
+
+    return memcmp (a->stops, b->stops, a->n_stops * sizeof (cairo_gradient_stop_t)) == 0;
+}
+
 cairo_int_status_t
 _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
                            unsigned int                  n_stops,
                            const cairo_gradient_stop_t  *stops,
                            cairo_gl_gradient_t         **gradient_out)
 {
+    unsigned long hash;
     cairo_gl_gradient_t *gradient;
     int tex_width;
     void *data;
@@ -163,16 +200,27 @@ _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
     if ((unsigned int) ctx->max_texture_size / 2 <= n_stops)
         return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    hash = _cairo_gl_gradient_hash (n_stops, stops);
+    
+    gradient = _cairo_gl_gradient_lookup (ctx, hash, n_stops, stops);
+    if (gradient) {
+        *gradient_out = _cairo_gl_gradient_reference (gradient);
+        return CAIRO_STATUS_SUCCESS;
+    }
+
     gradient = malloc (sizeof (cairo_gl_gradient_t) + sizeof (cairo_gradient_stop_t) * (n_stops - 2));
     if (gradient == NULL)
         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
+    tex_width = _cairo_gl_gradient_sample_width (n_stops, stops);
+
     CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1);
+    gradient->cache_entry.hash = hash;
+    gradient->cache_entry.size = tex_width;
     gradient->device = &ctx->base;
     gradient->n_stops = n_stops;
-    memcpy (gradient->stops, stops, n_stops * sizeof (cairo_gradient_stop_t));
-
-    tex_width = _cairo_gl_gradient_sample_width (n_stops, stops);
+    gradient->stops = gradient->stops_embedded;
+    memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t));
 
     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);
@@ -190,6 +238,10 @@ _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
 
     glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, 0);
 
+    /* we ignore errors here and just return an uncached gradient */
+    if (likely (! _cairo_cache_insert (&ctx->gradients, &gradient->cache_entry)))
+        _cairo_gl_gradient_reference (gradient);
+
     *gradient_out = gradient;
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 689c769..a02e279 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -181,6 +181,8 @@ struct _cairo_gl_context {
     cairo_gl_shader_t fill_rectangles_shader;
     cairo_cache_t shaders;
 
+    cairo_cache_t gradients;
+
     cairo_gl_glyph_cache_t glyph_cache[2];
     cairo_list_t fonts;
 
commit 932ab2641ea3183171c3b5699c96c4709fc6bd49
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu Jun 3 18:54:18 2010 +0200

    device: flush before setting finished
    
    Otherwise APIs critical for flushing - in particular acquiring the
    device - do not work.

diff --git a/src/cairo-device.c b/src/cairo-device.c
index a090f5b..933eda9 100644
--- a/src/cairo-device.c
+++ b/src/cairo-device.c
@@ -175,10 +175,10 @@ cairo_device_finish (cairo_device_t *device)
     if (device->finished)
 	return;
 
-    device->finished = TRUE;
-
     cairo_device_flush (device);
 
+    device->finished = TRUE;
+
     if (device->backend->finish != NULL)
 	device->backend->finish (device);
 }
commit 35e219d08f1c202399655db183ca0105a1c2166f
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu Jun 3 17:50:59 2010 +0200

    gl: Make gradient textures a separate object
    
    This is necessary so we can do proper refcounting and don't delete the
    gradient texture prematurely.

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 24f15c5..957e108 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -312,10 +312,12 @@ cairo_beos_headers = cairo-beos.h
 #cairo_beos_sources = cairo-beos-surface.cpp
 
 cairo_gl_headers = cairo-gl.h
-cairo_gl_private = cairo-gl-private.h
+cairo_gl_private = cairo-gl-private.h \
+		   cairo-gl-gradient-private.h
 cairo_gl_sources = cairo-gl-composite.c \
 		   cairo-gl-device.c \
 		   cairo-gl-glyphs.c \
+		   cairo-gl-gradient.c \
 		   cairo-gl-shaders.c \
 		   cairo-gl-surface.c
 
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 4b8fcdc..1ca6509 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -43,153 +43,22 @@
 #include "cairo-error-private.h"
 #include "cairo-gl-private.h"
 
-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,
-		  const 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 cairo_int_status_t
 _cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
 				   const cairo_gradient_pattern_t *pattern,
-				   GLuint *tex)
+                                   cairo_gl_gradient_t **gradient)
 {
     cairo_gl_context_t *ctx;
     cairo_status_t status;
-    int tex_width;
-    GLubyte *data;
-
-    assert (pattern->n_stops != 0);
 
     status = _cairo_gl_context_acquire (dst->base.device, &ctx);
     if (unlikely (status))
 	return status;
 
-    if ((unsigned int) ctx->max_texture_size / 2 <= pattern->n_stops) {
-        _cairo_gl_context_release (ctx);
-        return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    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);
-    _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
-    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);
+    status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
 
     _cairo_gl_context_release (ctx);
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 /**
@@ -301,7 +170,7 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 
         status = _cairo_gl_create_gradient_texture (dst,
                                                     gradient,
-                                                    &operand->linear.tex);
+                                                    &operand->linear.gradient);
         if (unlikely (status))
             return status;
 
@@ -335,7 +204,7 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 
         status = _cairo_gl_create_gradient_texture (dst,
                                                     gradient,
-                                                    &operand->radial.tex);
+                                                    &operand->radial.gradient);
         if (unlikely (status))
             return status;
 
@@ -370,10 +239,10 @@ _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
     case CAIRO_GL_OPERAND_CONSTANT:
 	break;
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-	glDeleteTextures (1, &operand->linear.tex);
+	_cairo_gl_gradient_destroy (operand->linear.gradient);
 	break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
-	glDeleteTextures (1, &operand->radial.tex);
+	_cairo_gl_gradient_destroy (operand->radial.gradient);
 	break;
     case CAIRO_GL_OPERAND_TEXTURE:
         _cairo_pattern_release_surface (NULL, /* XXX */
@@ -763,15 +632,17 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
         break;
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+        _cairo_gl_gradient_reference (operand->linear.gradient);
         glActiveTexture (GL_TEXTURE0 + tex_unit);
-        glBindTexture (GL_TEXTURE_1D, operand->linear.tex);
+        glBindTexture (GL_TEXTURE_1D, operand->linear.gradient->tex);
         _cairo_gl_texture_set_extend (ctx, GL_TEXTURE_1D, operand->linear.extend);
         _cairo_gl_texture_set_filter (ctx, GL_TEXTURE_1D, CAIRO_FILTER_BILINEAR);
         glEnable (GL_TEXTURE_1D);
         break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+        _cairo_gl_gradient_reference (operand->radial.gradient);
         glActiveTexture (GL_TEXTURE0 + tex_unit);
-        glBindTexture (GL_TEXTURE_1D, operand->radial.tex);
+        glBindTexture (GL_TEXTURE_1D, operand->radial.gradient->tex);
         _cairo_gl_texture_set_extend (ctx, GL_TEXTURE_1D, operand->radial.extend);
         _cairo_gl_texture_set_filter (ctx, GL_TEXTURE_1D, CAIRO_FILTER_BILINEAR);
         glEnable (GL_TEXTURE_1D);
@@ -810,7 +681,12 @@ _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
         glDisableClientState (GL_TEXTURE_COORD_ARRAY);
         break;
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+        _cairo_gl_gradient_destroy (ctx->operands[tex_unit].linear.gradient);
+        glActiveTexture (GL_TEXTURE0 + tex_unit);
+        glDisable (GL_TEXTURE_1D);
+        break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+        _cairo_gl_gradient_destroy (ctx->operands[tex_unit].radial.gradient);
         glActiveTexture (GL_TEXTURE0 + tex_unit);
         glDisable (GL_TEXTURE_1D);
         break;
diff --git a/src/cairo-gl-gradient-private.h b/src/cairo-gl-gradient-private.h
new file mode 100644
index 0000000..3c3b52e
--- /dev/null
+++ b/src/cairo-gl-gradient-private.h
@@ -0,0 +1,80 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * 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
+ * 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):
+ *	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>
+ */
+
+#ifndef CAIRO_GL_GRADIENT_PRIVATE_H
+#define CAIRO_GL_GRADIENT_PRIVATE_H
+
+#include "cairo-device-private.h"
+#include "cairo-reference-count-private.h"
+#include "cairo-types-private.h"
+
+#include <GL/glew.h>
+
+#include "cairo-gl.h"
+
+#include <GL/gl.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glext.h>
+
+/* XXX: Declare in a better place */
+typedef struct _cairo_gl_context cairo_gl_context_t;
+
+typedef struct _cairo_gl_gradient {
+    cairo_reference_count_t   ref_count;
+    cairo_device_t           *device; /* NB: we don't hold a reference */
+    GLuint                    tex;
+    unsigned int	      n_stops;
+    cairo_gradient_stop_t     stops[2];
+} cairo_gl_gradient_t;
+
+cairo_private cairo_int_status_t
+_cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
+                           unsigned int                  n_stops,
+                           const cairo_gradient_stop_t  *stops,
+                           cairo_gl_gradient_t         **gradient_out);
+
+cairo_private_no_warn cairo_gl_gradient_t *
+_cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient);
+
+cairo_private void
+_cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient);
+
+
+#endif /* CAIRO_GL_GRADIENT_PRIVATE_H */
diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
new file mode 100644
index 0000000..78d74f1
--- /dev/null
+++ b/src/cairo-gl-gradient.c
@@ -0,0 +1,223 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * 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
+ * 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):
+ *	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 "cairo-gl-gradient-private.h"
+
+#include <string.h>
+
+#include "cairo-error-private.h"
+#include "cairo-gl-private.h"
+
+static int
+_cairo_gl_gradient_sample_width (unsigned int                 n_stops,
+                                 const cairo_gradient_stop_t *stops)
+{
+    unsigned int n;
+    int width;
+
+    width = 8;
+    for (n = 1; n < n_stops; n++) {
+	double dx = stops[n].offset - stops[n-1].offset;
+	double delta, max;
+	int ramp;
+
+	if (dx == 0)
+	    continue;
+
+	max = stops[n].color.red - stops[n-1].color.red;
+
+	delta = stops[n].color.green - stops[n-1].color.green;
+	if (delta > max)
+	    max = delta;
+
+	delta = stops[n].color.blue - stops[n-1].color.blue;
+	if (delta > max)
+	    max = delta;
+
+	delta = stops[n].color.alpha - 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
+_cairo_gl_gradient_render (const cairo_gl_context_t    *ctx,
+                           unsigned int                 n_stops,
+                           const cairo_gradient_stop_t *stops,
+                           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 (n_stops > ARRAY_LENGTH (pixman_stops_stack))) {
+	pixman_stops = _cairo_malloc_ab (n_stops,
+					 sizeof (pixman_gradient_stop_t));
+	if (unlikely (pixman_stops == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    for (i = 0; i < n_stops; i++) {
+	pixman_stops[i].x = _cairo_fixed_16_16_from_double (stops[i].offset);
+	pixman_stops[i].color.red   = stops[i].color.red_short;
+	pixman_stops[i].color.green = stops[i].color.green_short;
+	pixman_stops[i].color.blue  = stops[i].color.blue_short;
+	pixman_stops[i].color.alpha = 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,
+						    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;
+}
+
+cairo_int_status_t
+_cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
+                           unsigned int                  n_stops,
+                           const cairo_gradient_stop_t  *stops,
+                           cairo_gl_gradient_t         **gradient_out)
+{
+    cairo_gl_gradient_t *gradient;
+    int tex_width;
+    void *data;
+
+    assert (n_stops >= 2);
+    if ((unsigned int) ctx->max_texture_size / 2 <= n_stops)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    gradient = malloc (sizeof (cairo_gl_gradient_t) + sizeof (cairo_gradient_stop_t) * (n_stops - 2));
+    if (gradient == NULL)
+        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1);
+    gradient->device = &ctx->base;
+    gradient->n_stops = n_stops;
+    memcpy (gradient->stops, stops, n_stops * sizeof (cairo_gradient_stop_t));
+
+    tex_width = _cairo_gl_gradient_sample_width (n_stops, stops);
+
+    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);
+
+    _cairo_gl_gradient_render (ctx, n_stops, stops, data, tex_width);
+
+    glUnmapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB);
+
+    glGenTextures (1, &gradient->tex);
+    _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
+    glBindTexture (GL_TEXTURE_1D, gradient->tex);
+    glTexImage1D (GL_TEXTURE_1D, 0, GL_RGBA8, tex_width, 0,
+                  GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
+
+    glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+
+    *gradient_out = gradient;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_gl_gradient_t *
+_cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient)
+{
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
+
+    _cairo_reference_count_inc (&gradient->ref_count);
+
+    return gradient;
+}
+
+void
+_cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient)
+{
+    cairo_gl_context_t *ctx;
+
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
+
+    if (! _cairo_reference_count_dec_and_test (&gradient->ref_count))
+	return;
+
+    if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) {
+        glDeleteTextures (1, &gradient->tex);
+        _cairo_gl_context_release (ctx);
+    }
+
+    free (gradient);
+}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 0ec85b3..689c769 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -43,6 +43,7 @@
 #define CAIRO_GL_PRIVATE_H
 
 #include "cairoint.h"
+#include "cairo-gl-gradient-private.h"
 #include "cairo-device-private.h"
 #include "cairo-rtree-private.h"
 
@@ -144,14 +145,14 @@ typedef struct cairo_gl_operand {
 	    GLfloat color[4];
 	} constant;
 	struct {
-	    GLuint tex;
+	    cairo_gl_gradient_t *gradient;
 	    cairo_matrix_t m;
 	    float segment_x;
 	    float segment_y;
             cairo_extend_t extend;
 	} linear;
 	struct {
-	    GLuint tex;
+	    cairo_gl_gradient_t *gradient;
 	    cairo_matrix_t m;
 	    float circle_1_x;
 	    float circle_1_y;
@@ -163,7 +164,7 @@ typedef struct cairo_gl_operand {
     unsigned int vertex_offset;
 } cairo_gl_operand_t;
 
-typedef struct _cairo_gl_context {
+struct _cairo_gl_context {
     cairo_device_t base;
 
     GLuint dummy_tex;
@@ -201,7 +202,7 @@ typedef struct _cairo_gl_context {
     void (*make_current) (void *ctx, cairo_gl_surface_t *surface);
     void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface);
     void (*destroy) (void *ctx);
-} cairo_gl_context_t;
+};
 
 typedef struct _cairo_gl_composite {
     cairo_gl_surface_t *dst;
commit 9c17a477d29f633a4850ef8b458cbca82a19afc4
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu Jun 3 17:40:56 2010 +0200

    gl: Use the generic functions for filter/extend in gradients

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 6eb8f49..4b8fcdc 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -188,24 +188,6 @@ _cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
 
     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;
-    }
-    
     _cairo_gl_context_release (ctx);
     return CAIRO_STATUS_SUCCESS;
 }
@@ -336,6 +318,8 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 	operand->linear.segment_x = x1 - x0;
 	operand->linear.segment_y = y1 - y0;
 
+        operand->linear.extend = pattern->extend;
+
 	operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
         return CAIRO_STATUS_SUCCESS;
     } else {
@@ -370,6 +354,8 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 	operand->radial.radius_0 = r0;
 	operand->radial.radius_1 = r1;
 
+        operand->radial.extend = pattern->extend;
+
 	operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT;
         return CAIRO_STATUS_SUCCESS;
     }
@@ -779,11 +765,15 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
         glActiveTexture (GL_TEXTURE0 + tex_unit);
         glBindTexture (GL_TEXTURE_1D, operand->linear.tex);
+        _cairo_gl_texture_set_extend (ctx, GL_TEXTURE_1D, operand->linear.extend);
+        _cairo_gl_texture_set_filter (ctx, GL_TEXTURE_1D, CAIRO_FILTER_BILINEAR);
         glEnable (GL_TEXTURE_1D);
         break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
         glActiveTexture (GL_TEXTURE0 + tex_unit);
         glBindTexture (GL_TEXTURE_1D, operand->radial.tex);
+        _cairo_gl_texture_set_extend (ctx, GL_TEXTURE_1D, operand->radial.extend);
+        _cairo_gl_texture_set_filter (ctx, GL_TEXTURE_1D, CAIRO_FILTER_BILINEAR);
         glEnable (GL_TEXTURE_1D);
         break;
     }
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 3554c67..0ec85b3 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -148,6 +148,7 @@ typedef struct cairo_gl_operand {
 	    cairo_matrix_t m;
 	    float segment_x;
 	    float segment_y;
+            cairo_extend_t extend;
 	} linear;
 	struct {
 	    GLuint tex;
@@ -156,6 +157,7 @@ typedef struct cairo_gl_operand {
 	    float circle_1_y;
 	    float radius_0;
 	    float radius_1;
+            cairo_extend_t extend;
 	} radial;
     };
     unsigned int vertex_offset;
commit df93802765afcf883abef5549bd5dff3465e2d79
Author: Benjamin Otte <otte at redhat.com>
Date:   Thu Jun 3 17:38:28 2010 +0200

    gl: Create separate functions for setting extend and filter

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 4ced6f9..6eb8f49 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -571,43 +571,49 @@ _cairo_gl_composite_bind_to_shader (cairo_gl_context_t   *ctx,
 }
 
 static void
-_cairo_gl_texture_set_attributes (cairo_gl_context_t         *ctx,
-                                  cairo_surface_attributes_t *attributes)
+_cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
+                              GLuint              target,
+                              cairo_extend_t      extend)
 {
     assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
-              (attributes->extend != CAIRO_EXTEND_REPEAT &&
-	       attributes->extend != CAIRO_EXTEND_REFLECT));
+            (extend != CAIRO_EXTEND_REPEAT && extend != CAIRO_EXTEND_REFLECT));
 
-    switch (attributes->extend) {
+    switch (extend) {
     case CAIRO_EXTEND_NONE:
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+	glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+	glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
 	break;
     case CAIRO_EXTEND_PAD:
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 	break;
     case CAIRO_EXTEND_REPEAT:
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_WRAP_S, GL_REPEAT);
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_WRAP_T, GL_REPEAT);
+	glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_REPEAT);
 	break;
     case CAIRO_EXTEND_REFLECT:
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+	glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+	glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
 	break;
     }
+}
 
-    switch (attributes->filter) {
+static void
+_cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
+                              GLuint              target,
+                              cairo_filter_t      filter)
+{
+    switch (filter) {
     case CAIRO_FILTER_FAST:
     case CAIRO_FILTER_NEAREST:
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 	break;
     case CAIRO_FILTER_GOOD:
     case CAIRO_FILTER_BEST:
     case CAIRO_FILTER_BILINEAR:
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 	break;
     default:
     case CAIRO_FILTER_GAUSSIAN:
@@ -760,7 +766,10 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
         glActiveTexture (GL_TEXTURE0 + tex_unit);
         glBindTexture (ctx->tex_target, operand->texture.tex);
         glEnable (ctx->tex_target);
-        _cairo_gl_texture_set_attributes (ctx, &operand->texture.attributes);
+        _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
+                                      operand->texture.attributes.extend);
+        _cairo_gl_texture_set_filter (ctx, ctx->tex_target,
+                                      operand->texture.attributes.filter);
 
 	glClientActiveTexture (GL_TEXTURE0 + tex_unit);
 	glTexCoordPointer (2, GL_FLOAT, ctx->vertex_size,
commit 10e71806d2e1929aa127642a397fa6ccef434b5b
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed Jun 2 20:04:57 2010 +0200

    gl: Switch to deferred rendering
    
    1) call _cairo_gl_composite_flush() or cairo_surface_flush() where
       needed
    2) Destroy texture operands when necessary
    3) get rid of _cairo_gl_composite_end()
    
    With this patch, vertices are not flushed immediately anymore, but only
    when needed or when a new set of vertices is emitted that requires an
    incompatible setup. This improves performance a lot in particular for
    text. (gnome-terminal-vim gets 10x faster)

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index c77bd39..4ced6f9 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -726,6 +726,11 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
                                                  operand,
                                                  vertex_offset);
 
+    if (needs_setup) {
+        _cairo_gl_composite_flush (ctx);
+        _cairo_gl_context_destroy_operand (ctx, tex_unit);
+    }
+
     memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
     ctx->operands[tex_unit].vertex_offset = vertex_offset;
 
@@ -858,6 +863,9 @@ _cairo_gl_set_operator (cairo_gl_context_t *ctx,
     GLenum src_factor, dst_factor;
 
     assert (op < ARRAY_LENGTH (blend_factors));
+    /* different dst and component_alpha changes cause flushes elsewhere */
+    if (ctx->current_operator != op)
+        _cairo_gl_composite_flush (ctx);
     ctx->current_operator = op;
 
     src_factor = blend_factors[op].src;
@@ -1068,6 +1076,17 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     }
 
     _cairo_gl_context_set_destination (ctx, setup->dst);
+
+    if (_cairo_gl_context_is_flushed (ctx)) {
+        glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
+
+        glVertexPointer (2, GL_FLOAT, ctx->vertex_size, NULL);
+        glEnableClientState (GL_VERTEX_ARRAY);
+    }
+
+    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size, shader != NULL);
+    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size, shader != NULL);
+
     _cairo_gl_set_operator (ctx,
                             setup->op,
                             component_alpha);
@@ -1079,16 +1098,11 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
         }
         _cairo_gl_set_shader (ctx, shader);
         _cairo_gl_composite_bind_to_shader (ctx, setup);
-
-        glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
-
-        glVertexPointer (2, GL_FLOAT, ctx->vertex_size, NULL);
-        glEnableClientState (GL_VERTEX_ARRAY);
     }
 
-    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size, shader != NULL);
-    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size, shader != NULL);
-
+    if (! _cairo_gl_context_is_flushed (ctx) &&
+        ! cairo_region_equal (ctx->clip_region, setup->clip_region))
+        _cairo_gl_composite_flush (ctx);
     cairo_region_destroy (ctx->clip_region);
     ctx->clip_region = cairo_region_reference (setup->clip_region);
     if (ctx->clip_region)
@@ -1293,16 +1307,6 @@ _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
 }
 
 void
-_cairo_gl_composite_end (cairo_gl_context_t *ctx,
-                         cairo_gl_composite_t *setup)
-{
-    _cairo_gl_composite_flush (ctx);
-
-    _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
-    _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
-}
-
-void
 _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
 {
     _cairo_gl_operand_destroy (&setup->src);
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 91d3c20..a19174d 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -293,9 +293,6 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	}
 
 	if (scaled_glyph->surface->format != last_format) {
-            if (last_format != CAIRO_FORMAT_INVALID)
-                _cairo_gl_composite_end (ctx, &setup);
-
 	    cache = cairo_gl_context_get_glyph_cache (ctx,
 						      scaled_glyph->surface->format);
 
@@ -350,7 +347,6 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
     status = CAIRO_STATUS_SUCCESS;
   FINISH:
-    _cairo_gl_composite_end (ctx, &setup);
     _cairo_scaled_font_thaw_cache (scaled_font);
 
     _cairo_gl_context_release (ctx);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 0733304..3554c67 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -348,10 +348,6 @@ cairo_private void
 _cairo_gl_composite_flush (cairo_gl_context_t *ctx);
 
 cairo_private void
-_cairo_gl_composite_end (cairo_gl_context_t *ctx,
-                         cairo_gl_composite_t *setup);
-
-cairo_private void
 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
                                    cairo_gl_tex_t tex_unit);
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 59053a4..f7a16ae 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -440,6 +440,8 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
         if (_cairo_gl_context_acquire (surface->base.device, &ctx))
             return;
 
+        cairo_surface_flush (abstract_surface);
+
 	ctx->swap_buffers (ctx, surface);
 
         _cairo_gl_context_release (ctx);
@@ -553,11 +555,13 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	    color.blue = 0.0;
 	    color.alpha = 1.0;
 
+            _cairo_gl_composite_flush (ctx);
 	    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
 	    _cairo_gl_surface_fill_rectangles (dst,
 					       CAIRO_OPERATOR_SOURCE,
 					       &color,
 					       &rect, 1);
+            _cairo_gl_composite_flush (ctx);
 	    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 	}
     } else {
@@ -652,6 +656,8 @@ _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_composite_flush (ctx);
     _cairo_gl_context_set_destination (ctx, surface);
 
     glPixelStorei (GL_PACK_ALIGNMENT, 1);
@@ -951,7 +957,6 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
                                        0);
     }
 
-    _cairo_gl_composite_end (ctx, &setup);
     _cairo_gl_context_release (ctx);
 
   CLEANUP:
@@ -1063,7 +1068,6 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
                                        0);
     }
 
-    _cairo_gl_composite_end (ctx, &setup);
     _cairo_gl_context_release (ctx);
 
   CLEANUP:
@@ -1166,10 +1170,6 @@ _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
 static cairo_status_t
 _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
 {
-    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
-    _cairo_gl_composite_end (renderer->ctx, &renderer->setup);
-
     return CAIRO_STATUS_SUCCESS;
 }
 
commit f2f79ca1b3455000df4138ab500ae03b6584250c
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed Jun 2 19:57:47 2010 +0200

    gl: Make using shaders an explicit argument
    
    This is preparation for a followup patch

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index bc222b7..c77bd39 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -715,10 +715,13 @@ static void
 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
                                  cairo_gl_tex_t      tex_unit,
                                  cairo_gl_operand_t *operand,
-                                 unsigned int        vertex_offset)
+                                 unsigned int        vertex_offset,
+                                 cairo_bool_t        use_shaders)
 {
     cairo_bool_t needs_setup;
 
+    /* XXX: we need to do setup when switching from shaders
+     * to no shaders (or back) */
     needs_setup = _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
                                                  operand,
                                                  vertex_offset);
@@ -741,13 +744,11 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
 	glEnableClientState (GL_COLOR_ARRAY);
         /* fall through */
     case CAIRO_GL_OPERAND_CONSTANT:
-        if (ctx->current_shader == NULL) {
+        if (! use_shaders) {
             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);
-        } else {
-            glDisable (ctx->tex_target);
         }
         break;
     case CAIRO_GL_OPERAND_TEXTURE:
@@ -773,7 +774,7 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
         break;
     }
 
-    if (ctx->current_shader == NULL)
+    if (! use_shaders)
         _cairo_gl_operand_setup_fixed (operand, tex_unit);
 }
 
@@ -1085,8 +1086,8 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
         glEnableClientState (GL_VERTEX_ARRAY);
     }
 
-    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size);
-    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size);
+    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size, shader != NULL);
+    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size, shader != NULL);
 
     cairo_region_destroy (ctx->clip_region);
     ctx->clip_region = cairo_region_reference (setup->clip_region);
commit 19c1d8316e22fc37c7cdaf6c3e56519c06d10561
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed Jun 2 18:14:28 2010 +0200

    gl: Special case blend mode for CAIRO_CONTENT_COLOR
    
    This ensures that alpha stays at 1 for RGB in all cases.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 0470157..bc222b7 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -882,6 +882,8 @@ _cairo_gl_set_operator (cairo_gl_context_t *ctx,
 
     if (ctx->current_target->base.content == CAIRO_CONTENT_ALPHA) {
         glBlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
+    } else if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
+        glBlendFuncSeparate (src_factor, dst_factor, GL_ONE, GL_ONE);
     } else {
         glBlendFunc (src_factor, dst_factor);
     }
commit 1f249064cc5c19a39ffe0faaa8825c8f8b6a2175
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed Jun 2 18:11:04 2010 +0200

    gl: rework _cairo_gl_set_operator()
    
    1) store the current operator. This will be useful later to check if the
       operator changed.
    2) pass the context instead of the destination as first argument. The
       destination is known to be the current target.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index ef0c2ac..0470157 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -830,8 +830,9 @@ _cairo_gl_set_src_alpha (cairo_gl_context_t *ctx,
 }
 
 static void
-_cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
-			cairo_bool_t component_alpha)
+_cairo_gl_set_operator (cairo_gl_context_t *ctx,
+                        cairo_operator_t    op,
+			cairo_bool_t        component_alpha)
 {
     struct {
 	GLenum src;
@@ -856,6 +857,7 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
     GLenum src_factor, dst_factor;
 
     assert (op < ARRAY_LENGTH (blend_factors));
+    ctx->current_operator = op;
 
     src_factor = blend_factors[op].src;
     dst_factor = blend_factors[op].dst;
@@ -864,7 +866,7 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
      * due to texture filtering of GL_CLAMP_TO_BORDER.  So fix those
      * bits in that case.
      */
-    if (dst->base.content == CAIRO_CONTENT_COLOR) {
+    if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
 	if (src_factor == GL_ONE_MINUS_DST_ALPHA)
 	    src_factor = GL_ZERO;
 	if (src_factor == GL_DST_ALPHA)
@@ -878,7 +880,7 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
 	    dst_factor = GL_SRC_COLOR;
     }
 
-    if (dst->base.content == CAIRO_CONTENT_ALPHA) {
+    if (ctx->current_target->base.content == CAIRO_CONTENT_ALPHA) {
         glBlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
     } else {
         glBlendFunc (src_factor, dst_factor);
@@ -1063,7 +1065,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     }
 
     _cairo_gl_context_set_destination (ctx, setup->dst);
-    _cairo_gl_set_operator (setup->dst,
+    _cairo_gl_set_operator (ctx,
                             setup->op,
                             component_alpha);
 
@@ -1110,13 +1112,13 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
         cairo_gl_shader_t *prev_shader = ctx->current_shader;
 
         _cairo_gl_set_shader (ctx, ctx->pre_shader);
-        _cairo_gl_set_operator (ctx->current_target, CAIRO_OPERATOR_DEST_OUT, TRUE);
+        _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
         _cairo_gl_set_src_alpha (ctx, TRUE);
         glDrawArrays (GL_TRIANGLES, 0, count);
         _cairo_gl_set_src_alpha (ctx, FALSE);
 
         _cairo_gl_set_shader (ctx, prev_shader);
-        _cairo_gl_set_operator (ctx->current_target, CAIRO_OPERATOR_ADD, TRUE);
+        _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
         glDrawArrays (GL_TRIANGLES, 0, count);
     }
 }
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index ff64ae6..54a2fde 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -80,6 +80,7 @@ _gl_flush (void *device)
     }
 
     ctx->current_target = NULL;
+    ctx->current_operator = -1;
     ctx->vertex_size = 0;
     ctx->pre_shader = NULL;
     _cairo_gl_set_shader (ctx, NULL);
@@ -196,6 +197,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     else
 	ctx->tex_target = GL_TEXTURE_2D;
 
+    ctx->current_operator = -1;
+
     status = _cairo_gl_context_init_shaders (ctx);
     if (unlikely (status))
 	return status;
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 4101651..0733304 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -182,6 +182,7 @@ typedef struct _cairo_gl_context {
     cairo_list_t fonts;
 
     cairo_gl_surface_t *current_target;
+    cairo_operator_t current_operator;
     cairo_gl_shader_t *pre_shader; /* for component alpha */
     cairo_gl_shader_t *current_shader;
 
commit f66500d8b052251ea3ce06f06d2fa4c8dec2ff3b
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed Jun 2 15:53:48 2010 +0200

    gl: Only resetup textures if we need to

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 42eacf6..ef0c2ac 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -675,15 +675,60 @@ _cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
     }
 }
 
+static cairo_bool_t
+_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
+                               cairo_gl_operand_t *source,
+                               unsigned int        vertex_offset)
+{
+    if (dest->type != source->type)
+        return TRUE;
+    if (dest->vertex_offset != vertex_offset)
+        return TRUE;
+
+    switch (source->type) {
+    case CAIRO_GL_OPERAND_NONE:
+    case CAIRO_GL_OPERAND_SPANS:
+        return FALSE;
+    case CAIRO_GL_OPERAND_CONSTANT:
+        return dest->constant.color[0] != source->constant.color[0] ||
+               dest->constant.color[1] != source->constant.color[1] ||
+               dest->constant.color[2] != source->constant.color[2] ||
+               dest->constant.color[3] != source->constant.color[3];
+    case CAIRO_GL_OPERAND_TEXTURE:
+        return dest->texture.surface != source->texture.surface ||
+               dest->texture.attributes.extend != source->texture.attributes.extend ||
+               dest->texture.attributes.filter != source->texture.attributes.filter ||
+               dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+        /* XXX: improve this */
+        return TRUE;
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+        break;
+    }
+    return TRUE;
+}
+
 static void
 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
                                  cairo_gl_tex_t      tex_unit,
                                  cairo_gl_operand_t *operand,
                                  unsigned int        vertex_offset)
 {
+    cairo_bool_t needs_setup;
+
+    needs_setup = _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
+                                                 operand,
+                                                 vertex_offset);
+
     memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
     ctx->operands[tex_unit].vertex_offset = vertex_offset;
 
+    if (! needs_setup)
+        return;
+
     switch (operand->type) {
     default:
     case CAIRO_GL_OPERAND_COUNT:
commit d9dcafd61ad6aeecb4538e9fd44e3443a8a50bf1
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed Jun 2 15:26:45 2010 +0200

    gl: Do not reset the current target on release
    
    This now also requires a call to cairo_device_flush().

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index af897f1..ff64ae6 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -57,7 +57,6 @@ _gl_unlock (void *device)
     cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
 
     ctx->release (ctx);
-    ctx->current_target = NULL;
 }
 
 static cairo_status_t
@@ -80,6 +79,7 @@ _gl_flush (void *device)
         ctx->clip_region = NULL;
     }
 
+    ctx->current_target = NULL;
     ctx->vertex_size = 0;
     ctx->pre_shader = NULL;
     _cairo_gl_set_shader (ctx, NULL);
commit ce36be5c67fa5b574eb11eb98cdd8c9cd7e09335
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed Jun 2 15:23:57 2010 +0200

    glx: When acquiring device, use the correct drawable

diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c
index c1c69c8..d289051 100644
--- a/src/cairo-glx-context.c
+++ b/src/cairo-glx-context.c
@@ -67,13 +67,23 @@ static void
 _glx_acquire (void *abstract_ctx)
 {
     cairo_glx_context_t *ctx = abstract_ctx;
+    GLXDrawable current_drawable;
 
     ctx->prev_context = glXGetCurrentContext ();
     ctx->prev_drawable = glXGetCurrentDrawable ();
 
-    /* XXX: This is necessary with current code, but shouldn't be */
-    if (ctx->prev_context != ctx->context)
-        glXMakeCurrent (ctx->display, ctx->dummy_window, ctx->context);
+    if (ctx->base.current_target == NULL ||
+        _cairo_gl_surface_is_texture (ctx->base.current_target)) {
+        current_drawable = ctx->dummy_window;
+    } else {
+        cairo_glx_surface_t *surface = (cairo_glx_surface_t *) ctx->base.current_target;
+        current_drawable = surface->win;
+    }
+
+    if (ctx->prev_context != ctx->context ||
+        (ctx->prev_drawable != current_drawable &&
+         current_drawable != ctx->dummy_window))
+        glXMakeCurrent (ctx->display, current_drawable, ctx->context);
 }
 
 static void
commit 5819bb07eb7ac64f0e2fbe6a46cc3db0de1d92ce
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed Jun 2 15:23:08 2010 +0200

    gl: Store the vertex offset in the operand

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 1b7f6bb..42eacf6 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -682,6 +682,7 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
                                  unsigned int        vertex_offset)
 {
     memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
+    ctx->operands[tex_unit].vertex_offset = vertex_offset;
 
     switch (operand->type) {
     default:
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index a6aea40..4101651 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -158,6 +158,7 @@ typedef struct cairo_gl_operand {
 	    float radius_1;
 	} radial;
     };
+    unsigned int vertex_offset;
 } cairo_gl_operand_t;
 
 typedef struct _cairo_gl_context {
commit c75460c54d88ce9a50ac59c15a10684043ca4b0e
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 30 22:01:10 2010 +0200

    gl: Introduce a temporary texture unit
    
    ...and use it for image uploads. This makes sure that the texture units
    used for SOURCE and MASK get not clobbered when images get uploaded to
    textures.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index f720614..1b7f6bb 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -181,6 +181,7 @@ _cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
     glUnmapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB);
 
     glGenTextures (1, tex);
+    _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
     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);
@@ -642,6 +643,7 @@ _cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
     }
 
     switch (tex_unit) {
+    case CAIRO_GL_TEX_TEMP:
     default:
         ASSERT_NOT_REACHED;
         break;
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 2e6bfb9..af897f1 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -214,6 +214,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size);
     ctx->max_texture_size = 0;
     glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
+    ctx->max_textures = 0;
+    glGetIntegerv (GL_MAX_TEXTURE_UNITS, &ctx->max_textures);
 
     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
 	_cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
@@ -221,6 +223,21 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     return CAIRO_STATUS_SUCCESS;
 }
 
+void
+_cairo_gl_context_activate (cairo_gl_context_t *ctx,
+                            cairo_gl_tex_t      tex_unit)
+{
+    if (ctx->max_textures <= (GLint) tex_unit) {
+        if (tex_unit < 2) {
+            _cairo_gl_composite_flush (ctx);
+            _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);   
+        }
+        glActiveTexture (ctx->max_textures - 1);
+    } else {
+        glActiveTexture (GL_TEXTURE0 + tex_unit);
+    }
+}
+
 static void
 _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
                               cairo_gl_surface_t *surface)
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index eaf1143..a6aea40 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -90,7 +90,8 @@ typedef struct cairo_gl_glyph_cache {
 
 typedef enum cairo_gl_tex {
     CAIRO_GL_TEX_SOURCE = 0,
-    CAIRO_GL_TEX_MASK = 1
+    CAIRO_GL_TEX_MASK = 1,
+    CAIRO_GL_TEX_TEMP = 2
 } cairo_gl_tex_t;
 
 typedef enum cairo_gl_operand_type {
@@ -167,6 +168,7 @@ typedef struct _cairo_gl_context {
     GLuint vbo;
     GLint max_framebuffer_size;
     GLint max_texture_size;
+    GLint max_textures;
     GLenum tex_target;
 
     const cairo_gl_shader_impl_t *shader_impl;
@@ -279,6 +281,10 @@ _cairo_gl_context_acquire (cairo_device_t *device,
 cairo_private void
 _cairo_gl_context_set_destination (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface);
 
+cairo_private void
+_cairo_gl_context_activate (cairo_gl_context_t *ctx,
+                            cairo_gl_tex_t      tex_unit);
+
 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 9a75e28..59053a4 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -281,6 +281,7 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
     }
 
     /* Create the texture used to store the surface's data. */
+    _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
     glGenTextures (1, &surface->tex);
     glBindTexture (ctx->tex_target, surface->tex);
     glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -525,6 +526,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
     glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
     if (_cairo_gl_surface_is_texture (dst)) {
+        _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
 	glBindTexture (ctx->tex_target, dst->tex);
 	glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 	glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
commit 1ddff8aba35466fe6689536bc5f2d7eeefaea02c
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 30 21:25:20 2010 +0200

    gl: Only allocate a framebuffer if we need one
    
    This way, we don't clobber the current target when creating textures for
    image surfaces.

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 1741ac0..2e6bfb9 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -221,6 +221,31 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void
+_cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
+                              cairo_gl_surface_t *surface)
+{
+    GLenum status;
+
+    if (likely (surface->fb))
+        return;
+
+    /* Create a framebuffer object wrapping the texture so that we can render
+     * to it.
+     */
+    glGenFramebuffersEXT (1, &surface->fb);
+    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
+    glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
+			       GL_COLOR_ATTACHMENT0_EXT,
+			       ctx->tex_target,
+			       surface->tex,
+			       0);
+
+    status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
+    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+	fprintf (stderr, "destination is framebuffer incomplete\n");
+}
+
 void
 _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
                                    cairo_gl_surface_t *surface)
@@ -233,6 +258,7 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
     ctx->current_target = surface;
 
     if (_cairo_gl_surface_is_texture (surface)) {
+        _cairo_gl_ensure_framebuffer (ctx, surface);
         glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
         glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
         glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index fe5be0c..eaf1143 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -235,7 +235,7 @@ _cairo_gl_surface_init (cairo_device_t *device,
 static cairo_always_inline cairo_bool_t cairo_warn
 _cairo_gl_surface_is_texture (cairo_gl_surface_t *surface)
 {
-    return surface->fb != 0;
+    return surface->tex != 0;
 }
 
 cairo_private cairo_status_t
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 1d26413..9a75e28 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -242,7 +242,6 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
 {
     cairo_gl_surface_t *surface;
     GLenum format;
-    cairo_status_t status;
 
     assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size);
 
@@ -289,22 +288,6 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
     glTexImage2D (ctx->tex_target, 0, format, width, height, 0,
 		  format, GL_UNSIGNED_BYTE, NULL);
 
-    /* Create a framebuffer object wrapping the texture so that we can render
-     * to it.
-     */
-    glGenFramebuffersEXT (1, &surface->fb);
-    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
-    glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
-			       GL_COLOR_ATTACHMENT0_EXT,
-			       ctx->tex_target,
-			       surface->tex,
-			       0);
-    ctx->current_target = NULL;
-
-    status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
-    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
-	fprintf (stderr, "destination is framebuffer incomplete\n");
-
     return &surface->base;
 }
 
@@ -707,7 +690,8 @@ _cairo_gl_surface_finish (void *abstract_surface)
     if (ctx->current_target == surface)
 	ctx->current_target = NULL;
 
-    glDeleteFramebuffersEXT (1, &surface->fb);
+    if (surface->fb)
+        glDeleteFramebuffersEXT (1, &surface->fb);
     glDeleteTextures (1, &surface->tex);
 
     _cairo_gl_context_release (ctx);
commit 1c15510c3d00553aba9ec4fd4e6764da3cdb0a41
Author: Benjamin Otte <otte at redhat.com>
Date:   Sun May 30 20:12:31 2010 +0200

    Call cairo_surface_flush() before setting finished
    
    With the current code, the surface will never be flushed as the flush
    function checks if the surface is finished, and if so, doesn't call the
    vfunc. Ooops.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index e8accfc..8a41883 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -663,8 +663,8 @@ cairo_surface_finish (cairo_surface_t *surface)
     if (surface->snapshot_of != NULL)
 	_cairo_surface_detach_snapshot (surface);
 
-    surface->finished = TRUE;
     cairo_surface_flush (surface);
+    surface->finished = TRUE;
 
     /* call finish even if in error mode */
     if (surface->backend->finish) {
commit 467d5e7f90b9edfb62ca71e67608704424a10aca
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 21:56:57 2010 +0200

    gl: Flush properly in set_destination

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index a957381..1741ac0 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -223,23 +223,24 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 
 void
 _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
-                           cairo_gl_surface_t *surface)
+                                   cairo_gl_surface_t *surface)
 {
-    cairo_surface_flush (&surface->base);
-
-    if (ctx->current_target != surface) {
-	ctx->current_target = surface;
-
-	if (_cairo_gl_surface_is_texture (surface)) {
-	    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
-	    glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
-	    glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
-	} else {
-	    ctx->make_current (ctx, surface);
-	    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
-	    glDrawBuffer (GL_BACK_LEFT);
-	    glReadBuffer (GL_BACK_LEFT);
-	}
+    if (ctx->current_target == surface)
+        return;
+
+    _cairo_gl_composite_flush (ctx);
+
+    ctx->current_target = surface;
+
+    if (_cairo_gl_surface_is_texture (surface)) {
+        glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
+        glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
+        glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
+    } else {
+        ctx->make_current (ctx, surface);
+        glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
+        glDrawBuffer (GL_BACK_LEFT);
+        glReadBuffer (GL_BACK_LEFT);
     }
 
     glViewport (0, 0, surface->width, surface->height);
commit e15348d8d0bbff6968b1f640e63315d159f143f5
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 21:55:26 2010 +0200

    gl: Don't reset vertex size

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 24291cf..f720614 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -960,7 +960,7 @@ cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
                            cairo_gl_context_t **ctx_out)
 {
-    unsigned int dst_size, src_size, mask_size;
+    unsigned int dst_size, src_size, mask_size, vertex_size;
     cairo_gl_context_t *ctx;
     cairo_status_t status;
     cairo_bool_t component_alpha;
@@ -1008,7 +1008,11 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     src_size  = _cairo_gl_operand_get_vertex_size (setup->src.type);
     mask_size = _cairo_gl_operand_get_vertex_size (setup->mask.type);
 
-    ctx->vertex_size = dst_size + src_size + mask_size;
+    vertex_size = dst_size + src_size + mask_size;
+    if (ctx->vertex_size != vertex_size) {
+        _cairo_gl_composite_flush (ctx);
+        ctx->vertex_size = vertex_size;
+    }
 
     _cairo_gl_context_set_destination (ctx, setup->dst);
     _cairo_gl_set_operator (setup->dst,
@@ -1243,8 +1247,6 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
 
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
-
-    ctx->vertex_size = 0;
 }
 
 void
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 603de6c..a957381 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -80,6 +80,7 @@ _gl_flush (void *device)
         ctx->clip_region = NULL;
     }
 
+    ctx->vertex_size = 0;
     ctx->pre_shader = NULL;
     _cairo_gl_set_shader (ctx, NULL);
 
commit a8d6ac1efc3f1f5ff4f92f4e7a3492e62518f3f7
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 21:51:08 2010 +0200

    gl: Remove check if we're between begin/end
    
    This will be useless soon, because we will keep the current state alive as
    long as possible.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index ff8fc0c..24291cf 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -972,7 +972,6 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     if (unlikely (status))
 	return status;
 
-    assert (! _cairo_gl_context_is_in_progress (ctx));
     glEnable (GL_BLEND);
 
     component_alpha = ((setup->mask.type == CAIRO_GL_OPERAND_TEXTURE) &&
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index f28b0f5..fe5be0c 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -226,13 +226,6 @@ _cairo_gl_context_create_in_error (cairo_status_t status)
 cairo_private cairo_status_t
 _cairo_gl_context_init (cairo_gl_context_t *ctx);
 
-static cairo_always_inline cairo_bool_t cairo_warn
-_cairo_gl_context_is_in_progress (cairo_gl_context_t *ctx)
-{
-    /* This variable gets set when _begin() is called */
-    return ctx->vertex_size != 0;
-}
-
 cairo_private void
 _cairo_gl_surface_init (cairo_device_t *device,
 			cairo_gl_surface_t *surface,
commit 8f675fb801f7864aa52778d4d53d7ab68f4e664b
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 21:46:52 2010 +0200

    gl: Stop disabling the vertex array and the array buffer

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 52d265a..ff8fc0c 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1023,12 +1023,12 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
         }
         _cairo_gl_set_shader (ctx, shader);
         _cairo_gl_composite_bind_to_shader (ctx, setup);
-    }
 
-    glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
+        glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
 
-    glVertexPointer (2, GL_FLOAT, ctx->vertex_size, NULL);
-    glEnableClientState (GL_VERTEX_ARRAY);
+        glVertexPointer (2, GL_FLOAT, ctx->vertex_size, NULL);
+        glEnableClientState (GL_VERTEX_ARRAY);
+    }
 
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size);
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size);
@@ -1242,10 +1242,6 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
 {
     _cairo_gl_composite_flush (ctx);
 
-    glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
-
-    glDisableClientState (GL_VERTEX_ARRAY);
-
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
 
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index d7a0694..603de6c 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -83,6 +83,10 @@ _gl_flush (void *device)
     ctx->pre_shader = NULL;
     _cairo_gl_set_shader (ctx, NULL);
 
+    glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
+
+    glDisableClientState (GL_VERTEX_ARRAY);
+
     glDisable (GL_SCISSOR_TEST);
     glDisable (GL_BLEND);
 
commit bef0b541497eb5a621df0b5528e08adb0beff961
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 21:08:17 2010 +0200

    gl: Do not reset shaders on _end()
    
    Instead, keep the shader around until cairo_device_flush() is called.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index d364e57..52d265a 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -733,7 +733,7 @@ void
 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
                                    cairo_gl_tex_t tex_unit)
 {
-    assert (ctx->vb == NULL);
+    assert (_cairo_gl_context_is_flushed (ctx));
 
     switch (ctx->operands[tex_unit].type) {
     default:
@@ -860,6 +860,7 @@ static cairo_status_t
 _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
                                             cairo_gl_composite_t *setup)
 {
+    cairo_gl_shader_t *pre_shader = NULL;
     cairo_status_t status;
 
     /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
@@ -938,7 +939,6 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
      * lets two values come out of the shader and into the blend unit.
      */
     if (setup->op == CAIRO_OPERATOR_OVER) {
-        cairo_gl_shader_t *pre_shader;
 	setup->op = CAIRO_OPERATOR_ADD;
 	status = _cairo_gl_get_shader_by_type (ctx,
                                                setup->src.type,
@@ -947,12 +947,12 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
                                                &pre_shader);
         if (unlikely (status))
             return status;
-
-        _cairo_gl_set_shader (ctx, pre_shader);
-        _cairo_gl_composite_bind_to_shader (ctx, setup);
-        ctx->pre_shader = pre_shader;
     }
 
+    if (ctx->pre_shader != pre_shader)
+        _cairo_gl_composite_flush (ctx);
+    ctx->pre_shader = pre_shader;
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -983,6 +983,11 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
         status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
         if (unlikely (status))
             goto FAIL;
+    } else {
+        if (ctx->pre_shader) {
+            _cairo_gl_composite_flush (ctx);
+            ctx->pre_shader = NULL;
+        }
     }
 
     status = _cairo_gl_get_shader_by_type (ctx,
@@ -995,6 +1000,8 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
         ctx->pre_shader = NULL;
         goto FAIL;
     }
+    if (ctx->current_shader != shader)
+        _cairo_gl_composite_flush (ctx);
 
     status = CAIRO_STATUS_SUCCESS;
 
@@ -1009,8 +1016,14 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
                             setup->op,
                             component_alpha);
 
-    _cairo_gl_set_shader (ctx, shader);
-    _cairo_gl_composite_bind_to_shader (ctx, setup);
+    if (_cairo_gl_context_is_flushed (ctx)) {
+        if (ctx->pre_shader) {
+            _cairo_gl_set_shader (ctx, ctx->pre_shader);
+            _cairo_gl_composite_bind_to_shader (ctx, setup);
+        }
+        _cairo_gl_set_shader (ctx, shader);
+        _cairo_gl_composite_bind_to_shader (ctx, setup);
+    }
 
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
 
@@ -1062,7 +1075,7 @@ _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
 {
     unsigned int count;
 
-    if (ctx->vb_offset == 0)
+    if (_cairo_gl_context_is_flushed (ctx))
         return;
 
     count = ctx->vb_offset / ctx->vertex_size;
@@ -1231,15 +1244,11 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
 
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
 
-    _cairo_gl_set_shader (ctx, NULL);
-
     glDisableClientState (GL_VERTEX_ARRAY);
 
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
 
-    ctx->pre_shader = NULL;
-
     ctx->vertex_size = 0;
 }
 
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 385cb68..d7a0694 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -80,6 +80,9 @@ _gl_flush (void *device)
         ctx->clip_region = NULL;
     }
 
+    ctx->pre_shader = NULL;
+    _cairo_gl_set_shader (ctx, NULL);
+
     glDisable (GL_SCISSOR_TEST);
     glDisable (GL_BLEND);
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 511f654..f28b0f5 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -398,6 +398,12 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx);
 cairo_private void
 _cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx);
 
+static cairo_always_inline cairo_bool_t
+_cairo_gl_context_is_flushed (cairo_gl_context_t *ctx)
+{
+    return ctx->vb == NULL;
+}
+
 cairo_private cairo_status_t
 _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
                               cairo_gl_operand_type_t source,
commit 534c14729921cbc2f8e24575eb792de9ddb96e23
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 21:06:58 2010 +0200

    region: clarify docs of cairo_region_equal()

diff --git a/src/cairo-region.c b/src/cairo-region.c
index 1df44b8..565a7de 100644
--- a/src/cairo-region.c
+++ b/src/cairo-region.c
@@ -760,13 +760,14 @@ slim_hidden_def (cairo_region_contains_point);
 
 /**
  * cairo_region_equal:
- * @region_a: a #cairo_region_t
- * @region_b: a #cairo_region_t
+ * @region_a: a #cairo_region_t or %NULL
+ * @region_b: a #cairo_region_t or %NULL
  *
- * Compares whether region_a is equivalent to region_b.
+ * Compares whether region_a is equivalent to region_b. %NULL as an argument
+ * is equal to itself, but not to any non-%NULL region.
  *
  * Return value: %TRUE if both regions contained the same coverage,
- * %FALSE if it is not.
+ * %FALSE if it is not or any region is in an error status.
  *
  * Since: 1.10
  **/
commit 0fc6f08981604ffdd0109362dcbbd9773501cd9a
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 20:45:52 2010 +0200

    gl: Make _shader_by_type() a getter
    
    And refactor code to do the current_shader assigning itself.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index edab8b3..d364e57 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -938,16 +938,19 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
      * lets two values come out of the shader and into the blend unit.
      */
     if (setup->op == CAIRO_OPERATOR_OVER) {
+        cairo_gl_shader_t *pre_shader;
 	setup->op = CAIRO_OPERATOR_ADD;
-	status = _cairo_gl_set_shader_by_type (ctx,
+	status = _cairo_gl_get_shader_by_type (ctx,
                                                setup->src.type,
                                                setup->mask.type,
-                                               CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA);
+                                               CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
+                                               &pre_shader);
         if (unlikely (status))
             return status;
 
+        _cairo_gl_set_shader (ctx, pre_shader);
         _cairo_gl_composite_bind_to_shader (ctx, setup);
-        ctx->pre_shader = ctx->current_shader;
+        ctx->pre_shader = pre_shader;
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -961,6 +964,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     cairo_gl_context_t *ctx;
     cairo_status_t status;
     cairo_bool_t component_alpha;
+    cairo_gl_shader_t *shader;
 
     assert (setup->dst);
 
@@ -981,11 +985,12 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
             goto FAIL;
     }
 
-    status = _cairo_gl_set_shader_by_type (ctx,
+    status = _cairo_gl_get_shader_by_type (ctx,
                                            setup->src.type,
                                            setup->mask.type,
                                            component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
-                                                           : CAIRO_GL_SHADER_IN_NORMAL);
+                                                           : CAIRO_GL_SHADER_IN_NORMAL,
+                                           &shader);
     if (unlikely (status)) {
         ctx->pre_shader = NULL;
         goto FAIL;
@@ -1004,6 +1009,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
                             setup->op,
                             component_alpha);
 
+    _cairo_gl_set_shader (ctx, shader);
     _cairo_gl_composite_bind_to_shader (ctx, setup);
 
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index f82a45c..511f654 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -399,10 +399,11 @@ cairo_private void
 _cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx);
 
 cairo_private cairo_status_t
-_cairo_gl_set_shader_by_type (cairo_gl_context_t *ctx,
+_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
                               cairo_gl_operand_type_t source,
                               cairo_gl_operand_type_t mask,
-                              cairo_gl_shader_in_t in);
+                              cairo_gl_shader_in_t in,
+                              cairo_gl_shader_t **shader);
 
 cairo_private void
 _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index c61f73f..b39c500 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -924,17 +924,20 @@ _cairo_gl_set_shader (cairo_gl_context_t *ctx,
 }
 
 cairo_status_t
-_cairo_gl_set_shader_by_type (cairo_gl_context_t *ctx,
+_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
                               cairo_gl_operand_type_t source,
                               cairo_gl_operand_type_t mask,
-                              cairo_gl_shader_in_t in)
+                              cairo_gl_shader_in_t in,
+                              cairo_gl_shader_t **shader)
 {
     cairo_shader_cache_entry_t lookup, *entry;
     char *fs_source;
     cairo_status_t status;
 
-    if (ctx->shader_impl == NULL)
+    if (ctx->shader_impl == NULL) {
+        *shader = NULL;
 	return CAIRO_STATUS_SUCCESS;
+    }
 
     lookup.src = source;
     lookup.mask = mask;
@@ -946,7 +949,7 @@ _cairo_gl_set_shader_by_type (cairo_gl_context_t *ctx,
     entry = _cairo_cache_lookup (&ctx->shaders, &lookup.base);
     if (entry) {
         assert (entry->shader.program);
-        _cairo_gl_set_shader (ctx, &entry->shader);
+        *shader = &entry->shader;
 	return CAIRO_STATUS_SUCCESS;
     }
 
@@ -988,7 +991,7 @@ _cairo_gl_set_shader_by_type (cairo_gl_context_t *ctx,
 	return status;
     }
 
-    _cairo_gl_set_shader (ctx, &entry->shader);
+    *shader = &entry->shader;
 
     return CAIRO_STATUS_SUCCESS;
 }
commit 2971ca049881298cd171cf27cd3beb49d2c0572f
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 20:39:22 2010 +0200

    gl: bind all shader variables at the same place
    
    Avoids the need to bind the shader when creating it.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 29e26e7..edab8b3 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -486,13 +486,14 @@ _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
 static void
 _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                                   cairo_gl_operand_t *operand,
-                                  const char         *name)
+                                  cairo_gl_tex_t      tex_unit)
 {
     char uniform_name[50];
     char *custom_part;
+    static const char *names[] = { "source", "mask" };
 
-    strcpy (uniform_name, name);
-    custom_part = uniform_name + strlen (name);
+    strcpy (uniform_name, names[tex_unit]);
+    custom_part = uniform_name + strlen (names[tex_unit]);
 
     switch (operand->type) {
     default:
@@ -500,7 +501,6 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
         ASSERT_NOT_REACHED;
     case CAIRO_GL_OPERAND_NONE:
     case CAIRO_GL_OPERAND_SPANS:
-    case CAIRO_GL_OPERAND_TEXTURE:
         break;
     case CAIRO_GL_OPERAND_CONSTANT:
         strcpy (custom_part, "_constant");
@@ -521,6 +521,10 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                                       uniform_name,
 				      operand->linear.segment_x,
 				      operand->linear.segment_y);
+        strcpy (custom_part, "_sampler");
+	_cairo_gl_shader_bind_texture(ctx,
+                                      uniform_name,
+                                      tex_unit);
         break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
         strcpy (custom_part, "_matrix");
@@ -540,6 +544,16 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
         _cairo_gl_shader_bind_float  (ctx,
                                       uniform_name,
                                       operand->radial.radius_1);
+        strcpy (custom_part, "_sampler");
+	_cairo_gl_shader_bind_texture(ctx,
+                                      uniform_name,
+                                      tex_unit);
+        break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+        strcpy (custom_part, "_sampler");
+	_cairo_gl_shader_bind_texture(ctx,
+                                      uniform_name,
+                                      tex_unit);
         break;
     }
 }
@@ -551,8 +565,8 @@ _cairo_gl_composite_bind_to_shader (cairo_gl_context_t   *ctx,
     if (ctx->current_shader == NULL)
         return;
 
-    _cairo_gl_operand_bind_to_shader (ctx, &setup->src, "source");
-    _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, "mask");
+    _cairo_gl_operand_bind_to_shader (ctx, &setup->src,  CAIRO_GL_TEX_SOURCE);
+    _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
 }
 
 static void
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 2b55119..c61f73f 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -990,16 +990,5 @@ _cairo_gl_set_shader_by_type (cairo_gl_context_t *ctx,
 
     _cairo_gl_set_shader (ctx, &entry->shader);
 
-    if (source != CAIRO_GL_OPERAND_CONSTANT &&
-	source != CAIRO_GL_OPERAND_SPANS &&
-	source != CAIRO_GL_OPERAND_NONE) {
-	_cairo_gl_shader_bind_texture (ctx, "source_sampler", 0);
-    }
-    if (mask != CAIRO_GL_OPERAND_CONSTANT &&
-	mask != CAIRO_GL_OPERAND_SPANS &&
-	mask != CAIRO_GL_OPERAND_NONE) {
-	_cairo_gl_shader_bind_texture (ctx, "mask_sampler", 1);
-    }
-
     return CAIRO_STATUS_SUCCESS;
 }
commit e11d8370e0503f085beaa355d85fa6991cd497da
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 17:37:19 2010 +0200

    gl: Set GL_BLEND and GL_SCISSOR_TEST globally
    
    Note that we do set them unconditionally in _begin() because a flush
    might have cleared them.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 7691ef9..29e26e7 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -816,7 +816,6 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
 	    dst_factor = GL_SRC_COLOR;
     }
 
-    glEnable (GL_BLEND);
     if (dst->base.content == CAIRO_CONTENT_ALPHA) {
         glBlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
     } else {
@@ -956,6 +955,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
 	return status;
 
     assert (! _cairo_gl_context_is_in_progress (ctx));
+    glEnable (GL_BLEND);
 
     component_alpha = ((setup->mask.type == CAIRO_GL_OPERAND_TEXTURE) &&
                        setup->mask.texture.attributes.has_component_alpha);
@@ -1004,6 +1004,8 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     ctx->clip_region = cairo_region_reference (setup->clip_region);
     if (ctx->clip_region)
 	glEnable (GL_SCISSOR_TEST);
+    else
+	glDisable (GL_SCISSOR_TEST);
 
     *ctx_out = ctx;
 
@@ -1207,16 +1209,9 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
 {
     _cairo_gl_composite_flush (ctx);
 
-    if (ctx->clip_region) {
-	glDisable (GL_SCISSOR_TEST);
-        cairo_region_destroy (ctx->clip_region);
-        ctx->clip_region = NULL;
-    }
-
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
 
     _cairo_gl_set_shader (ctx, NULL);
-    glDisable (GL_BLEND);
 
     glDisableClientState (GL_VERTEX_ARRAY);
 
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index bf57038..385cb68 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -75,6 +75,14 @@ _gl_flush (void *device)
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
 
+    if (ctx->clip_region) {
+        cairo_region_destroy (ctx->clip_region);
+        ctx->clip_region = NULL;
+    }
+
+    glDisable (GL_SCISSOR_TEST);
+    glDisable (GL_BLEND);
+
     _cairo_gl_context_release (ctx);
 
     return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index e64a05a..1d26413 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -334,6 +334,7 @@ _cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
         a = 1.0;
     }
 
+    glDisable (GL_SCISSOR_TEST);
     glClearColor (r, g, b, a);
     glClear (GL_COLOR_BUFFER_BIT);
     _cairo_gl_context_release (ctx);
commit 7747f6d9146c19419fdc4fbbdf72eed42dfa731d
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 17:19:56 2010 +0200

    gl: Introduce flush functions
    
    The flush functions will clear the state that will in the future be kep
    unconditionally.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index c576b67..7691ef9 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -249,8 +249,6 @@ _cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
 
     assert (surface->base.backend == &_cairo_gl_surface_backend);
 
-    cairo_surface_flush (&surface->base);
-
     operand->type = CAIRO_GL_OPERAND_TEXTURE;
     operand->texture.surface = surface;
     operand->texture.tex = surface->tex;
@@ -717,10 +715,12 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
         _cairo_gl_operand_setup_fixed (operand, tex_unit);
 }
 
-static void
+void
 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
                                    cairo_gl_tex_t tex_unit)
 {
+    assert (ctx->vb == NULL);
+
     switch (ctx->operands[tex_unit].type) {
     default:
     case CAIRO_GL_OPERAND_COUNT:
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 0d52058..bf57038 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -60,6 +60,26 @@ _gl_unlock (void *device)
     ctx->current_target = NULL;
 }
 
+static cairo_status_t
+_gl_flush (void *device)
+{
+    cairo_gl_context_t *ctx;
+    cairo_status_t status;
+
+    status = _cairo_gl_context_acquire (device, &ctx);
+    if (unlikely (status))
+        return status;
+
+    _cairo_gl_composite_flush (ctx);
+
+    _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
+    _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
+
+    _cairo_gl_context_release (ctx);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static void
 _gl_finish (void *device)
 {
@@ -106,7 +126,7 @@ static const cairo_device_backend_t _cairo_gl_device_backend = {
     _gl_lock,
     _gl_unlock,
 
-    NULL, /* flush */
+    _gl_flush, /* flush */
     _gl_finish,
     _gl_destroy,
 };
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 5e5d91f..f82a45c 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -350,6 +350,10 @@ cairo_private void
 _cairo_gl_composite_end (cairo_gl_context_t *ctx,
                          cairo_gl_composite_t *setup);
 
+cairo_private void
+_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
+                                   cairo_gl_tex_t tex_unit);
+
 cairo_private cairo_bool_t
 _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
 				     GLenum *internal_format, GLenum *format,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index f7340ee..e64a05a 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -697,12 +697,18 @@ _cairo_gl_surface_finish (void *abstract_surface)
     if (unlikely (status))
         return status;
 
-    glDeleteFramebuffersEXT (1, &surface->fb);
-    glDeleteTextures (1, &surface->tex);
-
+    if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
+        ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
+        _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
+    if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
+        ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
+        _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
     if (ctx->current_target == surface)
 	ctx->current_target = NULL;
 
+    glDeleteFramebuffersEXT (1, &surface->fb);
+    glDeleteTextures (1, &surface->tex);
+
     _cairo_gl_context_release (ctx);
 
     return CAIRO_STATUS_SUCCESS;
@@ -1276,6 +1282,28 @@ _cairo_gl_surface_get_font_options (void                  *abstract_surface,
     cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
 }
 
+static cairo_status_t
+_cairo_gl_surface_flush (void *abstract_surface)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+    cairo_gl_context_t *ctx;
+
+    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+    if (unlikely (status))
+        return status;
+
+    if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
+         ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) ||
+        (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
+         ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) ||
+        (ctx->current_target == surface))
+      _cairo_gl_composite_flush (ctx);
+
+    _cairo_gl_context_release (ctx);
+
+    return CAIRO_STATUS_SUCCESS;
+}
 
 static cairo_int_status_t
 _cairo_gl_surface_paint (void *abstract_surface,
@@ -1320,7 +1348,7 @@ const cairo_surface_backend_t _cairo_gl_surface_backend = {
     _cairo_gl_surface_get_extents,
     NULL, /* old_show_glyphs */
     _cairo_gl_surface_get_font_options,
-    NULL, /* flush */
+    _cairo_gl_surface_flush,
     NULL, /* mark_dirty_rectangle */
     _cairo_gl_surface_scaled_font_fini,
     _cairo_gl_surface_scaled_glyph_fini,
commit 5c74beaaa5dedd82f891f1cc109142f7b6e222a8
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 17:19:45 2010 +0200

    docs: fix typo

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 8b67e66..e8accfc 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1002,7 +1002,7 @@ slim_hidden_def (cairo_surface_get_font_options);
  * @surface: a #cairo_surface_t
  *
  * Do any pending drawing for the surface and also restore any
- * temporary modification's cairo has made to the surface's
+ * temporary modifications cairo has made to the surface's
  * state. This function must be called before switching from
  * drawing on the surface with cairo to drawing on it directly
  * with native APIs. If the surface doesn't support direct access,
commit 92d7b1eee96e6b1448aaf3c95a44238fa0eeff48
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 16:19:12 2010 +0200

    device: Make flush vfunc return a cairo_status_t
    
    Mirror the behavior of the surface flush vfunc: Make it return a status
    and if it's an error set it on the device.

diff --git a/src/cairo-device-private.h b/src/cairo-device-private.h
index 0c977e8..6eb44f3 100644
--- a/src/cairo-device-private.h
+++ b/src/cairo-device-private.h
@@ -60,7 +60,7 @@ struct _cairo_device_backend {
     void (*lock) (void *device);
     void (*unlock) (void *device);
 
-    void (*flush) (void *device);
+    cairo_warn cairo_status_t (*flush) (void *device);
     void (*finish) (void *device);
     void (*destroy) (void *device);
 };
diff --git a/src/cairo-device.c b/src/cairo-device.c
index f8a499e..a090f5b 100644
--- a/src/cairo-device.c
+++ b/src/cairo-device.c
@@ -150,11 +150,16 @@ cairo_device_status (cairo_device_t *device)
 void
 cairo_device_flush (cairo_device_t *device)
 {
+    cairo_status_t status;
+
     if (device == NULL || device->status)
 	return;
 
-    if (device->backend->flush != NULL)
-	device->backend->flush (device);
+    if (device->backend->flush != NULL) {
+	status = device->backend->flush (device);
+	if (unlikely (status))
+	    status = _cairo_device_set_error (device, status);
+    }
 }
 slim_hidden_def (cairo_device_flush);
 
diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c
index 1b52a7d..55b5b8e 100644
--- a/src/cairo-xml-surface.c
+++ b/src/cairo-xml-surface.c
@@ -215,13 +215,15 @@ _format_to_string (cairo_format_t format)
     return "INVALID";
 }
 
-static void
+static cairo_status_t
 _device_flush (void *abstract_device)
 {
     cairo_xml_t *xml = abstract_device;
     cairo_status_t status;
 
     status = _cairo_output_stream_flush (xml->stream);
+
+    return status;
 }
 
 static void
commit 63e3cf3888d5b55295a04c4af28e876c04245b85
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 15:09:23 2010 +0200

    gl: Move unsetting the state into the operand destroy function

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 367eb83..c576b67 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -721,7 +721,35 @@ static void
 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
                                    cairo_gl_tex_t tex_unit)
 {
-  memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
+    switch (ctx->operands[tex_unit].type) {
+    default:
+    case CAIRO_GL_OPERAND_COUNT:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_NONE:
+        break;
+    case CAIRO_GL_OPERAND_SPANS:
+        glDisableClientState (GL_COLOR_ARRAY);
+        /* fall through */
+    case CAIRO_GL_OPERAND_CONSTANT:
+        if (ctx->current_shader == NULL) {
+            glActiveTexture (GL_TEXTURE0 + tex_unit);
+            glDisable (ctx->tex_target);
+        }
+        break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+        glActiveTexture (GL_TEXTURE0 + tex_unit);
+        glDisable (ctx->tex_target);
+        glClientActiveTexture (GL_TEXTURE0 + tex_unit);
+        glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+        break;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+        glActiveTexture (GL_TEXTURE0 + tex_unit);
+        glDisable (GL_TEXTURE_1D);
+        break;
+    }
+
+    memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
 }
 
 /* Swizzles the source for creating the "source alpha" value
@@ -1191,19 +1219,6 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
     glDisable (GL_BLEND);
 
     glDisableClientState (GL_VERTEX_ARRAY);
-    glDisableClientState (GL_COLOR_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);
 
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
commit b9b85dbf3706fe9e50f40b5fda655e71931c2d7f
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 13:42:11 2010 +0200

    gl: get rid of the operand's pattern variable
    
    Now someone just needs to teach cairo-gl to not use
    cairo_pattern_acquire_surface() and we could avoid the nasty hack in
    cairo_gl_operand_destroy().

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 3067be4..367eb83 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -87,7 +87,7 @@ _cairo_gl_gradient_sample_width (const cairo_gradient_pattern_t *gradient)
 
 static cairo_status_t
 _render_gradient (const cairo_gl_context_t *ctx,
-		  cairo_gradient_pattern_t *pattern,
+		  const cairo_gradient_pattern_t *pattern,
 		  void *bytes,
 		  int width)
 {
@@ -151,7 +151,7 @@ _render_gradient (const cairo_gl_context_t *ctx,
 
 static cairo_int_status_t
 _cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
-				   cairo_gradient_pattern_t *pattern,
+				   const cairo_gradient_pattern_t *pattern,
 				   GLuint *tex)
 {
     cairo_gl_context_t *ctx;
@@ -241,7 +241,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
 	(attributes->extend == CAIRO_EXTEND_REPEAT ||
 	 attributes->extend == CAIRO_EXTEND_REFLECT))
     {
-	_cairo_pattern_release_surface (operand->pattern,
+	_cairo_pattern_release_surface (src,
 					&surface->base,
 					attributes);
 	return UNSUPPORTED ("EXT_texture_rectangle with repeat/reflect");
@@ -300,9 +300,10 @@ _cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
 
 static cairo_status_t
 _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
-				 cairo_gl_surface_t *dst)
+				 cairo_gl_surface_t *dst,
+                                 const cairo_pattern_t *pattern)
 {
-    cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *)operand->pattern;
+    const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
     cairo_status_t status;
 
     if (! _cairo_gl_device_has_glsl (dst->base.device))
@@ -328,7 +329,7 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 	 */
 	cairo_matrix_init_translate (&operand->linear.m, -x0, -y0);
 	cairo_matrix_multiply (&operand->linear.m,
-			       &operand->pattern->matrix,
+			       &pattern->matrix,
 			       &operand->linear.m);
 	cairo_matrix_translate (&operand->linear.m, 0, dst->height);
 	cairo_matrix_scale (&operand->linear.m, 1.0, -1.0);
@@ -360,7 +361,7 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 	 */
 	cairo_matrix_init_translate (&operand->radial.m, -x0, -y0);
 	cairo_matrix_multiply (&operand->radial.m,
-			       &operand->pattern->matrix,
+			       &pattern->matrix,
 			       &operand->radial.m);
 	cairo_matrix_translate (&operand->radial.m, 0, dst->height);
 	cairo_matrix_scale (&operand->radial.m, 1.0, -1.0);
@@ -390,7 +391,7 @@ _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
 	glDeleteTextures (1, &operand->radial.tex);
 	break;
     case CAIRO_GL_OPERAND_TEXTURE:
-        _cairo_pattern_release_surface (operand->pattern,
+        _cairo_pattern_release_surface (NULL, /* XXX */
                                         &operand->texture.surface->base,
                                         &operand->texture.attributes);
 	break;
@@ -415,15 +416,13 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
 {
     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 (operand, dst);
+	status = _cairo_gl_gradient_operand_init (operand, dst, pattern);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index d8520df..5e5d91f 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -157,8 +157,6 @@ typedef struct cairo_gl_operand {
 	    float radius_1;
 	} radial;
     };
-
-    const cairo_pattern_t *pattern;
 } cairo_gl_operand_t;
 
 typedef struct _cairo_gl_context {
commit ae9517a39fdddec389553a64116140e222970ef0
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 13:18:28 2010 +0200

    gl: Check mask's attributes for component alpha
    
    ... and don't duplicate that information into the cairo_gl_composite_t

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 32940af..3067be4 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -462,7 +462,6 @@ _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
                               int width, int height)
 {
     _cairo_gl_operand_destroy (&setup->mask);
-    setup->has_component_alpha = pattern && pattern->has_component_alpha;
     if (pattern == NULL)
         return CAIRO_STATUS_SUCCESS;
 
@@ -478,7 +477,6 @@ _cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup)
 {
     _cairo_gl_operand_destroy (&setup->mask);
     setup->mask.type = CAIRO_GL_OPERAND_SPANS;
-    setup->has_component_alpha = FALSE;
 }
 
 void
@@ -922,6 +920,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     unsigned int dst_size, src_size, mask_size;
     cairo_gl_context_t *ctx;
     cairo_status_t status;
+    cairo_bool_t component_alpha;
 
     assert (setup->dst);
 
@@ -931,8 +930,11 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
 
     assert (! _cairo_gl_context_is_in_progress (ctx));
 
+    component_alpha = ((setup->mask.type == CAIRO_GL_OPERAND_TEXTURE) &&
+                       setup->mask.texture.attributes.has_component_alpha);
+
     /* Do various magic for component alpha */
-    if (setup->has_component_alpha) {
+    if (component_alpha) {
         status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
         if (unlikely (status))
             goto FAIL;
@@ -941,8 +943,8 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     status = _cairo_gl_set_shader_by_type (ctx,
                                            setup->src.type,
                                            setup->mask.type,
-                                           setup->has_component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
-                                                                      : CAIRO_GL_SHADER_IN_NORMAL);
+                                           component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
+                                                           : CAIRO_GL_SHADER_IN_NORMAL);
     if (unlikely (status)) {
         ctx->pre_shader = NULL;
         goto FAIL;
@@ -959,7 +961,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     _cairo_gl_context_set_destination (ctx, setup->dst);
     _cairo_gl_set_operator (setup->dst,
                             setup->op,
-                            setup->has_component_alpha);
+                            component_alpha);
 
     _cairo_gl_composite_bind_to_shader (ctx, setup);
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index c2a1e13..d8520df 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -202,7 +202,6 @@ typedef struct _cairo_gl_context {
 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;
commit f72afc09d0b99030f5766e7bbbb05f6db606e195
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 13:14:09 2010 +0200

    gl: Merge fixed function setup into general texture setup

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index f81ebfe..32940af 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -618,7 +618,6 @@ _cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
     case CAIRO_GL_OPERAND_TEXTURE:
         glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0 + tex_unit);
         glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0 + tex_unit);
-	break;
         break;
     case CAIRO_GL_OPERAND_SPANS:
         glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
@@ -630,6 +629,37 @@ _cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
     case CAIRO_GL_OPERAND_NONE:
+        return;
+    }
+
+    switch (tex_unit) {
+    default:
+        ASSERT_NOT_REACHED;
+        break;
+    case CAIRO_GL_TEX_SOURCE:
+        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_OPERAND0_RGB, GL_SRC_COLOR);
+        glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+        break;
+
+    case CAIRO_GL_TEX_MASK:
+        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);
+
+        if (operand->type == CAIRO_GL_OPERAND_TEXTURE &&
+            operand->texture.attributes.has_component_alpha)
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+        else
+            glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+        glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
         break;
     }
 }
@@ -685,6 +715,9 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
         glEnable (GL_TEXTURE_1D);
         break;
     }
+
+    if (ctx->current_shader == NULL)
+        _cairo_gl_operand_setup_fixed (operand, tex_unit);
 }
 
 static void
@@ -694,24 +727,6 @@ _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
   memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
 }
 
-static void
-_cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
-			   cairo_gl_composite_t *setup)
-{
-    if (ctx->current_shader)
-        return;
-
-    glActiveTexture (GL_TEXTURE0);
-
-    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_OPERAND0_RGB, GL_SRC_COLOR);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-    _cairo_gl_operand_setup_fixed (&setup->src, CAIRO_GL_TEX_SOURCE);
-}
-
 /* Swizzles the source for creating the "source alpha" value
  * (src.aaaa * mask.argb) required by component alpha rendering.
  */
@@ -728,34 +743,6 @@ _cairo_gl_set_src_alpha (cairo_gl_context_t *ctx,
 }
 
 static void
-_cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
-			    cairo_gl_composite_t *setup,
-                            cairo_bool_t component_alpha)
-{
-    if (ctx->current_shader)
-        return;
-
-    glActiveTexture (GL_TEXTURE1);
-
-    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);
-
-    if (component_alpha)
-        glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-    else
-        glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-    _cairo_gl_operand_setup_fixed (&setup->mask, CAIRO_GL_TEX_MASK);
-}
-
-static void
 _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
 			cairo_bool_t component_alpha)
 {
@@ -984,9 +971,6 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size);
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size);
 
-    _cairo_gl_set_src_operand (ctx, setup);
-    _cairo_gl_set_mask_operand (ctx, setup, setup->has_component_alpha);
-
     cairo_region_destroy (ctx->clip_region);
     ctx->clip_region = cairo_region_reference (setup->clip_region);
     if (ctx->clip_region)
commit dd1faaf02e2a75ca8b9c484abd15726f5c6d3ac4
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 12:54:54 2010 +0200

    gl: Move function
    
    I wanna use it elsewhere and keep the diff small.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 0268ba5..f81ebfe 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -606,6 +606,35 @@ _cairo_gl_texture_set_attributes (cairo_gl_context_t         *ctx,
 }
 
 static void
+_cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
+                               cairo_gl_tex_t tex_unit)
+{
+    switch (operand->type) {
+    case CAIRO_GL_OPERAND_CONSTANT:
+        glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, operand->constant.color);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
+        break;
+    case CAIRO_GL_OPERAND_TEXTURE:
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0 + tex_unit);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0 + tex_unit);
+	break;
+        break;
+    case CAIRO_GL_OPERAND_SPANS:
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR);
+        break;
+    case CAIRO_GL_OPERAND_COUNT:
+    default:
+        ASSERT_NOT_REACHED;
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+    case CAIRO_GL_OPERAND_NONE:
+        break;
+    }
+}
+
+static void
 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
                                  cairo_gl_tex_t      tex_unit,
                                  cairo_gl_operand_t *operand,
@@ -666,35 +695,6 @@ _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
 }
 
 static void
-_cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
-                               cairo_gl_tex_t tex_unit)
-{
-    switch (operand->type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-        glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, operand->constant.color);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
-        break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0 + tex_unit);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0 + tex_unit);
-	break;
-        break;
-    case CAIRO_GL_OPERAND_SPANS:
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR);
-        break;
-    case CAIRO_GL_OPERAND_COUNT:
-    default:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
-    case CAIRO_GL_OPERAND_NONE:
-        break;
-    }
-}
-
-static void
 _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 			   cairo_gl_composite_t *setup)
 {
commit d03800313623fb2b9e7d15c6a659ceaaee2882e8
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 12:51:08 2010 +0200

    gl: Simplify mask operand setup code
    
    Component alpha just has one different value

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 59381f7..0268ba5 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -727,36 +727,10 @@ _cairo_gl_set_src_alpha (cairo_gl_context_t *ctx,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, activate ? GL_SRC_ALPHA : GL_SRC_COLOR);
 }
 
-/* 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)
-{
-    if (ctx->current_shader)
-        return;
-
-    glActiveTexture (GL_TEXTURE1);
-
-    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);
-
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-    _cairo_gl_operand_setup_fixed (&setup->mask, CAIRO_GL_TEX_MASK);
-}
-
 static void
 _cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
-			    cairo_gl_composite_t *setup)
+			    cairo_gl_composite_t *setup,
+                            cairo_bool_t component_alpha)
 {
     if (ctx->current_shader)
         return;
@@ -772,7 +746,10 @@ _cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+    if (component_alpha)
+        glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+    else
+        glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
     _cairo_gl_operand_setup_fixed (&setup->mask, CAIRO_GL_TEX_MASK);
@@ -1008,10 +985,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size);
 
     _cairo_gl_set_src_operand (ctx, setup);
-    if (setup->has_component_alpha)
-        _cairo_gl_set_component_alpha_mask_operand (ctx, setup);
-    else
-        _cairo_gl_set_mask_operand (ctx, setup);
+    _cairo_gl_set_mask_operand (ctx, setup, setup->has_component_alpha);
 
     cairo_region_destroy (ctx->clip_region);
     ctx->clip_region = cairo_region_reference (setup->clip_region);
commit e20261dddaa194ab4e980da8681e9378d7fd7ef1
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 12:48:59 2010 +0200

    gl: Get rid of operand argument to emit functions

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index ecd1b57..59381f7 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1138,7 +1138,6 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
 
 static inline void
 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
-                                 cairo_gl_composite_t *setup,
                                  GLfloat x,
                                  GLfloat y,
                                  uint8_t alpha)
@@ -1148,15 +1147,14 @@ _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
     *vb++ = x;
     *vb++ = y;
 
-    _cairo_gl_operand_emit (&setup->src, &vb, x, y, alpha);
-    _cairo_gl_operand_emit (&setup->mask, &vb, x, y, alpha);
+    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y, alpha);
+    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y, alpha);
 
     ctx->vb_offset += ctx->vertex_size;
 }
 
 void
 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
-                               cairo_gl_composite_t *setup,
                                GLfloat x1,
                                GLfloat y1,
                                GLfloat x2,
@@ -1165,18 +1163,17 @@ _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
 {
     _cairo_gl_composite_prepare_buffer (ctx, 6);
 
-    _cairo_gl_composite_emit_vertex (ctx, setup, x1, y1, alpha);
-    _cairo_gl_composite_emit_vertex (ctx, setup, x2, y1, alpha);
-    _cairo_gl_composite_emit_vertex (ctx, setup, x1, y2, alpha);
+    _cairo_gl_composite_emit_vertex (ctx, x1, y1, alpha);
+    _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
+    _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
 
-    _cairo_gl_composite_emit_vertex (ctx, setup, x2, y1, alpha);
-    _cairo_gl_composite_emit_vertex (ctx, setup, x2, y2, alpha);
-    _cairo_gl_composite_emit_vertex (ctx, setup, x1, y2, alpha);
+    _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
+    _cairo_gl_composite_emit_vertex (ctx, x2, y2, alpha);
+    _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
 }
 
 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,
@@ -1187,7 +1184,7 @@ _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
     *vb++ = x;
     *vb++ = y;
 
-    _cairo_gl_operand_emit (&setup->src, &vb, x, y, 0);
+    _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y, 0);
 
     *vb++ = glyph_x;
     *vb++ = glyph_y;
@@ -1197,7 +1194,6 @@ _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
 
 void
 _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
-                                cairo_gl_composite_t *setup,
                                 GLfloat x1,
                                 GLfloat y1,
                                 GLfloat x2,
@@ -1209,13 +1205,13 @@ _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
 {
     _cairo_gl_composite_prepare_buffer (ctx, 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, x1, y1, glyph_x1, glyph_y1);
+    _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
+    _cairo_gl_composite_emit_glyph_vertex (ctx, 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);
+    _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
+    _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
+    _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
 }
 
 void
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index d500785..91d3c20 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -342,7 +342,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	y2 = y1 + scaled_glyph->surface->height;
 
 	glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
-	_cairo_gl_composite_emit_glyph (ctx, &setup,
+	_cairo_gl_composite_emit_glyph (ctx,
 					x1, y1, x2, y2,
                                         glyph->p1.x, glyph->p1.y,
                                         glyph->p2.x, glyph->p2.y);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 9e653f4..c2a1e13 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -329,7 +329,6 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
 
 cairo_private void
 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
-                               cairo_gl_composite_t *setup,
                                GLfloat x1,
                                GLfloat y1,
                                GLfloat x2,
@@ -338,7 +337,6 @@ _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
 
 cairo_private void
 _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
-                                cairo_gl_composite_t *setup,
                                 GLfloat x1,
                                 GLfloat y1,
                                 GLfloat x2,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 53cba20..f7340ee 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -946,13 +946,13 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	    cairo_rectangle_int_t rect;
 
 	    cairo_region_get_rectangle (clip_region, i, &rect);
-            _cairo_gl_composite_emit_rect (ctx, &setup,
+            _cairo_gl_composite_emit_rect (ctx,
                                            rect.x,              rect.y,
                                            rect.x + rect.width, rect.y + rect.height,
                                            0);
 	}
     } else {
-        _cairo_gl_composite_emit_rect (ctx, &setup,
+        _cairo_gl_composite_emit_rect (ctx,
                                        dst_x,         dst_y,
                                        dst_x + width, dst_y + height,
                                        0);
@@ -1062,7 +1062,7 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
         goto CLEANUP;
 
     for (i = 0; i < num_rects; i++) {
-        _cairo_gl_composite_emit_rect (ctx, &setup,
+        _cairo_gl_composite_emit_rect (ctx,
                                        rects[i].x,
                                        rects[i].y,
                                        rects[i].x + rects[i].width,
@@ -1103,7 +1103,6 @@ _cairo_gl_render_bounded_spans (void *abstract_renderer,
     do {
 	if (spans[0].coverage) {
             _cairo_gl_composite_emit_rect (renderer->ctx,
-                                           &renderer->setup,
                                            spans[0].x, y,
                                            spans[1].x, y + height,
                                            spans[0].coverage);
@@ -1125,7 +1124,6 @@ _cairo_gl_render_unbounded_spans (void *abstract_renderer,
 
     if (num_spans == 0) {
         _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       &renderer->setup,
                                        renderer->xmin, y,
                                        renderer->xmax, y + height,
                                        0);
@@ -1134,7 +1132,6 @@ _cairo_gl_render_unbounded_spans (void *abstract_renderer,
 
     if (spans[0].x != renderer->xmin) {
         _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       &renderer->setup,
                                        renderer->xmin, y,
                                        spans[0].x,     y + height,
                                        0);
@@ -1142,7 +1139,6 @@ _cairo_gl_render_unbounded_spans (void *abstract_renderer,
 
     do {
         _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       &renderer->setup,
                                        spans[0].x, y,
                                        spans[1].x, y + height,
                                        spans[0].coverage);
@@ -1151,7 +1147,6 @@ _cairo_gl_render_unbounded_spans (void *abstract_renderer,
 
     if (spans[0].x != renderer->xmax) {
         _cairo_gl_composite_emit_rect (renderer->ctx,
-                                       &renderer->setup,
                                        spans[0].x,     y,
                                        renderer->xmax, y + height,
                                        0);
commit 8062fb352e6cd1d961f0fbc660779f4ad94c7508
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 11:03:09 2010 +0200

    gl: Add an enum for tex units
    
    Instead of hardcoding 0 for source and 1 for mask, use an enum. It's
    also clearer when functions take a cairo_gl_tex_t argument instead of a
    GLuint.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 55154c3..ecd1b57 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -607,7 +607,7 @@ _cairo_gl_texture_set_attributes (cairo_gl_context_t         *ctx,
 
 static void
 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
-                                 GLuint              tex_unit,
+                                 cairo_gl_tex_t      tex_unit,
                                  cairo_gl_operand_t *operand,
                                  unsigned int        vertex_offset)
 {
@@ -660,14 +660,14 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
 
 static void
 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
-                                   GLuint              tex_unit)
+                                   cairo_gl_tex_t tex_unit)
 {
   memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
 }
 
 static void
 _cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
-                               GLuint tex_unit)
+                               cairo_gl_tex_t tex_unit)
 {
     switch (operand->type) {
     case CAIRO_GL_OPERAND_CONSTANT:
@@ -709,7 +709,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
-    _cairo_gl_operand_setup_fixed (&setup->src, 0);
+    _cairo_gl_operand_setup_fixed (&setup->src, CAIRO_GL_TEX_SOURCE);
 }
 
 /* Swizzles the source for creating the "source alpha" value
@@ -751,7 +751,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
-    _cairo_gl_operand_setup_fixed (&setup->mask, 1);
+    _cairo_gl_operand_setup_fixed (&setup->mask, CAIRO_GL_TEX_MASK);
 }
 
 static void
@@ -775,7 +775,7 @@ _cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
-    _cairo_gl_operand_setup_fixed (&setup->mask, 1);
+    _cairo_gl_operand_setup_fixed (&setup->mask, CAIRO_GL_TEX_MASK);
 }
 
 static void
@@ -1004,8 +1004,8 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     glVertexPointer (2, GL_FLOAT, ctx->vertex_size, NULL);
     glEnableClientState (GL_VERTEX_ARRAY);
 
-    _cairo_gl_context_setup_operand (ctx, 0, &setup->src, dst_size);
-    _cairo_gl_context_setup_operand (ctx, 1, &setup->mask, dst_size + src_size);
+    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size);
+    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size);
 
     _cairo_gl_set_src_operand (ctx, setup);
     if (setup->has_component_alpha)
@@ -1250,8 +1250,8 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
     glDisable (GL_TEXTURE_1D);
     glDisable (ctx->tex_target);
 
-    _cairo_gl_context_destroy_operand (ctx, 0);
-    _cairo_gl_context_destroy_operand (ctx, 1);
+    _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
+    _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
 
     ctx->pre_shader = NULL;
 
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 070f79c..9e653f4 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -88,6 +88,11 @@ typedef struct cairo_gl_glyph_cache {
     cairo_surface_pattern_t pattern;
 } cairo_gl_glyph_cache_t;
 
+typedef enum cairo_gl_tex {
+    CAIRO_GL_TEX_SOURCE = 0,
+    CAIRO_GL_TEX_MASK = 1
+} cairo_gl_tex_t;
+
 typedef enum cairo_gl_operand_type {
     CAIRO_GL_OPERAND_NONE,
     CAIRO_GL_OPERAND_CONSTANT,
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index fdd4b67..2b55119 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -87,7 +87,7 @@ typedef struct cairo_gl_shader_impl {
     void
     (*bind_texture) (cairo_gl_shader_t *shader,
 		     const char *name,
-		     GLuint tex_unit);
+		     cairo_gl_tex_t tex_unit);
 
     void
     (*use) (cairo_gl_shader_t *shader);
@@ -243,7 +243,7 @@ bind_matrix_arb (cairo_gl_shader_t *shader,
 static void
 bind_texture_arb (cairo_gl_shader_t *shader,
 		  const char *name,
-		  GLuint tex_unit)
+		  cairo_gl_tex_t tex_unit)
 {
     GLint location = glGetUniformLocationARB (shader->program, name);
     assert (location != -1);
@@ -397,7 +397,7 @@ bind_matrix_core_2_0 (cairo_gl_shader_t *shader, const char *name, cairo_matrix_
 }
 
 static void
-bind_texture_core_2_0 (cairo_gl_shader_t *shader, const char *name, GLuint tex_unit)
+bind_texture_core_2_0 (cairo_gl_shader_t *shader, const char *name, cairo_gl_tex_t tex_unit)
 {
     GLint location = glGetUniformLocation (shader->program, name);
     assert (location != -1);
@@ -559,12 +559,6 @@ _cairo_gl_shader_fini (cairo_gl_context_t *ctx,
         ctx->shader_impl->destroy_program (shader->program);
 }
 
-typedef enum cairo_gl_operand_name {
-  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
@@ -589,7 +583,7 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
 static void
 cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
                                cairo_gl_var_type_t type,
-                               cairo_gl_operand_name_t name)
+                               cairo_gl_tex_t name)
 {
     switch (type) {
     default:
@@ -612,7 +606,7 @@ cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
 static void
 cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
                              cairo_gl_var_type_t type,
-                             cairo_gl_operand_name_t name)
+                             cairo_gl_tex_t name)
 {
     switch (type) {
     default:
@@ -643,18 +637,16 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
     unsigned int length;
     cairo_status_t status;
 
-    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_gl_shader_emit_variable (stream, src, CAIRO_GL_TEX_SOURCE);
+    cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_TEX_MASK);
 
     _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_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE);
+    cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK);
 
     _cairo_output_stream_write (stream,
 				"}\n\0", 3);
@@ -671,7 +663,7 @@ 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)
+                            cairo_gl_tex_t name)
 {
     const char *namestr = operand_names[name];
     const char *rectstr = (tex_target == GL_TEXTURE_RECTANGLE_EXT ? "Rect" : "");
@@ -781,10 +773,8 @@ cairo_gl_shader_get_fragment_source (GLuint tex_target,
     unsigned int length;
     cairo_status_t status;
 
-    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_gl_shader_emit_color (stream, tex_target, src, CAIRO_GL_TEX_SOURCE);
+    cairo_gl_shader_emit_color (stream, tex_target, mask, CAIRO_GL_TEX_MASK);
 
     _cairo_output_stream_printf (stream,
         "void main()\n"
commit 5db362dd6792af20282e0e9a2805ee6f1b921e44
Author: Benjamin Otte <otte at redhat.com>
Date:   Fri May 28 10:24:33 2010 +0200

    gl: Keep a copy of the current operand in the context
    
    Note that they are currently only valid as long as the
    cairo_gl_composite_t exists, but that will be changed soon.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 760aabb..55154c3 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -606,11 +606,13 @@ _cairo_gl_texture_set_attributes (cairo_gl_context_t         *ctx,
 }
 
 static void
-_cairo_gl_operand_setup_texture (cairo_gl_context_t *ctx,
-                                 cairo_gl_operand_t *operand,
+_cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
                                  GLuint              tex_unit,
+                                 cairo_gl_operand_t *operand,
                                  unsigned int        vertex_offset)
 {
+    memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
+
     switch (operand->type) {
     default:
     case CAIRO_GL_OPERAND_COUNT:
@@ -657,6 +659,13 @@ _cairo_gl_operand_setup_texture (cairo_gl_context_t *ctx,
 }
 
 static void
+_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
+                                   GLuint              tex_unit)
+{
+  memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
+}
+
+static void
 _cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
                                GLuint tex_unit)
 {
@@ -995,8 +1004,8 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     glVertexPointer (2, GL_FLOAT, ctx->vertex_size, NULL);
     glEnableClientState (GL_VERTEX_ARRAY);
 
-    _cairo_gl_operand_setup_texture (ctx, &setup->src, 0, dst_size);
-    _cairo_gl_operand_setup_texture (ctx, &setup->mask, 1, dst_size + src_size);
+    _cairo_gl_context_setup_operand (ctx, 0, &setup->src, dst_size);
+    _cairo_gl_context_setup_operand (ctx, 1, &setup->mask, dst_size + src_size);
 
     _cairo_gl_set_src_operand (ctx, setup);
     if (setup->has_component_alpha)
@@ -1241,6 +1250,9 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
     glDisable (GL_TEXTURE_1D);
     glDisable (ctx->tex_target);
 
+    _cairo_gl_context_destroy_operand (ctx, 0);
+    _cairo_gl_context_destroy_operand (ctx, 1);
+
     ctx->pre_shader = NULL;
 
     ctx->vertex_size = 0;
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 434b1b1..070f79c 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -179,6 +179,8 @@ typedef struct _cairo_gl_context {
     cairo_gl_shader_t *pre_shader; /* for component alpha */
     cairo_gl_shader_t *current_shader;
 
+    cairo_gl_operand_t operands[2];
+
     char *vb;
     unsigned int vb_offset;
     unsigned int vertex_size;
commit a05f062c806ac014d0daffa1d74bdb0dd90a8a26
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 19:23:18 2010 +0200

    gl: Move struct definitions in header

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index bc916d3..434b1b1 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -123,6 +123,39 @@ typedef enum cairo_gl_var_type {
 #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)
 
+/* This union structure describes a potential source or mask operand to the
+ * compositing equation.
+ */
+typedef struct cairo_gl_operand {
+    cairo_gl_operand_type_t type;
+    union {
+	struct {
+	    GLuint tex;
+	    cairo_gl_surface_t *surface;
+	    cairo_surface_attributes_t attributes;
+	} texture;
+	struct {
+	    GLfloat color[4];
+	} constant;
+	struct {
+	    GLuint tex;
+	    cairo_matrix_t m;
+	    float segment_x;
+	    float segment_y;
+	} linear;
+	struct {
+	    GLuint tex;
+	    cairo_matrix_t m;
+	    float circle_1_x;
+	    float circle_1_y;
+	    float radius_0;
+	    float radius_1;
+	} radial;
+    };
+
+    const cairo_pattern_t *pattern;
+} cairo_gl_operand_t;
+
 typedef struct _cairo_gl_context {
     cairo_device_t base;
 
@@ -159,39 +192,6 @@ typedef struct _cairo_gl_context {
     void (*destroy) (void *ctx);
 } cairo_gl_context_t;
 
-/* This union structure describes a potential source or mask operand to the
- * compositing equation.
- */
-typedef struct cairo_gl_operand {
-    cairo_gl_operand_type_t type;
-    union {
-	struct {
-	    GLuint tex;
-	    cairo_gl_surface_t *surface;
-	    cairo_surface_attributes_t attributes;
-	} texture;
-	struct {
-	    GLfloat color[4];
-	} constant;
-	struct {
-	    GLuint tex;
-	    cairo_matrix_t m;
-	    float segment_x;
-	    float segment_y;
-	} linear;
-	struct {
-	    GLuint tex;
-	    cairo_matrix_t m;
-	    float circle_1_x;
-	    float circle_1_y;
-	    float radius_0;
-	    float radius_1;
-	} radial;
-    };
-
-    const cairo_pattern_t *pattern;
-} cairo_gl_operand_t;
-
 typedef struct _cairo_gl_composite {
     cairo_gl_surface_t *dst;
     cairo_operator_t op;
commit 85d4c6c55b85c52d8f86247f00659e37354abd49
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 21:23:40 2010 +0200

    gl: operand->texture.surface cannot be NULL

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 6cd2eb7..760aabb 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -390,13 +390,9 @@ _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
 	glDeleteTextures (1, &operand->radial.tex);
 	break;
     case CAIRO_GL_OPERAND_TEXTURE:
-	if (operand->texture.surface != NULL) {
-	    cairo_gl_surface_t *surface = operand->texture.surface;
-
-	    _cairo_pattern_release_surface (operand->pattern,
-					    &surface->base,
-					    &operand->texture.attributes);
-	}
+        _cairo_pattern_release_surface (operand->pattern,
+                                        &operand->texture.surface->base,
+                                        &operand->texture.attributes);
 	break;
     default:
     case CAIRO_GL_OPERAND_COUNT:
commit 9486ad5fbdad047b5194f6bed68a08bb4c594610
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 19:16:41 2010 +0200

    gl: Remove composite_t argument from _flush() function

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 38b46cc..6cd2eb7 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1024,7 +1024,6 @@ FAIL:
 
 static inline void
 _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
-                          cairo_gl_composite_t *setup,
 			  unsigned int count)
 {
     if (! ctx->pre_shader) {
@@ -1045,8 +1044,7 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
 }
 
 void
-_cairo_gl_composite_flush (cairo_gl_context_t *ctx,
-                           cairo_gl_composite_t *setup)
+_cairo_gl_composite_flush (cairo_gl_context_t *ctx)
 {
     unsigned int count;
 
@@ -1068,20 +1066,19 @@ _cairo_gl_composite_flush (cairo_gl_context_t *ctx,
 	    cairo_region_get_rectangle (ctx->clip_region, i, &rect);
 
 	    glScissor (rect.x, rect.y, rect.width, rect.height);
-            _cairo_gl_composite_draw (ctx, setup, count);
+            _cairo_gl_composite_draw (ctx, count);
 	}
     } else {
-        _cairo_gl_composite_draw (ctx, setup, count);
+        _cairo_gl_composite_draw (ctx, count);
     }
 }
 
 static void
 _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
-                                    cairo_gl_composite_t *setup,
                                     unsigned int n_vertices)
 {
     if (ctx->vb_offset + n_vertices * ctx->vertex_size > CAIRO_GL_VBO_SIZE)
-	_cairo_gl_composite_flush (ctx, setup);
+	_cairo_gl_composite_flush (ctx);
 
     if (ctx->vb == NULL) {
 	glBufferDataARB (GL_ARRAY_BUFFER_ARB, CAIRO_GL_VBO_SIZE,
@@ -1161,7 +1158,7 @@ _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
                                GLfloat y2,
                                uint8_t alpha)
 {
-    _cairo_gl_composite_prepare_buffer (ctx, setup, 6);
+    _cairo_gl_composite_prepare_buffer (ctx, 6);
 
     _cairo_gl_composite_emit_vertex (ctx, setup, x1, y1, alpha);
     _cairo_gl_composite_emit_vertex (ctx, setup, x2, y1, alpha);
@@ -1205,7 +1202,7 @@ _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
                                 GLfloat glyph_x2,
                                 GLfloat glyph_y2)
 {
-    _cairo_gl_composite_prepare_buffer (ctx, setup, 6);
+    _cairo_gl_composite_prepare_buffer (ctx, 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);
@@ -1220,7 +1217,7 @@ void
 _cairo_gl_composite_end (cairo_gl_context_t *ctx,
                          cairo_gl_composite_t *setup)
 {
-    _cairo_gl_composite_flush (ctx, setup);
+    _cairo_gl_composite_flush (ctx);
 
     if (ctx->clip_region) {
 	glDisable (GL_SCISSOR_TEST);
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index ca0b596..d500785 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -324,7 +324,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_composite_flush (ctx, &setup);
+                _cairo_gl_composite_flush (ctx);
 		_cairo_gl_glyph_cache_unlock (cache);
 		status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
 	    }
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index e8c8c68..bc916d3 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -342,8 +342,7 @@ _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
                                 GLfloat glyph_y2);
 
 cairo_private void
-_cairo_gl_composite_flush (cairo_gl_context_t *ctx,
-                           cairo_gl_composite_t *setup);
+_cairo_gl_composite_flush (cairo_gl_context_t *ctx);
 
 cairo_private void
 _cairo_gl_composite_end (cairo_gl_context_t *ctx,
commit 16e420b4dca5325ab295a27103299a916f334b05
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 19:13:53 2010 +0200

    gl: Remove dependency on composite_t in draw function

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 809e51d..38b46cc 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1033,13 +1033,13 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
         cairo_gl_shader_t *prev_shader = ctx->current_shader;
 
         _cairo_gl_set_shader (ctx, ctx->pre_shader);
-        _cairo_gl_set_operator (setup->dst, CAIRO_OPERATOR_DEST_OUT, TRUE);
+        _cairo_gl_set_operator (ctx->current_target, CAIRO_OPERATOR_DEST_OUT, TRUE);
         _cairo_gl_set_src_alpha (ctx, TRUE);
         glDrawArrays (GL_TRIANGLES, 0, count);
         _cairo_gl_set_src_alpha (ctx, FALSE);
 
         _cairo_gl_set_shader (ctx, prev_shader);
-        _cairo_gl_set_operator (setup->dst, setup->op, TRUE);
+        _cairo_gl_set_operator (ctx->current_target, CAIRO_OPERATOR_ADD, TRUE);
         glDrawArrays (GL_TRIANGLES, 0, count);
     }
 }
commit e46215ec6b94355b741acf5dfdd264d6396b4bc8
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 18:44:20 2010 +0200

    gl: Remove unneeded and broken workaround
    
    We now ensure the values are properly zeroed when setting the operator.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index e74d555..809e51d 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -671,19 +671,7 @@ _cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
         glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
         break;
     case CAIRO_GL_OPERAND_TEXTURE:
-        /* Set up the constant color we use to set color to 0 if needed. */
-        /* 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 (operand->texture.surface->base.content != CAIRO_CONTENT_ALPHA) {
-            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0 + tex_unit);
-        } else {
-            GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
-
-            glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
-            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-        }
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0 + tex_unit);
         glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0 + tex_unit);
 	break;
         break;
commit b2d709b5c7e463437189b8e4a2c53a3317437825
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 17:41:01 2010 +0200

    gl: Switch src alpha handling to a tiny on/off function
    
    Instead of doing setup every time, we just set this one flag. Much
    nicer.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index d21a4cb..e74d555 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -719,27 +719,19 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
     _cairo_gl_operand_setup_fixed (&setup->src, 0);
 }
 
-/* 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.
+/* Swizzles the source for creating the "source alpha" value
+ * (src.aaaa * mask.argb) required by component alpha rendering.
  */
 static void
-_cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
-				 cairo_gl_composite_t *setup)
+_cairo_gl_set_src_alpha (cairo_gl_context_t *ctx,
+                         cairo_bool_t activate)
 {
     if (ctx->current_shader)
         return;
 
     glActiveTexture (GL_TEXTURE0);
 
-    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_OPERAND0_RGB, GL_SRC_ALPHA);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-    _cairo_gl_operand_setup_fixed (&setup->src, 0);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, activate ? GL_SRC_ALPHA : GL_SRC_COLOR);
 }
 
 /* This is like _cairo_gl_set_src_alpha_operand, for component alpha setup
@@ -1054,12 +1046,12 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
 
         _cairo_gl_set_shader (ctx, ctx->pre_shader);
         _cairo_gl_set_operator (setup->dst, CAIRO_OPERATOR_DEST_OUT, TRUE);
-        _cairo_gl_set_src_alpha_operand (ctx, setup);
+        _cairo_gl_set_src_alpha (ctx, TRUE);
         glDrawArrays (GL_TRIANGLES, 0, count);
+        _cairo_gl_set_src_alpha (ctx, FALSE);
 
         _cairo_gl_set_shader (ctx, prev_shader);
         _cairo_gl_set_operator (setup->dst, setup->op, TRUE);
-        _cairo_gl_set_src_operand (ctx, setup);
         glDrawArrays (GL_TRIANGLES, 0, count);
     }
 }
commit 53fd451f85974d2ed0d6f29a0a0549fd4c7035fe
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 17:32:14 2010 +0200

    gl: Avoid redundant mask setup
    
    The mask doesn't change, so no need to set it up twice

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 5704bbd..d21a4cb 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1055,13 +1055,11 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
         _cairo_gl_set_shader (ctx, ctx->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_TRIANGLES, 0, count);
 
         _cairo_gl_set_shader (ctx, prev_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_TRIANGLES, 0, count);
     }
 }
commit 1b3675fc4b9c7f6ad4d9edd9b27bee10c2502b81
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 17:28:05 2010 +0200

    gl: Split fixed-function operand setup into own function

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 0e90a76..5704bbd 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -661,56 +661,64 @@ _cairo_gl_operand_setup_texture (cairo_gl_context_t *ctx,
 }
 
 static void
-_cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
-			   cairo_gl_composite_t *setup)
+_cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand,
+                               GLuint tex_unit)
 {
-    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
-
-    if (ctx->current_shader)
-        return;
-
-    glActiveTexture (GL_TEXTURE0);
-
-    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_OPERAND0_RGB, GL_SRC_COLOR);
-    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
-    switch (setup->src.type) {
+    switch (operand->type) {
     case CAIRO_GL_OPERAND_CONSTANT:
-        glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, setup->src.constant.color);
+        glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, operand->constant.color);
         glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
         glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
-	break;
+        break;
     case CAIRO_GL_OPERAND_TEXTURE:
         /* 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. */
-
-        /* Force the src color to 0 if the surface should be
+        /* 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->src.texture.surface->base.content !=
-            CAIRO_CONTENT_ALPHA)
-            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
-        else
+        if (operand->texture.surface->base.content != CAIRO_CONTENT_ALPHA) {
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0 + tex_unit);
+        } else {
+            GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
+
+            glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
             glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
+        }
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0 + tex_unit);
 	break;
-
-    default:
+        break;
+    case CAIRO_GL_OPERAND_SPANS:
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR);
+        break;
     case CAIRO_GL_OPERAND_COUNT:
+    default:
         ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_NONE:
-    case CAIRO_GL_OPERAND_SPANS:
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
+    case CAIRO_GL_OPERAND_NONE:
         break;
     }
 }
 
+static void
+_cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
+			   cairo_gl_composite_t *setup)
+{
+    if (ctx->current_shader)
+        return;
+
+    glActiveTexture (GL_TEXTURE0);
+
+    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_OPERAND0_RGB, GL_SRC_COLOR);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+    _cairo_gl_operand_setup_fixed (&setup->src, 0);
+}
+
 /* 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.
@@ -731,26 +739,7 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
-    switch (setup->src.type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-        glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, setup->src.constant.color);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
-	break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-        /* Set up the combiner to just set color to the sampled texture. */
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
-	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;
-    }
+    _cairo_gl_operand_setup_fixed (&setup->src, 0);
 }
 
 /* This is like _cairo_gl_set_src_alpha_operand, for component alpha setup
@@ -760,8 +749,6 @@ static void
 _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
 					    cairo_gl_composite_t *setup)
 {
-    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
-
     if (ctx->current_shader)
         return;
 
@@ -779,39 +766,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
-    switch (setup->mask.type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-        glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
-                    setup->mask.constant.color);
-
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
-	break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-        /* 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.texture.surface == NULL ||
-            setup->mask.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_SRC1_ALPHA, GL_TEXTURE1);
-	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;
-    }
+    _cairo_gl_operand_setup_fixed (&setup->mask, 1);
 }
 
 static void
@@ -835,29 +790,7 @@ _cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
-    switch (setup->mask.type) {
-    case CAIRO_GL_OPERAND_CONSTANT:
-        glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, setup->mask.constant.color);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
-        break;
-    case CAIRO_GL_OPERAND_TEXTURE:
-        /* IN: dst.argb = src.argb * mask.aaaa */
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
-        break;
-    case CAIRO_GL_OPERAND_SPANS:
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR);
-        break;
-    case CAIRO_GL_OPERAND_COUNT:
-    default:
-        ASSERT_NOT_REACHED;
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
-    case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
-    case CAIRO_GL_OPERAND_NONE:
-        break;
-    }
+    _cairo_gl_operand_setup_fixed (&setup->mask, 1);
 }
 
 static void
commit 02da871050f6be02ba0231e545d6613a42c3a7e6
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 17:02:29 2010 +0200

    gl: Unify fixed function setup code

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 9e187a3..0e90a76 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -719,8 +719,6 @@ static 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};
-
     if (ctx->current_shader)
         return;
 
@@ -730,24 +728,19 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
 
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
     switch (setup->src.type) {
     case CAIRO_GL_OPERAND_CONSTANT:
-	constant_color[0] = setup->src.constant.color[3];
-	constant_color[1] = setup->src.constant.color[3];
-	constant_color[2] = setup->src.constant.color[3];
-	constant_color[3] = setup->src.constant.color[3];
-        glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
+        glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, setup->src.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:
         /* Set up the combiner to just set color to the sampled texture. */
         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:
commit 74f9094162fba54c29859e25ad5be085604aa0b6
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 15:46:39 2010 +0200

    gl: switch OPERAND0 and OPERAND1 in the fixed function path
    
    This should not change anything as we multiply the values.
    But it allows unifying parts of the code, which will happen in another
    patch.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index ac6691f..9e187a3 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -778,21 +778,21 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
     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_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);
 
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
     switch (setup->mask.type) {
     case CAIRO_GL_OPERAND_CONSTANT:
         glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
                     setup->mask.constant.color);
 
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
 	break;
     case CAIRO_GL_OPERAND_TEXTURE:
         /* Set up the constant color we use to set color to 0 if needed. */
@@ -804,9 +804,9 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
          */
         if (setup->mask.texture.surface == NULL ||
             setup->mask.texture.surface->base.content != CAIRO_CONTENT_ALPHA)
-            glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
         else
-            glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
+            glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
         glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
 	break;
 
@@ -834,28 +834,28 @@ _cairo_gl_set_mask_operand (cairo_gl_context_t *ctx,
     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_OPERAND1_RGB, 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);
 
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
     switch (setup->mask.type) {
     case CAIRO_GL_OPERAND_CONSTANT:
         glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, setup->mask.constant.color);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
-        glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
         break;
     case CAIRO_GL_OPERAND_TEXTURE:
         /* 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_SRC0_RGB, GL_TEXTURE1);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
         break;
     case CAIRO_GL_OPERAND_SPANS:
-        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_SRC0_RGB, GL_PRIMARY_COLOR);
+        glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR);
         break;
     case CAIRO_GL_OPERAND_COUNT:
     default:
commit c6aac5d0134f1473d3867c1b6a4b40753700ffcb
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 15:42:56 2010 +0200

    gl: Move the pre shader to the context, too
    
    It's required when flushing, too.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 3ee0f47..ac6691f 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1034,7 +1034,7 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
             return status;
 
         _cairo_gl_composite_bind_to_shader (ctx, setup);
-        setup->pre_shader = ctx->current_shader;
+        ctx->pre_shader = ctx->current_shader;
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -1069,7 +1069,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
                                            setup->has_component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
                                                                       : CAIRO_GL_SHADER_IN_NORMAL);
     if (unlikely (status)) {
-        setup->pre_shader = NULL;
+        ctx->pre_shader = NULL;
         goto FAIL;
     }
 
@@ -1121,12 +1121,12 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
                           cairo_gl_composite_t *setup,
 			  unsigned int count)
 {
-    if (! setup->pre_shader) {
+    if (! ctx->pre_shader) {
         glDrawArrays (GL_TRIANGLES, 0, count);
     } else {
         cairo_gl_shader_t *prev_shader = ctx->current_shader;
 
-        _cairo_gl_set_shader (ctx, setup->pre_shader);
+        _cairo_gl_set_shader (ctx, ctx->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);
@@ -1344,7 +1344,7 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
     glDisable (GL_TEXTURE_1D);
     glDisable (ctx->tex_target);
 
-    setup->pre_shader = NULL;
+    ctx->pre_shader = NULL;
 
     ctx->vertex_size = 0;
 }
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index a66d8f0..e8c8c68 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -143,6 +143,7 @@ typedef struct _cairo_gl_context {
     cairo_list_t fonts;
 
     cairo_gl_surface_t *current_target;
+    cairo_gl_shader_t *pre_shader; /* for component alpha */
     cairo_gl_shader_t *current_shader;
 
     char *vb;
@@ -199,7 +200,6 @@ typedef struct _cairo_gl_composite {
 
     cairo_gl_operand_t src;
     cairo_gl_operand_t mask;
-    cairo_gl_shader_t *pre_shader; /* for component alpha */
 } cairo_gl_composite_t;
 
 cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
commit 61bc3067ca5fa4aeaef537c397c37826facc7621
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 15:28:32 2010 +0200

    gl: Store the clip region in the context
    
    This is necessary because we want to get rid of keeping the composite
    stuff around.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index be9f830..3ee0f47 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1102,7 +1102,9 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     else
         _cairo_gl_set_mask_operand (ctx, setup);
 
-    if (setup->clip_region)
+    cairo_region_destroy (ctx->clip_region);
+    ctx->clip_region = cairo_region_reference (setup->clip_region);
+    if (ctx->clip_region)
 	glEnable (GL_SCISSOR_TEST);
 
     *ctx_out = ctx;
@@ -1153,13 +1155,13 @@ _cairo_gl_composite_flush (cairo_gl_context_t *ctx,
     ctx->vb = NULL;
     ctx->vb_offset = 0;
 
-    if (setup->clip_region) {
-	int i, num_rectangles = cairo_region_num_rectangles (setup->clip_region);
+    if (ctx->clip_region) {
+	int i, num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
 
 	for (i = 0; i < num_rectangles; i++) {
 	    cairo_rectangle_int_t rect;
 
-	    cairo_region_get_rectangle (setup->clip_region, i, &rect);
+	    cairo_region_get_rectangle (ctx->clip_region, i, &rect);
 
 	    glScissor (rect.x, rect.y, rect.width, rect.height);
             _cairo_gl_composite_draw (ctx, setup, count);
@@ -1316,8 +1318,11 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
 {
     _cairo_gl_composite_flush (ctx, setup);
 
-    if (setup->clip_region)
+    if (ctx->clip_region) {
 	glDisable (GL_SCISSOR_TEST);
+        cairo_region_destroy (ctx->clip_region);
+        ctx->clip_region = NULL;
+    }
 
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
 
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index e71dc13..0d52058 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -93,6 +93,8 @@ _gl_destroy (void *device)
     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
 	_cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
 
+    cairo_region_destroy (ctx->clip_region);
+
     ctx->destroy (ctx);
 
     free (ctx);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index d15e575..a66d8f0 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -148,6 +148,7 @@ typedef struct _cairo_gl_context {
     char *vb;
     unsigned int vb_offset;
     unsigned int vertex_size;
+    cairo_region_t *clip_region;
 
     void (*acquire) (void *ctx);
     void (*release) (void *ctx);
commit db79880d9a836d50e9202caa5c73e22a2b6b97b3
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 13:03:12 2010 +0200

    gl: Make gl_composite_begin() acquire the context
    
    Also remove the previous places for context acquisition. This completes
    fixing the potential ABBA deadlock I talked about a few commits ago.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 80a7e4f..be9f830 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1041,19 +1041,26 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
 }
 
 cairo_status_t
-_cairo_gl_composite_begin (cairo_gl_context_t *ctx,
-                           cairo_gl_composite_t *setup)
+_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
+                           cairo_gl_context_t **ctx_out)
 {
     unsigned int dst_size, src_size, mask_size;
+    cairo_gl_context_t *ctx;
     cairo_status_t status;
 
+    assert (setup->dst);
+
+    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
+    if (unlikely (status))
+	return status;
+
     assert (! _cairo_gl_context_is_in_progress (ctx));
 
     /* 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;
+            goto FAIL;
     }
 
     status = _cairo_gl_set_shader_by_type (ctx,
@@ -1063,7 +1070,7 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
                                                                       : CAIRO_GL_SHADER_IN_NORMAL);
     if (unlikely (status)) {
         setup->pre_shader = NULL;
-	return status;
+        goto FAIL;
     }
 
     status = CAIRO_STATUS_SUCCESS;
@@ -1098,6 +1105,12 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
     if (setup->clip_region)
 	glEnable (GL_SCISSOR_TEST);
 
+    *ctx_out = ctx;
+
+FAIL:
+    if (unlikely (status))
+        _cairo_gl_context_release (ctx);
+
     return status;
 }
 
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 1890ee2..ca0b596 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -309,9 +309,14 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
 	    *has_component_alpha |= cache->pattern.base.has_component_alpha;
 
-            status = _cairo_gl_composite_begin (ctx, &setup);
+            status = _cairo_gl_composite_begin (&setup, &ctx);
             if (unlikely (status))
                 goto FINISH;
+
+            /* XXX: _cairo_gl_composite_begin() acquires the context a
+             * second time. Need to refactor this loop so this doesn't happen.
+             */
+            _cairo_gl_context_release (ctx);
 	}
 
 	if (scaled_glyph->surface_private == NULL) {
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 9d36c45..d15e575 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -316,8 +316,8 @@ cairo_private void
 _cairo_gl_composite_set_mask_spans (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_gl_composite_begin (cairo_gl_composite_t *setup,
+                           cairo_gl_context_t **ctx);
 
 cairo_private void
 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 54526b3..53cba20 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -913,10 +913,6 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
         }
     }
 
-    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
-    if (unlikely (status))
-	return status;
-
     status = _cairo_gl_composite_init (&setup, op, dst,
                                        mask && mask->has_component_alpha,
                                        &rect);
@@ -937,7 +933,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     if (unlikely (status))
         goto CLEANUP;
 
-    status = _cairo_gl_composite_begin (ctx, &setup);
+    status = _cairo_gl_composite_begin (&setup, &ctx);
     if (unlikely (status))
 	goto CLEANUP;
 
@@ -963,9 +959,9 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     }
 
     _cairo_gl_composite_end (ctx, &setup);
+    _cairo_gl_context_release (ctx);
 
   CLEANUP:
-    _cairo_gl_context_release (ctx);
     _cairo_gl_composite_fini (&setup);
 
     return status;
@@ -1040,10 +1036,6 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
     cairo_gl_composite_t setup;
     int i;
 
-    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
-    if (unlikely (status))
-	return status;
-
     status = _cairo_gl_composite_init (&setup, op, dst,
                                        FALSE,
                                        /* XXX */ NULL);
@@ -1065,7 +1057,7 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
     if (unlikely (status))
         goto CLEANUP;
 
-    status = _cairo_gl_composite_begin (ctx, &setup);
+    status = _cairo_gl_composite_begin (&setup, &ctx);
     if (unlikely (status))
         goto CLEANUP;
 
@@ -1079,9 +1071,9 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
     }
 
     _cairo_gl_composite_end (ctx, &setup);
+    _cairo_gl_context_release (ctx);
 
   CLEANUP:
-    _cairo_gl_context_release (ctx);
     _cairo_gl_composite_fini (&setup);
 
     return status;
@@ -1238,12 +1230,6 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     renderer->xmin = extents->x;
     renderer->xmax = extents->x + extents->width;
 
-    status = _cairo_gl_context_acquire (dst->base.device, &renderer->ctx);
-    if (unlikely (status)) {
-	free (renderer);
-	return _cairo_span_renderer_create_in_error (status);
-    }
-
     status = _cairo_gl_composite_init (&renderer->setup,
                                        op, dst,
                                        FALSE, extents);
@@ -1260,15 +1246,13 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     _cairo_gl_composite_set_mask_spans (&renderer->setup);
     _cairo_gl_composite_set_clip_region (&renderer->setup, clip_region);
 
-    status = _cairo_gl_composite_begin (renderer->ctx, &renderer->setup);
+    status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx);
     if (unlikely (status))
         goto FAIL;
 
     return &renderer->base;
 
-
 FAIL:
-    _cairo_gl_context_release (renderer->ctx);
     _cairo_gl_composite_fini (&renderer->setup);
     free (renderer);
     return _cairo_span_renderer_create_in_error (status);
commit 1320a168fa5b73fd42438040a4bf8ee9ad222a0e
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 12:26:49 2010 +0200

    gl: Remove unused code
    
    We don't need to acquire/release the context, we're not using it.

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index b9929e1..1890ee2 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -367,25 +367,18 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
 					cairo_clip_t		*clip,
 					int			*remaining_glyphs)
 {
-    cairo_gl_context_t *ctx;
     cairo_surface_t *mask;
     cairo_status_t status;
     cairo_bool_t has_component_alpha;
     int i;
 
-    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
-    if (unlikely (status))
-	return status;
-
     /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
     mask = cairo_gl_surface_create (dst->base.device,
                                     CAIRO_CONTENT_COLOR_ALPHA,
                                     glyph_extents->width,
                                     glyph_extents->height);
-    if (unlikely (mask->status)) {
-        _cairo_gl_context_release (ctx);
+    if (unlikely (mask->status))
         return mask->status;
-    }
 
     for (i = 0; i < num_glyphs; i++) {
 	glyphs[i].x -= glyph_extents->x;
@@ -419,8 +412,6 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
 
     cairo_surface_destroy (mask);
 
-    _cairo_gl_context_release (ctx);
-
     return status;
 }
 
commit 8f5c3b706b5bad6b0851a3e27752f7d1a3ca8a72
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 12:16:01 2010 +0200

    gl: Make composite_set_clip_region not require the context

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 85000a0..80a7e4f 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -486,8 +486,7 @@ _cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup)
 }
 
 void
-_cairo_gl_composite_set_clip_region (cairo_gl_context_t *ctx,
-                                     cairo_gl_composite_t *setup,
+_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
                                      cairo_region_t *clip_region)
 {
     setup->clip_region = clip_region;
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 8750789..b9929e1 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -265,7 +265,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	cairo_list_add (&scaled_font->link, &ctx->fonts);
     }
 
-    _cairo_gl_composite_set_clip_region (ctx, &setup, clip_region);
+    _cairo_gl_composite_set_clip_region (&setup, clip_region);
 
     for (i = 0; i < num_glyphs; i++) {
 	cairo_scaled_glyph_t *scaled_glyph;
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index a3a1cd4..9d36c45 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -295,8 +295,7 @@ cairo_private void
 _cairo_gl_composite_fini (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_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
                                      cairo_region_t *clip_region);
 
 cairo_private cairo_int_status_t
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index bd864e4..54526b3 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1258,7 +1258,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
         goto FAIL;
 
     _cairo_gl_composite_set_mask_spans (&renderer->setup);
-    _cairo_gl_composite_set_clip_region (renderer->ctx, &renderer->setup, clip_region);
+    _cairo_gl_composite_set_clip_region (&renderer->setup, clip_region);
 
     status = _cairo_gl_composite_begin (renderer->ctx, &renderer->setup);
     if (unlikely (status))
commit ac6abcbac7f79e5717c44e251135dcba8ab00b27
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 12:14:24 2010 +0200

    gl: Make composite_set_source/mask/mask_spans not require a context

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 37a1685..85000a0 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -149,17 +149,27 @@ _render_gradient (const cairo_gl_context_t *ctx,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static void
-_cairo_gl_create_gradient_texture (const cairo_gl_context_t *ctx,
-				   cairo_gl_surface_t *surface,
+static cairo_int_status_t
+_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
 				   cairo_gradient_pattern_t *pattern,
 				   GLuint *tex)
 {
+    cairo_gl_context_t *ctx;
+    cairo_status_t status;
     int tex_width;
     GLubyte *data;
 
     assert (pattern->n_stops != 0);
 
+    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
+    if (unlikely (status))
+	return status;
+
+    if ((unsigned int) ctx->max_texture_size / 2 <= pattern->n_stops) {
+        _cairo_gl_context_release (ctx);
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
     tex_width = _cairo_gl_gradient_sample_width (pattern);
 
     glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, ctx->texture_load_pbo);
@@ -194,6 +204,9 @@ _cairo_gl_create_gradient_texture (const cairo_gl_context_t *ctx,
 	glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
 	break;
     }
+    
+    _cairo_gl_context_release (ctx);
+    return CAIRO_STATUS_SUCCESS;
 }
 
 /**
@@ -201,8 +214,7 @@ _cairo_gl_create_gradient_texture (const cairo_gl_context_t *ctx,
  * from dest to src coords.
  */
 static cairo_status_t
-_cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
-                                 cairo_gl_operand_t *operand,
+_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
 				 const cairo_pattern_t *src,
 				 cairo_gl_surface_t *dst,
 				 int src_x, int src_y,
@@ -225,7 +237,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
     if (unlikely (status))
 	return status;
 
-    if (_cairo_gl_device_requires_power_of_two_textures (&ctx->base) &&
+    if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device) &&
 	(attributes->extend == CAIRO_EXTEND_REPEAT ||
 	 attributes->extend == CAIRO_EXTEND_REFLECT))
     {
@@ -258,7 +270,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
      * (unnormalized dst -> unnormalized src) to
      * (unnormalized dst -> normalized src)
      */
-    if (_cairo_gl_device_requires_power_of_two_textures (&ctx->base)) {
+    if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
 	cairo_matrix_init_scale (&m,
 				 1.0,
 				 1.0);
@@ -287,13 +299,13 @@ _cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
 }
 
 static cairo_status_t
-_cairo_gl_gradient_operand_init (cairo_gl_context_t *ctx,
-                                 cairo_gl_operand_t *operand,
+_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 				 cairo_gl_surface_t *dst)
 {
     cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *)operand->pattern;
+    cairo_status_t status;
 
-    if (! _cairo_gl_device_has_glsl (&ctx->base))
+    if (! _cairo_gl_device_has_glsl (dst->base.device))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
@@ -305,14 +317,11 @@ _cairo_gl_gradient_operand_init (cairo_gl_context_t *ctx,
 	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->linear.tex);
+        status = _cairo_gl_create_gradient_texture (dst,
+                                                    gradient,
+                                                    &operand->linear.tex);
+        if (unlikely (status))
+            return status;
 
 	/* Translation matrix from the destination fragment coordinates
 	 * (pixels from lower left = 0,0) to the coordinates in the
@@ -340,13 +349,11 @@ _cairo_gl_gradient_operand_init (cairo_gl_context_t *ctx,
 	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->radial.tex);
+        status = _cairo_gl_create_gradient_texture (dst,
+                                                    gradient,
+                                                    &operand->radial.tex);
+        if (unlikely (status))
+            return status;
 
 	/* Translation matrix from the destination fragment coordinates
 	 * (pixels from lower left = 0,0) to the coordinates in the
@@ -403,8 +410,7 @@ _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
 }
 
 static cairo_int_status_t
-_cairo_gl_operand_init (cairo_gl_context_t *ctx,
-                        cairo_gl_operand_t *operand,
+_cairo_gl_operand_init (cairo_gl_operand_t *operand,
 		        const cairo_pattern_t *pattern,
 		        cairo_gl_surface_t *dst,
 		        int src_x, int src_y,
@@ -421,7 +427,7 @@ _cairo_gl_operand_init (cairo_gl_context_t *ctx,
 		                             &((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);
+	status = _cairo_gl_gradient_operand_init (operand, dst);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
@@ -429,7 +435,7 @@ _cairo_gl_operand_init (cairo_gl_context_t *ctx,
 
     default:
     case CAIRO_PATTERN_TYPE_SURFACE:
-	return _cairo_gl_pattern_texture_setup (ctx, operand,
+	return _cairo_gl_pattern_texture_setup (operand,
 						pattern, dst,
 						src_x, src_y,
 						dst_x, dst_y,
@@ -438,15 +444,14 @@ _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,
+_cairo_gl_composite_set_source (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,
+    return _cairo_gl_operand_init (&setup->src, pattern,
                                    setup->dst,
                                    src_x, src_y,
                                    dst_x, dst_y,
@@ -454,8 +459,7 @@ _cairo_gl_composite_set_source (cairo_gl_context_t *ctx,
 }
 
 cairo_int_status_t
-_cairo_gl_composite_set_mask (cairo_gl_context_t *ctx,
-                              cairo_gl_composite_t *setup,
+_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
 			      const cairo_pattern_t *pattern,
                               int src_x, int src_y,
                               int dst_x, int dst_y,
@@ -466,7 +470,7 @@ _cairo_gl_composite_set_mask (cairo_gl_context_t *ctx,
     if (pattern == NULL)
         return CAIRO_STATUS_SUCCESS;
 
-    return _cairo_gl_operand_init (ctx, &setup->mask, pattern,
+    return _cairo_gl_operand_init (&setup->mask, pattern,
                                    setup->dst,
                                    src_x, src_y,
                                    dst_x, dst_y,
@@ -474,8 +478,7 @@ _cairo_gl_composite_set_mask (cairo_gl_context_t *ctx,
 }
 
 void
-_cairo_gl_composite_set_mask_spans (cairo_gl_context_t *ctx,
-                                    cairo_gl_composite_t *setup)
+_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup)
 {
     _cairo_gl_operand_destroy (&setup->mask);
     setup->mask.type = CAIRO_GL_OPERAND_SPANS;
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index f4de7b0..8750789 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -251,7 +251,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	goto FINISH;
     }
 
-    status = _cairo_gl_composite_set_source (ctx, &setup, source,
+    status = _cairo_gl_composite_set_source (&setup, source,
                                              glyph_extents->x, glyph_extents->y,
                                              dst_x, dst_y,
                                              glyph_extents->width,
@@ -301,8 +301,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
 	    last_format = scaled_glyph->surface->format;
 
-            status = _cairo_gl_composite_set_mask (ctx,
-                                                   &setup,
+            status = _cairo_gl_composite_set_mask (&setup,
                                                    &cache->pattern.base,
                                                    0, 0, 0, 0, 0, 0);
             if (unlikely (status))
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 445a0f6..a3a1cd4 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -300,24 +300,21 @@ _cairo_gl_composite_set_clip_region (cairo_gl_context_t *ctx,
                                      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,
+_cairo_gl_composite_set_source (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,
+_cairo_gl_composite_set_mask (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);
+_cairo_gl_composite_set_mask_spans (cairo_gl_composite_t *setup);
 
 cairo_private cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index b549ab2..bd864e4 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -923,14 +923,14 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     if (unlikely (status))
         goto CLEANUP;
 
-    status = _cairo_gl_composite_set_source (ctx, &setup, src,
+    status = _cairo_gl_composite_set_source (&setup, src,
                                              src_x, src_y,
                                              dst_x, dst_y,
                                              width, height);
     if (unlikely (status))
         goto CLEANUP;
 
-    status = _cairo_gl_composite_set_mask (ctx, &setup, mask,
+    status = _cairo_gl_composite_set_mask (&setup, mask,
                                            mask_x, mask_y,
                                            dst_x, dst_y,
                                            width, height);
@@ -1051,14 +1051,14 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
         goto CLEANUP;
 
     _cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR_ALPHA);
-    status = _cairo_gl_composite_set_source (ctx, &setup, &solid.base,
+    status = _cairo_gl_composite_set_source (&setup, &solid.base,
                                              0, 0,
                                              0, 0,
                                              0, 0);
     if (unlikely (status))
         goto CLEANUP;
 
-    status = _cairo_gl_composite_set_mask (ctx, &setup, NULL,
+    status = _cairo_gl_composite_set_mask (&setup, NULL,
                                            0, 0,
                                            0, 0,
                                            0, 0);
@@ -1250,15 +1250,14 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     if (unlikely (status))
         goto FAIL;
 
-    status = _cairo_gl_composite_set_source (renderer->ctx,
-                                             &renderer->setup, src,
+    status = _cairo_gl_composite_set_source (&renderer->setup, src,
                                              rects->source.x, rects->source.y,
                                              extents->x, extents->y,
                                              extents->width, extents->height);
     if (unlikely (status))
         goto FAIL;
 
-    _cairo_gl_composite_set_mask_spans (renderer->ctx, &renderer->setup);
+    _cairo_gl_composite_set_mask_spans (&renderer->setup);
     _cairo_gl_composite_set_clip_region (renderer->ctx, &renderer->setup, clip_region);
 
     status = _cairo_gl_composite_begin (renderer->ctx, &renderer->setup);
commit 88a70d66fcdbca7e489baa48cd145bb69c3e28e0
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 11:59:36 2010 +0200

    gl: Add API for querying if we need GL_TEXTURE_RECTANGLE_EXT
    
    We need to do that querying outside of taking the lock, so we want to be
    able to query the device, not the context.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 7dc2a60..37a1685 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -225,7 +225,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
     if (unlikely (status))
 	return status;
 
-    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT &&
+    if (_cairo_gl_device_requires_power_of_two_textures (&ctx->base) &&
 	(attributes->extend == CAIRO_EXTEND_REPEAT ||
 	 attributes->extend == CAIRO_EXTEND_REFLECT))
     {
@@ -258,7 +258,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
      * (unnormalized dst -> unnormalized src) to
      * (unnormalized dst -> normalized src)
      */
-    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT) {
+    if (_cairo_gl_device_requires_power_of_two_textures (&ctx->base)) {
 	cairo_matrix_init_scale (&m,
 				 1.0,
 				 1.0);
@@ -566,10 +566,9 @@ static void
 _cairo_gl_texture_set_attributes (cairo_gl_context_t         *ctx,
                                   cairo_surface_attributes_t *attributes)
 {
-    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT) {
-	assert (attributes->extend != CAIRO_EXTEND_REPEAT &&
-		attributes->extend != CAIRO_EXTEND_REFLECT);
-    }
+    assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
+              (attributes->extend != CAIRO_EXTEND_REPEAT &&
+	       attributes->extend != CAIRO_EXTEND_REFLECT));
 
     switch (attributes->extend) {
     case CAIRO_EXTEND_NONE:
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 28a7264..f4de7b0 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -110,7 +110,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
     glyph_private->p1.y = node->y;
     glyph_private->p2.x = node->x + glyph_surface->width;
     glyph_private->p2.y = node->y + glyph_surface->height;
-    if (ctx->tex_target != GL_TEXTURE_RECTANGLE_EXT) {
+    if (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base)) {
 	glyph_private->p1.x /= cache_surface->width;
 	glyph_private->p1.y /= cache_surface->height;
 	glyph_private->p2.x /= cache_surface->width;
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index ef5ce16..445a0f6 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -253,6 +253,12 @@ _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_requires_power_of_two_textures (cairo_device_t *device)
+{
+    return ((cairo_gl_context_t *) device)->tex_target == GL_TEXTURE_RECTANGLE_EXT;
+}
+
 static cairo_always_inline cairo_status_t cairo_warn
 _cairo_gl_context_acquire (cairo_device_t *device,
 			   cairo_gl_context_t **ctx)
commit 9c6e1338a1c7d61b4cc84bcdc5c38573a34cd561
Author: Benjamin Otte <otte at redhat.com>
Date:   Wed May 26 11:36:22 2010 +0200

    gl: Make cairo_gl_composite_t not require a gl context anymore
    
    First patch in a series.
    
    The idea is to make all gl operations in Cairo work like this:
    1) prepare cairo_gl_composite_t
    2) acquire device
    3) begin composite operation
    4) emit vertexes
    5) end operation
    6) release device
    7) cleanup composite operation
    
    This both reduces the time required with the device locked, cleans the
    API and more importantly avoids ABBA deadlocks, as we currently call
    acquire_pattern() with the device lock held.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 4a1267f..7dc2a60 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -1331,16 +1331,14 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
 }
 
 void
-_cairo_gl_composite_fini (cairo_gl_context_t *ctx,
-                          cairo_gl_composite_t *setup)
+_cairo_gl_composite_fini (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_gl_composite_init (cairo_gl_composite_t *setup,
                           cairo_operator_t op,
                           cairo_gl_surface_t *dst,
                           cairo_bool_t assume_component_alpha,
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 4252710..28a7264 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -240,8 +240,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 
     _cairo_scaled_font_freeze_cache (scaled_font);
 
-    status = _cairo_gl_composite_init (ctx, &setup,
-                                       op, dst,
+    status = _cairo_gl_composite_init (&setup, op, dst,
                                        TRUE, glyph_extents);
 
     if (unlikely (status))
@@ -350,10 +349,10 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     _cairo_gl_composite_end (ctx, &setup);
     _cairo_scaled_font_thaw_cache (scaled_font);
 
-    _cairo_gl_composite_fini (ctx, &setup);
-
     _cairo_gl_context_release (ctx);
 
+    _cairo_gl_composite_fini (&setup);
+
     *remaining_glyphs = num_glyphs - i;
     return status;
 }
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 960865c..ef5ce16 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -279,16 +279,14 @@ cairo_private cairo_bool_t
 _cairo_gl_operator_is_supported (cairo_operator_t op);
 
 cairo_private cairo_status_t
-_cairo_gl_composite_init (cairo_gl_context_t *ctx,
-                          cairo_gl_composite_t *setup,
+_cairo_gl_composite_init (cairo_gl_composite_t *setup,
                           cairo_operator_t op,
                           cairo_gl_surface_t *dst,
                           cairo_bool_t has_component_alpha,
                           const cairo_rectangle_int_t *rect);
 
 cairo_private void
-_cairo_gl_composite_fini (cairo_gl_context_t *ctx,
-                          cairo_gl_composite_t *setup);
+_cairo_gl_composite_fini (cairo_gl_composite_t *setup);
 
 cairo_private void
 _cairo_gl_composite_set_clip_region (cairo_gl_context_t *ctx,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index d1066ef..b549ab2 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -917,8 +917,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_gl_composite_init (ctx, &setup,
-                                       op, dst,
+    status = _cairo_gl_composite_init (&setup, op, dst,
                                        mask && mask->has_component_alpha,
                                        &rect);
     if (unlikely (status))
@@ -966,8 +965,8 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     _cairo_gl_composite_end (ctx, &setup);
 
   CLEANUP:
-    _cairo_gl_composite_fini (ctx, &setup);
     _cairo_gl_context_release (ctx);
+    _cairo_gl_composite_fini (&setup);
 
     return status;
 }
@@ -1045,8 +1044,7 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_gl_composite_init (ctx, &setup,
-                                       op, dst,
+    status = _cairo_gl_composite_init (&setup, op, dst,
                                        FALSE,
                                        /* XXX */ NULL);
     if (unlikely (status))
@@ -1083,8 +1081,8 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_dst,
     _cairo_gl_composite_end (ctx, &setup);
 
   CLEANUP:
-    _cairo_gl_composite_fini (ctx, &setup);
     _cairo_gl_context_release (ctx);
+    _cairo_gl_composite_fini (&setup);
 
     return status;
 }
@@ -1178,10 +1176,10 @@ _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
     if (!renderer)
 	return;
 
-    _cairo_gl_composite_fini (renderer->ctx, &renderer->setup);
-
     _cairo_gl_context_release (renderer->ctx);
 
+    _cairo_gl_composite_fini (&renderer->setup);
+
     free (renderer);
 }
 
@@ -1246,8 +1244,7 @@ _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,
+    status = _cairo_gl_composite_init (&renderer->setup,
                                        op, dst,
                                        FALSE, extents);
     if (unlikely (status))
@@ -1272,8 +1269,8 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 
 
 FAIL:
-    _cairo_gl_composite_fini (renderer->ctx, &renderer->setup);
     _cairo_gl_context_release (renderer->ctx);
+    _cairo_gl_composite_fini (&renderer->setup);
     free (renderer);
     return _cairo_span_renderer_create_in_error (status);
 }
commit 60f0cb9c60556f94af903dd6f9da0628a05a1f7f
Author: Benjamin Otte <otte at redhat.com>
Date:   Sat May 22 18:42:44 2010 +0200

    gl: Flush surface at the right times

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 3963310..4a1267f 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -237,6 +237,8 @@ _cairo_gl_pattern_texture_setup (cairo_gl_context_t *ctx,
 
     assert (surface->base.backend == &_cairo_gl_surface_backend);
 
+    cairo_surface_flush (&surface->base);
+
     operand->type = CAIRO_GL_OPERAND_TEXTURE;
     operand->texture.surface = surface;
     operand->texture.tex = surface->tex;
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index be4298f..e71dc13 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -187,6 +187,8 @@ void
 _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
                            cairo_gl_surface_t *surface)
 {
+    cairo_surface_flush (&surface->base);
+
     if (ctx->current_target != surface) {
 	ctx->current_target = surface;
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index ca0b7a2..d1066ef 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -536,6 +536,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
     if (unlikely (status))
 	return status;
 
+    cairo_surface_flush (&dst->base);
+
     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
     glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
     if (_cairo_gl_surface_is_texture (dst)) {


More information about the cairo-commit mailing list