[cairo-commit] 4 commits - src/cairo-gl-composite.c src/cairo-gl-device.c src/cairo-gl-private.h src/cairo-gl-shaders.c src/cairo-gl-surface.c

Chris Wilson ickle at kemper.freedesktop.org
Mon May 17 04:50:56 PDT 2010


 src/cairo-gl-composite.c |  138 ++++++------
 src/cairo-gl-device.c    |   14 -
 src/cairo-gl-private.h   |  100 +++++----
 src/cairo-gl-shaders.c   |  508 ++++++++++++++++++++++++++---------------------
 src/cairo-gl-surface.c   |   75 +++---
 5 files changed, 450 insertions(+), 385 deletions(-)

New commits:
commit 145db7a427e594f1d68a6c0f4afe5e365e219cf0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 17 12:37:46 2010 +0100

    gl: Check status after composite_begin
    
    Skip the unnecessary work in _cairo_gl_surface_composite() if we fail
    to setup the GL composite operation.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 2fcc701..b5f33e3 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -994,6 +994,8 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     }
 
     status = _cairo_gl_composite_begin (ctx, &setup);
+    if (unlikely (status))
+	goto CLEANUP;
 
     if (clip_region != NULL) {
         int i, num_rectangles;
commit 8695c41e80ce932fd5dd434307b92f323a937c7c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 17 12:36:54 2010 +0100

    gl: Throw a _cairo_error when detecting a GLerror
    
    This allows us to easily set an breakpoint and inspect cairo's state
    when we do something illegal.

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index bb12c9b..1f03d41 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -206,8 +206,10 @@ cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
 cairo_private const char *_cairo_gl_error_to_string (GLenum err);
 #define _cairo_gl_check_error() do { \
     GLenum err; \
-    while ((err = glGetError ())) \
+    while ((err = glGetError ())) { \
 	fprintf (stderr, "%s:%d: GL error 0x%04x: %s\n", __FILE__,__LINE__, (int) err, _cairo_gl_error_to_string (err)); \
+	_cairo_error_throw (CAIRO_STATUS_DEVICE_ERROR); \
+    } \
 } while (0)
 
 static inline cairo_device_t *
commit 1c18ab02c8d41be8e5886cbb34aeda5099189fef
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 17 11:42:26 2010 +0100

    gl: Rename cairo_gl_shader_program_t to cairo_gl_shader_t
    
    And complete the move of the shaders into the cairo_gl_shader namespace.
    Of particular note, the bind_*_to_shader become
    _cairo_gl_shader_bind_*() and have proper types.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 91f94f9..98e52f9 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -565,13 +565,13 @@ _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx,
 	else
 	    uniform_name = "mask_constant";
 
-	bind_vec4_to_shader (ctx,
-                             setup->shader->program,
-                             uniform_name,
-                             color[0],
-                             color[1],
-                             color[2],
-                             color[3]);
+	_cairo_gl_shader_bind_vec4 (ctx,
+				    setup->shader,
+				    uniform_name,
+				    color[0],
+				    color[1],
+				    color[2],
+				    color[3]);
 
 	return;
     }
@@ -652,14 +652,14 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
 	glEnable (GL_TEXTURE_1D);
 
-	bind_matrix_to_shader (ctx, setup->shader->program,
-			       "source_matrix",
-			       &setup->src.operand.linear.m);
+	_cairo_gl_shader_bind_matrix (ctx, setup->shader,
+				      "source_matrix",
+				      &setup->src.operand.linear.m);
 
-	bind_vec2_to_shader (ctx, setup->shader->program,
-			     "source_segment",
-			     setup->src.operand.linear.segment_x,
-			     setup->src.operand.linear.segment_y);
+	_cairo_gl_shader_bind_vec2 (ctx, setup->shader,
+				    "source_segment",
+				    setup->src.operand.linear.segment_x,
+				    setup->src.operand.linear.segment_y);
 	break;
 
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
@@ -667,22 +667,22 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 	glBindTexture (GL_TEXTURE_1D, setup->src.operand.linear.tex);
 	glEnable (GL_TEXTURE_1D);
 
-        bind_matrix_to_shader (ctx, setup->shader->program,
-			       "source_matrix",
-			       &setup->src.operand.radial.m);
+        _cairo_gl_shader_bind_matrix (ctx, setup->shader,
+				      "source_matrix",
+				      &setup->src.operand.radial.m);
 
-        bind_vec2_to_shader (ctx, setup->shader->program,
-                             "source_circle_1",
-                             setup->src.operand.radial.circle_1_x,
-                             setup->src.operand.radial.circle_1_y);
+	_cairo_gl_shader_bind_vec2 (ctx, setup->shader,
+				    "source_circle_1",
+				    setup->src.operand.radial.circle_1_x,
+				    setup->src.operand.radial.circle_1_y);
 
-        bind_float_to_shader (ctx, setup->shader->program,
-                              "source_radius_0",
-                              setup->src.operand.radial.radius_0);
+        _cairo_gl_shader_bind_float (ctx, setup->shader,
+				     "source_radius_0",
+				     setup->src.operand.radial.radius_0);
 
-        bind_float_to_shader (ctx, setup->shader->program,
-                              "source_radius_1",
-                              setup->src.operand.radial.radius_1);
+        _cairo_gl_shader_bind_float (ctx, setup->shader,
+				     "source_radius_1",
+				     setup->src.operand.radial.radius_1);
 	break;
     default:
     case CAIRO_GL_OPERAND_COUNT:
@@ -751,13 +751,13 @@ _cairo_gl_set_linear_gradient_mask_operand (cairo_gl_context_t *ctx,
     glBindTexture (GL_TEXTURE_1D, setup->mask.operand.linear.tex);
     glEnable (GL_TEXTURE_1D);
 
-    bind_matrix_to_shader (ctx, setup->shader->program,
-			   "mask_matrix", &setup->mask.operand.linear.m);
+    _cairo_gl_shader_bind_matrix (ctx, setup->shader,
+				  "mask_matrix", &setup->mask.operand.linear.m);
 
-    bind_vec2_to_shader (ctx, setup->shader->program,
-			 "mask_segment",
-			 setup->mask.operand.linear.segment_x,
-			 setup->mask.operand.linear.segment_y);
+    _cairo_gl_shader_bind_vec2 (ctx, setup->shader,
+				"mask_segment",
+				setup->mask.operand.linear.segment_x,
+				setup->mask.operand.linear.segment_y);
 }
 
 static void
