Pattern/GL: Two Color Stops optimization for linear gradients. 33/54833/2
authornisanthmp <nisanth.mp@samsung.com>
Fri, 18 Dec 2015 06:00:06 +0000 (11:30 +0530)
committernisanthmp <nisanth.mp@samsung.com>
Fri, 18 Dec 2015 08:00:26 +0000 (13:30 +0530)
Also 1) Updated shader cache lookup code to include 2 stops case.
     2) 2 stop opt code now supports repeat and reflect patterns.
     3) texel R,G and B values are now pre-multiplied by alpha.

Change-Id: I053a074660635fc362a8ae37f2782009ef08f125
Signed-off-by: nisanthmp <nisanth.mp@samsung.com>
src/cairo-gl-gradient-private.h
src/cairo-gl-gradient.c
src/cairo-gl-operand.c
src/cairo-gl-shaders.c

index 8d95f70..d66f3dc 100644 (file)
@@ -94,8 +94,7 @@ cairo_private cairo_int_status_t
 _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
                            unsigned int                  n_stops,
                            const cairo_gradient_stop_t  *stops,
-                           cairo_gl_gradient_t         **gradient_out,
-                           cairo_pattern_type_t          pat_type);
+                           cairo_gl_gradient_t         **gradient_out);
 
 cairo_private_no_warn cairo_gl_gradient_t *
 _cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient);
index a6084ce..325612b 100644 (file)
@@ -233,8 +233,7 @@ cairo_int_status_t
 _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
                            unsigned int                  n_stops,
                            const cairo_gradient_stop_t  *stops,
-                           cairo_gl_gradient_t         **gradient_out,
-                           cairo_pattern_type_t          pat_type)
+                           cairo_gl_gradient_t         **gradient_out)
 {
     unsigned long hash;
     cairo_gl_gradient_t *gradient;
@@ -270,7 +269,7 @@ _cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
     gradient->stops = gradient->stops_embedded;
     memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t));
 
-    if (pat_type != CAIRO_PATTERN_TYPE_RADIAL || n_stops != 2) {
+    if (n_stops != 2) {
        ctx->dispatch.GenTextures (1, &gradient->tex);
        _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
        ctx->dispatch.BindTexture (ctx->tex_target, gradient->tex);
index 443d06a..575096a 100644 (file)
@@ -65,7 +65,7 @@ _cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
     if (unlikely (status))
        return status;
 
-    status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient, pattern->base.type);
+    status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
 
     return _cairo_gl_context_release (ctx, status);
 }
@@ -1220,6 +1220,8 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
        _cairo_gl_shader_bind_float  (ctx,
                                      ctx->current_shader->radius_0_location[tex_unit],
                                      operand->gradient.radius_0);
+        /* fall through */
+    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
        if (operand->gradient.gradient->n_stops == 2) {
            _cairo_gl_shader_bind_vec4   (ctx,
                                          ctx->current_shader->color_1_location[tex_unit],
@@ -1243,7 +1245,6 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                                         operand->gradient.gradient->stops[1].offset);
        }
         /* fall through */
-    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
     case CAIRO_GL_OPERAND_TEXTURE:
     case CAIRO_GL_OPERAND_GAUSSIAN:
        /*
index 623f8d6..b5796f7 100644 (file)
@@ -125,6 +125,9 @@ typedef struct _cairo_shader_cache_entry {
     cairo_bool_t src_use_atlas;
     cairo_bool_t mask_use_atlas;
 
+    cairo_bool_t src_n_stops_is_two;
+    cairo_bool_t mask_n_stops_is_two;
+
     cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */
     cairo_gl_shader_t shader;
 } cairo_shader_cache_entry_t;
@@ -144,7 +147,9 @@ _cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b)
            a->use_coverage == b->use_coverage &&
            a->in   == b->in &&
            (both_have_npot_repeat || a->src_extend == b->src_extend) &&
