[cairo-commit] 3 commits - src/cairo-gl-glyphs.c src/cairo-gl-private.h src/cairo-gl-shaders.c src/cairo-gl-surface.c

Eric Anholt anholt at kemper.freedesktop.org
Tue Feb 16 13:30:47 PST 2010


 src/cairo-gl-glyphs.c  |   25 +++---
 src/cairo-gl-private.h |    1 
 src/cairo-gl-shaders.c |   44 +++++++++++
 src/cairo-gl-surface.c |  196 ++++++++++++++++++++++++++++++++-----------------
 4 files changed, 187 insertions(+), 79 deletions(-)

New commits:
commit e845450905f373e4fcb9ae4717cfd2c3e6472423
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Feb 16 13:18:33 2010 -0800

    gl: Add GLSL support for ARB_texture_rectangle, and repeat/reflect fallbacks.
    
    Most testcases are now passing like the ARB_texture_non_power_of_two
    case.  EXT_texture_rectangle support is dropped in favor of
    ARB_texture_non_power_of_two.  If we have issues with drivers not
    having that but having EXT (which just lacks the GLSL part of the
    spec), we can split it out.  Right now non-GLSL support in cairo-gl is
    probably in bad shape anyway and will require someone that cares for
    it in order to get fixed up.

diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index e2797d5..70a8c75 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -717,6 +717,13 @@ static const char *fs_source_texture =
     "{\n"
     "	return texture2D(source_sampler, source_texcoords);\n"
     "}\n";
+static const char *fs_source_texture_rect =
+    "uniform sampler2DRect source_sampler;\n"
+    "varying vec2 source_texcoords;\n"
+    "vec4 get_source()\n"
+    "{\n"
+    "	return texture2DRect(source_sampler, source_texcoords);\n"
+    "}\n";
 static const char *fs_source_texture_alpha =
     "uniform sampler2D source_sampler;\n"
     "varying vec2 source_texcoords;\n"
@@ -724,6 +731,13 @@ static const char *fs_source_texture_alpha =
     "{\n"
     "	return vec4(0, 0, 0, texture2D(source_sampler, source_texcoords).a);\n"
     "}\n";
+static const char *fs_source_texture_alpha_rect =
+    "uniform sampler2DRect source_sampler;\n"
+    "varying vec2 source_texcoords;\n"
+    "vec4 get_source()\n"
+    "{\n"
+    "	return vec4(0, 0, 0, texture2DRect(source_sampler, source_texcoords).a);\n"
+    "}\n";
 static const char *fs_source_linear_gradient =
     "uniform sampler1D source_sampler;\n"
     "uniform mat4 source_matrix;\n"
@@ -784,6 +798,13 @@ static const char *fs_mask_texture =
     "{\n"
     "	return texture2D(mask_sampler, mask_texcoords);\n"
     "}\n";
+static const char *fs_mask_texture_rect =
+    "uniform sampler2DRect mask_sampler;\n"
+    "varying vec2 mask_texcoords;\n"
+    "vec4 get_mask()\n"
+    "{\n"
+    "	return texture2DRect(mask_sampler, mask_texcoords);\n"
+    "}\n";
 static const char *fs_mask_texture_alpha =
     "uniform sampler2D mask_sampler;\n"
     "varying vec2 mask_texcoords;\n"
@@ -791,6 +812,13 @@ static const char *fs_mask_texture_alpha =
     "{\n"
     "	return vec4(0, 0, 0, texture2D(mask_sampler, mask_texcoords).a);\n"
     "}\n";
+static const char *fs_mask_texture_alpha_rect =
+    "uniform sampler2DRect mask_sampler;\n"
+    "varying vec2 mask_texcoords;\n"
+    "vec4 get_mask()\n"
+    "{\n"
+    "	return vec4(0, 0, 0, texture2DRect(mask_sampler, mask_texcoords).a);\n"
+    "}\n";
 static const char *fs_mask_linear_gradient =
     "uniform sampler1D mask_sampler;\n"
     "uniform mat4 mask_matrix;\n"