@@ -770,22 +770,22 @@ _cairo_gl_set_radial_gradient_mask_operand (cairo_gl_context_t *ctx,
     glBindTexture (GL_TEXTURE_1D, setup->mask.operand.radial.tex);
     glEnable (GL_TEXTURE_1D);
 
-    bind_matrix_to_shader (ctx, setup->shader->program,
-                           "mask_matrix",
-                           &setup->mask.operand.radial.m);
+    _cairo_gl_shader_bind_matrix (ctx, setup->shader,
+				  "mask_matrix",
+				  &setup->mask.operand.radial.m);
 
-    bind_vec2_to_shader (ctx, setup->shader->program,
-                         "mask_circle_1",
-                         setup->mask.operand.radial.circle_1_x,
-                         setup->mask.operand.radial.circle_1_y);
+    _cairo_gl_shader_bind_vec2 (ctx, setup->shader,
+				"mask_circle_1",
+				setup->mask.operand.radial.circle_1_x,
+				setup->mask.operand.radial.circle_1_y);
 
-    bind_float_to_shader (ctx, setup->shader->program,
-                          "mask_radius_0",
-                          setup->mask.operand.radial.radius_0);
+    _cairo_gl_shader_bind_float (ctx, setup->shader,
+				 "mask_radius_0",
+				 setup->mask.operand.radial.radius_0);
 
-    bind_float_to_shader (ctx, setup->shader->program,
-                          "mask_radius_1",
-                          setup->mask.operand.radial.radius_1);
+    _cairo_gl_shader_bind_float (ctx, setup->shader,
+				 "mask_radius_1",
+				 setup->mask.operand.radial.radius_1);
 }
 
 /* This is like _cairo_gl_set_src_alpha_operand, for component alpha setup
@@ -815,12 +815,12 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
     case CAIRO_GL_OPERAND_CONSTANT:
 	/* Have to have a dummy texture bound in order to use the combiner unit. */
 	if (setup->shader) {
-	    bind_vec4_to_shader (ctx, setup->shader->program,
-                                 "mask_constant",
-                                 setup->src.operand.constant.color[0],
-                                 setup->src.operand.constant.color[1],
-                                 setup->src.operand.constant.color[2],
-                                 setup->src.operand.constant.color[3]);
+	    _cairo_gl_shader_bind_vec4 (ctx, setup->shader,
+					"mask_constant",
+					setup->src.operand.constant.color[0],
+					setup->src.operand.constant.color[1],
+					setup->src.operand.constant.color[2],
+					setup->src.operand.constant.color[3]);
 	} else {
 	    glBindTexture (ctx->tex_target, ctx->dummy_tex);
 	    glActiveTexture (GL_TEXTURE1);
@@ -1044,12 +1044,12 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
      */
     if (setup->op == CAIRO_OPERATOR_OVER) {
 	setup->op = CAIRO_OPERATOR_ADD;
-        status = _cairo_gl_get_program (ctx,
-                                        setup->src.type,
-                                        setup->mask.type,
-                                        CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
-                                        &setup->pre_shader);
-        if (unlikely (_cairo_status_is_error (status)))
+	status = _cairo_gl_get_shader (ctx,
+				       setup->src.type,
+				       setup->mask.type,
+				       CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
+				       &setup->pre_shader);
+        if (unlikely (status))
             return status;
     }
 
@@ -1070,13 +1070,13 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
             return status;
     }
 
-    status = _cairo_gl_get_program (ctx,
-                                    setup->src.type,
-                                    setup->mask.type,
-				    setup->has_component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
-                                                               : CAIRO_GL_SHADER_IN_NORMAL,
-				    &setup->shader);
-    if (_cairo_status_is_error (status)) {
+    status = _cairo_gl_get_shader (ctx,
+				   setup->src.type,
+				   setup->mask.type,
+				   setup->has_component_alpha ? CAIRO_GL_SHADER_IN_CA_SOURCE
+				   : CAIRO_GL_SHADER_IN_NORMAL,
+				   &setup->shader);
+    if (unlikely (status)) {
         setup->pre_shader = NULL;
 	return status;
     }
@@ -1094,7 +1094,7 @@ _cairo_gl_composite_begin (cairo_gl_context_t *ctx,
                             setup->op,
                             setup->has_component_alpha);
 
-    _cairo_gl_use_program (ctx, setup->shader);
+    _cairo_gl_set_shader (ctx, setup->shader);
 
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, ctx->vbo);
 
