From 8abd02c2bd76c652823901e7c8c0487e97bc8ebf Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 30 Jan 2010 19:24:31 +1000 Subject: [PATCH] [gl] initial support for 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. --- src/cairo-gl-glyphs.c | 25 +++++----- src/cairo-gl-private.h | 1 + src/cairo-gl-surface.c | 124 +++++++++++++++++++++++++++++------------------ 3 files changed, 90 insertions(+), 60 deletions(-) diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c index e3e2a99..28c2c7a 100644 --- a/src/cairo-gl-glyphs.c +++ b/src/cairo-gl-glyphs.c @@ -56,7 +56,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; @@ -116,7 +117,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, @@ -187,10 +188,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); } @@ -277,7 +278,7 @@ _cairo_gl_glyphs_set_shader (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); @@ -534,7 +535,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 @@ -550,13 +551,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))) @@ -590,12 +591,12 @@ _render_glyphs (cairo_gl_surface_t *dst, glClientActiveTexture (GL_TEXTURE0); glDisableClientState (GL_TEXTURE_COORD_ARRAY); glActiveTexture (GL_TEXTURE0); - 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); if (vbo != 0) { glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 84f0143..5e85bb8 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -87,6 +87,7 @@ typedef struct _cairo_gl_context { GLint fill_rectangles_color_uniform; GLint max_framebuffer_size; GLint max_texture_size; + GLint tex_target; cairo_gl_surface_t *current_target; cairo_gl_surface_t *glyphs_temporary_mask; diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index df0cb14..fedddf3 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -99,8 +99,7 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) 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) + ! GLEW_ARB_texture_env_combine) { fprintf (stderr, "Required GL extensions not available:\n"); @@ -108,16 +107,27 @@ _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"); 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; + /* 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); ctx->max_framebuffer_size = 0; @@ -346,45 +356,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 @@ -451,10 +469,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 @@ -464,7 +482,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; @@ -643,6 +661,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, @@ -670,12 +689,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); @@ -968,7 +987,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, @@ -1002,9 +1021,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); @@ -1112,8 +1137,8 @@ _cairo_gl_set_tex_combine_constant_color (cairo_gl_context_t *ctx, int tex_unit, { 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); @@ -1156,7 +1181,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); /* Set up the constant color we use to set color to 0 if needed. */ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color); /* Set up the combiner to just set color to the sampled texture. */ @@ -1207,7 +1232,7 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx, constant_color[2] = 0.0; constant_color[3] = 1.0; _cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex, - src_attributes); + src_attributes, ctx->tex_target); /* 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); @@ -1234,7 +1259,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx, mask_attributes = &setup->mask.operand.texture.attributes; 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); @@ -1247,7 +1272,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx, switch (setup->mask.type) { case OPERAND_CONSTANT: /* Have to have a dummy texture bound in order to use the combiner unit. */ - glBindTexture (GL_TEXTURE_2D, ctx->dummy_tex); + glBindTexture (ctx->tex_target, ctx->dummy_tex); glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, setup->mask.operand.constant.color); @@ -1260,7 +1285,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); /* Set up the constant color we use to set color to 0 if needed. */ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color); @@ -1486,12 +1511,12 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op, glClientActiveTexture (GL_TEXTURE0); glDisableClientState (GL_TEXTURE_COORD_ARRAY); glActiveTexture (GL_TEXTURE0); - 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); while ((err = glGetError ())) fprintf (stderr, "GL error 0x%08x\n", (int) err); @@ -1598,7 +1623,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); glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); @@ -1708,12 +1733,12 @@ _cairo_gl_surface_composite (cairo_operator_t op, glClientActiveTexture (GL_TEXTURE0); glDisableClientState (GL_TEXTURE_COORD_ARRAY); glActiveTexture (GL_TEXTURE0); - 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); while ((err = glGetError ())) fprintf (stderr, "GL error 0x%08x\n", (int) err); @@ -2234,9 +2259,11 @@ _cairo_gl_surface_span_renderer_finish (void *abstract_renderer) glDisableClientState (GL_TEXTURE_COORD_ARRAY); glActiveTexture (GL_TEXTURE0); glDisable (GL_TEXTURE_2D); + glDisable (GL_TEXTURE_RECTANGLE_EXT); glActiveTexture (GL_TEXTURE1); glDisable (GL_TEXTURE_2D); + glDisable (GL_TEXTURE_RECTANGLE_EXT); glDisable (GL_BLEND); @@ -2271,6 +2298,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; @@ -2322,8 +2350,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); -- 1.6.6