@@ -935,6 +963,22 @@ _cairo_gl_get_program (cairo_gl_context_t *ctx,
     source_source = source_sources[source];
     mask_source = mask_sources[mask];
     in_source = in_sources[in];
+
+    /* For ARB_texture_rectangle, rewrite sampler2D and texture2D to
+     * sampler2DRect and texture2DRect.
+     */
+    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT) {
+	if (source_source == fs_source_texture)
+	    source_source = fs_source_texture_rect;
+	else if (source_source == fs_source_texture_alpha)
+	    source_source = fs_source_texture_alpha_rect;
+
+	if (mask_source == fs_mask_texture)
+	    mask_source = fs_mask_texture_rect;
+	else if (mask_source == fs_mask_texture_alpha)
+	    mask_source = fs_mask_texture_alpha_rect;
+    }
+
     fs_source = _cairo_malloc (strlen(source_source) +
 			       strlen(mask_source) +
 			       strlen(in_source) +
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 6470f69..f86a4fd 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -119,10 +119,10 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     }
 
     if (! GLEW_ARB_texture_non_power_of_two &&
-	! GLEW_EXT_texture_rectangle ) {
+	! GLEW_ARB_texture_rectangle ) {
 	fprintf (stderr,
 		 "Required GL extensions not available:\n");
-	fprintf (stderr, "    GL_ARB_texture_non_power_of_two, GL_EXT_texture_rectangle\n");
+	fprintf (stderr, "    GL_ARB_texture_non_power_of_two, GL_ARB_texture_rectangle\n");
     }
 
     if (!GLEW_ARB_texture_non_power_of_two)