-           (both_have_npot_repeat || a->mask_extend == b->mask_extend));
+           (both_have_npot_repeat || a->mask_extend == b->mask_extend) &&
+           a->src_n_stops_is_two == b->src_n_stops_is_two &&
+           a->mask_n_stops_is_two == b->mask_n_stops_is_two);
 }
 
 /*
@@ -171,13 +176,17 @@ _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
            (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 &&
-           (both_have_npot_repeat || a->mask_extend == b->mask_extend));
+           (both_have_npot_repeat || a->mask_extend == b->mask_extend) &&
+           a->src_n_stops_is_two == b->src_n_stops_is_two &&
+           a->mask_n_stops_is_two == b->mask_n_stops_is_two);
 }
 
 static unsigned long
 _cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry)
 {
-    return ((entry->src << 15) |
+    return ((entry->src_n_stops_is_two << 19) |
+            (entry->mask_n_stops_is_two << 18) |
+            (entry->src << 15) |
            (entry->mask << 12) |
            (entry->dest << 9) |
            (entry->in << 7) |
@@ -749,6 +758,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
        }
         break;
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+       if (op->gradient.gradient->n_stops != 2) {
        if (needs_glsl330 == CAIRO_GLSL_VERSION_330) {
            _cairo_output_stream_printf (stream,
                "in vec2 %s_texcoords;\n"
@@ -788,6 +798,91 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "}\n",
                textstr, rectstr, namestr, namestr, namestr);
        }
+        } else { // else of if (op->gradient.gradient->n_stops != 2)
+        if (needs_glsl330 == CAIRO_GLSL_VERSION_330) {
+            _cairo_output_stream_printf (stream,
+                "in vec2 %s_texcoords;\n"
+                "uniform vec2 %s_texdims;\n"
+                "uniform sampler2D%s %s_sampler;\n"
+                "uniform vec4 %s_color_1;\n"
+                "uniform vec4 %s_color_2;\n"
+                "uniform float %s_offset_1;\n"
+                "uniform float %s_offset_2;\n"
+                "\n"
+                "vec4 get_%s()\n"
+                "{\n",
+                namestr, namestr, rectstr, namestr, namestr,
+                namestr, namestr, namestr, namestr);
+        }
+        else {
+            _cairo_output_stream_printf (stream,
+                "varying vec2 %s_texcoords;\n"
+                "uniform vec2 %s_texdims;\n"
+                "uniform sampler2D%s %s_sampler;\n"
+                "uniform vec4 %s_color_1;\n"
+                "uniform vec4 %s_color_2;\n"
+                "uniform float %s_offset_1;\n"
+                "uniform float %s_offset_2;\n"
+                "\n"
+                "vec4 get_%s()\n"
+                "{\n",
+                namestr, namestr, rectstr, namestr, namestr,
+                namestr, namestr, namestr, namestr);
+        }
+
+        if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
+             ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
+            _cairo_gl_shader_needs_border_fade (op))
+        {
+            _cairo_output_stream_printf (stream,
+                "    float border_fade = %s_border_fade (%s_texcoords.x, %s_texdims.x);\n"
+                "    vec4 texel;\n"
+                "    float scale;\n"
+                "    float factor;\n"
+                "    float upper_t = %s_texcoords.x;\n"
+                "    if (upper_t <= %s_offset_1) {\n"
+                "       texel = %s_color_1;\n"
+                "    } else if (upper_t >= %s_offset_2) {\n"
+                "       texel = %s_color_2;\n"
+                "    } else {\n"
+                "       scale = %s_offset_2 - %s_offset_1;\n"
+                "       factor = (upper_t - %s_offset_1)/scale;\n"
+                "       texel = mix (%s_color_1, %s_color_2, factor);\n"
+                "    }\n"
+                "    texel = vec4(texel.rgb * texel.a, texel.a);\n"
+                "    return texel * border_fade;\n"
+                "}\n",
+                namestr, namestr, namestr,
+                namestr, namestr, namestr, namestr,
+                namestr,
+                namestr, namestr, namestr, namestr, namestr);
+        }
+        else
+        {
+            _cairo_output_stream_printf (stream,
+                "    vec4 texel;\n"
+                "    float scale;\n"
+                "    float factor;\n"
+                "    float upper_t = (vec2(%s_wrap (vec2 (%s_texcoords.x, 0.5)))).x;\n"
+                "    if (upper_t <= %s_offset_1) {\n"
+                "       texel = %s_color_1;\n"
+                "    } else if (upper_t >= %s_offset_2) {\n"
+                "       texel = %s_color_2;\n"
+                "    } else {\n"
+                "       scale = %s_offset_2 - %s_offset_1;\n"
+                "       factor = (upper_t - %s_offset_1)/scale;\n"
+                "       texel = mix (%s_color_1, %s_color_2, factor);\n"
+                "    }\n"
+                "    texel = vec4(texel.rgb * texel.a, texel.a);\n"
+                "    return texel;\n"
+                "}\n",
+                namestr, namestr, namestr, namestr, namestr, namestr,
+                namestr, namestr, namestr, namestr, namestr
+                );
+        }
+
+        } //end of if (op->gradient.gradient->n_stops != 2)
+
        break;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
        if (op->gradient.gradient->n_stops != 2) {
@@ -858,13 +953,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "uniform sampler2D%s %s_sampler;\n"
                "uniform vec3 %s_circle_d;\n"
                "uniform float %s_radius_0;\n"
-//two_color_mod
-#if 1
                "uniform vec4 %s_color_1;\n"
                "uniform vec4 %s_color_2;\n"
                "uniform float %s_offset_1;\n"
                "uniform float %s_offset_2;\n"
-#endif
                "\n"
                "vec4 get_%s()\n"
                "{\n"
@@ -885,13 +977,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "uniform sampler2D%s %s_sampler;\n"
                "uniform vec3 %s_circle_d;\n"
                "uniform float %s_radius_0;\n"
-//two_color_mod
-#if 1
                "uniform vec4 %s_color_1;\n"
                "uniform vec4 %s_color_2;\n"
                "uniform float %s_offset_1;\n"
                "uniform float %s_offset_2;\n"
-#endif
                "\n"
                "vec4 get_%s()\n"
                "{\n"
@@ -913,8 +1002,6 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
        {
            _cairo_output_stream_printf (stream,
                "    float border_fade = %s_border_fade (t, %s_texdims.x);\n"
-               //"    vec4 texel = texture%s%s (%s_sampler, vec2 (t, 0.5));\n"
-//two_color_mod
                "    vec4 texel;\n"
                "    float scale;\n"
                "    float factor;\n"
@@ -927,6 +1014,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "       factor = (t - %s_offset_1)/scale;\n"
                "       texel = mix (%s_color_1, %s_color_2, factor);\n"
                "    }\n"
+                "    texel = vec4(texel.rgb * texel.a, texel.a);\n"
                "    return mix (vec4 (0.0), texel * border_fade, is_valid);\n"
                "}\n",
                namestr, namestr, namestr, namestr, namestr, namestr,
@@ -935,8 +1023,6 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
        else
        {
            _cairo_output_stream_printf (stream,
-               //"    vec4 texel = texture%s%s (%s_sampler, %s_wrap (vec2 (t, 0.5)));\n"
-//two_color_mod
                "    vec4 texel;\n"
                "    float scale;\n"
                "    float factor;\n"
@@ -950,6 +1036,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "       factor = (upper_t - %s_offset_1)/scale;\n"
                "       texel = mix (%s_color_1, %s_color_2, factor);\n"
                "    }\n"
+                "    texel = vec4(texel.rgb * texel.a, texel.a);\n"
                "    return mix (vec4 (0.0), texel, is_valid);\n"
                "}\n",
                namestr, namestr, namestr, namestr, namestr,
@@ -1042,13 +1129,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "uniform vec3 %s_circle_d;\n"
                "uniform float %s_a;\n"
                "uniform float %s_radius_0;\n"
-//two_color_mod
-#if 1
                "uniform vec4 %s_color_1;\n"
                "uniform vec4 %s_color_2;\n"
                "uniform float %s_offset_1;\n"
                "uniform float %s_offset_2;\n"
-#endif
                "\n"
                "vec4 get_%s()\n"
                "{\n"
@@ -1076,13 +1160,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "uniform vec3 %s_circle_d;\n"
                "uniform float %s_a;\n"
                "uniform float %s_radius_0;\n"
-//two_color_mod
-#if 1
                "uniform vec4 %s_color_1;\n"
                "uniform vec4 %s_color_2;\n"
                "uniform float %s_offset_1;\n"
                "uniform float %s_offset_2;\n"
-#endif
                "\n"
                "vec4 get_%s()\n"
                "{\n"
@@ -1110,8 +1191,6 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
        {
            _cairo_output_stream_printf (stream,
                "    float border_fade = %s_border_fade (upper_t, %s_texdims.x);\n"
-               //"    vec4 texel = texture%s%s (%s_sampler, vec2 (upper_t, 0.5));\n"
-//two_color_mod
                "    vec4 texel;\n"
                "    float scale;\n"
                "    float factor;\n"
@@ -1124,6 +1203,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "       factor = (upper_t - %s_offset_1)/scale;\n"
                "       texel = mix (%s_color_1, %s_color_2, factor);\n"
                "    }\n"
+                "    texel = vec4(texel.rgb * texel.a, texel.a);\n"
                "    return mix (vec4 (0.0), texel * border_fade, has_color);\n"
                "}\n",
                namestr, namestr, namestr, namestr, namestr, namestr,
@@ -1132,8 +1212,6 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
        else
        {
            _cairo_output_stream_printf (stream,
-               //"    vec4 texel = texture%s%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
-//two_color_mod
                "    vec4 texel;\n"
                "    float scale;\n"
                "    float factor;\n"
@@ -1147,6 +1225,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "       factor = (upper_tw - %s_offset_1)/scale;\n"
                "       texel = mix (%s_color_1, %s_color_2, factor);\n"
                "    }\n"
+                "    texel = vec4(texel.rgb * texel.a, texel.a);\n"
                "    return mix (vec4 (0.0), texel, has_color);\n"
                "}\n",
                namestr, namestr, namestr, namestr, namestr,
@@ -1225,13 +1304,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "uniform vec3 %s_circle_d;\n"
                "uniform float %s_a;\n"
                "uniform float %s_radius_0;\n"
-//two_color_mod
-#if 1
                "uniform vec4 %s_color_1;\n"
                "uniform vec4 %s_color_2;\n"
                "uniform float %s_offset_1;\n"
                "uniform float %s_offset_2;\n"
-#endif
                "\n"
                "vec4 get_%s()\n"
                "{\n"
@@ -1248,7 +1324,6 @@ 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"
-//two_color_mod
                "    vec4 texel;\n"
                "    float scale;\n"
                "    float factor;\n"
@@ -1262,6 +1337,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "       factor = (upper_tw - %s_offset_1)/scale;\n"
                "       texel = mix (%s_color_1, %s_color_2, factor);\n"
                "    }\n"
+                "    texel = vec4(texel.rgb * texel.a, texel.a);\n"
                "    return mix (vec4 (0.0), texel, has_color);\n"
                "}\n",
                namestr, rectstr, namestr, namestr, namestr, namestr,
@@ -1277,13 +1353,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "uniform vec3 %s_circle_d;\n"
                "uniform float %s_a;\n"
                "uniform float %s_radius_0;\n"
-//two_color_mod
-#if 1
                "uniform vec4 %s_color_1;\n"
                "uniform vec4 %s_color_2;\n"
                "uniform float %s_offset_1;\n"
                "uniform float %s_offset_2;\n"
-#endif
                "\n"
                "vec4 get_%s()\n"
                "{\n"
@@ -1300,7 +1373,6 @@ 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"
-//two_color_mod
                "    vec4 texel;\n"
                "    float scale;\n"
                "    float factor;\n"
@@ -1314,6 +1386,7 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
                "       factor = (upper_tw - %s_offset_1)/scale;\n"
                "       texel = mix (%s_color_1, %s_color_2, factor);\n"
                "    }\n"
+                "    texel = vec4(texel.rgb * texel.a, texel.a);\n"
                "    return mix (vec4 (0.0), texel, has_color);\n"
                "}\n",
                namestr, rectstr, namestr, namestr, namestr, namestr,
@@ -1456,7 +1529,12 @@ _cairo_gl_shader_emit_wrap (cairo_gl_context_t *ctx,
        }
     }
     else {
-       if (! ctx->has_npot_repeat &&
+        if (((! ctx->has_npot_repeat) ||
+                ((operand->type == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
+                  operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0 ||
+                  operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE ||
+                  operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT) &&
+                 operand->gradient.gradient->n_stops == 2)) &&
            (extend == CAIRO_EXTEND_REPEAT ||
             extend == CAIRO_EXTEND_REFLECT)) {
            if (extend == CAIRO_EXTEND_REPEAT) {
@@ -1775,7 +1853,6 @@ _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
        shader->alpha_location[i] =
             _cairo_gl_get_op_uniform_location (ctx, shader, i, "alpha");
 
-//two_color_mod
        shader->color_1_location[i] =
             _cairo_gl_get_op_uniform_location (ctx, shader, i, "color_1");
        shader->color_2_location[i] =
@@ -1955,6 +2032,22 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
                                            use_coverage,
                                            CAIRO_GL_VAR_NONE);
 
+    if (source->type == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
+        source->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0 ||
+        source->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE ||
+        source->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT)
+        lookup.src_n_stops_is_two = source->gradient.gradient->n_stops == 2;
+    else
+        lookup.src_n_stops_is_two = FALSE;
+
+    if (mask->type == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
+        mask->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0 ||
+        mask->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE ||
+        mask->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT)
+        lookup.mask_n_stops_is_two = mask->gradient.gradient->n_stops == 2;
+    else
+        lookup.mask_n_stops_is_two = FALSE;
+
     lookup.src = source->type;
     lookup.mask = mask->type;
     lookup.dest = CAIRO_GL_OPERAND_NONE;