@@ -1142,13 +1142,13 @@ _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
     if (! setup->pre_shader) {
         glDrawArrays (GL_TRIANGLES, 0, count);
     } else {
-        _cairo_gl_use_program (ctx, setup->pre_shader);
+        _cairo_gl_set_shader (ctx, setup->pre_shader);
         _cairo_gl_set_operator (setup->dst, CAIRO_OPERATOR_DEST_OUT, TRUE);
         _cairo_gl_set_src_alpha_operand (ctx, setup);
         _cairo_gl_set_component_alpha_mask_operand (ctx, setup);
         glDrawArrays (GL_TRIANGLES, 0, count);
 
-        _cairo_gl_use_program (ctx, setup->shader);
+        _cairo_gl_set_shader (ctx, setup->shader);
         _cairo_gl_set_operator (setup->dst, setup->op, TRUE);
         _cairo_gl_set_src_operand (ctx, setup);
         _cairo_gl_set_component_alpha_mask_operand (ctx, setup);
@@ -1332,7 +1332,7 @@ _cairo_gl_composite_end (cairo_gl_context_t *ctx,
 
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
 
-    _cairo_gl_use_program (ctx, NULL);
+    _cairo_gl_set_shader (ctx, NULL);
     glDisable (GL_BLEND);
 
     glDisableClientState (GL_VERTEX_ARRAY);
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index e506ca7..e31fc05 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -64,15 +64,10 @@ static void
 _gl_finish (void *device)
 {
     cairo_gl_context_t *ctx = device;
-    int i;
 
     _gl_lock (device);
 
-    for (i = 0; i <= CAIRO_GL_VAR_TYPE_MAX; i++) {
-        destroy_shader (ctx, ctx->vertex_shaders[i]);
-    }
-
-    _cairo_cache_fini (&ctx->shaders);
+    _cairo_gl_context_fini_shaders (ctx);
 
     _gl_unlock (device);
 }
@@ -117,6 +112,7 @@ static const cairo_device_backend_t _cairo_gl_device_backend = {
 cairo_status_t
 _cairo_gl_context_init (cairo_gl_context_t *ctx)
 {
+    cairo_status_t status;
     int n;
 
     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
@@ -162,9 +158,9 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     else
 	ctx->tex_target = GL_TEXTURE_2D;
 
-    _cairo_gl_context_init_shaders (ctx);
-
-    init_shader_program (&ctx->fill_rectangles_shader);
+    status = _cairo_gl_context_init_shaders (ctx);
+    if (unlikely (status))
+	return status;
 
     /* Set up the dummy texture for tex_env_combine with constant color. */
     glGenTextures (1, &ctx->dummy_tex);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 3c157f5..bb12c9b 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -102,11 +102,10 @@ typedef enum cairo_gl_operand_type {
 
 typedef struct cairo_gl_shader_impl cairo_gl_shader_impl_t;
 
-typedef struct cairo_gl_shader_program {
+typedef struct cairo_gl_shader {
     GLuint fragment_shader;
     GLuint program;
-    cairo_bool_t build_failure;
-} cairo_gl_shader_program_t;
+} cairo_gl_shader_t;
 
 typedef enum cairo_gl_shader_in {
     CAIRO_GL_SHADER_IN_NORMAL,
@@ -138,7 +137,7 @@ typedef struct _cairo_gl_context {
     const cairo_gl_shader_impl_t *shader_impl;
 
     GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1];
-    cairo_gl_shader_program_t fill_rectangles_shader;
+    cairo_gl_shader_t fill_rectangles_shader;
     cairo_cache_t shaders;
 
     cairo_gl_surface_t *current_target;
@@ -194,8 +193,8 @@ typedef struct _cairo_gl_composite {
 
     cairo_gl_operand_t src;
     cairo_gl_operand_t mask;
-    cairo_gl_shader_program_t *shader;
-    cairo_gl_shader_program_t *pre_shader; /* for component alpha */
+    cairo_gl_shader_t *shader;
+    cairo_gl_shader_t *pre_shader; /* for component alpha */
 
     char *vb;
     unsigned int vb_offset;
@@ -403,66 +402,74 @@ _cairo_gl_y_flip (cairo_gl_surface_t *surface, int y)
 	return (surface->height - 1) - y;
 }
 
-cairo_private void
+cairo_private cairo_status_t
 _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx);
 
 cairo_private void
-destroy_shader (cairo_gl_context_t *ctx, GLuint shader);
+_cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx);
 
 cairo_private void
-init_shader_program (cairo_gl_shader_program_t *program);
+_cairo_gl_shader_init (cairo_gl_shader_t *shader);
 
-cairo_private void
-destroy_shader_program (cairo_gl_context_t *ctx,
-                        cairo_gl_shader_program_t *program);
+cairo_private cairo_status_t
+_cairo_gl_shader_compile (cairo_gl_context_t *ctx,
+			  cairo_gl_shader_t *program,
+			  cairo_gl_var_type_t src,
+			  cairo_gl_var_type_t mask,
+			  const char *fragment_text);
 
 cairo_private cairo_status_t
-create_shader_program (cairo_gl_context_t *ctx,
-                       cairo_gl_shader_program_t *program,
-                       cairo_gl_var_type_t src,
-                       cairo_gl_var_type_t mask,
-                       const char *fragment_text);
+_cairo_gl_get_shader (cairo_gl_context_t *ctx,
+		      cairo_gl_operand_type_t source,
+		      cairo_gl_operand_type_t mask,
+		      cairo_gl_shader_in_t in,
+		      cairo_gl_shader_t **out_program);
 
 cairo_private void
-bind_float_to_shader (cairo_gl_context_t *ctx,
-                      GLuint program, const char *name,
-                      float value);
+_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
+			     cairo_gl_shader_t *shader,
+			     const char *name,
+			     float value);
 
 cairo_private void
-bind_vec2_to_shader (cairo_gl_context_t *ctx,
-                     GLuint program, const char *name,
-                     float value0, float value1);
+_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
+			    cairo_gl_shader_t *shader,
+			    const char *name,
+			    float value0, float value1);
 
 cairo_private void
-bind_vec3_to_shader (cairo_gl_context_t *ctx,
-                     GLuint program, const char *name,
-                     float value0, float value1,
-                     float value2);
+_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
+			    cairo_gl_shader_t *shader,
+			    const char *name,
+			    float value0,
+			    float value1,
+			    float value2);
 
 cairo_private void
-bind_vec4_to_shader (cairo_gl_context_t *ctx,
-                     GLuint program, const char *name,
-                     float value0, float value1,
-                     float value2, float value3);
+_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
+			    cairo_gl_shader_t *shader,
+			    const char *name,
+			    float value0, float value1,
+			    float value2, float value3);
 
 cairo_private void
-bind_matrix_to_shader (cairo_gl_context_t *ctx,
-                       GLuint program, const char *name, cairo_matrix_t* m);
+_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
+			      cairo_gl_shader_t *shader,
+			      const char *name,
+			      cairo_matrix_t* m);
 
 cairo_private void
-bind_texture_to_shader (cairo_gl_context_t *ctx,
-                        GLuint program, const char *name, GLuint tex_unit);
+_cairo_gl_shader_bind_texture (cairo_gl_context_t *ctx,
+			       cairo_gl_shader_t *shader,
+			       const char *name,
+			       GLuint tex_unit);
 
 cairo_private void
-_cairo_gl_use_program (cairo_gl_context_t *ctx,
-                       cairo_gl_shader_program_t *shader);
+_cairo_gl_set_shader (cairo_gl_context_t *ctx,
+		      cairo_gl_shader_t *shader);
 
-cairo_private cairo_status_t
-_cairo_gl_get_program (cairo_gl_context_t *ctx,
-		       cairo_gl_operand_type_t source,
-		       cairo_gl_operand_type_t mask,
-		       cairo_gl_shader_in_t in,
-		       cairo_gl_shader_program_t **out_program);
+cairo_private void
+_cairo_gl_shader_fini (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader);
 
 slim_hidden_proto (cairo_gl_surface_create);
 
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 403f76f..b364c71 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -43,10 +43,10 @@
 #include "cairo-output-stream-private.h"
 
 typedef struct cairo_gl_shader_impl {
-    cairo_status_t
+    void
     (*compile_shader) (GLuint *shader, GLenum type, const char *text);
 
-    cairo_status_t
+    void
     (*link_shader) (GLuint *program, GLuint vert, GLuint frag);
 
     void
@@ -56,36 +56,46 @@ typedef struct cairo_gl_shader_impl {
     (*destroy_program) (GLuint program);
 
     void
-    (*bind_float_to_shader) (GLuint program, const char *name,
-                             float value);
+    (*bind_float) (cairo_gl_shader_t *shader,
+		   const char *name,
+		   float value);
 
     void
-    (*bind_vec2_to_shader) (GLuint program, const char *name,
-                            float value0, float value1);
+    (*bind_vec2) (cairo_gl_shader_t *shader,
+		  const char *name,
+		  float value0,
+		  float value1);
 
     void
-    (*bind_vec3_to_shader) (GLuint program, const char *name,
-                            float value0, float value1,
-                            float value2);
+    (*bind_vec3) (cairo_gl_shader_t *shader,
+		  const char *name,
+		  float value0,
+		  float value1,
+		  float value2);
 
     void
-    (*bind_vec4_to_shader) (GLuint program, const char *name,
-                            float value0, float value1,
-                            float value2, float value3);
+    (*bind_vec4) (cairo_gl_shader_t *shader,
+		  const char *name,
+		  float value0, float value1,
+		  float value2, float value3);
 
     void
-    (*bind_matrix_to_shader) (GLuint program, const char *name, cairo_matrix_t* m);
+    (*bind_matrix) (cairo_gl_shader_t *shader,
+		    const char *name,
+		    cairo_matrix_t* m);
 
     void
-    (*bind_texture_to_shader) (GLuint program, const char *name, GLuint tex_unit);
+    (*bind_texture) (cairo_gl_shader_t *shader,
+		     const char *name,
+		     GLuint tex_unit);
 
     void
-    (*use_program) (cairo_gl_shader_program_t *program);
+    (*use) (cairo_gl_shader_t *shader);
 } shader_impl_t;
 
 /* ARB_shader_objects / ARB_vertex_shader / ARB_fragment_shader extensions
    API. */
-static cairo_status_t
+static void
 compile_shader_arb (GLuint *shader, GLenum type, const char *text)
 {
     const char* strings[1] = { text };
@@ -115,13 +125,11 @@ compile_shader_arb (GLuint *shader, GLenum type, const char *text)
             printf ("OpenGL shader compilation failed.\n");
         }
 
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+	ASSERT_NOT_REACHED;
     }
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 link_shader_arb (GLuint *program, GLuint vert, GLuint frag)
 {
     GLint gl_status;
@@ -147,10 +155,8 @@ link_shader_arb (GLuint *program, GLuint vert, GLuint frag)
             printf ("OpenGL shader link failed.\n");
         }
 
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+	ASSERT_NOT_REACHED;
     }
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -166,47 +172,57 @@ destroy_program_arb (GLuint shader)
 }
 
 static void