@@ -382,11 +382,10 @@ _cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
 {
 
     if (tex_target == GL_TEXTURE_RECTANGLE_EXT) {
-	if (attributes->extend == CAIRO_EXTEND_REPEAT ||
-	    attributes->extend == CAIRO_EXTEND_REFLECT)
-	    fprintf(stderr,"cannot use rect texture for repeat/reflect\n");
+	assert (attributes->extend != CAIRO_EXTEND_REPEAT &&
+		attributes->extend != CAIRO_EXTEND_REFLECT);
     }
-	
+
     glActiveTexture (GL_TEXTURE0 + tex_unit);
     glBindTexture (tex_target, tex);
     switch (attributes->extend) {
@@ -1175,6 +1174,16 @@ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
     if (unlikely (status))
 	return status;
 
+    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT &&
+	(attributes->extend == CAIRO_EXTEND_REPEAT ||
+	 attributes->extend == CAIRO_EXTEND_REFLECT))
+    {
+	_cairo_pattern_release_surface (operand->pattern,
+					&surface->base,
+					attributes);
+	return UNSUPPORTED ("EXT_texture_rectangle with repeat/reflect");
+    }
+
     assert (surface->base.backend == &_cairo_gl_surface_backend);
 
     operand->operand.texture.surface = surface;
commit 40294377cb26fab7bcf17ee98b8e4f5bf9778ca2
Author: Dave Airlie <airlied at redhat.com>
Date:   Sat Jan 30 19:24:31 2010 +1000

    gl: initial support for EXT_texture_rectangle extension
    
    The only issue is the repeat modes aren't supported for rectangular
    textures. In any case even with ARB_npot radeon's pre-r600 lie and
    fail to do repeats anyway.

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 9e130d0..dbd24c5 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -50,7 +50,8 @@ typedef struct _cairo_gl_glyph_private {
 } cairo_gl_glyph_private_t;
 
 static cairo_status_t
-_cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache,
+_cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
+				 cairo_gl_glyph_cache_t *cache,
 				 cairo_scaled_glyph_t  *scaled_glyph)
 {
     cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
@@ -110,7 +111,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache,
     glPixelStorei (GL_UNPACK_ROW_LENGTH,
 		   glyph_surface->stride /
 		   (PIXMAN_FORMAT_BPP (glyph_surface->pixman_format) / 8));
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
+    glTexSubImage2D (ctx->tex_target, 0,
 		     node->x, node->y,
 		     glyph_surface->width, glyph_surface->height,
 		     format, type,
@@ -181,10 +182,10 @@ cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx,
 	}
 
 	glGenTextures (1, &cache->tex);
-	glBindTexture (GL_TEXTURE_2D, cache->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, internal_format,
+	glBindTexture (ctx->tex_target, cache->tex);
+	glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexImage2D (ctx->tex_target, 0, internal_format,
 		      GLYPH_CACHE_WIDTH, GLYPH_CACHE_HEIGHT, 0,
 		      internal_format, GL_FLOAT, NULL);
     }
@@ -271,7 +272,7 @@ _cairo_gl_glyphs_set_shader_fixed (cairo_gl_context_t *ctx,
      * the loop over glyphs below.
      */
     glActiveTexture (GL_TEXTURE1);
-    glEnable (GL_TEXTURE_2D);
+    glEnable (ctx->tex_target);
     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
     glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
@@ -555,7 +556,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	    cache = cairo_gl_context_get_glyph_cache (ctx,
 						      scaled_glyph->surface->format);
 
-	    glBindTexture (GL_TEXTURE_2D, cache->tex);
+	    glBindTexture (ctx->tex_target, cache->tex);
 
 	    last_format = scaled_glyph->surface->format;
 	    /* If we're doing component alpha in this function, it should
@@ -571,13 +572,13 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	}
 
 	if (scaled_glyph->surface_private == NULL) {
-	    status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
+	    status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
 
 	    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
 		/* Cache is full, so flush existing prims and try again. */
 		_cairo_gl_flush_glyphs (ctx, &setup);
 		_cairo_gl_glyph_cache_unlock (cache);
-		status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
+		status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
 	    }
 
 	    if (unlikely (_cairo_status_is_error (status)))
@@ -612,12 +613,12 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
     glActiveTexture (GL_TEXTURE0);
     glDisable (GL_TEXTURE_1D);
-    glDisable (GL_TEXTURE_2D);
+    glDisable (ctx->tex_target);
 
     glClientActiveTexture (GL_TEXTURE1);
     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
     glActiveTexture (GL_TEXTURE1);
-    glDisable (GL_TEXTURE_2D);
+    glDisable (ctx->tex_target);
     _cairo_gl_use_program (NULL);
 
     glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 6cd3ec8..6faaffa 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -122,6 +122,7 @@ typedef struct _cairo_gl_context {
     GLuint vbo;
     GLint max_framebuffer_size;
     GLint max_texture_size;
+    GLenum tex_target;
     cairo_bool_t using_glsl;
 
     cairo_bool_t using_shaders;
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 919c6cf..6470f69 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -100,7 +100,6 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 
     if (! GLEW_EXT_framebuffer_object ||
 	! GLEW_ARB_texture_env_combine ||
-	! GLEW_ARB_texture_non_power_of_two ||
 	! GLEW_EXT_bgra)
     {
 	fprintf (stderr,
@@ -109,8 +108,6 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 	    fprintf (stderr, "    GL_EXT_framebuffer_object\n");
 	if (! GLEW_ARB_texture_env_combine)
 	    fprintf (stderr, "    GL_ARB_texture_env_combine\n");
-	if (! GLEW_ARB_texture_non_power_of_two)
-	    fprintf (stderr, "    GL_ARB_texture_non_power_of_two\n");
 	/* EXT_bgra is used in two places:
 	 * - draw_image to upload common pixman formats without hand-swizzling.
 	 * - get_image to download common pixman formats without hand-swizzling.
@@ -121,6 +118,19 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
     }
 
+    if (! GLEW_ARB_texture_non_power_of_two &&
+	! GLEW_EXT_texture_rectangle ) {
+	fprintf (stderr,
+		 "Required GL extensions not available:\n");
+	fprintf (stderr, "    GL_ARB_texture_non_power_of_two, GL_EXT_texture_rectangle\n");
+    }
+
+    if (!GLEW_ARB_texture_non_power_of_two)
+	ctx->tex_target = GL_TEXTURE_RECTANGLE_EXT;
+    else
+	ctx->tex_target = GL_TEXTURE_2D;
+
+
     if (GLEW_VERSION_2_0 ||
 	(GLEW_ARB_fragment_shader &&
 	 GLEW_ARB_vertex_shader &&
@@ -133,8 +143,8 @@ _cairo_gl_context_init (cairo_gl_context_t *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,
+    glBindTexture (ctx->tex_target, ctx->dummy_tex);
+    glTexImage2D (ctx->tex_target, 0, GL_RGBA, 1, 1, 0,
 		  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 
     /* PBO for any sort of texture upload */
@@ -367,45 +377,53 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
 
 static void
 _cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
-			       cairo_surface_attributes_t *attributes)
+			       cairo_surface_attributes_t *attributes,
+			       GLint tex_target)
 {
+
+    if (tex_target == GL_TEXTURE_RECTANGLE_EXT) {
+	if (attributes->extend == CAIRO_EXTEND_REPEAT ||
+	    attributes->extend == CAIRO_EXTEND_REFLECT)
+	    fprintf(stderr,"cannot use rect texture for repeat/reflect\n");
+    }
+	
     glActiveTexture (GL_TEXTURE0 + tex_unit);
-    glBindTexture (GL_TEXTURE_2D, tex);
+    glBindTexture (tex_target, 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);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
 	break;
     case CAIRO_EXTEND_PAD:
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 	break;
     case CAIRO_EXTEND_REPEAT:
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_REPEAT);
 	break;
     case CAIRO_EXTEND_REFLECT:
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+	glTexParameteri (tex_target, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
 	break;
     }
     switch (attributes->filter) {
     case CAIRO_FILTER_FAST:
     case CAIRO_FILTER_NEAREST:
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri (tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 	break;
     case CAIRO_FILTER_GOOD:
     case CAIRO_FILTER_BEST:
     case CAIRO_FILTER_BILINEAR:
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri (tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri (tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 	break;
     default:
     case CAIRO_FILTER_GAUSSIAN:
 	ASSERT_NOT_REACHED;
     }
-    glEnable (GL_TEXTURE_2D);
+    glEnable (tex_target);
 }
 
 void
@@ -472,10 +490,10 @@ _cairo_gl_surface_create_scratch (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,
+    glBindTexture (ctx->tex_target, surface->tex);
+    glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexImage2D (ctx->tex_target, 0, format, width, height, 0,
 		  format, GL_UNSIGNED_BYTE, NULL);
 
     /* Create a framebuffer object wrapping the texture so that we can render
@@ -485,7 +503,7 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
     glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, surface->fb);
     glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
 			       GL_COLOR_ATTACHMENT0_EXT,
-			       GL_TEXTURE_2D,
+			       ctx->tex_target,
 			       surface->tex,
 			       0);
     ctx->current_target = NULL;
@@ -664,6 +682,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
     GLenum internal_format, format, type;
     cairo_bool_t has_alpha;
     cairo_image_surface_t *clone = NULL;
+    cairo_gl_context_t *ctx = (cairo_gl_context_t *) dst->base.device;
     int cpp;
 
     if (! _cairo_gl_get_image_format_and_type (src->pixman_format,
@@ -691,12 +710,12 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 
     cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
 
-    glBindTexture (GL_TEXTURE_2D, dst->tex);
-    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glBindTexture (ctx->tex_target, dst->tex);
+    glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
     glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
-    glTexSubImage2D (GL_TEXTURE_2D, 0,
+    glTexSubImage2D (ctx->tex_target, 0,
 	             dst_x, dst_y, width, height,
 		     format, GL_UNSIGNED_BYTE,
 		     src->data + src_y * src->stride + src_x * cpp);
@@ -1143,7 +1162,7 @@ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
     cairo_matrix_t m;
     cairo_gl_surface_t *surface;
     cairo_surface_attributes_t *attributes;
-
+    cairo_gl_context_t *ctx = (cairo_gl_context_t *) dst->base.device;
     attributes = &operand->operand.texture.attributes;
 
     status = _cairo_pattern_acquire_surface (src, &dst->base,
@@ -1183,9 +1202,15 @@ _cairo_gl_pattern_texture_setup (cairo_gl_composite_operand_t *operand,
      * (unnormalized src -> unnormalized src) to
      * (unnormalized dst -> normalized src)
      */
-    cairo_matrix_init_scale (&m,
-			     1.0 / surface->width,
-			     1.0 / surface->height);
+    if (ctx->tex_target == GL_TEXTURE_RECTANGLE_EXT) {
+	cairo_matrix_init_scale (&m,
+				 1.0,
+				 1.0);
+    } else {
+	cairo_matrix_init_scale (&m,
+				 1.0 / surface->width,
+				 1.0 / surface->height);
+    }
     cairo_matrix_multiply (&attributes->matrix,
 			   &attributes->matrix,
 			   &m);
@@ -1415,8 +1440,8 @@ _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx,
     /* Fall back to fixed function */
     glActiveTexture (GL_TEXTURE0 + tex_unit);
     /* Have to have a dummy texture bound in order to use the combiner unit. */
-    glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex);
-    glEnable (GL_TEXTURE_2D);
+    glBindTexture (ctx->tex_target, ctx->dummy_tex);
+    glEnable (ctx->tex_target);
 
     glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
@@ -1460,7 +1485,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
 	break;
     case OPERAND_TEXTURE:
 	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
-				       src_attributes);
+				       src_attributes, ctx->tex_target);
 	if (!setup->shader) {
 	    /* Set up the constant color we use to set color to 0 if needed. */
 	    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
@@ -1573,7 +1598,7 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
 	break;
     case OPERAND_TEXTURE:
 	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
-				       src_attributes);
+				       src_attributes, ctx->tex_target);
 	if (!setup->shader) {
 	    /* Set up the combiner to just set color to the sampled texture. */
 	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
@@ -1699,9 +1724,9 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
 				setup->src.operand.constant.color[2],
 				setup->src.operand.constant.color[3]);
 	} else {
-	    glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex);
+	    glBindTexture (ctx->tex_target, ctx->dummy_tex);
 	    glActiveTexture (GL_TEXTURE1);
