[cairo-commit] 51 commits - boilerplate/cairo-boilerplate-gl.c boilerplate/Makefile.sources boilerplate/Makefile.win32.features build/configure.ac.features build/Makefile.win32.features build/Makefile.win32.features-h configure.ac NEWS perf/cairo-perf.c perf/cairo-perf-trace.c src/cairo-eagle-context.c src/cairo-gl.h src/cairo-gl-private.h src/cairo-gl-surface.c src/cairo-glx-context.c src/cairo.h src/cairo-mutex-list-private.h src/Makefile.sources src/Makefile.win32.features test/a1-image-sample.gl.xfail.png test/alpha-similar.gl.argb32.xfail.png test/alpha-similar.gl.rgb24.xfail.png test/device-offset-fractional.gl.xfail.png test/filter-nearest-offset.gl.xfail.png test/filter-nearest-transformed.gl.xfail.png test/finer-grained-fallbacks.gl.argb32.ref.png test/get-clip.c test/Makefile.am test/mask-glyphs.gl.ref.png test/meta-surface-pattern.gl.argb32.ref.png test/scale-offset-image.gl.ref.png test/scale-offset-similar.gl.ref.png test/source-clip-scale.gl.ref.png test/unbounded-operator.gl.argb32.xfail.png test/unbounded-operator.gl.rgb24.xfail.png util/cairo-script

Chris Wilson ickle at kemper.freedesktop.org
Wed Jul 22 00:24:02 PDT 2009


 NEWS                                           |    8 
 boilerplate/Makefile.sources                   |    2 
 boilerplate/Makefile.win32.features            |   20 
 boilerplate/cairo-boilerplate-gl.c             |  162 ++
 build/Makefile.win32.features                  |    2 
 build/Makefile.win32.features-h                |    6 
 build/configure.ac.features                    |    8 
 configure.ac                                   |   29 
 perf/cairo-perf-trace.c                        |    3 
 perf/cairo-perf.c                              |    3 
 src/Makefile.sources                           |   10 
 src/Makefile.win32.features                    |   28 
 src/cairo-eagle-context.c                      |  181 ++
 src/cairo-gl-private.h                         |   90 +
 src/cairo-gl-surface.c                         | 1902 +++++++++++++++++++++++++
 src/cairo-gl.h                                 |  101 +
 src/cairo-glx-context.c                        |  194 ++
 src/cairo-mutex-list-private.h                 |    4 
 src/cairo.h                                    |    4 
 test/Makefile.am                               |   14 
 test/a1-image-sample.gl.xfail.png              |binary
 test/alpha-similar.gl.argb32.xfail.png         |binary
 test/alpha-similar.gl.rgb24.xfail.png          |binary
 test/device-offset-fractional.gl.xfail.png     |binary
 test/filter-nearest-offset.gl.xfail.png        |binary
 test/filter-nearest-transformed.gl.xfail.png   |binary
 test/finer-grained-fallbacks.gl.argb32.ref.png |binary
 test/get-clip.c                                |    1 
 test/mask-glyphs.gl.ref.png                    |binary
 test/meta-surface-pattern.gl.argb32.ref.png    |binary
 test/scale-offset-image.gl.ref.png             |binary
 test/scale-offset-similar.gl.ref.png           |binary
 test/source-clip-scale.gl.ref.png              |binary
 test/unbounded-operator.gl.argb32.xfail.png    |binary
 test/unbounded-operator.gl.rgb24.xfail.png     |binary
 util/cairo-script/Makefile.am                  |    4 
 util/cairo-script/csi-replay.c                 |   60 
 37 files changed, 2828 insertions(+), 8 deletions(-)

New commits:
commit bfbe875ded0b0666a8048ef5fb598179a81c610a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 22 07:52:30 2009 +0100

    [gl] Enable GL backend for cairo-perf-trace

diff --git a/perf/cairo-perf-trace.c b/perf/cairo-perf-trace.c
index b79f516..a9a8746 100644
--- a/perf/cairo-perf-trace.c
+++ b/perf/cairo-perf-trace.c
@@ -111,6 +111,9 @@ target_is_measurable (const cairo_boilerplate_target_t *target)
 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,9,3)
     case CAIRO_INTERNAL_SURFACE_TYPE_NULL:
 #endif
+#if CAIRO_HAS_GL_SURFACE
+    case CAIRO_SURFACE_TYPE_GL:
+#endif
 	return TRUE;
     case CAIRO_SURFACE_TYPE_PDF:
     case CAIRO_SURFACE_TYPE_PS:
diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c
index 8ad697b..c06eac0 100644
--- a/perf/cairo-perf.c
+++ b/perf/cairo-perf.c
@@ -90,7 +90,6 @@ target_is_measurable (const cairo_boilerplate_target_t *target)
 	    return TRUE;
 	}
     case CAIRO_SURFACE_TYPE_XCB:
-    case CAIRO_SURFACE_TYPE_GL:
     case CAIRO_SURFACE_TYPE_GLITZ:
     case CAIRO_SURFACE_TYPE_QUARTZ:
     case CAIRO_SURFACE_TYPE_WIN32:
@@ -102,6 +101,9 @@ target_is_measurable (const cairo_boilerplate_target_t *target)
 #if CAIRO_VERSION > CAIRO_VERSION_ENCODE(1,9,4)
     case CAIRO_SURFACE_TYPE_QT:
 #endif
+#if CAIRO_HAS_GL_SURFACE
+    case CAIRO_SURFACE_TYPE_GL:
+#endif
 	return TRUE;
 
     default:
commit fed000620335a5fc2bda2ffeca5cbdd0ca5a158c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 22 07:49:05 2009 +0100

    [NEWS] Add stub for OpenGL.

diff --git a/NEWS b/NEWS
index ef1a5d4..681f234 100644
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,14 @@ New experimental backends:
    OpenVG - The initial work was done by Øyvind Kolås, and made ready for
             inclusion by Pierre Tardy.
 
+   OpenGL - An advanced OpenGL compositor. The aim is to write a integrate
+            directed rendering using OpenGL at a high-level into Cairo. In
+	    contrast to the previous attempt using Glitz which tried to
+	    implement the RENDER protocol on top of OpenGL, using the
+	    high-level interface should permit greater flexibility and
+	    more offloading onto the GPU.
+	    The initial work on the backend was performed by Eric Anholt.
+
 
 Snapshot 1.9.2 (2009-06-12)
 ===========================
commit bff0b11634ffe52a5c8b2bbc9b6aee5bc3d2772c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 22 07:45:21 2009 +0100

    [gl] Update reference images

diff --git a/test/Makefile.am b/test/Makefile.am
index 6cb3dd2..2e0eb10 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -127,9 +127,12 @@ CLEANFILES += $(BUILT_SOURCES) make-cairo-test-constructors
 # All tests which have a reference image go here.
 REFERENCE_IMAGES = \
 	a1-image-sample.ref.png \
+	a1-image-sample.gl.xfail.png \
 	a1-mask.ref.png \
 	a1-traps-sample.ref.png \
 	a8-mask.ref.png \
+	alpha-similar.gl.argb32.xfail.png \
+	alpha-similar.gl.rgb24.xfail.png \
 	alpha-similar.pdf.argb32.xfail.png \
 	alpha-similar.pdf.rgb24.xfail.png \
 	alpha-similar.ps.argb32.xfail.png \
@@ -293,6 +296,7 @@ REFERENCE_IMAGES = \
 	degenerate-pen.ps3.ref.png \
 	degenerate-pen.quartz.ref.png \
 	degenerate-pen.ref.png \
+	device-offset-fractional.gl.xfail.png \
 	device-offset-fractional.pdf.argb32.ref.png \
 	device-offset-fractional.pdf.ref.png \
 	device-offset-fractional.pdf.rgb24.ref.png \
@@ -397,14 +401,17 @@ REFERENCE_IMAGES = \
 	filter-bilinear-extents.ps2.ref.png \
 	filter-bilinear-extents.ps3.ref.png \
 	filter-bilinear-extents.ref.png \
+	filter-nearest-offset.gl.xfail.png \
 	filter-nearest-offset.pdf.xfail.png \
 	filter-nearest-offset.ps2.ref.png \
 	filter-nearest-offset.ps3.ref.png \
 	filter-nearest-offset.ref.png \
 	filter-nearest-offset.svg.xfail.png \
+	filter-nearest-transformed.gl.xfail.png \
 	filter-nearest-transformed.pdf.xfail.png \
 	filter-nearest-transformed.ref.png \
 	filter-nearest-transformed.svg.xfail.png \
+	finer-grained-fallbacks.gl.argb32.ref.png \
 	finer-grained-fallbacks.ps2.argb32.ref.png \
 	finer-grained-fallbacks.ps2.ref.png \
 	finer-grained-fallbacks.ps2.rgb24.ref.png \
@@ -540,6 +547,7 @@ REFERENCE_IMAGES = \
 	mask-alpha.xlib.rgb24.ref.png \
 	mask-ctm.ref.png \
 	mask-ctm.rgb24.ref.png \
+	mask-glyphs.gl.ref.png \
 	mask-glyphs.pdf.ref.png \
 	mask-glyphs.ref.png \
 	mask-glyphs.svg.ref.png \
@@ -561,6 +569,7 @@ REFERENCE_IMAGES = \
 	mask.xlib-fallback.rgb24.ref.png \
 	mask.xlib.ref.png \
 	mask.xlib.rgb24.ref.png \
+	meta-surface-pattern.gl.argb32.ref.png \
 	meta-surface-pattern.pdf.argb32.ref.png \
 	meta-surface-pattern.pdf.rgb24.ref.png \
 	meta-surface-pattern.ps2.argb32.ref.png \
@@ -717,12 +726,14 @@ REFERENCE_IMAGES = \
 	rotate-image-surface-paint.ref.png \
 	rotate-image-surface-paint.svg.ref.png \
 	scale-down-source-surface-paint.ref.png \
+	scale-offset-image.gl.ref.png \
 	scale-offset-image.pdf.argb32.ref.png \
 	scale-offset-image.pdf.rgb24.ref.png \
 	scale-offset-image.ps.ref.png \
 	scale-offset-image.ref.png \
 	scale-offset-image.xfail.png \
 	scale-offset-image.xlib.xfail.png \
+	scale-offset-similar.gl.ref.png \
 	scale-offset-similar.pdf.argb32.ref.png \
 	scale-offset-similar.pdf.rgb24.ref.png \
 	scale-offset-similar.ps.ref.png \
@@ -784,6 +795,7 @@ REFERENCE_IMAGES = \
 	smask.ref.png \
 	smask.svg.ref.png \
 	solid-pattern-cache-stress.ref.png \
+	source-clip-scale.gl.ref.png \
 	source-clip-scale.pdf.ref.png \
 	source-clip-scale.ps2.argb32.ref.png \
 	source-clip-scale.ps2.rgb24.ref.png \
@@ -875,6 +887,8 @@ REFERENCE_IMAGES = \
 	twin.svg.ref.png \
 	unantialiased-shapes.quartz.ref.png \
 	unantialiased-shapes.ref.png \
+	unbounded-operator.gl.argb32.xfail.png \
+	unbounded-operator.gl.rgb24.xfail.png \
 	unbounded-operator.pdf.argb32.ref.png \
 	unbounded-operator.ps2.argb32.ref.png \
 	unbounded-operator.ps3.argb32.ref.png \
diff --git a/test/a1-image-sample.gl.xfail.png b/test/a1-image-sample.gl.xfail.png
new file mode 100644
index 0000000..384ba4a
Binary files /dev/null and b/test/a1-image-sample.gl.xfail.png differ
diff --git a/test/alpha-similar.gl.argb32.xfail.png b/test/alpha-similar.gl.argb32.xfail.png
new file mode 100644
index 0000000..579aae1
Binary files /dev/null and b/test/alpha-similar.gl.argb32.xfail.png differ
diff --git a/test/alpha-similar.gl.rgb24.xfail.png b/test/alpha-similar.gl.rgb24.xfail.png
new file mode 100644
index 0000000..86366d2
Binary files /dev/null and b/test/alpha-similar.gl.rgb24.xfail.png differ
diff --git a/test/device-offset-fractional.gl.xfail.png b/test/device-offset-fractional.gl.xfail.png
new file mode 100644
index 0000000..96b0a6a
Binary files /dev/null and b/test/device-offset-fractional.gl.xfail.png differ
diff --git a/test/filter-nearest-offset.gl.xfail.png b/test/filter-nearest-offset.gl.xfail.png
new file mode 100644
index 0000000..a777e7c
Binary files /dev/null and b/test/filter-nearest-offset.gl.xfail.png differ
diff --git a/test/filter-nearest-transformed.gl.xfail.png b/test/filter-nearest-transformed.gl.xfail.png
new file mode 100644
index 0000000..ba8170b
Binary files /dev/null and b/test/filter-nearest-transformed.gl.xfail.png differ
diff --git a/test/finer-grained-fallbacks.gl.argb32.ref.png b/test/finer-grained-fallbacks.gl.argb32.ref.png
new file mode 100644
index 0000000..69ec487
Binary files /dev/null and b/test/finer-grained-fallbacks.gl.argb32.ref.png differ
diff --git a/test/mask-glyphs.gl.ref.png b/test/mask-glyphs.gl.ref.png
new file mode 100644
index 0000000..d341097
Binary files /dev/null and b/test/mask-glyphs.gl.ref.png differ
diff --git a/test/meta-surface-pattern.gl.argb32.ref.png b/test/meta-surface-pattern.gl.argb32.ref.png
new file mode 100644
index 0000000..50e6f5a
Binary files /dev/null and b/test/meta-surface-pattern.gl.argb32.ref.png differ
diff --git a/test/scale-offset-image.gl.ref.png b/test/scale-offset-image.gl.ref.png
new file mode 100644
index 0000000..d2a845c
Binary files /dev/null and b/test/scale-offset-image.gl.ref.png differ
diff --git a/test/scale-offset-similar.gl.ref.png b/test/scale-offset-similar.gl.ref.png
new file mode 100644
index 0000000..d2a845c
Binary files /dev/null and b/test/scale-offset-similar.gl.ref.png differ
diff --git a/test/source-clip-scale.gl.ref.png b/test/source-clip-scale.gl.ref.png
new file mode 100644
index 0000000..fcffbef
Binary files /dev/null and b/test/source-clip-scale.gl.ref.png differ
diff --git a/test/unbounded-operator.gl.argb32.xfail.png b/test/unbounded-operator.gl.argb32.xfail.png
new file mode 100644
index 0000000..34e32eb
Binary files /dev/null and b/test/unbounded-operator.gl.argb32.xfail.png differ
diff --git a/test/unbounded-operator.gl.rgb24.xfail.png b/test/unbounded-operator.gl.rgb24.xfail.png
new file mode 100644
index 0000000..b91da8f
Binary files /dev/null and b/test/unbounded-operator.gl.rgb24.xfail.png differ
commit 653351cd2e9fbe42333cd5ce57b7b49c6da3d122
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 22 07:38:24 2009 +0100

    [gl] Copy font options from image backend.
    
    Enable hint metrics similar to the default image backend. However,
    consider using the display stored in the GLX context to query the screen
    default.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index b547e7f..c3b4231 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1850,6 +1850,15 @@ _cairo_gl_surface_get_extents (void		     *abstract_surface,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void
+_cairo_gl_surface_get_font_options (void                  *abstract_surface,
+				    cairo_font_options_t  *options)
+{
+    _cairo_font_options_init_default (options);
+
+    cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
+}
+
 static const cairo_surface_backend_t _cairo_gl_surface_backend = {
     CAIRO_SURFACE_TYPE_GL,
     _cairo_gl_surface_create_similar,
@@ -1870,7 +1879,7 @@ static const cairo_surface_backend_t _cairo_gl_surface_backend = {
     NULL, /* intersect_clip_path */
     _cairo_gl_surface_get_extents,
     NULL, /* old_show_glyphs */
-    NULL, /* get_font_options */
+    _cairo_gl_surface_get_font_options,
     NULL, /* flush */
     NULL, /* mark_dirty_rectangle */
     NULL, /* scaled_font_fini */
commit a2ac67274d4ef89079c47cc415144a6ac0303f70
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 22 00:05:07 2009 +0100

    [gl] Add warning about missing hook for XCloseDisplay().

diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c
index 05346a6..d3b7b80 100644
--- a/src/cairo-glx-context.c
+++ b/src/cairo-glx-context.c
@@ -42,6 +42,8 @@
 
 #include <X11/Xutil.h>
 
+/* XXX needs hooking into XCloseDisplay() */
+
 typedef struct _cairo_glx_context {
     cairo_gl_context_t base;
 
commit f2f42ec70a626a69f4b29f55f9d1818942bb0b19
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 22 00:01:22 2009 +0100

    [gl] Apply pixel sample bias for spans

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 7ce27a0..b547e7f 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -45,6 +45,8 @@ slim_hidden_proto (cairo_gl_surface_create);
 
 #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
 
+#define BIAS .375
+
 static inline float
 int_as_float (uint32_t val)
 {
@@ -1611,14 +1613,14 @@ _cairo_gl_emit_span_vertex (cairo_gl_surface_span_renderer_t *renderer,
 
     src_attributes = &renderer->setup.src.operand.texture.attributes;
 
-    vertices[v++] = dst_x;
-    vertices[v++] = dst_y;
+    vertices[v++] = dst_x + BIAS;
+    vertices[v++] = dst_y + BIAS;
     vertices[v++] = int_as_float (alpha << 24);
     if (renderer->setup.src.type == OPERAND_TEXTURE) {
 	double s, t;
 
-	s = dst_x;
-	t = dst_y;
+	s = dst_x + BIAS;
+	t = dst_y + BIAS;
 	cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
 	vertices[v++] = s;
 	vertices[v++] = t;
commit 9e420f5d0669ec12eaaf7faf4e55642c10b95fb3
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 21 23:45:00 2009 +0100

    [gl] Another whitespace pass.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 17c4abe..7ce27a0 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -46,7 +46,7 @@ slim_hidden_proto (cairo_gl_surface_create);
 #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
 
 static inline float
-int_as_float(uint32_t val)
+int_as_float (uint32_t val)
 {
     union fi {
 	float f;
@@ -984,8 +984,8 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
     glGenTextures (1, &tex);
     glBindTexture (GL_TEXTURE_2D, tex);
     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
-    assert(((image_surface->stride * image_surface->depth) %
-	    image_surface->depth) == 0);
+    assert (((image_surface->stride * image_surface->depth) %
+	     image_surface->depth) == 0);
     glPixelStorei (GL_UNPACK_ROW_LENGTH,
 		   image_surface->stride /
 		   (PIXMAN_FORMAT_BPP (image_surface->pixman_format) / 8));
@@ -1540,7 +1540,7 @@ typedef struct _cairo_gl_surface_span_renderer {
 } cairo_gl_surface_span_renderer_t;
 
 static void
-_cairo_gl_span_renderer_flush(cairo_gl_surface_span_renderer_t *renderer)
+_cairo_gl_span_renderer_flush (cairo_gl_surface_span_renderer_t *renderer)
 {
     if (renderer->vbo_offset == 0)
 	return;
@@ -1551,8 +1551,8 @@ _cairo_gl_span_renderer_flush(cairo_gl_surface_span_renderer_t *renderer)
 }
 
 static void *
-_cairo_gl_span_renderer_get_vbo(cairo_gl_surface_span_renderer_t *renderer,
-				unsigned int num_vertices)
+_cairo_gl_span_renderer_get_vbo (cairo_gl_surface_span_renderer_t *renderer,
+				 unsigned int num_vertices)
 {
     unsigned int offset;
 
@@ -1562,49 +1562,49 @@ _cairo_gl_span_renderer_get_vbo(cairo_gl_surface_span_renderer_t *renderer,
 	glBindBuffer (GL_ARRAY_BUFFER_ARB, renderer->vbo);
 
 	if (renderer->setup.src.type == OPERAND_TEXTURE)
-	    renderer->vertex_size = 4 * sizeof(float) + sizeof(uint32_t);
+	    renderer->vertex_size = 4 * sizeof (float) + sizeof (uint32_t);
 	else
-	    renderer->vertex_size = 2 * sizeof(float) + sizeof(uint32_t);
+	    renderer->vertex_size = 2 * sizeof (float) + sizeof (uint32_t);
 
 	glVertexPointer (2, GL_FLOAT, renderer->vertex_size, 0);
 	glEnableClientState (GL_VERTEX_ARRAY);
 
 	glColorPointer (4, GL_UNSIGNED_BYTE, renderer->vertex_size,
-			(void *)(uintptr_t)(2 * sizeof(float)));
+			(void *) (uintptr_t) (2 * sizeof (float)));
 	glEnableClientState (GL_COLOR_ARRAY);
 
 	if (renderer->setup.src.type == OPERAND_TEXTURE) {
-	    glClientActiveTexture(GL_TEXTURE0);
+	    glClientActiveTexture (GL_TEXTURE0);
 	    glTexCoordPointer (2, GL_FLOAT, renderer->vertex_size,
-			       (void *)(uintptr_t)(2 * sizeof(float) +
-						   sizeof(uint32_t)));
+			       (void *) (uintptr_t) (2 * sizeof (float) +
+						     sizeof (uint32_t)));
 	    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
 	}
     }
 
     if (renderer->vbo_offset + num_vertices * renderer->vertex_size >
 	renderer->vbo_size) {
-	_cairo_gl_span_renderer_flush(renderer);
+	_cairo_gl_span_renderer_flush (renderer);
     }
 
     if (renderer->vbo_offset == 0) {
 	/* We'll only be using these vertices once. */
-	glBufferData(GL_ARRAY_BUFFER_ARB, renderer->vbo_size, NULL,
-		     GL_STREAM_DRAW_ARB);
-	renderer->vbo_base = glMapBuffer(GL_ARRAY_BUFFER_ARB,
+	glBufferData (GL_ARRAY_BUFFER_ARB, renderer->vbo_size, NULL,
+		      GL_STREAM_DRAW_ARB);
+	renderer->vbo_base = glMapBuffer (GL_ARRAY_BUFFER_ARB,
 					 GL_WRITE_ONLY_ARB);
     }
 
     offset = renderer->vbo_offset;
     renderer->vbo_offset += num_vertices * renderer->vertex_size;
 
-    return (char *)renderer->vbo_base + offset;
+    return (char *) renderer->vbo_base + offset;
 }
 
 static void
-_cairo_gl_emit_span_vertex(cairo_gl_surface_span_renderer_t *renderer,
-			   int dst_x, int dst_y, uint8_t alpha,
-			   float *vertices)
+_cairo_gl_emit_span_vertex (cairo_gl_surface_span_renderer_t *renderer,
+			    int dst_x, int dst_y, uint8_t alpha,
+			    float *vertices)
 {
     cairo_surface_attributes_t *src_attributes;
     int v = 0;
@@ -1613,7 +1613,7 @@ _cairo_gl_emit_span_vertex(cairo_gl_surface_span_renderer_t *renderer,
 
     vertices[v++] = dst_x;
     vertices[v++] = dst_y;
-    vertices[v++] = int_as_float(alpha << 24);
+    vertices[v++] = int_as_float (alpha << 24);
     if (renderer->setup.src.type == OPERAND_TEXTURE) {
 	double s, t;
 
@@ -1626,13 +1626,13 @@ _cairo_gl_emit_span_vertex(cairo_gl_surface_span_renderer_t *renderer,
 }
 
 static void
-_cairo_gl_emit_span(cairo_gl_surface_span_renderer_t *renderer,
-		    int x1, int x2, int y, uint8_t alpha)
+_cairo_gl_emit_span (cairo_gl_surface_span_renderer_t *renderer,
+		     int x1, int x2, int y, uint8_t alpha)
 {
-    float *vertices = _cairo_gl_span_renderer_get_vbo(renderer, 2);
+    float *vertices = _cairo_gl_span_renderer_get_vbo (renderer, 2);
 
-    _cairo_gl_emit_span_vertex(renderer, x1, y, alpha, vertices);
-    _cairo_gl_emit_span_vertex(renderer, x2, y, alpha,
+    _cairo_gl_emit_span_vertex (renderer, x1, y, alpha, vertices);
+    _cairo_gl_emit_span_vertex (renderer, x2, y, alpha,
 			       vertices + renderer->vertex_size / 4);
 }
 
@@ -1681,17 +1681,18 @@ _cairo_gl_surface_span_renderer_render_row (
 	if (x >= xmax)
 	    break;
 
-	_cairo_gl_emit_span(renderer, prev_x + x_translate, x + x_translate, y,
-			    prev_alpha);
+	_cairo_gl_emit_span (renderer,
+			     prev_x + x_translate, x + x_translate, y,
+			     prev_alpha);
 
 	prev_x = x;
 	prev_alpha = spans[i].coverage;
     }
 
     if (prev_x < xmax) {
-	_cairo_gl_emit_span(renderer,
-			    prev_x + x_translate, xmax + x_translate, y,
-			    prev_alpha);
+	_cairo_gl_emit_span (renderer,
+			     prev_x + x_translate, xmax + x_translate, y,
+			     prev_alpha);
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -1716,7 +1717,7 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
 {
     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
 
-    _cairo_gl_span_renderer_flush(renderer);
+    _cairo_gl_span_renderer_flush (renderer);
 
     glBindBuffer (GL_ARRAY_BUFFER_ARB, 0);
     glDeleteBuffers (1, &renderer->vbo);
@@ -1759,7 +1760,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 					const cairo_composite_rectangles_t *rects)
 {
     cairo_gl_surface_t *dst = abstract_dst;
-    cairo_gl_surface_span_renderer_t *renderer = calloc(1, sizeof(*renderer));
+    cairo_gl_surface_span_renderer_t *renderer = calloc (1, sizeof (*renderer));
     cairo_status_t status;
     int width = rects->width;
     int height = rects->height;
@@ -1828,7 +1829,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 
     while ((err = glGetError ()))
-	fprintf(stderr, "GL error 0x%08x\n", (int) err);
+	fprintf (stderr, "GL error 0x%08x\n", (int) err);
 
     return &renderer->base;
 }
commit 222fd8b49b25c56f38ad375059240983a8f576ce
Merge: 5471603... 7ee0fee...
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 21 23:42:34 2009 +0100

    Merge commit 'anholt/gl-span-renderer'

diff --cc src/cairo-gl-surface.c
index 6e605f4,269ba14..17c4abe
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@@ -43,8 -43,20 +43,20 @@@ slim_hidden_proto (cairo_gl_context_ref
  slim_hidden_proto (cairo_gl_context_destroy);
  slim_hidden_proto (cairo_gl_surface_create);
  
 -#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
 +#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
  
+ static inline float
+ int_as_float(uint32_t val)
+ {
+     union fi {
+ 	float f;
+ 	uint32_t u;
+     } fi;
+ 
+     fi.u = val;
+     return fi.f;
+ }
+ 
  enum cairo_gl_composite_operand_type {
      OPERAND_CONSTANT,
      OPERAND_TEXTURE,
@@@ -1219,10 -1240,9 +1271,9 @@@ _cairo_gl_surface_composite (cairo_oper
      cairo_status_t status;
      int i;
      GLenum err;
-     GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
      cairo_gl_composite_setup_t setup;
  
 -    memset(&setup, 0, sizeof(setup));
 +    memset (&setup, 0, sizeof (setup));
  
      status = _cairo_gl_operand_init (&setup.src, src, dst,
  				     src_x, src_y,
commit 5471603b527ecf43aaa72665d47929a1038aa642
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 21 23:38:05 2009 +0100

    [gl] Use QUADS for drawing fill_rectangles() not TRIFAN
    
    As each rectangle is independent, we need to draw the array using QUADS.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 695b245..6e605f4 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1485,7 +1485,7 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
     glEnableClientState (GL_VERTEX_ARRAY);
     glColorPointer (4, GL_FLOAT, sizeof (GLfloat)*4, colors);
     glEnableClientState (GL_COLOR_ARRAY);
-    glDrawArrays (GL_TRIANGLE_FAN, 0, 4 * num_rects);
+    glDrawArrays (GL_QUADS, 0, 4 * num_rects);
 
     glDisableClientState (GL_COLOR_ARRAY);
     glDisableClientState (GL_VERTEX_ARRAY);
commit c3ef0c8d2011a23d73ff919dbb947ca68e1d8c1b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 21 23:31:30 2009 +0100

    [gl] Whitespace
    
    Ensure we leave a space between a function call and its parameters.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index e863d66..695b245 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -43,7 +43,7 @@ slim_hidden_proto (cairo_gl_context_reference);
 slim_hidden_proto (cairo_gl_context_destroy);
 slim_hidden_proto (cairo_gl_surface_create);
 
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
 
 enum cairo_gl_composite_operand_type {
     OPERAND_CONSTANT,
@@ -330,14 +330,14 @@ _cairo_gl_set_destination (cairo_gl_surface_t *surface)
     glViewport (0, 0, surface->width, surface->height);
 
     glMatrixMode (GL_PROJECTION);
-    glLoadIdentity();
+    glLoadIdentity ();
     if (surface->fb)
-	glOrtho(0, surface->width, 0, surface->height, -1.0, 1.0);
+	glOrtho (0, surface->width, 0, surface->height, -1.0, 1.0);
     else
-	glOrtho(0, surface->width, surface->height, 0, -1.0, 1.0);
+	glOrtho (0, surface->width, surface->height, 0, -1.0, 1.0);
 
     glMatrixMode (GL_MODELVIEW);
-    glLoadIdentity();
+    glLoadIdentity ();
 }
 
 static int
@@ -498,8 +498,8 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     /* Create a framebuffer object wrapping the texture so that we can render
      * to it.
      */
-    glGenFramebuffersEXT(1, &surface->fb);
-    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, surface->fb);
+    glGenFramebuffersEXT (1, &surface->fb);
+    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
     glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
 			       GL_COLOR_ATTACHMENT0_EXT,
 			       GL_TEXTURE_2D,
@@ -507,12 +507,12 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
 			       0);
 
     while ((err = glGetError ())) {
-	fprintf(stderr, "GL error in surface create: 0x%08x\n", err);
+	fprintf (stderr, "GL error in surface create: 0x%08x\n", err);
     }
 
     status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
     if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
-	fprintf(stderr, "destination is framebuffer incomplete\n");
+	fprintf (stderr, "destination is framebuffer incomplete\n");
 
     /* Cairo surfaces start out initialized to transparent (black) */
     ctx = _cairo_gl_context_acquire (surface->ctx);
@@ -615,7 +615,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 {
     char *temp_data;
     int y;
-    unsigned int cpp = PIXMAN_FORMAT_BPP(src->pixman_format) / 8;
+    unsigned int cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
     GLenum internal_format, format, type;
     char *src_data_start;
     cairo_bool_t has_alpha;
@@ -645,7 +645,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 
     _cairo_gl_set_destination (dst);
     glRasterPos2i (dst_x, dst_y);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
     glDrawPixels (width, height, format, type, temp_data);
 
     free (temp_data);
@@ -700,7 +700,7 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
 	type = GL_UNSIGNED_BYTE;
 	cpp = 1;
     } else {
-	fprintf(stderr, "get_image fallback: %d\n", surface->base.content);
+	fprintf (stderr, "get_image fallback: %d\n", surface->base.content);
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
@@ -714,7 +714,7 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
      * it the destination.  But then, this is the fallback path, so let's not
      * fall back instead.
      */
-    _cairo_gl_set_destination(surface);
+    _cairo_gl_set_destination (surface);
 
     /* Read the data to a temporary as GL gives us bottom-to-top data
      * screen-wise, and we want top-to-bottom.
@@ -723,13 +723,13 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
     if (temp_data == NULL)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    glPixelStorei(GL_PACK_ALIGNMENT, 1);
-    glReadPixels(extents.x, extents.y,
+    glPixelStorei (GL_PACK_ALIGNMENT, 1);
+    glReadPixels (extents.x, extents.y,
 		 extents.width, extents.height,
 		 format, type, temp_data);
 
     for (y = 0; y < extents.height; y++) {
-	memcpy ((char *)image->data + y * image->stride,
+	memcpy ((char *) image->data + y * image->stride,
 		temp_data + y * extents.width * cpp,
 		extents.width * cpp);
     }
@@ -738,7 +738,7 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
     *image_out = image;
 
     while ((err = glGetError ()))
-	fprintf(stderr, "GL error 0x%08x\n", (int) err);
+	fprintf (stderr, "GL error 0x%08x\n", (int) err);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -754,7 +754,7 @@ _cairo_gl_surface_finish (void *abstract_surface)
     if (surface->ctx->current_target == surface)
 	surface->ctx->current_target = NULL;
 
-    cairo_gl_context_destroy(surface->ctx);
+    cairo_gl_context_destroy (surface->ctx);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -976,7 +976,7 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 	    image_surface->depth) == 0);
     glPixelStorei (GL_UNPACK_ROW_LENGTH,
 		   image_surface->stride /
-		   (PIXMAN_FORMAT_BPP(image_surface->pixman_format) / 8));
+		   (PIXMAN_FORMAT_BPP (image_surface->pixman_format) / 8));
     /* The filter will be correctly set up later, but for now we want to
      * hint to glTexImage that we're not mipmapping.
      */
@@ -1013,9 +1013,9 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
     cairo_matrix_init_translate (&m,
 				 src_x - dst_x,
 				 src_y - dst_y);
-    cairo_matrix_multiply(&attributes->matrix,
-			  &m,
-			  &attributes->matrix);
+    cairo_matrix_multiply (&attributes->matrix,
+			   &m,
+			   &attributes->matrix);
 
     /* Translate the matrix from
      * (unnormalized src -> unnormalized src) to
@@ -1069,7 +1069,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
     if (unlikely (status))
 	return status;
 
-    assert(surface->base.backend == &_cairo_gl_surface_backend);
+    assert (surface->base.backend == &_cairo_gl_surface_backend);
 
     operand->operand.texture.surface = surface;
     operand->operand.texture.tex = surface->tex;
@@ -1110,7 +1110,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
 }
 
 static cairo_int_status_t
-_cairo_gl_operand_init(cairo_gl_composite_operand_t *operand,
+_cairo_gl_operand_init (cairo_gl_composite_operand_t *operand,
 		       const cairo_pattern_t *pattern,
 		       cairo_gl_surface_t *dst,
 		       int src_x, int src_y,
@@ -1134,11 +1134,11 @@ _cairo_gl_operand_init(cairo_gl_composite_operand_t *operand,
     case CAIRO_PATTERN_TYPE_LINEAR:
     case CAIRO_PATTERN_TYPE_RADIAL:
 	operand->type = OPERAND_TEXTURE;
-	return _cairo_gl_pattern_texture_setup(operand,
-					       pattern, dst,
-					       src_x, src_y,
-					       dst_x, dst_y,
-					       width, height);
+	return _cairo_gl_pattern_texture_setup (operand,
+						pattern, dst,
+						src_x, src_y,
+						dst_x, dst_y,
+						width, height);
     }
 }
 
@@ -1222,7 +1222,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
     cairo_gl_composite_setup_t setup;
 
-    memset(&setup, 0, sizeof(setup));
+    memset (&setup, 0, sizeof (setup));
 
     status = _cairo_gl_operand_init (&setup.src, src, dst,
 				     src_x, src_y,
@@ -1232,7 +1232,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	return status;
     src_attributes = &setup.src.operand.texture.attributes;
 
-    if (mask != NULL && _cairo_pattern_is_opaque(mask))
+    if (mask != NULL && _cairo_pattern_is_opaque (mask))
 	mask = NULL;
 
     if (mask != NULL) {
@@ -1327,7 +1327,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     vertices[3][0] = dst_x;
     vertices[3][1] = dst_y + height;
 
-    glVertexPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, vertices);
+    glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 2, vertices);
     glEnableClientState (GL_VERTEX_ARRAY);
 
     if (setup.src.type == OPERAND_TEXTURE) {
@@ -1342,7 +1342,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	}
 
 	glClientActiveTexture (GL_TEXTURE0);
-	glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_src);
+	glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_src);
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
     }
 
@@ -1359,7 +1359,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	    }
 
 	    glClientActiveTexture (GL_TEXTURE1);
-	    glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_mask);
+	    glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat)*2, texcoord_mask);
 	    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
 	}
     }
@@ -1381,7 +1381,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     glDisable (GL_TEXTURE_2D);
 
     while ((err = glGetError ()))
-	fprintf(stderr, "GL error 0x%08x\n", (int) err);
+	fprintf (stderr, "GL error 0x%08x\n", (int) err);
 
     _cairo_gl_context_release (ctx);
 
@@ -1450,12 +1450,12 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
 	return status;
     }
 
-    vertices = _cairo_malloc_ab(num_rects, sizeof(GLfloat) * 4 * 2);
-    colors = _cairo_malloc_ab(num_rects, sizeof(GLfloat) * 4 * 4);
+    vertices = _cairo_malloc_ab (num_rects, sizeof (GLfloat) * 4 * 2);
+    colors = _cairo_malloc_ab (num_rects, sizeof (GLfloat) * 4 * 4);
     if (!vertices || !colors) {
-	_cairo_gl_context_release(ctx);
-	free(vertices);
-	free(colors);
+	_cairo_gl_context_release (ctx);
+	free (vertices);
+	free (colors);
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
@@ -1481,9 +1481,9 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
     }
 
     glEnable (GL_BLEND);
-    glVertexPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, vertices);
+    glVertexPointer (2, GL_FLOAT, sizeof (GLfloat)*2, vertices);
     glEnableClientState (GL_VERTEX_ARRAY);
-    glColorPointer (4, GL_FLOAT, sizeof(GLfloat) * 4, colors);
+    glColorPointer (4, GL_FLOAT, sizeof (GLfloat)*4, colors);
     glEnableClientState (GL_COLOR_ARRAY);
     glDrawArrays (GL_TRIANGLE_FAN, 0, 4 * num_rects);
 
@@ -1492,8 +1492,8 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
     glDisable (GL_BLEND);
 
     _cairo_gl_context_release (ctx);
-    free(vertices);
-    free(colors);
+    free (vertices);
+    free (colors);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1549,7 +1549,7 @@ static const cairo_surface_backend_t _cairo_gl_surface_backend = {
 cairo_status_t
 cairo_gl_surface_glfinish (cairo_surface_t *surface)
 {
-    glFinish();
+    glFinish ();
 
     return CAIRO_STATUS_SUCCESS;
 }
commit b71c27bf4ebd19f74f22392ddb2612d843c74a38
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 21 23:26:15 2009 +0100

    [gl] Remove dead code.
    
    The loop between texture_setup() and clone_similar() should be
    impossible, since every compositing backend should know how to clone an
    image surface. cairo-gl is no longer an exception and so this code can
    safely be removed.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 9b66481..e863d66 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1058,29 +1058,6 @@ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
     if (status == CAIRO_STATUS_SUCCESS)
 	return CAIRO_STATUS_SUCCESS;
 
-    /* Avoid looping in acquire surface fallback -> clone similar -> paint ->
-     * gl_composite -> acquire surface -> fallback.
-     */
-    if (src->type == CAIRO_PATTERN_TYPE_SURFACE) {
-	cairo_surface_pattern_t *surface_pattern;
-
-	surface_pattern = (cairo_surface_pattern_t *)src;
-	if (_cairo_surface_is_image (surface_pattern->surface)) {
-	    cairo_image_surface_t *image_surface;
-	    GLenum internal_format, format, type;
-	    cairo_bool_t has_alpha;
-
-	    image_surface = (cairo_image_surface_t *)surface_pattern->surface;
-
-	    status = _cairo_gl_get_image_format_and_type (image_surface->pixman_format,
-							  &internal_format,
-							  &format, &type,
-							  &has_alpha);
-		if (status)
-		    return status;
-	}
-    }
-
     status = _cairo_pattern_acquire_surface (src, &dst->base,
 					     CAIRO_CONTENT_COLOR_ALPHA,
 					     src_x, src_y,
@@ -1089,12 +1066,12 @@ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
 					     (cairo_surface_t **)
 					     &surface,
 					     attributes);
-    operand->operand.texture.surface = surface;
     if (unlikely (status))
 	return status;
 
     assert(surface->base.backend == &_cairo_gl_surface_backend);
 
+    operand->operand.texture.surface = surface;
     operand->operand.texture.tex = surface->tex;
     switch (surface->base.content) {
     case CAIRO_CONTENT_ALPHA:
commit c8cc6a205a68a7c87239424aa93a29b5b166561d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 21 23:08:39 2009 +0100

    [gl] Avoid temporary allocation of pixman trapezoids
    
    When creating the trapezoid mask, avoid having to allocate a temporary
    array to hold the converted pixman trapezoids by instead rasterizing each
    trapezoid separately into the mask.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index df130f8..9b66481 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -883,56 +883,46 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
 			     cairo_trapezoid_t *traps,
 			     int num_traps,
 			     cairo_antialias_t antialias,
-			     cairo_pattern_t **pattern)
+			     cairo_surface_pattern_t *pattern)
 {
-    pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
-    pixman_trapezoid_t *pixman_traps;
-    cairo_image_surface_t *image_surface;
+    pixman_format_code_t pixman_format;
+    pixman_image_t *image;
+    cairo_surface_t *surface;
     int i;
 
-    /* Convert traps to pixman traps */
-    pixman_traps = stack_traps;
-    if (num_traps > ARRAY_LENGTH (stack_traps)) {
-	pixman_traps = _cairo_malloc_ab (num_traps, sizeof (pixman_trapezoid_t));
-	if (unlikely (pixman_traps == NULL))
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
+    pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
+    image = pixman_image_create_bits (pixman_format, width, height, NULL, 0);
+    if (unlikely (image == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     for (i = 0; i < num_traps; i++) {
-	pixman_traps[i].top = _cairo_fixed_to_16_16 (traps[i].top);
-	pixman_traps[i].bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
-	pixman_traps[i].left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
-	pixman_traps[i].left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
-	pixman_traps[i].left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
-	pixman_traps[i].left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
-	pixman_traps[i].right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
-	pixman_traps[i].right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
-	pixman_traps[i].right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
-	pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
-    }
+	pixman_trapezoid_t trap;
 
-    if (antialias != CAIRO_ANTIALIAS_NONE) {
-	image_surface = (cairo_image_surface_t*)
-	    cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
-    } else {
-	image_surface = (cairo_image_surface_t*)
-	    cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
-    }
+	trap.top = _cairo_fixed_to_16_16 (traps[i].top);
+	trap.bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
 
-    if (image_surface->base.status) {
-	if (pixman_traps != stack_traps)
-	    free (pixman_traps);
-	return image_surface->base.status;
-    }
+	trap.left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
+	trap.left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
+	trap.left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
+	trap.left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
 
-    pixman_add_trapezoids (image_surface->pixman_image, -dst_x, -dst_y,
-			   num_traps, pixman_traps);
+	trap.right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
+	trap.right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
+	trap.right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
+	trap.right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
 
-    if (pixman_traps != stack_traps)
-	free (pixman_traps);
+	pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
+    }
+
+    surface = _cairo_image_surface_create_for_pixman_image (image,
+							    pixman_format);
+    if (unlikely (surface->status)) {
+	pixman_image_unref (image);
+	return surface->status;
+    }
 
-    *pattern = cairo_pattern_create_for_surface (&image_surface->base);
-    cairo_surface_destroy (&image_surface->base);
+    _cairo_pattern_init_for_surface (pattern, surface);
+    cairo_surface_destroy (surface);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1438,24 +1428,24 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
 					int num_traps)
 {
     cairo_gl_surface_t *dst = abstract_dst;
-    cairo_pattern_t *traps_pattern;
+    cairo_surface_pattern_t traps_pattern;
     cairo_int_status_t status;
 
     status = _cairo_gl_get_traps_pattern (dst,
 					  dst_x, dst_y, width, height,
 					  traps, num_traps, antialias,
 					  &traps_pattern);
-    if (status) {
-	fprintf(stderr, "traps falllback\n");
+    if (unlikely (status))
 	return status;
-    }
 
-    status = _cairo_gl_surface_composite (op, pattern, traps_pattern, dst,
+    status = _cairo_gl_surface_composite (op,
+					  pattern, &traps_pattern.base, dst,
 					  src_x, src_y,
 					  0, 0,
 					  dst_x, dst_y,
 					  width, height);
-    cairo_pattern_destroy (traps_pattern);
+
+    _cairo_pattern_fini (&traps_pattern.base);
 
     return status;
 }
commit 5deb8fa213ce86759053be391966618ee0959f50
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jun 9 16:20:32 2009 +0100

    [gl] Construct a dummy window for the initial context
    
    In order to make the initial context current we need a Drawable that
    matches the context. In general, the RootWindow may not match the desired
    context so we need to query the context and construct an appropriate
    Drawable.

diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c
index 2fa5faf..05346a6 100644
--- a/src/cairo-glx-context.c
+++ b/src/cairo-glx-context.c
@@ -40,10 +40,13 @@
 
 #include "cairo-gl-private.h"
 
+#include <X11/Xutil.h>
+
 typedef struct _cairo_glx_context {
     cairo_gl_context_t base;
 
     Display *display;
+    Window dummy_window;
     GLXContext context;
 } cairo_glx_context_t;
 
@@ -77,6 +80,61 @@ _glx_swap_buffers (void *abstract_ctx,
 static void
 _glx_destroy (void *abstract_ctx)
 {
+    cairo_glx_context_t *ctx = abstract_ctx;
+
+    if (ctx->dummy_window != None)
+	XDestroyWindow (ctx->display, ctx->dummy_window);
+}
+
+static cairo_status_t
+_glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy)
+{
+    int attr[3] = { GLX_FBCONFIG_ID, 0, None };
+    GLXFBConfig *config;
+    XVisualInfo *vi;
+    Colormap cmap;
+    XSetWindowAttributes swa;
+    Window win = None;
+    int cnt;
+
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    /* Create a dummy window created for the target GLX context that we can
+     * use to query the available GL/GLX extensions.
+     */
+    glXQueryContext (dpy, gl_ctx, GLX_FBCONFIG_ID, &attr[1]);
+
+    cnt = 0;
+    config = glXChooseFBConfig (dpy, DefaultScreen (dpy), attr, &cnt);
+    if (cnt == 0)
+	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
+    vi = glXGetVisualFromFBConfig (dpy, config[0]);
+    XFree (config);
+
+    cmap = XCreateColormap (dpy,
+			    RootWindow (dpy, vi->screen),
+			    vi->visual,
+			    AllocNone);
+    swa.colormap = cmap;
+    swa.border_pixel = 0;
+    win = XCreateWindow (dpy, RootWindow (dpy, vi->screen),
+			 -1, -1, 1, 1, 0,
+			 vi->depth,
+			 InputOutput,
+			 vi->visual,
+			 CWBorderPixel | CWColormap, &swa);
+    XFreeColormap (dpy, cmap);
+    XFree (vi);
+
+    XFlush (dpy);
+    if (! glXMakeCurrent (dpy, win, gl_ctx)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	XDestroyWindow (dpy, win);
+	win = None;
+    }
+
+    *dummy = win;
+    return status;
 }
 
 cairo_gl_context_t *
@@ -84,20 +142,18 @@ cairo_glx_context_create (Display *dpy, GLXContext gl_ctx)
 {
     cairo_glx_context_t *ctx;
     cairo_status_t status;
+    Window dummy = None;
 
-    /* Make our GL context active.  While we'll be setting the destination
-     * drawable with each rendering operation, in order to set the context
-     * we have to choose a drawable.  The root window happens to be convenient
-     * for this.
-     */
-    if (! glXMakeCurrent (dpy, RootWindow (dpy, DefaultScreen (dpy)), gl_ctx))
-	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+    status = _glx_dummy_ctx (dpy, gl_ctx, &dummy);
+    if (status)
+	return _cairo_gl_context_create_in_error (status);
 
     ctx = calloc (1, sizeof (cairo_glx_context_t));
     if (ctx == NULL)
 	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
 
     ctx->display = dpy;
+    ctx->dummy_window = dummy;
     ctx->context = gl_ctx;
 
     ctx->base.make_current = _glx_make_current;
commit 911482e5ae88ba26a1b3290731968f8b8a80cd70
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 22 23:44:27 2009 +0100

    [gl] Constrain image sources to max texture size

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 47ebd01..3d37fe0 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -65,6 +65,8 @@ struct _cairo_gl_context {
 
     cairo_mutex_t mutex; /* needed? */
     GLuint dummy_tex;
+    GLint max_framebuffer_size;
+    GLint max_texture_size;
 
     cairo_gl_surface_t *current_target;
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index d54c0a2..df130f8 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -130,6 +130,11 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
 		  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 
+    ctx->max_framebuffer_size = 0;
+    glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size);
+    ctx->max_texture_size = 0;
+    glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -459,6 +464,9 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     if (ctx->status)
 	return _cairo_surface_create_in_error (ctx->status);
 
+    if (width > ctx->max_framebuffer_size || height > ctx->max_framebuffer_size)
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+
     surface = calloc (1, sizeof (cairo_gl_surface_t));
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -584,6 +592,12 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
 
     assert (CAIRO_CONTENT_VALID (content));
 
+    if (width > surface->ctx->max_framebuffer_size ||
+	height > surface->ctx->max_framebuffer_size)
+    {
+	return NULL;
+    }
+
     if (width < 1)
 	width = 1;
     if (height < 1)
@@ -946,6 +960,11 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     image_surface = (cairo_image_surface_t *)surface_pattern->surface;
+    if (image_surface->width > dst->ctx->max_texture_size ||
+	image_surface->height > dst->ctx->max_texture_size)
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
 
     /* The textures we create almost always has appropriate alpha channel
      * contents.  But sometimes GL sucks at image specification and we end up
commit 1ae5942a3aa9f73aa71438dc40221836b0dff7e2
Merge: fd9df49... 6a59574...
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 21 22:28:44 2009 +0100

    Merge commit 'anholt/gl'
    
    Conflicts:
    	boilerplate/Makefile.sources
    	boilerplate/cairo-boilerplate.c
    	build/configure.ac.features
    	src/cairo.h
    	util/cairo-script/Makefile.am

diff --cc boilerplate/Makefile.sources
index b40df4c,971c7e1..3e3135a
--- a/boilerplate/Makefile.sources
+++ b/boilerplate/Makefile.sources
@@@ -21,9 -18,16 +21,9 @@@ cairo_boilerplate_private = 
  
  # automake is stupid enough to always use c++ linker if we enable the
  # following lines, even if beos surface is not enabled.  Disable it for now.
 -cairo_boilerplate_beos_private = cairo-boilerplate-beos-private.h
  #libcairoboilerplate_la_SOURCES += cairo-boilerplate-beos.cpp
  
- cairo_boilerplate_directfb_sources = cairo-boilerplate-directfb.c
 -cairo_boilerplate_directfb_private = cairo-boilerplate-directfb-private.h
 -cairo_boilerplate_directfb_sources = cairo-boilerplate-directfb.c
 -
 -cairo_boilerplate_gl_private = cairo-boilerplate-gl-private.h
+ cairo_boilerplate_gl_sources = cairo-boilerplate-gl.c
 -
 -cairo_boilerplate_glitz_private = cairo-boilerplate-glitz-private.h
  cairo_boilerplate_glitz_sources = \
  	cairo-boilerplate-glitz-agl.c \
  	cairo-boilerplate-glitz-glx.c \
diff --cc boilerplate/Makefile.win32.features
index e691118,a2efcd8..44ca95f
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@@ -139,6 -129,36 +139,16 @@@ enabled_cairo_boilerplate_private += $(
  enabled_cairo_boilerplate_sources += $(cairo_boilerplate_png_sources)
  endif
  
+ unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
+ all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
+ all_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
+ all_cairo_boilerplate_sources += $(cairo_boilerplate_gl_sources)
+ ifeq ($(CAIRO_HAS_GL_SURFACE),1)
+ enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
+ enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
+ enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_sources)
+ endif
+ 
 -supported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_glx_headers)
 -all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_glx_headers)
 -all_cairo_boilerplate_private += $(cairo_boilerplate_gl_glx_private)
 -all_cairo_boilerplate_sources += $(cairo_boilerplate_gl_glx_sources)
 -ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
 -enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gl_glx_headers)
 -enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_glx_private)
 -enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_glx_sources)
 -endif
 -
 -supported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_egl_headers)
 -all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_egl_headers)
 -all_cairo_boilerplate_private += $(cairo_boilerplate_gl_egl_private)
 -all_cairo_boilerplate_sources += $(cairo_boilerplate_gl_egl_sources)
 -ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
 -enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gl_egl_headers)
 -enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_egl_private)
 -enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_egl_sources)
 -endif
 -
  unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_glitz_headers)
  all_cairo_boilerplate_headers += $(cairo_boilerplate_glitz_headers)
  all_cairo_boilerplate_private += $(cairo_boilerplate_glitz_private)
@@@ -159,36 -179,6 +169,46 @@@ enabled_cairo_boilerplate_private += $(
  enabled_cairo_boilerplate_sources += $(cairo_boilerplate_directfb_sources)
  endif
  
 +unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_vg_headers)
 +all_cairo_boilerplate_headers += $(cairo_boilerplate_vg_headers)
 +all_cairo_boilerplate_private += $(cairo_boilerplate_vg_private)
 +all_cairo_boilerplate_sources += $(cairo_boilerplate_vg_sources)
 +ifeq ($(CAIRO_HAS_VG_SURFACE),1)
 +enabled_cairo_boilerplate_headers += $(cairo_boilerplate_vg_headers)
 +enabled_cairo_boilerplate_private += $(cairo_boilerplate_vg_private)
 +enabled_cairo_boilerplate_sources += $(cairo_boilerplate_vg_sources)
 +endif
 +
++supported_cairo_boilerplate_headers += $(cairo_boilerplate_eagle_headers)
++all_cairo_boilerplate_headers += $(cairo_boilerplate_eagle_headers)
++all_cairo_boilerplate_private += $(cairo_boilerplate_eagle_private)
++all_cairo_boilerplate_sources += $(cairo_boilerplate_eagle_sources)
++ifeq ($(CAIRO_HAS_EAGLE_FUNCTIONS),1)
++enabled_cairo_boilerplate_headers += $(cairo_boilerplate_eagle_headers)
++enabled_cairo_boilerplate_private += $(cairo_boilerplate_eagle_private)
++enabled_cairo_boilerplate_sources += $(cairo_boilerplate_eagle_sources)
++endif
++
 +supported_cairo_boilerplate_headers += $(cairo_boilerplate_egl_headers)
 +all_cairo_boilerplate_headers += $(cairo_boilerplate_egl_headers)
 +all_cairo_boilerplate_private += $(cairo_boilerplate_egl_private)
 +all_cairo_boilerplate_sources += $(cairo_boilerplate_egl_sources)
 +ifeq ($(CAIRO_HAS_EGL_FUNCTIONS),1)
 +enabled_cairo_boilerplate_headers += $(cairo_boilerplate_egl_headers)
 +enabled_cairo_boilerplate_private += $(cairo_boilerplate_egl_private)
 +enabled_cairo_boilerplate_sources += $(cairo_boilerplate_egl_sources)
 +endif
 +
 +supported_cairo_boilerplate_headers += $(cairo_boilerplate_glx_headers)
 +all_cairo_boilerplate_headers += $(cairo_boilerplate_glx_headers)
 +all_cairo_boilerplate_private += $(cairo_boilerplate_glx_private)
 +all_cairo_boilerplate_sources += $(cairo_boilerplate_glx_sources)
 +ifeq ($(CAIRO_HAS_GLX_FUNCTIONS),1)
 +enabled_cairo_boilerplate_headers += $(cairo_boilerplate_glx_headers)
 +enabled_cairo_boilerplate_private += $(cairo_boilerplate_glx_private)
 +enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glx_sources)
 +endif
 +
  unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_script_headers)
  all_cairo_boilerplate_headers += $(cairo_boilerplate_script_headers)
  all_cairo_boilerplate_private += $(cairo_boilerplate_script_private)
diff --cc boilerplate/cairo-boilerplate-gl.c
index 0000000,37dfc42..940fd75
mode 000000,100644..100644
--- a/boilerplate/cairo-boilerplate-gl.c
+++ b/boilerplate/cairo-boilerplate-gl.c
@@@ -1,0 -1,139 +1,162 @@@
+ /* Cairo - a vector graphics library with display and print output
+  *
+  * Copyright © 2009 Chris Wilson
+  *
+  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Chris Wilson.
+  */
+ 
 -#include "cairo-boilerplate.h"
 -#include "cairo-boilerplate-gl-private.h"
++#include "cairo-boilerplate-private.h"
+ 
+ #include <cairo-gl.h>
+ 
+ typedef struct _gl_target_closure {
+     Display *dpy;
+     int screen;
+ 
+     GLXContext gl_ctx;
+     cairo_gl_context_t *ctx;
+     cairo_surface_t *surface;
+ } gl_target_closure_t;
+ 
 -void
++static void
+ _cairo_boilerplate_gl_cleanup (void *closure)
+ {
+     gl_target_closure_t *gltc = closure;
+ 
+     cairo_gl_context_destroy (gltc->ctx);
+     glXDestroyContext (gltc->dpy, gltc->gl_ctx);
+     XCloseDisplay (gltc->dpy);
+     free (gltc);
+ }
+ 
 -cairo_surface_t *
++static cairo_surface_t *
+ _cairo_boilerplate_gl_create_surface (const char		 *name,
 -				       cairo_content_t		  content,
 -				       int			  width,
 -				       int			  height,
 -				       int			  max_width,
 -				       int			  max_height,
 -				       cairo_boilerplate_mode_t	  mode,
 -				       int			  id,
 -				       void			**closure)
++				      cairo_content_t		  content,
++				      double			  width,
++				      double			  height,
++				      double			  max_width,
++				      double			  max_height,
++				      cairo_boilerplate_mode_t	  mode,
++				      int			  id,
++				      void			**closure)
+ {
+     int rgba_attribs[] = { GLX_RGBA,
+ 			   GLX_RED_SIZE, 1,
+ 			   GLX_GREEN_SIZE, 1,
+ 			   GLX_BLUE_SIZE, 1,
+ 			   GLX_ALPHA_SIZE, 1,
+ 			   GLX_DOUBLEBUFFER,
+ 			   None };
+     int rgb_attribs[] = { GLX_RGBA,
+ 			  GLX_RED_SIZE, 1,
+ 			  GLX_GREEN_SIZE, 1,
+ 			  GLX_BLUE_SIZE, 1,
+ 			  GLX_DOUBLEBUFFER,
+ 			  None };
+     XVisualInfo *visinfo;
+     GLXContext gl_ctx;
+     gl_target_closure_t *gltc;
+     Display *dpy;
+ 
+     gltc = malloc (sizeof (gl_target_closure_t));
+     *closure = gltc;
+ 
+     if (width == 0)
+ 	width = 1;
+     if (height == 0)
+ 	height = 1;
+ 
+     dpy = XOpenDisplay (NULL);
+     gltc->dpy = dpy;
+     if (!gltc->dpy) {
+ 	fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0));
+ 	free (gltc);
+ 	return NULL;
+     }
+ 
+     if (mode == CAIRO_BOILERPLATE_MODE_TEST)
+ 	XSynchronize (gltc->dpy, 1);
+ 
+     if (content == CAIRO_CONTENT_COLOR)
+ 	visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs);
+     else
+ 	visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
+ 
+     if (visinfo == NULL) {
+ 	fprintf (stderr, "Failed to create RGB, double-buffered visual\n");
+ 	XCloseDisplay (dpy);
+ 	free (gltc);
+ 	return NULL;
+     }
+ 
+     gl_ctx = glXCreateContext (dpy, visinfo, NULL, True);
+     XFree (visinfo);
+ 
+     gltc->gl_ctx = gl_ctx;
+     gltc->ctx = cairo_glx_context_create (dpy, gl_ctx);
+ 
+     gltc->surface = cairo_gl_surface_create (gltc->ctx, content,
 -					     width, height);
++					     ceil (width), ceil (height));
+ 
+     if (gltc->surface == NULL || cairo_surface_status (gltc->surface))
+ 	_cairo_boilerplate_gl_cleanup (gltc);
+ 
+     return gltc->surface;
+ }
+ 
 -void
++static void
+ _cairo_boilerplate_gl_synchronize (void *closure)
+ {
+     gl_target_closure_t *gltc = closure;
+ 
+     cairo_gl_surface_glfinish (gltc->surface);
+ }
++
++static const cairo_boilerplate_target_t targets[] = {
++    {
++	"gl", "gl", NULL, NULL,
++	CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
++	_cairo_boilerplate_gl_create_surface,
++	NULL, NULL,
++	_cairo_boilerplate_get_image_surface,
++	cairo_surface_write_to_png,
++	_cairo_boilerplate_gl_cleanup,
++	_cairo_boilerplate_gl_synchronize
++    },
++    {
++	"gl", "gl", NULL, NULL,
++	CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR, 1,
++	_cairo_boilerplate_gl_create_surface,
++	NULL, NULL,
++	_cairo_boilerplate_get_image_surface,
++	cairo_surface_write_to_png,
++	_cairo_boilerplate_gl_cleanup,
++	_cairo_boilerplate_gl_synchronize
++    },
++};
++CAIRO_BOILERPLATE (gl, targets)
diff --cc build/Makefile.win32.features
index 4d42c8b,9e72224..a7e5442
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@@ -12,11 -11,11 +12,13 @@@ CAIRO_HAS_WIN32_FONT=
  CAIRO_HAS_OS2_SURFACE=0
  CAIRO_HAS_BEOS_SURFACE=0
  CAIRO_HAS_PNG_FUNCTIONS=1
+ CAIRO_HAS_GL_SURFACE=0
 -CAIRO_HAS_GL_GLX_SURFACE=0
 -CAIRO_HAS_GL_EGL_SURFACE=0
  CAIRO_HAS_GLITZ_SURFACE=0
  CAIRO_HAS_DIRECTFB_SURFACE=0
 +CAIRO_HAS_VG_SURFACE=0
++CAIRO_HAS_EAGLE_FUNCTIONS=0
 +CAIRO_HAS_EGL_FUNCTIONS=0
 +CAIRO_HAS_GLX_FUNCTIONS=0
  CAIRO_HAS_SCRIPT_SURFACE=0
  CAIRO_HAS_FT_FONT=0
  CAIRO_HAS_FC_FONT=0
diff --cc build/Makefile.win32.features-h
index 2dc43bd,57514b4..42a1cf6
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@@ -41,21 -38,21 +41,27 @@@ endi
  ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
  	@echo "#define CAIRO_HAS_PNG_FUNCTIONS 1" >> src/cairo-features.h
  endif
+ ifeq ($(CAIRO_HAS_GL_SURFACE),1)
+ 	@echo "#define CAIRO_HAS_GL_SURFACE 1" >> src/cairo-features.h
+ endif
 -ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
 -	@echo "#define CAIRO_HAS_GL_GLX_SURFACE 1" >> src/cairo-features.h
 -endif
 -ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
 -	@echo "#define CAIRO_HAS_GL_EGL_SURFACE 1" >> src/cairo-features.h
 -endif
  ifeq ($(CAIRO_HAS_GLITZ_SURFACE),1)
  	@echo "#define CAIRO_HAS_GLITZ_SURFACE 1" >> src/cairo-features.h
  endif
  ifeq ($(CAIRO_HAS_DIRECTFB_SURFACE),1)
  	@echo "#define CAIRO_HAS_DIRECTFB_SURFACE 1" >> src/cairo-features.h
  endif
 +ifeq ($(CAIRO_HAS_VG_SURFACE),1)
 +	@echo "#define CAIRO_HAS_VG_SURFACE 1" >> src/cairo-features.h
 +endif
++ifeq ($(CAIRO_HAS_EAGLE_FUNCTIONS),1)
++	@echo "#define CAIRO_HAS_EAGLE_FUNCTIONS 1" >> src/cairo-features.h
++endif
 +ifeq ($(CAIRO_HAS_EGL_FUNCTIONS),1)
 +	@echo "#define CAIRO_HAS_EGL_FUNCTIONS 1" >> src/cairo-features.h
 +endif
 +ifeq ($(CAIRO_HAS_GLX_FUNCTIONS),1)
 +	@echo "#define CAIRO_HAS_GLX_FUNCTIONS 1" >> src/cairo-features.h
 +endif
  ifeq ($(CAIRO_HAS_SCRIPT_SURFACE),1)
  	@echo "#define CAIRO_HAS_SCRIPT_SURFACE 1" >> src/cairo-features.h
  endif
diff --cc build/configure.ac.features
index e2d3262,ce79546..a06496f
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@@ -374,6 -372,7 +374,7 @@@ AC_DEFUN([CAIRO_REPORT]
  	echo "  PostScript:    $use_ps"
  	echo "  PDF:           $use_pdf"
  	echo "  SVG:           $use_svg"
 -	echo "  GL:            $use_gl"
++	echo "  OpenGL:        $use_gl"
  	echo "  glitz:         $use_glitz"
  	echo "  BeOS:          $use_beos"
  	echo "  DirectFB:      $use_directfb"
@@@ -387,9 -388,7 +388,10 @@@
  	echo "  Quartz:        $use_quartz_font"
  	echo ""
  	echo "The following functions:"
--	echo "  PNG functions: $use_png"
- 	echo "  GLX functions: $use_glx"
- 	echo "  EGL functions: $use_egl"
++	echo "  PNG functions:   $use_png"
++	echo "  GLX functions:   $use_glx"
++	echo "  EGL functions:   $use_egl"
++	echo "  Eagle functions: $use_eagle"
  	echo ""
  	echo "And the following internal features:"
  	echo "  gtk-doc:       $enable_gtk_doc"
diff --cc configure.ac
index 2d4d5bb,606fc3a..9b2f77f
--- a/configure.ac
+++ b/configure.ac
@@@ -195,6 -184,48 +195,24 @@@ CAIRO_ENABLE_FUNCTIONS(png, PNG, yes, 
  ])
  
  dnl ===========================================================================
 -CAIRO_ENABLE_SURFACE_BACKEND(gl, gl, no, [
++CAIRO_ENABLE_SURFACE_BACKEND(gl, OpenGL, no, [
+   gl_REQUIRES="gl"
+   PKG_CHECK_MODULES(gl, $gl_REQUIRES, , [AC_MSG_RESULT(no)
+   use_gl="no (requires gl.pc)"])
+ 
+   AC_CHECK_LIB(GLEW, glewInit, [
+     AC_CHECK_HEADER(GL/glew.h, [], [
+       use_gl="no (requires glew http://glew.sourceforge.net/)"
+     ])
+   ], [
+     use_gl="no (requires glew http://glew.sourceforge.net/)"
+   ])
+   gl_NONPKGCONFIG_LIBS="-lGLEW"
 -])
 -
 -CAIRO_ENABLE_SURFACE_BACKEND(gl_glx, GLX, auto, [
 -  if test "x$use_gl" != "xyes"; then
 -    use_gl_glx="no (requires --enable-gl)"
 -  else
 -    gl_glx_BASE=cairo-gl
 -    old_CPPFLAGS=$CPPFLAGS
 -    CPPFLAGS="$CPPFLAGS $gl_CFLAGS $gl_NONPKGCONFIG_CFLAGS"
 -    AC_CHECK_HEADER(GL/glx.h,
 -		    [],
 -		    [use_gl_glx="no (requires GLX)"])
 -    CPPFLAGS=$old_CPPFLAGS
 -  fi
 -])
 -
 -CAIRO_ENABLE_SURFACE_BACKEND(gl_egl, eagle, auto, [
 -  if test "x$use_gl" != "xyes"; then
 -    use_gl_egl="no (requires --enable-gl)"
 -  else
 -    gl_egl_BASE=cairo-gl
 -    gl_egl_REQUIRES="eagle"
 -    PKG_CHECK_MODULES(gl_egl, $gl_egl_REQUIRES, ,
 -		      [AC_MSG_RESULT(no)
 -		       use_gl_egl="no (requires eagle)"])
 -  fi
++  need_glx_functions=yes
++  need_eagle_functions=yes
+ ])
+ 
+ dnl ===========================================================================
  
  GLITZ_MIN_VERSION=0.5.1
  CAIRO_ENABLE_SURFACE_BACKEND(glitz, glitz, no, [
@@@ -242,49 -273,6 +260,60 @@@ CAIRO_ENABLE_SURFACE_BACKEND(directfb, 
  
  dnl ===========================================================================
  
 +CAIRO_ENABLE_SURFACE_BACKEND(vg, OpenVG, no, [
 +  dnl There is no pkgconfig for OpenVG; lets do a header check
 +  AC_CHECK_HEADER(VG/openvg.h,, [use_vg="no (OpenVG headers not found)"])
 +  if test "x$use_vg" = "xyes"; then
 +      vg_NONPKGCONFIG_CFLAGS=
 +      vg_NONPKGCONFIG_LIBS="-lOpenVG"
 +      need_egl_functions=yes
 +      need_glx_functions=yes
 +  fi
 +])
 +
++CAIRO_ENABLE_FUNCTIONS(eagle, eagle, auto, [
++  if test "x$need_eagle_functions" = "xyes"; then
++      eagle_REQUIRES="eagle"
++      PKG_CHECK_MODULES(eagle, $eagle_REQUIRES, ,
++                       [AC_MSG_RESULT(no)
++                       use_eagle="no (requires eagle)"])
++  else
++      use_eagle="no (not required by any backend)"
++  fi
++])
++
 +CAIRO_ENABLE_FUNCTIONS(egl, EGL, auto, [
 +  if test "x$need_egl_functions" = "xyes"; then
 +    AC_CHECK_HEADER(EGL/egl.h,, [use_egl="no (EGL headers not found)"])
 +    if test "x$use_egl" = "xyes"; then
 +      egl_NONPKGCONFIG_CFLAGS=
 +      egl_NONPKGCONFIG_LIBS=
 +      for lib in EGL egl13 egl12 egl11; do
 +	if test -z "$egl_NONPKGCONFIG_LIBS"; then
 +          AC_CHECK_LIB($lib, eglGetError, egl_NONPKGCONFIG_LIBS="-l$lib")
 +	fi
 +      done
 +      if test -z "$egl_NONPKGCONFIG_LIBS"; then
 +        use_egl="no (EGL library not found)"
 +      fi
 +    fi
 +  else
 +      use_egl="no (not required by any backend)"
 +  fi
 +])
 +
 +CAIRO_ENABLE_FUNCTIONS(glx, GLX, auto, [
 +  if test "x$need_glx_functions" = "xyes"; then
 +    AC_CHECK_HEADER(GL/glx.h,, [use_glx="no (GLX headers not found)"])
 +    glx_NONPKGCONFIG_CFLAGS=
 +    glx_NONPKGCONFIG_LIBS="-lGL"
 +  else
 +      use_glx="no (not required by any backend)"
 +  fi
 +])
 +
 +dnl ===========================================================================
 +
  any2ppm_cs=no
  CAIRO_ENABLE_SURFACE_BACKEND(script, script, no, [
    any2ppm_cs=yes
diff --cc src/Makefile.sources
index 6bec91e,d528978..c5c14f7
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@@ -165,6 -164,6 +165,10 @@@ _cairo_font_subset_sources = 
  cairo_private += $(_cairo_font_subset_private)
  cairo_sources += $(_cairo_font_subset_sources)
  
++cairo_glx_sources =
++cairo_egl_sources =
++cairo_eagle_sources =
++
  _cairo_pdf_operators_private = cairo-pdf-operators-private.h
  _cairo_pdf_operators_sources = cairo-pdf-operators.c
  cairo_private += $(_cairo_pdf_operators_private)
@@@ -249,6 -245,12 +253,12 @@@ cairo_os2_sources = cairo-os2-surface.
  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_sources = cairo-gl-surface.c
 -cairo_gl_glx_sources = cairo-glx-context.c
 -cairo_gl_egl_sources = cairo-egl-context.c
++cairo_glx_sources += cairo-glx-context.c
++cairo_eagle_sources += cairo-eagle-context.c
+ 
  cairo_glitz_headers = cairo-glitz.h
  cairo_glitz_private = cairo-glitz-private.h
  cairo_glitz_sources = cairo-glitz-surface.c
diff --cc src/Makefile.win32.features
index 0de7b88,3967de4..61b630c
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@@ -189,6 -175,48 +189,20 @@@ ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1
  enabled_cairo_pkgconf += cairo-png.pc
  endif
  
+ unsupported_cairo_headers += $(cairo_gl_headers)
+ all_cairo_headers += $(cairo_gl_headers)
+ all_cairo_private += $(cairo_gl_private)
+ all_cairo_sources += $(cairo_gl_sources)
+ ifeq ($(CAIRO_HAS_GL_SURFACE),1)
+ enabled_cairo_headers += $(cairo_gl_headers)
+ enabled_cairo_private += $(cairo_gl_private)
+ enabled_cairo_sources += $(cairo_gl_sources)
+ endif
+ all_cairo_pkgconf += cairo-gl.pc
+ ifeq ($(CAIRO_HAS_GL_SURFACE),1)
+ enabled_cairo_pkgconf += cairo-gl.pc
+ endif
+ 
 -supported_cairo_headers += $(cairo_gl_glx_headers)
 -all_cairo_headers += $(cairo_gl_glx_headers)
 -all_cairo_private += $(cairo_gl_glx_private)
 -all_cairo_sources += $(cairo_gl_glx_sources)
 -ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
 -enabled_cairo_headers += $(cairo_gl_glx_headers)
 -enabled_cairo_private += $(cairo_gl_glx_private)
 -enabled_cairo_sources += $(cairo_gl_glx_sources)
 -endif
 -all_cairo_pkgconf += cairo-gl-glx.pc
 -ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
 -enabled_cairo_pkgconf += cairo-gl-glx.pc
 -endif
 -
 -supported_cairo_headers += $(cairo_gl_egl_headers)
 -all_cairo_headers += $(cairo_gl_egl_headers)
 -all_cairo_private += $(cairo_gl_egl_private)
 -all_cairo_sources += $(cairo_gl_egl_sources)
 -ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
 -enabled_cairo_headers += $(cairo_gl_egl_headers)
 -enabled_cairo_private += $(cairo_gl_egl_private)
 -enabled_cairo_sources += $(cairo_gl_egl_sources)
 -endif
 -all_cairo_pkgconf += cairo-gl-egl.pc
 -ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
 -enabled_cairo_pkgconf += cairo-gl-egl.pc
 -endif
 -
  unsupported_cairo_headers += $(cairo_glitz_headers)
  all_cairo_headers += $(cairo_glitz_headers)
  all_cairo_private += $(cairo_glitz_private)
@@@ -217,48 -245,6 +231,62 @@@ ifeq ($(CAIRO_HAS_DIRECTFB_SURFACE),1
  enabled_cairo_pkgconf += cairo-directfb.pc
  endif
  
 +unsupported_cairo_headers += $(cairo_vg_headers)
 +all_cairo_headers += $(cairo_vg_headers)
 +all_cairo_private += $(cairo_vg_private)
 +all_cairo_sources += $(cairo_vg_sources)
 +ifeq ($(CAIRO_HAS_VG_SURFACE),1)
 +enabled_cairo_headers += $(cairo_vg_headers)
 +enabled_cairo_private += $(cairo_vg_private)
 +enabled_cairo_sources += $(cairo_vg_sources)
 +endif
 +all_cairo_pkgconf += cairo-vg.pc
 +ifeq ($(CAIRO_HAS_VG_SURFACE),1)
 +enabled_cairo_pkgconf += cairo-vg.pc
 +endif
 +
++supported_cairo_headers += $(cairo_eagle_headers)
++all_cairo_headers += $(cairo_eagle_headers)
++all_cairo_private += $(cairo_eagle_private)
++all_cairo_sources += $(cairo_eagle_sources)
++ifeq ($(CAIRO_HAS_EAGLE_FUNCTIONS),1)
++enabled_cairo_headers += $(cairo_eagle_headers)
++enabled_cairo_private += $(cairo_eagle_private)
++enabled_cairo_sources += $(cairo_eagle_sources)
++endif
++all_cairo_pkgconf += cairo-eagle.pc
++ifeq ($(CAIRO_HAS_EAGLE_FUNCTIONS),1)
++enabled_cairo_pkgconf += cairo-eagle.pc
++endif
++
 +supported_cairo_headers += $(cairo_egl_headers)
 +all_cairo_headers += $(cairo_egl_headers)
 +all_cairo_private += $(cairo_egl_private)
 +all_cairo_sources += $(cairo_egl_sources)
 +ifeq ($(CAIRO_HAS_EGL_FUNCTIONS),1)
 +enabled_cairo_headers += $(cairo_egl_headers)
 +enabled_cairo_private += $(cairo_egl_private)
 +enabled_cairo_sources += $(cairo_egl_sources)
 +endif
 +all_cairo_pkgconf += cairo-egl.pc
 +ifeq ($(CAIRO_HAS_EGL_FUNCTIONS),1)
 +enabled_cairo_pkgconf += cairo-egl.pc
 +endif
 +
 +supported_cairo_headers += $(cairo_glx_headers)
 +all_cairo_headers += $(cairo_glx_headers)
 +all_cairo_private += $(cairo_glx_private)
 +all_cairo_sources += $(cairo_glx_sources)
 +ifeq ($(CAIRO_HAS_GLX_FUNCTIONS),1)
 +enabled_cairo_headers += $(cairo_glx_headers)
 +enabled_cairo_private += $(cairo_glx_private)
 +enabled_cairo_sources += $(cairo_glx_sources)
 +endif
 +all_cairo_pkgconf += cairo-glx.pc
 +ifeq ($(CAIRO_HAS_GLX_FUNCTIONS),1)
 +enabled_cairo_pkgconf += cairo-glx.pc
 +endif
 +
  unsupported_cairo_headers += $(cairo_script_headers)
  all_cairo_headers += $(cairo_script_headers)
  all_cairo_private += $(cairo_script_private)
diff --cc src/cairo-eagle-context.c
index 0000000,0000000..23766a9
new file mode 100644
--- /dev/null
+++ b/src/cairo-eagle-context.c
@@@ -1,0 -1,0 +1,181 @@@
++/* cairo - a vector graphics library with display and print output
++ *
++ * Copyright © 2009 Eric Anholt
++ * Copyright © 2009 Chris Wilson
++ * Copyright © 2005 Red Hat, Inc
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it either under the terms of the GNU Lesser General Public
++ * License version 2.1 as published by the Free Software Foundation
++ * (the "LGPL") or, at your option, under the terms of the Mozilla
++ * Public License Version 1.1 (the "MPL"). If you do not alter this
++ * notice, a recipient may use your version of this file under either
++ * the MPL or the LGPL.
++ *
++ * You should have received a copy of the LGPL along with this library
++ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ * You should have received a copy of the MPL along with this library
++ * in the file COPYING-MPL-1.1
++ *
++ * The contents of this file are subject to the Mozilla Public License
++ * Version 1.1 (the "License"); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License at
++ * http://www.mozilla.org/MPL/
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
++ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
++ * the specific language governing rights and limitations.
++ *
++ * The Original Code is the cairo graphics library.
++ *
++ * The Initial Developer of the Original Code is Red Hat, Inc.
++ *
++ * Contributor(s):
++ *	Carl Worth <cworth at cworth.org>
++ *	Chris Wilson <chris at chris-wilson.co.uk>
++ */
++
++#include "cairoint.h"
++
++#include "cairo-gl-private.h"
++
++#include <i915_drm.h> /* XXX dummy surface for glewInit() */
++#include <sys/ioctl.h>
++
++typedef struct _cairo_eagle_context {
++    cairo_gl_context_t base;
++
++    EGLDisplay display;
++    EGLContext context;
++} cairo_eagle_context_t;
++
++typedef struct _cairo_eagle_surface {
++    cairo_gl_surface_t base;
++
++    EGLSurface eagle;
++} cairo_eagle_surface_t;
++
++static void
++_eagle_make_current (void *abstract_ctx,
++	           cairo_gl_surface_t *abstract_surface)
++{
++    cairo_eagle_context_t *ctx = abstract_ctx;
++    cairo_eagle_surface_t *surface = (cairo_eagle_surface_t *) abstract_surface;
++
++    eagleMakeCurrent (ctx->display, surface->eagle, surface->eagle, ctx->context);
++}
++
++static void
++_eagle_swap_buffers (void *abstract_ctx,
++		   cairo_gl_surface_t *abstract_surface)
++{
++    cairo_eagle_context_t *ctx = abstract_ctx;
++    cairo_eagle_surface_t *surface = (cairo_eagle_surface_t *) abstract_surface;
++
++    eagleSwapBuffers (ctx->display, surface->eagle);
++}
++
++static void
++_eagle_destroy (void *abstract_ctx)
++{
++}
++
++static cairo_bool_t
++_eagle_init (EGLDisplay display, EGLContext context)
++{
++    const EGLint config_attribs[] = {
++	EGL_CONFIG_CAVEAT, EGL_NONE,
++	EGL_NONE
++    };
++    const EGLint surface_attribs[] = {
++	EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
++	EGL_NONE
++    };
++    EGLConfig config;
++    EGLSurface dummy;
++    struct drm_i915_gem_create create;
++    struct drm_gem_flink flink;
++    int fd;
++    GLenum err;
++
++    if (! eagleChooseConfig (display, config_attribs, &config, 1, NULL)) {
++	fprintf (stderr, "Unable to choose config\n");
++	return FALSE;
++    }
++
++    /* XXX */
++    fd = eagleGetDisplayFD (display);
++
++    create.size = 4096;
++    if (ioctl (fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
++	fprintf (stderr, "gem create failed: %m\n");
++	return FALSE;
++    }
++    flink.handle = create.handle;
++    if (ioctl (fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
++	fprintf (stderr, "gem flink failed: %m\n");
++	return FALSE;
++    }
++
++    dummy = eagleCreateSurfaceForName (display, config, flink.name,
++				     1, 1, 4, surface_attribs);
++    if (dummy == NULL) {
++	fprintf (stderr, "Failed to create dummy surface\n");
++	return FALSE;
++    }
++
++    eagleMakeCurrent (display, dummy, dummy, context);
++}
++
++cairo_gl_context_t *
++cairo_eagle_context_create (EGLDisplay display, EGLContext context)
++{
++    cairo_eagle_context_t *ctx;
++    cairo_status_t status;
++
++    if (! _eagle_init (display, context)) {
++	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
++    }
++
++    ctx = calloc (1, sizeof (cairo_eagle_context_t));
++    if (ctx == NULL)
++	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
++
++    ctx->display = display;
++    ctx->context = context;
++
++    ctx->base.make_current = _eagle_make_current;
++    ctx->base.swap_buffers = _eagle_swap_buffers;
++    ctx->base.destroy = _eagle_destroy;
++
++    status = _cairo_gl_context_init (&ctx->base);
++    if (status) {
++	free (ctx);
++	return _cairo_gl_context_create_in_error (status);
++    }
++
++    return &ctx->base;
++}
++
++cairo_surface_t *
++cairo_gl_surface_create_for_eagle (cairo_gl_context_t   *ctx,
++				   EGLSurface            eagle,
++				   int                   width,
++				   int                   height)
++{
++    cairo_eagle_surface_t *surface;
++
++    if (ctx->status)
++	return _cairo_surface_create_in_error (ctx->status);
++
++    surface = calloc (1, sizeof (cairo_eagle_surface_t));
++    if (unlikely (surface == NULL))
++	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
++
++    _cairo_gl_surface_init (ctx, &surface->base,
++			    CAIRO_CONTENT_COLOR_ALPHA, width, height);
++    surface->eagle = eagle;
++
++    return &surface->base.base;
++}
diff --cc src/cairo-gl-surface.c
index 0000000,a3e0c06..d54c0a2
mode 000000,100644..100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@@ -1,0 -1,1568 +1,1569 @@@
+ /* cairo - a vector graphics library with display and print output
+  *
+  * Copyright © 2009 Eric Anholt
+  * Copyright © 2009 Chris Wilson
+  * Copyright © 2005 Red Hat, Inc
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it either under the terms of the GNU Lesser General Public
+  * License version 2.1 as published by the Free Software Foundation
+  * (the "LGPL") or, at your option, under the terms of the Mozilla
+  * Public License Version 1.1 (the "MPL"). If you do not alter this
+  * notice, a recipient may use your version of this file under either
+  * the MPL or the LGPL.
+  *
+  * You should have received a copy of the LGPL along with this library
+  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+  * You should have received a copy of the MPL along with this library
+  * in the file COPYING-MPL-1.1
+  *
+  * The contents of this file are subject to the Mozilla Public License
+  * Version 1.1 (the "License"); you may not use this file except in
+  * compliance with the License. You may obtain a copy of the License at
+  * http://www.mozilla.org/MPL/
+  *
+  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+  * the specific language governing rights and limitations.
+  *
+  * The Original Code is the cairo graphics library.
+  *
+  * The Initial Developer of the Original Code is Red Hat, Inc.
+  *
+  * Contributor(s):
+  *	Carl Worth <cworth at cworth.org>
+  */
+ 
+ #include "cairoint.h"
+ 
+ #include "cairo-gl-private.h"
+ 
+ slim_hidden_proto (cairo_gl_context_reference);
+ slim_hidden_proto (cairo_gl_context_destroy);
+ slim_hidden_proto (cairo_gl_surface_create);
+ 
+ #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+ 
+ enum cairo_gl_composite_operand_type {
+     OPERAND_CONSTANT,
+     OPERAND_TEXTURE,
+ };
+ 
+ /* This union structure describes a potential source or mask operand to the
+  * compositing equation.
+  */
+ typedef struct cairo_gl_composite_operand {
+     enum cairo_gl_composite_operand_type type;
+     union {
+ 	struct {
+ 	    GLuint tex;
+ 	    cairo_gl_surface_t *surface;
+ 	    cairo_surface_attributes_t attributes;
+ 	    cairo_bool_t has_alpha;
+ 	} texture;
+ 	struct {
+ 	    GLfloat color[4];
+ 	} constant;
+     } operand;
+ 
+     const cairo_pattern_t *pattern;
+ } cairo_gl_composite_operand_t;
+ 
+ typedef struct _cairo_gl_composite_setup {
+     cairo_gl_composite_operand_t src;
+     cairo_gl_composite_operand_t mask;
+ } cairo_gl_composite_setup_t;
+ 
+ static const cairo_surface_backend_t _cairo_gl_surface_backend;
+ 
+ static const cairo_gl_context_t _nil_context = {
+     CAIRO_REFERENCE_COUNT_INVALID,
+     CAIRO_STATUS_NO_MEMORY
+ };
+ 
+ static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
+ {
+     return surface->backend == &_cairo_gl_surface_backend;
+ }
+ 
+ cairo_gl_context_t *
+ _cairo_gl_context_create_in_error (cairo_status_t status)
+ {
+     if (status == CAIRO_STATUS_NO_MEMORY)
+ 	return (cairo_gl_context_t *) &_nil_context;
+ 
+     ASSERT_NOT_REACHED;
+     return NULL;
+ }
+ 
+ cairo_status_t
+ _cairo_gl_context_init (cairo_gl_context_t *ctx)
+ {
+     ctx->status = CAIRO_STATUS_SUCCESS;
+     CAIRO_REFERENCE_COUNT_INIT (&ctx->ref_count, 1);
+     CAIRO_MUTEX_INIT (ctx->mutex);
+ 
+     if (glewInit () != GLEW_OK) {
+ 	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
+     }
+ 
+     if (! GLEW_EXT_framebuffer_object ||
+ 	! GLEW_ARB_texture_env_combine ||
+ 	! GLEW_ARB_texture_non_power_of_two)
+     {
+ 	fprintf (stderr,
+ 		 "Required GL extensions not available:\n");
+ 	if (! GLEW_EXT_framebuffer_object)
+ 	    fprintf (stderr, "    GL_EXT_framebuffer_object\n");
+ 	if (! GLEW_ARB_texture_env_combine)
+ 	    fprintf (stderr, "    GL_ARB_texture_env_combine\n");
+ 	if (! GLEW_ARB_texture_non_power_of_two)
+ 	    fprintf (stderr, "    GL_ARB_texture_non_power_of_two\n");
+ 
+ 	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
+     }
+ 
+     /* Set up the dummy texture for tex_env_combine with constant color. */
+     glGenTextures (1, &ctx->dummy_tex);
+     glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex);
+     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
+ 		  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ cairo_gl_context_t *
+ cairo_gl_context_reference (cairo_gl_context_t *context)
+ {
+     if (context == NULL ||
+ 	CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count))
+     {
+ 	return context;
+     }
+ 
+     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
+     _cairo_reference_count_inc (&context->ref_count);
+ 
+     return context;
+ }
+ slim_hidden_def (cairo_gl_context_reference);
+ 
+ void
+ cairo_gl_context_destroy (cairo_gl_context_t *context)
+ {
+     if (context == NULL ||
+ 	CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count))
+     {
+ 	return;
+     }
+ 
+     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
+     if (! _cairo_reference_count_dec_and_test (&context->ref_count))
+ 	return;
+ 
+     glDeleteTextures (1, &context->dummy_tex);
+ 
+     context->destroy (context);
+ 
+     free (context);
+ }
+ slim_hidden_def (cairo_gl_context_destroy);
+ 
+ static cairo_gl_context_t *
+ _cairo_gl_context_acquire (cairo_gl_context_t *ctx)
+ {
+     CAIRO_MUTEX_LOCK (ctx->mutex);
+     return ctx;
+ }
+ 
+ static cairo_status_t
+ _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
+ 				     GLenum *internal_format, GLenum *format,
+ 				     GLenum *type, cairo_bool_t *has_alpha)
+ {
+     *has_alpha = TRUE;
+ 
+     switch (pixman_format) {
+     case PIXMAN_a8r8g8b8:
+ 	*internal_format = GL_RGBA;
+ 	*format = GL_BGRA;
+ 	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_x8r8g8b8:
+ 	*internal_format = GL_RGB;
+ 	*format = GL_BGRA;
+ 	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ 	*has_alpha = FALSE;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_a8b8g8r8:
+ 	*internal_format = GL_RGBA;
+ 	*format = GL_RGBA;
+ 	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_x8b8g8r8:
+ 	*internal_format = GL_RGB;
+ 	*format = GL_RGBA;
+ 	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ 	*has_alpha = FALSE;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_b8g8r8a8:
+ 	*internal_format = GL_BGRA;
+ 	*format = GL_BGRA;
+ 	*type = GL_UNSIGNED_INT_8_8_8_8;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_b8g8r8x8:
+ 	*internal_format = GL_RGB;
+ 	*format = GL_BGRA;
+ 	*type = GL_UNSIGNED_INT_8_8_8_8;
+ 	*has_alpha = FALSE;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_r8g8b8:
+ 	*internal_format = GL_RGB;
+ 	*format = GL_RGB;
+ 	*type = GL_UNSIGNED_BYTE;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_b8g8r8:
+ 	*internal_format = GL_RGB;
+ 	*format = GL_BGR;
+ 	*type = GL_UNSIGNED_BYTE;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_r5g6b5:
+ 	*internal_format = GL_RGB;
+ 	*format = GL_RGB;
+ 	*type = GL_UNSIGNED_SHORT_5_6_5;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_b5g6r5:
+ 	*internal_format = GL_RGB;
+ 	*format = GL_RGB;
+ 	*type = GL_UNSIGNED_SHORT_5_6_5_REV;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_a1r5g5b5:
+ 	*internal_format = GL_RGBA;
+ 	*format = GL_BGRA;
+ 	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_x1r5g5b5:
+ 	*internal_format = GL_RGB;
+ 	*format = GL_BGRA;
+ 	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ 	*has_alpha = FALSE;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_a1b5g5r5:
+ 	*internal_format = GL_RGBA;
+ 	*format = GL_RGBA;
+ 	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_x1b5g5r5:
+ 	*internal_format = GL_RGB;
+ 	*format = GL_RGBA;
+ 	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ 	*has_alpha = FALSE;
+ 	return CAIRO_STATUS_SUCCESS;
+     case PIXMAN_a8:
+ 	*internal_format = GL_ALPHA;
+ 	*format = GL_ALPHA;
+ 	*type = GL_UNSIGNED_BYTE;
+ 	return CAIRO_STATUS_SUCCESS;
+ 
+     case PIXMAN_a2b10g10r10:
+     case PIXMAN_x2b10g10r10:
+     case PIXMAN_a4r4g4b4:
+     case PIXMAN_x4r4g4b4:
+     case PIXMAN_a4b4g4r4:
+     case PIXMAN_x4b4g4r4:
+     case PIXMAN_r3g3b2:
+     case PIXMAN_b2g3r3:
+     case PIXMAN_a2r2g2b2:
+     case PIXMAN_a2b2g2r2:
+     case PIXMAN_c8:
+     case PIXMAN_x4a4:
+     /* case PIXMAN_x4c4: */
+     case PIXMAN_x4g4:
+     case PIXMAN_a4:
+     case PIXMAN_r1g2b1:
+     case PIXMAN_b1g2r1:
+     case PIXMAN_a1r1g1b1:
+     case PIXMAN_a1b1g1r1:
+     case PIXMAN_c4:
+     case PIXMAN_g4:
+     case PIXMAN_a1:
+     case PIXMAN_g1:
+     case PIXMAN_yuy2:
+     case PIXMAN_yv12:
+     default:
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+     }
+ }
+ 
+ static void
+ _cairo_gl_context_release (cairo_gl_context_t *ctx)
+ {
+     CAIRO_MUTEX_UNLOCK (ctx->mutex);
+ }
+ 
+ static void
+ _cairo_gl_set_destination (cairo_gl_surface_t *surface)
+ {
+     cairo_gl_context_t *ctx = surface->ctx;
+ 
+     if (ctx->current_target != surface) {
+ 	ctx->current_target = surface;
+ 
+ 	if (surface->fb) {
+ 	    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);
+ 
+     glMatrixMode (GL_PROJECTION);
+     glLoadIdentity();
+     if (surface->fb)
+ 	glOrtho(0, surface->width, 0, surface->height, -1.0, 1.0);
+     else
+ 	glOrtho(0, surface->width, surface->height, 0, -1.0, 1.0);
+ 
+     glMatrixMode (GL_MODELVIEW);
+     glLoadIdentity();
+ }
+ 
+ static int
+ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op)
+ {
+     struct {
+ 	GLenum src;
+ 	GLenum dst;
+     } blend_factors[] = {
+ 	{ GL_ZERO, GL_ZERO }, /* Clear */
+ 	{ GL_ONE, GL_ZERO }, /* Source */
+ 	{ GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */
+ 	{ GL_DST_ALPHA, GL_ZERO }, /* In */
+ 	{ GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */
+ 	{ GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */
+ 
+ 	{ GL_ZERO, GL_ONE }, /* Dest */
+ 	{ GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */
+ 	{ GL_ZERO, GL_SRC_ALPHA }, /* DestIn */
+ 	{ GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */
+ 	{ GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */
+ 
+ 	{ GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
+ 	{ GL_ONE, GL_ONE }, /* Add */
+     };
+     GLenum src_factor, dst_factor;
+ 
+     if (op >= ARRAY_SIZE (blend_factors))
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+ 
+     src_factor = blend_factors[op].src;
+     dst_factor = blend_factors[op].dst;
+ 
+     /* We may have a visual with alpha bits despite the user requesting
+      * CAIRO_CONTENT_COLOR.  So clear out those bits in that case.
+      */
+     if (dst->base.content == CAIRO_CONTENT_COLOR) {
+ 	if (src_factor == GL_ONE_MINUS_DST_ALPHA)
+ 	    src_factor = GL_ZERO;
+ 	if (src_factor == GL_DST_ALPHA)
+ 	    src_factor = GL_ONE;
+     }
+ 
+     glBlendFunc (src_factor, dst_factor);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static void
+ _cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
+ 			       cairo_surface_attributes_t *attributes)
+ {
+     glActiveTexture (GL_TEXTURE0 + tex_unit);
+     glBindTexture (GL_TEXTURE_2D, tex);
+     switch (attributes->extend) {
+     case CAIRO_EXTEND_NONE:
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ 	break;
+     case CAIRO_EXTEND_PAD:
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ 	break;
+     case CAIRO_EXTEND_REPEAT:
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ 	break;
+     case CAIRO_EXTEND_REFLECT:
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+ 	break;
+     }
+     switch (attributes->filter) {
+     case CAIRO_FILTER_FAST:
+     case CAIRO_FILTER_NEAREST:
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ 	break;
+     case CAIRO_FILTER_GOOD:
+     case CAIRO_FILTER_BEST:
+     case CAIRO_FILTER_BILINEAR:
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ 	break;
+     default:
+     case CAIRO_FILTER_GAUSSIAN:
+ 	ASSERT_NOT_REACHED;
+     }
+     glEnable (GL_TEXTURE_2D);
+ }
+ 
+ void
+ _cairo_gl_surface_init (cairo_gl_context_t *ctx,
+ 			cairo_gl_surface_t *surface,
+ 			cairo_content_t content,
+ 			int width, int height)
+ {
+     _cairo_surface_init (&surface->base,
+ 			 &_cairo_gl_surface_backend,
+ 			 content);
+ 
+     surface->ctx = cairo_gl_context_reference (ctx);
+     surface->width = width;
+     surface->height = height;
+ }
+ 
+ cairo_surface_t *
+ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
+ 			 cairo_content_t	content,
+ 			 int			width,
+ 			 int			height)
+ {
+     cairo_gl_surface_t *surface;
+     GLenum err, format;
+     cairo_status_t status;
+ 
+     if (!CAIRO_CONTENT_VALID (content))
+ 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
+ 
+     if (ctx == NULL) {
+ 	return cairo_image_surface_create (_cairo_format_from_content (content),
+ 					   width, height);
+     }
+     if (ctx->status)
+ 	return _cairo_surface_create_in_error (ctx->status);
+ 
+     surface = calloc (1, sizeof (cairo_gl_surface_t));
+     if (unlikely (surface == NULL))
+ 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ 
+     _cairo_gl_surface_init (ctx, surface, content, width, height);
+ 
+     switch (content) {
+     default:
+ 	ASSERT_NOT_REACHED;
+     case CAIRO_CONTENT_COLOR_ALPHA:
+ 	format = GL_RGBA;
+ 	break;
+     case CAIRO_CONTENT_ALPHA:
+ 	format = GL_RGBA;
+ 	break;
+     case CAIRO_CONTENT_COLOR:
+ 	format = GL_RGB;
+ 	break;
+     }
+ 
+     /* Create the texture used to store the surface's data. */
+     glGenTextures (1, &surface->tex);
+     glBindTexture (GL_TEXTURE_2D, surface->tex);
+     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+     glTexImage2D (GL_TEXTURE_2D, 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,
+ 			       GL_TEXTURE_2D,
+ 			       surface->tex,
+ 			       0);
+ 
+     while ((err = glGetError ())) {
+ 	fprintf(stderr, "GL error in surface create: 0x%08x\n", err);
+     }
+ 
+     status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
+     if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ 	fprintf(stderr, "destination is framebuffer incomplete\n");
+ 
+     /* Cairo surfaces start out initialized to transparent (black) */
+     ctx = _cairo_gl_context_acquire (surface->ctx);
+     _cairo_gl_set_destination (surface);
+     glClearColor (0.0, 0.0, 0.0, 0.0);
+     glClear (GL_COLOR_BUFFER_BIT);
+     _cairo_gl_context_release (ctx);
+ 
+     return &surface->base;
+ }
+ slim_hidden_def (cairo_gl_surface_create);
+ 
+ void
+ cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
+ 			   int              width,
+ 			   int              height)
+ {
+     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+     cairo_status_t status;
+ 
+     if (! _cairo_surface_is_gl (abstract_surface) || surface->fb) {
+ 	status = _cairo_surface_set_error (abstract_surface,
+ 		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ 	return;
+     }
+ 
+     surface->width = width;
+     surface->height = height;
+ }
+ 
+ int
+ cairo_gl_surface_get_width (cairo_surface_t *abstract_surface)
+ {
+     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+ 
+     if (! _cairo_surface_is_gl (abstract_surface))
+ 	return 0;
+ 
+     return surface->width;
+ }
+ 
+ int
+ cairo_gl_surface_get_height (cairo_surface_t *abstract_surface)
+ {
+     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+ 
+     if (! _cairo_surface_is_gl (abstract_surface))
+ 	return 0;
+ 
+     return surface->height;
+ }
+ 
+ 
+ void
+ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
+ {
+     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+     cairo_status_t status;
+ 
+     if (! _cairo_surface_is_gl (abstract_surface)) {
+ 	status = _cairo_surface_set_error (abstract_surface,
+ 		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ 	return;
+     }
+ 
+     if (! surface->fb)
+ 	surface->ctx->swap_buffers (surface->ctx, surface);
+ }
+ 
+ static cairo_surface_t *
+ _cairo_gl_surface_create_similar (void		 *abstract_surface,
+ 				  cairo_content_t  content,
+ 				  int		  width,
+ 				  int		  height)
+ {
+     cairo_gl_surface_t *surface = abstract_surface;
+ 
+     assert (CAIRO_CONTENT_VALID (content));
+ 
+     if (width < 1)
+ 	width = 1;
+     if (height < 1)
+ 	height = 1;
+ 
+     return cairo_gl_surface_create (surface->ctx, content, width, height);
+ }
+ 
+ static cairo_status_t
+ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
+ 			      cairo_image_surface_t *src,
+ 			      int src_x, int src_y,
+ 			      int width, int height,
+ 			      int dst_x, int dst_y)
+ {
+     char *temp_data;
+     int y;
+     unsigned int cpp = PIXMAN_FORMAT_BPP(src->pixman_format) / 8;
+     GLenum internal_format, format, type;
+     char *src_data_start;
+     cairo_bool_t has_alpha;
+     cairo_status_t status;
+ 
+     status = _cairo_gl_get_image_format_and_type (src->pixman_format,
+ 						  &internal_format,
+ 						  &format,
+ 						  &type,
+ 						  &has_alpha);
+     if (status != CAIRO_STATUS_SUCCESS)
+ 	return status;
+ 
+     /* Write the data to a temporary as GL wants bottom-to-top data
+      * screen-wise, and we want top-to-bottom.
+      */
+     temp_data = malloc (width * height * cpp);
+     if (temp_data == NULL)
+ 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ 
+     src_data_start = (char *)src->data + (src_y * src->stride) + (src_x * cpp);
+     for (y = 0; y < height; y++) {
+ 	memcpy (temp_data + y * width * cpp, src_data_start +
+ 		y * src->stride,
+ 		width * cpp);
+     }
+ 
+     _cairo_gl_set_destination (dst);
+     glRasterPos2i (dst_x, dst_y);
+     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+     glDrawPixels (width, height, format, type, temp_data);
+ 
+     free (temp_data);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_status_t
+ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
+ 			     cairo_rectangle_int_t   *interest,
+ 			     cairo_image_surface_t  **image_out,
+ 			     cairo_rectangle_int_t   *rect_out)
+ {
+     cairo_image_surface_t *image;
+     cairo_rectangle_int_t extents;
+     GLenum err;
+     char *temp_data;
+     int y;
+     unsigned int cpp;
+     GLenum format, type;
+     cairo_format_t cairo_format;
+ 
+     extents.x = 0;
+     extents.y = 0;
+     extents.width  = surface->width;
+     extents.height = surface->height;
+ 
+     if (interest != NULL) {
+ 	if (! _cairo_rectangle_intersect (&extents, interest)) {
+ 	    *image_out = NULL;
+ 	    return CAIRO_STATUS_SUCCESS;
+ 	}
+     }
+ 
+     if (rect_out != NULL)
+ 	*rect_out = extents;
+ 
+     /* Want to use a switch statement here but the compiler gets whiny. */
+     if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
+ 	format = GL_BGRA;
+ 	cairo_format = CAIRO_FORMAT_ARGB32;
+ 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ 	cpp = 4;
+     } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
+ 	format = GL_BGRA;
+ 	cairo_format = CAIRO_FORMAT_RGB24;
+ 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ 	cpp = 4;
+     } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
+ 	format = GL_ALPHA;
+ 	cairo_format = CAIRO_FORMAT_A8;
+ 	type = GL_UNSIGNED_BYTE;
+ 	cpp = 1;
+     } else {
+ 	fprintf(stderr, "get_image fallback: %d\n", surface->base.content);
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+     }
+ 
+     image = (cairo_image_surface_t*)
+ 	cairo_image_surface_create (cairo_format,
+ 				    extents.width, extents.height);
+     if (image->base.status)
+ 	return image->base.status;
+ 
+     /* This is inefficient, as we'd rather just read the thing without making
+      * it the destination.  But then, this is the fallback path, so let's not
+      * fall back instead.
+      */
+     _cairo_gl_set_destination(surface);
+ 
+     /* Read the data to a temporary as GL gives us bottom-to-top data
+      * screen-wise, and we want top-to-bottom.
+      */
+     temp_data = malloc (extents.width * extents.height * cpp);
+     if (temp_data == NULL)
+ 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ 
+     glPixelStorei(GL_PACK_ALIGNMENT, 1);
+     glReadPixels(extents.x, extents.y,
+ 		 extents.width, extents.height,
+ 		 format, type, temp_data);
+ 
+     for (y = 0; y < extents.height; y++) {
+ 	memcpy ((char *)image->data + y * image->stride,
+ 		temp_data + y * extents.width * cpp,
+ 		extents.width * cpp);
+     }
+     free (temp_data);
+ 
+     *image_out = image;
+ 
+     while ((err = glGetError ()))
+ 	fprintf(stderr, "GL error 0x%08x\n", (int) err);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_status_t
+ _cairo_gl_surface_finish (void *abstract_surface)
+ {
+     cairo_gl_surface_t *surface = abstract_surface;
+ 
+     glDeleteFramebuffersEXT (1, &surface->fb);
+     glDeleteTextures (1, &surface->tex);
+ 
+     if (surface->ctx->current_target == surface)
+ 	surface->ctx->current_target = NULL;
+ 
+     cairo_gl_context_destroy(surface->ctx);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_status_t
+ _cairo_gl_surface_acquire_source_image (void		       *abstract_surface,
+ 					cairo_image_surface_t **image_out,
+ 					void		      **image_extra)
+ {
+     cairo_gl_surface_t *surface = abstract_surface;
+ 
+     *image_extra = NULL;
+ 
+     return _cairo_gl_surface_get_image (surface, NULL, image_out, NULL);
+ }
+ 
+ static void
+ _cairo_gl_surface_release_source_image (void		      *abstract_surface,
+ 					cairo_image_surface_t *image,
+ 					void		      *image_extra)
+ {
+     cairo_surface_destroy (&image->base);
+ }
+ 
+ static cairo_status_t
+ _cairo_gl_surface_acquire_dest_image (void		      *abstract_surface,
+ 				      cairo_rectangle_int_t   *interest_rect,
+ 				      cairo_image_surface_t  **image_out,
+ 				      cairo_rectangle_int_t   *image_rect_out,
+ 				      void		     **image_extra)
+ {
+     cairo_gl_surface_t *surface = abstract_surface;
+ 
+     *image_extra = NULL;
+     return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
+ 					image_rect_out);
+ }
+ 
+ static void
+ _cairo_gl_surface_release_dest_image (void		      *abstract_surface,
+ 				      cairo_rectangle_int_t   *interest_rect,
+ 				      cairo_image_surface_t   *image,
+ 				      cairo_rectangle_int_t   *image_rect,
+ 				      void		      *image_extra)
+ {
+     cairo_status_t status;
+ 
+     status = _cairo_gl_surface_draw_image (abstract_surface, image,
+ 					   0, 0,
+ 					   image->width, image->height,
+ 					   image_rect->x, image_rect->y);
+     if (status)
+ 	status = _cairo_surface_set_error (abstract_surface, status);
+ 
+     cairo_surface_destroy (&image->base);
+ }
+ 
+ static cairo_status_t
+ _cairo_gl_surface_clone_similar (void		     *abstract_surface,
+ 				 cairo_surface_t     *src,
+ 				 cairo_content_t      content,
+ 				 int                  src_x,
+ 				 int                  src_y,
+ 				 int                  width,
+ 				 int                  height,
+ 				 int                 *clone_offset_x,
+ 				 int                 *clone_offset_y,
+ 				 cairo_surface_t    **clone_out)
+ {
+     cairo_gl_surface_t *surface = abstract_surface;
+ 
+     if (src->backend == surface->base.backend) {
+ 	*clone_offset_x = 0;
+ 	*clone_offset_y = 0;
+ 	*clone_out = cairo_surface_reference (src);
+ 
+ 	return CAIRO_STATUS_SUCCESS;
+     } else if (_cairo_surface_is_image (src)) {
+ 	cairo_gl_surface_t *clone;
+ 	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
+ 	cairo_status_t status;
+ 	GLenum internal_format, format, type;
+ 	cairo_bool_t has_alpha;
+ 
+ 	status = _cairo_gl_get_image_format_and_type (image_src->pixman_format,
+ 						      &internal_format,
+ 						      &format,
+ 						      &type,
+ 						      &has_alpha);
+ 	if (status != CAIRO_STATUS_SUCCESS)
+ 	    return status;
+ 
+ 	clone = (cairo_gl_surface_t *)
+ 	    _cairo_gl_surface_create_similar (&surface->base,
+ 		                              content,
+ 					      width, height);
+ 	if (clone == NULL)
+ 	    return CAIRO_INT_STATUS_UNSUPPORTED;
+ 	if (clone->base.status)
+ 	    return clone->base.status;
+ 
+ 	status = _cairo_gl_surface_draw_image (clone, image_src,
+ 					       src_x, src_y,
+ 					       width, height,
+ 					       0, 0);
+ 	if (status) {
+ 	    cairo_surface_destroy (&clone->base);
+ 	    return status;
+ 	}
+ 
+ 	*clone_out = &clone->base;
+ 	*clone_offset_x = src_x;
+ 	*clone_offset_y = src_y;
+ 
+ 	return CAIRO_STATUS_SUCCESS;
+     }
+ 
+     return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ 
+ /** Creates a cairo-gl pattern surface for the given trapezoids */
+ static cairo_status_t
+ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
+ 			     int dst_x, int dst_y,
+ 			     int width, int height,
+ 			     cairo_trapezoid_t *traps,
+ 			     int num_traps,
+ 			     cairo_antialias_t antialias,
+ 			     cairo_pattern_t **pattern)
+ {
+     pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
+     pixman_trapezoid_t *pixman_traps;
+     cairo_image_surface_t *image_surface;
+     int i;
+ 
+     /* Convert traps to pixman traps */
+     pixman_traps = stack_traps;
+     if (num_traps > ARRAY_LENGTH (stack_traps)) {
+ 	pixman_traps = _cairo_malloc_ab (num_traps, sizeof (pixman_trapezoid_t));
+ 	if (unlikely (pixman_traps == NULL))
+ 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+     }
+ 
+     for (i = 0; i < num_traps; i++) {
+ 	pixman_traps[i].top = _cairo_fixed_to_16_16 (traps[i].top);
+ 	pixman_traps[i].bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
+ 	pixman_traps[i].left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
+ 	pixman_traps[i].left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
+ 	pixman_traps[i].left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
+ 	pixman_traps[i].left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
+ 	pixman_traps[i].right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
+ 	pixman_traps[i].right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
+ 	pixman_traps[i].right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
+ 	pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
+     }
+ 
+     if (antialias != CAIRO_ANTIALIAS_NONE) {
+ 	image_surface = (cairo_image_surface_t*)
+ 	    cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
+     } else {
+ 	image_surface = (cairo_image_surface_t*)
+ 	    cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
+     }
+ 
+     if (image_surface->base.status) {
+ 	if (pixman_traps != stack_traps)
+ 	    free (pixman_traps);
+ 	return image_surface->base.status;
+     }
+ 
+     pixman_add_trapezoids (image_surface->pixman_image, -dst_x, -dst_y,
+ 			   num_traps, pixman_traps);
+ 
+     if (pixman_traps != stack_traps)
+ 	free (pixman_traps);
+ 
+     *pattern = cairo_pattern_create_for_surface (&image_surface->base);
+     cairo_surface_destroy (&image_surface->base);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_status_t
+ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
+ 				       const cairo_pattern_t *src,
+ 				       cairo_gl_surface_t *dst,
+ 				       int src_x, int src_y,
+ 				       int dst_x, int dst_y,
+ 				       int width, int height)
+ {
+     cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src;
+     cairo_image_surface_t *image_surface;
+     cairo_matrix_t m;
+     cairo_surface_attributes_t *attributes;
+     GLuint tex;
+     GLenum format, internal_format, type;
+     cairo_status_t status;
+ 
+     if (src->type != CAIRO_PATTERN_TYPE_SURFACE)
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+ 
+     if (!_cairo_surface_is_image (surface_pattern->surface))
+ 	return CAIRO_INT_STATUS_UNSUPPORTED;
+ 
+     image_surface = (cairo_image_surface_t *)surface_pattern->surface;
+ 
+     /* The textures we create almost always has appropriate alpha channel
+      * contents.  But sometimes GL sucks at image specification and we end up
+      * with junk in the alpha.
+      */
+     operand->operand.texture.has_alpha = TRUE;
+ 
+     status = _cairo_gl_get_image_format_and_type (image_surface->pixman_format,
+ 						  &internal_format, &format,
+ 						  &type,
+ 						  &operand->operand.texture.has_alpha);
+     if (status)
+ 	return status;
+ 
+     glGenTextures (1, &tex);
+     glBindTexture (GL_TEXTURE_2D, tex);
+     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+     assert(((image_surface->stride * image_surface->depth) %
+ 	    image_surface->depth) == 0);
+     glPixelStorei (GL_UNPACK_ROW_LENGTH,
+ 		   image_surface->stride /
+ 		   (PIXMAN_FORMAT_BPP(image_surface->pixman_format) / 8));
+     /* The filter will be correctly set up later, but for now we want to
+      * hint to glTexImage that we're not mipmapping.
+      */
+     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+     glTexImage2D (GL_TEXTURE_2D, 0, internal_format,
+ 		  image_surface->width, image_surface->height, 0,
+ 		  format, type, image_surface->data);
+     glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+ 
+     attributes = &operand->operand.texture.attributes;
+ 
+     operand->type = OPERAND_TEXTURE;
+     operand->operand.texture.tex = tex;
+     operand->operand.texture.surface = NULL;
+     attributes->matrix = src->matrix;
+     attributes->extend = src->extend;
+     attributes->filter = src->filter;
+     /* Demote the filter if we're doing a 1:1 mapping of pixels. */
+     if ((src->filter == CAIRO_FILTER_GOOD ||
+ 	 src->filter == CAIRO_FILTER_BEST ||
+ 	 src->filter == CAIRO_FILTER_BILINEAR) &&
+ 	_cairo_matrix_is_pixel_exact (&src->matrix)) {
+ 	attributes->filter = CAIRO_FILTER_NEAREST;
+     }
+ 
+     attributes->x_offset = 0;
+     attributes->y_offset = 0;
+ 
+ 
+     /* Set up translation matrix for
+      * (unnormalized dst -> unnormalized src)
+      */
+     cairo_matrix_init_translate (&m,
+ 				 src_x - dst_x,
+ 				 src_y - dst_y);
+     cairo_matrix_multiply(&attributes->matrix,
+ 			  &m,
+ 			  &attributes->matrix);
+ 
+     /* Translate the matrix from
+      * (unnormalized src -> unnormalized src) to
+      * (unnormalized dst -> normalized src)
+      */
+     cairo_matrix_init_scale (&m,
+ 			     1.0 / image_surface->width,
+ 			     1.0 / image_surface->height);
+     cairo_matrix_multiply (&attributes->matrix,
+ 			   &attributes->matrix,
+ 			   &m);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ /**
+  * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
+  * from dest to src coords.
+  */
+ static cairo_status_t
+ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
+ 				 const cairo_pattern_t *src,
+ 				 cairo_gl_surface_t *dst,
+ 				 int src_x, int src_y,
+ 				 int dst_x, int dst_y,
+ 				 int width, int height)
+ {
+     cairo_status_t status;
+     cairo_matrix_t m;
+     cairo_gl_surface_t *surface;
+     cairo_surface_attributes_t *attributes;
+ 
+     attributes = &operand->operand.texture.attributes;
+ 
+     /* First, try to just upload it to a texture if it's an image surface. */
+     status = _cairo_gl_pattern_image_texture_setup (operand, src, dst,
+ 						    src_x, src_y,
+ 						    dst_x, dst_y,
+ 						    width, height);
+     if (status == CAIRO_STATUS_SUCCESS)
+ 	return CAIRO_STATUS_SUCCESS;
+ 
+     /* Avoid looping in acquire surface fallback -> clone similar -> paint ->
+      * gl_composite -> acquire surface -> fallback.
+      */
+     if (src->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ 	cairo_surface_pattern_t *surface_pattern;
+ 
+ 	surface_pattern = (cairo_surface_pattern_t *)src;
+ 	if (_cairo_surface_is_image (surface_pattern->surface)) {
+ 	    cairo_image_surface_t *image_surface;
+ 	    GLenum internal_format, format, type;
+ 	    cairo_bool_t has_alpha;
+ 
+ 	    image_surface = (cairo_image_surface_t *)surface_pattern->surface;
+ 
+ 	    status = _cairo_gl_get_image_format_and_type (image_surface->pixman_format,
+ 							  &internal_format,
+ 							  &format, &type,
+ 							  &has_alpha);
+ 		if (status)
+ 		    return status;
+ 	}
+     }
+ 
+     status = _cairo_pattern_acquire_surface (src, &dst->base,
+ 					     CAIRO_CONTENT_COLOR_ALPHA,
+ 					     src_x, src_y,
+ 					     width, height,
++					     CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
+ 					     (cairo_surface_t **)
+ 					     &surface,
+ 					     attributes);
+     operand->operand.texture.surface = surface;
+     if (unlikely (status))
+ 	return status;
+ 
+     assert(surface->base.backend == &_cairo_gl_surface_backend);
+ 
+     operand->operand.texture.tex = surface->tex;
+     switch (surface->base.content) {
+     case CAIRO_CONTENT_ALPHA:
+     case CAIRO_CONTENT_COLOR_ALPHA:
+ 	operand->operand.texture.has_alpha = TRUE;
+ 	break;
+     case CAIRO_CONTENT_COLOR:
+ 	operand->operand.texture.has_alpha = FALSE;
+ 	break;
+     }
+ 
+     /* Translate the matrix from
+      * (unnormalized src -> unnormalized src) to
+      * (unnormalized dst -> unnormalized src)
+      */
+     cairo_matrix_init_translate (&m,
+ 				 src_x - dst_x + attributes->x_offset,
+ 				 src_y - dst_y + attributes->y_offset);
+     cairo_matrix_multiply (&attributes->matrix,
+ 			   &m,
+ 			   &attributes->matrix);
+ 
+ 
+     /* Translate the matrix from
+      * (unnormalized src -> unnormalized src) to
+      * (unnormalized dst -> normalized src)
+      */
+     cairo_matrix_init_scale (&m,
+ 			     1.0 / surface->width,
+ 			     1.0 / surface->height);
+     cairo_matrix_multiply (&attributes->matrix,
+ 			   &attributes->matrix,
+ 			   &m);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_int_status_t
+ _cairo_gl_operand_init(cairo_gl_composite_operand_t *operand,
+ 		       const cairo_pattern_t *pattern,
+ 		       cairo_gl_surface_t *dst,
+ 		       int src_x, int src_y,
+ 		       int dst_x, int dst_y,
+ 		       int width, int height)
+ {
+     cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern;
+ 
+     operand->pattern = pattern;
+ 
+     switch (pattern->type) {
+     case CAIRO_PATTERN_TYPE_SOLID:
+ 	operand->type = OPERAND_CONSTANT;
+ 	operand->operand.constant.color[0] = solid->color.red * solid->color.alpha;
+ 	operand->operand.constant.color[1] = solid->color.green * solid->color.alpha;
+ 	operand->operand.constant.color[2] = solid->color.blue * solid->color.alpha;
+ 	operand->operand.constant.color[3] = solid->color.alpha;
+ 	return CAIRO_STATUS_SUCCESS;
+     default:
+     case CAIRO_PATTERN_TYPE_SURFACE:
+     case CAIRO_PATTERN_TYPE_LINEAR:
+     case CAIRO_PATTERN_TYPE_RADIAL:
+ 	operand->type = OPERAND_TEXTURE;
+ 	return _cairo_gl_pattern_texture_setup(operand,
+ 					       pattern, dst,
+ 					       src_x, src_y,
+ 					       dst_x, dst_y,
+ 					       width, height);
+     }
+ }
+ 
+ static void
+ _cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand)
+ {
+     switch (operand->type) {
+     case OPERAND_CONSTANT:
+ 	break;
+     case OPERAND_TEXTURE:
+ 	if (operand->operand.texture.surface != NULL) {
+ 	    cairo_gl_surface_t *surface = operand->operand.texture.surface;
+ 
+ 	    _cairo_pattern_release_surface (operand->pattern,
+ 					    &surface->base,
+ 					    &operand->operand.texture.attributes);
+ 	} else {
+ 	    glDeleteTextures (1, &operand->operand.texture.tex);
+ 	}
+ 	break;
+     }
+ }
+ 
+ static void
+ _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx, int tex_unit,
+ 					  GLfloat *color)
+ {
+     glActiveTexture (GL_TEXTURE0 + tex_unit);
+     /* Have to have a dummy texture bound in order to use the combiner unit. */
+     glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex);
+     glEnable (GL_TEXTURE_2D);
+ 
+     glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
+     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+     if (tex_unit == 0) {
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+     } else {
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+     }
+     glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
+     glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
+     if (tex_unit == 0) {
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+     } else {
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ 
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+     }
+ }
+ 
+ static cairo_int_status_t
+ _cairo_gl_surface_composite (cairo_operator_t		  op,
+ 			     const cairo_pattern_t	 *src,
+ 			     const cairo_pattern_t	 *mask,
+ 			     void			 *abstract_dst,
+ 			     int			  src_x,
+ 			     int			  src_y,
+ 			     int			  mask_x,
+ 			     int			  mask_y,
+ 			     int			  dst_x,
+ 			     int			  dst_y,
+ 			     unsigned int		  width,
+ 			     unsigned int		  height)
+ {
+     cairo_gl_surface_t	*dst = abstract_dst;
+     cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL;
+     cairo_gl_context_t *ctx;
+     GLfloat vertices[4][2];
+     GLfloat texcoord_src[4][2];
+     GLfloat texcoord_mask[4][2];
+     cairo_status_t status;
+     int i;
+     GLenum err;
+     GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
+     cairo_gl_composite_setup_t setup;
+ 
+     memset(&setup, 0, sizeof(setup));
+ 
+     status = _cairo_gl_operand_init (&setup.src, src, dst,
+ 				     src_x, src_y,
+ 				     dst_x, dst_y,
+ 				     width, height);
+     if (unlikely (status))
+ 	return status;
+     src_attributes = &setup.src.operand.texture.attributes;
+ 
+     if (mask != NULL && _cairo_pattern_is_opaque(mask))
+ 	mask = NULL;
+ 
+     if (mask != NULL) {
+ 	status = _cairo_gl_operand_init (&setup.mask, mask, dst,
+ 					 mask_x, mask_y,
+ 					 dst_x, dst_y,
+ 					 width, height);
+ 	if (unlikely (status)) {
+ 	    _cairo_gl_operand_destroy (&setup.src);
+ 	    return status;
+ 	}
+ 	mask_attributes = &setup.mask.operand.texture.attributes;
+     }
+ 
+     ctx = _cairo_gl_context_acquire (dst->ctx);
+     _cairo_gl_set_destination (dst);
+     status = _cairo_gl_set_operator (dst, op);
+     if (status != CAIRO_STATUS_SUCCESS) {
+ 	_cairo_gl_operand_destroy (&setup.src);
+ 	if (mask != NULL)
+ 	    _cairo_gl_operand_destroy (&setup.mask);
+ 	_cairo_gl_context_release (ctx);
+ 	return status;
+     }
+ 
+     glEnable (GL_BLEND);
+ 
+     switch (setup.src.type) {
+     case OPERAND_CONSTANT:
+ 	_cairo_gl_set_tex_combine_constant_color (ctx, 0,
+ 	    setup.src.operand.constant.color);
+ 	break;
+     case OPERAND_TEXTURE:
+ 	_cairo_gl_set_texture_surface (0, setup.src.operand.texture.tex,
+ 				       src_attributes);
+ 	/* Set up the constant color we use to set alpha to 1 if needed. */
+ 	glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
+ 	/* Set up the combiner to just set color to the sampled texture. */
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ 
+ 	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
+ 	/* Wire the src alpha to 1 if the surface doesn't have it.
+ 	 * We may have a teximage with alpha bits even though we didn't ask
+ 	 * for it and we don't pay attention to setting alpha to 1 in a dest
+ 	 * that has inadvertent alpha.
+ 	 */
+ 	if (setup.src.operand.texture.has_alpha)
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
+ 	else
+ 	    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;
+     }
+ 
+     if (mask != NULL) {
+ 	switch (setup.mask.type) {
+ 	case OPERAND_CONSTANT:
+ 	    _cairo_gl_set_tex_combine_constant_color (ctx, 1,
+ 		setup.mask.operand.constant.color);
+ 	    break;
+ 	case OPERAND_TEXTURE:
+ 	    _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex,
+ 					   mask_attributes);
+ 
+ 	    /* IN: dst.argb = src.argb * mask.aaaa */
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ 
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ 
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
+ 	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ 	    break;
+ 	}
+     }
+ 
+     vertices[0][0] = dst_x;
+     vertices[0][1] = dst_y;
+     vertices[1][0] = dst_x + width;
+     vertices[1][1] = dst_y;
+     vertices[2][0] = dst_x + width;
+     vertices[2][1] = dst_y + height;
+     vertices[3][0] = dst_x;
+     vertices[3][1] = dst_y + height;
+ 
+     glVertexPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, vertices);
+     glEnableClientState (GL_VERTEX_ARRAY);
+ 
+     if (setup.src.type == OPERAND_TEXTURE) {
+ 	for (i = 0; i < 4; i++) {
+ 	    double s, t;
+ 
+ 	    s = vertices[i][0];
+ 	    t = vertices[i][1];
+ 	    cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
+ 	    texcoord_src[i][0] = s;
+ 	    texcoord_src[i][1] = t;
+ 	}
+ 
+ 	glClientActiveTexture (GL_TEXTURE0);
+ 	glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_src);
+ 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+     }
+ 
+     if (mask != NULL) {
+ 	if (setup.mask.type == OPERAND_TEXTURE) {
+ 	    for (i = 0; i < 4; i++) {
+ 		double s, t;
+ 
+ 		s = vertices[i][0];
+ 		t = vertices[i][1];
+ 		cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t);
+ 		texcoord_mask[i][0] = s;
+ 		texcoord_mask[i][1] = t;
+ 	    }
+ 
+ 	    glClientActiveTexture (GL_TEXTURE1);
+ 	    glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_mask);
+ 	    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ 	}
+     }
+ 
+     glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
+ 
+     glDisable (GL_BLEND);
+ 
+     glDisableClientState (GL_VERTEX_ARRAY);
+ 
+     glClientActiveTexture (GL_TEXTURE0);
+     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+     glActiveTexture (GL_TEXTURE0);
+     glDisable (GL_TEXTURE_2D);
+ 
+     glClientActiveTexture (GL_TEXTURE1);
+     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+     glActiveTexture (GL_TEXTURE1);
+     glDisable (GL_TEXTURE_2D);
+ 
+     while ((err = glGetError ()))
+ 	fprintf(stderr, "GL error 0x%08x\n", (int) err);
+ 
+     _cairo_gl_context_release (ctx);
+ 
+     _cairo_gl_operand_destroy (&setup.src);
+     if (mask != NULL)
+ 	_cairo_gl_operand_destroy (&setup.mask);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_int_status_t
+ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
+ 					const cairo_pattern_t *pattern,
+ 					void *abstract_dst,
+ 					cairo_antialias_t antialias,
+ 					int src_x, int src_y,
+ 					int dst_x, int dst_y,
+ 					unsigned int width,
+ 					unsigned int height,
+ 					cairo_trapezoid_t *traps,
+ 					int num_traps)
+ {
+     cairo_gl_surface_t *dst = abstract_dst;
+     cairo_pattern_t *traps_pattern;
+     cairo_int_status_t status;
+ 
+     status = _cairo_gl_get_traps_pattern (dst,
+ 					  dst_x, dst_y, width, height,
+ 					  traps, num_traps, antialias,
+ 					  &traps_pattern);
+     if (status) {
+ 	fprintf(stderr, "traps falllback\n");
+ 	return status;
+     }
+ 
+     status = _cairo_gl_surface_composite (op, pattern, traps_pattern, dst,
+ 					  src_x, src_y,
+ 					  0, 0,
+ 					  dst_x, dst_y,
+ 					  width, height);
+     cairo_pattern_destroy (traps_pattern);
+ 
+     return status;
+ }
+ 
+ static cairo_int_status_t
+ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
+ 				   cairo_operator_t	    op,
+ 				   const cairo_color_t     *color,
+ 				   cairo_rectangle_int_t   *rects,
+ 				   int			    num_rects)
+ {
+     cairo_gl_surface_t *surface = abstract_surface;
+     cairo_gl_context_t *ctx;
+     cairo_int_status_t status;
+     int i;
+     GLfloat *vertices;
+     GLfloat *colors;
+ 
+     ctx = _cairo_gl_context_acquire (surface->ctx);
+ 
+     _cairo_gl_set_destination (surface);
+     status = _cairo_gl_set_operator (surface, op);
+     if (status != CAIRO_STATUS_SUCCESS) {
+ 	_cairo_gl_context_release (ctx);
+ 	return status;
+     }
+ 
+     vertices = _cairo_malloc_ab(num_rects, sizeof(GLfloat) * 4 * 2);
+     colors = _cairo_malloc_ab(num_rects, sizeof(GLfloat) * 4 * 4);
+     if (!vertices || !colors) {
+ 	_cairo_gl_context_release(ctx);
+ 	free(vertices);
+ 	free(colors);
+ 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+     }
+ 
+     /* This should be loaded in as either a blend constant and an operator
+      * setup specific to this, or better, a fragment shader constant.
+      */
+     for (i = 0; i < num_rects * 4; i++) {
+ 	colors[i * 4 + 0] = color->red * color->alpha;
+ 	colors[i * 4 + 1] = color->green * color->alpha;
+ 	colors[i * 4 + 2] = color->blue * color->alpha;
+ 	colors[i * 4 + 3] = color->alpha;
+     }
+ 
+     for (i = 0; i < num_rects; i++) {
+ 	vertices[i * 8 + 0] = rects[i].x;
+ 	vertices[i * 8 + 1] = rects[i].y;
+ 	vertices[i * 8 + 2] = rects[i].x + rects[i].width;
+ 	vertices[i * 8 + 3] = rects[i].y;
+ 	vertices[i * 8 + 4] = rects[i].x + rects[i].width;
+ 	vertices[i * 8 + 5] = rects[i].y + rects[i].height;
+ 	vertices[i * 8 + 6] = rects[i].x;
+ 	vertices[i * 8 + 7] = rects[i].y + rects[i].height;
+     }
+ 
+     glEnable (GL_BLEND);
+     glVertexPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, vertices);
+     glEnableClientState (GL_VERTEX_ARRAY);
+     glColorPointer (4, GL_FLOAT, sizeof(GLfloat) * 4, colors);
+     glEnableClientState (GL_COLOR_ARRAY);
+     glDrawArrays (GL_TRIANGLE_FAN, 0, 4 * num_rects);
+ 
+     glDisableClientState (GL_COLOR_ARRAY);
+     glDisableClientState (GL_VERTEX_ARRAY);
+     glDisable (GL_BLEND);
+ 
+     _cairo_gl_context_release (ctx);
+     free(vertices);
+     free(colors);
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static cairo_int_status_t
+ _cairo_gl_surface_get_extents (void		     *abstract_surface,
+ 			       cairo_rectangle_int_t *rectangle)
+ {
+     cairo_gl_surface_t *surface = abstract_surface;
+ 
+     rectangle->x = 0;
+     rectangle->y = 0;
+     rectangle->width  = surface->width;
+     rectangle->height = surface->height;
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static const cairo_surface_backend_t _cairo_gl_surface_backend = {
+     CAIRO_SURFACE_TYPE_GL,
+     _cairo_gl_surface_create_similar,
+     _cairo_gl_surface_finish,
+     _cairo_gl_surface_acquire_source_image,
+     _cairo_gl_surface_release_source_image,
+     _cairo_gl_surface_acquire_dest_image,
+     _cairo_gl_surface_release_dest_image,
+     _cairo_gl_surface_clone_similar,
+     _cairo_gl_surface_composite,
+     _cairo_gl_surface_fill_rectangles,
+     _cairo_gl_surface_composite_trapezoids,
+     NULL, /* create_span_renderer */
+     NULL, /* check_span_renderer */
+     NULL, /* copy_page */
+     NULL, /* show_page */
+     NULL, /* set_clip_region */
+     NULL, /* intersect_clip_path */
+     _cairo_gl_surface_get_extents,
+     NULL, /* old_show_glyphs */
+     NULL, /* get_font_options */
+     NULL, /* flush */
+     NULL, /* mark_dirty_rectangle */
+     NULL, /* scaled_font_fini */
+     NULL, /* scaled_glyph_fini */
+     NULL, /* paint */
+     NULL, /* mask */
+     NULL, /* stroke */
+     NULL, /* fill */
+     NULL, /* show_glyphs */
+     NULL  /* snapshot */
+ };
+ 
+ /** Call glFinish(), used for accurate performance testing. */
+ cairo_status_t
+ cairo_gl_surface_glfinish (cairo_surface_t *surface)
+ {
+     glFinish();
+ 
+     return CAIRO_STATUS_SUCCESS;
+ }
diff --cc src/cairo-gl.h
index 0000000,9d8eea4..1b8f795
mode 000000,100644..100644
--- a/src/cairo-gl.h
+++ b/src/cairo-gl.h
@@@ -1,0 -1,101 +1,101 @@@
+ /* Cairo - a vector graphics library with display and print output
+  *
+  * Copyright © 2009 Eric Anholt
+  * Copyright © 2009 Chris Wilson
+  *
+  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Eric Anholt.
+  */
+ 
+ #ifndef CAIRO_GL_H
+ #define CAIRO_GL_H
+ 
+ #include "cairo.h"
+ 
+ #if CAIRO_HAS_GL_SURFACE
+ 
+ CAIRO_BEGIN_DECLS
+ 
+ typedef struct _cairo_gl_context cairo_gl_context_t;
+ 
+ cairo_public cairo_gl_context_t *
+ cairo_gl_context_reference (cairo_gl_context_t *context);
+ 
+ cairo_public void
+ cairo_gl_context_destroy (cairo_gl_context_t *context);
+ 
+ cairo_public cairo_surface_t *
+ cairo_gl_surface_create (cairo_gl_context_t *ctx,
+ 			 cairo_content_t content,
+ 			 int width, int height);
+ 
+ cairo_public void
+ cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
+ 
+ cairo_public int
+ cairo_gl_surface_get_width (cairo_surface_t *abstract_surface);
+ 
+ cairo_public int
+ cairo_gl_surface_get_height (cairo_surface_t *abstract_surface);
+ 
+ cairo_public void
+ cairo_gl_surface_swapbuffers (cairo_surface_t *surface);
+ 
+ cairo_public cairo_status_t
+ cairo_gl_surface_glfinish (cairo_surface_t *surface);
+ 
 -#if CAIRO_HAS_GL_GLX_SURFACE
++#if CAIRO_HAS_GLX_FUNCTIONS
+ #include <GL/glx.h>
+ 
+ cairo_public cairo_gl_context_t *
+ cairo_glx_context_create (Display *dpy, GLXContext gl_ctx);
+ 
+ cairo_public cairo_surface_t *
+ cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
+ 				    Window win,
+ 				    int width, int height);
+ #endif
+ 
 -#if CAIRO_HAS_GL_EGL_SURFACE
++#if CAIRO_HAS_EAGLE_FUNCTIONS
+ #include <eagle.h>
+ 
+ cairo_public cairo_gl_context_t *
 -cairo_egl_context_create (EGLDisplay display, EGLContext context);
++cairo_eagle_context_create (EGLDisplay display, EGLContext context);
+ 
+ cairo_public cairo_surface_t *
+ cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx,
+ 				   EGLSurface surface,
+ 				   int width, int height);
+ #endif
+ 
+ CAIRO_END_DECLS
+ 
+ #else  /* CAIRO_HAS_GL_SURFACE */
+ # error Cairo was not compiled with support for the GL backend
+ #endif /* CAIRO_HAS_GL_SURFACE */
+ 
+ #endif /* CAIRO_GL_H */
diff --cc src/cairo.h
index 48ecc37,4350bc1..bd4eb66
--- a/src/cairo.h
+++ b/src/cairo.h
@@@ -1940,9 -1889,7 +1940,10 @@@ cairo_surface_status (cairo_surface_t *
   * @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface
   * @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image
   * @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10
 + * @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10
 + * @CAIRO_SURFACE_TYPE_META: The surface is a meta-type, since 1.10
 + * @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10
+  * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10
   *
   * #cairo_surface_type_t is used to describe the type of a given
   * surface. The surface types are also known as "backends" or "surface
@@@ -1983,9 -1930,7 +1984,10 @@@ typedef enum _cairo_surface_type 
      CAIRO_SURFACE_TYPE_WIN32_PRINTING,
      CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
      CAIRO_SURFACE_TYPE_SCRIPT,
 +    CAIRO_SURFACE_TYPE_QT,
 +    CAIRO_SURFACE_TYPE_META,
-     CAIRO_SURFACE_TYPE_VG
++    CAIRO_SURFACE_TYPE_VG,
+     CAIRO_SURFACE_TYPE_GL,
  } cairo_surface_type_t;
  
  cairo_public cairo_surface_type_t
diff --cc test/get-clip.c
index 5232a0e,1a07f01..4103118
--- a/test/get-clip.c
+++ b/test/get-clip.c
@@@ -129,6 -129,6 +129,7 @@@ draw (cairo_t *cr, int width, int heigh
      case CAIRO_SURFACE_TYPE_WIN32:
      case CAIRO_SURFACE_TYPE_BEOS:
      case CAIRO_SURFACE_TYPE_DIRECTFB:
++    case CAIRO_SURFACE_TYPE_GL:
          uses_clip_rects = TRUE;
  	break;
      case CAIRO_SURFACE_TYPE_QUARTZ:
diff --cc util/cairo-script/Makefile.am
index c742cda,4966e20..acde8f5
--- a/util/cairo-script/Makefile.am
+++ b/util/cairo-script/Makefile.am
@@@ -27,8 -28,19 +28,5 @@@ csi_replay_LDADD = libcairo-script-inte
  csi_exec_SOURCES = csi-exec.c
  csi_exec_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
  
- csi_bind_SOURCES = csi-bind.c
- csi_bind_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
- 
 -if CAIRO_HAS_GL_EGL_SURFACE
 -noinst_PROGRAMS += csi-egl
 -csi_egl_SOURCES = csi-egl.c
 -csi_egl_CFLAGS = $(CAIRO_CFLAGS)
 -csi_egl_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
 -endif
 -
 -if CAIRO_HAS_GL_GLX_SURFACE
 -noinst_PROGRAMS += csi-glx
 -csi_glx_SOURCES = csi-glx.c
 -csi_glx_CFLAGS = $(CAIRO_CFLAGS)
 -csi_glx_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
 -endif
 -
  EXTRA_DIST = \
  	COPYING
commit 6a5957475139a7c80a6bb55fb63927e5ec8866f6
Author: Eric Anholt <eric at anholt.net>
Date:   Sun Jun 7 10:43:43 2009 +0000

    [gl] consolidate the pixman format to GL format/type/internalformat code.
    
    This means that draw_image gets all the love that the pattern texture code
    does.  Not that I'm sure it still needs to exist.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 666ec84..a3e0c06 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -177,6 +177,125 @@ _cairo_gl_context_acquire (cairo_gl_context_t *ctx)
     return ctx;
 }
 
+static cairo_status_t
+_cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
+				     GLenum *internal_format, GLenum *format,
+				     GLenum *type, cairo_bool_t *has_alpha)
+{
+    *has_alpha = TRUE;
+
+    switch (pixman_format) {
+    case PIXMAN_a8r8g8b8:
+	*internal_format = GL_RGBA;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_x8r8g8b8:
+	*internal_format = GL_RGB;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	*has_alpha = FALSE;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_a8b8g8r8:
+	*internal_format = GL_RGBA;
+	*format = GL_RGBA;
+	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_x8b8g8r8:
+	*internal_format = GL_RGB;
+	*format = GL_RGBA;
+	*type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	*has_alpha = FALSE;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_b8g8r8a8:
+	*internal_format = GL_BGRA;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_INT_8_8_8_8;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_b8g8r8x8:
+	*internal_format = GL_RGB;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_INT_8_8_8_8;
+	*has_alpha = FALSE;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_r8g8b8:
+	*internal_format = GL_RGB;
+	*format = GL_RGB;
+	*type = GL_UNSIGNED_BYTE;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_b8g8r8:
+	*internal_format = GL_RGB;
+	*format = GL_BGR;
+	*type = GL_UNSIGNED_BYTE;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_r5g6b5:
+	*internal_format = GL_RGB;
+	*format = GL_RGB;
+	*type = GL_UNSIGNED_SHORT_5_6_5;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_b5g6r5:
+	*internal_format = GL_RGB;
+	*format = GL_RGB;
+	*type = GL_UNSIGNED_SHORT_5_6_5_REV;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_a1r5g5b5:
+	*internal_format = GL_RGBA;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_x1r5g5b5:
+	*internal_format = GL_RGB;
+	*format = GL_BGRA;
+	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	*has_alpha = FALSE;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_a1b5g5r5:
+	*internal_format = GL_RGBA;
+	*format = GL_RGBA;
+	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_x1b5g5r5:
+	*internal_format = GL_RGB;
+	*format = GL_RGBA;
+	*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	*has_alpha = FALSE;
+	return CAIRO_STATUS_SUCCESS;
+    case PIXMAN_a8:
+	*internal_format = GL_ALPHA;
+	*format = GL_ALPHA;
+	*type = GL_UNSIGNED_BYTE;
+	return CAIRO_STATUS_SUCCESS;
+
+    case PIXMAN_a2b10g10r10:
+    case PIXMAN_x2b10g10r10:
+    case PIXMAN_a4r4g4b4:
+    case PIXMAN_x4r4g4b4:
+    case PIXMAN_a4b4g4r4:
+    case PIXMAN_x4b4g4r4:
+    case PIXMAN_r3g3b2:
+    case PIXMAN_b2g3r3:
+    case PIXMAN_a2r2g2b2:
+    case PIXMAN_a2b2g2r2:
+    case PIXMAN_c8:
+    case PIXMAN_x4a4:
+    /* case PIXMAN_x4c4: */
+    case PIXMAN_x4g4:
+    case PIXMAN_a4:
+    case PIXMAN_r1g2b1:
+    case PIXMAN_b1g2r1:
+    case PIXMAN_a1r1g1b1:
+    case PIXMAN_a1b1g1r1:
+    case PIXMAN_c4:
+    case PIXMAN_g4:
+    case PIXMAN_a1:
+    case PIXMAN_g1:
+    case PIXMAN_yuy2:
+    case PIXMAN_yv12:
+    default:
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+}
+
 static void
 _cairo_gl_context_release (cairo_gl_context_t *ctx)
 {
@@ -473,21 +592,6 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
     return cairo_gl_surface_create (surface->ctx, content, width, height);
 }
 
-static cairo_bool_t
-_cairo_gl_surface_draw_image_format_compatible (cairo_image_surface_t *surface)
-{
-    if (surface->pixman_format == PIXMAN_a8r8g8b8 ||
-	surface->pixman_format == PIXMAN_x8r8g8b8 ||
-	surface->pixman_format == PIXMAN_a8 ||
-	surface->pixman_format == PIXMAN_a1r5g5b5 ||
-	surface->pixman_format == PIXMAN_r5g6b5 ||
-	surface->pixman_format == PIXMAN_a1b5g5r5 ||
-	surface->pixman_format == PIXMAN_b5g6r5)
-	return TRUE;
-    else
-	return FALSE;
-}
-
 static cairo_status_t
 _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 			      cairo_image_surface_t *src,
@@ -497,45 +601,19 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 {
     char *temp_data;
     int y;
-    unsigned int cpp;
-    GLenum format, type;
+    unsigned int cpp = PIXMAN_FORMAT_BPP(src->pixman_format) / 8;
+    GLenum internal_format, format, type;
     char *src_data_start;
+    cairo_bool_t has_alpha;
+    cairo_status_t status;
 
-    /* Want to use a switch statement here but the compiler gets whiny. */
-    if (src->pixman_format == PIXMAN_a8r8g8b8) {
-	format = GL_BGRA;
-	type = GL_UNSIGNED_INT_8_8_8_8_REV;
-	cpp = 4;
-    } else if (src->pixman_format == PIXMAN_x8r8g8b8) {
-	assert(dst->base.content != CAIRO_CONTENT_COLOR_ALPHA);
-	assert(dst->base.content != CAIRO_CONTENT_ALPHA);
-	format = GL_BGRA;
-	type = GL_UNSIGNED_INT_8_8_8_8_REV;
-	cpp = 4;
-    } else if (src->pixman_format == PIXMAN_a8) {
-	format = GL_ALPHA;
-	type = GL_UNSIGNED_BYTE;
-	cpp = 1;
-    } else if (src->pixman_format == PIXMAN_r5g6b5) {
-	format = GL_RGB;
-	type = GL_UNSIGNED_SHORT_5_6_5;
-	cpp = 2;
-    } else if (src->pixman_format == PIXMAN_b5g6r5) {
-	format = GL_RGB;
-	type = GL_UNSIGNED_SHORT_5_6_5_REV;
-	cpp = 2;
-    } else if (src->pixman_format == PIXMAN_a1r5g5b5) {
-	format = GL_BGRA;
-	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
-	cpp = 2;
-    } else if (src->pixman_format == PIXMAN_a1b5g5r5) {
-	format = GL_RGBA;
-	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
-	cpp = 2;
-    } else {
-	fprintf(stderr, "draw_image fallback\n");
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
+    status = _cairo_gl_get_image_format_and_type (src->pixman_format,
+						  &internal_format,
+						  &format,
+						  &type,
+						  &has_alpha);
+    if (status != CAIRO_STATUS_SUCCESS)
+	return status;
 
     /* Write the data to a temporary as GL wants bottom-to-top data
      * screen-wise, and we want top-to-bottom.
@@ -744,9 +822,16 @@ _cairo_gl_surface_clone_similar (void		     *abstract_surface,
 	cairo_gl_surface_t *clone;
 	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
 	cairo_status_t status;
-
-	if (!_cairo_gl_surface_draw_image_format_compatible (image_src))
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	GLenum internal_format, format, type;
+	cairo_bool_t has_alpha;
+
+	status = _cairo_gl_get_image_format_and_type (image_src->pixman_format,
+						      &internal_format,
+						      &format,
+						      &type,
+						      &has_alpha);
+	if (status != CAIRO_STATUS_SUCCESS)
+	    return status;
 
 	clone = (cairo_gl_surface_t *)
 	    _cairo_gl_surface_create_similar (&surface->base,
@@ -852,6 +937,7 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
     cairo_surface_attributes_t *attributes;
     GLuint tex;
     GLenum format, internal_format, type;
+    cairo_status_t status;
 
     if (src->type != CAIRO_PATTERN_TYPE_SURFACE)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -867,111 +953,12 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
      */
     operand->operand.texture.has_alpha = TRUE;
 
-    switch (image_surface->pixman_format) {
-    case PIXMAN_a8r8g8b8:
-	internal_format = GL_RGBA;
-	format = GL_BGRA;
-	type = GL_UNSIGNED_INT_8_8_8_8_REV;
-	break;
-    case PIXMAN_x8r8g8b8:
-	internal_format = GL_RGB;
-	format = GL_BGRA;
-	type = GL_UNSIGNED_INT_8_8_8_8_REV;
-	operand->operand.texture.has_alpha = FALSE;
-	break;
-    case PIXMAN_a8b8g8r8:
-	internal_format = GL_RGBA;
-	format = GL_RGBA;
-	type = GL_UNSIGNED_INT_8_8_8_8_REV;
-	break;
-    case PIXMAN_x8b8g8r8:
-	internal_format = GL_RGB;
-	format = GL_RGBA;
-	type = GL_UNSIGNED_INT_8_8_8_8_REV;
-	operand->operand.texture.has_alpha = FALSE;
-	break;
-    case PIXMAN_b8g8r8a8:
-	internal_format = GL_BGRA;
-	format = GL_BGRA;
-	type = GL_UNSIGNED_INT_8_8_8_8;
-	break;
-    case PIXMAN_r8g8b8:
-	internal_format = GL_RGB;
-	format = GL_RGB;
-	type = GL_UNSIGNED_BYTE;
-	break;
-    case PIXMAN_b8g8r8:
-	internal_format = GL_RGB;
-	format = GL_BGR;
-	type = GL_UNSIGNED_BYTE;
-	break;
-    case PIXMAN_r5g6b5:
-	internal_format = GL_RGB;
-	format = GL_RGB;
-	type = GL_UNSIGNED_SHORT_5_6_5;
-	break;
-    case PIXMAN_b5g6r5:
-	internal_format = GL_RGB;
-	format = GL_RGB;
-	type = GL_UNSIGNED_SHORT_5_6_5_REV;
-	break;
-    case PIXMAN_a1r5g5b5:
-	internal_format = GL_RGBA;
-	format = GL_BGRA;
-	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
-	break;
-    case PIXMAN_x1r5g5b5:
-	internal_format = GL_RGB;
-	format = GL_BGRA;
-	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
-	break;
-    case PIXMAN_a1b5g5r5:
-	internal_format = GL_RGBA;
-	format = GL_RGBA;
-	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
-	operand->operand.texture.has_alpha = FALSE;
-	break;
-    case PIXMAN_x1b5g5r5:
-	internal_format = GL_RGB;
-	format = GL_RGBA;
-	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
-	operand->operand.texture.has_alpha = FALSE;
-	break;
-    case PIXMAN_a8:
-	internal_format = GL_ALPHA;
-	format = GL_ALPHA;
-	type = GL_UNSIGNED_BYTE;
-	break;
-
-    case PIXMAN_a2b10g10r10:
-    case PIXMAN_x2b10g10r10:
-    case PIXMAN_a4r4g4b4:
-    case PIXMAN_x4r4g4b4:
-    case PIXMAN_a4b4g4r4:
-    case PIXMAN_x4b4g4r4:
-    case PIXMAN_r3g3b2:
-    case PIXMAN_b2g3r3:
-    case PIXMAN_a2r2g2b2:
-    case PIXMAN_a2b2g2r2:
-    case PIXMAN_c8:
-    case PIXMAN_x4a4:
-    /* case PIXMAN_x4c4: */
-    case PIXMAN_x4g4:
-    case PIXMAN_a4:
-    case PIXMAN_r1g2b1:
-    case PIXMAN_b1g2r1:
-    case PIXMAN_a1r1g1b1:
-    case PIXMAN_a1b1g1r1:
-    case PIXMAN_c4:
-    case PIXMAN_g4:
-    case PIXMAN_a1:
-    case PIXMAN_g1:
-    case PIXMAN_yuy2:
-    case PIXMAN_yv12:
-    case PIXMAN_b8g8r8x8:
-    default:
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
+    status = _cairo_gl_get_image_format_and_type (image_surface->pixman_format,
+						  &internal_format, &format,
+						  &type,
+						  &operand->operand.texture.has_alpha);
+    if (status)
+	return status;
 
     glGenTextures (1, &tex);
     glBindTexture (GL_TEXTURE_2D, tex);
@@ -1067,13 +1054,21 @@ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
      */
     if (src->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	cairo_surface_pattern_t *surface_pattern;
-	cairo_image_surface_t *image_surface;
 
 	surface_pattern = (cairo_surface_pattern_t *)src;
 	if (_cairo_surface_is_image (surface_pattern->surface)) {
+	    cairo_image_surface_t *image_surface;
+	    GLenum internal_format, format, type;
+	    cairo_bool_t has_alpha;
+
 	    image_surface = (cairo_image_surface_t *)surface_pattern->surface;
-	    if (!_cairo_gl_surface_draw_image_format_compatible (image_surface))
-		return CAIRO_INT_STATUS_UNSUPPORTED;
+
+	    status = _cairo_gl_get_image_format_and_type (image_surface->pixman_format,
+							  &internal_format,
+							  &format, &type,
+							  &has_alpha);
+		if (status)
+		    return status;
 	}
     }
 
commit cb1e5674cd7a61a2d96bd4ae8895b26686571e78
Author: Eric Anholt <eric at anholt.net>
Date:   Sun Jun 7 10:09:28 2009 +0000

    [gl] Add support for more 16-bit image formats.
    
    Fixes test-fallback16-surface-source

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 3897ed4..666ec84 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -478,7 +478,11 @@ _cairo_gl_surface_draw_image_format_compatible (cairo_image_surface_t *surface)
 {
     if (surface->pixman_format == PIXMAN_a8r8g8b8 ||
 	surface->pixman_format == PIXMAN_x8r8g8b8 ||
-	surface->pixman_format == PIXMAN_a8)
+	surface->pixman_format == PIXMAN_a8 ||
+	surface->pixman_format == PIXMAN_a1r5g5b5 ||
+	surface->pixman_format == PIXMAN_r5g6b5 ||
+	surface->pixman_format == PIXMAN_a1b5g5r5 ||
+	surface->pixman_format == PIXMAN_b5g6r5)
 	return TRUE;
     else
 	return FALSE;
@@ -512,6 +516,22 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	format = GL_ALPHA;
 	type = GL_UNSIGNED_BYTE;
 	cpp = 1;
+    } else if (src->pixman_format == PIXMAN_r5g6b5) {
+	format = GL_RGB;
+	type = GL_UNSIGNED_SHORT_5_6_5;
+	cpp = 2;
+    } else if (src->pixman_format == PIXMAN_b5g6r5) {
+	format = GL_RGB;
+	type = GL_UNSIGNED_SHORT_5_6_5_REV;
+	cpp = 2;
+    } else if (src->pixman_format == PIXMAN_a1r5g5b5) {
+	format = GL_BGRA;
+	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	cpp = 2;
+    } else if (src->pixman_format == PIXMAN_a1b5g5r5) {
+	format = GL_RGBA;
+	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	cpp = 2;
     } else {
 	fprintf(stderr, "draw_image fallback\n");
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -890,17 +910,39 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 	format = GL_RGB;
 	type = GL_UNSIGNED_SHORT_5_6_5;
 	break;
+    case PIXMAN_b5g6r5:
+	internal_format = GL_RGB;
+	format = GL_RGB;
+	type = GL_UNSIGNED_SHORT_5_6_5_REV;
+	break;
+    case PIXMAN_a1r5g5b5:
+	internal_format = GL_RGBA;
+	format = GL_BGRA;
+	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	break;
+    case PIXMAN_x1r5g5b5:
+	internal_format = GL_RGB;
+	format = GL_BGRA;
+	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	break;
+    case PIXMAN_a1b5g5r5:
+	internal_format = GL_RGBA;
+	format = GL_RGBA;
+	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	operand->operand.texture.has_alpha = FALSE;
+	break;
+    case PIXMAN_x1b5g5r5:
+	internal_format = GL_RGB;
+	format = GL_RGBA;
+	type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+	operand->operand.texture.has_alpha = FALSE;
+	break;
     case PIXMAN_a8:
 	internal_format = GL_ALPHA;
 	format = GL_ALPHA;
 	type = GL_UNSIGNED_BYTE;
 	break;
 
-    case PIXMAN_b5g6r5:
-    case PIXMAN_a1r5g5b5:
-    case PIXMAN_x1r5g5b5:
-    case PIXMAN_a1b5g5r5:
-    case PIXMAN_x1b5g5r5:
     case PIXMAN_a2b10g10r10:
     case PIXMAN_x2b10g10r10:
     case PIXMAN_a4r4g4b4:
commit f59f44c140e5f60d336423e0585d2bb8a6c0ea01
Merge: 2da78fd... 4232719...
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Jun 2 00:37:19 2009 -0700

    Merge commit 'origin/master' into gl
    
    Felt like pulling the latest stuff, since I branched back in February.
    
    Conflicts:
    	build/configure.ac.features
    	src/cairo.h
    	util/cairo-script/csi-replay.c

diff --cc build/Makefile.win32.features
index f9e064d,764639c..9e72224
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@@ -10,11 -10,7 +10,10 @@@ CAIRO_HAS_WIN32_SURFACE=
  CAIRO_HAS_WIN32_FONT=1
  CAIRO_HAS_OS2_SURFACE=0
  CAIRO_HAS_BEOS_SURFACE=0
- CAIRO_HAS_SDL_SURFACE=0
  CAIRO_HAS_PNG_FUNCTIONS=1
 +CAIRO_HAS_GL_SURFACE=0
 +CAIRO_HAS_GL_GLX_SURFACE=0
 +CAIRO_HAS_GL_EGL_SURFACE=0
  CAIRO_HAS_GLITZ_SURFACE=0
  CAIRO_HAS_DIRECTFB_SURFACE=0
  CAIRO_HAS_SCRIPT_SURFACE=0
diff --cc build/configure.ac.features
index f477414,8ccee7b..ce79546
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@@ -376,10 -375,6 +376,9 @@@ AC_DEFUN([CAIRO_REPORT]
  	echo "  glitz:         $use_glitz"
  	echo "  BeOS:          $use_beos"
  	echo "  DirectFB:      $use_directfb"
- 	echo "  SDL:           $use_sdl"
 +	echo "  GL:            $use_gl"
 +	echo "  GL/GLX:        $use_gl_glx"
 +	echo "  GL/EGL:        $use_gl_egl"
  	echo ""
  	echo "The following font backends:"
  	echo "  User:          yes (always builtin)"
diff --cc src/cairo-gl-surface.c
index 2d601ee,0000000..3897ed4
mode 100644,000000..100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@@ -1,1529 -1,0 +1,1531 @@@
 +/* cairo - a vector graphics library with display and print output
 + *
 + * Copyright © 2009 Eric Anholt
 + * Copyright © 2009 Chris Wilson
 + * Copyright © 2005 Red Hat, Inc
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it either under the terms of the GNU Lesser General Public
 + * License version 2.1 as published by the Free Software Foundation
 + * (the "LGPL") or, at your option, under the terms of the Mozilla
 + * Public License Version 1.1 (the "MPL"). If you do not alter this
 + * notice, a recipient may use your version of this file under either
 + * the MPL or the LGPL.
 + *
 + * You should have received a copy of the LGPL along with this library
 + * in the file COPYING-LGPL-2.1; if not, write to the Free Software
 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 + * You should have received a copy of the MPL along with this library
 + * in the file COPYING-MPL-1.1
 + *
 + * The contents of this file are subject to the Mozilla Public License
 + * Version 1.1 (the "License"); you may not use this file except in
 + * compliance with the License. You may obtain a copy of the License at
 + * http://www.mozilla.org/MPL/
 + *
 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
 + * OF ANY KIND, either express or implied. See the LGPL or the MPL for
 + * the specific language governing rights and limitations.
 + *
 + * The Original Code is the cairo graphics library.
 + *
 + * The Initial Developer of the Original Code is Red Hat, Inc.
 + *
 + * Contributor(s):
 + *	Carl Worth <cworth at cworth.org>
 + */
 +
 +#include "cairoint.h"
 +
 +#include "cairo-gl-private.h"
 +
 +slim_hidden_proto (cairo_gl_context_reference);
 +slim_hidden_proto (cairo_gl_context_destroy);
 +slim_hidden_proto (cairo_gl_surface_create);
 +
 +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
 +
 +enum cairo_gl_composite_operand_type {
 +    OPERAND_CONSTANT,
 +    OPERAND_TEXTURE,
 +};
 +
 +/* This union structure describes a potential source or mask operand to the
 + * compositing equation.
 + */
 +typedef struct cairo_gl_composite_operand {
 +    enum cairo_gl_composite_operand_type type;
 +    union {
 +	struct {
 +	    GLuint tex;
 +	    cairo_gl_surface_t *surface;
 +	    cairo_surface_attributes_t attributes;
 +	    cairo_bool_t has_alpha;
 +	} texture;
 +	struct {
 +	    GLfloat color[4];
 +	} constant;
 +    } operand;
 +
 +    const cairo_pattern_t *pattern;
 +} cairo_gl_composite_operand_t;
 +
 +typedef struct _cairo_gl_composite_setup {
 +    cairo_gl_composite_operand_t src;
 +    cairo_gl_composite_operand_t mask;
 +} cairo_gl_composite_setup_t;
 +
 +static const cairo_surface_backend_t _cairo_gl_surface_backend;
 +
 +static const cairo_gl_context_t _nil_context = {
 +    CAIRO_REFERENCE_COUNT_INVALID,
 +    CAIRO_STATUS_NO_MEMORY
 +};
 +
 +static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
 +{
 +    return surface->backend == &_cairo_gl_surface_backend;
 +}
 +
 +cairo_gl_context_t *
 +_cairo_gl_context_create_in_error (cairo_status_t status)
 +{
 +    if (status == CAIRO_STATUS_NO_MEMORY)
 +	return (cairo_gl_context_t *) &_nil_context;
 +
 +    ASSERT_NOT_REACHED;
 +    return NULL;
 +}
 +
 +cairo_status_t
 +_cairo_gl_context_init (cairo_gl_context_t *ctx)
 +{
 +    ctx->status = CAIRO_STATUS_SUCCESS;
 +    CAIRO_REFERENCE_COUNT_INIT (&ctx->ref_count, 1);
 +    CAIRO_MUTEX_INIT (ctx->mutex);
 +
 +    if (glewInit () != GLEW_OK) {
 +	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
 +    }
 +
 +    if (! GLEW_EXT_framebuffer_object ||
 +	! GLEW_ARB_texture_env_combine ||
 +	! GLEW_ARB_texture_non_power_of_two)
 +    {
 +	fprintf (stderr,
 +		 "Required GL extensions not available:\n");
 +	if (! GLEW_EXT_framebuffer_object)
 +	    fprintf (stderr, "    GL_EXT_framebuffer_object\n");
 +	if (! GLEW_ARB_texture_env_combine)
 +	    fprintf (stderr, "    GL_ARB_texture_env_combine\n");
 +	if (! GLEW_ARB_texture_non_power_of_two)
 +	    fprintf (stderr, "    GL_ARB_texture_non_power_of_two\n");
 +
 +	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
 +    }
 +
 +    /* Set up the dummy texture for tex_env_combine with constant color. */
 +    glGenTextures (1, &ctx->dummy_tex);
 +    glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex);
 +    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
 +		  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +cairo_gl_context_t *
 +cairo_gl_context_reference (cairo_gl_context_t *context)
 +{
 +    if (context == NULL ||
 +	CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count))
 +    {
 +	return context;
 +    }
 +
 +    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
 +    _cairo_reference_count_inc (&context->ref_count);
 +
 +    return context;
 +}
 +slim_hidden_def (cairo_gl_context_reference);
 +
 +void
 +cairo_gl_context_destroy (cairo_gl_context_t *context)
 +{
 +    if (context == NULL ||
 +	CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count))
 +    {
 +	return;
 +    }
 +
 +    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
 +    if (! _cairo_reference_count_dec_and_test (&context->ref_count))
 +	return;
 +
 +    glDeleteTextures (1, &context->dummy_tex);
 +
 +    context->destroy (context);
 +
 +    free (context);
 +}
 +slim_hidden_def (cairo_gl_context_destroy);
 +
 +static cairo_gl_context_t *
 +_cairo_gl_context_acquire (cairo_gl_context_t *ctx)
 +{
 +    CAIRO_MUTEX_LOCK (ctx->mutex);
 +    return ctx;
 +}
 +
 +static void
 +_cairo_gl_context_release (cairo_gl_context_t *ctx)
 +{
 +    CAIRO_MUTEX_UNLOCK (ctx->mutex);
 +}
 +
 +static void
 +_cairo_gl_set_destination (cairo_gl_surface_t *surface)
 +{
 +    cairo_gl_context_t *ctx = surface->ctx;
 +
 +    if (ctx->current_target != surface) {
 +	ctx->current_target = surface;
 +
 +	if (surface->fb) {
 +	    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);
 +
 +    glMatrixMode (GL_PROJECTION);
 +    glLoadIdentity();
 +    if (surface->fb)
 +	glOrtho(0, surface->width, 0, surface->height, -1.0, 1.0);
 +    else
 +	glOrtho(0, surface->width, surface->height, 0, -1.0, 1.0);
 +
 +    glMatrixMode (GL_MODELVIEW);
 +    glLoadIdentity();
 +}
 +
 +static int
 +_cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op)
 +{
 +    struct {
 +	GLenum src;
 +	GLenum dst;
 +    } blend_factors[] = {
 +	{ GL_ZERO, GL_ZERO }, /* Clear */
 +	{ GL_ONE, GL_ZERO }, /* Source */
 +	{ GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */
 +	{ GL_DST_ALPHA, GL_ZERO }, /* In */
 +	{ GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */
 +	{ GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */
 +
 +	{ GL_ZERO, GL_ONE }, /* Dest */
 +	{ GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */
 +	{ GL_ZERO, GL_SRC_ALPHA }, /* DestIn */
 +	{ GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */
 +	{ GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */
 +
 +	{ GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
 +	{ GL_ONE, GL_ONE }, /* Add */
 +    };
 +    GLenum src_factor, dst_factor;
 +
 +    if (op >= ARRAY_SIZE (blend_factors))
 +	return CAIRO_INT_STATUS_UNSUPPORTED;
 +
 +    src_factor = blend_factors[op].src;
 +    dst_factor = blend_factors[op].dst;
 +
 +    /* We may have a visual with alpha bits despite the user requesting
 +     * CAIRO_CONTENT_COLOR.  So clear out those bits in that case.
 +     */
 +    if (dst->base.content == CAIRO_CONTENT_COLOR) {
 +	if (src_factor == GL_ONE_MINUS_DST_ALPHA)
 +	    src_factor = GL_ZERO;
 +	if (src_factor == GL_DST_ALPHA)
 +	    src_factor = GL_ONE;
 +    }
 +
 +    glBlendFunc (src_factor, dst_factor);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static void
 +_cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
 +			       cairo_surface_attributes_t *attributes)
 +{
 +    glActiveTexture (GL_TEXTURE0 + tex_unit);
 +    glBindTexture (GL_TEXTURE_2D, tex);
 +    switch (attributes->extend) {
 +    case CAIRO_EXTEND_NONE:
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
 +	break;
 +    case CAIRO_EXTEND_PAD:
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 +	break;
 +    case CAIRO_EXTEND_REPEAT:
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 +	break;
 +    case CAIRO_EXTEND_REFLECT:
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
 +	break;
 +    }
 +    switch (attributes->filter) {
 +    case CAIRO_FILTER_FAST:
 +    case CAIRO_FILTER_NEAREST:
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 +	break;
 +    case CAIRO_FILTER_GOOD:
 +    case CAIRO_FILTER_BEST:
 +    case CAIRO_FILTER_BILINEAR:
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 +	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 +	break;
 +    default:
 +    case CAIRO_FILTER_GAUSSIAN:
 +	ASSERT_NOT_REACHED;
 +    }
 +    glEnable (GL_TEXTURE_2D);
 +}
 +
 +void
 +_cairo_gl_surface_init (cairo_gl_context_t *ctx,
 +			cairo_gl_surface_t *surface,
 +			cairo_content_t content,
 +			int width, int height)
 +{
 +    _cairo_surface_init (&surface->base,
 +			 &_cairo_gl_surface_backend,
 +			 content);
 +
 +    surface->ctx = cairo_gl_context_reference (ctx);
 +    surface->width = width;
 +    surface->height = height;
 +}
 +
 +cairo_surface_t *
 +cairo_gl_surface_create (cairo_gl_context_t   *ctx,
 +			 cairo_content_t	content,
 +			 int			width,
 +			 int			height)
 +{
 +    cairo_gl_surface_t *surface;
 +    GLenum err, format;
 +    cairo_status_t status;
 +
 +    if (!CAIRO_CONTENT_VALID (content))
 +	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
 +
 +    if (ctx == NULL) {
 +	return cairo_image_surface_create (_cairo_format_from_content (content),
 +					   width, height);
 +    }
 +    if (ctx->status)
 +	return _cairo_surface_create_in_error (ctx->status);
 +
 +    surface = calloc (1, sizeof (cairo_gl_surface_t));
 +    if (unlikely (surface == NULL))
 +	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 +
 +    _cairo_gl_surface_init (ctx, surface, content, width, height);
 +
 +    switch (content) {
 +    default:
 +	ASSERT_NOT_REACHED;
 +    case CAIRO_CONTENT_COLOR_ALPHA:
 +	format = GL_RGBA;
 +	break;
 +    case CAIRO_CONTENT_ALPHA:
 +	format = GL_RGBA;
 +	break;
 +    case CAIRO_CONTENT_COLOR:
 +	format = GL_RGB;
 +	break;
 +    }
 +
 +    /* Create the texture used to store the surface's data. */
 +    glGenTextures (1, &surface->tex);
 +    glBindTexture (GL_TEXTURE_2D, surface->tex);
 +    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 +    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 +    glTexImage2D (GL_TEXTURE_2D, 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,
 +			       GL_TEXTURE_2D,
 +			       surface->tex,
 +			       0);
 +
 +    while ((err = glGetError ())) {
 +	fprintf(stderr, "GL error in surface create: 0x%08x\n", err);
 +    }
 +
 +    status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
 +    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
 +	fprintf(stderr, "destination is framebuffer incomplete\n");
 +
 +    /* Cairo surfaces start out initialized to transparent (black) */
 +    ctx = _cairo_gl_context_acquire (surface->ctx);
 +    _cairo_gl_set_destination (surface);
 +    glClearColor (0.0, 0.0, 0.0, 0.0);
 +    glClear (GL_COLOR_BUFFER_BIT);
 +    _cairo_gl_context_release (ctx);
 +
 +    return &surface->base;
 +}
 +slim_hidden_def (cairo_gl_surface_create);
 +
 +void
 +cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
 +			   int              width,
 +			   int              height)
 +{
 +    cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
 +    cairo_status_t status;
 +
 +    if (! _cairo_surface_is_gl (abstract_surface) || surface->fb) {
 +	status = _cairo_surface_set_error (abstract_surface,
 +		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
 +	return;
 +    }
 +
 +    surface->width = width;
 +    surface->height = height;
 +}
 +
 +int
 +cairo_gl_surface_get_width (cairo_surface_t *abstract_surface)
 +{
 +    cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
 +
 +    if (! _cairo_surface_is_gl (abstract_surface))
 +	return 0;
 +
 +    return surface->width;
 +}
 +
 +int
 +cairo_gl_surface_get_height (cairo_surface_t *abstract_surface)
 +{
 +    cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
 +
 +    if (! _cairo_surface_is_gl (abstract_surface))
 +	return 0;
 +
 +    return surface->height;
 +}
 +
 +
 +void
 +cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
 +{
 +    cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
 +    cairo_status_t status;
 +
 +    if (! _cairo_surface_is_gl (abstract_surface)) {
 +	status = _cairo_surface_set_error (abstract_surface,
 +		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
 +	return;
 +    }
 +
 +    if (! surface->fb)
 +	surface->ctx->swap_buffers (surface->ctx, surface);
 +}
 +
 +static cairo_surface_t *
 +_cairo_gl_surface_create_similar (void		 *abstract_surface,
 +				  cairo_content_t  content,
 +				  int		  width,
 +				  int		  height)
 +{
 +    cairo_gl_surface_t *surface = abstract_surface;
 +
 +    assert (CAIRO_CONTENT_VALID (content));
 +
 +    if (width < 1)
 +	width = 1;
 +    if (height < 1)
 +	height = 1;
 +
 +    return cairo_gl_surface_create (surface->ctx, content, width, height);
 +}
 +
 +static cairo_bool_t
 +_cairo_gl_surface_draw_image_format_compatible (cairo_image_surface_t *surface)
 +{
 +    if (surface->pixman_format == PIXMAN_a8r8g8b8 ||
 +	surface->pixman_format == PIXMAN_x8r8g8b8 ||
 +	surface->pixman_format == PIXMAN_a8)
 +	return TRUE;
 +    else
 +	return FALSE;
 +}
 +
 +static cairo_status_t
 +_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 +			      cairo_image_surface_t *src,
 +			      int src_x, int src_y,
 +			      int width, int height,
 +			      int dst_x, int dst_y)
 +{
 +    char *temp_data;
 +    int y;
 +    unsigned int cpp;
 +    GLenum format, type;
 +    char *src_data_start;
 +
 +    /* Want to use a switch statement here but the compiler gets whiny. */
 +    if (src->pixman_format == PIXMAN_a8r8g8b8) {
 +	format = GL_BGRA;
 +	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 +	cpp = 4;
 +    } else if (src->pixman_format == PIXMAN_x8r8g8b8) {
 +	assert(dst->base.content != CAIRO_CONTENT_COLOR_ALPHA);
 +	assert(dst->base.content != CAIRO_CONTENT_ALPHA);
 +	format = GL_BGRA;
 +	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 +	cpp = 4;
 +    } else if (src->pixman_format == PIXMAN_a8) {
 +	format = GL_ALPHA;
 +	type = GL_UNSIGNED_BYTE;
 +	cpp = 1;
 +    } else {
 +	fprintf(stderr, "draw_image fallback\n");
 +	return CAIRO_INT_STATUS_UNSUPPORTED;
 +    }
 +
 +    /* Write the data to a temporary as GL wants bottom-to-top data
 +     * screen-wise, and we want top-to-bottom.
 +     */
 +    temp_data = malloc (width * height * cpp);
 +    if (temp_data == NULL)
 +	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 +
 +    src_data_start = (char *)src->data + (src_y * src->stride) + (src_x * cpp);
 +    for (y = 0; y < height; y++) {
 +	memcpy (temp_data + y * width * cpp, src_data_start +
 +		y * src->stride,
 +		width * cpp);
 +    }
 +
 +    _cairo_gl_set_destination (dst);
 +    glRasterPos2i (dst_x, dst_y);
 +    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 +    glDrawPixels (width, height, format, type, temp_data);
 +
 +    free (temp_data);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static cairo_status_t
 +_cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
 +			     cairo_rectangle_int_t   *interest,
 +			     cairo_image_surface_t  **image_out,
 +			     cairo_rectangle_int_t   *rect_out)
 +{
 +    cairo_image_surface_t *image;
 +    cairo_rectangle_int_t extents;
 +    GLenum err;
 +    char *temp_data;
-     unsigned int y;
++    int y;
 +    unsigned int cpp;
 +    GLenum format, type;
 +    cairo_format_t cairo_format;
 +
 +    extents.x = 0;
 +    extents.y = 0;
 +    extents.width  = surface->width;
 +    extents.height = surface->height;
 +
 +    if (interest != NULL) {
 +	if (! _cairo_rectangle_intersect (&extents, interest)) {
 +	    *image_out = NULL;
 +	    return CAIRO_STATUS_SUCCESS;
 +	}
 +    }
 +
 +    if (rect_out != NULL)
 +	*rect_out = extents;
 +
 +    /* Want to use a switch statement here but the compiler gets whiny. */
 +    if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
 +	format = GL_BGRA;
 +	cairo_format = CAIRO_FORMAT_ARGB32;
 +	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 +	cpp = 4;
 +    } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
 +	format = GL_BGRA;
 +	cairo_format = CAIRO_FORMAT_RGB24;
 +	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 +	cpp = 4;
 +    } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
 +	format = GL_ALPHA;
 +	cairo_format = CAIRO_FORMAT_A8;
 +	type = GL_UNSIGNED_BYTE;
 +	cpp = 1;
 +    } else {
 +	fprintf(stderr, "get_image fallback: %d\n", surface->base.content);
 +	return CAIRO_INT_STATUS_UNSUPPORTED;
 +    }
 +
 +    image = (cairo_image_surface_t*)
 +	cairo_image_surface_create (cairo_format,
 +				    extents.width, extents.height);
 +    if (image->base.status)
 +	return image->base.status;
 +
 +    /* This is inefficient, as we'd rather just read the thing without making
 +     * it the destination.  But then, this is the fallback path, so let's not
 +     * fall back instead.
 +     */
 +    _cairo_gl_set_destination(surface);
 +
 +    /* Read the data to a temporary as GL gives us bottom-to-top data
 +     * screen-wise, and we want top-to-bottom.
 +     */
 +    temp_data = malloc (extents.width * extents.height * cpp);
 +    if (temp_data == NULL)
 +	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 +
 +    glPixelStorei(GL_PACK_ALIGNMENT, 1);
 +    glReadPixels(extents.x, extents.y,
 +		 extents.width, extents.height,
 +		 format, type, temp_data);
 +
 +    for (y = 0; y < extents.height; y++) {
 +	memcpy ((char *)image->data + y * image->stride,
 +		temp_data + y * extents.width * cpp,
 +		extents.width * cpp);
 +    }
 +    free (temp_data);
 +
 +    *image_out = image;
 +
 +    while ((err = glGetError ()))
 +	fprintf(stderr, "GL error 0x%08x\n", (int) err);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static cairo_status_t
 +_cairo_gl_surface_finish (void *abstract_surface)
 +{
 +    cairo_gl_surface_t *surface = abstract_surface;
 +
 +    glDeleteFramebuffersEXT (1, &surface->fb);
 +    glDeleteTextures (1, &surface->tex);
 +
 +    if (surface->ctx->current_target == surface)
 +	surface->ctx->current_target = NULL;
 +
 +    cairo_gl_context_destroy(surface->ctx);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static cairo_status_t
 +_cairo_gl_surface_acquire_source_image (void		       *abstract_surface,
 +					cairo_image_surface_t **image_out,
 +					void		      **image_extra)
 +{
 +    cairo_gl_surface_t *surface = abstract_surface;
 +
 +    *image_extra = NULL;
 +
 +    return _cairo_gl_surface_get_image (surface, NULL, image_out, NULL);
 +}
 +
 +static void
 +_cairo_gl_surface_release_source_image (void		      *abstract_surface,
 +					cairo_image_surface_t *image,
 +					void		      *image_extra)
 +{
 +    cairo_surface_destroy (&image->base);
 +}
 +
 +static cairo_status_t
 +_cairo_gl_surface_acquire_dest_image (void		      *abstract_surface,
 +				      cairo_rectangle_int_t   *interest_rect,
 +				      cairo_image_surface_t  **image_out,
 +				      cairo_rectangle_int_t   *image_rect_out,
 +				      void		     **image_extra)
 +{
 +    cairo_gl_surface_t *surface = abstract_surface;
 +
 +    *image_extra = NULL;
 +    return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
 +					image_rect_out);
 +}
 +
 +static void
 +_cairo_gl_surface_release_dest_image (void		      *abstract_surface,
 +				      cairo_rectangle_int_t   *interest_rect,
 +				      cairo_image_surface_t   *image,
 +				      cairo_rectangle_int_t   *image_rect,
 +				      void		      *image_extra)
 +{
 +    cairo_status_t status;
 +
 +    status = _cairo_gl_surface_draw_image (abstract_surface, image,
 +					   0, 0,
 +					   image->width, image->height,
 +					   image_rect->x, image_rect->y);
 +    if (status)
 +	status = _cairo_surface_set_error (abstract_surface, status);
 +
 +    cairo_surface_destroy (&image->base);
 +}
 +
 +static cairo_status_t
 +_cairo_gl_surface_clone_similar (void		     *abstract_surface,
 +				 cairo_surface_t     *src,
++				 cairo_content_t      content,
 +				 int                  src_x,
 +				 int                  src_y,
 +				 int                  width,
 +				 int                  height,
 +				 int                 *clone_offset_x,
 +				 int                 *clone_offset_y,
 +				 cairo_surface_t    **clone_out)
 +{
 +    cairo_gl_surface_t *surface = abstract_surface;
 +
 +    if (src->backend == surface->base.backend) {
 +	*clone_offset_x = 0;
 +	*clone_offset_y = 0;
 +	*clone_out = cairo_surface_reference (src);
 +
 +	return CAIRO_STATUS_SUCCESS;
 +    } else if (_cairo_surface_is_image (src)) {
 +	cairo_gl_surface_t *clone;
 +	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
 +	cairo_status_t status;
 +
 +	if (!_cairo_gl_surface_draw_image_format_compatible (image_src))
 +	    return CAIRO_INT_STATUS_UNSUPPORTED;
 +
 +	clone = (cairo_gl_surface_t *)
 +	    _cairo_gl_surface_create_similar (&surface->base,
- 		                              src->content,
++		                              content,
 +					      width, height);
 +	if (clone == NULL)
 +	    return CAIRO_INT_STATUS_UNSUPPORTED;
 +	if (clone->base.status)
 +	    return clone->base.status;
 +
 +	status = _cairo_gl_surface_draw_image (clone, image_src,
 +					       src_x, src_y,
 +					       width, height,
 +					       0, 0);
 +	if (status) {
 +	    cairo_surface_destroy (&clone->base);
 +	    return status;
 +	}
 +
 +	*clone_out = &clone->base;
 +	*clone_offset_x = src_x;
 +	*clone_offset_y = src_y;
 +
 +	return CAIRO_STATUS_SUCCESS;
 +    }
 +
 +    return CAIRO_INT_STATUS_UNSUPPORTED;
 +}
 +
 +/** Creates a cairo-gl pattern surface for the given trapezoids */
 +static cairo_status_t
 +_cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
 +			     int dst_x, int dst_y,
 +			     int width, int height,
 +			     cairo_trapezoid_t *traps,
 +			     int num_traps,
 +			     cairo_antialias_t antialias,
 +			     cairo_pattern_t **pattern)
 +{
 +    pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
 +    pixman_trapezoid_t *pixman_traps;
 +    cairo_image_surface_t *image_surface;
 +    int i;
 +
 +    /* Convert traps to pixman traps */
 +    pixman_traps = stack_traps;
 +    if (num_traps > ARRAY_LENGTH (stack_traps)) {
 +	pixman_traps = _cairo_malloc_ab (num_traps, sizeof (pixman_trapezoid_t));
 +	if (unlikely (pixman_traps == NULL))
 +	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 +    }
 +
 +    for (i = 0; i < num_traps; i++) {
 +	pixman_traps[i].top = _cairo_fixed_to_16_16 (traps[i].top);
 +	pixman_traps[i].bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
 +	pixman_traps[i].left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
 +	pixman_traps[i].left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
 +	pixman_traps[i].left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
 +	pixman_traps[i].left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
 +	pixman_traps[i].right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
 +	pixman_traps[i].right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
 +	pixman_traps[i].right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
 +	pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
 +    }
 +
 +    if (antialias != CAIRO_ANTIALIAS_NONE) {
 +	image_surface = (cairo_image_surface_t*)
 +	    cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
 +    } else {
 +	image_surface = (cairo_image_surface_t*)
 +	    cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
 +    }
 +
 +    if (image_surface->base.status) {
 +	if (pixman_traps != stack_traps)
 +	    free (pixman_traps);
 +	return image_surface->base.status;
 +    }
 +
 +    pixman_add_trapezoids (image_surface->pixman_image, -dst_x, -dst_y,
 +			   num_traps, pixman_traps);
 +
 +    if (pixman_traps != stack_traps)
 +	free (pixman_traps);
 +
 +    *pattern = cairo_pattern_create_for_surface (&image_surface->base);
 +    cairo_surface_destroy (&image_surface->base);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static cairo_status_t
 +_cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 +				       const cairo_pattern_t *src,
 +				       cairo_gl_surface_t *dst,
 +				       int src_x, int src_y,
 +				       int dst_x, int dst_y,
 +				       int width, int height)
 +{
 +    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src;
 +    cairo_image_surface_t *image_surface;
 +    cairo_matrix_t m;
 +    cairo_surface_attributes_t *attributes;
 +    GLuint tex;
 +    GLenum format, internal_format, type;
 +
 +    if (src->type != CAIRO_PATTERN_TYPE_SURFACE)
 +	return CAIRO_INT_STATUS_UNSUPPORTED;
 +
 +    if (!_cairo_surface_is_image (surface_pattern->surface))
 +	return CAIRO_INT_STATUS_UNSUPPORTED;
 +
 +    image_surface = (cairo_image_surface_t *)surface_pattern->surface;
 +
 +    /* The textures we create almost always has appropriate alpha channel
 +     * contents.  But sometimes GL sucks at image specification and we end up
 +     * with junk in the alpha.
 +     */
 +    operand->operand.texture.has_alpha = TRUE;
 +
 +    switch (image_surface->pixman_format) {
 +    case PIXMAN_a8r8g8b8:
 +	internal_format = GL_RGBA;
 +	format = GL_BGRA;
 +	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 +	break;
 +    case PIXMAN_x8r8g8b8:
 +	internal_format = GL_RGB;
 +	format = GL_BGRA;
 +	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 +	operand->operand.texture.has_alpha = FALSE;
 +	break;
 +    case PIXMAN_a8b8g8r8:
 +	internal_format = GL_RGBA;
 +	format = GL_RGBA;
 +	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 +	break;
 +    case PIXMAN_x8b8g8r8:
 +	internal_format = GL_RGB;
 +	format = GL_RGBA;
 +	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 +	operand->operand.texture.has_alpha = FALSE;
 +	break;
 +    case PIXMAN_b8g8r8a8:
 +	internal_format = GL_BGRA;
 +	format = GL_BGRA;
 +	type = GL_UNSIGNED_INT_8_8_8_8;
 +	break;
 +    case PIXMAN_r8g8b8:
 +	internal_format = GL_RGB;
 +	format = GL_RGB;
 +	type = GL_UNSIGNED_BYTE;
 +	break;
 +    case PIXMAN_b8g8r8:
 +	internal_format = GL_RGB;
 +	format = GL_BGR;
 +	type = GL_UNSIGNED_BYTE;
 +	break;
 +    case PIXMAN_r5g6b5:
 +	internal_format = GL_RGB;
 +	format = GL_RGB;
 +	type = GL_UNSIGNED_SHORT_5_6_5;
 +	break;
 +    case PIXMAN_a8:
 +	internal_format = GL_ALPHA;
 +	format = GL_ALPHA;
 +	type = GL_UNSIGNED_BYTE;
 +	break;
 +
 +    case PIXMAN_b5g6r5:
 +    case PIXMAN_a1r5g5b5:
 +    case PIXMAN_x1r5g5b5:
 +    case PIXMAN_a1b5g5r5:
 +    case PIXMAN_x1b5g5r5:
 +    case PIXMAN_a2b10g10r10:
 +    case PIXMAN_x2b10g10r10:
 +    case PIXMAN_a4r4g4b4:
 +    case PIXMAN_x4r4g4b4:
 +    case PIXMAN_a4b4g4r4:
 +    case PIXMAN_x4b4g4r4:
 +    case PIXMAN_r3g3b2:
 +    case PIXMAN_b2g3r3:
 +    case PIXMAN_a2r2g2b2:
 +    case PIXMAN_a2b2g2r2:
 +    case PIXMAN_c8:
 +    case PIXMAN_x4a4:
 +    /* case PIXMAN_x4c4: */
 +    case PIXMAN_x4g4:
 +    case PIXMAN_a4:
 +    case PIXMAN_r1g2b1:
 +    case PIXMAN_b1g2r1:
 +    case PIXMAN_a1r1g1b1:
 +    case PIXMAN_a1b1g1r1:
 +    case PIXMAN_c4:
 +    case PIXMAN_g4:
 +    case PIXMAN_a1:
 +    case PIXMAN_g1:
 +    case PIXMAN_yuy2:
 +    case PIXMAN_yv12:
 +    case PIXMAN_b8g8r8x8:
 +    default:
 +	return CAIRO_INT_STATUS_UNSUPPORTED;
 +    }
 +
 +    glGenTextures (1, &tex);
 +    glBindTexture (GL_TEXTURE_2D, tex);
 +    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
 +    assert(((image_surface->stride * image_surface->depth) %
 +	    image_surface->depth) == 0);
 +    glPixelStorei (GL_UNPACK_ROW_LENGTH,
 +		   image_surface->stride /
 +		   (PIXMAN_FORMAT_BPP(image_surface->pixman_format) / 8));
 +    /* The filter will be correctly set up later, but for now we want to
 +     * hint to glTexImage that we're not mipmapping.
 +     */
 +    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 +    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 +    glTexImage2D (GL_TEXTURE_2D, 0, internal_format,
 +		  image_surface->width, image_surface->height, 0,
 +		  format, type, image_surface->data);
 +    glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
 +
 +    attributes = &operand->operand.texture.attributes;
 +
 +    operand->type = OPERAND_TEXTURE;
 +    operand->operand.texture.tex = tex;
 +    operand->operand.texture.surface = NULL;
 +    attributes->matrix = src->matrix;
 +    attributes->extend = src->extend;
 +    attributes->filter = src->filter;
 +    /* Demote the filter if we're doing a 1:1 mapping of pixels. */
 +    if ((src->filter == CAIRO_FILTER_GOOD ||
 +	 src->filter == CAIRO_FILTER_BEST ||
 +	 src->filter == CAIRO_FILTER_BILINEAR) &&
 +	_cairo_matrix_is_pixel_exact (&src->matrix)) {
 +	attributes->filter = CAIRO_FILTER_NEAREST;
 +    }
 +
 +    attributes->x_offset = 0;
 +    attributes->y_offset = 0;
 +
 +
 +    /* Set up translation matrix for
 +     * (unnormalized dst -> unnormalized src)
 +     */
 +    cairo_matrix_init_translate (&m,
 +				 src_x - dst_x,
 +				 src_y - dst_y);
 +    cairo_matrix_multiply(&attributes->matrix,
 +			  &m,
 +			  &attributes->matrix);
 +
 +    /* Translate the matrix from
 +     * (unnormalized src -> unnormalized src) to
 +     * (unnormalized dst -> normalized src)
 +     */
 +    cairo_matrix_init_scale (&m,
 +			     1.0 / image_surface->width,
 +			     1.0 / image_surface->height);
 +    cairo_matrix_multiply (&attributes->matrix,
 +			   &attributes->matrix,
 +			   &m);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +/**
 + * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
 + * from dest to src coords.
 + */
 +static cairo_status_t
 +_cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
 +				 const cairo_pattern_t *src,
 +				 cairo_gl_surface_t *dst,
 +				 int src_x, int src_y,
 +				 int dst_x, int dst_y,
 +				 int width, int height)
 +{
 +    cairo_status_t status;
 +    cairo_matrix_t m;
 +    cairo_gl_surface_t *surface;
 +    cairo_surface_attributes_t *attributes;
 +
 +    attributes = &operand->operand.texture.attributes;
 +
 +    /* First, try to just upload it to a texture if it's an image surface. */
 +    status = _cairo_gl_pattern_image_texture_setup (operand, src, dst,
 +						    src_x, src_y,
 +						    dst_x, dst_y,
 +						    width, height);
 +    if (status == CAIRO_STATUS_SUCCESS)
 +	return CAIRO_STATUS_SUCCESS;
 +
 +    /* Avoid looping in acquire surface fallback -> clone similar -> paint ->
 +     * gl_composite -> acquire surface -> fallback.
 +     */
 +    if (src->type == CAIRO_PATTERN_TYPE_SURFACE) {
 +	cairo_surface_pattern_t *surface_pattern;
 +	cairo_image_surface_t *image_surface;
 +
 +	surface_pattern = (cairo_surface_pattern_t *)src;
 +	if (_cairo_surface_is_image (surface_pattern->surface)) {
 +	    image_surface = (cairo_image_surface_t *)surface_pattern->surface;
 +	    if (!_cairo_gl_surface_draw_image_format_compatible (image_surface))
 +		return CAIRO_INT_STATUS_UNSUPPORTED;
 +	}
 +    }
 +
 +    status = _cairo_pattern_acquire_surface (src, &dst->base,
++					     CAIRO_CONTENT_COLOR_ALPHA,
 +					     src_x, src_y,
 +					     width, height,
 +					     (cairo_surface_t **)
 +					     &surface,
 +					     attributes);
 +    operand->operand.texture.surface = surface;
 +    if (unlikely (status))
 +	return status;
 +
 +    assert(surface->base.backend == &_cairo_gl_surface_backend);
 +
 +    operand->operand.texture.tex = surface->tex;
 +    switch (surface->base.content) {
 +    case CAIRO_CONTENT_ALPHA:
 +    case CAIRO_CONTENT_COLOR_ALPHA:
 +	operand->operand.texture.has_alpha = TRUE;
 +	break;
 +    case CAIRO_CONTENT_COLOR:
 +	operand->operand.texture.has_alpha = FALSE;
 +	break;
 +    }
 +
 +    /* Translate the matrix from
 +     * (unnormalized src -> unnormalized src) to
 +     * (unnormalized dst -> unnormalized src)
 +     */
 +    cairo_matrix_init_translate (&m,
 +				 src_x - dst_x + attributes->x_offset,
 +				 src_y - dst_y + attributes->y_offset);
 +    cairo_matrix_multiply (&attributes->matrix,
 +			   &m,
 +			   &attributes->matrix);
 +
 +
 +    /* Translate the matrix from
 +     * (unnormalized src -> unnormalized src) to
 +     * (unnormalized dst -> normalized src)
 +     */
 +    cairo_matrix_init_scale (&m,
 +			     1.0 / surface->width,
 +			     1.0 / surface->height);
 +    cairo_matrix_multiply (&attributes->matrix,
 +			   &attributes->matrix,
 +			   &m);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static cairo_int_status_t
 +_cairo_gl_operand_init(cairo_gl_composite_operand_t *operand,
 +		       const cairo_pattern_t *pattern,
 +		       cairo_gl_surface_t *dst,
 +		       int src_x, int src_y,
 +		       int dst_x, int dst_y,
 +		       int width, int height)
 +{
 +    cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern;
 +
 +    operand->pattern = pattern;
 +
 +    switch (pattern->type) {
 +    case CAIRO_PATTERN_TYPE_SOLID:
 +	operand->type = OPERAND_CONSTANT;
 +	operand->operand.constant.color[0] = solid->color.red * solid->color.alpha;
 +	operand->operand.constant.color[1] = solid->color.green * solid->color.alpha;
 +	operand->operand.constant.color[2] = solid->color.blue * solid->color.alpha;
 +	operand->operand.constant.color[3] = solid->color.alpha;
 +	return CAIRO_STATUS_SUCCESS;
 +    default:
 +    case CAIRO_PATTERN_TYPE_SURFACE:
 +    case CAIRO_PATTERN_TYPE_LINEAR:
 +    case CAIRO_PATTERN_TYPE_RADIAL:
 +	operand->type = OPERAND_TEXTURE;
 +	return _cairo_gl_pattern_texture_setup(operand,
 +					       pattern, dst,
 +					       src_x, src_y,
 +					       dst_x, dst_y,
 +					       width, height);
 +    }
 +}
 +
 +static void
 +_cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand)
 +{
 +    switch (operand->type) {
 +    case OPERAND_CONSTANT:
 +	break;
 +    case OPERAND_TEXTURE:
 +	if (operand->operand.texture.surface != NULL) {
 +	    cairo_gl_surface_t *surface = operand->operand.texture.surface;
 +
 +	    _cairo_pattern_release_surface (operand->pattern,
 +					    &surface->base,
 +					    &operand->operand.texture.attributes);
 +	} else {
 +	    glDeleteTextures (1, &operand->operand.texture.tex);
 +	}
 +	break;
 +    }
 +}
 +
 +static void
 +_cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx, int tex_unit,
 +					  GLfloat *color)
 +{
 +    glActiveTexture (GL_TEXTURE0 + tex_unit);
 +    /* Have to have a dummy texture bound in order to use the combiner unit. */
 +    glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex);
 +    glEnable (GL_TEXTURE_2D);
 +
 +    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
 +    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 +    if (tex_unit == 0) {
 +	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
 +	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
 +    } else {
 +	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
 +	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
 +    }
 +    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
 +    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
 +    if (tex_unit == 0) {
 +	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 +	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 +    } else {
 +	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
 +	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 +
 +	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
 +	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
 +	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 +	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 +    }
 +}
 +
 +static cairo_int_status_t
 +_cairo_gl_surface_composite (cairo_operator_t		  op,
 +			     const cairo_pattern_t	 *src,
 +			     const cairo_pattern_t	 *mask,
 +			     void			 *abstract_dst,
 +			     int			  src_x,
 +			     int			  src_y,
 +			     int			  mask_x,
 +			     int			  mask_y,
 +			     int			  dst_x,
 +			     int			  dst_y,
 +			     unsigned int		  width,
 +			     unsigned int		  height)
 +{
 +    cairo_gl_surface_t	*dst = abstract_dst;
 +    cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL;
 +    cairo_gl_context_t *ctx;
 +    GLfloat vertices[4][2];
 +    GLfloat texcoord_src[4][2];
 +    GLfloat texcoord_mask[4][2];
 +    cairo_status_t status;
 +    int i;
 +    GLenum err;
 +    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
 +    cairo_gl_composite_setup_t setup;
 +
 +    memset(&setup, 0, sizeof(setup));
 +
 +    status = _cairo_gl_operand_init (&setup.src, src, dst,
 +				     src_x, src_y,
 +				     dst_x, dst_y,
 +				     width, height);
 +    if (unlikely (status))
 +	return status;
 +    src_attributes = &setup.src.operand.texture.attributes;
 +
 +    if (mask != NULL && _cairo_pattern_is_opaque(mask))
 +	mask = NULL;
 +
 +    if (mask != NULL) {
 +	status = _cairo_gl_operand_init (&setup.mask, mask, dst,
 +					 mask_x, mask_y,
 +					 dst_x, dst_y,
 +					 width, height);
 +	if (unlikely (status)) {
 +	    _cairo_gl_operand_destroy (&setup.src);
 +	    return status;
 +	}
 +	mask_attributes = &setup.mask.operand.texture.attributes;
 +    }
 +
 +    ctx = _cairo_gl_context_acquire (dst->ctx);
 +    _cairo_gl_set_destination (dst);
 +    status = _cairo_gl_set_operator (dst, op);
 +    if (status != CAIRO_STATUS_SUCCESS) {
 +	_cairo_gl_operand_destroy (&setup.src);
 +	if (mask != NULL)
 +	    _cairo_gl_operand_destroy (&setup.mask);
 +	_cairo_gl_context_release (ctx);
 +	return status;
 +    }
 +
 +    glEnable (GL_BLEND);
 +
 +    switch (setup.src.type) {
 +    case OPERAND_CONSTANT:
 +	_cairo_gl_set_tex_combine_constant_color (ctx, 0,
 +	    setup.src.operand.constant.color);
 +	break;
 +    case OPERAND_TEXTURE:
 +	_cairo_gl_set_texture_surface (0, setup.src.operand.texture.tex,
 +				       src_attributes);
 +	/* Set up the constant color we use to set alpha to 1 if needed. */
 +	glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
 +	/* Set up the combiner to just set color to the sampled texture. */
 +	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 +	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
 +	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
 +
 +	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
 +	/* Wire the src alpha to 1 if the surface doesn't have it.
 +	 * We may have a teximage with alpha bits even though we didn't ask
 +	 * for it and we don't pay attention to setting alpha to 1 in a dest
 +	 * that has inadvertent alpha.
 +	 */
 +	if (setup.src.operand.texture.has_alpha)
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
 +	else
 +	    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;
 +    }
 +
 +    if (mask != NULL) {
 +	switch (setup.mask.type) {
 +	case OPERAND_CONSTANT:
 +	    _cairo_gl_set_tex_combine_constant_color (ctx, 1,
 +		setup.mask.operand.constant.color);
 +	    break;
 +	case OPERAND_TEXTURE:
 +	    _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex,
 +					   mask_attributes);
 +
 +	    /* IN: dst.argb = src.argb * mask.aaaa */
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
 +
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 +
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
 +	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 +	    break;
 +	}
 +    }
 +
 +    vertices[0][0] = dst_x;
 +    vertices[0][1] = dst_y;
 +    vertices[1][0] = dst_x + width;
 +    vertices[1][1] = dst_y;
 +    vertices[2][0] = dst_x + width;
 +    vertices[2][1] = dst_y + height;
 +    vertices[3][0] = dst_x;
 +    vertices[3][1] = dst_y + height;
 +
 +    glVertexPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, vertices);
 +    glEnableClientState (GL_VERTEX_ARRAY);
 +
 +    if (setup.src.type == OPERAND_TEXTURE) {
 +	for (i = 0; i < 4; i++) {
 +	    double s, t;
 +
 +	    s = vertices[i][0];
 +	    t = vertices[i][1];
 +	    cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
 +	    texcoord_src[i][0] = s;
 +	    texcoord_src[i][1] = t;
 +	}
 +
 +	glClientActiveTexture (GL_TEXTURE0);
 +	glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_src);
 +	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
 +    }
 +
 +    if (mask != NULL) {
 +	if (setup.mask.type == OPERAND_TEXTURE) {
 +	    for (i = 0; i < 4; i++) {
 +		double s, t;
 +
 +		s = vertices[i][0];
 +		t = vertices[i][1];
 +		cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t);
 +		texcoord_mask[i][0] = s;
 +		texcoord_mask[i][1] = t;
 +	    }
 +
 +	    glClientActiveTexture (GL_TEXTURE1);
 +	    glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_mask);
 +	    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
 +	}
 +    }
 +
 +    glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
 +
 +    glDisable (GL_BLEND);
 +
 +    glDisableClientState (GL_VERTEX_ARRAY);
 +
 +    glClientActiveTexture (GL_TEXTURE0);
 +    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 +    glActiveTexture (GL_TEXTURE0);
 +    glDisable (GL_TEXTURE_2D);
 +
 +    glClientActiveTexture (GL_TEXTURE1);
 +    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 +    glActiveTexture (GL_TEXTURE1);
 +    glDisable (GL_TEXTURE_2D);
 +
 +    while ((err = glGetError ()))
 +	fprintf(stderr, "GL error 0x%08x\n", (int) err);
 +
 +    _cairo_gl_context_release (ctx);
 +
 +    _cairo_gl_operand_destroy (&setup.src);
 +    if (mask != NULL)
 +	_cairo_gl_operand_destroy (&setup.mask);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static cairo_int_status_t
 +_cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
 +					const cairo_pattern_t *pattern,
 +					void *abstract_dst,
 +					cairo_antialias_t antialias,
 +					int src_x, int src_y,
 +					int dst_x, int dst_y,
 +					unsigned int width,
 +					unsigned int height,
 +					cairo_trapezoid_t *traps,
 +					int num_traps)
 +{
 +    cairo_gl_surface_t *dst = abstract_dst;
 +    cairo_pattern_t *traps_pattern;
 +    cairo_int_status_t status;
 +
 +    status = _cairo_gl_get_traps_pattern (dst,
 +					  dst_x, dst_y, width, height,
 +					  traps, num_traps, antialias,
 +					  &traps_pattern);
 +    if (status) {
 +	fprintf(stderr, "traps falllback\n");
 +	return status;
 +    }
 +
 +    status = _cairo_gl_surface_composite (op, pattern, traps_pattern, dst,
 +					  src_x, src_y,
 +					  0, 0,
 +					  dst_x, dst_y,
 +					  width, height);
 +    cairo_pattern_destroy (traps_pattern);
 +
 +    return status;
 +}
 +
 +static cairo_int_status_t
 +_cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
 +				   cairo_operator_t	    op,
 +				   const cairo_color_t     *color,
 +				   cairo_rectangle_int_t   *rects,
 +				   int			    num_rects)
 +{
 +    cairo_gl_surface_t *surface = abstract_surface;
 +    cairo_gl_context_t *ctx;
 +    cairo_int_status_t status;
 +    int i;
 +    GLfloat *vertices;
 +    GLfloat *colors;
 +
 +    ctx = _cairo_gl_context_acquire (surface->ctx);
 +
 +    _cairo_gl_set_destination (surface);
 +    status = _cairo_gl_set_operator (surface, op);
 +    if (status != CAIRO_STATUS_SUCCESS) {
 +	_cairo_gl_context_release (ctx);
 +	return status;
 +    }
 +
 +    vertices = _cairo_malloc_ab(num_rects, sizeof(GLfloat) * 4 * 2);
 +    colors = _cairo_malloc_ab(num_rects, sizeof(GLfloat) * 4 * 4);
 +    if (!vertices || !colors) {
 +	_cairo_gl_context_release(ctx);
 +	free(vertices);
 +	free(colors);
 +	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 +    }
 +
 +    /* This should be loaded in as either a blend constant and an operator
 +     * setup specific to this, or better, a fragment shader constant.
 +     */
 +    for (i = 0; i < num_rects * 4; i++) {
 +	colors[i * 4 + 0] = color->red * color->alpha;
 +	colors[i * 4 + 1] = color->green * color->alpha;
 +	colors[i * 4 + 2] = color->blue * color->alpha;
 +	colors[i * 4 + 3] = color->alpha;
 +    }
 +
 +    for (i = 0; i < num_rects; i++) {
 +	vertices[i * 8 + 0] = rects[i].x;
 +	vertices[i * 8 + 1] = rects[i].y;
 +	vertices[i * 8 + 2] = rects[i].x + rects[i].width;
 +	vertices[i * 8 + 3] = rects[i].y;
 +	vertices[i * 8 + 4] = rects[i].x + rects[i].width;
 +	vertices[i * 8 + 5] = rects[i].y + rects[i].height;
 +	vertices[i * 8 + 6] = rects[i].x;
 +	vertices[i * 8 + 7] = rects[i].y + rects[i].height;
 +    }
 +
 +    glEnable (GL_BLEND);
 +    glVertexPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, vertices);
 +    glEnableClientState (GL_VERTEX_ARRAY);
 +    glColorPointer (4, GL_FLOAT, sizeof(GLfloat) * 4, colors);
 +    glEnableClientState (GL_COLOR_ARRAY);
 +    glDrawArrays (GL_TRIANGLE_FAN, 0, 4 * num_rects);
 +
 +    glDisableClientState (GL_COLOR_ARRAY);
 +    glDisableClientState (GL_VERTEX_ARRAY);
 +    glDisable (GL_BLEND);
 +
 +    _cairo_gl_context_release (ctx);
 +    free(vertices);
 +    free(colors);
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static cairo_int_status_t
 +_cairo_gl_surface_get_extents (void		     *abstract_surface,
 +			       cairo_rectangle_int_t *rectangle)
 +{
 +    cairo_gl_surface_t *surface = abstract_surface;
 +
 +    rectangle->x = 0;
 +    rectangle->y = 0;
 +    rectangle->width  = surface->width;
 +    rectangle->height = surface->height;
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
 +static const cairo_surface_backend_t _cairo_gl_surface_backend = {
 +    CAIRO_SURFACE_TYPE_GL,
 +    _cairo_gl_surface_create_similar,
 +    _cairo_gl_surface_finish,
 +    _cairo_gl_surface_acquire_source_image,
 +    _cairo_gl_surface_release_source_image,
 +    _cairo_gl_surface_acquire_dest_image,
 +    _cairo_gl_surface_release_dest_image,
 +    _cairo_gl_surface_clone_similar,
 +    _cairo_gl_surface_composite,
 +    _cairo_gl_surface_fill_rectangles,
 +    _cairo_gl_surface_composite_trapezoids,
 +    NULL, /* create_span_renderer */
 +    NULL, /* check_span_renderer */
 +    NULL, /* copy_page */
 +    NULL, /* show_page */
 +    NULL, /* set_clip_region */
 +    NULL, /* intersect_clip_path */
 +    _cairo_gl_surface_get_extents,
 +    NULL, /* old_show_glyphs */
 +    NULL, /* get_font_options */
 +    NULL, /* flush */
 +    NULL, /* mark_dirty_rectangle */
 +    NULL, /* scaled_font_fini */
 +    NULL, /* scaled_glyph_fini */
 +    NULL, /* paint */
 +    NULL, /* mask */
 +    NULL, /* stroke */
 +    NULL, /* fill */
 +    NULL, /* show_glyphs */
 +    NULL  /* snapshot */
 +};
 +
 +/** Call glFinish(), used for accurate performance testing. */
 +cairo_status_t
 +cairo_gl_surface_glfinish (cairo_surface_t *surface)
 +{
 +    glFinish();
 +
 +    return CAIRO_STATUS_SUCCESS;
 +}
diff --cc src/cairo.h
index e35c9ca,b9c47db..4350bc1
--- a/src/cairo.h
+++ b/src/cairo.h
@@@ -1877,9 -1888,7 +1888,8 @@@ cairo_surface_status (cairo_surface_t *
   * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2
   * @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface
   * @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image
-  * @CAIRO_SURFACE_TYPE_SDL: The surface is of type SDL, since 1.10
   * @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10
 + * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10
   *
   * #cairo_surface_type_t is used to describe the type of a given
   * surface. The surface types are also known as "backends" or "surface
@@@ -1919,9 -1928,7 +1929,8 @@@ typedef enum _cairo_surface_type 
      CAIRO_SURFACE_TYPE_OS2,
      CAIRO_SURFACE_TYPE_WIN32_PRINTING,
      CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
-     CAIRO_SURFACE_TYPE_SDL,
 -    CAIRO_SURFACE_TYPE_SCRIPT
 +    CAIRO_SURFACE_TYPE_SCRIPT,
 +    CAIRO_SURFACE_TYPE_GL,
  } cairo_surface_type_t;
  
  cairo_public cairo_surface_type_t
diff --cc test/Makefile.am
index 567e684,ef2d875..bd5cf27
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@@ -224,21 -18,11 +18,21 @@@ endi
  
  # Need to add quartz-surface-source
  if CAIRO_HAS_QUARTZ_SURFACE
- test_sources += quartz-surface-source.c
+ test_sources += $(quartz_surface_test_sources)
  endif
  
 +if CAIRO_HAS_GL_EGL_SURFACE
 +EXTRA_PROGRAMS += egl-flowers$(EXEEXT)
 +egl_flowers_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
 +endif
 +
 +if CAIRO_HAS_GL_GLX_SURFACE
 +EXTRA_PROGRAMS += glx-flowers$(EXEEXT)
 +glx_flowers_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
 +endif
 +
  if CAIRO_HAS_GLITZ_SURFACE
- test_sources += glitz-surface-source.c
+ test_sources += $(glitz_surface_test_sources)
  endif
  
  if CAIRO_HAS_PDF_SURFACE
diff --cc util/cairo-script/csi-replay.c
index 8a1f3cd,4e0b606..16b733c
--- a/util/cairo-script/csi-replay.c
+++ b/util/cairo-script/csi-replay.c
@@@ -107,64 -110,8 +111,65 @@@ _xrender_surface_create (void *closure
      return surface;
  }
  #endif
+ #endif
  
 +#if CAIRO_HAS_GL_GLX_SURFACE
 +#include <cairo-gl.h>
 +static cairo_gl_context_t *
 +_glx_get_context (cairo_content_t content)
 +{
 +    static cairo_gl_context_t *context;
 +
 +    if (context == NULL) {
 +	int rgba_attribs[] = {
 +	    GLX_RGBA,
 +	    GLX_RED_SIZE, 1,
 +	    GLX_GREEN_SIZE, 1,
 +	    GLX_BLUE_SIZE, 1,
 +	    GLX_ALPHA_SIZE, 1,
 +	    GLX_DOUBLEBUFFER,
 +	    None
 +	};
 +	XVisualInfo *visinfo;
 +	GLXContext gl_ctx;
 +	Display *dpy;
 +
 +	dpy = XOpenDisplay (NULL);
 +	if (dpy == NULL) {
 +	    fprintf (stderr, "Failed to open display.\n");
 +	    exit (1);
 +	}
 +
 +	visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
 +	if (visinfo == NULL) {
 +	    fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
 +	    exit (1);
 +	}
 +
 +	gl_ctx = glXCreateContext (dpy, visinfo, NULL, True);
 +	XFree (visinfo);
 +
 +	context = cairo_glx_context_create (dpy, gl_ctx);
 +    }
 +
 +    return context;
 +}
 +
 +static cairo_surface_t *
 +_glx_surface_create (void *closure,
 +		     cairo_content_t content,
 +		     double width, double height)
 +{
 +    if (width == 0)
 +	width = 1;
 +    if (height == 0)
 +	height = 1;
 +
 +    return cairo_gl_surface_create (_glx_get_context (content),
 +				    content, width, height);
 +}
 +#endif
 +
  #if CAIRO_HAS_PDF_SURFACE
  #include <cairo-pdf.h>
  static cairo_surface_t *
@@@ -232,9 -181,9 +239,12 @@@ main (int argc, char **argv
  #if CAIRO_HAS_XLIB_XRENDER_SURFACE
  	{ "--xrender", _xrender_surface_create },
  #endif
 +#if CAIRO_HAS_GL_GLX_SURFACE
 +	{ "--glx", _glx_surface_create },
 +#endif
+ #if CAIRO_HAS_XLIB_SURFACE
+ 	{ "--xlib", _xlib_surface_create },
+ #endif
  #if CAIRO_HAS_PDF_SURFACE
  	{ "--pdf", _pdf_surface_create },
  #endif
commit 2da78fd4666faa27d037ae3625ca83353a6e7629
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jun 1 14:04:21 2009 -0700

    [gl] Drop use of packed datatypes where it's disallowed.
    
    I had naively assumed that GL image specification let you do useful things
    and describe the most common datatypes in graphics, since we do things that
    way inside of the DRI drivers.  Silly me.  GL_BGR and GL_RGB can't do
    GL_UNSIGNED_INT_8_8_8_8{,_REV}, so no specifying 24-depth 32-bpp data with
    implicit alpha.  GL_BGR can't even do r5g6b5!
    
    This fixes 20 regressions in the test suite.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index c052794..2d601ee 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -840,6 +840,12 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 
     image_surface = (cairo_image_surface_t *)surface_pattern->surface;
 
+    /* The textures we create almost always has appropriate alpha channel
+     * contents.  But sometimes GL sucks at image specification and we end up
+     * with junk in the alpha.
+     */
+    operand->operand.texture.has_alpha = TRUE;
+
     switch (image_surface->pixman_format) {
     case PIXMAN_a8r8g8b8:
 	internal_format = GL_RGBA;
@@ -848,8 +854,9 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 	break;
     case PIXMAN_x8r8g8b8:
 	internal_format = GL_RGB;
-	format = GL_BGR;
+	format = GL_BGRA;
 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	operand->operand.texture.has_alpha = FALSE;
 	break;
     case PIXMAN_a8b8g8r8:
 	internal_format = GL_RGBA;
@@ -858,8 +865,9 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 	break;
     case PIXMAN_x8b8g8r8:
 	internal_format = GL_RGB;
-	format = GL_RGB;
+	format = GL_RGBA;
 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	operand->operand.texture.has_alpha = FALSE;
 	break;
     case PIXMAN_b8g8r8a8:
 	internal_format = GL_BGRA;
@@ -881,17 +889,13 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 	format = GL_RGB;
 	type = GL_UNSIGNED_SHORT_5_6_5;
 	break;
-    case PIXMAN_b5g6r5:
-	internal_format = GL_RGB;
-	format = GL_BGR;
-	type = GL_UNSIGNED_SHORT_5_6_5;
-	break;
     case PIXMAN_a8:
 	internal_format = GL_ALPHA;
 	format = GL_ALPHA;
 	type = GL_UNSIGNED_BYTE;
 	break;
 
+    case PIXMAN_b5g6r5:
     case PIXMAN_a1r5g5b5:
     case PIXMAN_x1r5g5b5:
     case PIXMAN_a1b5g5r5:
@@ -932,7 +936,8 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
     assert(((image_surface->stride * image_surface->depth) %
 	    image_surface->depth) == 0);
     glPixelStorei (GL_UNPACK_ROW_LENGTH,
-		   image_surface->stride / (image_surface->depth / 8));
+		   image_surface->stride /
+		   (PIXMAN_FORMAT_BPP(image_surface->pixman_format) / 8));
     /* The filter will be correctly set up later, but for now we want to
      * hint to glTexImage that we're not mipmapping.
      */
@@ -948,10 +953,6 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
     operand->type = OPERAND_TEXTURE;
     operand->operand.texture.tex = tex;
     operand->operand.texture.surface = NULL;
-    /* The textures we create always have appropriate alpha channels --
-     * we aren't uploading x8 channels to a8 channels.
-     */
-    operand->operand.texture.has_alpha = TRUE;
     attributes->matrix = src->matrix;
     attributes->extend = src->extend;
     attributes->filter = src->filter;
commit 69a150b7d8115babf2c60d7c5f7ca340162dc098
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jun 1 13:36:32 2009 -0700

    [gl] Initialize has_alpha in the image surface composite fastpath.
    
    Fixes bilevel-image, set-source, and zero-alpha.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 5bcdff1..c052794 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -948,6 +948,10 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
     operand->type = OPERAND_TEXTURE;
     operand->operand.texture.tex = tex;
     operand->operand.texture.surface = NULL;
+    /* The textures we create always have appropriate alpha channels --
+     * we aren't uploading x8 channels to a8 channels.
+     */
+    operand->operand.texture.has_alpha = TRUE;
     attributes->matrix = src->matrix;
     attributes->extend = src->extend;
     attributes->filter = src->filter;
commit 7ee0fee900bf30a7ca0497ab64199c9013f81cdd
Merge: 882f1d5... d3a478b...
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jun 1 10:45:36 2009 -0700

    Merge branch 'gl' into gl-span-renderer
    
    Conflicts:
    	src/cairo-gl-surface.c

diff --cc src/cairo-gl-surface.c
index c16838a,5bcdff1..269ba14
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@@ -49,41 -45,6 +45,18 @@@ slim_hidden_proto (cairo_gl_surface_cre
  
  #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
  
 +static inline float
 +int_as_float(uint32_t val)
 +{
 +    union fi {
 +	float f;
 +	uint32_t u;
 +    } fi;
 +
 +    fi.u = val;
 +    return fi.f;
 +}
 +
- typedef struct _cairo_gl_surface {
-     cairo_surface_t base;
- 
-     cairo_gl_context_t *ctx;
-     cairo_content_t content;
-     int width, height;
- 
-     Window win; /* window if not rendering to FBO */
-     GLuint tex; /* GL texture object containing our data. */
-     GLuint fb; /* GL framebuffer object wrapping our data. */
- } cairo_gl_surface_t;
- 
- struct _cairo_gl_context {
-     cairo_reference_count_t ref_count;
-     cairo_status_t status;
- 
-     Display *dpy;
-     GLXContext gl_ctx;
-     cairo_mutex_t mutex; /* needed? */
-     cairo_gl_surface_t *current_target;
-     GLuint dummy_tex;
- };
- 
  enum cairo_gl_composite_operand_type {
      OPERAND_CONSTANT,
      OPERAND_TEXTURE,
commit d3a478b6c0dca3884a68c5014185cad0a166801c
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jun 1 10:19:24 2009 -0700

    [gl] Fix check-plt.sh for the GL surface.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index d98d771..5bcdff1 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -39,6 +39,10 @@
 
 #include "cairo-gl-private.h"
 
+slim_hidden_proto (cairo_gl_context_reference);
+slim_hidden_proto (cairo_gl_context_destroy);
+slim_hidden_proto (cairo_gl_surface_create);
+
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
 
 enum cairo_gl_composite_operand_type {
@@ -143,6 +147,7 @@ cairo_gl_context_reference (cairo_gl_context_t *context)
 
     return context;
 }
+slim_hidden_def (cairo_gl_context_reference);
 
 void
 cairo_gl_context_destroy (cairo_gl_context_t *context)
@@ -163,6 +168,7 @@ cairo_gl_context_destroy (cairo_gl_context_t *context)
 
     free (context);
 }
+slim_hidden_def (cairo_gl_context_destroy);
 
 static cairo_gl_context_t *
 _cairo_gl_context_acquire (cairo_gl_context_t *ctx)
@@ -390,6 +396,7 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
 
     return &surface->base;
 }
+slim_hidden_def (cairo_gl_surface_create);
 
 void
 cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
commit 1f7c393a6d63282a632a62264b99e67e26ecf38e
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jun 1 10:10:00 2009 -0700

    [gl] Fix check-doc-syntax.sh for GL surface.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index a241e7b..d98d771 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -981,7 +981,7 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 }
 
 /**
- * Like cairo_pattern_acquire_surface, but returns a matrix that transforms
+ * Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
  * from dest to src coords.
  */
 static cairo_status_t
commit 19bc0f2f1d75b1514b22d0bb737bad67ff8d1ee6
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jun 1 10:09:16 2009 -0700

    [gl] Fix check-def.sh for GL surface.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 299500f..a241e7b 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -73,7 +73,7 @@ typedef struct _cairo_gl_composite_setup {
 
 static const cairo_surface_backend_t _cairo_gl_surface_backend;
 
-const cairo_gl_context_t _nil_context = {
+static const cairo_gl_context_t _nil_context = {
     CAIRO_REFERENCE_COUNT_INVALID,
     CAIRO_STATUS_NO_MEMORY
 };
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
index 6b7fee2..9d8eea4 100644
--- a/src/cairo-gl.h
+++ b/src/cairo-gl.h
@@ -45,9 +45,6 @@ typedef struct _cairo_gl_context cairo_gl_context_t;
 cairo_public cairo_gl_context_t *
 cairo_gl_context_reference (cairo_gl_context_t *context);
 
-cairo_public cairo_status_t
-cairo_gl_context_status (cairo_gl_context_t *context);
-
 cairo_public void
 cairo_gl_context_destroy (cairo_gl_context_t *context);
 
@@ -56,9 +53,6 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
 			 cairo_content_t content,
 			 int width, int height);
 
-cairo_public cairo_gl_context_t *
-cairo_gl_surface_get_context (cairo_surface_t *abstract_surface);
-
 cairo_public void
 cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
 
commit 87b764908a38cbb4159ac76d8b7d1d08a24b838e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue May 19 15:53:55 2009 +0100

    [gl] Add EGL target
    
    Split the GLX context from the GL surface to enable use of an alternative
    EGL interface.

diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 3d55ced..fd08ed6 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -149,6 +149,26 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
 enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_sources)
 endif
 
+supported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_glx_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_glx_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_gl_glx_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_gl_glx_sources)
+ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gl_glx_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_glx_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_glx_sources)
+endif
+
+supported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_egl_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_egl_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_gl_egl_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_gl_egl_sources)
+ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gl_egl_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_egl_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_egl_sources)
+endif
+
 unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_glitz_headers)
 all_cairo_boilerplate_headers += $(cairo_boilerplate_glitz_headers)
 all_cairo_boilerplate_private += $(cairo_boilerplate_glitz_private)
diff --git a/boilerplate/cairo-boilerplate-gl.c b/boilerplate/cairo-boilerplate-gl.c
index e818341..37dfc42 100644
--- a/boilerplate/cairo-boilerplate-gl.c
+++ b/boilerplate/cairo-boilerplate-gl.c
@@ -119,7 +119,7 @@ _cairo_boilerplate_gl_create_surface (const char		 *name,
     XFree (visinfo);
 
     gltc->gl_ctx = gl_ctx;
-    gltc->ctx = cairo_gl_glx_context_create (dpy, gl_ctx);
+    gltc->ctx = cairo_glx_context_create (dpy, gl_ctx);
 
     gltc->surface = cairo_gl_surface_create (gltc->ctx, content,
 					     width, height);
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index 69b3b39..f9e064d 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -13,6 +13,8 @@ CAIRO_HAS_BEOS_SURFACE=0
 CAIRO_HAS_SDL_SURFACE=0
 CAIRO_HAS_PNG_FUNCTIONS=1
 CAIRO_HAS_GL_SURFACE=0
+CAIRO_HAS_GL_GLX_SURFACE=0
+CAIRO_HAS_GL_EGL_SURFACE=0
 CAIRO_HAS_GLITZ_SURFACE=0
 CAIRO_HAS_DIRECTFB_SURFACE=0
 CAIRO_HAS_SCRIPT_SURFACE=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index cae8135..da80593 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -44,6 +44,12 @@ endif
 ifeq ($(CAIRO_HAS_GL_SURFACE),1)
 	@echo "#define CAIRO_HAS_GL_SURFACE 1" >> src/cairo-features.h
 endif
+ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
+	@echo "#define CAIRO_HAS_GL_GLX_SURFACE 1" >> src/cairo-features.h
+endif
+ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
+	@echo "#define CAIRO_HAS_GL_EGL_SURFACE 1" >> src/cairo-features.h
+endif
 ifeq ($(CAIRO_HAS_GLITZ_SURFACE),1)
 	@echo "#define CAIRO_HAS_GLITZ_SURFACE 1" >> src/cairo-features.h
 endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index 06ed7f3..f477414 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -377,6 +377,9 @@ AC_DEFUN([CAIRO_REPORT],
 	echo "  BeOS:          $use_beos"
 	echo "  DirectFB:      $use_directfb"
 	echo "  SDL:           $use_sdl"
+	echo "  GL:            $use_gl"
+	echo "  GL/GLX:        $use_gl_glx"
+	echo "  GL/EGL:        $use_gl_egl"
 	echo ""
 	echo "The following font backends:"
 	echo "  User:          yes (always builtin)"
diff --git a/configure.ac b/configure.ac
index 4d1e811..821545f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,14 +199,40 @@ CAIRO_ENABLE_SURFACE_BACKEND(gl, gl, no, [
 
   AC_CHECK_LIB(GLEW, glewInit, [
     AC_CHECK_HEADER(GL/glew.h, [], [
-      have_gl="no (requires glew http://glew.sourceforge.net/)"
+      use_gl="no (requires glew http://glew.sourceforge.net/)"
     ])
   ], [
-    have_gl="no (requires glew http://glew.sourceforge.net/)"
+    use_gl="no (requires glew http://glew.sourceforge.net/)"
   ])
   gl_NONPKGCONFIG_LIBS="-lGLEW"
 ])
 
+CAIRO_ENABLE_SURFACE_BACKEND(gl_glx, GLX, auto, [
+  if test "x$use_gl" != "xyes"; then
+    use_gl_glx="no (requires --enable-gl)"
+  else
+    gl_glx_BASE=cairo-gl
+    old_CPPFLAGS=$CPPFLAGS
+    CPPFLAGS="$CPPFLAGS $gl_CFLAGS $gl_NONPKGCONFIG_CFLAGS"
+    AC_CHECK_HEADER(GL/glx.h,
+		    [],
+		    [use_gl_glx="no (requires GLX)"])
+    CPPFLAGS=$old_CPPFLAGS
+  fi
+])
+
+CAIRO_ENABLE_SURFACE_BACKEND(gl_egl, eagle, auto, [
+  if test "x$use_gl" != "xyes"; then
+    use_gl_egl="no (requires --enable-gl)"
+  else
+    gl_egl_BASE=cairo-gl
+    gl_egl_REQUIRES="eagle"
+    PKG_CHECK_MODULES(gl_egl, $gl_egl_REQUIRES, ,
+		      [AC_MSG_RESULT(no)
+		       use_gl_egl="no (requires eagle)"])
+  fi
+])
+
 dnl ===========================================================================
 
 GLITZ_MIN_VERSION=0.5.1
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 6407271..a926064 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -245,8 +245,10 @@ 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 = cairo-gl-private.h
 cairo_gl_sources = cairo-gl-surface.c
+cairo_gl_glx_sources = cairo-glx-context.c
+cairo_gl_egl_sources = cairo-egl-context.c
 
 cairo_glitz_headers = cairo-glitz.h
 cairo_glitz_private = cairo-glitz-private.h
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index 9e7bffe..f90c36b 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -203,6 +203,34 @@ ifeq ($(CAIRO_HAS_GL_SURFACE),1)
 enabled_cairo_pkgconf += cairo-gl.pc
 endif
 
+supported_cairo_headers += $(cairo_gl_glx_headers)
+all_cairo_headers += $(cairo_gl_glx_headers)
+all_cairo_private += $(cairo_gl_glx_private)
+all_cairo_sources += $(cairo_gl_glx_sources)
+ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
+enabled_cairo_headers += $(cairo_gl_glx_headers)
+enabled_cairo_private += $(cairo_gl_glx_private)
+enabled_cairo_sources += $(cairo_gl_glx_sources)
+endif
+all_cairo_pkgconf += cairo-gl-glx.pc
+ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
+enabled_cairo_pkgconf += cairo-gl-glx.pc
+endif
+
+supported_cairo_headers += $(cairo_gl_egl_headers)
+all_cairo_headers += $(cairo_gl_egl_headers)
+all_cairo_private += $(cairo_gl_egl_private)
+all_cairo_sources += $(cairo_gl_egl_sources)
+ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
+enabled_cairo_headers += $(cairo_gl_egl_headers)
+enabled_cairo_private += $(cairo_gl_egl_private)
+enabled_cairo_sources += $(cairo_gl_egl_sources)
+endif
+all_cairo_pkgconf += cairo-gl-egl.pc
+ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
+enabled_cairo_pkgconf += cairo-gl-egl.pc
+endif
+
 unsupported_cairo_headers += $(cairo_glitz_headers)
 all_cairo_headers += $(cairo_glitz_headers)
 all_cairo_private += $(cairo_glitz_private)
diff --git a/src/cairo-egl-context.c b/src/cairo-egl-context.c
new file mode 100644
index 0000000..ba314d5
--- /dev/null
+++ b/src/cairo-egl-context.c
@@ -0,0 +1,181 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Carl Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+#include <i915_drm.h> /* XXX dummy surface for glewInit() */
+#include <sys/ioctl.h>
+
+typedef struct _cairo_egl_context {
+    cairo_gl_context_t base;
+
+    EGLDisplay display;
+    EGLContext context;
+} cairo_egl_context_t;
+
+typedef struct _cairo_egl_surface {
+    cairo_gl_surface_t base;
+
+    EGLSurface egl;
+} cairo_egl_surface_t;
+
+static void
+_egl_make_current (void *abstract_ctx,
+	           cairo_gl_surface_t *abstract_surface)
+{
+    cairo_egl_context_t *ctx = abstract_ctx;
+    cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
+
+    eglMakeCurrent (ctx->display, surface->egl, surface->egl, ctx->context);
+}
+
+static void
+_egl_swap_buffers (void *abstract_ctx,
+		   cairo_gl_surface_t *abstract_surface)
+{
+    cairo_egl_context_t *ctx = abstract_ctx;
+    cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
+
+    eglSwapBuffers (ctx->display, surface->egl);
+}
+
+static void
+_egl_destroy (void *abstract_ctx)
+{
+}
+
+static cairo_bool_t
+_egl_init (EGLDisplay display, EGLContext context)
+{
+    const EGLint config_attribs[] = {
+	EGL_CONFIG_CAVEAT, EGL_NONE,
+	EGL_NONE
+    };
+    const EGLint surface_attribs[] = {
+	EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
+	EGL_NONE
+    };
+    EGLConfig config;
+    EGLSurface dummy;
+    struct drm_i915_gem_create create;
+    struct drm_gem_flink flink;
+    int fd;
+    GLenum err;
+
+    if (! eglChooseConfig (display, config_attribs, &config, 1, NULL)) {
+	fprintf (stderr, "Unable to choose config\n");
+	return FALSE;
+    }
+
+    /* XXX */
+    fd = eglGetDisplayFD (display);
+
+    create.size = 4096;
+    if (ioctl (fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
+	fprintf (stderr, "gem create failed: %m\n");
+	return FALSE;
+    }
+    flink.handle = create.handle;
+    if (ioctl (fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
+	fprintf (stderr, "gem flink failed: %m\n");
+	return FALSE;
+    }
+
+    dummy = eglCreateSurfaceForName (display, config, flink.name,
+				     1, 1, 4, surface_attribs);
+    if (dummy == NULL) {
+	fprintf (stderr, "Failed to create dummy surface\n");
+	return FALSE;
+    }
+
+    eglMakeCurrent (display, dummy, dummy, context);
+}
+
+cairo_gl_context_t *
+cairo_egl_context_create (EGLDisplay display, EGLContext context)
+{
+    cairo_egl_context_t *ctx;
+    cairo_status_t status;
+
+    if (! _egl_init (display, context)) {
+	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    ctx = calloc (1, sizeof (cairo_egl_context_t));
+    if (ctx == NULL)
+	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    ctx->display = display;
+    ctx->context = context;
+
+    ctx->base.make_current = _egl_make_current;
+    ctx->base.swap_buffers = _egl_swap_buffers;
+    ctx->base.destroy = _egl_destroy;
+
+    status = _cairo_gl_context_init (&ctx->base);
+    if (status) {
+	free (ctx);
+	return _cairo_gl_context_create_in_error (status);
+    }
+
+    return &ctx->base;
+}
+
+cairo_surface_t *
+cairo_gl_surface_create_for_eagle (cairo_gl_context_t   *ctx,
+				   EGLSurface            egl,
+				   int                   width,
+				   int                   height)
+{
+    cairo_egl_surface_t *surface;
+
+    if (ctx->status)
+	return _cairo_surface_create_in_error (ctx->status);
+
+    surface = calloc (1, sizeof (cairo_egl_surface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_gl_surface_init (ctx, &surface->base,
+			    CAIRO_CONTENT_COLOR_ALPHA, width, height);
+    surface->egl = egl;
+
+    return &surface->base.base;
+}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
new file mode 100644
index 0000000..47ebd01
--- /dev/null
+++ b/src/cairo-gl-private.h
@@ -0,0 +1,88 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Carl Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_GL_PRIVATE_H
+#define CAIRO_GL_PRIVATE_H
+
+#include "cairoint.h"
+
+#include <GL/glew.h>
+
+#include "cairo-gl.h"
+
+#include <GL/gl.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glext.h>
+
+typedef struct _cairo_gl_surface {
+    cairo_surface_t base;
+
+    cairo_gl_context_t *ctx;
+    int width, height;
+
+    GLuint tex; /* GL texture object containing our data. */
+    GLuint fb; /* GL framebuffer object wrapping our data. */
+} cairo_gl_surface_t;
+
+struct _cairo_gl_context {
+    cairo_reference_count_t ref_count;
+    cairo_status_t status;
+
+    cairo_mutex_t mutex; /* needed? */
+    GLuint dummy_tex;
+
+    cairo_gl_surface_t *current_target;
+
+    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_private cairo_gl_context_t *
+_cairo_gl_context_create_in_error (cairo_status_t status);
+
+cairo_private cairo_status_t
+_cairo_gl_context_init (cairo_gl_context_t *ctx);
+
+cairo_private void
+_cairo_gl_surface_init (cairo_gl_context_t *ctx,
+			cairo_gl_surface_t *surface,
+			cairo_content_t content,
+			int width, int height);
+
+#endif /* CAIRO_GL_PRIVATE_H */
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 8bf6e29..299500f 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -35,43 +35,12 @@
  *	Carl Worth <cworth at cworth.org>
  */
 
-
-#include <X11/Xlib.h>
-
-#include <GL/glew.h>
-#define GL_GLEXT_PROTOTYPES
-#include <GL/glx.h>
-#include <GL/glext.h>
-
 #include "cairoint.h"
 
-#include "cairo-gl.h"
+#include "cairo-gl-private.h"
 
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
 
-typedef struct _cairo_gl_surface {
-    cairo_surface_t base;
-
-    cairo_gl_context_t *ctx;
-    cairo_content_t content;
-    int width, height;
-
-    Window win; /* window if not rendering to FBO */
-    GLuint tex; /* GL texture object containing our data. */
-    GLuint fb; /* GL framebuffer object wrapping our data. */
-} cairo_gl_surface_t;
-
-struct _cairo_gl_context {
-    cairo_reference_count_t ref_count;
-    cairo_status_t status;
-
-    Display *dpy;
-    GLXContext gl_ctx;
-    cairo_mutex_t mutex; /* needed? */
-    cairo_gl_surface_t *current_target;
-    GLuint dummy_tex;
-};
-
 enum cairo_gl_composite_operand_type {
     OPERAND_CONSTANT,
     OPERAND_TEXTURE,
@@ -114,7 +83,7 @@ static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
     return surface->backend == &_cairo_gl_surface_backend;
 }
 
-static cairo_gl_context_t *
+cairo_gl_context_t *
 _cairo_gl_context_create_in_error (cairo_status_t status)
 {
     if (status == CAIRO_STATUS_NO_MEMORY)
@@ -124,37 +93,31 @@ _cairo_gl_context_create_in_error (cairo_status_t status)
     return NULL;
 }
 
-cairo_gl_context_t *
-cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
+cairo_status_t
+_cairo_gl_context_init (cairo_gl_context_t *ctx)
 {
-    cairo_gl_context_t *ctx;
-    GLenum err;
-
-    ctx = calloc (1, sizeof(cairo_gl_context_t));
-    if (ctx == NULL)
-	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
+    ctx->status = CAIRO_STATUS_SUCCESS;
     CAIRO_REFERENCE_COUNT_INIT (&ctx->ref_count, 1);
-    ctx->dpy = dpy;
-    ctx->gl_ctx = gl_ctx;
+    CAIRO_MUTEX_INIT (ctx->mutex);
 
-    /* Make our GL context active.  While we'll be setting the destination
-     * drawable with each rendering operation, in order to set the context
-     * we have to choose a drawable.  The root window happens to be convenient
-     * for this.
-     */
-    glXMakeCurrent(dpy, RootWindow (dpy, DefaultScreen (dpy)), gl_ctx);
-
-    err = glewInit();
-    if (err != GLEW_OK) {
-	free(ctx);
-	return NULL;
+    if (glewInit () != GLEW_OK) {
+	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
     }
 
-    if (!GLEW_EXT_framebuffer_object || !GLEW_ARB_texture_env_combine ||
-	!GLEW_ARB_texture_non_power_of_two) {
-	free(ctx);
-	return NULL;
+    if (! GLEW_EXT_framebuffer_object ||
+	! GLEW_ARB_texture_env_combine ||
+	! GLEW_ARB_texture_non_power_of_two)
+    {
+	fprintf (stderr,
+		 "Required GL extensions not available:\n");
+	if (! GLEW_EXT_framebuffer_object)
+	    fprintf (stderr, "    GL_EXT_framebuffer_object\n");
+	if (! GLEW_ARB_texture_env_combine)
+	    fprintf (stderr, "    GL_ARB_texture_env_combine\n");
+	if (! GLEW_ARB_texture_non_power_of_two)
+	    fprintf (stderr, "    GL_ARB_texture_non_power_of_two\n");
+
+	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
     }
 
     /* Set up the dummy texture for tex_env_combine with constant color. */
@@ -163,7 +126,7 @@ cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
 		  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 
-    return ctx;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 cairo_gl_context_t *
@@ -196,6 +159,8 @@ cairo_gl_context_destroy (cairo_gl_context_t *context)
 
     glDeleteTextures (1, &context->dummy_tex);
 
+    context->destroy (context);
+
     free (context);
 }
 
@@ -225,8 +190,7 @@ _cairo_gl_set_destination (cairo_gl_surface_t *surface)
 	    glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
 	    glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
 	} else {
-	    /* Set the window as the target of our context. */
-	    glXMakeCurrent (ctx->dpy, surface->win, ctx->gl_ctx);
+	    ctx->make_current (ctx, surface);
 	    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
 	    glDrawBuffer (GL_BACK_LEFT);
 	    glReadBuffer (GL_BACK_LEFT);
@@ -280,7 +244,7 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op)
     /* We may have a visual with alpha bits despite the user requesting
      * CAIRO_CONTENT_COLOR.  So clear out those bits in that case.
      */
-    if (dst->content == CAIRO_CONTENT_COLOR) {
+    if (dst->base.content == CAIRO_CONTENT_COLOR) {
 	if (src_factor == GL_ONE_MINUS_DST_ALPHA)
 	    src_factor = GL_ZERO;
 	if (src_factor == GL_DST_ALPHA)
@@ -335,6 +299,21 @@ _cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
     glEnable (GL_TEXTURE_2D);
 }
 
+void
+_cairo_gl_surface_init (cairo_gl_context_t *ctx,
+			cairo_gl_surface_t *surface,
+			cairo_content_t content,
+			int width, int height)
+{
+    _cairo_surface_init (&surface->base,
+			 &_cairo_gl_surface_backend,
+			 content);
+
+    surface->ctx = cairo_gl_context_reference (ctx);
+    surface->width = width;
+    surface->height = height;
+}
+
 cairo_surface_t *
 cairo_gl_surface_create (cairo_gl_context_t   *ctx,
 			 cairo_content_t	content,
@@ -359,12 +338,7 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    _cairo_surface_init (&surface->base,
-			 &_cairo_gl_surface_backend,
-			 content);
-
-    surface->ctx = cairo_gl_context_reference (ctx);
-    surface->content = content;
+    _cairo_gl_surface_init (ctx, surface, content, width, height);
 
     switch (content) {
     default:
@@ -407,9 +381,6 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
 	fprintf(stderr, "destination is framebuffer incomplete\n");
 
-    surface->width = width;
-    surface->height = height;
-
     /* Cairo surfaces start out initialized to transparent (black) */
     ctx = _cairo_gl_context_acquire (surface->ctx);
     _cairo_gl_set_destination (surface);
@@ -420,33 +391,6 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     return &surface->base;
 }
 
-
-cairo_surface_t *
-cairo_gl_surface_create_for_window (cairo_gl_context_t   *ctx,
-				    Window                win,
-				    int                   width,
-				    int                   height)
-{
-    cairo_gl_surface_t *surface;
-    cairo_content_t content = CAIRO_CONTENT_COLOR_ALPHA;
-
-    surface = calloc (1, sizeof (cairo_gl_surface_t));
-    if (unlikely (surface == NULL))
-	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
-    _cairo_surface_init (&surface->base,
-			 &_cairo_gl_surface_backend,
-			 content);
-
-    surface->ctx = cairo_gl_context_reference (ctx);
-    surface->content = content;
-    surface->width = width;
-    surface->height = height;
-    surface->win = win;
-
-    return &surface->base;
-}
-
 void
 cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
 			   int              width,
@@ -465,19 +409,43 @@ cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
     surface->height = height;
 }
 
+int
+cairo_gl_surface_get_width (cairo_surface_t *abstract_surface)
+{
+    cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+
+    if (! _cairo_surface_is_gl (abstract_surface))
+	return 0;
+
+    return surface->width;
+}
+
+int
+cairo_gl_surface_get_height (cairo_surface_t *abstract_surface)
+{
+    cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+
+    if (! _cairo_surface_is_gl (abstract_surface))
+	return 0;
+
+    return surface->height;
+}
+
+
 void
 cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
 {
     cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
     cairo_status_t status;
 
-    if (! _cairo_surface_is_gl (abstract_surface) || surface->fb) {
+    if (! _cairo_surface_is_gl (abstract_surface)) {
 	status = _cairo_surface_set_error (abstract_surface,
 		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
 	return;
     }
 
-    glXSwapBuffers(surface->ctx->dpy, surface->win);
+    if (! surface->fb)
+	surface->ctx->swap_buffers (surface->ctx, surface);
 }
 
 static cairo_surface_t *
@@ -528,8 +496,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 	cpp = 4;
     } else if (src->pixman_format == PIXMAN_x8r8g8b8) {
-	assert(dst->content != CAIRO_CONTENT_COLOR_ALPHA);
-	assert(dst->content != CAIRO_CONTENT_ALPHA);
+	assert(dst->base.content != CAIRO_CONTENT_COLOR_ALPHA);
+	assert(dst->base.content != CAIRO_CONTENT_ALPHA);
 	format = GL_BGRA;
 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 	cpp = 4;
@@ -547,7 +515,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
      */
     temp_data = malloc (width * height * cpp);
     if (temp_data == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     src_data_start = (char *)src->data + (src_y * src->stride) + (src_x * cpp);
     for (y = 0; y < height; y++) {
@@ -597,23 +565,23 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
 	*rect_out = extents;
 
     /* Want to use a switch statement here but the compiler gets whiny. */
-    if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
+    if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
 	format = GL_BGRA;
 	cairo_format = CAIRO_FORMAT_ARGB32;
 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 	cpp = 4;
-    } else if (surface->content == CAIRO_CONTENT_COLOR) {
+    } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
 	format = GL_BGRA;
 	cairo_format = CAIRO_FORMAT_RGB24;
 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 	cpp = 4;
-    } else if (surface->content == CAIRO_CONTENT_ALPHA) {
+    } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
 	format = GL_ALPHA;
 	cairo_format = CAIRO_FORMAT_A8;
 	type = GL_UNSIGNED_BYTE;
 	cpp = 1;
     } else {
-	fprintf(stderr, "get_image fallback: %d\n", surface->content);
+	fprintf(stderr, "get_image fallback: %d\n", surface->base.content);
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
@@ -634,7 +602,7 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
      */
     temp_data = malloc (extents.width * extents.height * cpp);
     if (temp_data == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     glPixelStorei(GL_PACK_ALIGNMENT, 1);
     glReadPixels(extents.x, extents.y,
@@ -753,7 +721,8 @@ _cairo_gl_surface_clone_similar (void		     *abstract_surface,
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
 
 	clone = (cairo_gl_surface_t *)
-	    _cairo_gl_surface_create_similar (&surface->base, src->content,
+	    _cairo_gl_surface_create_similar (&surface->base,
+		                              src->content,
 					      width, height);
 	if (clone == NULL)
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1449,7 +1418,7 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
 	_cairo_gl_context_release(ctx);
 	free(vertices);
 	free(colors);
-	return CAIRO_STATUS_NO_MEMORY;
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
     /* This should be loaded in as either a blend constant and an operator
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
index eb98977..6b7fee2 100644
--- a/src/cairo-gl.h
+++ b/src/cairo-gl.h
@@ -34,8 +34,6 @@
 #ifndef CAIRO_GL_H
 #define CAIRO_GL_H
 
-#include <GL/glx.h>
-
 #include "cairo.h"
 
 #if CAIRO_HAS_GL_SURFACE
@@ -45,9 +43,6 @@ CAIRO_BEGIN_DECLS
 typedef struct _cairo_gl_context cairo_gl_context_t;
 
 cairo_public cairo_gl_context_t *
-cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx);
-
-cairo_public cairo_gl_context_t *
 cairo_gl_context_reference (cairo_gl_context_t *context);
 
 cairo_public cairo_status_t
@@ -61,23 +56,48 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
 			 cairo_content_t content,
 			 int width, int height);
 
-cairo_public cairo_surface_t *
-cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
-				    Window win,
-				    int width, int height);
-
 cairo_public cairo_gl_context_t *
 cairo_gl_surface_get_context (cairo_surface_t *abstract_surface);
 
 cairo_public void
 cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
 
+cairo_public int
+cairo_gl_surface_get_width (cairo_surface_t *abstract_surface);
+
+cairo_public int
+cairo_gl_surface_get_height (cairo_surface_t *abstract_surface);
+
 cairo_public void
 cairo_gl_surface_swapbuffers (cairo_surface_t *surface);
 
 cairo_public cairo_status_t
 cairo_gl_surface_glfinish (cairo_surface_t *surface);
 
+#if CAIRO_HAS_GL_GLX_SURFACE
+#include <GL/glx.h>
+
+cairo_public cairo_gl_context_t *
+cairo_glx_context_create (Display *dpy, GLXContext gl_ctx);
+
+cairo_public cairo_surface_t *
+cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
+				    Window win,
+				    int width, int height);
+#endif
+
+#if CAIRO_HAS_GL_EGL_SURFACE
+#include <eagle.h>
+
+cairo_public cairo_gl_context_t *
+cairo_egl_context_create (EGLDisplay display, EGLContext context);
+
+cairo_public cairo_surface_t *
+cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx,
+				   EGLSurface surface,
+				   int width, int height);
+#endif
+
 CAIRO_END_DECLS
 
 #else  /* CAIRO_HAS_GL_SURFACE */
@@ -85,4 +105,3 @@ CAIRO_END_DECLS
 #endif /* CAIRO_HAS_GL_SURFACE */
 
 #endif /* CAIRO_GL_H */
-
diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c
new file mode 100644
index 0000000..2fa5faf
--- /dev/null
+++ b/src/cairo-glx-context.c
@@ -0,0 +1,136 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Carl Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+typedef struct _cairo_glx_context {
+    cairo_gl_context_t base;
+
+    Display *display;
+    GLXContext context;
+} cairo_glx_context_t;
+
+typedef struct _cairo_glx_surface {
+    cairo_gl_surface_t base;
+
+    Window win;
+} cairo_glx_surface_t;
+
+static void
+_glx_make_current (void *abstract_ctx,
+	           cairo_gl_surface_t *abstract_surface)
+{
+    cairo_glx_context_t *ctx = abstract_ctx;
+    cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface;
+
+    /* Set the window as the target of our context. */
+    glXMakeCurrent (ctx->display, surface->win, ctx->context);
+}
+
+static void
+_glx_swap_buffers (void *abstract_ctx,
+		   cairo_gl_surface_t *abstract_surface)
+{
+    cairo_glx_context_t *ctx = abstract_ctx;
+    cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface;
+
+    glXSwapBuffers (ctx->display, surface->win);
+}
+
+static void
+_glx_destroy (void *abstract_ctx)
+{
+}
+
+cairo_gl_context_t *
+cairo_glx_context_create (Display *dpy, GLXContext gl_ctx)
+{
+    cairo_glx_context_t *ctx;
+    cairo_status_t status;
+
+    /* Make our GL context active.  While we'll be setting the destination
+     * drawable with each rendering operation, in order to set the context
+     * we have to choose a drawable.  The root window happens to be convenient
+     * for this.
+     */
+    if (! glXMakeCurrent (dpy, RootWindow (dpy, DefaultScreen (dpy)), gl_ctx))
+	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    ctx = calloc (1, sizeof (cairo_glx_context_t));
+    if (ctx == NULL)
+	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    ctx->display = dpy;
+    ctx->context = gl_ctx;
+
+    ctx->base.make_current = _glx_make_current;
+    ctx->base.swap_buffers = _glx_swap_buffers;
+    ctx->base.destroy = _glx_destroy;
+
+    status = _cairo_gl_context_init (&ctx->base);
+    if (status) {
+	free (ctx);
+	return _cairo_gl_context_create_in_error (status);
+    }
+
+    return &ctx->base;
+}
+
+cairo_surface_t *
+cairo_gl_surface_create_for_window (cairo_gl_context_t   *ctx,
+				    Window                win,
+				    int                   width,
+				    int                   height)
+{
+    cairo_glx_surface_t *surface;
+
+    if (ctx->status)
+	return _cairo_surface_create_in_error (ctx->status);
+
+    surface = calloc (1, sizeof (cairo_glx_surface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_gl_surface_init (ctx, &surface->base,
+			    CAIRO_CONTENT_COLOR_ALPHA, width, height);
+    surface->win = win;
+
+    return &surface->base.base;
+}
diff --git a/test/.gitignore b/test/.gitignore
index 24ec7a6..fd3f4fb 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -13,6 +13,8 @@ any2ppm
 .any2ppm.errors
 cairo-test-constructors.c
 cairo-test-suite
+egl-flowers
+glx-flowers
 pdf2png
 ps2png
 svg2png
diff --git a/test/Makefile.am b/test/Makefile.am
index 0b53116..567e684 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -227,6 +227,16 @@ if CAIRO_HAS_QUARTZ_SURFACE
 test_sources += quartz-surface-source.c
 endif
 
+if CAIRO_HAS_GL_EGL_SURFACE
+EXTRA_PROGRAMS += egl-flowers$(EXEEXT)
+egl_flowers_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
+endif
+
+if CAIRO_HAS_GL_GLX_SURFACE
+EXTRA_PROGRAMS += glx-flowers$(EXEEXT)
+glx_flowers_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
+endif
+
 if CAIRO_HAS_GLITZ_SURFACE
 test_sources += glitz-surface-source.c
 endif
diff --git a/test/egl-flowers.c b/test/egl-flowers.c
new file mode 100644
index 0000000..4facec7
--- /dev/null
+++ b/test/egl-flowers.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright © 2007 Michael Dominic K.
+ * Copyright © 2008, 2009 Kristian Høgsberg
+ * Copyright © 2009 Chris Wilson
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#include <cairo-gl.h>
+
+#include <math.h>
+#include <stdio.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <xf86drmMode.h>
+#include <i915_drm.h>
+
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
+#include <libudev.h>
+
+typedef struct {
+    float x;
+    float y;
+    float scale;
+    float rotation;
+    float r1, g1, b1, a1;
+    float r2, b2, g2, a2;
+} Flower;
+
+#define N_FLOWERS 200
+#define FLOWER_SIZE 128
+static Flower flowers[N_FLOWERS];
+
+static EGLDisplay
+_get_display (void)
+{
+    EGLint major, minor;
+    EGLDisplay display;
+    struct udev *udev;
+    struct udev_device *device;
+    struct stat st;
+
+    if (stat ("/dev/dri/card0", &st) < 0) {
+	fprintf(stderr, "no such device\n");
+	return NULL;
+    }
+
+    udev = udev_new ();
+    device = udev_device_new_from_devnum (udev, 'c', st.st_rdev);
+    if (device == NULL) {
+	fprintf (stderr, "failed to find device\n");
+	return NULL;
+    }
+    display = eglCreateDisplayNative (device);
+    udev_device_unref (device);
+    udev_unref (udev);
+
+    if (display == NULL) {
+	fprintf (stderr, "failed to open display\n");
+	return NULL;
+    }
+
+    if (! eglInitialize (display, &major, &minor)) {
+	fprintf (stderr, "failed to initialize display\n");
+	return NULL;
+    }
+
+    return display;
+}
+
+static cairo_surface_t *
+_get_fb (void)
+{
+    const EGLint config_attribs[] = {
+	EGL_DEPTH_SIZE, 24,
+	EGL_STENCIL_SIZE, 8,
+	EGL_CONFIG_CAVEAT, EGL_NONE,
+	EGL_NONE
+    };
+    const EGLint surface_attribs[] = {
+	EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
+	EGL_NONE
+    };
+
+    EGLDisplay display;
+    EGLContext context;
+    EGLConfig config;
+    EGLSurface s;
+
+    cairo_gl_context_t *ctx;
+    cairo_surface_t *surface;
+
+    drmModeConnector *connector;
+    drmModeRes *resources;
+    drmModeEncoder *encoder;
+    drmModeModeInfo *mode;
+    struct drm_i915_gem_create create;
+    struct drm_gem_flink flink;
+    int i, ret, fd;
+    uint32_t fb_id;
+
+    display = _get_display ();
+    if (display == NULL) {
+	fprintf (stderr, "Unable to open display\n");
+	return NULL;
+    }
+
+    if (! eglChooseConfig (display, config_attribs, &config, 1, NULL)) {
+	fprintf (stderr, "Unable to choose config\n");
+	return NULL;
+    }
+
+    context = eglCreateContext (display, config, NULL, NULL);
+    if (context == NULL) {
+	fprintf (stderr, "failed to create context\n");
+	return NULL;
+    }
+
+    fd = eglGetDisplayFD (display);
+    resources = drmModeGetResources (fd);
+    if (resources == NULL) {
+	fprintf (stderr, "drmModeGetResources failed\n");
+	return NULL;
+    }
+
+    for (i = 0; i < resources->count_connectors; i++) {
+	connector = drmModeGetConnector (fd, resources->connectors[i]);
+	if (connector == NULL)
+	    continue;
+
+	if (connector->connection == DRM_MODE_CONNECTED &&
+	    connector->count_modes > 0)
+	    break;
+
+	drmModeFreeConnector (connector);
+    }
+
+    if (i == resources->count_connectors) {
+	fprintf (stderr, "No currently active connector found.\n");
+	return NULL;
+    }
+
+    mode = &connector->modes[0];
+
+    for (i = 0; i < resources->count_encoders; i++) {
+	encoder = drmModeGetEncoder(fd, resources->encoders[i]);
+
+	if (encoder == NULL)
+	    continue;
+
+	if (encoder->encoder_id == connector->encoder_id)
+	    break;
+
+	drmModeFreeEncoder(encoder);
+    }
+
+    /* Mode size at 32 bpp */
+    create.size = mode->hdisplay * mode->vdisplay * 4;
+    if (ioctl (fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
+	fprintf (stderr, "gem create failed: %m\n");
+	return NULL;
+    }
+
+    ret = drmModeAddFB (fd, mode->hdisplay, mode->vdisplay,
+		       32, 32, mode->hdisplay * 4, create.handle, &fb_id);
+    if (ret) {
+	fprintf (stderr, "failed to add fb: %m\n");
+	return NULL;
+    }
+
+    ret = drmModeSetCrtc (fd, encoder->crtc_id, fb_id, 0, 0,
+			 &connector->connector_id, 1, mode);
+    if (ret) {
+	fprintf (stderr, "failed to set mode: %m\n");
+	return NULL;
+    }
+
+    flink.handle = create.handle;
+    if (ioctl (fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
+	fprintf (stderr, "gem flink failed: %m\n");
+	return NULL;
+    }
+
+    s = eglCreateSurfaceForName (display, config,
+				 flink.name,
+				 mode->hdisplay, mode->vdisplay,
+				 mode->hdisplay * 4,
+				 surface_attribs);
+    if (s == NULL) {
+	fprintf (stderr, "failed to create surface\n");
+	return NULL;
+    }
+
+    ctx = cairo_egl_context_create (display, context);
+    surface = cairo_gl_surface_create_for_eagle (ctx, s,
+						 mode->hdisplay,
+						 mode->vdisplay);
+    cairo_gl_context_destroy (ctx);
+
+    if (cairo_surface_status (surface)) {
+	fprintf (stderr, "failed to create cairo surface\n");
+	return NULL;
+    }
+
+    return surface;
+}
+
+
+static unsigned int
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+    static unsigned int x;
+    return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static void
+random_colour (float *r, float *g, float *b, float *a)
+{
+    unsigned int x = hars_petruska_f54_1_random ();
+    *r = (x & 255) / 255.; x >>= 8;
+    *g = (x & 255) / 255.; x >>= 8;
+    *b = (x & 255) / 255.; x >>= 8;
+    *a = x / 255.;
+}
+
+static void
+randomize_flower (Flower *flower, int width, int height)
+{
+    flower->x = (hars_petruska_f54_1_random() & 8191) * width / 8191.;
+    flower->y = (hars_petruska_f54_1_random() & 8191) * height / 8191.;
+    flower->scale = 10 + (hars_petruska_f54_1_random() & 511) * 140 / 512.;
+    flower->rotation = (hars_petruska_f54_1_random() & 511) * M_PI / 256;
+
+    random_colour (&flower->r1,
+	           &flower->g1,
+	           &flower->b1,
+	           &flower->a1);
+    random_colour (&flower->r2,
+	           &flower->g2,
+	           &flower->b2,
+	           &flower->a2);
+}
+
+static void
+randomize_flowers (int width, int height)
+{
+    int i;
+
+    for (i = 0; i < N_FLOWERS; i++)
+        randomize_flower (&flowers [i], width, height);
+}
+
+static cairo_pattern_t *
+create_flower (cairo_surface_t *target, int size)
+{
+    cairo_surface_t *surface;
+    cairo_pattern_t *mask;
+    cairo_t *cr;
+
+    surface = cairo_surface_create_similar (target,
+	                                    CAIRO_CONTENT_ALPHA, size, size);
+    cr = cairo_create (surface);
+    cairo_surface_destroy (surface);
+
+    cairo_scale (cr, size/2, size/2);
+    cairo_translate (cr, 1., 1.);
+    cairo_move_to (cr, 0, 0);
+    cairo_curve_to (cr, -0.9, 0, -0.9, -0.9, -0.9, -0.9);
+    cairo_curve_to (cr, 0.0, -0.9, 0, 0, 0, 0);
+    cairo_curve_to (cr, 0.9, 0.0, 0.9, -0.9, 0.9, -0.9);
+    cairo_curve_to (cr, 0.0, -0.9, 0.0, 0.0, 0.0, 0.0);
+    cairo_curve_to (cr, 0.9, 0.0, 0.9, 0.9, 0.9, 0.9);
+    cairo_curve_to (cr, 0.0, 0.9, 0.0, 0.0, 0.0, 0.0);
+    cairo_curve_to (cr, -0.9, 0.0, -0.9, 0.9, -0.9, 0.9);
+    cairo_curve_to (cr, 0.0, 0.9, 0.0, 0.0, 0.0, 0.0);
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_fill (cr);
+
+    mask = cairo_pattern_create_for_surface (cairo_get_target (cr));
+    cairo_destroy (cr);
+
+    return mask;
+}
+
+static void
+paint (cairo_surface_t *surface,
+       cairo_pattern_t *mask,
+       int mask_size)
+{
+    cairo_t *cr;
+    int i;
+
+    cr = cairo_create (surface);
+    for (i = 0; i < N_FLOWERS; i++) {
+        cairo_pattern_t *pattern;
+	cairo_matrix_t matrix;
+
+        cairo_matrix_init_identity (&matrix);
+        cairo_matrix_translate (&matrix, flowers[i].x, flowers[i].y);
+        cairo_matrix_scale (&matrix,
+			    flowers[i].scale/mask_size,
+			    flowers[i].scale/mask_size);
+        cairo_matrix_rotate (&matrix, flowers[i].rotation);
+        cairo_set_matrix (cr, &matrix);
+
+        pattern = cairo_pattern_create_linear (0, -mask_size, 0, mask_size);
+        cairo_pattern_add_color_stop_rgba (pattern, 0,
+		flowers[i].r1, flowers[i].g1, flowers[i].b1, flowers[i].a1);
+        cairo_pattern_add_color_stop_rgba (pattern, 1,
+		flowers[i].r2, flowers[i].g2, flowers[i].b2, flowers[i].a2);
+        cairo_set_source (cr, pattern);
+        cairo_pattern_destroy (pattern);
+
+	cairo_mask (cr, mask);
+    }
+    cairo_destroy (cr);
+}
+
+int
+main (int argc, char *argv[])
+{
+    cairo_surface_t *surface;
+    cairo_pattern_t *flower;
+
+    surface = _get_fb ();
+    if (surface == NULL) {
+	fprintf (stderr, "Failed to create framebuffer\n");
+	return 1;
+    }
+
+    flower = create_flower (surface, FLOWER_SIZE);
+    while (1) {
+	randomize_flowers (cairo_gl_surface_get_width (surface),
+			   cairo_gl_surface_get_height (surface));
+	paint (surface, flower, FLOWER_SIZE);
+	cairo_gl_surface_swapbuffers (surface);
+    }
+
+    cairo_pattern_destroy (flower);
+    cairo_surface_destroy (surface);
+
+    return 0;
+}
diff --git a/test/glx-flowers.c b/test/glx-flowers.c
new file mode 100644
index 0000000..855c204
--- /dev/null
+++ b/test/glx-flowers.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright © 2007 Michael Dominic K.
+ * Copyright © 2009 Chris Wilson
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#include <cairo-gl.h>
+
+#include <math.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+typedef struct {
+    float x;
+    float y;
+    float scale;
+    float rotation;
+    float r1, g1, b1, a1;
+    float r2, b2, g2, a2;
+} Flower;
+
+#define N_FLOWERS 200
+#define FLOWER_SIZE 128
+static Flower flowers[N_FLOWERS];
+
+#define WIDTH 640
+#define HEIGHT 480
+
+static cairo_surface_t *
+_surface_create (void)
+{
+    int rgb_attribs[] = { GLX_RGBA,
+			  GLX_RED_SIZE, 1,
+			  GLX_GREEN_SIZE, 1,
+			  GLX_BLUE_SIZE, 1,
+			  GLX_DOUBLEBUFFER,
+			  None };
+    XVisualInfo *vi;
+    GLXContext ctx;
+    Display *dpy;
+    Colormap cmap;
+    XSetWindowAttributes swa;
+    Window win;
+
+    cairo_gl_context_t *context;
+    cairo_surface_t *surface;
+
+    dpy = XOpenDisplay (NULL);
+    if (dpy == NULL) {
+	fprintf (stderr, "Failed to open display\n");
+	return NULL;
+    }
+
+    vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs);
+    if (vi == NULL) {
+	fprintf (stderr, "Failed to create RGB, double-buffered visual\n");
+	XCloseDisplay (dpy);
+	return NULL;
+    }
+
+    ctx = glXCreateContext (dpy, vi, NULL, True);
+
+    cmap = XCreateColormap (dpy,
+			    RootWindow (dpy, vi->screen),
+			    vi->visual,
+			    AllocNone);
+    swa.colormap = cmap;
+    swa.border_pixel = 0;
+    win = XCreateWindow (dpy, RootWindow (dpy, vi->screen),
+			 0, 0,
+			 640, 480,
+			 0,
+			 vi->depth,
+			 InputOutput,
+			 vi->visual,
+			 CWBorderPixel | CWColormap, &swa);
+    XMapWindow (dpy, win);
+    XFlush (dpy);
+    XFree (vi);
+
+    context = cairo_glx_context_create (dpy, ctx);
+    surface = cairo_gl_surface_create_for_window (context, win, WIDTH, HEIGHT);
+    cairo_gl_context_destroy (context);
+
+    if (cairo_surface_status (surface)) {
+	fprintf (stderr, "failed to create cairo surface\n");
+	return NULL;
+    }
+
+    return surface;
+}
+
+static unsigned int
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+    static unsigned int x;
+    return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static void
+random_colour (float *r, float *g, float *b, float *a)
+{
+    unsigned int x = hars_petruska_f54_1_random ();
+    *r = (x & 255) / 255.; x >>= 8;
+    *g = (x & 255) / 255.; x >>= 8;
+    *b = (x & 255) / 255.; x >>= 8;
+    *a = x / 255.;
+}
+
+static void
+randomize_flower (Flower *flower, int width, int height)
+{
+    flower->x = (hars_petruska_f54_1_random() & 8191) * width / 8191.;
+    flower->y = (hars_petruska_f54_1_random() & 8191) * height / 8191.;
+    flower->scale = 10 + (hars_petruska_f54_1_random() & 511) * 140 / 512.;
+    flower->rotation = (hars_petruska_f54_1_random() & 511) * M_PI / 256;
+
+    random_colour (&flower->r1, &flower->g1, &flower->b1, &flower->a1);
+    random_colour (&flower->r2, &flower->g2, &flower->b2, &flower->a2);
+}
+
+static void
+randomize_flowers (int width, int height)
+{
+    int i;
+
+    for (i = 0; i < N_FLOWERS; i++)
+        randomize_flower (&flowers [i], width, height);
+}
+
+static cairo_pattern_t *
+create_flower (cairo_surface_t *target, int size)
+{
+    cairo_surface_t *surface;
+    cairo_pattern_t *mask;
+    cairo_t *cr;
+
+    surface = cairo_surface_create_similar (target,
+	                                    CAIRO_CONTENT_ALPHA, size, size);
+    cr = cairo_create (surface);
+    cairo_surface_destroy (surface);
+
+    cairo_scale (cr, size/2, size/2);
+    cairo_translate (cr, 1., 1.);
+    cairo_move_to (cr, 0, 0);
+    cairo_curve_to (cr, -0.9, 0, -0.9, -0.9, -0.9, -0.9);
+    cairo_curve_to (cr, 0.0, -0.9, 0, 0, 0, 0);
+    cairo_curve_to (cr, 0.9, 0.0, 0.9, -0.9, 0.9, -0.9);
+    cairo_curve_to (cr, 0.0, -0.9, 0.0, 0.0, 0.0, 0.0);
+    cairo_curve_to (cr, 0.9, 0.0, 0.9, 0.9, 0.9, 0.9);
+    cairo_curve_to (cr, 0.0, 0.9, 0.0, 0.0, 0.0, 0.0);
+    cairo_curve_to (cr, -0.9, 0.0, -0.9, 0.9, -0.9, 0.9);
+    cairo_curve_to (cr, 0.0, 0.9, 0.0, 0.0, 0.0, 0.0);
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_fill (cr);
+
+    mask = cairo_pattern_create_for_surface (cairo_get_target (cr));
+    cairo_destroy (cr);
+
+    return mask;
+}
+
+static void
+paint (cairo_surface_t *surface,
+       cairo_pattern_t *mask,
+       int mask_size)
+{
+    cairo_t *cr;
+    int i;
+
+    cr = cairo_create (surface);
+    for (i = 0; i < N_FLOWERS; i++) {
+        cairo_pattern_t *pattern;
+	cairo_matrix_t matrix;
+
+        cairo_matrix_init_identity (&matrix);
+        cairo_matrix_translate (&matrix, flowers[i].x, flowers[i].y);
+        cairo_matrix_scale (&matrix,
+			    flowers[i].scale/mask_size,
+			    flowers[i].scale/mask_size);
+        cairo_matrix_rotate (&matrix, flowers[i].rotation);
+        cairo_set_matrix (cr, &matrix);
+
+        pattern = cairo_pattern_create_linear (0, -mask_size, 0, mask_size);
+        cairo_pattern_add_color_stop_rgba (pattern, 0,
+		flowers[i].r1, flowers[i].g1, flowers[i].b1, flowers[i].a1);
+        cairo_pattern_add_color_stop_rgba (pattern, 1,
+		flowers[i].r2, flowers[i].g2, flowers[i].b2, flowers[i].a2);
+        cairo_set_source (cr, pattern);
+        cairo_pattern_destroy (pattern);
+
+	cairo_mask (cr, mask);
+    }
+    cairo_destroy (cr);
+}
+
+int
+main (int argc, char *argv[])
+{
+    cairo_surface_t *surface;
+    cairo_pattern_t *flower;
+    int frame, frame_target = 5;
+    struct timeval start, stop;
+
+    surface = _surface_create ();
+    if (surface == NULL) {
+	fprintf (stderr, "Failed to create framebuffer\n");
+	return 1;
+    }
+
+    flower = create_flower (surface, FLOWER_SIZE);
+    frame = 0;
+    gettimeofday (&start, NULL);
+    while (1) {
+	randomize_flowers (cairo_gl_surface_get_width (surface),
+			   cairo_gl_surface_get_height (surface));
+	paint (surface, flower, FLOWER_SIZE);
+	cairo_gl_surface_swapbuffers (surface);
+
+	if (++frame == frame_target) {
+	    int ticks;
+
+	    gettimeofday (&stop, NULL);
+
+	    ticks = (stop.tv_sec - start.tv_sec) * 1000000;
+	    ticks += (stop.tv_usec - start.tv_usec);
+	    printf ("%.2f fps\n", frame * 1000000. / ticks);
+
+	    /* rate-limit output to once every 5 seconds */
+	    frame_target = (frame_target + 5000000 * frame / ticks + 1) / 2;
+
+	    frame = 0;
+	    start = stop;
+	}
+    }
+
+    cairo_pattern_destroy (flower);
+    cairo_surface_destroy (surface);
+
+    return 0;
+}
diff --git a/util/cairo-script/.gitignore b/util/cairo-script/.gitignore
index 855d640..0c31a3a 100644
--- a/util/cairo-script/.gitignore
+++ b/util/cairo-script/.gitignore
@@ -1,2 +1,4 @@
 csi-replay
 csi-exec
+csi-egl
+csi-glx
diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am
index db5e953..4966e20 100644
--- a/util/cairo-script/Makefile.am
+++ b/util/cairo-script/Makefile.am
@@ -22,10 +22,25 @@ libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_I
 libcairo_script_interpreter_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
 
 csi_replay_SOURCES = csi-replay.c
+csi_replay_CFLAGS = $(CAIRO_CFLAGS)
 csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
 
 csi_exec_SOURCES = csi-exec.c
 csi_exec_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
 
+if CAIRO_HAS_GL_EGL_SURFACE
+noinst_PROGRAMS += csi-egl
+csi_egl_SOURCES = csi-egl.c
+csi_egl_CFLAGS = $(CAIRO_CFLAGS)
+csi_egl_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
+endif
+
+if CAIRO_HAS_GL_GLX_SURFACE
+noinst_PROGRAMS += csi-glx
+csi_glx_SOURCES = csi-glx.c
+csi_glx_CFLAGS = $(CAIRO_CFLAGS)
+csi_glx_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
+endif
+
 EXTRA_DIST = \
 	COPYING
diff --git a/util/cairo-script/csi-egl.c b/util/cairo-script/csi-egl.c
new file mode 100644
index 0000000..41b45fb
--- /dev/null
+++ b/util/cairo-script/csi-egl.c
@@ -0,0 +1,263 @@
+#include <cairo-gl.h>
+#include "cairo-script-interpreter.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <xf86drmMode.h>
+#include <i915_drm.h>
+
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
+#include <libudev.h>
+
+static void
+die (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    vfprintf (stderr, fmt, ap);
+    va_end (ap);
+
+    exit (EXIT_FAILURE);
+}
+
+static EGLDisplay
+_get_display (const char *card)
+{
+    EGLint major, minor;
+    EGLDisplay display;
+    struct udev *udev;
+    struct udev_device *device;
+    struct stat st;
+
+    if (stat (card, &st) < 0) {
+	die ("no such device\n");
+	return NULL;
+    }
+
+    udev = udev_new ();
+    device = udev_device_new_from_devnum (udev, 'c', st.st_rdev);
+    if (device == NULL) {
+	die ("failed to find device\n");
+	return NULL;
+    }
+    display = eglCreateDisplayNative (device);
+    udev_device_unref (device);
+    udev_unref (udev);
+
+    if (display == NULL) {
+	die ("failed to open display\n");
+	return NULL;
+    }
+
+    if (! eglInitialize (display, &major, &minor)) {
+	die ("failed to initialize display\n");
+	return NULL;
+    }
+
+    return display;
+}
+
+static cairo_surface_t *
+_get_fb (const char *card)
+{
+    const EGLint config_attribs[] = {
+	EGL_DEPTH_SIZE, 24,
+	EGL_STENCIL_SIZE, 8,
+	EGL_CONFIG_CAVEAT, EGL_NONE,
+	EGL_NONE
+    };
+    const EGLint surface_attribs[] = {
+	EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
+	EGL_NONE
+    };
+
+    EGLDisplay display;
+    EGLContext context;
+    EGLConfig config;
+    EGLSurface s;
+
+    cairo_gl_context_t *ctx;
+    cairo_surface_t *surface;
+
+    drmModeConnector *connector;
+    drmModeRes *resources;
+    drmModeEncoder *encoder;
+    drmModeModeInfo *mode;
+    struct drm_i915_gem_create create;
+    struct drm_gem_flink flink;
+    int i, ret, fd;
+    uint32_t fb_id;
+
+    display = _get_display (card);
+    if (display == NULL) {
+	die ("Unable to open display\n");
+	return NULL;
+    }
+
+    if (! eglChooseConfig (display, config_attribs, &config, 1, NULL)) {
+	die ("Unable to choose config\n");
+	return NULL;
+    }
+
+    context = eglCreateContext (display, config, NULL, NULL);
+    if (context == NULL) {
+	die ("failed to create context\n");
+	return NULL;
+    }
+
+    fd = eglGetDisplayFD (display);
+    resources = drmModeGetResources (fd);
+    if (resources == NULL) {
+	die ("drmModeGetResources failed\n");
+	return NULL;
+    }
+
+    for (i = 0; i < resources->count_connectors; i++) {
+	connector = drmModeGetConnector (fd, resources->connectors[i]);
+	if (connector == NULL)
+	    continue;
+
+	if (connector->connection == DRM_MODE_CONNECTED &&
+	    connector->count_modes > 0)
+	    break;
+
+	drmModeFreeConnector (connector);
+    }
+
+    if (i == resources->count_connectors) {
+	die ("No currently active connector found.\n");
+	return NULL;
+    }
+
+    mode = &connector->modes[0];
+
+    for (i = 0; i < resources->count_encoders; i++) {
+	encoder = drmModeGetEncoder(fd, resources->encoders[i]);
+
+	if (encoder == NULL)
+	    continue;
+
+	if (encoder->encoder_id == connector->encoder_id)
+	    break;
+
+	drmModeFreeEncoder(encoder);
+    }
+
+    /* Mode size at 32 bpp */
+    create.size = mode->hdisplay * mode->vdisplay * 4;
+    if (ioctl (fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
+	die ("gem create failed: %m\n");
+	return NULL;
+    }
+
+    ret = drmModeAddFB (fd, mode->hdisplay, mode->vdisplay,
+		       32, 32, mode->hdisplay * 4, create.handle, &fb_id);
+    if (ret) {
+	die ("failed to add fb: %m\n");
+	return NULL;
+    }
+
+    ret = drmModeSetCrtc (fd, encoder->crtc_id, fb_id, 0, 0,
+			 &connector->connector_id, 1, mode);
+    if (ret) {
+	die ("failed to set mode: %m\n");
+	return NULL;
+    }
+
+    flink.handle = create.handle;
+    if (ioctl (fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
+	die ("gem flink failed: %m\n");
+	return NULL;
+    }
+
+    s = eglCreateSurfaceForName (display, config,
+				 flink.name,
+				 mode->hdisplay, mode->vdisplay,
+				 mode->hdisplay * 4,
+				 surface_attribs);
+    if (s == NULL) {
+	die ("failed to create surface\n");
+	return NULL;
+    }
+
+    ctx = cairo_egl_context_create (display, context);
+    surface = cairo_gl_surface_create_for_eagle (ctx, s,
+						 mode->hdisplay,
+						 mode->vdisplay);
+    cairo_gl_context_destroy (ctx);
+
+    return surface;
+}
+
+static cairo_surface_t *
+_egl_surface_create (void *closure,
+		     cairo_content_t content,
+		     double width, double height)
+{
+    return cairo_surface_create_similar (closure, content, width, height);
+}
+
+static struct list {
+    struct list *next;
+    cairo_t *context;
+    cairo_surface_t *surface;
+} *list;
+
+static cairo_t *
+_egl_context_create (void *closure, cairo_surface_t *surface)
+{
+    cairo_t *cr = cairo_create (surface);
+    struct list *l = malloc (sizeof (*l));
+    l->next = list;
+    l->context = cr;
+    l->surface = cairo_surface_reference (surface);
+    list = l;
+    return cr;
+}
+
+static void
+_egl_context_destroy (void *closure, void *ptr)
+{
+    struct list *l, **prev = &list;
+    while ((l = *prev) != NULL) {
+	if (l->context == ptr) {
+	    if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) {
+		cairo_t *cr = cairo_create (closure);
+		cairo_set_source_surface (cr, l->surface, 0, 0);
+		cairo_paint (cr);
+		cairo_destroy (cr);
+		cairo_gl_surface_swapbuffers (closure);
+	    }
+
+	    cairo_surface_destroy (l->surface);
+	    *prev = l->next;
+	    free (l);
+	    return;
+	}
+	prev = &l->next;
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+    const cairo_script_interpreter_hooks_t hooks = {
+	.closure = _get_fb ("/dev/dri/card0"),
+	.surface_create = _egl_surface_create,
+	.context_create = _egl_context_create,
+	.context_destroy = _egl_context_destroy
+    };
+    cairo_script_interpreter_t *csi;
+    int i;
+
+    csi = cairo_script_interpreter_create ();
+    cairo_script_interpreter_install_hooks (csi, &hooks);
+    for (i = 1; i < argc; i++)
+	cairo_script_interpreter_run (csi, argv[i]);
+    return cairo_script_interpreter_destroy (csi);
+}
diff --git a/util/cairo-script/csi-glx.c b/util/cairo-script/csi-glx.c
new file mode 100644
index 0000000..e55542a
--- /dev/null
+++ b/util/cairo-script/csi-glx.c
@@ -0,0 +1,150 @@
+#include <cairo-gl.h>
+#include "cairo-script-interpreter.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+static void
+die (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    vfprintf (stderr, fmt, ap);
+    va_end (ap);
+
+    exit (EXIT_FAILURE);
+}
+
+static cairo_surface_t *
+_get_fb (void)
+{
+    int rgb_attribs[] = { GLX_RGBA,
+			  GLX_RED_SIZE, 1,
+			  GLX_GREEN_SIZE, 1,
+			  GLX_BLUE_SIZE, 1,
+			  GLX_DOUBLEBUFFER,
+			  None };
+    XVisualInfo *vi;
+    GLXContext ctx;
+    Display *dpy;
+    Screen *screen;
+    Colormap cmap;
+    XSetWindowAttributes swa;
+    Window win;
+
+    cairo_gl_context_t *context;
+    cairo_surface_t *surface;
+
+    dpy = XOpenDisplay (NULL);
+    if (dpy == NULL)
+	die ("Failed to open display\n");
+
+    vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs);
+    if (vi == NULL)
+	die ("Failed to create RGB, double-buffered visual\n");
+
+    ctx = glXCreateContext (dpy, vi, NULL, True);
+
+    screen = ScreenOfDisplay (dpy, vi->screen);
+
+    cmap = XCreateColormap (dpy,
+			    RootWindowOfScreen (screen),
+			    vi->visual,
+			    AllocNone);
+    swa.colormap = cmap;
+    swa.border_pixel = 0;
+    swa.override_redirect = True;
+    win = XCreateWindow (dpy, RootWindowOfScreen (screen),
+			 0, 0,
+			 WidthOfScreen (screen), HeightOfScreen (screen),
+			 0,
+			 vi->depth,
+			 InputOutput,
+			 vi->visual,
+			 CWBorderPixel | CWColormap | CWOverrideRedirect,
+			 &swa);
+    XMapWindow (dpy, win);
+    XFlush (dpy);
+    XFree (vi);
+
+    context = cairo_glx_context_create (dpy, ctx);
+    surface = cairo_gl_surface_create_for_window (context, win,
+	                                          WidthOfScreen (screen),
+						  HeightOfScreen (screen));
+    cairo_gl_context_destroy (context);
+
+    if (cairo_surface_status (surface))
+	die ("failed to create cairo surface\n");
+
+    return surface;
+}
+
+static cairo_surface_t *
+_glx_surface_create (void *closure,
+		     cairo_content_t content,
+		     double width, double height)
+{
+    return cairo_surface_create_similar (closure, content, width, height);
+}
+
+static struct list {
+    struct list *next;
+    cairo_t *context;
+    cairo_surface_t *surface;
+} *list;
+
+static cairo_t *
+_glx_context_create (void *closure, cairo_surface_t *surface)
+{
+    cairo_t *cr = cairo_create (surface);
+    struct list *l = malloc (sizeof (*l));
+    l->next = list;
+    l->context = cr;
+    l->surface = cairo_surface_reference (surface);
+    list = l;
+    return cr;
+}
+
+static void
+_glx_context_destroy (void *closure, void *ptr)
+{
+    struct list *l, **prev = &list;
+    while ((l = *prev) != NULL) {
+	if (l->context == ptr) {
+	    if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) {
+		cairo_t *cr = cairo_create (closure);
+		cairo_set_source_surface (cr, l->surface, 0, 0);
+		cairo_paint (cr);
+		cairo_destroy (cr);
+		cairo_gl_surface_swapbuffers (closure);
+	    }
+
+	    cairo_surface_destroy (l->surface);
+	    *prev = l->next;
+	    free (l);
+	    return;
+	}
+	prev = &l->next;
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+    const cairo_script_interpreter_hooks_t hooks = {
+	.closure = _get_fb (),
+	.surface_create = _glx_surface_create,
+	.context_create = _glx_context_create,
+	.context_destroy = _glx_context_destroy
+    };
+    cairo_script_interpreter_t *csi;
+    int i;
+
+    csi = cairo_script_interpreter_create ();
+    cairo_script_interpreter_install_hooks (csi, &hooks);
+    for (i = 1; i < argc; i++)
+	cairo_script_interpreter_run (csi, argv[i]);
+    return cairo_script_interpreter_destroy (csi);
+}
diff --git a/util/cairo-script/csi-replay.c b/util/cairo-script/csi-replay.c
index cfae74c..8a1f3cd 100644
--- a/util/cairo-script/csi-replay.c
+++ b/util/cairo-script/csi-replay.c
@@ -3,6 +3,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 static const cairo_user_data_key_t _key;
 
@@ -107,6 +108,63 @@ _xrender_surface_create (void *closure,
 }
 #endif
 
+#if CAIRO_HAS_GL_GLX_SURFACE
+#include <cairo-gl.h>
+static cairo_gl_context_t *
+_glx_get_context (cairo_content_t content)
+{
+    static cairo_gl_context_t *context;
+
+    if (context == NULL) {
+	int rgba_attribs[] = {
+	    GLX_RGBA,
+	    GLX_RED_SIZE, 1,
+	    GLX_GREEN_SIZE, 1,
+	    GLX_BLUE_SIZE, 1,
+	    GLX_ALPHA_SIZE, 1,
+	    GLX_DOUBLEBUFFER,
+	    None
+	};
+	XVisualInfo *visinfo;
+	GLXContext gl_ctx;
+	Display *dpy;
+
+	dpy = XOpenDisplay (NULL);
+	if (dpy == NULL) {
+	    fprintf (stderr, "Failed to open display.\n");
+	    exit (1);
+	}
+
+	visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
+	if (visinfo == NULL) {
+	    fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
+	    exit (1);
+	}
+
+	gl_ctx = glXCreateContext (dpy, visinfo, NULL, True);
+	XFree (visinfo);
+
+	context = cairo_glx_context_create (dpy, gl_ctx);
+    }
+
+    return context;
+}
+
+static cairo_surface_t *
+_glx_surface_create (void *closure,
+		     cairo_content_t content,
+		     double width, double height)
+{
+    if (width == 0)
+	width = 1;
+    if (height == 0)
+	height = 1;
+
+    return cairo_gl_surface_create (_glx_get_context (content),
+				    content, width, height);
+}
+#endif
+
 #if CAIRO_HAS_PDF_SURFACE
 #include <cairo-pdf.h>
 static cairo_surface_t *
@@ -174,6 +232,9 @@ main (int argc, char **argv)
 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
 	{ "--xrender", _xrender_surface_create },
 #endif
+#if CAIRO_HAS_GL_GLX_SURFACE
+	{ "--glx", _glx_surface_create },
+#endif
 #if CAIRO_HAS_PDF_SURFACE
 	{ "--pdf", _pdf_surface_create },
 #endif
commit 882f1d5a60abfbf83c65fe00b31bb4c8e5c82f62
Author: Eric Anholt <eric at anholt.net>
Date:   Sun May 10 16:56:49 2009 -0700

    [gl] Use spans directly as geometry instead of rasterizing to a temporary.
    
    I was hoping for a bigger win than this, but cairogears is now significantly
    faster than it was with just traps.  One potential problem is that adding
    src texture coordinates blew up vertex size from 12 bytes to 20, and we're
    emitting quite a few vertices.  There's plenty of hope for the future,
    though: With shaders we could remove the 2 new texcoords again by stuffing a
    position to source coordinate transformation matrix in constants.  Then
    with EXT_geometry_shader4 plus EXT_gpu_shader4 we should be able to get the
    24 bytes for 2 vertices down to 16 or less.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 3ae53a0..c16838a 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1201,6 +1201,46 @@ _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx, int tex_unit,
     }
 }
 
+static void
+_cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
+			   cairo_gl_composite_setup_t *setup)
+{
+    cairo_surface_attributes_t *src_attributes;
+    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
+
+    src_attributes = &setup->src.operand.texture.attributes;
+
+    switch (setup->src.type) {
+    case OPERAND_CONSTANT:
+	_cairo_gl_set_tex_combine_constant_color (ctx, 0,
+	    setup->src.operand.constant.color);
+	break;
+    case OPERAND_TEXTURE:
+	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
+				       src_attributes);
+	/* Set up the constant color we use to set alpha to 1 if needed. */
+	glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
+	/* Set up the combiner to just set color to the sampled texture. */
+	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
+	/* Wire the src alpha to 1 if the surface doesn't have it.
+	 * We may have a teximage with alpha bits even though we didn't ask
+	 * for it and we don't pay attention to setting alpha to 1 in a dest
+	 * that has inadvertent alpha.
+	 */
+	if (setup->src.operand.texture.has_alpha)
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
+	else
+	    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;
+    }
+}
+
 static cairo_int_status_t
 _cairo_gl_surface_composite (cairo_operator_t		  op,
 			     const cairo_pattern_t	 *src,
@@ -1224,7 +1264,6 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     cairo_status_t status;
     int i;
     GLenum err;
-    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
     cairo_gl_composite_setup_t setup;
 
     memset(&setup, 0, sizeof(setup));
@@ -1265,35 +1304,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 
     glEnable (GL_BLEND);
 
-    switch (setup.src.type) {
-    case OPERAND_CONSTANT:
-	_cairo_gl_set_tex_combine_constant_color (ctx, 0,
-	    setup.src.operand.constant.color);
-	break;
-    case OPERAND_TEXTURE:
-	_cairo_gl_set_texture_surface (0, setup.src.operand.texture.tex,
-				       src_attributes);
-	/* Set up the constant color we use to set alpha to 1 if needed. */
-	glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
-	/* Set up the combiner to just set color to the sampled texture. */
-	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
-
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
-	/* Wire the src alpha to 1 if the surface doesn't have it.
-	 * We may have a teximage with alpha bits even though we didn't ask
-	 * for it and we don't pay attention to setting alpha to 1 in a dest
-	 * that has inadvertent alpha.
-	 */
-	if (setup.src.operand.texture.has_alpha)
-	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
-	else
-	    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;
-    }
+    _cairo_gl_set_src_operand (ctx, &setup);
 
     if (mask != NULL) {
 	switch (setup.mask.type) {
@@ -1506,11 +1517,11 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
 typedef struct _cairo_gl_surface_span_renderer {
     cairo_span_renderer_t base;
 
+    cairo_gl_composite_setup_t setup;
+
     cairo_operator_t op;
-    const cairo_pattern_t *pattern;
     cairo_antialias_t antialias;
 
-    cairo_gl_surface_t *mask;
     cairo_gl_surface_t *dst;
 
     cairo_composite_rectangles_t composite_rectangles;
@@ -1518,18 +1529,17 @@ typedef struct _cairo_gl_surface_span_renderer {
     void *vbo_base;
     unsigned int vbo_size;
     unsigned int vbo_offset;
+    unsigned int vertex_size;
 } cairo_gl_surface_span_renderer_t;
 
 static void
 _cairo_gl_span_renderer_flush(cairo_gl_surface_span_renderer_t *renderer)
 {
-    unsigned int vertex_size = 2 * sizeof(float) + sizeof(uint32_t);
-
     if (renderer->vbo_offset == 0)
 	return;
 
     glUnmapBuffer (GL_ARRAY_BUFFER_ARB);
-    glDrawArrays (GL_LINES, 0, renderer->vbo_offset / vertex_size);
+    glDrawArrays (GL_LINES, 0, renderer->vbo_offset / renderer->vertex_size);
     renderer->vbo_offset = 0;
 }
 
@@ -1537,21 +1547,35 @@ static void *
 _cairo_gl_span_renderer_get_vbo(cairo_gl_surface_span_renderer_t *renderer,
 				unsigned int num_vertices)
 {
-    unsigned int vertex_size = 2 * sizeof(float) + sizeof(uint32_t);
     unsigned int offset;
 
     if (renderer->vbo == 0) {
 	renderer->vbo_size = 16384;
 	glGenBuffers (1, &renderer->vbo);
 	glBindBuffer (GL_ARRAY_BUFFER_ARB, renderer->vbo);
-	glVertexPointer (2, GL_FLOAT, vertex_size, 0);
-	glColorPointer (4, GL_UNSIGNED_BYTE, vertex_size,
-			(void *)(uintptr_t)(2 * sizeof(float)));
+
+	if (renderer->setup.src.type == OPERAND_TEXTURE)
+	    renderer->vertex_size = 4 * sizeof(float) + sizeof(uint32_t);
+	else
+	    renderer->vertex_size = 2 * sizeof(float) + sizeof(uint32_t);
+
+	glVertexPointer (2, GL_FLOAT, renderer->vertex_size, 0);
 	glEnableClientState (GL_VERTEX_ARRAY);
+
+	glColorPointer (4, GL_UNSIGNED_BYTE, renderer->vertex_size,
+			(void *)(uintptr_t)(2 * sizeof(float)));
 	glEnableClientState (GL_COLOR_ARRAY);
+
+	if (renderer->setup.src.type == OPERAND_TEXTURE) {
+	    glClientActiveTexture(GL_TEXTURE0);
+	    glTexCoordPointer (2, GL_FLOAT, renderer->vertex_size,
+			       (void *)(uintptr_t)(2 * sizeof(float) +
+						   sizeof(uint32_t)));
+	    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+	}
     }
 
-    if (renderer->vbo_offset + num_vertices * vertex_size >
+    if (renderer->vbo_offset + num_vertices * renderer->vertex_size >
 	renderer->vbo_size) {
 	_cairo_gl_span_renderer_flush(renderer);
     }
@@ -1565,11 +1589,53 @@ _cairo_gl_span_renderer_get_vbo(cairo_gl_surface_span_renderer_t *renderer,
     }
 
     offset = renderer->vbo_offset;
-    renderer->vbo_offset += num_vertices * vertex_size;
+    renderer->vbo_offset += num_vertices * renderer->vertex_size;
 
     return (char *)renderer->vbo_base + offset;
 }
 
+static void
+_cairo_gl_emit_span_vertex(cairo_gl_surface_span_renderer_t *renderer,
+			   int dst_x, int dst_y, uint8_t alpha,
+			   float *vertices)
+{
+    cairo_surface_attributes_t *src_attributes;
+    int v = 0;
+
+    src_attributes = &renderer->setup.src.operand.texture.attributes;
+
+    vertices[v++] = dst_x;
+    vertices[v++] = dst_y;
+    vertices[v++] = int_as_float(alpha << 24);
+    if (renderer->setup.src.type == OPERAND_TEXTURE) {
+	double s, t;
+
+	s = dst_x;
+	t = dst_y;
+	cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
+	vertices[v++] = s;
+	vertices[v++] = t;
+    }
+}
+
+static void
+_cairo_gl_emit_span(cairo_gl_surface_span_renderer_t *renderer,
+		    int x1, int x2, int y, uint8_t alpha)
+{
+    float *vertices = _cairo_gl_span_renderer_get_vbo(renderer, 2);
+
+    _cairo_gl_emit_span_vertex(renderer, x1, y, alpha, vertices);
+    _cairo_gl_emit_span_vertex(renderer, x2, y, alpha,
+			       vertices + renderer->vertex_size / 4);
+}
+
+/* Emits the contents of the span renderer rows as GL_LINES with the span's
+ * alpha.
+ *
+ * Unlike the image surface, which is compositing into a temporary, we emit
+ * coverage even for alpha == 0, in case we're using an unbounded operator.
+ * But it means we avoid having to do the fixup.
+ */
 static cairo_status_t
 _cairo_gl_surface_span_renderer_render_row (
     void				*abstract_renderer,
@@ -1582,8 +1648,8 @@ _cairo_gl_surface_span_renderer_render_row (
     int xmax = xmin + renderer->composite_rectangles.width;
     int prev_x = xmin;
     int prev_alpha = 0;
-    unsigned i, v;
-    float *vertices;
+    unsigned i;
+    int x_translate;
 
     /* Make sure we're within y-range. */
     if (y < renderer->composite_rectangles.mask.y ||
@@ -1591,6 +1657,11 @@ _cairo_gl_surface_span_renderer_render_row (
 	renderer->composite_rectangles.height)
 	return CAIRO_STATUS_SUCCESS;
 
+    x_translate = renderer->composite_rectangles.dst.x -
+	renderer->composite_rectangles.mask.x;
+    y += renderer->composite_rectangles.dst.y -
+	renderer->composite_rectangles.mask.y;
+
     /* Find the first span within x-range. */
     for (i=0; i < num_spans && spans[i].x < xmin; i++) {}
     if (i>0)
@@ -1603,33 +1674,17 @@ _cairo_gl_surface_span_renderer_render_row (
 	if (x >= xmax)
 	    break;
 
-	if (prev_alpha != 0) {
-	    vertices = _cairo_gl_span_renderer_get_vbo(renderer, 2);
-	    v = 0;
-
-	    vertices[v++] = prev_x;
-	    vertices[v++] = y;
-	    vertices[v++] = int_as_float(prev_alpha << 24);
-
-	    vertices[v++] = x;
-	    vertices[v++] = y;
-	    vertices[v++] = int_as_float(prev_alpha << 24);
-	}
+	_cairo_gl_emit_span(renderer, prev_x + x_translate, x + x_translate, y,
+			    prev_alpha);
 
 	prev_x = x;
 	prev_alpha = spans[i].coverage;
     }
 
-    if (prev_alpha != 0 && prev_x < xmax) {
-	vertices = _cairo_gl_span_renderer_get_vbo(renderer, 2);
-	v = 0;
-	vertices[v++] = prev_x;
-	vertices[v++] = y;
-	vertices[v++] = int_as_float(prev_alpha << 24);
-
-	vertices[v++] = xmax;
-	vertices[v++] = y;
-	vertices[v++] = int_as_float(prev_alpha << 24);
+    if (prev_x < xmax) {
+	_cairo_gl_emit_span(renderer,
+			    prev_x + x_translate, xmax + x_translate, y,
+			    prev_alpha);
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -1643,8 +1698,8 @@ _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
     if (!renderer)
 	return;
 
-    if (renderer->mask != NULL)
-	cairo_surface_destroy (&renderer->mask->base);
+    _cairo_gl_operand_destroy (&renderer->setup.src);
+    _cairo_gl_context_release (renderer->dst->ctx);
 
     free (renderer);
 }
@@ -1653,11 +1708,6 @@ static cairo_status_t
 _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
 {
     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-    cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    cairo_pattern_t *mask_pattern = NULL;
-    int width = rects->width;
-    int height = rects->height;
 
     _cairo_gl_span_renderer_flush(renderer);
 
@@ -1666,61 +1716,15 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
     glDisableClientState (GL_VERTEX_ARRAY);
     glDisableClientState (GL_COLOR_ARRAY);
 
-    _cairo_gl_context_release (renderer->dst->ctx);
+    glClientActiveTexture (GL_TEXTURE0);
+    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+    glActiveTexture (GL_TEXTURE0);
+    glDisable (GL_TEXTURE_2D);
 
-    if (renderer->pattern == NULL || renderer->mask == NULL)
-	return CAIRO_STATUS_SUCCESS;
+    glActiveTexture (GL_TEXTURE1);
+    glDisable (GL_TEXTURE_2D);
 
-    status = cairo_surface_status (&renderer->mask->base);
-    if (status != CAIRO_STATUS_SUCCESS)
-	goto fail;
-    /*
-    status = _cairo_gl_surface_clone_similar (renderer->src,
-					      renderer->mask,
-					      0,
-					      0,
-					      renderer->mask->width,
-					      renderer->mask->height,
-					      &mask_x, &mask_y,
-					      &mask_gl);
-    if (status != CAIRO_STATUS_SUCCESS)
-	goto fail;
-    */
-    mask_pattern = cairo_pattern_create_for_surface (&renderer->mask->base);
-
-    status = _cairo_gl_surface_composite (renderer->op,
-					  renderer->pattern,
-					  mask_pattern,
-					  renderer->dst,
-					  rects->src.x,
-					  rects->src.y,
-					  0,
-					  0,
-					  rects->dst.x,
-					  rects->dst.y,
-					  width, height);
-    if (status != CAIRO_STATUS_SUCCESS)
-	goto fail;
-
-    /*
-    if (! _cairo_operator_bounded_by_mask (renderer->op))
-	status = _cairo_surface_composite_shape_fixup_unbounded (
-		&dst->base,
-		src_attributes,
-		src->width, src->height,
-		rects->width, rects->height,
-		rects->src.x, rects->src.y,
-		0, 0,
-		rects->dst.x, rects->dst.y,
-		rects->width, rects->height);
-*/
-
-fail:
-    cairo_pattern_destroy (mask_pattern);
-
-    if (status != CAIRO_STATUS_SUCCESS)
-	return _cairo_span_renderer_set_error (abstract_renderer,
-					       status);
+    glDisable (GL_BLEND);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1742,7 +1746,7 @@ _cairo_gl_surface_check_span_renderer (cairo_operator_t	  op,
 
 static cairo_span_renderer_t *
 _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
-					const cairo_pattern_t  *pattern,
+					const cairo_pattern_t	*src,
 					void			*abstract_dst,
 					cairo_antialias_t	 antialias,
 					const cairo_composite_rectangles_t *rects)
@@ -1752,6 +1756,8 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     cairo_status_t status;
     int width = rects->width;
     int height = rects->height;
+    cairo_surface_attributes_t *src_attributes;
+    GLenum err;
 
     if (renderer == NULL)
 	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
@@ -1764,38 +1770,58 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     renderer->base.render_row =
 	_cairo_gl_surface_span_renderer_render_row;
     renderer->op = op;
-    renderer->pattern = pattern;
     renderer->antialias = antialias;
     renderer->dst = dst;
 
     renderer->composite_rectangles = *rects;
 
-    /* TODO: support rendering to A1 surfaces (or: go add span
-     * compositing to pixman.) */
-    renderer->mask = (cairo_gl_surface_t *)
-	cairo_gl_surface_create (dst->ctx, CAIRO_CONTENT_ALPHA, width, height);
+    status = _cairo_gl_operand_init (&renderer->setup.src, src, dst,
+				     rects->src.x, rects->src.y,
+				     rects->dst.x, rects->dst.y,
+				     width, height);
+    if (unlikely (status)) {
+	_cairo_gl_context_acquire (dst->ctx);
+	_cairo_gl_surface_span_renderer_destroy (renderer);
+	return _cairo_span_renderer_create_in_error (status);
+    }
+
+    _cairo_gl_context_acquire (dst->ctx);
+
+    _cairo_gl_set_destination (dst);
 
-    status = cairo_surface_status (&renderer->mask->base);
+    src_attributes = &renderer->setup.src.operand.texture.attributes;
 
+    status = _cairo_gl_set_operator (dst, op);
     if (status != CAIRO_STATUS_SUCCESS) {
 	_cairo_gl_surface_span_renderer_destroy (renderer);
 	return _cairo_span_renderer_create_in_error (status);
     }
 
-    _cairo_gl_context_acquire (dst->ctx);
-    _cairo_gl_set_destination (renderer->mask);
+    glEnable (GL_BLEND);
 
-    /* Fix up the projection matrix from _cairo_gl_set_destination --
-     * we want to translate incoming vertices from
-     * (rectangles.mask.x, rectangles.mask.y) to the origin.
-     */
-    glMatrixMode (GL_PROJECTION);
-    glLoadIdentity();
-    glOrtho(renderer->composite_rectangles.mask.x,
-	    renderer->composite_rectangles.mask.x + renderer->mask->width,
-	    renderer->composite_rectangles.mask.y,
-	    renderer->composite_rectangles.mask.y + renderer->mask->height,
-	    -1.0, 1.0);
+    _cairo_gl_set_src_operand (dst->ctx, &renderer->setup);
+
+    /* Set up the mask to source from the incoming vertex color. */
+    glActiveTexture (GL_TEXTURE1);
+    /* Have to have a dummy texture bound in order to use the combiner unit. */
+    glBindTexture (GL_TEXTURE_2D, dst->ctx->dummy_tex);
+    glEnable (GL_TEXTURE_2D);
+    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PRIMARY_COLOR);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+
+    while ((err = glGetError ()))
+	fprintf(stderr, "GL error 0x%08x\n", (int) err);
 
     return &renderer->base;
 }
commit 7b4f2d5e6dd37232d4fa764b69065c7d96856dcc
Author: Eric Anholt <eric at anholt.net>
Date:   Sun May 10 14:50:22 2009 -0700

    [gl] Use Enable/DisableClientState for arrays for consistency.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 9e511d6..3ae53a0 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1547,8 +1547,8 @@ _cairo_gl_span_renderer_get_vbo(cairo_gl_surface_span_renderer_t *renderer,
 	glVertexPointer (2, GL_FLOAT, vertex_size, 0);
 	glColorPointer (4, GL_UNSIGNED_BYTE, vertex_size,
 			(void *)(uintptr_t)(2 * sizeof(float)));
-	glEnable (GL_VERTEX_ARRAY);
-	glEnable (GL_COLOR_ARRAY);
+	glEnableClientState (GL_VERTEX_ARRAY);
+	glEnableClientState (GL_COLOR_ARRAY);
     }
 
     if (renderer->vbo_offset + num_vertices * vertex_size >
@@ -1663,8 +1663,8 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
 
     glBindBuffer (GL_ARRAY_BUFFER_ARB, 0);
     glDeleteBuffers (1, &renderer->vbo);
-    glDisable (GL_VERTEX_ARRAY);
-    glDisable (GL_COLOR_ARRAY);
+    glDisableClientState (GL_VERTEX_ARRAY);
+    glDisableClientState (GL_COLOR_ARRAY);
 
     _cairo_gl_context_release (renderer->dst->ctx);
 
commit 705ee3da1372e8533f25e0b4bde072e4bf76872b
Author: Eric Anholt <eric at anholt.net>
Date:   Sat May 9 12:17:12 2009 -0700

    [gl] Add HW spans implementation using VBOs and GL_LINES.
    
    This is a minor performance regression over software, but is the basis for
    not rasterizing the geometry into a temporary mask, which should be a
    significant win.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 4147563..9e511d6 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -49,6 +49,18 @@
 
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
 
+static inline float
+int_as_float(uint32_t val)
+{
+    union fi {
+	float f;
+	uint32_t u;
+    } fi;
+
+    fi.u = val;
+    return fi.f;
+}
+
 typedef struct _cairo_gl_surface {
     cairo_surface_t base;
 
@@ -1498,12 +1510,66 @@ typedef struct _cairo_gl_surface_span_renderer {
     const cairo_pattern_t *pattern;
     cairo_antialias_t antialias;
 
-    cairo_image_surface_t *mask;
+    cairo_gl_surface_t *mask;
     cairo_gl_surface_t *dst;
 
     cairo_composite_rectangles_t composite_rectangles;
+    GLuint vbo;
+    void *vbo_base;
+    unsigned int vbo_size;
+    unsigned int vbo_offset;
 } cairo_gl_surface_span_renderer_t;
 
+static void
+_cairo_gl_span_renderer_flush(cairo_gl_surface_span_renderer_t *renderer)
+{
+    unsigned int vertex_size = 2 * sizeof(float) + sizeof(uint32_t);
+
+    if (renderer->vbo_offset == 0)
+	return;
+
+    glUnmapBuffer (GL_ARRAY_BUFFER_ARB);
+    glDrawArrays (GL_LINES, 0, renderer->vbo_offset / vertex_size);
+    renderer->vbo_offset = 0;
+}
+
+static void *
+_cairo_gl_span_renderer_get_vbo(cairo_gl_surface_span_renderer_t *renderer,
+				unsigned int num_vertices)
+{
+    unsigned int vertex_size = 2 * sizeof(float) + sizeof(uint32_t);
+    unsigned int offset;
+
+    if (renderer->vbo == 0) {
+	renderer->vbo_size = 16384;
+	glGenBuffers (1, &renderer->vbo);
+	glBindBuffer (GL_ARRAY_BUFFER_ARB, renderer->vbo);
+	glVertexPointer (2, GL_FLOAT, vertex_size, 0);
+	glColorPointer (4, GL_UNSIGNED_BYTE, vertex_size,
+			(void *)(uintptr_t)(2 * sizeof(float)));
+	glEnable (GL_VERTEX_ARRAY);
+	glEnable (GL_COLOR_ARRAY);
+    }
+
+    if (renderer->vbo_offset + num_vertices * vertex_size >
+	renderer->vbo_size) {
+	_cairo_gl_span_renderer_flush(renderer);
+    }
+
+    if (renderer->vbo_offset == 0) {
+	/* We'll only be using these vertices once. */
+	glBufferData(GL_ARRAY_BUFFER_ARB, renderer->vbo_size, NULL,
+		     GL_STREAM_DRAW_ARB);
+	renderer->vbo_base = glMapBuffer(GL_ARRAY_BUFFER_ARB,
+					 GL_WRITE_ONLY_ARB);
+    }
+
+    offset = renderer->vbo_offset;
+    renderer->vbo_offset += num_vertices * vertex_size;
+
+    return (char *)renderer->vbo_base + offset;
+}
+
 static cairo_status_t
 _cairo_gl_surface_span_renderer_render_row (
     void				*abstract_renderer,
@@ -1514,18 +1580,17 @@ _cairo_gl_surface_span_renderer_render_row (
     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
     int xmin = renderer->composite_rectangles.mask.x;
     int xmax = xmin + renderer->composite_rectangles.width;
-    uint8_t *row;
     int prev_x = xmin;
     int prev_alpha = 0;
-    unsigned i;
+    unsigned i, v;
+    float *vertices;
 
     /* Make sure we're within y-range. */
-    y -= renderer->composite_rectangles.mask.y;
-    if (y < 0 || y >= renderer->composite_rectangles.height)
+    if (y < renderer->composite_rectangles.mask.y ||
+	y >= renderer->composite_rectangles.mask.y +
+	renderer->composite_rectangles.height)
 	return CAIRO_STATUS_SUCCESS;
 
-    row = (uint8_t*)(renderer->mask->data) + y*(size_t)renderer->mask->stride - xmin;
-
     /* Find the first span within x-range. */
     for (i=0; i < num_spans && spans[i].x < xmin; i++) {}
     if (i>0)
@@ -1539,16 +1604,16 @@ _cairo_gl_surface_span_renderer_render_row (
 	    break;
 
 	if (prev_alpha != 0) {
-	    /* We implement setting rendering the most common single
-	     * pixel wide span case to avoid the overhead of a memset
-	     * call.  Open coding setting longer spans didn't show a
-	     * noticeable improvement over memset. */
-	    if (x == prev_x + 1) {
-		row[prev_x] = prev_alpha;
-	    }
-	    else {
-		memset(row + prev_x, prev_alpha, x - prev_x);
-	    }
+	    vertices = _cairo_gl_span_renderer_get_vbo(renderer, 2);
+	    v = 0;
+
+	    vertices[v++] = prev_x;
+	    vertices[v++] = y;
+	    vertices[v++] = int_as_float(prev_alpha << 24);
+
+	    vertices[v++] = x;
+	    vertices[v++] = y;
+	    vertices[v++] = int_as_float(prev_alpha << 24);
 	}
 
 	prev_x = x;
@@ -1556,7 +1621,15 @@ _cairo_gl_surface_span_renderer_render_row (
     }
 
     if (prev_alpha != 0 && prev_x < xmax) {
-	memset(row + prev_x, prev_alpha, xmax - prev_x);
+	vertices = _cairo_gl_span_renderer_get_vbo(renderer, 2);
+	v = 0;
+	vertices[v++] = prev_x;
+	vertices[v++] = y;
+	vertices[v++] = int_as_float(prev_alpha << 24);
+
+	vertices[v++] = xmax;
+	vertices[v++] = y;
+	vertices[v++] = int_as_float(prev_alpha << 24);
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -1566,7 +1639,9 @@ static void
 _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
 {
     cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-    if (!renderer) return;
+
+    if (!renderer)
+	return;
 
     if (renderer->mask != NULL)
 	cairo_surface_destroy (&renderer->mask->base);
@@ -1584,6 +1659,15 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
     int width = rects->width;
     int height = rects->height;
 
+    _cairo_gl_span_renderer_flush(renderer);
+
+    glBindBuffer (GL_ARRAY_BUFFER_ARB, 0);
+    glDeleteBuffers (1, &renderer->vbo);
+    glDisable (GL_VERTEX_ARRAY);
+    glDisable (GL_COLOR_ARRAY);
+
+    _cairo_gl_context_release (renderer->dst->ctx);
+
     if (renderer->pattern == NULL || renderer->mask == NULL)
 	return CAIRO_STATUS_SUCCESS;
 
@@ -1672,6 +1756,9 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
     if (renderer == NULL)
 	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
 
+    if (!GLEW_ARB_vertex_buffer_object)
+	return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED);
+
     renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
     renderer->base.finish = _cairo_gl_surface_span_renderer_finish;
     renderer->base.render_row =
@@ -1685,8 +1772,8 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 
     /* TODO: support rendering to A1 surfaces (or: go add span
      * compositing to pixman.) */
-    renderer->mask = (cairo_image_surface_t *)
-	cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
+    renderer->mask = (cairo_gl_surface_t *)
+	cairo_gl_surface_create (dst->ctx, CAIRO_CONTENT_ALPHA, width, height);
 
     status = cairo_surface_status (&renderer->mask->base);
 
@@ -1694,6 +1781,22 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 	_cairo_gl_surface_span_renderer_destroy (renderer);
 	return _cairo_span_renderer_create_in_error (status);
     }
+
+    _cairo_gl_context_acquire (dst->ctx);
+    _cairo_gl_set_destination (renderer->mask);
+
+    /* Fix up the projection matrix from _cairo_gl_set_destination --
+     * we want to translate incoming vertices from
+     * (rectangles.mask.x, rectangles.mask.y) to the origin.
+     */
+    glMatrixMode (GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(renderer->composite_rectangles.mask.x,
+	    renderer->composite_rectangles.mask.x + renderer->mask->width,
+	    renderer->composite_rectangles.mask.y,
+	    renderer->composite_rectangles.mask.y + renderer->mask->height,
+	    -1.0, 1.0);
+
     return &renderer->base;
 }
 
commit 934af24ccce9c06fc38ab7735d643d230fb3b8ad
Author: Eric Anholt <eric at anholt.net>
Date:   Sat May 9 10:03:06 2009 -0700

    [gl] Use the span renderer with an image surface temporary.
    
    This appears to be no performance difference in cairogears versus the traps
    fallback before, but is a step towards handing the information off to the
    hardware.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 8bf6e29..4147563 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1491,6 +1491,212 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
     return CAIRO_STATUS_SUCCESS;
 }
 
+typedef struct _cairo_gl_surface_span_renderer {
+    cairo_span_renderer_t base;
+
+    cairo_operator_t op;
+    const cairo_pattern_t *pattern;
+    cairo_antialias_t antialias;
+
+    cairo_image_surface_t *mask;
+    cairo_gl_surface_t *dst;
+
+    cairo_composite_rectangles_t composite_rectangles;
+} cairo_gl_surface_span_renderer_t;
+
+static cairo_status_t
+_cairo_gl_surface_span_renderer_render_row (
+    void				*abstract_renderer,
+    int					 y,
+    const cairo_half_open_span_t	*spans,
+    unsigned				 num_spans)
+{
+    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
+    int xmin = renderer->composite_rectangles.mask.x;
+    int xmax = xmin + renderer->composite_rectangles.width;
+    uint8_t *row;
+    int prev_x = xmin;
+    int prev_alpha = 0;
+    unsigned i;
+
+    /* Make sure we're within y-range. */
+    y -= renderer->composite_rectangles.mask.y;
+    if (y < 0 || y >= renderer->composite_rectangles.height)
+	return CAIRO_STATUS_SUCCESS;
+
+    row = (uint8_t*)(renderer->mask->data) + y*(size_t)renderer->mask->stride - xmin;
+
+    /* Find the first span within x-range. */
+    for (i=0; i < num_spans && spans[i].x < xmin; i++) {}
+    if (i>0)
+	prev_alpha = spans[i-1].coverage;
+
+    /* Set the intermediate spans. */
+    for (; i < num_spans; i++) {
+	int x = spans[i].x;
+
+	if (x >= xmax)
+	    break;
+
+	if (prev_alpha != 0) {
+	    /* We implement setting rendering the most common single
+	     * pixel wide span case to avoid the overhead of a memset
+	     * call.  Open coding setting longer spans didn't show a
+	     * noticeable improvement over memset. */
+	    if (x == prev_x + 1) {
+		row[prev_x] = prev_alpha;
+	    }
+	    else {
+		memset(row + prev_x, prev_alpha, x - prev_x);
+	    }
+	}
+
+	prev_x = x;
+	prev_alpha = spans[i].coverage;
+    }
+
+    if (prev_alpha != 0 && prev_x < xmax) {
+	memset(row + prev_x, prev_alpha, xmax - prev_x);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
+{
+    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
+    if (!renderer) return;
+
+    if (renderer->mask != NULL)
+	cairo_surface_destroy (&renderer->mask->base);
+
+    free (renderer);
+}
+
+static cairo_status_t
+_cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
+{
+    cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
+    cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_pattern_t *mask_pattern = NULL;
+    int width = rects->width;
+    int height = rects->height;
+
+    if (renderer->pattern == NULL || renderer->mask == NULL)
+	return CAIRO_STATUS_SUCCESS;
+
+    status = cairo_surface_status (&renderer->mask->base);
+    if (status != CAIRO_STATUS_SUCCESS)
+	goto fail;
+    /*
+    status = _cairo_gl_surface_clone_similar (renderer->src,
+					      renderer->mask,
+					      0,
+					      0,
+					      renderer->mask->width,
+					      renderer->mask->height,
+					      &mask_x, &mask_y,
+					      &mask_gl);
+    if (status != CAIRO_STATUS_SUCCESS)
+	goto fail;
+    */
+    mask_pattern = cairo_pattern_create_for_surface (&renderer->mask->base);
+
+    status = _cairo_gl_surface_composite (renderer->op,
+					  renderer->pattern,
+					  mask_pattern,
+					  renderer->dst,
+					  rects->src.x,
+					  rects->src.y,
+					  0,
+					  0,
+					  rects->dst.x,
+					  rects->dst.y,
+					  width, height);
+    if (status != CAIRO_STATUS_SUCCESS)
+	goto fail;
+
+    /*
+    if (! _cairo_operator_bounded_by_mask (renderer->op))
+	status = _cairo_surface_composite_shape_fixup_unbounded (
+		&dst->base,
+		src_attributes,
+		src->width, src->height,
+		rects->width, rects->height,
+		rects->src.x, rects->src.y,
+		0, 0,
+		rects->dst.x, rects->dst.y,
+		rects->width, rects->height);
+*/
+
+fail:
+    cairo_pattern_destroy (mask_pattern);
+
+    if (status != CAIRO_STATUS_SUCCESS)
+	return _cairo_span_renderer_set_error (abstract_renderer,
+					       status);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+_cairo_gl_surface_check_span_renderer (cairo_operator_t	  op,
+				       const cairo_pattern_t  *pattern,
+				       void			 *abstract_dst,
+				       cairo_antialias_t	  antialias,
+				       const cairo_composite_rectangles_t *rects)
+{
+    (void) op;
+    (void) pattern;
+    (void) abstract_dst;
+    (void) antialias;
+    (void) rects;
+    return TRUE;
+}
+
+static cairo_span_renderer_t *
+_cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
+					const cairo_pattern_t  *pattern,
+					void			*abstract_dst,
+					cairo_antialias_t	 antialias,
+					const cairo_composite_rectangles_t *rects)
+{
+    cairo_gl_surface_t *dst = abstract_dst;
+    cairo_gl_surface_span_renderer_t *renderer = calloc(1, sizeof(*renderer));
+    cairo_status_t status;
+    int width = rects->width;
+    int height = rects->height;
+
+    if (renderer == NULL)
+	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;
+    renderer->base.render_row =
+	_cairo_gl_surface_span_renderer_render_row;
+    renderer->op = op;
+    renderer->pattern = pattern;
+    renderer->antialias = antialias;
+    renderer->dst = dst;
+
+    renderer->composite_rectangles = *rects;
+
+    /* TODO: support rendering to A1 surfaces (or: go add span
+     * compositing to pixman.) */
+    renderer->mask = (cairo_image_surface_t *)
+	cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
+
+    status = cairo_surface_status (&renderer->mask->base);
+
+    if (status != CAIRO_STATUS_SUCCESS) {
+	_cairo_gl_surface_span_renderer_destroy (renderer);
+	return _cairo_span_renderer_create_in_error (status);
+    }
+    return &renderer->base;
+}
+
 static cairo_int_status_t
 _cairo_gl_surface_get_extents (void		     *abstract_surface,
 			       cairo_rectangle_int_t *rectangle)
@@ -1517,8 +1723,8 @@ static const cairo_surface_backend_t _cairo_gl_surface_backend = {
     _cairo_gl_surface_composite,
     _cairo_gl_surface_fill_rectangles,
     _cairo_gl_surface_composite_trapezoids,
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    _cairo_gl_surface_create_span_renderer,
+    _cairo_gl_surface_check_span_renderer,
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* set_clip_region */
commit 17b41fe7e3b8b493341be6384d816105aadf0cb6
Author: Eric Anholt <eric at anholt.net>
Date:   Sun May 10 10:17:27 2009 -0700

    [gl] Use filtering of GL_NEAREST to hint to TexImage not to alloc for mipmaps.
    
    Gl defaults to NEAREST_MIPMAP_LINEAR on new texture objects.
    This should save space or bandwidth with DRI drivers, as they'll use the
    parameter as a hint, and then not have to either fix up later or waste
    space for unused mipmap levels.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 1f5b0d7..8bf6e29 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -383,6 +383,8 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     /* Create the texture used to store the surface's data. */
     glGenTextures (1, &surface->tex);
     glBindTexture (GL_TEXTURE_2D, surface->tex);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0,
 		  format, GL_UNSIGNED_BYTE, NULL);
 
@@ -955,6 +957,11 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 	    image_surface->depth) == 0);
     glPixelStorei (GL_UNPACK_ROW_LENGTH,
 		   image_surface->stride / (image_surface->depth / 8));
+    /* The filter will be correctly set up later, but for now we want to
+     * hint to glTexImage that we're not mipmapping.
+     */
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexImage2D (GL_TEXTURE_2D, 0, internal_format,
 		  image_surface->width, image_surface->height, 0,
 		  format, type, image_surface->data);
commit a438acd37c5aaedc7e7a05e6a9d8758315931b44
Author: Eric Anholt <eric at anholt.net>
Date:   Sat May 9 11:33:53 2009 -0700

    [gl] Handle PIXMAN_b8g8r8a and PIXMAN_b8g8r8x8 in the image tex shortcut.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index b75c10f..1f5b0d7 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -883,6 +883,11 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
 	format = GL_RGB;
 	type = GL_UNSIGNED_INT_8_8_8_8_REV;
 	break;
+    case PIXMAN_b8g8r8a8:
+	internal_format = GL_BGRA;
+	format = GL_BGRA;
+	type = GL_UNSIGNED_INT_8_8_8_8;
+	break;
     case PIXMAN_r8g8b8:
 	internal_format = GL_RGB;
 	format = GL_RGB;
@@ -938,6 +943,7 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
     case PIXMAN_g1:
     case PIXMAN_yuy2:
     case PIXMAN_yv12:
+    case PIXMAN_b8g8r8x8:
     default:
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
commit 29768c2193b09d3bef54a178c8e3ba6f7e7cebd0
Author: Eric Anholt <eric at anholt.net>
Date:   Sat May 9 11:30:11 2009 -0700

    [gl] Don't forget that we require ARB_texture_non_power_of_two currently.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 5590e1b..b75c10f 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -151,7 +151,8 @@ cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
 	return NULL;
     }
 
-    if (!GLEW_EXT_framebuffer_object || !GLEW_ARB_texture_env_combine) {
+    if (!GLEW_EXT_framebuffer_object || !GLEW_ARB_texture_env_combine ||
+	!GLEW_ARB_texture_non_power_of_two) {
 	free(ctx);
 	return NULL;
     }
commit 979337dd4da40abb2ea49968a2c01709d9046aab
Author: Eric Anholt <eric at anholt.net>
Date:   Sat Mar 28 21:53:04 2009 -0700

    [gl] Wire blend factors using dst alpha to constants for CAIRO_CONTENT_COLOR.
    
    This fixes the operator and operator-alpha tests to rgb24 destinations.
    While we request an RGB texture, the returned texture has alpha bits, so when
    we blend against it as a renderbuffer, we get the junk alpha values.  Whether
    or not this is a driver bug, we'll have this problem when we get visuals
    with alpha bits for windows despite not requestiong alpha, so we have to
    handle it in cairo.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index a36f4bb..5590e1b 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -246,7 +246,7 @@ _cairo_gl_set_destination (cairo_gl_surface_t *surface)
 }
 
 static int
-_cairo_gl_set_operator (cairo_operator_t op)
+_cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op)
 {
     struct {
 	GLenum src;
@@ -268,11 +268,25 @@ _cairo_gl_set_operator (cairo_operator_t op)
 	{ GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
 	{ GL_ONE, GL_ONE }, /* Add */
     };
+    GLenum src_factor, dst_factor;
 
     if (op >= ARRAY_SIZE (blend_factors))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    glBlendFunc (blend_factors[op].src, blend_factors[op].dst);
+    src_factor = blend_factors[op].src;
+    dst_factor = blend_factors[op].dst;
+
+    /* We may have a visual with alpha bits despite the user requesting
+     * CAIRO_CONTENT_COLOR.  So clear out those bits in that case.
+     */
+    if (dst->content == CAIRO_CONTENT_COLOR) {
+	if (src_factor == GL_ONE_MINUS_DST_ALPHA)
+	    src_factor = GL_ZERO;
+	if (src_factor == GL_DST_ALPHA)
+	    src_factor = GL_ONE;
+    }
+
+    glBlendFunc (src_factor, dst_factor);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1214,7 +1228,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 
     ctx = _cairo_gl_context_acquire (dst->ctx);
     _cairo_gl_set_destination (dst);
-    status = _cairo_gl_set_operator (op);
+    status = _cairo_gl_set_operator (dst, op);
     if (status != CAIRO_STATUS_SUCCESS) {
 	_cairo_gl_operand_destroy (&setup.src);
 	if (mask != NULL)
@@ -1409,7 +1423,7 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
     ctx = _cairo_gl_context_acquire (surface->ctx);
 
     _cairo_gl_set_destination (surface);
-    status = _cairo_gl_set_operator (op);
+    status = _cairo_gl_set_operator (surface, op);
     if (status != CAIRO_STATUS_SUCCESS) {
 	_cairo_gl_context_release (ctx);
 	return status;
commit 809f7dc4c83009f0a67bc8af0608b480bf7fb00e
Author: Eric Anholt <eric at anholt.net>
Date:   Sat Mar 28 21:30:13 2009 -0700

    [gl] Make sure test visuals for CAIRO_CONTENT_COLOR_ALPHA have alpha bits.
    
    Since we're just making FBOs, the visual chosen probably shouldn't matter,
    and it doesn't on Intel.  But it does seem like the right thing to do.

diff --git a/boilerplate/cairo-boilerplate-gl.c b/boilerplate/cairo-boilerplate-gl.c
index b914ce0..e818341 100644
--- a/boilerplate/cairo-boilerplate-gl.c
+++ b/boilerplate/cairo-boilerplate-gl.c
@@ -66,12 +66,19 @@ _cairo_boilerplate_gl_create_surface (const char		 *name,
 				       int			  id,
 				       void			**closure)
 {
-    int attribs[] = { GLX_RGBA,
-		      GLX_RED_SIZE, 1,
-		      GLX_GREEN_SIZE, 1,
-		      GLX_BLUE_SIZE, 1,
-		      GLX_DOUBLEBUFFER,
-		      None };
+    int rgba_attribs[] = { GLX_RGBA,
+			   GLX_RED_SIZE, 1,
+			   GLX_GREEN_SIZE, 1,
+			   GLX_BLUE_SIZE, 1,
+			   GLX_ALPHA_SIZE, 1,
+			   GLX_DOUBLEBUFFER,
+			   None };
+    int rgb_attribs[] = { GLX_RGBA,
+			  GLX_RED_SIZE, 1,
+			  GLX_GREEN_SIZE, 1,
+			  GLX_BLUE_SIZE, 1,
+			  GLX_DOUBLEBUFFER,
+			  None };
     XVisualInfo *visinfo;
     GLXContext gl_ctx;
     gl_target_closure_t *gltc;
@@ -96,7 +103,11 @@ _cairo_boilerplate_gl_create_surface (const char		 *name,
     if (mode == CAIRO_BOILERPLATE_MODE_TEST)
 	XSynchronize (gltc->dpy, 1);
 
-    visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), attribs);
+    if (content == CAIRO_CONTENT_COLOR)
+	visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs);
+    else
+	visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
+
     if (visinfo == NULL) {
 	fprintf (stderr, "Failed to create RGB, double-buffered visual\n");
 	XCloseDisplay (dpy);
commit 93c437d4b9261bc1ce3daf9cbd02d9cc4d2584cc
Author: Eric Anholt <eric at anholt.net>
Date:   Sat Mar 28 20:59:01 2009 -0700

    [gl] Use GLEW to detect required extension presence.

diff --git a/configure.ac b/configure.ac
index 2cbd713..4d1e811 100644
--- a/configure.ac
+++ b/configure.ac
@@ -196,6 +196,15 @@ CAIRO_ENABLE_SURFACE_BACKEND(gl, gl, no, [
   gl_REQUIRES="gl"
   PKG_CHECK_MODULES(gl, $gl_REQUIRES, , [AC_MSG_RESULT(no)
   use_gl="no (requires gl.pc)"])
+
+  AC_CHECK_LIB(GLEW, glewInit, [
+    AC_CHECK_HEADER(GL/glew.h, [], [
+      have_gl="no (requires glew http://glew.sourceforge.net/)"
+    ])
+  ], [
+    have_gl="no (requires glew http://glew.sourceforge.net/)"
+  ])
+  gl_NONPKGCONFIG_LIBS="-lGLEW"
 ])
 
 dnl ===========================================================================
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index bf931ed..a36f4bb 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -38,6 +38,7 @@
 
 #include <X11/Xlib.h>
 
+#include <GL/glew.h>
 #define GL_GLEXT_PROTOTYPES
 #include <GL/glx.h>
 #include <GL/glext.h>
@@ -127,6 +128,7 @@ cairo_gl_context_t *
 cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
 {
     cairo_gl_context_t *ctx;
+    GLenum err;
 
     ctx = calloc (1, sizeof(cairo_gl_context_t));
     if (ctx == NULL)
@@ -143,6 +145,17 @@ cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
      */
     glXMakeCurrent(dpy, RootWindow (dpy, DefaultScreen (dpy)), gl_ctx);
 
+    err = glewInit();
+    if (err != GLEW_OK) {
+	free(ctx);
+	return NULL;
+    }
+
+    if (!GLEW_EXT_framebuffer_object || !GLEW_ARB_texture_env_combine) {
+	free(ctx);
+	return NULL;
+    }
+
     /* Set up the dummy texture for tex_env_combine with constant color. */
     glGenTextures (1, &ctx->dummy_tex);
     glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex);
commit 2df498ba452b188f2f40413c91fec5e5ed9cf967
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Mar 5 23:26:44 2009 -0800

    [gl] Use triangle fan instead of GL_QUADS for the single quad we draw.
    
    This saves the driver from converting the quad into tris on its own.  We'd
    rather be able to specify a rect as 2-3 points and use the rectangular
    rendering feature that most of our hardware has, if it was possible, but
    it isn't exposed in GL.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 3c09ae1..bf931ed 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1437,7 +1437,7 @@ _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
     glEnableClientState (GL_VERTEX_ARRAY);
     glColorPointer (4, GL_FLOAT, sizeof(GLfloat) * 4, colors);
     glEnableClientState (GL_COLOR_ARRAY);
-    glDrawArrays (GL_QUADS, 0, 4 * num_rects);
+    glDrawArrays (GL_TRIANGLE_FAN, 0, 4 * num_rects);
 
     glDisableClientState (GL_COLOR_ARRAY);
     glDisableClientState (GL_VERTEX_ARRAY);
commit 54228cb5fe0c41b10f0ec4a206b5fac28823cde6
Author: Eric Anholt <eric at anholt.net>
Date:   Sun Feb 15 14:29:55 2009 -0800

    [gl] Use textures and not fbo-based surfaces for image surface patterns.
    
    This cuts the BO allocation overhead for traps in more than half, and reduces
    the load on the accelerator.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 25b722a..3c09ae1 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -762,9 +762,6 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
     pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
     pixman_trapezoid_t *pixman_traps;
     cairo_image_surface_t *image_surface;
-    cairo_surface_t *gl_surface;
-    cairo_status_t status;
-    int gl_offset_x, gl_offset_y;
     int i;
 
     /* Convert traps to pixman traps */
@@ -808,16 +805,167 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
     if (pixman_traps != stack_traps)
 	free (pixman_traps);
 
-    status = _cairo_surface_clone_similar (&dst->base, &image_surface->base,
-					   0, 0, width, height,
-					   &gl_offset_x, &gl_offset_y,
-					   &gl_surface);
+    *pattern = cairo_pattern_create_for_surface (&image_surface->base);
     cairo_surface_destroy (&image_surface->base);
-    if (status)
-	return status;
 
-    *pattern = cairo_pattern_create_for_surface (gl_surface);
-    cairo_surface_destroy (gl_surface);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
+				       const cairo_pattern_t *src,
+				       cairo_gl_surface_t *dst,
+				       int src_x, int src_y,
+				       int dst_x, int dst_y,
+				       int width, int height)
+{
+    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src;
+    cairo_image_surface_t *image_surface;
+    cairo_matrix_t m;
+    cairo_surface_attributes_t *attributes;
+    GLuint tex;
+    GLenum format, internal_format, type;
+
+    if (src->type != CAIRO_PATTERN_TYPE_SURFACE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (!_cairo_surface_is_image (surface_pattern->surface))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    image_surface = (cairo_image_surface_t *)surface_pattern->surface;
+
+    switch (image_surface->pixman_format) {
+    case PIXMAN_a8r8g8b8:
+	internal_format = GL_RGBA;
+	format = GL_BGRA;
+	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	break;
+    case PIXMAN_x8r8g8b8:
+	internal_format = GL_RGB;
+	format = GL_BGR;
+	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	break;
+    case PIXMAN_a8b8g8r8:
+	internal_format = GL_RGBA;
+	format = GL_RGBA;
+	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	break;
+    case PIXMAN_x8b8g8r8:
+	internal_format = GL_RGB;
+	format = GL_RGB;
+	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	break;
+    case PIXMAN_r8g8b8:
+	internal_format = GL_RGB;
+	format = GL_RGB;
+	type = GL_UNSIGNED_BYTE;
+	break;
+    case PIXMAN_b8g8r8:
+	internal_format = GL_RGB;
+	format = GL_BGR;
+	type = GL_UNSIGNED_BYTE;
+	break;
+    case PIXMAN_r5g6b5:
+	internal_format = GL_RGB;
+	format = GL_RGB;
+	type = GL_UNSIGNED_SHORT_5_6_5;
+	break;
+    case PIXMAN_b5g6r5:
+	internal_format = GL_RGB;
+	format = GL_BGR;
+	type = GL_UNSIGNED_SHORT_5_6_5;
+	break;
+    case PIXMAN_a8:
+	internal_format = GL_ALPHA;
+	format = GL_ALPHA;
+	type = GL_UNSIGNED_BYTE;
+	break;
+
+    case PIXMAN_a1r5g5b5:
+    case PIXMAN_x1r5g5b5:
+    case PIXMAN_a1b5g5r5:
+    case PIXMAN_x1b5g5r5:
+    case PIXMAN_a2b10g10r10:
+    case PIXMAN_x2b10g10r10:
+    case PIXMAN_a4r4g4b4:
+    case PIXMAN_x4r4g4b4:
+    case PIXMAN_a4b4g4r4:
+    case PIXMAN_x4b4g4r4:
+    case PIXMAN_r3g3b2:
+    case PIXMAN_b2g3r3:
+    case PIXMAN_a2r2g2b2:
+    case PIXMAN_a2b2g2r2:
+    case PIXMAN_c8:
+    case PIXMAN_x4a4:
+    /* case PIXMAN_x4c4: */
+    case PIXMAN_x4g4:
+    case PIXMAN_a4:
+    case PIXMAN_r1g2b1:
+    case PIXMAN_b1g2r1:
+    case PIXMAN_a1r1g1b1:
+    case PIXMAN_a1b1g1r1:
+    case PIXMAN_c4:
+    case PIXMAN_g4:
+    case PIXMAN_a1:
+    case PIXMAN_g1:
+    case PIXMAN_yuy2:
+    case PIXMAN_yv12:
+    default:
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    glGenTextures (1, &tex);
+    glBindTexture (GL_TEXTURE_2D, tex);
+    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+    assert(((image_surface->stride * image_surface->depth) %
+	    image_surface->depth) == 0);
+    glPixelStorei (GL_UNPACK_ROW_LENGTH,
+		   image_surface->stride / (image_surface->depth / 8));
+    glTexImage2D (GL_TEXTURE_2D, 0, internal_format,
+		  image_surface->width, image_surface->height, 0,
+		  format, type, image_surface->data);
+    glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+
+    attributes = &operand->operand.texture.attributes;
+
+    operand->type = OPERAND_TEXTURE;
+    operand->operand.texture.tex = tex;
+    operand->operand.texture.surface = NULL;
+    attributes->matrix = src->matrix;
+    attributes->extend = src->extend;
+    attributes->filter = src->filter;
+    /* Demote the filter if we're doing a 1:1 mapping of pixels. */
+    if ((src->filter == CAIRO_FILTER_GOOD ||
+	 src->filter == CAIRO_FILTER_BEST ||
+	 src->filter == CAIRO_FILTER_BILINEAR) &&
+	_cairo_matrix_is_pixel_exact (&src->matrix)) {
+	attributes->filter = CAIRO_FILTER_NEAREST;
+    }
+
+    attributes->x_offset = 0;
+    attributes->y_offset = 0;
+
+
+    /* Set up translation matrix for
+     * (unnormalized dst -> unnormalized src)
+     */
+    cairo_matrix_init_translate (&m,
+				 src_x - dst_x,
+				 src_y - dst_y);
+    cairo_matrix_multiply(&attributes->matrix,
+			  &m,
+			  &attributes->matrix);
+
+    /* Translate the matrix from
+     * (unnormalized src -> unnormalized src) to
+     * (unnormalized dst -> normalized src)
+     */
+    cairo_matrix_init_scale (&m,
+			     1.0 / image_surface->width,
+			     1.0 / image_surface->height);
+    cairo_matrix_multiply (&attributes->matrix,
+			   &attributes->matrix,
+			   &m);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -841,6 +989,14 @@ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
 
     attributes = &operand->operand.texture.attributes;
 
+    /* First, try to just upload it to a texture if it's an image surface. */
+    status = _cairo_gl_pattern_image_texture_setup (operand, src, dst,
+						    src_x, src_y,
+						    dst_x, dst_y,
+						    width, height);
+    if (status == CAIRO_STATUS_SUCCESS)
+	return CAIRO_STATUS_SUCCESS;
+
     /* Avoid looping in acquire surface fallback -> clone similar -> paint ->
      * gl_composite -> acquire surface -> fallback.
      */
@@ -941,14 +1097,19 @@ _cairo_gl_operand_init(cairo_gl_composite_operand_t *operand,
 static void
 _cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand)
 {
-
     switch (operand->type) {
     case OPERAND_CONSTANT:
 	break;
     case OPERAND_TEXTURE:
-	_cairo_pattern_release_surface(operand->pattern,
-				       &operand->operand.texture.surface->base,
-				       &operand->operand.texture.attributes);
+	if (operand->operand.texture.surface != NULL) {
+	    cairo_gl_surface_t *surface = operand->operand.texture.surface;
+
+	    _cairo_pattern_release_surface (operand->pattern,
+					    &surface->base,
+					    &operand->operand.texture.attributes);
+	} else {
+	    glDeleteTextures (1, &operand->operand.texture.tex);
+	}
 	break;
     }
 }
commit 4c6e7a16032fb223f4224d4355c2ea046cd8fc4b
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Feb 11 05:09:23 2009 -0800

    [gl] Add support for constant color directly, not through a texture.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 2bf8675..25b722a 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1,6 +1,7 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
  * Copyright © 2005 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
@@ -67,8 +68,39 @@ struct _cairo_gl_context {
     GLXContext gl_ctx;
     cairo_mutex_t mutex; /* needed? */
     cairo_gl_surface_t *current_target;
+    GLuint dummy_tex;
 };
 
+enum cairo_gl_composite_operand_type {
+    OPERAND_CONSTANT,
+    OPERAND_TEXTURE,
+};
+
+/* This union structure describes a potential source or mask operand to the
+ * compositing equation.
+ */
+typedef struct cairo_gl_composite_operand {
+    enum cairo_gl_composite_operand_type type;
+    union {
+	struct {
+	    GLuint tex;
+	    cairo_gl_surface_t *surface;
+	    cairo_surface_attributes_t attributes;
+	    cairo_bool_t has_alpha;
+	} texture;
+	struct {
+	    GLfloat color[4];
+	} constant;
+    } operand;
+
+    const cairo_pattern_t *pattern;
+} cairo_gl_composite_operand_t;
+
+typedef struct _cairo_gl_composite_setup {
+    cairo_gl_composite_operand_t src;
+    cairo_gl_composite_operand_t mask;
+} cairo_gl_composite_setup_t;
+
 static const cairo_surface_backend_t _cairo_gl_surface_backend;
 
 const cairo_gl_context_t _nil_context = {
@@ -111,6 +143,12 @@ cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
      */
     glXMakeCurrent(dpy, RootWindow (dpy, DefaultScreen (dpy)), gl_ctx);
 
+    /* Set up the dummy texture for tex_env_combine with constant color. */
+    glGenTextures (1, &ctx->dummy_tex);
+    glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex);
+    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
+		  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
     return ctx;
 }
 
@@ -142,6 +180,8 @@ cairo_gl_context_destroy (cairo_gl_context_t *context)
     if (! _cairo_reference_count_dec_and_test (&context->ref_count))
 	return;
 
+    glDeleteTextures (1, &context->dummy_tex);
+
     free (context);
 }
 
@@ -225,12 +265,11 @@ _cairo_gl_set_operator (cairo_operator_t op)
 }
 
 static void
-_cairo_gl_set_texture_surface (int tex_unit, cairo_gl_surface_t *surface,
+_cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
 			       cairo_surface_attributes_t *attributes)
 {
-    assert(surface->base.backend = &_cairo_gl_surface_backend);
     glActiveTexture (GL_TEXTURE0 + tex_unit);
-    glBindTexture (GL_TEXTURE_2D, surface->tex);
+    glBindTexture (GL_TEXTURE_2D, tex);
     switch (attributes->extend) {
     case CAIRO_EXTEND_NONE:
 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
@@ -788,17 +827,19 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
  * from dest to src coords.
  */
 static cairo_status_t
-_cairo_gl_pattern_acquire_surface (const cairo_pattern_t *src,
-				   cairo_gl_surface_t *dst,
-				   int src_x, int src_y,
-				   int dst_x, int dst_y,
-				   int width, int height,
-				   cairo_gl_surface_t **out_surface,
-				   cairo_surface_attributes_t *out_attributes)
+_cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
+				 const cairo_pattern_t *src,
+				 cairo_gl_surface_t *dst,
+				 int src_x, int src_y,
+				 int dst_x, int dst_y,
+				 int width, int height)
 {
     cairo_status_t status;
     cairo_matrix_t m;
     cairo_gl_surface_t *surface;
+    cairo_surface_attributes_t *attributes;
+
+    attributes = &operand->operand.texture.attributes;
 
     /* Avoid looping in acquire surface fallback -> clone similar -> paint ->
      * gl_composite -> acquire surface -> fallback.
@@ -820,23 +861,34 @@ _cairo_gl_pattern_acquire_surface (const cairo_pattern_t *src,
 					     width, height,
 					     (cairo_surface_t **)
 					     &surface,
-					     out_attributes);
+					     attributes);
+    operand->operand.texture.surface = surface;
     if (unlikely (status))
 	return status;
 
     assert(surface->base.backend == &_cairo_gl_surface_backend);
-    *out_surface = surface;
+
+    operand->operand.texture.tex = surface->tex;
+    switch (surface->base.content) {
+    case CAIRO_CONTENT_ALPHA:
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	operand->operand.texture.has_alpha = TRUE;
+	break;
+    case CAIRO_CONTENT_COLOR:
+	operand->operand.texture.has_alpha = FALSE;
+	break;
+    }
 
     /* Translate the matrix from
      * (unnormalized src -> unnormalized src) to
      * (unnormalized dst -> unnormalized src)
      */
     cairo_matrix_init_translate (&m,
-				 src_x - dst_x + out_attributes->x_offset,
-				 src_y - dst_y + out_attributes->y_offset);
-    cairo_matrix_multiply (&out_attributes->matrix,
+				 src_x - dst_x + attributes->x_offset,
+				 src_y - dst_y + attributes->y_offset);
+    cairo_matrix_multiply (&attributes->matrix,
 			   &m,
-			   &out_attributes->matrix);
+			   &attributes->matrix);
 
 
     /* Translate the matrix from
@@ -846,14 +898,96 @@ _cairo_gl_pattern_acquire_surface (const cairo_pattern_t *src,
     cairo_matrix_init_scale (&m,
 			     1.0 / surface->width,
 			     1.0 / surface->height);
-    cairo_matrix_multiply (&out_attributes->matrix,
-			   &out_attributes->matrix,
+    cairo_matrix_multiply (&attributes->matrix,
+			   &attributes->matrix,
 			   &m);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
+_cairo_gl_operand_init(cairo_gl_composite_operand_t *operand,
+		       const cairo_pattern_t *pattern,
+		       cairo_gl_surface_t *dst,
+		       int src_x, int src_y,
+		       int dst_x, int dst_y,
+		       int width, int height)
+{
+    cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern;
+
+    operand->pattern = pattern;
+
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
+	operand->type = OPERAND_CONSTANT;
+	operand->operand.constant.color[0] = solid->color.red * solid->color.alpha;
+	operand->operand.constant.color[1] = solid->color.green * solid->color.alpha;
+	operand->operand.constant.color[2] = solid->color.blue * solid->color.alpha;
+	operand->operand.constant.color[3] = solid->color.alpha;
+	return CAIRO_STATUS_SUCCESS;
+    default:
+    case CAIRO_PATTERN_TYPE_SURFACE:
+    case CAIRO_PATTERN_TYPE_LINEAR:
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	operand->type = OPERAND_TEXTURE;
+	return _cairo_gl_pattern_texture_setup(operand,
+					       pattern, dst,
+					       src_x, src_y,
+					       dst_x, dst_y,
+					       width, height);
+    }
+}
+
+static void
+_cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand)
+{
+
+    switch (operand->type) {
+    case OPERAND_CONSTANT:
+	break;
+    case OPERAND_TEXTURE:
+	_cairo_pattern_release_surface(operand->pattern,
+				       &operand->operand.texture.surface->base,
+				       &operand->operand.texture.attributes);
+	break;
+    }
+}
+
+static void
+_cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx, int tex_unit,
+					  GLfloat *color)
+{
+    glActiveTexture (GL_TEXTURE0 + tex_unit);
+    /* Have to have a dummy texture bound in order to use the combiner unit. */
+    glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex);
+    glEnable (GL_TEXTURE_2D);
+
+    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
+    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+    if (tex_unit == 0) {
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+    } else {
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+    }
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
+    if (tex_unit == 0) {
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+    } else {
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+    }
+}
+
+static cairo_int_status_t
 _cairo_gl_surface_composite (cairo_operator_t		  op,
 			     const cairo_pattern_t	 *src,
 			     const cairo_pattern_t	 *mask,
@@ -868,8 +1002,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 			     unsigned int		  height)
 {
     cairo_gl_surface_t	*dst = abstract_dst;
-    cairo_gl_surface_t *src_surface, *mask_surface;
-    cairo_surface_attributes_t src_attributes, mask_attributes;
+    cairo_surface_attributes_t *src_attributes, *mask_attributes = NULL;
     cairo_gl_context_t *ctx;
     GLfloat vertices[4][2];
     GLfloat texcoord_src[4][2];
@@ -878,80 +1011,102 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     int i;
     GLenum err;
     GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
+    cairo_gl_composite_setup_t setup;
 
-    status = _cairo_gl_pattern_acquire_surface(src, dst,
-					       src_x, src_y,
-					       dst_x, dst_y,
-					       width, height,
-					       &src_surface,
-					       &src_attributes);
+    memset(&setup, 0, sizeof(setup));
+
+    status = _cairo_gl_operand_init (&setup.src, src, dst,
+				     src_x, src_y,
+				     dst_x, dst_y,
+				     width, height);
     if (unlikely (status))
 	return status;
+    src_attributes = &setup.src.operand.texture.attributes;
 
     if (mask != NULL && _cairo_pattern_is_opaque(mask))
 	mask = NULL;
 
     if (mask != NULL) {
-	status = _cairo_gl_pattern_acquire_surface(mask, dst,
-						   mask_x, mask_y,
-						   dst_x, dst_y,
-						   width, height,
-						   &mask_surface,
-						   &mask_attributes);
+	status = _cairo_gl_operand_init (&setup.mask, mask, dst,
+					 mask_x, mask_y,
+					 dst_x, dst_y,
+					 width, height);
 	if (unlikely (status)) {
-	    _cairo_pattern_release_surface(src,
-					   &src_surface->base,
-					   &src_attributes);
+	    _cairo_gl_operand_destroy (&setup.src);
 	    return status;
 	}
+	mask_attributes = &setup.mask.operand.texture.attributes;
     }
 
     ctx = _cairo_gl_context_acquire (dst->ctx);
     _cairo_gl_set_destination (dst);
     status = _cairo_gl_set_operator (op);
     if (status != CAIRO_STATUS_SUCCESS) {
+	_cairo_gl_operand_destroy (&setup.src);
+	if (mask != NULL)
+	    _cairo_gl_operand_destroy (&setup.mask);
 	_cairo_gl_context_release (ctx);
 	return status;
     }
 
     glEnable (GL_BLEND);
 
-    /* Set up the constant color we use to set alpha to 1 if needed. */
-    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
-    _cairo_gl_set_texture_surface (0, src_surface, &src_attributes);
-    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
-    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
-
-    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
-    /* Wire the src alpha to 1 if the surface doesn't have it.
-     * We may have a teximage with alpha bits even though we didn't ask
-     * for it and we don't pay attention to setting alpha to 1 in a dest
-     * that has inadvertent alpha.
-     */
-    if (src_surface->base.content != CAIRO_CONTENT_COLOR)
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
-    else
-	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);
-    if (mask != NULL) {
-	_cairo_gl_set_texture_surface (1, mask_surface, &mask_attributes);
-
-	/* IN: dst.argb = src.argb * mask.aaaa */
+    switch (setup.src.type) {
+    case OPERAND_CONSTANT:
+	_cairo_gl_set_tex_combine_constant_color (ctx, 0,
+	    setup.src.operand.constant.color);
+	break;
+    case OPERAND_TEXTURE:
+	_cairo_gl_set_texture_surface (0, setup.src.operand.texture.tex,
+				       src_attributes);
+	/* Set up the constant color we use to set alpha to 1 if needed. */
+	glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
+	/* Set up the combiner to just set color to the sampled texture. */
 	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_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_COMBINE_RGB, GL_REPLACE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
+	/* Wire the src alpha to 1 if the surface doesn't have it.
+	 * We may have a teximage with alpha bits even though we didn't ask
+	 * for it and we don't pay attention to setting alpha to 1 in a dest
+	 * that has inadvertent alpha.
+	 */
+	if (setup.src.operand.texture.has_alpha)
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
+	else
+	    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;
+    }
 
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
-	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
-	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+    if (mask != NULL) {
+	switch (setup.mask.type) {
+	case OPERAND_CONSTANT:
+	    _cairo_gl_set_tex_combine_constant_color (ctx, 1,
+		setup.mask.operand.constant.color);
+	    break;
+	case OPERAND_TEXTURE:
+	    _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex,
+					   mask_attributes);
+
+	    /* IN: dst.argb = src.argb * mask.aaaa */
+	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
+	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+	    break;
+	}
     }
 
     vertices[0][0] = dst_x;
@@ -966,36 +1121,40 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     glVertexPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, vertices);
     glEnableClientState (GL_VERTEX_ARRAY);
 
-    for (i = 0; i < 4; i++) {
-	double s, t;
-
-	s = vertices[i][0];
-	t = vertices[i][1];
-	cairo_matrix_transform_point (&src_attributes.matrix, &s, &t);
-	texcoord_src[i][0] = s;
-	texcoord_src[i][1] = t;
-    }
-
-    glClientActiveTexture (GL_TEXTURE0);
-    glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_src);
-    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
-
-    if (mask != NULL) {
+    if (setup.src.type == OPERAND_TEXTURE) {
 	for (i = 0; i < 4; i++) {
 	    double s, t;
 
 	    s = vertices[i][0];
 	    t = vertices[i][1];
-	    cairo_matrix_transform_point (&mask_attributes.matrix, &s, &t);
-	    texcoord_mask[i][0] = s;
-	    texcoord_mask[i][1] = t;
+	    cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
+	    texcoord_src[i][0] = s;
+	    texcoord_src[i][1] = t;
 	}
 
-	glClientActiveTexture (GL_TEXTURE1);
-	glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_mask);
+	glClientActiveTexture (GL_TEXTURE0);
+	glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_src);
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
     }
 
+    if (mask != NULL) {
+	if (setup.mask.type == OPERAND_TEXTURE) {
+	    for (i = 0; i < 4; i++) {
+		double s, t;
+
+		s = vertices[i][0];
+		t = vertices[i][1];
+		cairo_matrix_transform_point (&mask_attributes->matrix, &s, &t);
+		texcoord_mask[i][0] = s;
+		texcoord_mask[i][1] = t;
+	    }
+
+	    glClientActiveTexture (GL_TEXTURE1);
+	    glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_mask);
+	    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+	}
+    }
+
     glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
 
     glDisable (GL_BLEND);
@@ -1017,9 +1176,9 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 
     _cairo_gl_context_release (ctx);
 
-    _cairo_pattern_release_surface (src, &src_surface->base, &src_attributes);
+    _cairo_gl_operand_destroy (&setup.src);
     if (mask != NULL)
-	_cairo_pattern_release_surface (mask, &mask_surface->base, &mask_attributes);
+	_cairo_gl_operand_destroy (&setup.mask);
 
     return CAIRO_STATUS_SUCCESS;
 }
commit 31fb7382d22c9293c093b60716ee4e393fa0d5cf
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Feb 11 05:09:51 2009 -0800

    [gl] Fix some memory leaks on boilerplate-based runs.

diff --git a/boilerplate/cairo-boilerplate-gl.c b/boilerplate/cairo-boilerplate-gl.c
index 8a0422c..b914ce0 100644
--- a/boilerplate/cairo-boilerplate-gl.c
+++ b/boilerplate/cairo-boilerplate-gl.c
@@ -39,6 +39,7 @@ typedef struct _gl_target_closure {
     Display *dpy;
     int screen;
 
+    GLXContext gl_ctx;
     cairo_gl_context_t *ctx;
     cairo_surface_t *surface;
 } gl_target_closure_t;
@@ -49,6 +50,7 @@ _cairo_boilerplate_gl_cleanup (void *closure)
     gl_target_closure_t *gltc = closure;
 
     cairo_gl_context_destroy (gltc->ctx);
+    glXDestroyContext (gltc->dpy, gltc->gl_ctx);
     XCloseDisplay (gltc->dpy);
     free (gltc);
 }
@@ -103,7 +105,9 @@ _cairo_boilerplate_gl_create_surface (const char		 *name,
     }
 
     gl_ctx = glXCreateContext (dpy, visinfo, NULL, True);
+    XFree (visinfo);
 
+    gltc->gl_ctx = gl_ctx;
     gltc->ctx = cairo_gl_glx_context_create (dpy, gl_ctx);
 
     gltc->surface = cairo_gl_surface_create (gltc->ctx, content,
commit df96fc1f92b68ef3e76750d0891377980e039b09
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Feb 9 15:42:09 2009 -0800

    [gl] Avoid re-binding the same draw buffer.
    
    The driver could be smarter and avoid a lot of the cost, but this is easy
    and avoids needing much driver smarts.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 47745c5..2bf8675 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -161,16 +161,22 @@ _cairo_gl_context_release (cairo_gl_context_t *ctx)
 static void
 _cairo_gl_set_destination (cairo_gl_surface_t *surface)
 {
-    if (surface->fb) {
-	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
-	glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
-	glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
-    } else {
-	/* Set the window as the target of our context. */
-	glXMakeCurrent (surface->ctx->dpy, surface->win, surface->ctx->gl_ctx);
-	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
-	glDrawBuffer (GL_BACK_LEFT);
-	glReadBuffer (GL_BACK_LEFT);
+    cairo_gl_context_t *ctx = surface->ctx;
+
+    if (ctx->current_target != surface) {
+	ctx->current_target = surface;
+
+	if (surface->fb) {
+	    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
+	    glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
+	    glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
+	} else {
+	    /* Set the window as the target of our context. */
+	    glXMakeCurrent (ctx->dpy, surface->win, ctx->gl_ctx);
+	    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
+	    glDrawBuffer (GL_BACK_LEFT);
+	    glReadBuffer (GL_BACK_LEFT);
+	}
     }
 
     glViewport (0, 0, surface->width, surface->height);
@@ -588,6 +594,10 @@ _cairo_gl_surface_finish (void *abstract_surface)
 
     glDeleteFramebuffersEXT (1, &surface->fb);
     glDeleteTextures (1, &surface->tex);
+
+    if (surface->ctx->current_target == surface)
+	surface->ctx->current_target = NULL;
+
     cairo_gl_context_destroy(surface->ctx);
 
     return CAIRO_STATUS_SUCCESS;
commit fb6937565be558e7ff8ba3dd815a427721783cba
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Feb 9 15:30:21 2009 -0800

    [gl] Add interface for creating surfaces from window backbuffers.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index c24e059..47745c5 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -54,6 +54,7 @@ typedef struct _cairo_gl_surface {
     cairo_content_t content;
     int width, height;
 
+    Window win; /* window if not rendering to FBO */
     GLuint tex; /* GL texture object containing our data. */
     GLuint fb; /* GL framebuffer object wrapping our data. */
 } cairo_gl_surface_t;
@@ -75,6 +76,11 @@ const cairo_gl_context_t _nil_context = {
     CAIRO_STATUS_NO_MEMORY
 };
 
+static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
+{
+    return surface->backend == &_cairo_gl_surface_backend;
+}
+
 static cairo_gl_context_t *
 _cairo_gl_context_create_in_error (cairo_status_t status)
 {
@@ -155,15 +161,26 @@ _cairo_gl_context_release (cairo_gl_context_t *ctx)
 static void
 _cairo_gl_set_destination (cairo_gl_surface_t *surface)
 {
-    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
-    glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
-    glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
+    if (surface->fb) {
+	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
+	glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
+	glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
+    } else {
+	/* Set the window as the target of our context. */
+	glXMakeCurrent (surface->ctx->dpy, surface->win, surface->ctx->gl_ctx);
+	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
+	glDrawBuffer (GL_BACK_LEFT);
+	glReadBuffer (GL_BACK_LEFT);
+    }
 
     glViewport (0, 0, surface->width, surface->height);
 
     glMatrixMode (GL_PROJECTION);
     glLoadIdentity();
-    glOrtho(0, surface->width, 0, surface->height, -1.0, 1.0);
+    if (surface->fb)
+	glOrtho(0, surface->width, 0, surface->height, -1.0, 1.0);
+    else
+	glOrtho(0, surface->width, surface->height, 0, -1.0, 1.0);
 
     glMatrixMode (GL_MODELVIEW);
     glLoadIdentity();
@@ -328,6 +345,66 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     return &surface->base;
 }
 
+
+cairo_surface_t *
+cairo_gl_surface_create_for_window (cairo_gl_context_t   *ctx,
+				    Window                win,
+				    int                   width,
+				    int                   height)
+{
+    cairo_gl_surface_t *surface;
+    cairo_content_t content = CAIRO_CONTENT_COLOR_ALPHA;
+
+    surface = calloc (1, sizeof (cairo_gl_surface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_surface_init (&surface->base,
+			 &_cairo_gl_surface_backend,
+			 content);
+
+    surface->ctx = cairo_gl_context_reference (ctx);
+    surface->content = content;
+    surface->width = width;
+    surface->height = height;
+    surface->win = win;
+
+    return &surface->base;
+}
+
+void
+cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
+			   int              width,
+			   int              height)
+{
+    cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+    cairo_status_t status;
+
+    if (! _cairo_surface_is_gl (abstract_surface) || surface->fb) {
+	status = _cairo_surface_set_error (abstract_surface,
+		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return;
+    }
+
+    surface->width = width;
+    surface->height = height;
+}
+
+void
+cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
+{
+    cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+    cairo_status_t status;
+
+    if (! _cairo_surface_is_gl (abstract_surface) || surface->fb) {
+	status = _cairo_surface_set_error (abstract_surface,
+		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return;
+    }
+
+    glXSwapBuffers(surface->ctx->dpy, surface->win);
+}
+
 static cairo_surface_t *
 _cairo_gl_surface_create_similar (void		 *abstract_surface,
 				  cairo_content_t  content,
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
index ffe5879..eb98977 100644
--- a/src/cairo-gl.h
+++ b/src/cairo-gl.h
@@ -64,17 +64,16 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
 cairo_public cairo_surface_t *
 cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
 				    Window win,
-				    cairo_content_t content,
 				    int width, int height);
 
 cairo_public cairo_gl_context_t *
 cairo_gl_surface_get_context (cairo_surface_t *abstract_surface);
 
-cairo_public int
-cairo_gl_surface_get_width (cairo_surface_t *surface);
+cairo_public void
+cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
 
-cairo_public int
-cairo_gl_surface_get_height (cairo_surface_t *surface);
+cairo_public void
+cairo_gl_surface_swapbuffers (cairo_surface_t *surface);
 
 cairo_public cairo_status_t
 cairo_gl_surface_glfinish (cairo_surface_t *surface);
commit 6cc3d8dcc0fe418c56a519180163bd49fbdb9730
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Feb 9 12:30:20 2009 -0800

    [gl] Fix unantialiased-shapes tests.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 14cc210..c24e059 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -630,6 +630,7 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
 			     int width, int height,
 			     cairo_trapezoid_t *traps,
 			     int num_traps,
+			     cairo_antialias_t antialias,
 			     cairo_pattern_t **pattern)
 {
     pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
@@ -661,8 +662,14 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
 	pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
     }
 
-    image_surface = (cairo_image_surface_t*)
-	cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
+    if (antialias != CAIRO_ANTIALIAS_NONE) {
+	image_surface = (cairo_image_surface_t*)
+	    cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
+    } else {
+	image_surface = (cairo_image_surface_t*)
+	    cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
+    }
+
     if (image_surface->base.status) {
 	if (pixman_traps != stack_traps)
 	    free (pixman_traps);
@@ -948,7 +955,7 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
 
     status = _cairo_gl_get_traps_pattern (dst,
 					  dst_x, dst_y, width, height,
-					  traps, num_traps,
+					  traps, num_traps, antialias,
 					  &traps_pattern);
     if (status) {
 	fprintf(stderr, "traps falllback\n");
commit 23a8c58dc13bd9ff44f235bee8e4e7240831728a
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Feb 5 11:00:59 2009 -0800

    [gl] Fix infinite recursion on compositing A1 images.
    
    We could do this fast, but let's do it correct first.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index eb6abdc..14cc210 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -346,6 +346,16 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
     return cairo_gl_surface_create (surface->ctx, content, width, height);
 }
 
+static cairo_bool_t
+_cairo_gl_surface_draw_image_format_compatible (cairo_image_surface_t *surface)
+{
+    if (surface->pixman_format == PIXMAN_a8r8g8b8 ||
+	surface->pixman_format == PIXMAN_x8r8g8b8 ||
+	surface->pixman_format == PIXMAN_a8)
+	return TRUE;
+    else
+	return FALSE;
+}
 
 static cairo_status_t
 _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
@@ -583,6 +593,9 @@ _cairo_gl_surface_clone_similar (void		     *abstract_surface,
 	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
 	cairo_status_t status;
 
+	if (!_cairo_gl_surface_draw_image_format_compatible (image_src))
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+
 	clone = (cairo_gl_surface_t *)
 	    _cairo_gl_surface_create_similar (&surface->base, src->content,
 					      width, height);
@@ -693,6 +706,21 @@ _cairo_gl_pattern_acquire_surface (const cairo_pattern_t *src,
     cairo_matrix_t m;
     cairo_gl_surface_t *surface;
 
+    /* Avoid looping in acquire surface fallback -> clone similar -> paint ->
+     * gl_composite -> acquire surface -> fallback.
+     */
+    if (src->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	cairo_surface_pattern_t *surface_pattern;
+	cairo_image_surface_t *image_surface;
+
+	surface_pattern = (cairo_surface_pattern_t *)src;
+	if (_cairo_surface_is_image (surface_pattern->surface)) {
+	    image_surface = (cairo_image_surface_t *)surface_pattern->surface;
+	    if (!_cairo_gl_surface_draw_image_format_compatible (image_surface))
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+	}
+    }
+
     status = _cairo_pattern_acquire_surface (src, &dst->base,
 					     src_x, src_y,
 					     width, height,
commit b6dde667fa1c72c6da1970244c4f28c48a38f493
Author: Eric Anholt <eric at anholt.net>
Date:   Mon Feb 2 23:22:49 2009 -0800

    [gl] Add support for composite and composite_trapezoids.
    
    This is a simple implementation that uses GL_ARB_texture_env_combine after
    converting everything to GL surfaces (FBOs).

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index de1546d..eb6abdc 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -201,6 +201,50 @@ _cairo_gl_set_operator (cairo_operator_t op)
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void
+_cairo_gl_set_texture_surface (int tex_unit, cairo_gl_surface_t *surface,
+			       cairo_surface_attributes_t *attributes)
+{
+    assert(surface->base.backend = &_cairo_gl_surface_backend);
+    glActiveTexture (GL_TEXTURE0 + tex_unit);
+    glBindTexture (GL_TEXTURE_2D, surface->tex);
+    switch (attributes->extend) {
+    case CAIRO_EXTEND_NONE:
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+	break;
+    case CAIRO_EXTEND_PAD:
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	break;
+    case CAIRO_EXTEND_REPEAT:
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+	break;
+    case CAIRO_EXTEND_REFLECT:
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+	break;
+    }
+    switch (attributes->filter) {
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	break;
+    case CAIRO_FILTER_GOOD:
+    case CAIRO_FILTER_BEST:
+    case CAIRO_FILTER_BILINEAR:
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	break;
+    default:
+    case CAIRO_FILTER_GAUSSIAN:
+	ASSERT_NOT_REACHED;
+    }
+    glEnable (GL_TEXTURE_2D);
+}
+
 cairo_surface_t *
 cairo_gl_surface_create (cairo_gl_context_t   *ctx,
 			 cairo_content_t	content,
@@ -566,6 +610,333 @@ _cairo_gl_surface_clone_similar (void		     *abstract_surface,
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
+/** Creates a cairo-gl pattern surface for the given trapezoids */
+static cairo_status_t
+_cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
+			     int dst_x, int dst_y,
+			     int width, int height,
+			     cairo_trapezoid_t *traps,
+			     int num_traps,
+			     cairo_pattern_t **pattern)
+{
+    pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
+    pixman_trapezoid_t *pixman_traps;
+    cairo_image_surface_t *image_surface;
+    cairo_surface_t *gl_surface;
+    cairo_status_t status;
+    int gl_offset_x, gl_offset_y;
+    int i;
+
+    /* Convert traps to pixman traps */
+    pixman_traps = stack_traps;
+    if (num_traps > ARRAY_LENGTH (stack_traps)) {
+	pixman_traps = _cairo_malloc_ab (num_traps, sizeof (pixman_trapezoid_t));
+	if (unlikely (pixman_traps == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    for (i = 0; i < num_traps; i++) {
+	pixman_traps[i].top = _cairo_fixed_to_16_16 (traps[i].top);
+	pixman_traps[i].bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
+	pixman_traps[i].left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
+	pixman_traps[i].left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
+	pixman_traps[i].left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
+	pixman_traps[i].left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
+	pixman_traps[i].right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
+	pixman_traps[i].right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
+	pixman_traps[i].right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
+	pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
+    }
+
+    image_surface = (cairo_image_surface_t*)
+	cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
+    if (image_surface->base.status) {
+	if (pixman_traps != stack_traps)
+	    free (pixman_traps);
+	return image_surface->base.status;
+    }
+
+    pixman_add_trapezoids (image_surface->pixman_image, -dst_x, -dst_y,
+			   num_traps, pixman_traps);
+
+    if (pixman_traps != stack_traps)
+	free (pixman_traps);
+
+    status = _cairo_surface_clone_similar (&dst->base, &image_surface->base,
+					   0, 0, width, height,
+					   &gl_offset_x, &gl_offset_y,
+					   &gl_surface);
+    cairo_surface_destroy (&image_surface->base);
+    if (status)
+	return status;
+
+    *pattern = cairo_pattern_create_for_surface (gl_surface);
+    cairo_surface_destroy (gl_surface);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * Like cairo_pattern_acquire_surface, but returns a matrix that transforms
+ * from dest to src coords.
+ */
+static cairo_status_t
+_cairo_gl_pattern_acquire_surface (const cairo_pattern_t *src,
+				   cairo_gl_surface_t *dst,
+				   int src_x, int src_y,
+				   int dst_x, int dst_y,
+				   int width, int height,
+				   cairo_gl_surface_t **out_surface,
+				   cairo_surface_attributes_t *out_attributes)
+{
+    cairo_status_t status;
+    cairo_matrix_t m;
+    cairo_gl_surface_t *surface;
+
+    status = _cairo_pattern_acquire_surface (src, &dst->base,
+					     src_x, src_y,
+					     width, height,
+					     (cairo_surface_t **)
+					     &surface,
+					     out_attributes);
+    if (unlikely (status))
+	return status;
+
+    assert(surface->base.backend == &_cairo_gl_surface_backend);
+    *out_surface = surface;
+
+    /* Translate the matrix from
+     * (unnormalized src -> unnormalized src) to
+     * (unnormalized dst -> unnormalized src)
+     */
+    cairo_matrix_init_translate (&m,
+				 src_x - dst_x + out_attributes->x_offset,
+				 src_y - dst_y + out_attributes->y_offset);
+    cairo_matrix_multiply (&out_attributes->matrix,
+			   &m,
+			   &out_attributes->matrix);
+
+
+    /* Translate the matrix from
+     * (unnormalized src -> unnormalized src) to
+     * (unnormalized dst -> normalized src)
+     */
+    cairo_matrix_init_scale (&m,
+			     1.0 / surface->width,
+			     1.0 / surface->height);
+    cairo_matrix_multiply (&out_attributes->matrix,
+			   &out_attributes->matrix,
+			   &m);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_composite (cairo_operator_t		  op,
+			     const cairo_pattern_t	 *src,
+			     const cairo_pattern_t	 *mask,
+			     void			 *abstract_dst,
+			     int			  src_x,
+			     int			  src_y,
+			     int			  mask_x,
+			     int			  mask_y,
+			     int			  dst_x,
+			     int			  dst_y,
+			     unsigned int		  width,
+			     unsigned int		  height)
+{
+    cairo_gl_surface_t	*dst = abstract_dst;
+    cairo_gl_surface_t *src_surface, *mask_surface;
+    cairo_surface_attributes_t src_attributes, mask_attributes;
+    cairo_gl_context_t *ctx;
+    GLfloat vertices[4][2];
+    GLfloat texcoord_src[4][2];
+    GLfloat texcoord_mask[4][2];
+    cairo_status_t status;
+    int i;
+    GLenum err;
+    GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
+
+    status = _cairo_gl_pattern_acquire_surface(src, dst,
+					       src_x, src_y,
+					       dst_x, dst_y,
+					       width, height,
+					       &src_surface,
+					       &src_attributes);
+    if (unlikely (status))
+	return status;
+
+    if (mask != NULL && _cairo_pattern_is_opaque(mask))
+	mask = NULL;
+
+    if (mask != NULL) {
+	status = _cairo_gl_pattern_acquire_surface(mask, dst,
+						   mask_x, mask_y,
+						   dst_x, dst_y,
+						   width, height,
+						   &mask_surface,
+						   &mask_attributes);
+	if (unlikely (status)) {
+	    _cairo_pattern_release_surface(src,
+					   &src_surface->base,
+					   &src_attributes);
+	    return status;
+	}
+    }
+
+    ctx = _cairo_gl_context_acquire (dst->ctx);
+    _cairo_gl_set_destination (dst);
+    status = _cairo_gl_set_operator (op);
+    if (status != CAIRO_STATUS_SUCCESS) {
+	_cairo_gl_context_release (ctx);
+	return status;
+    }
+
+    glEnable (GL_BLEND);
+
+    /* Set up the constant color we use to set alpha to 1 if needed. */
+    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
+    _cairo_gl_set_texture_surface (0, src_surface, &src_attributes);
+    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+
+    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
+    /* Wire the src alpha to 1 if the surface doesn't have it.
+     * We may have a teximage with alpha bits even though we didn't ask
+     * for it and we don't pay attention to setting alpha to 1 in a dest
+     * that has inadvertent alpha.
+     */
+    if (src_surface->base.content != CAIRO_CONTENT_COLOR)
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
+    else
+	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);
+    if (mask != NULL) {
+	_cairo_gl_set_texture_surface (1, mask_surface, &mask_attributes);
+
+	/* IN: dst.argb = src.argb * mask.aaaa */
+	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
+	glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
+	glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+    }
+
+    vertices[0][0] = dst_x;
+    vertices[0][1] = dst_y;
+    vertices[1][0] = dst_x + width;
+    vertices[1][1] = dst_y;
+    vertices[2][0] = dst_x + width;
+    vertices[2][1] = dst_y + height;
+    vertices[3][0] = dst_x;
+    vertices[3][1] = dst_y + height;
+
+    glVertexPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, vertices);
+    glEnableClientState (GL_VERTEX_ARRAY);
+
+    for (i = 0; i < 4; i++) {
+	double s, t;
+
+	s = vertices[i][0];
+	t = vertices[i][1];
+	cairo_matrix_transform_point (&src_attributes.matrix, &s, &t);
+	texcoord_src[i][0] = s;
+	texcoord_src[i][1] = t;
+    }
+
+    glClientActiveTexture (GL_TEXTURE0);
+    glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_src);
+    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+    if (mask != NULL) {
+	for (i = 0; i < 4; i++) {
+	    double s, t;
+
+	    s = vertices[i][0];
+	    t = vertices[i][1];
+	    cairo_matrix_transform_point (&mask_attributes.matrix, &s, &t);
+	    texcoord_mask[i][0] = s;
+	    texcoord_mask[i][1] = t;
+	}
+
+	glClientActiveTexture (GL_TEXTURE1);
+	glTexCoordPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, texcoord_mask);
+	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+    }
+
+    glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
+
+    glDisable (GL_BLEND);
+
+    glDisableClientState (GL_VERTEX_ARRAY);
+
+    glClientActiveTexture (GL_TEXTURE0);
+    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+    glActiveTexture (GL_TEXTURE0);
+    glDisable (GL_TEXTURE_2D);
+
+    glClientActiveTexture (GL_TEXTURE1);
+    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+    glActiveTexture (GL_TEXTURE1);
+    glDisable (GL_TEXTURE_2D);
+
+    while ((err = glGetError ()))
+	fprintf(stderr, "GL error 0x%08x\n", (int) err);
+
+    _cairo_gl_context_release (ctx);
+
+    _cairo_pattern_release_surface (src, &src_surface->base, &src_attributes);
+    if (mask != NULL)
+	_cairo_pattern_release_surface (mask, &mask_surface->base, &mask_attributes);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
+					const cairo_pattern_t *pattern,
+					void *abstract_dst,
+					cairo_antialias_t antialias,
+					int src_x, int src_y,
+					int dst_x, int dst_y,
+					unsigned int width,
+					unsigned int height,
+					cairo_trapezoid_t *traps,
+					int num_traps)
+{
+    cairo_gl_surface_t *dst = abstract_dst;
+    cairo_pattern_t *traps_pattern;
+    cairo_int_status_t status;
+
+    status = _cairo_gl_get_traps_pattern (dst,
+					  dst_x, dst_y, width, height,
+					  traps, num_traps,
+					  &traps_pattern);
+    if (status) {
+	fprintf(stderr, "traps falllback\n");
+	return status;
+    }
+
+    status = _cairo_gl_surface_composite (op, pattern, traps_pattern, dst,
+					  src_x, src_y,
+					  0, 0,
+					  dst_x, dst_y,
+					  width, height);
+    cairo_pattern_destroy (traps_pattern);
+
+    return status;
+}
+
 static cairo_int_status_t
 _cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
 				   cairo_operator_t	    op,
@@ -660,9 +1031,9 @@ static const cairo_surface_backend_t _cairo_gl_surface_backend = {
     _cairo_gl_surface_acquire_dest_image,
     _cairo_gl_surface_release_dest_image,
     _cairo_gl_surface_clone_similar,
-    NULL, /* composite */
+    _cairo_gl_surface_composite,
     _cairo_gl_surface_fill_rectangles,
-    NULL, /* composite_trapezoids */
+    _cairo_gl_surface_composite_trapezoids,
     NULL, /* create_span_renderer */
     NULL, /* check_span_renderer */
     NULL, /* copy_page */
commit 6fb4c6200c840d438e1c9cdd2c9e7b0f140863d8
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Feb 5 10:29:01 2009 -0800

    [gl] Clamp surface size to a minimum of (1,1) in create_similar.
    
    Fixes clip-zero test.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 98dd880..de1546d 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -294,6 +294,11 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
 
     assert (CAIRO_CONTENT_VALID (content));
 
+    if (width < 1)
+	width = 1;
+    if (height < 1)
+	height = 1;
+
     return cairo_gl_surface_create (surface->ctx, content, width, height);
 }
 
commit a8a40810275ff0a59f5767034372523d34fbbd1b
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Feb 5 09:43:38 2009 -0800

    [gl] clear surfaces to transparent on creation

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index c2b6cd0..98dd880 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -274,6 +274,13 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     surface->width = width;
     surface->height = height;
 
+    /* Cairo surfaces start out initialized to transparent (black) */
+    ctx = _cairo_gl_context_acquire (surface->ctx);
+    _cairo_gl_set_destination (surface);
+    glClearColor (0.0, 0.0, 0.0, 0.0);
+    glClear (GL_COLOR_BUFFER_BIT);
+    _cairo_gl_context_release (ctx);
+
     return &surface->base;
 }
 
commit e7eb6dab12b9d622b80e4202d753324f7161b269
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Jan 29 22:31:56 2009 -0800

    [gl] Hook up fill_rectangles.
    
    First actual "acceleration" for cairogears.  Actually slows things down since
    we're now pingponging between cpu and gpu.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 1d57a63..c2b6cd0 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -45,6 +45,8 @@
 
 #include "cairo-gl.h"
 
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+
 typedef struct _cairo_gl_surface {
     cairo_surface_t base;
 
@@ -137,6 +139,18 @@ cairo_gl_context_destroy (cairo_gl_context_t *context)
     free (context);
 }
 
+static cairo_gl_context_t *
+_cairo_gl_context_acquire (cairo_gl_context_t *ctx)
+{
+    CAIRO_MUTEX_LOCK (ctx->mutex);
+    return ctx;
+}
+
+static void
+_cairo_gl_context_release (cairo_gl_context_t *ctx)
+{
+    CAIRO_MUTEX_UNLOCK (ctx->mutex);
+}
 
 static void
 _cairo_gl_set_destination (cairo_gl_surface_t *surface)
@@ -155,6 +169,38 @@ _cairo_gl_set_destination (cairo_gl_surface_t *surface)
     glLoadIdentity();
 }
 
+static int
+_cairo_gl_set_operator (cairo_operator_t op)
+{
+    struct {
+	GLenum src;
+	GLenum dst;
+    } blend_factors[] = {
+	{ GL_ZERO, GL_ZERO }, /* Clear */
+	{ GL_ONE, GL_ZERO }, /* Source */
+	{ GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */
+	{ GL_DST_ALPHA, GL_ZERO }, /* In */
+	{ GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */
+	{ GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */
+
+	{ GL_ZERO, GL_ONE }, /* Dest */
+	{ GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */
+	{ GL_ZERO, GL_SRC_ALPHA }, /* DestIn */
+	{ GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */
+	{ GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */
+
+	{ GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
+	{ GL_ONE, GL_ONE }, /* Add */
+    };
+
+    if (op >= ARRAY_SIZE (blend_factors))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    glBlendFunc (blend_factors[op].src, blend_factors[op].dst);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 cairo_surface_t *
 cairo_gl_surface_create (cairo_gl_context_t   *ctx,
 			 cairo_content_t	content,
@@ -509,6 +555,77 @@ _cairo_gl_surface_clone_similar (void		     *abstract_surface,
 }
 
 static cairo_int_status_t
+_cairo_gl_surface_fill_rectangles (void			   *abstract_surface,
+				   cairo_operator_t	    op,
+				   const cairo_color_t     *color,
+				   cairo_rectangle_int_t   *rects,
+				   int			    num_rects)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+    cairo_gl_context_t *ctx;
+    cairo_int_status_t status;
+    int i;
+    GLfloat *vertices;
+    GLfloat *colors;
+
+    ctx = _cairo_gl_context_acquire (surface->ctx);
+
+    _cairo_gl_set_destination (surface);
+    status = _cairo_gl_set_operator (op);
+    if (status != CAIRO_STATUS_SUCCESS) {
+	_cairo_gl_context_release (ctx);
+	return status;
+    }
+
+    vertices = _cairo_malloc_ab(num_rects, sizeof(GLfloat) * 4 * 2);
+    colors = _cairo_malloc_ab(num_rects, sizeof(GLfloat) * 4 * 4);
+    if (!vertices || !colors) {
+	_cairo_gl_context_release(ctx);
+	free(vertices);
+	free(colors);
+	return CAIRO_STATUS_NO_MEMORY;
+    }
+
+    /* This should be loaded in as either a blend constant and an operator
+     * setup specific to this, or better, a fragment shader constant.
+     */
+    for (i = 0; i < num_rects * 4; i++) {
+	colors[i * 4 + 0] = color->red * color->alpha;
+	colors[i * 4 + 1] = color->green * color->alpha;
+	colors[i * 4 + 2] = color->blue * color->alpha;
+	colors[i * 4 + 3] = color->alpha;
+    }
+
+    for (i = 0; i < num_rects; i++) {
+	vertices[i * 8 + 0] = rects[i].x;
+	vertices[i * 8 + 1] = rects[i].y;
+	vertices[i * 8 + 2] = rects[i].x + rects[i].width;
+	vertices[i * 8 + 3] = rects[i].y;
+	vertices[i * 8 + 4] = rects[i].x + rects[i].width;
+	vertices[i * 8 + 5] = rects[i].y + rects[i].height;
+	vertices[i * 8 + 6] = rects[i].x;
+	vertices[i * 8 + 7] = rects[i].y + rects[i].height;
+    }
+
+    glEnable (GL_BLEND);
+    glVertexPointer (2, GL_FLOAT, sizeof(GLfloat) * 2, vertices);
+    glEnableClientState (GL_VERTEX_ARRAY);
+    glColorPointer (4, GL_FLOAT, sizeof(GLfloat) * 4, colors);
+    glEnableClientState (GL_COLOR_ARRAY);
+    glDrawArrays (GL_QUADS, 0, 4 * num_rects);
+
+    glDisableClientState (GL_COLOR_ARRAY);
+    glDisableClientState (GL_VERTEX_ARRAY);
+    glDisable (GL_BLEND);
+
+    _cairo_gl_context_release (ctx);
+    free(vertices);
+    free(colors);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
 _cairo_gl_surface_get_extents (void		     *abstract_surface,
 			       cairo_rectangle_int_t *rectangle)
 {
@@ -532,7 +649,7 @@ static const cairo_surface_backend_t _cairo_gl_surface_backend = {
     _cairo_gl_surface_release_dest_image,
     _cairo_gl_surface_clone_similar,
     NULL, /* composite */
-    NULL, /* fill_rectangles */
+    _cairo_gl_surface_fill_rectangles,
     NULL, /* composite_trapezoids */
     NULL, /* create_span_renderer */
     NULL, /* check_span_renderer */
commit 2ad5c3fc8fdb5941bdedcda3c972b3bae426fb32
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Feb 4 13:10:47 2009 -0800

    [gl] Add a shortcut from image to gl in clone_similar.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 13b7ac7..1d57a63 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -476,6 +476,33 @@ _cairo_gl_surface_clone_similar (void		     *abstract_surface,
 	*clone_out = cairo_surface_reference (src);
 
 	return CAIRO_STATUS_SUCCESS;
+    } else if (_cairo_surface_is_image (src)) {
+	cairo_gl_surface_t *clone;
+	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
+	cairo_status_t status;
+
+	clone = (cairo_gl_surface_t *)
+	    _cairo_gl_surface_create_similar (&surface->base, src->content,
+					      width, height);
+	if (clone == NULL)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	if (clone->base.status)
+	    return clone->base.status;
+
+	status = _cairo_gl_surface_draw_image (clone, image_src,
+					       src_x, src_y,
+					       width, height,
+					       0, 0);
+	if (status) {
+	    cairo_surface_destroy (&clone->base);
+	    return status;
+	}
+
+	*clone_out = &clone->base;
+	*clone_offset_x = src_x;
+	*clone_offset_y = src_y;
+
+	return CAIRO_STATUS_SUCCESS;
     }
 
     return CAIRO_INT_STATUS_UNSUPPORTED;
commit d9d56bb2ed552dd40415af53105a98b9d6ba39ab
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Feb 4 13:06:31 2009 -0800

    [gl] Make create_similar actually create similar instead of image.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 3589330..13b7ac7 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -237,9 +237,11 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
 				  int		  width,
 				  int		  height)
 {
+    cairo_gl_surface_t *surface = abstract_surface;
+
     assert (CAIRO_CONTENT_VALID (content));
 
-    return cairo_gl_surface_create (NULL, content, width, height);
+    return cairo_gl_surface_create (surface->ctx, content, width, height);
 }
 
 
commit 90b30219b945d6cce941a1b702c9b789a60d8b27
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Jan 29 22:27:39 2009 -0800

    [gl] Replace all-software implementation with all-GL-read/drawpixels.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 2f1b153..3589330 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1,5 +1,6 @@
 /* cairo - a vector graphics library with display and print output
  *
+ * Copyright © 2009 Eric Anholt
  * Copyright © 2005 Red Hat, Inc
  *
  * This library is free software; you can redistribute it and/or
@@ -33,6 +34,13 @@
  *	Carl Worth <cworth at cworth.org>
  */
 
+
+#include <X11/Xlib.h>
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glx.h>
+#include <GL/glext.h>
+
 #include "cairoint.h"
 
 #include "cairo-gl.h"
@@ -40,8 +48,12 @@
 typedef struct _cairo_gl_surface {
     cairo_surface_t base;
 
-    /* This is a cairo_image_surface to hold the actual contents. */
-    cairo_surface_t *backing;
+    cairo_gl_context_t *ctx;
+    cairo_content_t content;
+    int width, height;
+
+    GLuint tex; /* GL texture object containing our data. */
+    GLuint fb; /* GL framebuffer object wrapping our data. */
 } cairo_gl_surface_t;
 
 struct _cairo_gl_context {
@@ -54,7 +66,7 @@ struct _cairo_gl_context {
     cairo_gl_surface_t *current_target;
 };
 
-static const cairo_surface_backend_t cairo_gl_surface_backend;
+static const cairo_surface_backend_t _cairo_gl_surface_backend;
 
 const cairo_gl_context_t _nil_context = {
     CAIRO_REFERENCE_COUNT_INVALID,
@@ -68,6 +80,7 @@ _cairo_gl_context_create_in_error (cairo_status_t status)
 	return (cairo_gl_context_t *) &_nil_context;
 
     ASSERT_NOT_REACHED;
+    return NULL;
 }
 
 cairo_gl_context_t *
@@ -93,6 +106,21 @@ cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
     return ctx;
 }
 
+cairo_gl_context_t *
+cairo_gl_context_reference (cairo_gl_context_t *context)
+{
+    if (context == NULL ||
+	CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count))
+    {
+	return context;
+    }
+
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
+    _cairo_reference_count_inc (&context->ref_count);
+
+    return context;
+}
+
 void
 cairo_gl_context_destroy (cairo_gl_context_t *context)
 {
@@ -109,6 +137,24 @@ cairo_gl_context_destroy (cairo_gl_context_t *context)
     free (context);
 }
 
+
+static void
+_cairo_gl_set_destination (cairo_gl_surface_t *surface)
+{
+    glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
+    glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
+    glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
+
+    glViewport (0, 0, surface->width, surface->height);
+
+    glMatrixMode (GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, surface->width, 0, surface->height, -1.0, 1.0);
+
+    glMatrixMode (GL_MODELVIEW);
+    glLoadIdentity();
+}
+
 cairo_surface_t *
 cairo_gl_surface_create (cairo_gl_context_t   *ctx,
 			 cairo_content_t	content,
@@ -116,22 +162,71 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
 			 int			height)
 {
     cairo_gl_surface_t *surface;
-    cairo_surface_t *backing;
+    GLenum err, format;
+    cairo_status_t status;
 
-    backing = _cairo_image_surface_create_with_content (content, width, height);
-    if (cairo_surface_status (backing))
-	return backing;
+    if (!CAIRO_CONTENT_VALID (content))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
 
-    surface = malloc (sizeof (cairo_gl_surface_t));
-    if (unlikely (surface == NULL)) {
-	cairo_surface_destroy (backing);
-	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+    if (ctx == NULL) {
+	return cairo_image_surface_create (_cairo_format_from_content (content),
+					   width, height);
     }
+    if (ctx->status)
+	return _cairo_surface_create_in_error (ctx->status);
+
+    surface = calloc (1, sizeof (cairo_gl_surface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    _cairo_surface_init (&surface->base, &cairo_gl_surface_backend,
+    _cairo_surface_init (&surface->base,
+			 &_cairo_gl_surface_backend,
 			 content);
 
-    surface->backing = backing;
+    surface->ctx = cairo_gl_context_reference (ctx);
+    surface->content = content;
+
+    switch (content) {
+    default:
+	ASSERT_NOT_REACHED;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	format = GL_RGBA;
+	break;
+    case CAIRO_CONTENT_ALPHA:
+	format = GL_RGBA;
+	break;
+    case CAIRO_CONTENT_COLOR:
+	format = GL_RGB;
+	break;
+    }
+
+    /* Create the texture used to store the surface's data. */
+    glGenTextures (1, &surface->tex);
+    glBindTexture (GL_TEXTURE_2D, surface->tex);
+    glTexImage2D (GL_TEXTURE_2D, 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,
+			       GL_TEXTURE_2D,
+			       surface->tex,
+			       0);
+
+    while ((err = glGetError ())) {
+	fprintf(stderr, "GL error in surface create: 0x%08x\n", err);
+    }
+
+    status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
+    if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+	fprintf(stderr, "destination is framebuffer incomplete\n");
+
+    surface->width = width;
+    surface->height = height;
 
     return &surface->base;
 }
@@ -147,12 +242,162 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
     return cairo_gl_surface_create (NULL, content, width, height);
 }
 
+
+static cairo_status_t
+_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
+			      cairo_image_surface_t *src,
+			      int src_x, int src_y,
+			      int width, int height,
+			      int dst_x, int dst_y)
+{
+    char *temp_data;
+    int y;
+    unsigned int cpp;
+    GLenum format, type;
+    char *src_data_start;
+
+    /* Want to use a switch statement here but the compiler gets whiny. */
+    if (src->pixman_format == PIXMAN_a8r8g8b8) {
+	format = GL_BGRA;
+	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	cpp = 4;
+    } else if (src->pixman_format == PIXMAN_x8r8g8b8) {
+	assert(dst->content != CAIRO_CONTENT_COLOR_ALPHA);
+	assert(dst->content != CAIRO_CONTENT_ALPHA);
+	format = GL_BGRA;
+	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	cpp = 4;
+    } else if (src->pixman_format == PIXMAN_a8) {
+	format = GL_ALPHA;
+	type = GL_UNSIGNED_BYTE;
+	cpp = 1;
+    } else {
+	fprintf(stderr, "draw_image fallback\n");
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    /* Write the data to a temporary as GL wants bottom-to-top data
+     * screen-wise, and we want top-to-bottom.
+     */
+    temp_data = malloc (width * height * cpp);
+    if (temp_data == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+
+    src_data_start = (char *)src->data + (src_y * src->stride) + (src_x * cpp);
+    for (y = 0; y < height; y++) {
+	memcpy (temp_data + y * width * cpp, src_data_start +
+		y * src->stride,
+		width * cpp);
+    }
+
+    _cairo_gl_set_destination (dst);
+    glRasterPos2i (dst_x, dst_y);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glDrawPixels (width, height, format, type, temp_data);
+
+    free (temp_data);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_surface_get_image (cairo_gl_surface_t      *surface,
+			     cairo_rectangle_int_t   *interest,
+			     cairo_image_surface_t  **image_out,
+			     cairo_rectangle_int_t   *rect_out)
+{
+    cairo_image_surface_t *image;
+    cairo_rectangle_int_t extents;
+    GLenum err;
+    char *temp_data;
+    unsigned int y;
+    unsigned int cpp;
+    GLenum format, type;
+    cairo_format_t cairo_format;
+
+    extents.x = 0;
+    extents.y = 0;
+    extents.width  = surface->width;
+    extents.height = surface->height;
+
+    if (interest != NULL) {
+	if (! _cairo_rectangle_intersect (&extents, interest)) {
+	    *image_out = NULL;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+
+    if (rect_out != NULL)
+	*rect_out = extents;
+
+    /* Want to use a switch statement here but the compiler gets whiny. */
+    if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
+	format = GL_BGRA;
+	cairo_format = CAIRO_FORMAT_ARGB32;
+	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	cpp = 4;
+    } else if (surface->content == CAIRO_CONTENT_COLOR) {
+	format = GL_BGRA;
+	cairo_format = CAIRO_FORMAT_RGB24;
+	type = GL_UNSIGNED_INT_8_8_8_8_REV;
+	cpp = 4;
+    } else if (surface->content == CAIRO_CONTENT_ALPHA) {
+	format = GL_ALPHA;
+	cairo_format = CAIRO_FORMAT_A8;
+	type = GL_UNSIGNED_BYTE;
+	cpp = 1;
+    } else {
+	fprintf(stderr, "get_image fallback: %d\n", surface->content);
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    image = (cairo_image_surface_t*)
+	cairo_image_surface_create (cairo_format,
+				    extents.width, extents.height);
+    if (image->base.status)
+	return image->base.status;
+
+    /* This is inefficient, as we'd rather just read the thing without making
+     * it the destination.  But then, this is the fallback path, so let's not
+     * fall back instead.
+     */
+    _cairo_gl_set_destination(surface);
+
+    /* Read the data to a temporary as GL gives us bottom-to-top data
+     * screen-wise, and we want top-to-bottom.
+     */
+    temp_data = malloc (extents.width * extents.height * cpp);
+    if (temp_data == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+
+    glPixelStorei(GL_PACK_ALIGNMENT, 1);
+    glReadPixels(extents.x, extents.y,
+		 extents.width, extents.height,
+		 format, type, temp_data);
+
+    for (y = 0; y < extents.height; y++) {
+	memcpy ((char *)image->data + y * image->stride,
+		temp_data + y * extents.width * cpp,
+		extents.width * cpp);
+    }
+    free (temp_data);
+
+    *image_out = image;
+
+    while ((err = glGetError ()))
+	fprintf(stderr, "GL error 0x%08x\n", (int) err);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static cairo_status_t
 _cairo_gl_surface_finish (void *abstract_surface)
 {
     cairo_gl_surface_t *surface = abstract_surface;
 
-    cairo_surface_destroy (surface->backing);
+    glDeleteFramebuffersEXT (1, &surface->fb);
+    glDeleteTextures (1, &surface->tex);
+    cairo_gl_context_destroy(surface->ctx);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -164,8 +409,9 @@ _cairo_gl_surface_acquire_source_image (void		       *abstract_surface,
 {
     cairo_gl_surface_t *surface = abstract_surface;
 
-    return _cairo_surface_acquire_source_image (surface->backing,
-						image_out, image_extra);
+    *image_extra = NULL;
+
+    return _cairo_gl_surface_get_image (surface, NULL, image_out, NULL);
 }
 
 static void
@@ -173,10 +419,7 @@ _cairo_gl_surface_release_source_image (void		      *abstract_surface,
 					cairo_image_surface_t *image,
 					void		      *image_extra)
 {
-    cairo_gl_surface_t *surface = abstract_surface;
-
-    _cairo_surface_release_source_image (surface->backing,
-					 image, image_extra);
+    cairo_surface_destroy (&image->base);
 }
 
 static cairo_status_t
@@ -188,11 +431,9 @@ _cairo_gl_surface_acquire_dest_image (void		      *abstract_surface,
 {
     cairo_gl_surface_t *surface = abstract_surface;
 
-    return _cairo_surface_acquire_dest_image (surface->backing,
-					      interest_rect,
-					      image_out,
-					      image_rect_out,
-					      image_extra);
+    *image_extra = NULL;
+    return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
+					image_rect_out);
 }
 
 static void
@@ -202,13 +443,16 @@ _cairo_gl_surface_release_dest_image (void		      *abstract_surface,
 				      cairo_rectangle_int_t   *image_rect,
 				      void		      *image_extra)
 {
-    cairo_gl_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+
+    status = _cairo_gl_surface_draw_image (abstract_surface, image,
+					   0, 0,
+					   image->width, image->height,
+					   image_rect->x, image_rect->y);
+    if (status)
+	status = _cairo_surface_set_error (abstract_surface, status);
 
-    _cairo_surface_release_dest_image (surface->backing,
-				       interest_rect,
-				       image,
-				       image_rect,
-				       image_extra);
+    cairo_surface_destroy (&image->base);
 }
 
 static cairo_status_t
@@ -241,10 +485,15 @@ _cairo_gl_surface_get_extents (void		     *abstract_surface,
 {
     cairo_gl_surface_t *surface = abstract_surface;
 
-    return _cairo_surface_get_extents (surface->backing, rectangle);
+    rectangle->x = 0;
+    rectangle->y = 0;
+    rectangle->width  = surface->width;
+    rectangle->height = surface->height;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
-static const cairo_surface_backend_t cairo_gl_surface_backend = {
+static const cairo_surface_backend_t _cairo_gl_surface_backend = {
     CAIRO_SURFACE_TYPE_GL,
     _cairo_gl_surface_create_similar,
     _cairo_gl_surface_finish,
commit 235de8d7a492ccd132fb83f78d33b408bd76aec1
Author: Eric Anholt <eric at anholt.net>
Date:   Thu Jan 29 09:19:01 2009 -0800

    [gl] Add basics for GL surface backend using test-fallback as base.

diff --git a/boilerplate/Makefile.sources b/boilerplate/Makefile.sources
index b3cea81..d3c0fa1 100644
--- a/boilerplate/Makefile.sources
+++ b/boilerplate/Makefile.sources
@@ -24,6 +24,9 @@ cairo_boilerplate_beos_private = cairo-boilerplate-beos-private.h
 cairo_boilerplate_directfb_private = cairo-boilerplate-directfb-private.h
 cairo_boilerplate_directfb_sources = cairo-boilerplate-directfb.c
 
+cairo_boilerplate_gl_private = cairo-boilerplate-gl-private.h
+cairo_boilerplate_gl_sources = cairo-boilerplate-gl.c
+
 cairo_boilerplate_glitz_private = cairo-boilerplate-glitz-private.h
 cairo_boilerplate_glitz_sources = \
 	cairo-boilerplate-glitz-agl.c \
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 74f1ec1..3d55ced 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -139,6 +139,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_png_private)
 enabled_cairo_boilerplate_sources += $(cairo_boilerplate_png_sources)
 endif
 
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_gl_sources)
+ifeq ($(CAIRO_HAS_GL_SURFACE),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_sources)
+endif
+
 unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_glitz_headers)
 all_cairo_boilerplate_headers += $(cairo_boilerplate_glitz_headers)
 all_cairo_boilerplate_private += $(cairo_boilerplate_glitz_private)
diff --git a/boilerplate/cairo-boilerplate-gl-private.h b/boilerplate/cairo-boilerplate-gl-private.h
new file mode 100644
index 0000000..2d256c3
--- /dev/null
+++ b/boilerplate/cairo-boilerplate-gl-private.h
@@ -0,0 +1,59 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Chris Wilson.
+ */
+
+#ifndef CAIRO_BOILERPLATE_GL_PRIVATE_H
+#define CAIRO_BOILERPLATE_GL_PRIVATE_H
+
+#include <cairo.h>
+
+CAIRO_BEGIN_DECLS
+
+extern cairo_surface_t *
+_cairo_boilerplate_gl_create_surface (const char		 *name,
+				      cairo_content_t		  content,
+				      int			  width,
+				      int			  height,
+				      int			  max_width,
+				      int			  max_height,
+				      cairo_boilerplate_mode_t	  mode,
+				      int                         id,
+				      void			**closure);
+
+extern void
+_cairo_boilerplate_gl_cleanup (void* closure);
+
+extern void
+_cairo_boilerplate_gl_synchronize (void *closure);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_BOILERPLATE_GL_PRIVATE_H */
diff --git a/boilerplate/cairo-boilerplate-gl.c b/boilerplate/cairo-boilerplate-gl.c
new file mode 100644
index 0000000..8a0422c
--- /dev/null
+++ b/boilerplate/cairo-boilerplate-gl.c
@@ -0,0 +1,124 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Chris Wilson.
+ */
+
+#include "cairo-boilerplate.h"
+#include "cairo-boilerplate-gl-private.h"
+
+#include <cairo-gl.h>
+
+typedef struct _gl_target_closure {
+    Display *dpy;
+    int screen;
+
+    cairo_gl_context_t *ctx;
+    cairo_surface_t *surface;
+} gl_target_closure_t;
+
+void
+_cairo_boilerplate_gl_cleanup (void *closure)
+{
+    gl_target_closure_t *gltc = closure;
+
+    cairo_gl_context_destroy (gltc->ctx);
+    XCloseDisplay (gltc->dpy);
+    free (gltc);
+}
+
+cairo_surface_t *
+_cairo_boilerplate_gl_create_surface (const char		 *name,
+				       cairo_content_t		  content,
+				       int			  width,
+				       int			  height,
+				       int			  max_width,
+				       int			  max_height,
+				       cairo_boilerplate_mode_t	  mode,
+				       int			  id,
+				       void			**closure)
+{
+    int attribs[] = { GLX_RGBA,
+		      GLX_RED_SIZE, 1,
+		      GLX_GREEN_SIZE, 1,
+		      GLX_BLUE_SIZE, 1,
+		      GLX_DOUBLEBUFFER,
+		      None };
+    XVisualInfo *visinfo;
+    GLXContext gl_ctx;
+    gl_target_closure_t *gltc;
+    Display *dpy;
+
+    gltc = malloc (sizeof (gl_target_closure_t));
+    *closure = gltc;
+
+    if (width == 0)
+	width = 1;
+    if (height == 0)
+	height = 1;
+
+    dpy = XOpenDisplay (NULL);
+    gltc->dpy = dpy;
+    if (!gltc->dpy) {
+	fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0));
+	free (gltc);
+	return NULL;
+    }
+
+    if (mode == CAIRO_BOILERPLATE_MODE_TEST)
+	XSynchronize (gltc->dpy, 1);
+
+    visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), attribs);
+    if (visinfo == NULL) {
+	fprintf (stderr, "Failed to create RGB, double-buffered visual\n");
+	XCloseDisplay (dpy);
+	free (gltc);
+	return NULL;
+    }
+
+    gl_ctx = glXCreateContext (dpy, visinfo, NULL, True);
+
+    gltc->ctx = cairo_gl_glx_context_create (dpy, gl_ctx);
+
+    gltc->surface = cairo_gl_surface_create (gltc->ctx, content,
+					     width, height);
+
+    if (gltc->surface == NULL || cairo_surface_status (gltc->surface))
+	_cairo_boilerplate_gl_cleanup (gltc);
+
+    return gltc->surface;
+}
+
+void
+_cairo_boilerplate_gl_synchronize (void *closure)
+{
+    gl_target_closure_t *gltc = closure;
+
+    cairo_gl_surface_glfinish (gltc->surface);
+}
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index dd34110..09859ba 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -35,6 +35,9 @@
 #if CAIRO_HAS_DIRECTFB_SURFACE
 #include "cairo-boilerplate-directfb-private.h"
 #endif
+#if CAIRO_HAS_GL_SURFACE
+#include "cairo-boilerplate-gl-private.h"
+#endif
 #if CAIRO_HAS_GLITZ_SURFACE
 #include "cairo-boilerplate-glitz-private.h"
 #endif
@@ -356,6 +359,28 @@ static cairo_boilerplate_target_t targets[] =
 	FALSE, TRUE
     },
 #endif
+#ifdef CAIRO_HAS_GL_SURFACE
+    {
+	"gl", "gl", NULL,
+	CAIRO_SURFACE_TYPE_GL,CAIRO_CONTENT_COLOR_ALPHA, 0,
+	_cairo_boilerplate_gl_create_surface, NULL,
+	NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	_cairo_boilerplate_gl_cleanup,
+	_cairo_boilerplate_gl_synchronize,
+    },
+    {
+	"gl", "gl", NULL,
+	CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR, 0,
+	_cairo_boilerplate_gl_create_surface, NULL,
+	NULL,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	_cairo_boilerplate_gl_cleanup,
+	_cairo_boilerplate_gl_synchronize,
+    },
+#endif
 #ifdef CAIRO_HAS_GLITZ_SURFACE
 #if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
     {
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index aa7e56e..69b3b39 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -12,6 +12,7 @@ CAIRO_HAS_OS2_SURFACE=0
 CAIRO_HAS_BEOS_SURFACE=0
 CAIRO_HAS_SDL_SURFACE=0
 CAIRO_HAS_PNG_FUNCTIONS=1
+CAIRO_HAS_GL_SURFACE=0
 CAIRO_HAS_GLITZ_SURFACE=0
 CAIRO_HAS_DIRECTFB_SURFACE=0
 CAIRO_HAS_SCRIPT_SURFACE=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index 82f6121..cae8135 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -41,6 +41,9 @@ endif
 ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
 	@echo "#define CAIRO_HAS_PNG_FUNCTIONS 1" >> src/cairo-features.h
 endif
+ifeq ($(CAIRO_HAS_GL_SURFACE),1)
+	@echo "#define CAIRO_HAS_GL_SURFACE 1" >> src/cairo-features.h
+endif
 ifeq ($(CAIRO_HAS_GLITZ_SURFACE),1)
 	@echo "#define CAIRO_HAS_GLITZ_SURFACE 1" >> src/cairo-features.h
 endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index a7311c1..06ed7f3 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -372,6 +372,7 @@ AC_DEFUN([CAIRO_REPORT],
 	echo "  PostScript:    $use_ps"
 	echo "  PDF:           $use_pdf"
 	echo "  SVG:           $use_svg"
+	echo "  GL:            $use_gl"
 	echo "  glitz:         $use_glitz"
 	echo "  BeOS:          $use_beos"
 	echo "  DirectFB:      $use_directfb"
diff --git a/configure.ac b/configure.ac
index d3ed703..2cbd713 100644
--- a/configure.ac
+++ b/configure.ac
@@ -192,6 +192,13 @@ CAIRO_ENABLE_FUNCTIONS(png, PNG, yes, [
 ])
 
 dnl ===========================================================================
+CAIRO_ENABLE_SURFACE_BACKEND(gl, gl, no, [
+  gl_REQUIRES="gl"
+  PKG_CHECK_MODULES(gl, $gl_REQUIRES, , [AC_MSG_RESULT(no)
+  use_gl="no (requires gl.pc)"])
+])
+
+dnl ===========================================================================
 
 GLITZ_MIN_VERSION=0.5.1
 CAIRO_ENABLE_SURFACE_BACKEND(glitz, glitz, no, [
diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c
index 6bb48f1..6d93eb4 100644
--- a/perf/cairo-perf.c
+++ b/perf/cairo-perf.c
@@ -91,6 +91,7 @@ target_is_measurable (cairo_boilerplate_target_t *target)
 	    return TRUE;
 	}
     case CAIRO_SURFACE_TYPE_XCB:
+    case CAIRO_SURFACE_TYPE_GL:
     case CAIRO_SURFACE_TYPE_GLITZ:
     case CAIRO_SURFACE_TYPE_QUARTZ:
     case CAIRO_SURFACE_TYPE_WIN32:
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 174bb99..6407271 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -244,6 +244,10 @@ cairo_os2_sources = cairo-os2-surface.c
 cairo_beos_headers = cairo-beos.h
 #cairo_beos_sources = cairo-beos-surface.cpp
 
+cairo_gl_headers = cairo-gl.h
+cairo_gl_private =
+cairo_gl_sources = cairo-gl-surface.c
+
 cairo_glitz_headers = cairo-glitz.h
 cairo_glitz_private = cairo-glitz-private.h
 cairo_glitz_sources = cairo-glitz-surface.c
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index 921ab2d..9e7bffe 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -189,6 +189,20 @@ ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
 enabled_cairo_pkgconf += cairo-png.pc
 endif
 
+unsupported_cairo_headers += $(cairo_gl_headers)
+all_cairo_headers += $(cairo_gl_headers)
+all_cairo_private += $(cairo_gl_private)
+all_cairo_sources += $(cairo_gl_sources)
+ifeq ($(CAIRO_HAS_GL_SURFACE),1)
+enabled_cairo_headers += $(cairo_gl_headers)
+enabled_cairo_private += $(cairo_gl_private)
+enabled_cairo_sources += $(cairo_gl_sources)
+endif
+all_cairo_pkgconf += cairo-gl.pc
+ifeq ($(CAIRO_HAS_GL_SURFACE),1)
+enabled_cairo_pkgconf += cairo-gl.pc
+endif
+
 unsupported_cairo_headers += $(cairo_glitz_headers)
 all_cairo_headers += $(cairo_glitz_headers)
 all_cairo_private += $(cairo_glitz_private)
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
new file mode 100644
index 0000000..2f1b153
--- /dev/null
+++ b/src/cairo-gl-surface.c
@@ -0,0 +1,287 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Carl Worth <cworth at cworth.org>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl.h"
+
+typedef struct _cairo_gl_surface {
+    cairo_surface_t base;
+
+    /* This is a cairo_image_surface to hold the actual contents. */
+    cairo_surface_t *backing;
+} cairo_gl_surface_t;
+
+struct _cairo_gl_context {
+    cairo_reference_count_t ref_count;
+    cairo_status_t status;
+
+    Display *dpy;
+    GLXContext gl_ctx;
+    cairo_mutex_t mutex; /* needed? */
+    cairo_gl_surface_t *current_target;
+};
+
+static const cairo_surface_backend_t cairo_gl_surface_backend;
+
+const cairo_gl_context_t _nil_context = {
+    CAIRO_REFERENCE_COUNT_INVALID,
+    CAIRO_STATUS_NO_MEMORY
+};
+
+static cairo_gl_context_t *
+_cairo_gl_context_create_in_error (cairo_status_t status)
+{
+    if (status == CAIRO_STATUS_NO_MEMORY)
+	return (cairo_gl_context_t *) &_nil_context;
+
+    ASSERT_NOT_REACHED;
+}
+
+cairo_gl_context_t *
+cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
+{
+    cairo_gl_context_t *ctx;
+
+    ctx = calloc (1, sizeof(cairo_gl_context_t));
+    if (ctx == NULL)
+	return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    CAIRO_REFERENCE_COUNT_INIT (&ctx->ref_count, 1);
+    ctx->dpy = dpy;
+    ctx->gl_ctx = gl_ctx;
+
+    /* Make our GL context active.  While we'll be setting the destination
+     * drawable with each rendering operation, in order to set the context
+     * we have to choose a drawable.  The root window happens to be convenient
+     * for this.
+     */
+    glXMakeCurrent(dpy, RootWindow (dpy, DefaultScreen (dpy)), gl_ctx);
+
+    return ctx;
+}
+
+void
+cairo_gl_context_destroy (cairo_gl_context_t *context)
+{
+    if (context == NULL ||
+	CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count))
+    {
+	return;
+    }
+
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
+    if (! _cairo_reference_count_dec_and_test (&context->ref_count))
+	return;
+
+    free (context);
+}
+
+cairo_surface_t *
+cairo_gl_surface_create (cairo_gl_context_t   *ctx,
+			 cairo_content_t	content,
+			 int			width,
+			 int			height)
+{
+    cairo_gl_surface_t *surface;
+    cairo_surface_t *backing;
+
+    backing = _cairo_image_surface_create_with_content (content, width, height);
+    if (cairo_surface_status (backing))
+	return backing;
+
+    surface = malloc (sizeof (cairo_gl_surface_t));
+    if (unlikely (surface == NULL)) {
+	cairo_surface_destroy (backing);
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+    }
+
+    _cairo_surface_init (&surface->base, &cairo_gl_surface_backend,
+			 content);
+
+    surface->backing = backing;
+
+    return &surface->base;
+}
+
+static cairo_surface_t *
+_cairo_gl_surface_create_similar (void		 *abstract_surface,
+				  cairo_content_t  content,
+				  int		  width,
+				  int		  height)
+{
+    assert (CAIRO_CONTENT_VALID (content));
+
+    return cairo_gl_surface_create (NULL, content, width, height);
+}
+
+static cairo_status_t
+_cairo_gl_surface_finish (void *abstract_surface)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+
+    cairo_surface_destroy (surface->backing);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gl_surface_acquire_source_image (void		       *abstract_surface,
+					cairo_image_surface_t **image_out,
+					void		      **image_extra)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+
+    return _cairo_surface_acquire_source_image (surface->backing,
+						image_out, image_extra);
+}
+
+static void
+_cairo_gl_surface_release_source_image (void		      *abstract_surface,
+					cairo_image_surface_t *image,
+					void		      *image_extra)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+
+    _cairo_surface_release_source_image (surface->backing,
+					 image, image_extra);
+}
+
+static cairo_status_t
+_cairo_gl_surface_acquire_dest_image (void		      *abstract_surface,
+				      cairo_rectangle_int_t   *interest_rect,
+				      cairo_image_surface_t  **image_out,
+				      cairo_rectangle_int_t   *image_rect_out,
+				      void		     **image_extra)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+
+    return _cairo_surface_acquire_dest_image (surface->backing,
+					      interest_rect,
+					      image_out,
+					      image_rect_out,
+					      image_extra);
+}
+
+static void
+_cairo_gl_surface_release_dest_image (void		      *abstract_surface,
+				      cairo_rectangle_int_t   *interest_rect,
+				      cairo_image_surface_t   *image,
+				      cairo_rectangle_int_t   *image_rect,
+				      void		      *image_extra)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+
+    _cairo_surface_release_dest_image (surface->backing,
+				       interest_rect,
+				       image,
+				       image_rect,
+				       image_extra);
+}
+
+static cairo_status_t
+_cairo_gl_surface_clone_similar (void		     *abstract_surface,
+				 cairo_surface_t     *src,
+				 int                  src_x,
+				 int                  src_y,
+				 int                  width,
+				 int                  height,
+				 int                 *clone_offset_x,
+				 int                 *clone_offset_y,
+				 cairo_surface_t    **clone_out)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+
+    if (src->backend == surface->base.backend) {
+	*clone_offset_x = 0;
+	*clone_offset_y = 0;
+	*clone_out = cairo_surface_reference (src);
+
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_gl_surface_get_extents (void		     *abstract_surface,
+			       cairo_rectangle_int_t *rectangle)
+{
+    cairo_gl_surface_t *surface = abstract_surface;
+
+    return _cairo_surface_get_extents (surface->backing, rectangle);
+}
+
+static const cairo_surface_backend_t cairo_gl_surface_backend = {
+    CAIRO_SURFACE_TYPE_GL,
+    _cairo_gl_surface_create_similar,
+    _cairo_gl_surface_finish,
+    _cairo_gl_surface_acquire_source_image,
+    _cairo_gl_surface_release_source_image,
+    _cairo_gl_surface_acquire_dest_image,
+    _cairo_gl_surface_release_dest_image,
+    _cairo_gl_surface_clone_similar,
+    NULL, /* composite */
+    NULL, /* fill_rectangles */
+    NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
+    NULL, /* copy_page */
+    NULL, /* show_page */
+    NULL, /* set_clip_region */
+    NULL, /* intersect_clip_path */
+    _cairo_gl_surface_get_extents,
+    NULL, /* old_show_glyphs */
+    NULL, /* get_font_options */
+    NULL, /* flush */
+    NULL, /* mark_dirty_rectangle */
+    NULL, /* scaled_font_fini */
+    NULL, /* scaled_glyph_fini */
+    NULL, /* paint */
+    NULL, /* mask */
+    NULL, /* stroke */
+    NULL, /* fill */
+    NULL, /* show_glyphs */
+    NULL  /* snapshot */
+};
+
+/** Call glFinish(), used for accurate performance testing. */
+cairo_status_t
+cairo_gl_surface_glfinish (cairo_surface_t *surface)
+{
+    glFinish();
+
+    return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
new file mode 100644
index 0000000..ffe5879
--- /dev/null
+++ b/src/cairo-gl.h
@@ -0,0 +1,89 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Eric Anholt.
+ */
+
+#ifndef CAIRO_GL_H
+#define CAIRO_GL_H
+
+#include <GL/glx.h>
+
+#include "cairo.h"
+
+#if CAIRO_HAS_GL_SURFACE
+
+CAIRO_BEGIN_DECLS
+
+typedef struct _cairo_gl_context cairo_gl_context_t;
+
+cairo_public cairo_gl_context_t *
+cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx);
+
+cairo_public cairo_gl_context_t *
+cairo_gl_context_reference (cairo_gl_context_t *context);
+
+cairo_public cairo_status_t
+cairo_gl_context_status (cairo_gl_context_t *context);
+
+cairo_public void
+cairo_gl_context_destroy (cairo_gl_context_t *context);
+
+cairo_public cairo_surface_t *
+cairo_gl_surface_create (cairo_gl_context_t *ctx,
+			 cairo_content_t content,
+			 int width, int height);
+
+cairo_public cairo_surface_t *
+cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
+				    Window win,
+				    cairo_content_t content,
+				    int width, int height);
+
+cairo_public cairo_gl_context_t *
+cairo_gl_surface_get_context (cairo_surface_t *abstract_surface);
+
+cairo_public int
+cairo_gl_surface_get_width (cairo_surface_t *surface);
+
+cairo_public int
+cairo_gl_surface_get_height (cairo_surface_t *surface);
+
+cairo_public cairo_status_t
+cairo_gl_surface_glfinish (cairo_surface_t *surface);
+
+CAIRO_END_DECLS
+
+#else  /* CAIRO_HAS_GL_SURFACE */
+# error Cairo was not compiled with support for the GL backend
+#endif /* CAIRO_HAS_GL_SURFACE */
+
+#endif /* CAIRO_GL_H */
+
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index 8f62cb9..97f1f35 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -53,6 +53,10 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
 #endif
 
+#if CAIRO_HAS_GL_SURFACE
+CAIRO_MUTEX_DECLARE (_cairo_gl_context_mutex)
+#endif
+
 #if !defined (HAS_ATOMIC_OPS) || defined (ATOMIC_OP_NEEDS_MEMORY_BARRIER)
 CAIRO_MUTEX_DECLARE (_cairo_atomic_mutex)
 #endif
diff --git a/src/cairo.h b/src/cairo.h
index 856f7af..e35c9ca 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1879,6 +1879,7 @@ cairo_surface_status (cairo_surface_t *surface);
  * @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image
  * @CAIRO_SURFACE_TYPE_SDL: The surface is of type SDL, since 1.10
  * @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10
+ * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10
  *
  * #cairo_surface_type_t is used to describe the type of a given
  * surface. The surface types are also known as "backends" or "surface
@@ -1919,7 +1920,8 @@ typedef enum _cairo_surface_type {
     CAIRO_SURFACE_TYPE_WIN32_PRINTING,
     CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
     CAIRO_SURFACE_TYPE_SDL,
-    CAIRO_SURFACE_TYPE_SCRIPT
+    CAIRO_SURFACE_TYPE_SCRIPT,
+    CAIRO_SURFACE_TYPE_GL,
 } cairo_surface_type_t;
 
 cairo_public cairo_surface_type_t


More information about the cairo-commit mailing list