-bind_float_to_shader_arb (GLuint program, const char *name,
-                               float value)
+bind_float_arb (cairo_gl_shader_t *shader,
+		const char *name,
+		float value)
 {
-    GLint location = glGetUniformLocationARB (program, name);
+    GLint location = glGetUniformLocationARB (shader->program, name);
     assert (location != -1);
     glUniform1fARB (location, value);
 }
 
 static void
-bind_vec2_to_shader_arb (GLuint program, const char *name,
-                              float value0, float value1)
+bind_vec2_arb (cairo_gl_shader_t *shader,
+	       const char *name,
+	       float value0,
+	       float value1)
 {
-    GLint location = glGetUniformLocationARB (program, name);
+    GLint location = glGetUniformLocationARB (shader->program, name);
     assert (location != -1);
     glUniform2fARB (location, value0, value1);
 }
 
 static void
-bind_vec3_to_shader_arb (GLuint program, const char *name,
-                              float value0, float value1,
-                              float value2)
+bind_vec3_arb (cairo_gl_shader_t *shader,
+	       const char *name,
+	       float value0,
+	       float value1,
+	       float value2)
 {
-    GLint location = glGetUniformLocationARB (program, name);
+    GLint location = glGetUniformLocationARB (shader->program, name);
     assert (location != -1);
     glUniform3fARB (location, value0, value1, value2);
 }
 
 static void
-bind_vec4_to_shader_arb (GLuint program, const char *name,
-                              float value0, float value1,
-                              float value2, float value3)
-{
-    GLint location = glGetUniformLocationARB (program, name);
+bind_vec4_arb (cairo_gl_shader_t *shader,
+	       const char *name,
+	       float value0,
+	       float value1,
+	       float value2,
+	       float value3)
+{
+    GLint location = glGetUniformLocationARB (shader->program, name);
     assert (location != -1);
     glUniform4fARB (location, value0, value1, value2, value3);
 }
 
 static void
-bind_matrix_to_shader_arb (GLuint program, const char *name, cairo_matrix_t* m)
+bind_matrix_arb (cairo_gl_shader_t *shader,
+		 const char *name,
+		 cairo_matrix_t* m)
 {
-    GLint location = glGetUniformLocationARB (program, name);
+    GLint location = glGetUniformLocationARB (shader->program, name);
     float gl_m[16] = {
         m->xx, m->xy, 0,     m->x0,
         m->yx, m->yy, 0,     m->y0,
@@ -218,24 +234,26 @@ bind_matrix_to_shader_arb (GLuint program, const char *name, cairo_matrix_t* m)
 }
 
 static void
-bind_texture_to_shader_arb (GLuint program, const char *name, GLuint tex_unit)
+bind_texture_arb (cairo_gl_shader_t *shader,
+		  const char *name,
+		  GLuint tex_unit)
 {
-    GLint location = glGetUniformLocationARB (program, name);
+    GLint location = glGetUniformLocationARB (shader->program, name);
     assert (location != -1);
     glUniform1iARB (location, tex_unit);
 }
 
 static void
-use_program_arb (cairo_gl_shader_program_t *program)
+use_program_arb (cairo_gl_shader_t *shader)
 {
-    if (program)
-	glUseProgramObjectARB (program->program);
+    if (shader)
+	glUseProgramObjectARB (shader->program);
     else
 	glUseProgramObjectARB (0);
 }
 
 /* OpenGL Core 2.0 API. */
-static cairo_status_t
+static void
 compile_shader_core_2_0 (GLuint *shader, GLenum type, const char *text)
 {
     const char* strings[1] = { text };
@@ -265,13 +283,11 @@ compile_shader_core_2_0 (GLuint *shader, GLenum type, const char *text)
             printf ("OpenGL shader compilation failed.\n");
         }
 
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+	ASSERT_NOT_REACHED;
     }
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static void
 link_shader_core_2_0 (GLuint *program, GLuint vert, GLuint frag)
 {
     GLint gl_status;
@@ -297,10 +313,8 @@ link_shader_core_2_0 (GLuint *program, GLuint vert, GLuint frag)
             printf ("OpenGL shader link failed.\n");
         }
 
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+	ASSERT_NOT_REACHED;
     }
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -312,51 +326,59 @@ destroy_shader_core_2_0 (GLuint shader)
 static void
 destroy_program_core_2_0 (GLuint shader)
 {
-  glDeleteProgram (shader);
+    glDeleteProgram (shader);
 }
 
 static void
-bind_float_to_shader_core_2_0 (GLuint program, const char *name,
-                               float value)
+bind_float_core_2_0 (cairo_gl_shader_t *shader,
+		     const char *name,
+		     float value)
 {
-    GLint location = glGetUniformLocation (program, name);
+    GLint location = glGetUniformLocation (shader->program, name);
     assert (location != -1);
     glUniform1f (location, value);
 }
 
 static void
-bind_vec2_to_shader_core_2_0 (GLuint program, const char *name,
-                              float value0, float value1)
+bind_vec2_core_2_0 (cairo_gl_shader_t *shader,
+		    const char *name,
+		    float value0,
+		    float value1)
 {
-    GLint location = glGetUniformLocation (program, name);
+    GLint location = glGetUniformLocation (shader->program, name);
     assert (location != -1);
     glUniform2f (location, value0, value1);
 }
 
 static void