-	    glEnable (GL_TEXTURE_2D);
+	    glEnable (ctx->tex_target);
 
 	    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
 			setup->mask.operand.constant.color);
@@ -1714,7 +1739,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
 	break;
     case OPERAND_TEXTURE:
 	_cairo_gl_set_texture_surface (1, setup->mask.operand.texture.tex,
-				       mask_attributes);
+				       mask_attributes, ctx->tex_target);
 	if (!setup->shader) {
 	    /* Set up the constant color we use to set color to 0 if needed. */
 	    glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
@@ -1980,13 +2005,13 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
     glActiveTexture (GL_TEXTURE0);
     glDisable (GL_TEXTURE_1D);
-    glDisable (GL_TEXTURE_2D);
+    glDisable (ctx->tex_target);
 
     glClientActiveTexture (GL_TEXTURE1);
     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
     glActiveTexture (GL_TEXTURE1);
     glDisable (GL_TEXTURE_1D);
-    glDisable (GL_TEXTURE_2D);
+    glDisable (ctx->tex_target);
 
     while ((err = glGetError ()))
 	fprintf (stderr, "GL error 0x%08x\n", (int) err);
@@ -2107,7 +2132,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 
 	case OPERAND_TEXTURE:
 	    _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex,
-					   mask_attributes);
+					   mask_attributes, ctx->tex_target);
 
 	    if (!setup.shader) {
 		glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
@@ -2227,13 +2252,13 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
     glActiveTexture (GL_TEXTURE0);
     glDisable (GL_TEXTURE_1D);
-    glDisable (GL_TEXTURE_2D);
+    glDisable (ctx->tex_target);
 
     glClientActiveTexture (GL_TEXTURE1);
     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
     glActiveTexture (GL_TEXTURE1);
     glDisable (GL_TEXTURE_1D);
-    glDisable (GL_TEXTURE_2D);
+    glDisable (ctx->tex_target);
 
     while ((err = glGetError ()))
 	fprintf (stderr, "GL error 0x%08x\n", (int) err);
@@ -2750,11 +2775,11 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer)
     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
     glActiveTexture (GL_TEXTURE0);
     glDisable (GL_TEXTURE_1D);
