From patchwork Thu May 3 10:41:29 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: alexandros.frantzis@linaro.org X-Patchwork-Id: 8377 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 1C04523E49 for ; Thu, 3 May 2012 10:41:37 +0000 (UTC) Received: from mail-yx0-f180.google.com (mail-yx0-f180.google.com [209.85.213.180]) by fiordland.canonical.com (Postfix) with ESMTP id C1114A18734 for ; Thu, 3 May 2012 10:41:36 +0000 (UTC) Received: by yenl4 with SMTP id l4so1949884yen.11 for ; Thu, 03 May 2012 03:41:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to :subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=ojzE7Q/RoK896WyJz/7Kqw6LrFYEWfUmi1tG+qgvwoA=; b=f0aLoz11zSkn46PVLhArdqI/wsTR7mxNmDb1F2PcFdAqW8gISGJ8w5U61HtvKGch9Q tD1vLhQ2h0sBTFGXHtEwgANLif1/9LGrJwj7fbdVMYv8tXMp1rQ+cnJR6ELfUHzWThjh z3KxK8O5cXHXZ5v9785C/GXDYC/EpZIlGfg1DcZigQwAacW4pWJpeYRTLYj/YSjNnwCk DG1B4pb26VfCXleLuCvxbxut6AKjb0JkdYF0b1Y8Q6YHBiaiRAL2xq/gVOlxDWximevI EWnDQShZq6biMrBk1aqtSzsCpKxEuInPOAeY87sQv+oSHVaaOzAZDweTGqqhC+eIiR64 XSBw== Received: by 10.42.142.71 with SMTP id r7mr826020icu.7.1336041695905; Thu, 03 May 2012 03:41:35 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.137.198 with SMTP id x6csp9861ibt; Thu, 3 May 2012 03:41:34 -0700 (PDT) Received: by 10.180.92.9 with SMTP id ci9mr2044376wib.15.1336041694642; Thu, 03 May 2012 03:41:34 -0700 (PDT) Received: from mail-wi0-f178.google.com (mail-wi0-f178.google.com [209.85.212.178]) by mx.google.com with ESMTPS id dm8si836653wib.7.2012.05.03.03.41.34 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 03 May 2012 03:41:34 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.212.178 is neither permitted nor denied by best guess record for domain of alexandros.frantzis@linaro.org) client-ip=209.85.212.178; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.212.178 is neither permitted nor denied by best guess record for domain of alexandros.frantzis@linaro.org) smtp.mail=alexandros.frantzis@linaro.org Received: by wibhr7 with SMTP id hr7so174742wib.13 for ; Thu, 03 May 2012 03:41:34 -0700 (PDT) Received: by 10.180.77.233 with SMTP id v9mr1986170wiw.22.1336041693745; Thu, 03 May 2012 03:41:33 -0700 (PDT) Received: from localhost (188.4.173.130.dsl.dyn.forthnet.gr. [188.4.173.130]) by mx.google.com with ESMTPS id fn2sm2249074wib.0.2012.05.03.03.41.31 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 03 May 2012 03:41:32 -0700 (PDT) From: alexandros.frantzis@linaro.org To: cairo@cairographics.org Subject: [PATCH 2/2] gl: Provide a shader implementation of repeat wrap modes Date: Thu, 3 May 2012 13:41:29 +0300 Message-Id: <10ba5bf18ac1d603bffce71fca51d6b261d6f538.1336038723.git.alexandros.frantzis@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: References: X-Gm-Message-State: ALoCoQlHtbCR9mOpIe6wtWuswuEM1wZWIdA4/4AV8LWaOzOa0eZu3GAFm4oibqiBc3035xQOfaeo From: Alexandros Frantzis In OpenGL ES 2.0, repeat wrap modes (GL_REPEAT and GL_MIRRORED REPEAT) are only available for NPOT textures if the GL_OES_texture_npot is supported. This commit adds a shader implementation of these wrap modes for use by devices that do not support GL_OES_texture_npot. --- src/cairo-gl-composite.c | 10 ++++-- src/cairo-gl-device.c | 16 ++++++--- src/cairo-gl-private.h | 1 + src/cairo-gl-shaders.c | 84 +++++++++++++++++++++++++++++++++++++++------- 4 files changed, 92 insertions(+), 19 deletions(-) diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c index 633d229..1ab7557 100644 --- a/src/cairo-gl-composite.c +++ b/src/cairo-gl-composite.c @@ -168,10 +168,16 @@ _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx, wrap_mode = GL_CLAMP_TO_EDGE; break; case CAIRO_EXTEND_REPEAT: - wrap_mode = GL_REPEAT; + if (ctx->has_npot_repeat) + wrap_mode = GL_REPEAT; + else + wrap_mode = GL_CLAMP_TO_EDGE; break; case CAIRO_EXTEND_REFLECT: - wrap_mode = GL_MIRRORED_REPEAT; + if (ctx->has_npot_repeat) + wrap_mode = GL_MIRRORED_REPEAT; + else + wrap_mode = GL_CLAMP_TO_EDGE; break; default: wrap_mode = 0; diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c index 47ee94e..3d3cc7e 100644 --- a/src/cairo-gl-device.c +++ b/src/cairo-gl-device.c @@ -187,18 +187,24 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) /* Check for required extensions */ if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) { - if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) + if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) { ctx->tex_target = GL_TEXTURE_2D; - else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) + ctx->has_npot_repeat = TRUE; + } + else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) { ctx->tex_target = GL_TEXTURE_RECTANGLE; - else + ctx->has_npot_repeat = FALSE; + } + else { return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); + } } else { + ctx->tex_target = GL_TEXTURE_2D; if (_cairo_gl_has_extension ("GL_OES_texture_npot")) - ctx->tex_target = GL_TEXTURE_2D; + ctx->has_npot_repeat = TRUE; else - return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); + ctx->has_npot_repeat = FALSE; } if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP && diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 3afdd70..9cbd3a9 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -319,6 +319,7 @@ struct _cairo_gl_context { cairo_gl_flavor_t gl_flavor; cairo_bool_t has_map_buffer; cairo_bool_t has_packed_depth_stencil; + cairo_bool_t has_npot_repeat; void (*acquire) (void *ctx); void (*release) (void *ctx); diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c index b3af6f7..ea57efa 100644 --- a/src/cairo-gl-shaders.c +++ b/src/cairo-gl-shaders.c @@ -319,8 +319,10 @@ typedef struct _cairo_shader_cache_entry { cairo_gl_shader_in_t in; GLint src_gl_filter; cairo_bool_t src_border_fade; + cairo_extend_t src_extend; GLint mask_gl_filter; cairo_bool_t mask_border_fade; + cairo_extend_t mask_extend; cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */ cairo_gl_shader_t shader; @@ -331,12 +333,16 @@ _cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b) { const cairo_shader_cache_entry_t *a = key_a; const cairo_shader_cache_entry_t *b = key_b; + cairo_bool_t both_have_npot_repeat = + a->ctx->has_npot_repeat && b->ctx->has_npot_repeat; return a->src == b->src && a->mask == b->mask && a->dest == b->dest && a->use_coverage == b->use_coverage && - a->in == b->in; + a->in == b->in && + (both_have_npot_repeat || a->src_extend == b->src_extend) && + (both_have_npot_repeat || a->mask_extend == b->mask_extend); } /* @@ -349,6 +355,8 @@ _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b) { const cairo_shader_cache_entry_t *a = key_a; const cairo_shader_cache_entry_t *b = key_b; + cairo_bool_t both_have_npot_repeat = + a->ctx->has_npot_repeat && b->ctx->has_npot_repeat; return a->src == b->src && a->mask == b->mask && @@ -357,8 +365,10 @@ _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b) a->in == b->in && a->src_gl_filter == b->src_gl_filter && a->src_border_fade == b->src_border_fade && + (both_have_npot_repeat || a->src_extend == b->src_extend) && a->mask_gl_filter == b->mask_gl_filter && - a->mask_border_fade == b->mask_border_fade; + a->mask_border_fade == b->mask_border_fade && + (both_have_npot_repeat || a->mask_extend == b->mask_extend); } static unsigned long @@ -642,9 +652,9 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, else { _cairo_output_stream_printf (stream, - " return texture2D%s (%s_sampler, %s_texcoords);\n" + " return texture2D%s (%s_sampler, %s_wrap (%s_texcoords));\n" "}\n", - rectstr, namestr, namestr); + rectstr, namestr, namestr, namestr); } break; case CAIRO_GL_OPERAND_LINEAR_GRADIENT: @@ -669,9 +679,9 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, else { _cairo_output_stream_printf (stream, - " return texture2D%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n" + " return texture2D%s (%s_sampler, %s_wrap (vec2 (%s_texcoords.x, 0.5)));\n" "}\n", - rectstr, namestr, namestr); + rectstr, namestr, namestr, namestr); } break; case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: @@ -706,9 +716,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, else { _cairo_output_stream_printf (stream, - " return mix (vec4 (0.0), texture2D%s (%s_sampler, vec2(t, 0.5)), is_valid);\n" + " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2 (t, 0.5)));\n" + " return mix (vec4 (0.0), texel, is_valid);\n" "}\n", - rectstr, namestr); + rectstr, namestr, namestr); } break; case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: @@ -750,9 +761,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, else { _cairo_output_stream_printf (stream, - " return mix (vec4 (0.0), texture2D%s (%s_sampler, vec2 (upper_t, 0.5)), has_color);\n" + " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n" + " return mix (vec4 (0.0), texel, has_color);\n" "}\n", - rectstr, namestr); + rectstr, namestr, namestr); } break; case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: @@ -778,11 +790,12 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n" " \n" " float upper_t = mix (t.y, t.x, is_valid.x);\n" - " return mix (vec4 (0.0), texture2D%s (%s_sampler, vec2 (upper_t, 0.5)), has_color);\n" + " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n" + " return mix (vec4 (0.0), texel, has_color);\n" "}\n", namestr, rectstr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, namestr, - namestr, namestr, namestr, rectstr, namestr); + namestr, namestr, namestr, rectstr, namestr, namestr); break; } } @@ -838,6 +851,47 @@ _cairo_gl_shader_emit_border_fade (cairo_output_stream_t *stream, _cairo_output_stream_printf (stream, "}\n"); } +/* + * Emits the wrap function used by an operand. + * + * In OpenGL ES 2.0, repeat wrap modes (GL_REPEAT and GL_MIRRORED REPEAT) are + * only available for NPOT textures if the GL_OES_texture_npot is supported. + * If GL_OES_texture_npot is not supported, we need to implement the wrapping + * functionality in the shader. + */ +static void +_cairo_gl_shader_emit_wrap (cairo_gl_context_t *ctx, + cairo_output_stream_t *stream, + cairo_gl_operand_t *operand, + cairo_gl_tex_t name) +{ + const char *namestr = operand_names[name]; + cairo_extend_t extend = _cairo_gl_operand_get_extend (operand); + + _cairo_output_stream_printf (stream, + "vec2 %s_wrap(vec2 coords)\n" + "{\n", + namestr); + + if (! ctx->has_npot_repeat && + (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT)) + { + if (extend == CAIRO_EXTEND_REPEAT) { + _cairo_output_stream_printf (stream, + " return fract(coords);\n"); + } else { /* CAIRO_EXTEND_REFLECT */ + _cairo_output_stream_printf (stream, + " return mix(fract(coords), 1.0 - fract(coords), floor(mod(coords, 2.0)));\n"); + } + } + else + { + _cairo_output_stream_printf (stream, " return coords;\n"); + } + + _cairo_output_stream_printf (stream, "}\n"); +} + static cairo_status_t cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx, cairo_gl_shader_in_t in, @@ -858,6 +912,9 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx, "precision mediump float;\n" "#endif\n"); + _cairo_gl_shader_emit_wrap (ctx, stream, src, CAIRO_GL_TEX_SOURCE); + _cairo_gl_shader_emit_wrap (ctx, stream, mask, CAIRO_GL_TEX_MASK); + if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) { if (_cairo_gl_shader_needs_border_fade (src)) _cairo_gl_shader_emit_border_fade (stream, src, CAIRO_GL_TEX_SOURCE); @@ -1065,6 +1122,7 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx, char *fs_source; cairo_status_t status; + lookup.ctx = ctx; lookup.src = source->type; lookup.mask = mask->type; lookup.dest = CAIRO_GL_OPERAND_NONE; @@ -1072,8 +1130,10 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx, lookup.in = in; lookup.src_gl_filter = _cairo_gl_operand_get_gl_filter (source); lookup.src_border_fade = _cairo_gl_shader_needs_border_fade (source); + lookup.src_extend = _cairo_gl_operand_get_extend (source); lookup.mask_gl_filter = _cairo_gl_operand_get_gl_filter (mask); lookup.mask_border_fade = _cairo_gl_shader_needs_border_fade (mask); + lookup.mask_extend = _cairo_gl_operand_get_extend (mask); lookup.base.hash = _cairo_gl_shader_cache_hash (&lookup); lookup.base.size = 1;