-bind_vec3_to_shader_core_2_0 (GLuint program, const char *name,
-                              float value0, float value1,
-                              float value2)
+bind_vec3_core_2_0 (cairo_gl_shader_t *shader,
+		    const char *name,
+		    float value0,
+		    float value1,
+		    float value2)
 {
-    GLint location = glGetUniformLocation (program, name);
+    GLint location = glGetUniformLocation (shader->program, name);
     assert (location != -1);
     glUniform3f (location, value0, value1, value2);
 }
 
 static void
-bind_vec4_to_shader_core_2_0 (GLuint program, const char *name,
-                              float value0, float value1,
-                              float value2, float value3)
-{
-    GLint location = glGetUniformLocation (program, name);
+bind_vec4_core_2_0 (cairo_gl_shader_t *shader,
+		    const char *name,
+		    float value0,
+		    float value1,
+		    float value2,
+		    float value3)
+{
+    GLint location = glGetUniformLocation (shader->program, name);
     assert (location != -1);
     glUniform4f (location, value0, value1, value2, value3);
 }
 
 static void
-bind_matrix_to_shader_core_2_0 (GLuint program, const char *name, cairo_matrix_t* m)
+bind_matrix_core_2_0 (cairo_gl_shader_t *shader, const char *name, cairo_matrix_t* m)
 {
-    GLint location = glGetUniformLocation (program, name);
+    GLint location = glGetUniformLocation (shader->program, name);
     float gl_m[16] = {
         m->xx, m->xy, 0,     m->x0,
         m->yx, m->yy, 0,     m->y0,
@@ -368,18 +390,18 @@ bind_matrix_to_shader_core_2_0 (GLuint program, const char *name, cairo_matrix_t
 }
 
 static void
-bind_texture_to_shader_core_2_0 (GLuint program, const char *name, GLuint tex_unit)
+bind_texture_core_2_0 (cairo_gl_shader_t *shader, const char *name, GLuint tex_unit)
 {
-    GLint location = glGetUniformLocation (program, name);
+    GLint location = glGetUniformLocation (shader->program, name);
     assert (location != -1);
     glUniform1i (location, tex_unit);
 }
 
 static void
-use_program_core_2_0 (cairo_gl_shader_program_t *program)
+use_program_core_2_0 (cairo_gl_shader_t *shader)
 {
-    if (program)
-	glUseProgram (program->program);
+    if (shader)
+	glUseProgram (shader->program);
     else
 	glUseProgram (0);
 }
@@ -389,12 +411,12 @@ static const cairo_gl_shader_impl_t shader_impl_core_2_0 = {
     link_shader_core_2_0,
     destroy_shader_core_2_0,
     destroy_program_core_2_0,
-    bind_float_to_shader_core_2_0,
-    bind_vec2_to_shader_core_2_0,
-    bind_vec3_to_shader_core_2_0,
-    bind_vec4_to_shader_core_2_0,
-    bind_matrix_to_shader_core_2_0,
-    bind_texture_to_shader_core_2_0,
+    bind_float_core_2_0,
+    bind_vec2_core_2_0,
+    bind_vec3_core_2_0,
+    bind_vec4_core_2_0,
+    bind_matrix_core_2_0,
+    bind_texture_core_2_0,
     use_program_core_2_0,
 };
 
@@ -403,12 +425,12 @@ static const cairo_gl_shader_impl_t shader_impl_arb = {
     link_shader_arb,
     destroy_shader_arb,
     destroy_program_arb,
-    bind_float_to_shader_arb,
-    bind_vec2_to_shader_arb,
-    bind_vec3_to_shader_arb,
-    bind_vec4_to_shader_arb,
-    bind_matrix_to_shader_arb,
-    bind_texture_to_shader_arb,
+    bind_float_arb,
+    bind_vec2_arb,
+    bind_vec3_arb,
+    bind_vec4_arb,
+    bind_matrix_arb,
+    bind_texture_arb,
     use_program_arb,
 };
 
@@ -421,7 +443,7 @@ typedef struct _cairo_shader_cache_entry {
     cairo_gl_shader_in_t in;
 
     cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */
-    cairo_gl_shader_program_t program;
+    cairo_gl_shader_t shader;
 } cairo_shader_cache_entry_t;
 
 static cairo_bool_t
@@ -447,13 +469,19 @@ _cairo_gl_shader_cache_destroy (void *data)
 {
     cairo_shader_cache_entry_t *entry = data;
 
-    destroy_shader_program (entry->ctx, &entry->program);
+    _cairo_gl_shader_fini (entry->ctx, &entry->shader);
     free (entry);
 }
 
-void
+cairo_status_t
 _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
 {
+    static const char *fill_fs_source =
+	"uniform vec4 color;\n"
+	"void main()\n"
+	"{\n"
+	"	gl_FragColor = color;\n"
+	"}\n";
     cairo_status_t status;
 
     /* XXX multiple device support? */
@@ -474,31 +502,50 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
                                 NULL,
                                 _cairo_gl_shader_cache_destroy,
                                 CAIRO_GL_MAX_SHADERS_PER_CONTEXT);
+    if (unlikely (status))
+	return status;
+
+    _cairo_gl_shader_init (&ctx->fill_rectangles_shader);
+    status = _cairo_gl_shader_compile (ctx,
+				       &ctx->fill_rectangles_shader,
+				       CAIRO_GL_VAR_NONE,
+				       CAIRO_GL_VAR_NONE,
+				       fill_fs_source);
+    if (unlikely (status))
+	return status;
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 void
-init_shader_program (cairo_gl_shader_program_t *program)
+_cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx)
 {
-    program->fragment_shader = 0;
-    program->program = 0;
-    program->build_failure = FALSE;
+    int i;
+
+    for (i = 0; i <= CAIRO_GL_VAR_TYPE_MAX; i++) {
+	if (ctx->vertex_shaders[i])
+	    ctx->shader_impl->destroy_shader (ctx->vertex_shaders[i]);
+    }
+
+    _cairo_cache_fini (&ctx->shaders);
 }
 
 void
-destroy_shader (cairo_gl_context_t *ctx, GLuint shader)
+_cairo_gl_shader_init (cairo_gl_shader_t *shader)
 {
-    if (shader)
-        ctx->shader_impl->destroy_shader (shader);
+    shader->fragment_shader = 0;
+    shader->program = 0;
 }
 
 void
-destroy_shader_program (cairo_gl_context_t *ctx,
-                        cairo_gl_shader_program_t *program)
+_cairo_gl_shader_fini (cairo_gl_context_t *ctx,
+		       cairo_gl_shader_t *shader)
 {
-    destroy_shader (ctx, program->fragment_shader);
+    if (shader->fragment_shader)
+        ctx->shader_impl->destroy_shader (shader->fragment_shader);
 
-    if (program->program)
-        ctx->shader_impl->destroy_program (program->program);
+    if (shader->program)
+        ctx->shader_impl->destroy_program (shader->program);
 }
 
 typedef enum cairo_gl_operand_target {
@@ -574,35 +621,39 @@ cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
     }
 }
 
-static char *
+static cairo_status_t
 cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
                                    cairo_gl_var_type_t mask,
-                                   cairo_gl_var_type_t dest)
+                                   cairo_gl_var_type_t dest,
+				   char **out)
 {
     cairo_output_stream_t *stream = _cairo_memory_stream_create ();
     unsigned char *source;
     unsigned int length;
+    cairo_status_t status;
 
     cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_OPERAND_SOURCE);
     cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_OPERAND_MASK);
     cairo_gl_shader_emit_variable (stream, dest, CAIRO_GL_OPERAND_DEST);