-    glDisable (GL_TEXTURE_2D);
+    glDisable (renderer->ctx->tex_target);
 
     if (!renderer->setup.shader) {
 	glActiveTexture (GL_TEXTURE1);
-	glDisable (GL_TEXTURE_2D);
+	glDisable (renderer->ctx->tex_target);
     }
 
     glDisable (GL_BLEND);
@@ -2791,6 +2816,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 					cairo_region_t		*clip_region)
 {
     cairo_gl_surface_t *dst = abstract_dst;
+    cairo_gl_context_t *ctx = (cairo_gl_context_t *) dst->base.device;
     cairo_gl_surface_span_renderer_t *renderer;
     cairo_status_t status;
     cairo_surface_attributes_t *src_attributes;
@@ -2850,8 +2876,8 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t	 op,
 	/* 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, renderer->ctx->dummy_tex);
-	glEnable (GL_TEXTURE_2D);
+	glBindTexture (ctx->tex_target, renderer->ctx->dummy_tex);
+	glEnable (ctx->tex_target);
 	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
 	glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
commit 6542a515f04d52d10fdc89ee9abc76e54282a2d8
Author: Eric Anholt <eric at anholt.net>
Date:   Sun Feb 7 20:26:56 2010 +0100

    gl: Reduce the size of the gradient texture for small numbers of stops.
    
    This code is stolen straight from cairo-drm-intel.c.  This saves a
    bunch of time calculating interpolated points when we just do
    interpolation between points at sampling time anyway.  Reduces
    firefox-talos-svg from 47 seconds back to the 42 it was at before the
    pixman change.
    
    This regresses the reported result of huge-radial, but there's no
    visible difference.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 9c7c28e..919c6cf 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -973,31 +973,58 @@ _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
     return CAIRO_STATUS_SUCCESS;
 }
 
-
-static inline void
-lerp_and_set_color (GLubyte *color,
-                    double t0, double t1, double t,
-                    double r0, double g0, double b0, double a0,
-                    double r1, double g1, double b1, double a1)
+static int
+_cairo_gl_gradient_sample_width (const cairo_gradient_pattern_t *gradient)
 {
-    double alpha = (t - t0) / (t1 - t0);
-    double a = ((1.0 - alpha) * a0 + alpha * a1);
-    color[0] = ((1.0 - alpha) * b0 + alpha * b1) * a * 255.0;
-    color[1] = ((1.0 - alpha) * g0 + alpha * g1) * a * 255.0;
-    color[2] = ((1.0 - alpha) * r0 + alpha * r1) * a * 255.0;
-    color[3] = a * 255.0;
+    unsigned int n;
+    int width;
+
+    width = 8;
+    for (n = 1; n < gradient->n_stops; n++) {
+	double dx = gradient->stops[n].offset - gradient->stops[n-1].offset;
+	double delta, max;
+	int ramp;
+
+	if (dx == 0)
+	    continue;
+
+	max = gradient->stops[n].color.red -
+	      gradient->stops[n-1].color.red;
+
+	delta = gradient->stops[n].color.green -
+	        gradient->stops[n-1].color.green;
+	if (delta > max)
+	    max = delta;
+
+	delta = gradient->stops[n].color.blue -
+	        gradient->stops[n-1].color.blue;
+	if (delta > max)
+	    max = delta;
+
+	delta = gradient->stops[n].color.alpha -
+	        gradient->stops[n-1].color.alpha;
+	if (delta > max)
+	    max = delta;
+
+	ramp = 128 * max / dx;
+	if (ramp > width)
+	    width = ramp;
+    }
+
+    width = (width + 7) & -8;
+    return MIN (width, 1024);
 }
 
 static cairo_status_t
 _render_gradient (const cairo_gl_context_t *ctx,
 		  cairo_gradient_pattern_t *pattern,
-		  void *bytes)
+		  void *bytes,
+		  int width)
 {
     pixman_image_t *gradient, *image;
     pixman_gradient_stop_t pixman_stops_stack[32];
     pixman_gradient_stop_t *pixman_stops;
     pixman_point_fixed_t p1, p2;
-    int width;
     unsigned int i;
 
     pixman_stops = pixman_stops_stack;
@@ -1016,8 +1043,6 @@ _render_gradient (const cairo_gl_context_t *ctx,
 	pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
     }
 
-    width = ctx->max_texture_size;
-
     p1.x = 0;
     p1.y = 0;
     p2.x = width << 16;
@@ -1059,16 +1084,18 @@ _cairo_gl_create_gradient_texture (const cairo_gl_context_t *ctx,
 				   float *first_offset,
 				   float *last_offset)
 {
-    const int tex_width = ctx->max_texture_size;
+    int tex_width;
     GLubyte *data;
 
     assert (pattern->n_stops != 0);
 
+    tex_width = _cairo_gl_gradient_sample_width (pattern);
+
     glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, ctx->texture_load_pbo);
     glBufferDataARB (GL_PIXEL_UNPACK_BUFFER_ARB, tex_width * sizeof (uint32_t), 0, GL_STREAM_DRAW);
     data = glMapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
 
-    _render_gradient (ctx, pattern, data);
+    _render_gradient (ctx, pattern, data, tex_width);
     *first_offset = 0.;
     *last_offset  = 1.;
 


More information about the cairo-commit mailing list