-    
-    _cairo_output_stream_printf (stream, 
-                                 "void main()\n"
-                                 "{\n"
-                                 "    gl_Position = ftransform();\n");
+
+    _cairo_output_stream_printf (stream,
+				 "void main()\n"
+				 "{\n"
+				 "    gl_Position = ftransform();\n");
 
     cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_OPERAND_SOURCE);
     cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_OPERAND_MASK);
     cairo_gl_shader_emit_vertex (stream, dest, CAIRO_GL_OPERAND_DEST);
-    
-    _cairo_output_stream_write (stream, 
-                                "}\n\0", 3);
 
-    if (_cairo_memory_stream_destroy (stream, &source, &length))
-        return NULL;
+    _cairo_output_stream_write (stream,
+				"}\n\0", 3);
 
-    return (char *) source;
+    status = _cairo_memory_stream_destroy (stream, &source, &length);
+    if (unlikely (status))
+	return status;
+
+    *out = (char *) source;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
@@ -706,23 +757,25 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
     }
 }
 
-static char *
+static cairo_status_t
 cairo_gl_shader_get_fragment_source (GLuint tex_target,
                                      cairo_gl_shader_in_t in,
                                      cairo_gl_operand_type_t src,
                                      cairo_gl_operand_type_t mask,
-                                     cairo_gl_operand_type_t dest)
+                                     cairo_gl_operand_type_t dest,
+				     char **out)
 {
     cairo_output_stream_t *stream = _cairo_memory_stream_create ();
     unsigned char *source;
     unsigned int length;
+    cairo_status_t status;
 
     cairo_gl_shader_emit_color (stream, tex_target, src, CAIRO_GL_OPERAND_SOURCE);
     cairo_gl_shader_emit_color (stream, tex_target, mask, CAIRO_GL_OPERAND_MASK);
     if (dest != CAIRO_GL_OPERAND_NONE)
       cairo_gl_shader_emit_color (stream, tex_target, dest, CAIRO_GL_OPERAND_DEST);
 
-    _cairo_output_stream_printf (stream, 
+    _cairo_output_stream_printf (stream,
         "void main()\n"
         "{\n");
     switch (in) {
@@ -730,155 +783,160 @@ cairo_gl_shader_get_fragment_source (GLuint tex_target,
     default:
         ASSERT_NOT_REACHED;
     case CAIRO_GL_SHADER_IN_NORMAL:
-        _cairo_output_stream_printf (stream, 
+        _cairo_output_stream_printf (stream,
             "    gl_FragColor = get_source() * get_mask().a;\n");
         break;
     case CAIRO_GL_SHADER_IN_CA_SOURCE:
-        _cairo_output_stream_printf (stream, 
+        _cairo_output_stream_printf (stream,
             "    gl_FragColor = get_source() * get_mask();\n");
         break;
     case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA:
-        _cairo_output_stream_printf (stream, 
+        _cairo_output_stream_printf (stream,
             "    gl_FragColor = get_source().a * get_mask();\n");
         break;
     }
 
-    _cairo_output_stream_write (stream, 
+    _cairo_output_stream_write (stream,
                                 "}\n\0", 3);
 
-    if (_cairo_memory_stream_destroy (stream, &source, &length))
-        return NULL;
+    status = _cairo_memory_stream_destroy (stream, &source, &length);
+    if (unlikely (status))
+        return status;
 
-    return (char *) source;
+    *out = (char *) source;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 cairo_status_t
-create_shader_program (cairo_gl_context_t *ctx,
-                       cairo_gl_shader_program_t *program,
-                       cairo_gl_var_type_t src,
-                       cairo_gl_var_type_t mask,
-                       const char *fragment_text)
+_cairo_gl_shader_compile (cairo_gl_context_t *ctx,
+			  cairo_gl_shader_t *shader,
+			  cairo_gl_var_type_t src,
+			  cairo_gl_var_type_t mask,
+			  const char *fragment_text)
 {
-    cairo_status_t status;
     unsigned int vertex_shader;
+    cairo_status_t status;
 
-    if (program->program != 0)
+    if (ctx->shader_impl == NULL)
         return CAIRO_STATUS_SUCCESS;
 
-    if (program->build_failure)
-        return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (ctx->shader_impl == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+    assert (shader->program == 0);
 
     vertex_shader = cairo_gl_var_type_hash (src, mask, CAIRO_GL_VAR_NONE);
     if (ctx->vertex_shaders[vertex_shader] == 0) {
-        char *source = cairo_gl_shader_get_vertex_source (src, mask, CAIRO_GL_VAR_NONE);
-        if (unlikely (source == NULL))
-            goto FAILURE;
+	char *source;
 
-        status = ctx->shader_impl->compile_shader (&ctx->vertex_shaders[vertex_shader],
-                                                   GL_VERTEX_SHADER,
-                                                   source);
-        free (source);
+	status = cairo_gl_shader_get_vertex_source (src,
+						    mask,
+						    CAIRO_GL_VAR_NONE,
+						    &source);
         if (unlikely (status))
             goto FAILURE;
+
+	ctx->shader_impl->compile_shader (&ctx->vertex_shaders[vertex_shader],
+					  GL_VERTEX_SHADER,
+					  source);
+        free (source);
     }
 
-    status = ctx->shader_impl->compile_shader (&program->fragment_shader,
-                                               GL_FRAGMENT_SHADER,
-                                               fragment_text);
-    if (unlikely (status))
-        goto FAILURE;
+    ctx->shader_impl->compile_shader (&shader->fragment_shader,
+				      GL_FRAGMENT_SHADER,
+				      fragment_text);
 
-    status = ctx->shader_impl->link_shader (&program->program,
-                                            ctx->vertex_shaders[vertex_shader],
-                                            program->fragment_shader);
-    if (unlikely (status))
-        goto FAILURE;
+    ctx->shader_impl->link_shader (&shader->program,
+				   ctx->vertex_shaders[vertex_shader],
+				   shader->fragment_shader);
 
     return CAIRO_STATUS_SUCCESS;
 
  FAILURE:
-    destroy_shader_program (ctx, program);
-    program->fragment_shader = 0;
-    program->program = 0;
-    program->build_failure = TRUE;
+    _cairo_gl_shader_fini (ctx, shader);
+    shader->fragment_shader = 0;
+    shader->program = 0;
 
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    return status;
 }
 
 void
-bind_float_to_shader (cairo_gl_context_t *ctx,
-                      GLuint program, const char *name,
-                      float value)
+_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
+			     cairo_gl_shader_t *shader,
+			     const char *name,
+			     float value)
 {
-    ctx->shader_impl->bind_float_to_shader(program, name, value);
+    ctx->shader_impl->bind_float (shader, name, value);
 }
 
 void
-bind_vec2_to_shader (cairo_gl_context_t *ctx,
-                     GLuint program, const char *name,
-                     float value0, float value1)
+_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
+			    cairo_gl_shader_t *shader,
+			    const char *name,
+			    float value0,
+			    float value1)
 {
-    ctx->shader_impl->bind_vec2_to_shader(program, name, value0, value1);
+    ctx->shader_impl->bind_vec2 (shader, name, value0, value1);
 }
 
 void
-bind_vec3_to_shader (cairo_gl_context_t *ctx,
-                     GLuint program, const char *name,
-                     float value0, float value1,
-                     float value2)
+_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
+			    cairo_gl_shader_t *shader,
+			    const char *name,
+			    float value0,
+			    float value1,
+			    float value2)
 {
-    ctx->shader_impl->bind_vec3_to_shader(program, name, value0, value1, value2);
+    ctx->shader_impl->bind_vec3 (shader, name, value0, value1, value2);
 }
 
 void
-bind_vec4_to_shader (cairo_gl_context_t *ctx,
-                     GLuint program, const char *name,
-                     float value0, float value1,
-                     float value2, float value3)
+_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
+			    cairo_gl_shader_t *shader,
+			    const char *name,
+			    float value0, float value1,
+			    float value2, float value3)
 {
-    ctx->shader_impl->bind_vec4_to_shader(program, name, value0, value1, value2, value3);
+    ctx->shader_impl->bind_vec4 (shader, name, value0, value1, value2, value3);
 }
 
 void
-bind_matrix_to_shader (cairo_gl_context_t *ctx,
-                       GLuint program, const char *name, cairo_matrix_t* m)
+_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
+			      cairo_gl_shader_t *shader,
+			      const char *name, cairo_matrix_t* m)
 {
-    ctx->shader_impl->bind_matrix_to_shader(program, name, m);
+    ctx->shader_impl->bind_matrix (shader, name, m);
 }
 
 void
-bind_texture_to_shader (cairo_gl_context_t *ctx,
-                        GLuint program, const char *name, GLuint tex_unit)
+_cairo_gl_shader_bind_texture (cairo_gl_context_t *ctx,
+			       cairo_gl_shader_t *shader,
+			       const char *name, GLuint tex_unit)
 {
-    ctx->shader_impl->bind_texture_to_shader(program, name, tex_unit);
+    ctx->shader_impl->bind_texture (shader, name, tex_unit);
 }
 
 void
-_cairo_gl_use_program (cairo_gl_context_t *ctx,
-                       cairo_gl_shader_program_t *program)
+_cairo_gl_set_shader (cairo_gl_context_t *ctx,
+		      cairo_gl_shader_t *shader)
 {
-    if (!ctx->shader_impl)
-        return;
+    if (ctx->shader_impl == NULL)
+	return;
 
-    ctx->shader_impl->use_program (program);
+    ctx->shader_impl->use (shader);
 }
 
 cairo_status_t
-_cairo_gl_get_program (cairo_gl_context_t *ctx,
-		       cairo_gl_operand_type_t source,
-		       cairo_gl_operand_type_t mask,
-		       cairo_gl_shader_in_t in,
-		       cairo_gl_shader_program_t **out_program)
+_cairo_gl_get_shader (cairo_gl_context_t *ctx,
+		      cairo_gl_operand_type_t source,
+		      cairo_gl_operand_type_t mask,
+		      cairo_gl_shader_in_t in,
+		      cairo_gl_shader_t **out)
 {
     cairo_shader_cache_entry_t lookup, *entry;
     char *fs_source;
     cairo_status_t status;
 
+    *out = NULL;
     if (ctx->shader_impl == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+	return CAIRO_STATUS_SUCCESS;
 
     lookup.src = source;
     lookup.mask = mask;
@@ -889,21 +947,19 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
 
     entry = _cairo_cache_lookup (&ctx->shaders, &lookup.base);
     if (entry) {
-        if (entry->program.build_failure)
-            return CAIRO_INT_STATUS_UNSUPPORTED;
-
-        assert (entry->program.program);
-	*out_program = &entry->program;
+        assert (entry->shader.program);
+	*out = &entry->shader;
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    fs_source = cairo_gl_shader_get_fragment_source (ctx->tex_target,
-                                                     in,
-                                                     source,
-                                                     mask,
-                                                     CAIRO_GL_OPERAND_NONE);
-    if (unlikely (fs_source == NULL))
-	return CAIRO_STATUS_NO_MEMORY;
+    status = cairo_gl_shader_get_fragment_source (ctx->tex_target,
+						  in,
+						  source,
+						  mask,
+						  CAIRO_GL_OPERAND_NONE,
+						  &fs_source);
+    if (unlikely (status))
+	return status;
 
     entry = malloc (sizeof (cairo_shader_cache_entry_t));
     if (unlikely (entry == NULL)) {
@@ -914,38 +970,38 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     memcpy (entry, &lookup, sizeof (cairo_shader_cache_entry_t));
 
     entry->ctx = ctx;
-    init_shader_program (&entry->program);
-    status = create_shader_program (ctx,
-                                    &entry->program,
-				    cairo_gl_operand_get_var_type (source),
-				    cairo_gl_operand_get_var_type (mask),
-				    fs_source);
+    _cairo_gl_shader_init (&entry->shader);
+    status = _cairo_gl_shader_compile (ctx,
+				       &entry->shader,
+				       cairo_gl_operand_get_var_type (source),
+				       cairo_gl_operand_get_var_type (mask),
+				       fs_source);
     free (fs_source);
 
     if (unlikely (status)) {
-        /* still add to cache, so we know we got a build failure */
-        if (_cairo_status_is_error (status) ||
-            _cairo_cache_insert (&ctx->shaders, &entry->base)) {
-            free (entry);
-        }
+	free (entry);
+	return status;
+    }
 
+    status = _cairo_cache_insert (&ctx->shaders, &entry->base);
+    if (unlikely (status)) {
+	_cairo_gl_shader_fini (ctx, &entry->shader);
+	free (entry);
 	return status;
     }
 
-    _cairo_gl_use_program (ctx, &entry->program);
+    _cairo_gl_set_shader (ctx, &entry->shader);
     if (source != CAIRO_GL_OPERAND_CONSTANT) {
-	bind_texture_to_shader (ctx, entry->program.program, "source_sampler", 0);
+	_cairo_gl_shader_bind_texture (ctx, &entry->shader, "source_sampler", 0);
     }
     if (mask != CAIRO_GL_OPERAND_CONSTANT &&
 	mask != CAIRO_GL_OPERAND_SPANS &&
 	mask != CAIRO_GL_OPERAND_NONE) {
-	bind_texture_to_shader (ctx, entry->program.program, "mask_sampler", 1);
+	_cairo_gl_shader_bind_texture (ctx, &entry->shader, "mask_sampler", 1);
     }
 
-    status = _cairo_cache_insert (&ctx->shaders, &entry->base);
-
-    _cairo_gl_use_program (ctx, NULL);
+    _cairo_gl_set_shader (ctx, NULL);
 
-    *out_program = &entry->program;
-    return status;
+    *out = &entry->shader;
+    return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 0432bd1..2fcc701 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -605,19 +605,19 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	GLfloat vertices[8], texcoords[8];
 
 	if (_cairo_gl_device_has_glsl (&ctx->base)) {
-	    cairo_gl_shader_program_t *program;
-
-	    status = _cairo_gl_get_program (ctx,
-					    CAIRO_GL_OPERAND_TEXTURE,
-					    CAIRO_GL_OPERAND_NONE,
-					    CAIRO_GL_SHADER_IN_NORMAL,
-					    &program);
-	    if (_cairo_status_is_error (status)) {
+	    cairo_gl_shader_t *shader;
+
+	    status = _cairo_gl_get_shader (ctx,
+					   CAIRO_GL_OPERAND_TEXTURE,
+					   CAIRO_GL_OPERAND_NONE,
+					   CAIRO_GL_SHADER_IN_NORMAL,
+					   &shader);
+	    if (unlikely (status)) {
 		_cairo_gl_context_release (ctx);
 		goto fail;
 	    }
 
-	    _cairo_gl_use_program (ctx, program);
+	    _cairo_gl_set_shader (ctx, shader);
 	} else {
 	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 	}
@@ -679,8 +679,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 	glDisableClientState (GL_VERTEX_ARRAY);
 	glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 
-	if (_cairo_gl_device_has_glsl (&ctx->base))
-	    _cairo_gl_use_program (ctx, NULL);
+	_cairo_gl_set_shader (ctx, NULL);
 	glDeleteTextures (1, &tex);
 	glDisable (ctx->tex_target);
     }
@@ -1181,12 +1180,6 @@ _cairo_gl_surface_fill_rectangles_glsl (void                  *abstract_surface,
     cairo_gl_context_t *ctx;
     int i;
     GLfloat *vertices;
-    static const char *fill_fs_source =
-	"uniform vec4 color;\n"
-	"void main()\n"
-	"{\n"
-	"	gl_FragColor = color;\n"
-	"}\n";
     cairo_status_t status;
 
     if (! _cairo_gl_operator_is_supported (op))
@@ -1196,16 +1189,6 @@ _cairo_gl_surface_fill_rectangles_glsl (void                  *abstract_surface,
     if (unlikely (status))
 	return status;
 
-    status = create_shader_program (ctx,
-                                    &ctx->fill_rectangles_shader,
-                                    CAIRO_GL_VAR_NONE,
-                                    CAIRO_GL_VAR_NONE,
-				    fill_fs_source);
-    if (unlikely (status)) {
-	_cairo_gl_context_release (ctx);
-	return status;
-    }
-
     if (num_rects > N_STACK_RECTS) {
 	vertices = _cairo_malloc_ab (num_rects, sizeof (GLfloat) * 4 * 2);
 	if (!vertices) {
@@ -1217,18 +1200,17 @@ _cairo_gl_surface_fill_rectangles_glsl (void                  *abstract_surface,
 	vertices = vertices_stack;
     }
 
-    _cairo_gl_use_program (ctx, &ctx->fill_rectangles_shader);
-
     _cairo_gl_context_set_destination (ctx, surface);
     _cairo_gl_set_operator (surface, op, FALSE);
 
-    bind_vec4_to_shader (ctx,
-                         ctx->fill_rectangles_shader.program,
-                         "color",
-                         color->red * color->alpha,
-                         color->green * color->alpha,
-                         color->blue * color->alpha,
-                         color->alpha);
+    _cairo_gl_set_shader (ctx, &ctx->fill_rectangles_shader);
+    _cairo_gl_shader_bind_vec4 (ctx,
+				&ctx->fill_rectangles_shader,
+				"color",
+				color->red * color->alpha,
+				color->green * color->alpha,
+				color->blue * color->alpha,
+				color->alpha);
 
     for (i = 0; i < num_rects; i++) {
 	vertices[i * 8 + 0] = rects[i].x;
commit 2325d755b03958d8ead9a995c0d1d03e4f93af0c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon May 17 10:33:46 2010 +0100

    gl: Pretty print the error GLenum.

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 77d0ef7..3c157f5 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -204,10 +204,11 @@ typedef struct _cairo_gl_composite {
 
 cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
 
+cairo_private const char *_cairo_gl_error_to_string (GLenum err);
 #define _cairo_gl_check_error() do { \
     GLenum err; \
     while ((err = glGetError ())) \
-	fprintf (stderr, "%s:%d: GL error 0x%08x\n", __FILE__,__LINE__, (int) err); \
+	fprintf (stderr, "%s:%d: GL error 0x%04x: %s\n", __FILE__,__LINE__, (int) err, _cairo_gl_error_to_string (err)); \
 } while (0)
 
 static inline cairo_device_t *
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index f485682..0432bd1 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -58,6 +58,25 @@ static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
     return surface->backend == &_cairo_gl_surface_backend;
 }
 
+const char *_cairo_gl_error_to_string (GLenum err)
+{
+    switch ((int) err) {
+    case GL_NO_ERROR:
+	ASSERT_NOT_REACHED;
+	return "success";
+
+    case GL_INVALID_ENUM:      return "invalid enum";
+    case GL_INVALID_VALUE:     return "invalid value";
+    case GL_INVALID_OPERATION: return "invalid operation";
+    case GL_STACK_OVERFLOW:    return "stack overflow";
+    case GL_STACK_UNDERFLOW:   return "stack underflow";
+    case GL_OUT_OF_MEMORY:     return "out of memory";
+
+    default:
+	return "unknown error";
+    }
+}
+
 cairo_bool_t
 _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
 				     GLenum *internal_format, GLenum *format,


More information about the cairo-commit mailing list