135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2009 Intel Corporation
335c4bbdfSmrg *
435c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a
535c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
635c4bbdfSmrg * to deal in the Software without restriction, including without limitation
735c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
835c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the
935c4bbdfSmrg * Software is furnished to do so, subject to the following conditions:
1035c4bbdfSmrg *
1135c4bbdfSmrg * The above copyright notice and this permission notice (including the next
1235c4bbdfSmrg * paragraph) shall be included in all copies or substantial portions of the
1335c4bbdfSmrg * Software.
1435c4bbdfSmrg *
1535c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1635c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1735c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1835c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1935c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2035c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2135c4bbdfSmrg * IN THE SOFTWARE.
2235c4bbdfSmrg *
2335c4bbdfSmrg * Authors:
2435c4bbdfSmrg *    Junyan He <junyan.he@linux.intel.com>
2535c4bbdfSmrg *
2635c4bbdfSmrg */
2735c4bbdfSmrg
2835c4bbdfSmrg/** @file glamor_gradient.c
2935c4bbdfSmrg *
3035c4bbdfSmrg * Gradient acceleration implementation
3135c4bbdfSmrg */
3235c4bbdfSmrg
3335c4bbdfSmrg#include "glamor_priv.h"
3435c4bbdfSmrg
3535c4bbdfSmrg#define LINEAR_SMALL_STOPS (6 + 2)
3635c4bbdfSmrg#define LINEAR_LARGE_STOPS (16 + 2)
3735c4bbdfSmrg
3835c4bbdfSmrg#define RADIAL_SMALL_STOPS (6 + 2)
3935c4bbdfSmrg#define RADIAL_LARGE_STOPS (16 + 2)
4035c4bbdfSmrg
411b5d61b8Smrgstatic char *
4235c4bbdfSmrg_glamor_create_getcolor_fs_source(ScreenPtr screen, int stops_count,
4335c4bbdfSmrg                                  int use_array)
4435c4bbdfSmrg{
4535c4bbdfSmrg    char *gradient_fs = NULL;
4635c4bbdfSmrg
4735c4bbdfSmrg#define gradient_fs_getcolor\
4835c4bbdfSmrg	    GLAMOR_DEFAULT_PRECISION\
4935c4bbdfSmrg	    "uniform int n_stop;\n"\
5035c4bbdfSmrg	    "uniform float stops[%d];\n"\
5135c4bbdfSmrg	    "uniform vec4 stop_colors[%d];\n"\
5235c4bbdfSmrg	    "vec4 get_color(float stop_len)\n"\
5335c4bbdfSmrg	    "{\n"\
5435c4bbdfSmrg	    "    int i = 0;\n"\
551b5d61b8Smrg	    "    vec4 stop_color_before;\n"\
5635c4bbdfSmrg	    "    vec4 gradient_color;\n"\
571b5d61b8Smrg	    "    float stop_delta;\n"\
5835c4bbdfSmrg	    "    float percentage; \n"\
591b5d61b8Smrg	    "    \n"\
601b5d61b8Smrg	    "    if(stop_len < stops[0])\n"\
611b5d61b8Smrg	    "        return vec4(0.0, 0.0, 0.0, 0.0); \n"\
621b5d61b8Smrg	    "    for(i = 1; i < n_stop; i++) {\n"\
6335c4bbdfSmrg	    "        if(stop_len < stops[i])\n"\
6435c4bbdfSmrg	    "            break; \n"\
6535c4bbdfSmrg	    "    }\n"\
661b5d61b8Smrg	    "    if(i == n_stop)\n"\
671b5d61b8Smrg	    "        return vec4(0.0, 0.0, 0.0, 0.0); \n"\
6835c4bbdfSmrg	    "    \n"\
691b5d61b8Smrg	    "    stop_color_before = stop_colors[i-1];\n"\
701b5d61b8Smrg	    "    stop_delta = stops[i] - stops[i-1];\n"\
711b5d61b8Smrg	    "    if(stop_delta > 2.0)\n"\
7235c4bbdfSmrg	    "        percentage = 0.0;\n" /*For comply with pixman, walker->stepper overflow.*/\
731b5d61b8Smrg	    "    else if(stop_delta < 0.000001)\n"\
7435c4bbdfSmrg	    "        percentage = 0.0;\n"\
7535c4bbdfSmrg	    "    else \n"\
761b5d61b8Smrg	    "        percentage = (stop_len - stops[i-1])/stop_delta;\n"\
7735c4bbdfSmrg	    "    \n"\
781b5d61b8Smrg	    "    gradient_color = stop_color_before;\n"\
791b5d61b8Smrg	    "    if(percentage != 0.0)\n"\
801b5d61b8Smrg	    "        gradient_color += (stop_colors[i] - gradient_color)*percentage;\n"\
811b5d61b8Smrg	    "    return vec4(gradient_color.rgb * gradient_color.a, gradient_color.a);\n"\
8235c4bbdfSmrg	    "}\n"
8335c4bbdfSmrg
8435c4bbdfSmrg    /* Because the array access for shader is very slow, the performance is very low
8535c4bbdfSmrg       if use array. So use global uniform to replace for it if the number of n_stops is small. */
8635c4bbdfSmrg    const char *gradient_fs_getcolor_no_array =
8735c4bbdfSmrg        GLAMOR_DEFAULT_PRECISION
8835c4bbdfSmrg        "uniform int n_stop;\n"
8935c4bbdfSmrg        "uniform float stop0;\n"
9035c4bbdfSmrg        "uniform float stop1;\n"
9135c4bbdfSmrg        "uniform float stop2;\n"
9235c4bbdfSmrg        "uniform float stop3;\n"
9335c4bbdfSmrg        "uniform float stop4;\n"
9435c4bbdfSmrg        "uniform float stop5;\n"
9535c4bbdfSmrg        "uniform float stop6;\n"
9635c4bbdfSmrg        "uniform float stop7;\n"
9735c4bbdfSmrg        "uniform vec4 stop_color0;\n"
9835c4bbdfSmrg        "uniform vec4 stop_color1;\n"
9935c4bbdfSmrg        "uniform vec4 stop_color2;\n"
10035c4bbdfSmrg        "uniform vec4 stop_color3;\n"
10135c4bbdfSmrg        "uniform vec4 stop_color4;\n"
10235c4bbdfSmrg        "uniform vec4 stop_color5;\n"
10335c4bbdfSmrg        "uniform vec4 stop_color6;\n"
10435c4bbdfSmrg        "uniform vec4 stop_color7;\n"
10535c4bbdfSmrg        "\n"
10635c4bbdfSmrg        "vec4 get_color(float stop_len)\n"
10735c4bbdfSmrg        "{\n"
10835c4bbdfSmrg        "    vec4 stop_color_before;\n"
10935c4bbdfSmrg        "    vec4 stop_color_after;\n"
11035c4bbdfSmrg        "    vec4 gradient_color;\n"
1111b5d61b8Smrg        "    float stop_before;\n"
1121b5d61b8Smrg        "    float stop_delta;\n"
11335c4bbdfSmrg        "    float percentage; \n"
11435c4bbdfSmrg        "    \n"
11535c4bbdfSmrg        "    if((stop_len < stop0) && (n_stop >= 1)) {\n"
1161b5d61b8Smrg        "        stop_color_before = vec4(0.0, 0.0, 0.0, 0.0);\n"
1171b5d61b8Smrg        "        stop_delta = 0.0;\n"
11835c4bbdfSmrg        "    } else if((stop_len < stop1) && (n_stop >= 2)) {\n"
11935c4bbdfSmrg        "        stop_color_before = stop_color0;\n"
12035c4bbdfSmrg        "        stop_color_after = stop_color1;\n"
12135c4bbdfSmrg        "        stop_before = stop0;\n"
1221b5d61b8Smrg        "        stop_delta = stop1 - stop0;\n"
12335c4bbdfSmrg        "    } else if((stop_len < stop2) && (n_stop >= 3)) {\n"
12435c4bbdfSmrg        "        stop_color_before = stop_color1;\n"
12535c4bbdfSmrg        "        stop_color_after = stop_color2;\n"
12635c4bbdfSmrg        "        stop_before = stop1;\n"
1271b5d61b8Smrg        "        stop_delta = stop2 - stop1;\n"
12835c4bbdfSmrg        "    } else if((stop_len < stop3) && (n_stop >= 4)){\n"
12935c4bbdfSmrg        "        stop_color_before = stop_color2;\n"
13035c4bbdfSmrg        "        stop_color_after = stop_color3;\n"
13135c4bbdfSmrg        "        stop_before = stop2;\n"
1321b5d61b8Smrg        "        stop_delta = stop3 - stop2;\n"
13335c4bbdfSmrg        "    } else if((stop_len < stop4) && (n_stop >= 5)){\n"
13435c4bbdfSmrg        "        stop_color_before = stop_color3;\n"
13535c4bbdfSmrg        "        stop_color_after = stop_color4;\n"
13635c4bbdfSmrg        "        stop_before = stop3;\n"
1371b5d61b8Smrg        "        stop_delta = stop4 - stop3;\n"
13835c4bbdfSmrg        "    } else if((stop_len < stop5) && (n_stop >= 6)){\n"
13935c4bbdfSmrg        "        stop_color_before = stop_color4;\n"
14035c4bbdfSmrg        "        stop_color_after = stop_color5;\n"
14135c4bbdfSmrg        "        stop_before = stop4;\n"
1421b5d61b8Smrg        "        stop_delta = stop5 - stop4;\n"
14335c4bbdfSmrg        "    } else if((stop_len < stop6) && (n_stop >= 7)){\n"
14435c4bbdfSmrg        "        stop_color_before = stop_color5;\n"
14535c4bbdfSmrg        "        stop_color_after = stop_color6;\n"
14635c4bbdfSmrg        "        stop_before = stop5;\n"
1471b5d61b8Smrg        "        stop_delta = stop6 - stop5;\n"
14835c4bbdfSmrg        "    } else if((stop_len < stop7) && (n_stop >= 8)){\n"
14935c4bbdfSmrg        "        stop_color_before = stop_color6;\n"
15035c4bbdfSmrg        "        stop_color_after = stop_color7;\n"
15135c4bbdfSmrg        "        stop_before = stop6;\n"
1521b5d61b8Smrg        "        stop_delta = stop7 - stop6;\n"
15335c4bbdfSmrg        "    } else {\n"
1541b5d61b8Smrg        "        stop_color_before = vec4(0.0, 0.0, 0.0, 0.0);\n"
1551b5d61b8Smrg        "        stop_delta = 0.0;\n"
15635c4bbdfSmrg        "    }\n"
1571b5d61b8Smrg        "    if(stop_delta > 2.0)\n"
15835c4bbdfSmrg        "        percentage = 0.0;\n" //For comply with pixman, walker->stepper overflow.
1591b5d61b8Smrg        "    else if(stop_delta < 0.000001)\n"
16035c4bbdfSmrg        "        percentage = 0.0;\n"
1611b5d61b8Smrg        "    else\n"
1621b5d61b8Smrg        "        percentage = (stop_len - stop_before)/stop_delta;\n"
16335c4bbdfSmrg        "    \n"
1641b5d61b8Smrg        "    gradient_color = stop_color_before;\n"
1651b5d61b8Smrg        "    if(percentage != 0.0)\n"
1661b5d61b8Smrg        "        gradient_color += (stop_color_after - gradient_color)*percentage;\n"
1671b5d61b8Smrg        "    return vec4(gradient_color.rgb * gradient_color.a, gradient_color.a);\n"
16835c4bbdfSmrg        "}\n";
16935c4bbdfSmrg
17035c4bbdfSmrg    if (use_array) {
17135c4bbdfSmrg        XNFasprintf(&gradient_fs,
17235c4bbdfSmrg                    gradient_fs_getcolor, stops_count, stops_count);
17335c4bbdfSmrg        return gradient_fs;
17435c4bbdfSmrg    }
17535c4bbdfSmrg    else {
17635c4bbdfSmrg        return XNFstrdup(gradient_fs_getcolor_no_array);
17735c4bbdfSmrg    }
17835c4bbdfSmrg}
17935c4bbdfSmrg
18035c4bbdfSmrgstatic void
18135c4bbdfSmrg_glamor_create_radial_gradient_program(ScreenPtr screen, int stops_count,
18235c4bbdfSmrg                                       int dyn_gen)
18335c4bbdfSmrg{
18435c4bbdfSmrg    glamor_screen_private *glamor_priv;
18535c4bbdfSmrg    int index;
18635c4bbdfSmrg
18735c4bbdfSmrg    GLint gradient_prog = 0;
18835c4bbdfSmrg    char *gradient_fs = NULL;
18935c4bbdfSmrg    GLint fs_prog, vs_prog;
19035c4bbdfSmrg
19135c4bbdfSmrg    const char *gradient_vs =
19235c4bbdfSmrg        GLAMOR_DEFAULT_PRECISION
19335c4bbdfSmrg        "attribute vec4 v_position;\n"
19435c4bbdfSmrg        "attribute vec4 v_texcoord;\n"
19535c4bbdfSmrg        "varying vec2 source_texture;\n"
19635c4bbdfSmrg        "\n"
19735c4bbdfSmrg        "void main()\n"
19835c4bbdfSmrg        "{\n"
19935c4bbdfSmrg        "    gl_Position = v_position;\n"
20035c4bbdfSmrg        "    source_texture = v_texcoord.xy;\n"
20135c4bbdfSmrg        "}\n";
20235c4bbdfSmrg
20335c4bbdfSmrg    /*
20435c4bbdfSmrg     *     Refer to pixman radial gradient.
20535c4bbdfSmrg     *
20635c4bbdfSmrg     *     The problem is given the two circles of c1 and c2 with the radius of r1 and
207ed6184dfSmrg     *     r1, we need to calculate the t, which is used to do interpolate with stops,
20835c4bbdfSmrg     *     using the fomula:
20935c4bbdfSmrg     *     length((1-t)*c1 + t*c2 - p) = (1-t)*r1 + t*r2
21035c4bbdfSmrg     *     expand the fomula with xy coond, get the following:
21135c4bbdfSmrg     *     sqrt(sqr((1-t)*c1.x + t*c2.x - p.x) + sqr((1-t)*c1.y + t*c2.y - p.y))
21235c4bbdfSmrg     *           = (1-t)r1 + t*r2
21335c4bbdfSmrg     *     <====> At*t- 2Bt + C = 0
21435c4bbdfSmrg     *     where A = sqr(c2.x - c1.x) + sqr(c2.y - c1.y) - sqr(r2 -r1)
21535c4bbdfSmrg     *           B = (p.x - c1.x)*(c2.x - c1.x) + (p.y - c1.y)*(c2.y - c1.y) + r1*(r2 -r1)
21635c4bbdfSmrg     *           C = sqr(p.x - c1.x) + sqr(p.y - c1.y) - r1*r1
21735c4bbdfSmrg     *
21835c4bbdfSmrg     *     solve the fomula and we get the result of
21935c4bbdfSmrg     *     t = (B + sqrt(B*B - A*C)) / A  or
22035c4bbdfSmrg     *     t = (B - sqrt(B*B - A*C)) / A  (quadratic equation have two solutions)
22135c4bbdfSmrg     *
22235c4bbdfSmrg     *     The solution we are going to prefer is the bigger one, unless the
22335c4bbdfSmrg     *     radius associated to it is negative (or it falls outside the valid t range)
22435c4bbdfSmrg     */
22535c4bbdfSmrg
22635c4bbdfSmrg#define gradient_radial_fs_template\
22735c4bbdfSmrg	    GLAMOR_DEFAULT_PRECISION\
22835c4bbdfSmrg	    "uniform mat3 transform_mat;\n"\
22935c4bbdfSmrg	    "uniform int repeat_type;\n"\
23035c4bbdfSmrg	    "uniform float A_value;\n"\
23135c4bbdfSmrg	    "uniform vec2 c1;\n"\
23235c4bbdfSmrg	    "uniform float r1;\n"\
23335c4bbdfSmrg	    "uniform vec2 c2;\n"\
23435c4bbdfSmrg	    "uniform float r2;\n"\
23535c4bbdfSmrg	    "varying vec2 source_texture;\n"\
23635c4bbdfSmrg	    "\n"\
23735c4bbdfSmrg	    "vec4 get_color(float stop_len);\n"\
23835c4bbdfSmrg	    "\n"\
23935c4bbdfSmrg	    "int t_invalid;\n"\
24035c4bbdfSmrg	    "\n"\
24135c4bbdfSmrg	    "float get_stop_len()\n"\
24235c4bbdfSmrg	    "{\n"\
24335c4bbdfSmrg	    "    float t = 0.0;\n"\
24435c4bbdfSmrg	    "    float sqrt_value;\n"\
24535c4bbdfSmrg	    "    t_invalid = 0;\n"\
24635c4bbdfSmrg	    "    \n"\
24735c4bbdfSmrg	    "    vec3 tmp = vec3(source_texture.x, source_texture.y, 1.0);\n"\
24835c4bbdfSmrg	    "    vec3 source_texture_trans = transform_mat * tmp;\n"\
24935c4bbdfSmrg	    "    source_texture_trans.xy = source_texture_trans.xy/source_texture_trans.z;\n"\
25035c4bbdfSmrg	    "    float B_value = (source_texture_trans.x - c1.x) * (c2.x - c1.x)\n"\
25135c4bbdfSmrg	    "                     + (source_texture_trans.y - c1.y) * (c2.y - c1.y)\n"\
25235c4bbdfSmrg	    "                     + r1 * (r2 - r1);\n"\
25335c4bbdfSmrg	    "    float C_value = (source_texture_trans.x - c1.x) * (source_texture_trans.x - c1.x)\n"\
25435c4bbdfSmrg	    "                     + (source_texture_trans.y - c1.y) * (source_texture_trans.y - c1.y)\n"\
25535c4bbdfSmrg	    "                     - r1*r1;\n"\
25635c4bbdfSmrg	    "    if(abs(A_value) < 0.00001) {\n"\
25735c4bbdfSmrg	    "        if(B_value == 0.0) {\n"\
25835c4bbdfSmrg	    "            t_invalid = 1;\n"\
25935c4bbdfSmrg	    "            return t;\n"\
26035c4bbdfSmrg	    "        }\n"\
26135c4bbdfSmrg	    "        t = 0.5 * C_value / B_value;"\
26235c4bbdfSmrg	    "    } else {\n"\
26335c4bbdfSmrg	    "        sqrt_value = B_value * B_value - A_value * C_value;\n"\
26435c4bbdfSmrg	    "        if(sqrt_value < 0.0) {\n"\
26535c4bbdfSmrg	    "            t_invalid = 1;\n"\
26635c4bbdfSmrg	    "            return t;\n"\
26735c4bbdfSmrg	    "        }\n"\
26835c4bbdfSmrg	    "        sqrt_value = sqrt(sqrt_value);\n"\
26935c4bbdfSmrg	    "        t = (B_value + sqrt_value) / A_value;\n"\
27035c4bbdfSmrg	    "    }\n"\
27135c4bbdfSmrg	    "    if(repeat_type == %d) {\n" /* RepeatNone case. */\
27235c4bbdfSmrg	    "        if((t <= 0.0) || (t > 1.0))\n"\
27335c4bbdfSmrg	    /*           try another if first one invalid*/\
27435c4bbdfSmrg	    "            t = (B_value - sqrt_value) / A_value;\n"\
27535c4bbdfSmrg	    "        \n"\
27635c4bbdfSmrg	    "        if((t <= 0.0) || (t > 1.0)) {\n" /*still invalid, return.*/\
27735c4bbdfSmrg	    "            t_invalid = 1;\n"\
27835c4bbdfSmrg	    "            return t;\n"\
27935c4bbdfSmrg	    "        }\n"\
28035c4bbdfSmrg	    "    } else {\n"\
28135c4bbdfSmrg	    "        if(t * (r2 - r1) <= -1.0 * r1)\n"\
28235c4bbdfSmrg	    /*           try another if first one invalid*/\
28335c4bbdfSmrg	    "            t = (B_value - sqrt_value) / A_value;\n"\
28435c4bbdfSmrg	    "        \n"\
28535c4bbdfSmrg	    "        if(t * (r2 -r1) <= -1.0 * r1) {\n" /*still invalid, return.*/\
28635c4bbdfSmrg	    "            t_invalid = 1;\n"\
28735c4bbdfSmrg	    "            return t;\n"\
28835c4bbdfSmrg	    "        }\n"\
28935c4bbdfSmrg	    "    }\n"\
29035c4bbdfSmrg	    "    \n"\
29135c4bbdfSmrg	    "    if(repeat_type == %d){\n" /* repeat normal*/\
29235c4bbdfSmrg	    "        t = fract(t);\n"\
29335c4bbdfSmrg	    "    }\n"\
29435c4bbdfSmrg	    "    \n"\
29535c4bbdfSmrg	    "    if(repeat_type == %d) {\n" /* repeat reflect*/\
29635c4bbdfSmrg	    "        t = abs(fract(t * 0.5 + 0.5) * 2.0 - 1.0);\n"\
29735c4bbdfSmrg	    "    }\n"\
29835c4bbdfSmrg	    "    \n"\
29935c4bbdfSmrg	    "    return t;\n"\
30035c4bbdfSmrg	    "}\n"\
30135c4bbdfSmrg	    "\n"\
30235c4bbdfSmrg	    "void main()\n"\
30335c4bbdfSmrg	    "{\n"\
30435c4bbdfSmrg	    "    float stop_len = get_stop_len();\n"\
30535c4bbdfSmrg	    "    if(t_invalid == 1) {\n"\
30635c4bbdfSmrg	    "        gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"\
30735c4bbdfSmrg	    "    } else {\n"\
30835c4bbdfSmrg	    "        gl_FragColor = get_color(stop_len);\n"\
30935c4bbdfSmrg	    "    }\n"\
31035c4bbdfSmrg	    "}\n"\
31135c4bbdfSmrg	    "\n"\
31235c4bbdfSmrg            "%s\n" /* fs_getcolor_source */
3131b5d61b8Smrg    char *fs_getcolor_source;
31435c4bbdfSmrg
31535c4bbdfSmrg    glamor_priv = glamor_get_screen_private(screen);
31635c4bbdfSmrg
31735c4bbdfSmrg    if ((glamor_priv->radial_max_nstops >= stops_count) && (dyn_gen)) {
31835c4bbdfSmrg        /* Very Good, not to generate again. */
31935c4bbdfSmrg        return;
32035c4bbdfSmrg    }
32135c4bbdfSmrg
32235c4bbdfSmrg    glamor_make_current(glamor_priv);
32335c4bbdfSmrg
32435c4bbdfSmrg    if (dyn_gen && glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2]) {
32535c4bbdfSmrg        glDeleteProgram(glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2]);
32635c4bbdfSmrg        glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2] = 0;
32735c4bbdfSmrg    }
32835c4bbdfSmrg
32935c4bbdfSmrg    gradient_prog = glCreateProgram();
33035c4bbdfSmrg
33135c4bbdfSmrg    vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, gradient_vs);
33235c4bbdfSmrg
33335c4bbdfSmrg    fs_getcolor_source =
33435c4bbdfSmrg        _glamor_create_getcolor_fs_source(screen, stops_count,
33535c4bbdfSmrg                                          (stops_count > 0));
33635c4bbdfSmrg
33735c4bbdfSmrg    XNFasprintf(&gradient_fs,
33835c4bbdfSmrg                gradient_radial_fs_template,
33935c4bbdfSmrg                PIXMAN_REPEAT_NONE, PIXMAN_REPEAT_NORMAL,
34035c4bbdfSmrg                PIXMAN_REPEAT_REFLECT,
34135c4bbdfSmrg                fs_getcolor_source);
34235c4bbdfSmrg
34335c4bbdfSmrg    fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, gradient_fs);
34435c4bbdfSmrg
34535c4bbdfSmrg    free(gradient_fs);
3461b5d61b8Smrg    free(fs_getcolor_source);
34735c4bbdfSmrg
34835c4bbdfSmrg    glAttachShader(gradient_prog, vs_prog);
34935c4bbdfSmrg    glAttachShader(gradient_prog, fs_prog);
35035c4bbdfSmrg    glDeleteShader(vs_prog);
35135c4bbdfSmrg    glDeleteShader(fs_prog);
35235c4bbdfSmrg
35335c4bbdfSmrg    glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_position");
35435c4bbdfSmrg    glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord");
35535c4bbdfSmrg
35635c4bbdfSmrg    glamor_link_glsl_prog(screen, gradient_prog, "radial gradient");
35735c4bbdfSmrg
35835c4bbdfSmrg    if (dyn_gen) {
35935c4bbdfSmrg        index = 2;
36035c4bbdfSmrg        glamor_priv->radial_max_nstops = stops_count;
36135c4bbdfSmrg    }
36235c4bbdfSmrg    else if (stops_count) {
36335c4bbdfSmrg        index = 1;
36435c4bbdfSmrg    }
36535c4bbdfSmrg    else {
36635c4bbdfSmrg        index = 0;
36735c4bbdfSmrg    }
36835c4bbdfSmrg
36935c4bbdfSmrg    glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][index] = gradient_prog;
37035c4bbdfSmrg}
37135c4bbdfSmrg
37235c4bbdfSmrgstatic void
37335c4bbdfSmrg_glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count,
37435c4bbdfSmrg                                       int dyn_gen)
37535c4bbdfSmrg{
37635c4bbdfSmrg    glamor_screen_private *glamor_priv;
37735c4bbdfSmrg
37835c4bbdfSmrg    int index = 0;
37935c4bbdfSmrg    GLint gradient_prog = 0;
38035c4bbdfSmrg    char *gradient_fs = NULL;
38135c4bbdfSmrg    GLint fs_prog, vs_prog;
38235c4bbdfSmrg
38335c4bbdfSmrg    const char *gradient_vs =
38435c4bbdfSmrg        GLAMOR_DEFAULT_PRECISION
38535c4bbdfSmrg        "attribute vec4 v_position;\n"
38635c4bbdfSmrg        "attribute vec4 v_texcoord;\n"
38735c4bbdfSmrg        "varying vec2 source_texture;\n"
38835c4bbdfSmrg        "\n"
38935c4bbdfSmrg        "void main()\n"
39035c4bbdfSmrg        "{\n"
39135c4bbdfSmrg        "    gl_Position = v_position;\n"
39235c4bbdfSmrg        "    source_texture = v_texcoord.xy;\n"
39335c4bbdfSmrg        "}\n";
39435c4bbdfSmrg
39535c4bbdfSmrg    /*
39635c4bbdfSmrg     *                                      |
39735c4bbdfSmrg     *                                      |\
39835c4bbdfSmrg     *                                      | \
39935c4bbdfSmrg     *                                      |  \
40035c4bbdfSmrg     *                                      |   \
40135c4bbdfSmrg     *                                      |\   \
40235c4bbdfSmrg     *                                      | \   \
40335c4bbdfSmrg     *     cos_val =                        |\ p1d \   /
40435c4bbdfSmrg     *      sqrt(1/(slope*slope+1.0))  ------>\ \   \ /
40535c4bbdfSmrg     *                                      |  \ \   \
40635c4bbdfSmrg     *                                      |   \ \ / \
40735c4bbdfSmrg     *                                      |    \ *Pt1\
40835c4bbdfSmrg     *         *p1                          |     \     \     *P
40935c4bbdfSmrg     *          \                           |    / \     \   /
41035c4bbdfSmrg     *           \                          |   /   \     \ /
41135c4bbdfSmrg     *            \                         |       pd     \
41235c4bbdfSmrg     *             \                        |         \   / \
41335c4bbdfSmrg     *            p2*                       |          \ /   \       /
41435c4bbdfSmrg     *        slope = (p2.y - p1.y) /       |           /     p2d   /
41535c4bbdfSmrg     *                    (p2.x - p1.x)     |          /       \   /
41635c4bbdfSmrg     *                                      |         /         \ /
41735c4bbdfSmrg     *                                      |        /           /
41835c4bbdfSmrg     *                                      |       /           /
41935c4bbdfSmrg     *                                      |      /           *Pt2
42035c4bbdfSmrg     *                                      |                 /
42135c4bbdfSmrg     *                                      |                /
42235c4bbdfSmrg     *                                      |               /
42335c4bbdfSmrg     *                                      |              /
42435c4bbdfSmrg     *                                      |             /
42535c4bbdfSmrg     *                               -------+---------------------------------
42635c4bbdfSmrg     *                                     O|
42735c4bbdfSmrg     *                                      |
42835c4bbdfSmrg     *                                      |
42935c4bbdfSmrg     *
43035c4bbdfSmrg     *      step 1: compute the distance of p, pt1 and pt2 in the slope direction.
431ed6184dfSmrg     *              Calculate the distance on Y axis first and multiply cos_val to
43235c4bbdfSmrg     *              get the value on slope direction(pd, p1d and p2d represent the
43335c4bbdfSmrg     *              distance of p, pt1, and pt2 respectively).
43435c4bbdfSmrg     *
435ed6184dfSmrg     *      step 2: calculate the percentage of (pd - p1d)/(p2d - p1d).
43635c4bbdfSmrg     *              If (pd - p1d) > (p2d - p1d) or < 0, then sub or add (p2d - p1d)
43735c4bbdfSmrg     *              to make it in the range of [0, (p2d - p1d)].
43835c4bbdfSmrg     *
43935c4bbdfSmrg     *      step 3: compare the percentage to every stop and find the stpos just
44035c4bbdfSmrg     *              before and after it. Use the interpolation fomula to compute RGBA.
44135c4bbdfSmrg     */
44235c4bbdfSmrg
44335c4bbdfSmrg#define gradient_fs_template	\
44435c4bbdfSmrg	    GLAMOR_DEFAULT_PRECISION\
44535c4bbdfSmrg	    "uniform mat3 transform_mat;\n"\
44635c4bbdfSmrg	    "uniform int repeat_type;\n"\
44735c4bbdfSmrg	    "uniform int hor_ver;\n"\
44835c4bbdfSmrg	    "uniform float pt_slope;\n"\
44935c4bbdfSmrg	    "uniform float cos_val;\n"\
45035c4bbdfSmrg	    "uniform float p1_distance;\n"\
45135c4bbdfSmrg	    "uniform float pt_distance;\n"\
45235c4bbdfSmrg	    "varying vec2 source_texture;\n"\
45335c4bbdfSmrg	    "\n"\
45435c4bbdfSmrg	    "vec4 get_color(float stop_len);\n"\
45535c4bbdfSmrg	    "\n"\
45635c4bbdfSmrg	    "float get_stop_len()\n"\
45735c4bbdfSmrg	    "{\n"\
45835c4bbdfSmrg	    "    vec3 tmp = vec3(source_texture.x, source_texture.y, 1.0);\n"\
45935c4bbdfSmrg	    "    float distance;\n"\
46035c4bbdfSmrg	    "    float _p1_distance;\n"\
46135c4bbdfSmrg	    "    float _pt_distance;\n"\
46235c4bbdfSmrg	    "    float y_dist;\n"\
46335c4bbdfSmrg	    "    vec3 source_texture_trans = transform_mat * tmp;\n"\
46435c4bbdfSmrg	    "    \n"\
46535c4bbdfSmrg	    "    if(hor_ver == 0) { \n" /*Normal case.*/\
46635c4bbdfSmrg	    "        y_dist = source_texture_trans.y - source_texture_trans.x*pt_slope;\n"\
46735c4bbdfSmrg	    "        distance = y_dist * cos_val;\n"\
46835c4bbdfSmrg	    "        _p1_distance = p1_distance * source_texture_trans.z;\n"\
46935c4bbdfSmrg	    "        _pt_distance = pt_distance * source_texture_trans.z;\n"\
47035c4bbdfSmrg	    "        \n"\
47135c4bbdfSmrg	    "    } else if (hor_ver == 1) {\n"/*horizontal case.*/\
47235c4bbdfSmrg	    "        distance = source_texture_trans.x;\n"\
47335c4bbdfSmrg	    "        _p1_distance = p1_distance * source_texture_trans.z;\n"\
47435c4bbdfSmrg	    "        _pt_distance = pt_distance * source_texture_trans.z;\n"\
47535c4bbdfSmrg	    "    } \n"\
47635c4bbdfSmrg	    "    \n"\
4771b5d61b8Smrg	    "    distance = (distance - _p1_distance) / _pt_distance;\n"\
47835c4bbdfSmrg	    "    \n"\
47935c4bbdfSmrg	    "    if(repeat_type == %d){\n" /* repeat normal*/\
4801b5d61b8Smrg	    "        distance = fract(distance);\n"\
48135c4bbdfSmrg	    "    }\n"\
48235c4bbdfSmrg	    "    \n"\
48335c4bbdfSmrg	    "    if(repeat_type == %d) {\n" /* repeat reflect*/\
4841b5d61b8Smrg	    "        distance = abs(fract(distance * 0.5 + 0.5) * 2.0 - 1.0);\n"\
48535c4bbdfSmrg	    "    }\n"\
48635c4bbdfSmrg	    "    \n"\
4871b5d61b8Smrg	    "    return distance;\n"\
48835c4bbdfSmrg	    "}\n"\
48935c4bbdfSmrg	    "\n"\
49035c4bbdfSmrg	    "void main()\n"\
49135c4bbdfSmrg	    "{\n"\
49235c4bbdfSmrg	    "    float stop_len = get_stop_len();\n"\
49335c4bbdfSmrg	    "    gl_FragColor = get_color(stop_len);\n"\
49435c4bbdfSmrg	    "}\n"\
49535c4bbdfSmrg	    "\n"\
49635c4bbdfSmrg            "%s" /* fs_getcolor_source */
4971b5d61b8Smrg    char *fs_getcolor_source;
49835c4bbdfSmrg
49935c4bbdfSmrg    glamor_priv = glamor_get_screen_private(screen);
50035c4bbdfSmrg
50135c4bbdfSmrg    if ((glamor_priv->linear_max_nstops >= stops_count) && (dyn_gen)) {
50235c4bbdfSmrg        /* Very Good, not to generate again. */
50335c4bbdfSmrg        return;
50435c4bbdfSmrg    }
50535c4bbdfSmrg
50635c4bbdfSmrg    glamor_make_current(glamor_priv);
50735c4bbdfSmrg    if (dyn_gen && glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2]) {
50835c4bbdfSmrg        glDeleteProgram(glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2]);
50935c4bbdfSmrg        glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2] = 0;
51035c4bbdfSmrg    }
51135c4bbdfSmrg
51235c4bbdfSmrg    gradient_prog = glCreateProgram();
51335c4bbdfSmrg
51435c4bbdfSmrg    vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, gradient_vs);
51535c4bbdfSmrg
51635c4bbdfSmrg    fs_getcolor_source =
51735c4bbdfSmrg        _glamor_create_getcolor_fs_source(screen, stops_count, stops_count > 0);
51835c4bbdfSmrg
51935c4bbdfSmrg    XNFasprintf(&gradient_fs,
52035c4bbdfSmrg                gradient_fs_template,
52135c4bbdfSmrg                PIXMAN_REPEAT_NORMAL, PIXMAN_REPEAT_REFLECT,
52235c4bbdfSmrg                fs_getcolor_source);
52335c4bbdfSmrg
52435c4bbdfSmrg    fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, gradient_fs);
52535c4bbdfSmrg    free(gradient_fs);
5261b5d61b8Smrg    free(fs_getcolor_source);
52735c4bbdfSmrg
52835c4bbdfSmrg    glAttachShader(gradient_prog, vs_prog);
52935c4bbdfSmrg    glAttachShader(gradient_prog, fs_prog);
53035c4bbdfSmrg    glDeleteShader(vs_prog);
53135c4bbdfSmrg    glDeleteShader(fs_prog);
53235c4bbdfSmrg
53335c4bbdfSmrg    glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_position");
53435c4bbdfSmrg    glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord");
53535c4bbdfSmrg
53635c4bbdfSmrg    glamor_link_glsl_prog(screen, gradient_prog, "linear gradient");
53735c4bbdfSmrg
53835c4bbdfSmrg    if (dyn_gen) {
53935c4bbdfSmrg        index = 2;
54035c4bbdfSmrg        glamor_priv->linear_max_nstops = stops_count;
54135c4bbdfSmrg    }
54235c4bbdfSmrg    else if (stops_count) {
54335c4bbdfSmrg        index = 1;
54435c4bbdfSmrg    }
54535c4bbdfSmrg    else {
54635c4bbdfSmrg        index = 0;
54735c4bbdfSmrg    }
54835c4bbdfSmrg
54935c4bbdfSmrg    glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][index] = gradient_prog;
55035c4bbdfSmrg}
55135c4bbdfSmrg
55235c4bbdfSmrgvoid
55335c4bbdfSmrgglamor_init_gradient_shader(ScreenPtr screen)
55435c4bbdfSmrg{
55535c4bbdfSmrg    glamor_screen_private *glamor_priv;
55635c4bbdfSmrg    int i;
55735c4bbdfSmrg
55835c4bbdfSmrg    glamor_priv = glamor_get_screen_private(screen);
55935c4bbdfSmrg
56035c4bbdfSmrg    for (i = 0; i < 3; i++) {
56135c4bbdfSmrg        glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][i] = 0;
56235c4bbdfSmrg        glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][i] = 0;
56335c4bbdfSmrg    }
56435c4bbdfSmrg    glamor_priv->linear_max_nstops = 0;
56535c4bbdfSmrg    glamor_priv->radial_max_nstops = 0;
56635c4bbdfSmrg
56735c4bbdfSmrg    _glamor_create_linear_gradient_program(screen, 0, 0);
56835c4bbdfSmrg    _glamor_create_linear_gradient_program(screen, LINEAR_LARGE_STOPS, 0);
56935c4bbdfSmrg
57035c4bbdfSmrg    _glamor_create_radial_gradient_program(screen, 0, 0);
57135c4bbdfSmrg    _glamor_create_radial_gradient_program(screen, RADIAL_LARGE_STOPS, 0);
57235c4bbdfSmrg}
57335c4bbdfSmrg
57435c4bbdfSmrgstatic void
57535c4bbdfSmrg_glamor_gradient_convert_trans_matrix(PictTransform *from, float to[3][3],
57635c4bbdfSmrg                                      int width, int height, int normalize)
57735c4bbdfSmrg{
57835c4bbdfSmrg    /*
57935c4bbdfSmrg     * Because in the shader program, we normalize all the pixel cood to [0, 1],
58035c4bbdfSmrg     * so with the transform matrix, the correct logic should be:
58135c4bbdfSmrg     * v_s = A*T*v
58235c4bbdfSmrg     * v_s: point vector in shader after normalized.
58335c4bbdfSmrg     * A: The transition matrix from   width X height --> 1.0 X 1.0
58435c4bbdfSmrg     * T: The transform matrix.
58535c4bbdfSmrg     * v: point vector in width X height space.
58635c4bbdfSmrg     *
58735c4bbdfSmrg     * result is OK if we use this fomula. But for every point in width X height space,
58835c4bbdfSmrg     * we can just use their normalized point vector in shader, namely we can just
58935c4bbdfSmrg     * use the result of A*v in shader. So we have no chance to insert T in A*v.
59035c4bbdfSmrg     * We can just convert v_s = A*T*v to v_s = A*T*inv(A)*A*v, where inv(A) is the
59135c4bbdfSmrg     * inverse matrix of A. Now, v_s = (A*T*inv(A)) * (A*v)
59235c4bbdfSmrg     * So, to get the correct v_s, we need to cacula1 the matrix: (A*T*inv(A)), and
59335c4bbdfSmrg     * we name this matrix T_s.
59435c4bbdfSmrg     *
5951b5d61b8Smrg     * Firstly, because A is for the scale conversion, we find
59635c4bbdfSmrg     *      --         --
59735c4bbdfSmrg     *      |1/w  0   0 |
59835c4bbdfSmrg     * A =  | 0  1/h  0 |
59935c4bbdfSmrg     *      | 0   0  1.0|
60035c4bbdfSmrg     *      --         --
60135c4bbdfSmrg     * so T_s = A*T*inv(a) and result
60235c4bbdfSmrg     *
60335c4bbdfSmrg     *       --                      --
60435c4bbdfSmrg     *       | t11      h*t12/w  t13/w|
60535c4bbdfSmrg     * T_s = | w*t21/h  t22      t23/h|
60635c4bbdfSmrg     *       | w*t31    h*t32    t33  |
60735c4bbdfSmrg     *       --                      --
60835c4bbdfSmrg     */
60935c4bbdfSmrg
61035c4bbdfSmrg    to[0][0] = (float) pixman_fixed_to_double(from->matrix[0][0]);
61135c4bbdfSmrg    to[0][1] = (float) pixman_fixed_to_double(from->matrix[0][1])
61235c4bbdfSmrg        * (normalize ? (((float) height) / ((float) width)) : 1.0);
61335c4bbdfSmrg    to[0][2] = (float) pixman_fixed_to_double(from->matrix[0][2])
61435c4bbdfSmrg        / (normalize ? ((float) width) : 1.0);
61535c4bbdfSmrg
61635c4bbdfSmrg    to[1][0] = (float) pixman_fixed_to_double(from->matrix[1][0])
61735c4bbdfSmrg        * (normalize ? (((float) width) / ((float) height)) : 1.0);
61835c4bbdfSmrg    to[1][1] = (float) pixman_fixed_to_double(from->matrix[1][1]);
61935c4bbdfSmrg    to[1][2] = (float) pixman_fixed_to_double(from->matrix[1][2])
62035c4bbdfSmrg        / (normalize ? ((float) height) : 1.0);
62135c4bbdfSmrg
62235c4bbdfSmrg    to[2][0] = (float) pixman_fixed_to_double(from->matrix[2][0])
62335c4bbdfSmrg        * (normalize ? ((float) width) : 1.0);
62435c4bbdfSmrg    to[2][1] = (float) pixman_fixed_to_double(from->matrix[2][1])
62535c4bbdfSmrg        * (normalize ? ((float) height) : 1.0);
62635c4bbdfSmrg    to[2][2] = (float) pixman_fixed_to_double(from->matrix[2][2]);
62735c4bbdfSmrg
62835c4bbdfSmrg    DEBUGF("the transform matrix is:\n%f\t%f\t%f\n%f\t%f\t%f\n%f\t%f\t%f\n",
62935c4bbdfSmrg           to[0][0], to[0][1], to[0][2],
63035c4bbdfSmrg           to[1][0], to[1][1], to[1][2], to[2][0], to[2][1], to[2][2]);
63135c4bbdfSmrg}
63235c4bbdfSmrg
63335c4bbdfSmrgstatic int
63435c4bbdfSmrg_glamor_gradient_set_pixmap_destination(ScreenPtr screen,
63535c4bbdfSmrg                                        glamor_screen_private *glamor_priv,
63635c4bbdfSmrg                                        PicturePtr dst_picture,
63735c4bbdfSmrg                                        GLfloat *xscale, GLfloat *yscale,
63835c4bbdfSmrg                                        int x_source, int y_source,
63935c4bbdfSmrg                                        int tex_normalize)
64035c4bbdfSmrg{
64135c4bbdfSmrg    glamor_pixmap_private *pixmap_priv;
64235c4bbdfSmrg    PixmapPtr pixmap = NULL;
64335c4bbdfSmrg    GLfloat *v;
64435c4bbdfSmrg    char *vbo_offset;
64535c4bbdfSmrg
64635c4bbdfSmrg    pixmap = glamor_get_drawable_pixmap(dst_picture->pDrawable);
64735c4bbdfSmrg    pixmap_priv = glamor_get_pixmap_private(pixmap);
64835c4bbdfSmrg
64935c4bbdfSmrg    if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {     /* should always have here. */
65035c4bbdfSmrg        return 0;
65135c4bbdfSmrg    }
65235c4bbdfSmrg
65335c4bbdfSmrg    glamor_set_destination_pixmap_priv_nc(glamor_priv, pixmap, pixmap_priv);
65435c4bbdfSmrg
65535c4bbdfSmrg    pixmap_priv_get_dest_scale(pixmap, pixmap_priv, xscale, yscale);
65635c4bbdfSmrg
65735c4bbdfSmrg    DEBUGF("xscale = %f, yscale = %f,"
65835c4bbdfSmrg           " x_source = %d, y_source = %d, width = %d, height = %d\n",
65935c4bbdfSmrg           *xscale, *yscale, x_source, y_source,
66035c4bbdfSmrg           dst_picture->pDrawable->width, dst_picture->pDrawable->height);
66135c4bbdfSmrg
66235c4bbdfSmrg    v = glamor_get_vbo_space(screen, 16 * sizeof(GLfloat), &vbo_offset);
66335c4bbdfSmrg
66435c4bbdfSmrg    glamor_set_normalize_vcoords_tri_strip(*xscale, *yscale,
66535c4bbdfSmrg                                           0, 0,
66635c4bbdfSmrg                                           (INT16) (dst_picture->pDrawable->
66735c4bbdfSmrg                                                    width),
66835c4bbdfSmrg                                           (INT16) (dst_picture->pDrawable->
66935c4bbdfSmrg                                                    height),
67035c4bbdfSmrg                                           v);
67135c4bbdfSmrg
67235c4bbdfSmrg    if (tex_normalize) {
67335c4bbdfSmrg        glamor_set_normalize_tcoords_tri_stripe(*xscale, *yscale,
67435c4bbdfSmrg                                                x_source, y_source,
67535c4bbdfSmrg                                                (INT16) (dst_picture->
67635c4bbdfSmrg                                                         pDrawable->width +
67735c4bbdfSmrg                                                         x_source),
67835c4bbdfSmrg                                                (INT16) (dst_picture->
67935c4bbdfSmrg                                                         pDrawable->height +
68035c4bbdfSmrg                                                         y_source),
68135c4bbdfSmrg                                                &v[8]);
68235c4bbdfSmrg    }
68335c4bbdfSmrg    else {
68435c4bbdfSmrg        glamor_set_tcoords_tri_strip(x_source, y_source,
68535c4bbdfSmrg                                     (INT16) (dst_picture->pDrawable->width) +
68635c4bbdfSmrg                                     x_source,
68735c4bbdfSmrg                                     (INT16) (dst_picture->pDrawable->height) +
68835c4bbdfSmrg                                     y_source,
68935c4bbdfSmrg                                     &v[8]);
69035c4bbdfSmrg    }
69135c4bbdfSmrg
69235c4bbdfSmrg    DEBUGF("vertices --> leftup : %f X %f, rightup: %f X %f,"
69335c4bbdfSmrg           "rightbottom: %f X %f, leftbottom : %f X %f\n",
69435c4bbdfSmrg           v[0], v[1], v[2], v[3],
69535c4bbdfSmrg           v[4], v[5], v[6], v[7]);
69635c4bbdfSmrg    DEBUGF("tex_vertices --> leftup : %f X %f, rightup: %f X %f,"
69735c4bbdfSmrg           "rightbottom: %f X %f, leftbottom : %f X %f\n",
69835c4bbdfSmrg           v[8], v[9], v[10], v[11],
69935c4bbdfSmrg           v[12], v[13], v[14], v[15]);
70035c4bbdfSmrg
70135c4bbdfSmrg    glamor_make_current(glamor_priv);
70235c4bbdfSmrg
70335c4bbdfSmrg    glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
70435c4bbdfSmrg                          GL_FALSE, 0, vbo_offset);
70535c4bbdfSmrg    glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
70635c4bbdfSmrg                          GL_FALSE, 0, vbo_offset + 8 * sizeof(GLfloat));
70735c4bbdfSmrg
70835c4bbdfSmrg    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
70935c4bbdfSmrg    glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
71035c4bbdfSmrg
71135c4bbdfSmrg    glamor_put_vbo_space(screen);
71235c4bbdfSmrg    return 1;
71335c4bbdfSmrg}
71435c4bbdfSmrg
71535c4bbdfSmrgstatic int
71635c4bbdfSmrg_glamor_gradient_set_stops(PicturePtr src_picture, PictGradient *pgradient,
71735c4bbdfSmrg                           GLfloat *stop_colors, GLfloat *n_stops)
71835c4bbdfSmrg{
71935c4bbdfSmrg    int i;
72035c4bbdfSmrg    int count = 1;
72135c4bbdfSmrg
72235c4bbdfSmrg    for (i = 0; i < pgradient->nstops; i++) {
72335c4bbdfSmrg        stop_colors[count * 4] =
72435c4bbdfSmrg            pixman_fixed_to_double(pgradient->stops[i].color.red);
72535c4bbdfSmrg        stop_colors[count * 4 + 1] =
72635c4bbdfSmrg            pixman_fixed_to_double(pgradient->stops[i].color.green);
72735c4bbdfSmrg        stop_colors[count * 4 + 2] =
72835c4bbdfSmrg            pixman_fixed_to_double(pgradient->stops[i].color.blue);
72935c4bbdfSmrg        stop_colors[count * 4 + 3] =
73035c4bbdfSmrg            pixman_fixed_to_double(pgradient->stops[i].color.alpha);
73135c4bbdfSmrg
73235c4bbdfSmrg        n_stops[count] =
73335c4bbdfSmrg            (GLfloat) pixman_fixed_to_double(pgradient->stops[i].x);
73435c4bbdfSmrg        count++;
73535c4bbdfSmrg    }
73635c4bbdfSmrg
73735c4bbdfSmrg    /* for the end stop. */
73835c4bbdfSmrg    count++;
73935c4bbdfSmrg
74035c4bbdfSmrg    switch (src_picture->repeatType) {
74135c4bbdfSmrg#define REPEAT_FILL_STOPS(m, n) \
74235c4bbdfSmrg			stop_colors[(m)*4 + 0] = stop_colors[(n)*4 + 0]; \
74335c4bbdfSmrg			stop_colors[(m)*4 + 1] = stop_colors[(n)*4 + 1]; \
74435c4bbdfSmrg			stop_colors[(m)*4 + 2] = stop_colors[(n)*4 + 2]; \
74535c4bbdfSmrg			stop_colors[(m)*4 + 3] = stop_colors[(n)*4 + 3];
74635c4bbdfSmrg
74735c4bbdfSmrg    default:
74835c4bbdfSmrg    case PIXMAN_REPEAT_NONE:
74935c4bbdfSmrg        stop_colors[0] = 0.0;   //R
75035c4bbdfSmrg        stop_colors[1] = 0.0;   //G
75135c4bbdfSmrg        stop_colors[2] = 0.0;   //B
75235c4bbdfSmrg        stop_colors[3] = 0.0;   //Alpha
7531b5d61b8Smrg        n_stops[0] = n_stops[1];
75435c4bbdfSmrg
75535c4bbdfSmrg        stop_colors[0 + (count - 1) * 4] = 0.0; //R
75635c4bbdfSmrg        stop_colors[1 + (count - 1) * 4] = 0.0; //G
75735c4bbdfSmrg        stop_colors[2 + (count - 1) * 4] = 0.0; //B
75835c4bbdfSmrg        stop_colors[3 + (count - 1) * 4] = 0.0; //Alpha
7591b5d61b8Smrg        n_stops[count - 1] = n_stops[count - 2];
76035c4bbdfSmrg        break;
76135c4bbdfSmrg    case PIXMAN_REPEAT_NORMAL:
76235c4bbdfSmrg        REPEAT_FILL_STOPS(0, count - 2);
76335c4bbdfSmrg        n_stops[0] = n_stops[count - 2] - 1.0;
76435c4bbdfSmrg
76535c4bbdfSmrg        REPEAT_FILL_STOPS(count - 1, 1);
76635c4bbdfSmrg        n_stops[count - 1] = n_stops[1] + 1.0;
76735c4bbdfSmrg        break;
76835c4bbdfSmrg    case PIXMAN_REPEAT_REFLECT:
76935c4bbdfSmrg        REPEAT_FILL_STOPS(0, 1);
77035c4bbdfSmrg        n_stops[0] = -n_stops[1];
77135c4bbdfSmrg
77235c4bbdfSmrg        REPEAT_FILL_STOPS(count - 1, count - 2);
77335c4bbdfSmrg        n_stops[count - 1] = 1.0 + 1.0 - n_stops[count - 2];
77435c4bbdfSmrg        break;
77535c4bbdfSmrg    case PIXMAN_REPEAT_PAD:
77635c4bbdfSmrg        REPEAT_FILL_STOPS(0, 1);
77735c4bbdfSmrg        n_stops[0] = -(float) INT_MAX;
77835c4bbdfSmrg
77935c4bbdfSmrg        REPEAT_FILL_STOPS(count - 1, count - 2);
78035c4bbdfSmrg        n_stops[count - 1] = (float) INT_MAX;
78135c4bbdfSmrg        break;
78235c4bbdfSmrg#undef REPEAT_FILL_STOPS
78335c4bbdfSmrg    }
78435c4bbdfSmrg
78535c4bbdfSmrg    for (i = 0; i < count; i++) {
78635c4bbdfSmrg        DEBUGF("n_stops[%d] = %f, color = r:%f g:%f b:%f a:%f\n",
78735c4bbdfSmrg               i, n_stops[i],
78835c4bbdfSmrg               stop_colors[i * 4], stop_colors[i * 4 + 1],
78935c4bbdfSmrg               stop_colors[i * 4 + 2], stop_colors[i * 4 + 3]);
79035c4bbdfSmrg    }
79135c4bbdfSmrg
79235c4bbdfSmrg    return count;
79335c4bbdfSmrg}
79435c4bbdfSmrg
79535c4bbdfSmrgPicturePtr
79635c4bbdfSmrgglamor_generate_radial_gradient_picture(ScreenPtr screen,
79735c4bbdfSmrg                                        PicturePtr src_picture,
79835c4bbdfSmrg                                        int x_source, int y_source,
79935c4bbdfSmrg                                        int width, int height,
80035c4bbdfSmrg                                        PictFormatShort format)
80135c4bbdfSmrg{
80235c4bbdfSmrg    glamor_screen_private *glamor_priv;
80335c4bbdfSmrg    PicturePtr dst_picture = NULL;
80435c4bbdfSmrg    PixmapPtr pixmap = NULL;
80535c4bbdfSmrg    GLint gradient_prog = 0;
80635c4bbdfSmrg    int error;
80735c4bbdfSmrg    int stops_count = 0;
80835c4bbdfSmrg    int count = 0;
80935c4bbdfSmrg    GLfloat *stop_colors = NULL;
81035c4bbdfSmrg    GLfloat *n_stops = NULL;
81135c4bbdfSmrg    GLfloat xscale, yscale;
81235c4bbdfSmrg    float transform_mat[3][3];
81335c4bbdfSmrg    static const float identity_mat[3][3] = { {1.0, 0.0, 0.0},
81435c4bbdfSmrg    {0.0, 1.0, 0.0},
81535c4bbdfSmrg    {0.0, 0.0, 1.0}
81635c4bbdfSmrg    };
81735c4bbdfSmrg    GLfloat stop_colors_st[RADIAL_SMALL_STOPS * 4];
81835c4bbdfSmrg    GLfloat n_stops_st[RADIAL_SMALL_STOPS];
81935c4bbdfSmrg    GLfloat A_value;
82035c4bbdfSmrg    GLfloat cxy[4];
82135c4bbdfSmrg    float c1x, c1y, c2x, c2y, r1, r2;
82235c4bbdfSmrg
82335c4bbdfSmrg    GLint transform_mat_uniform_location = 0;
82435c4bbdfSmrg    GLint repeat_type_uniform_location = 0;
82535c4bbdfSmrg    GLint n_stop_uniform_location = 0;
82635c4bbdfSmrg    GLint stops_uniform_location = 0;
82735c4bbdfSmrg    GLint stop_colors_uniform_location = 0;
82835c4bbdfSmrg    GLint stop0_uniform_location = 0;
82935c4bbdfSmrg    GLint stop1_uniform_location = 0;
83035c4bbdfSmrg    GLint stop2_uniform_location = 0;
83135c4bbdfSmrg    GLint stop3_uniform_location = 0;
83235c4bbdfSmrg    GLint stop4_uniform_location = 0;
83335c4bbdfSmrg    GLint stop5_uniform_location = 0;
83435c4bbdfSmrg    GLint stop6_uniform_location = 0;
83535c4bbdfSmrg    GLint stop7_uniform_location = 0;
83635c4bbdfSmrg    GLint stop_color0_uniform_location = 0;
83735c4bbdfSmrg    GLint stop_color1_uniform_location = 0;
83835c4bbdfSmrg    GLint stop_color2_uniform_location = 0;
83935c4bbdfSmrg    GLint stop_color3_uniform_location = 0;
84035c4bbdfSmrg    GLint stop_color4_uniform_location = 0;
84135c4bbdfSmrg    GLint stop_color5_uniform_location = 0;
84235c4bbdfSmrg    GLint stop_color6_uniform_location = 0;
84335c4bbdfSmrg    GLint stop_color7_uniform_location = 0;
84435c4bbdfSmrg    GLint A_value_uniform_location = 0;
84535c4bbdfSmrg    GLint c1_uniform_location = 0;
84635c4bbdfSmrg    GLint r1_uniform_location = 0;
84735c4bbdfSmrg    GLint c2_uniform_location = 0;
84835c4bbdfSmrg    GLint r2_uniform_location = 0;
84935c4bbdfSmrg
85035c4bbdfSmrg    glamor_priv = glamor_get_screen_private(screen);
85135c4bbdfSmrg    glamor_make_current(glamor_priv);
85235c4bbdfSmrg
85335c4bbdfSmrg    /* Create a pixmap with VBO. */
85435c4bbdfSmrg    pixmap = glamor_create_pixmap(screen,
85535c4bbdfSmrg                                  width, height,
85635c4bbdfSmrg                                  PIXMAN_FORMAT_DEPTH(format), 0);
85735c4bbdfSmrg    if (!pixmap)
85835c4bbdfSmrg        goto GRADIENT_FAIL;
85935c4bbdfSmrg
86035c4bbdfSmrg    dst_picture = CreatePicture(0, &pixmap->drawable,
86135c4bbdfSmrg                                PictureMatchFormat(screen,
86235c4bbdfSmrg                                                   PIXMAN_FORMAT_DEPTH(format),
86335c4bbdfSmrg                                                   format), 0, 0, serverClient,
86435c4bbdfSmrg                                &error);
86535c4bbdfSmrg
86635c4bbdfSmrg    /* Release the reference, picture will hold the last one. */
86735c4bbdfSmrg    glamor_destroy_pixmap(pixmap);
86835c4bbdfSmrg
86935c4bbdfSmrg    if (!dst_picture)
87035c4bbdfSmrg        goto GRADIENT_FAIL;
87135c4bbdfSmrg
87235c4bbdfSmrg    ValidatePicture(dst_picture);
87335c4bbdfSmrg
87435c4bbdfSmrg    stops_count = src_picture->pSourcePict->radial.nstops + 2;
87535c4bbdfSmrg
8761b5d61b8Smrg    /* Because the max value of nstops is unknown, so create a program
87735c4bbdfSmrg       when nstops > LINEAR_LARGE_STOPS. */
87835c4bbdfSmrg    if (stops_count <= RADIAL_SMALL_STOPS) {
87935c4bbdfSmrg        gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][0];
88035c4bbdfSmrg    }
88135c4bbdfSmrg    else if (stops_count <= RADIAL_LARGE_STOPS) {
88235c4bbdfSmrg        gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][1];
88335c4bbdfSmrg    }
88435c4bbdfSmrg    else {
88535c4bbdfSmrg        _glamor_create_radial_gradient_program(screen,
88635c4bbdfSmrg                                               src_picture->pSourcePict->linear.
88735c4bbdfSmrg                                               nstops + 2, 1);
88835c4bbdfSmrg        gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2];
88935c4bbdfSmrg    }
89035c4bbdfSmrg
89135c4bbdfSmrg    /* Bind all the uniform vars . */
89235c4bbdfSmrg    transform_mat_uniform_location = glGetUniformLocation(gradient_prog,
89335c4bbdfSmrg                                                          "transform_mat");
89435c4bbdfSmrg    repeat_type_uniform_location = glGetUniformLocation(gradient_prog,
89535c4bbdfSmrg                                                        "repeat_type");
89635c4bbdfSmrg    n_stop_uniform_location = glGetUniformLocation(gradient_prog, "n_stop");
89735c4bbdfSmrg    A_value_uniform_location = glGetUniformLocation(gradient_prog, "A_value");
89835c4bbdfSmrg    c1_uniform_location = glGetUniformLocation(gradient_prog, "c1");
89935c4bbdfSmrg    r1_uniform_location = glGetUniformLocation(gradient_prog, "r1");
90035c4bbdfSmrg    c2_uniform_location = glGetUniformLocation(gradient_prog, "c2");
90135c4bbdfSmrg    r2_uniform_location = glGetUniformLocation(gradient_prog, "r2");
90235c4bbdfSmrg
90335c4bbdfSmrg    if (src_picture->pSourcePict->radial.nstops + 2 <= RADIAL_SMALL_STOPS) {
90435c4bbdfSmrg        stop0_uniform_location =
90535c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop0");
90635c4bbdfSmrg        stop1_uniform_location =
90735c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop1");
90835c4bbdfSmrg        stop2_uniform_location =
90935c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop2");
91035c4bbdfSmrg        stop3_uniform_location =
91135c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop3");
91235c4bbdfSmrg        stop4_uniform_location =
91335c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop4");
91435c4bbdfSmrg        stop5_uniform_location =
91535c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop5");
91635c4bbdfSmrg        stop6_uniform_location =
91735c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop6");
91835c4bbdfSmrg        stop7_uniform_location =
91935c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop7");
92035c4bbdfSmrg
92135c4bbdfSmrg        stop_color0_uniform_location =
92235c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color0");
92335c4bbdfSmrg        stop_color1_uniform_location =
92435c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color1");
92535c4bbdfSmrg        stop_color2_uniform_location =
92635c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color2");
92735c4bbdfSmrg        stop_color3_uniform_location =
92835c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color3");
92935c4bbdfSmrg        stop_color4_uniform_location =
93035c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color4");
93135c4bbdfSmrg        stop_color5_uniform_location =
93235c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color5");
93335c4bbdfSmrg        stop_color6_uniform_location =
93435c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color6");
93535c4bbdfSmrg        stop_color7_uniform_location =
93635c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color7");
93735c4bbdfSmrg    }
93835c4bbdfSmrg    else {
93935c4bbdfSmrg        stops_uniform_location =
94035c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stops");
94135c4bbdfSmrg        stop_colors_uniform_location =
94235c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_colors");
94335c4bbdfSmrg    }
94435c4bbdfSmrg
94535c4bbdfSmrg    glUseProgram(gradient_prog);
94635c4bbdfSmrg
94735c4bbdfSmrg    glUniform1i(repeat_type_uniform_location, src_picture->repeatType);
94835c4bbdfSmrg
94935c4bbdfSmrg    if (src_picture->transform) {
95035c4bbdfSmrg        _glamor_gradient_convert_trans_matrix(src_picture->transform,
95135c4bbdfSmrg                                              transform_mat, width, height, 0);
95235c4bbdfSmrg        glUniformMatrix3fv(transform_mat_uniform_location,
95335c4bbdfSmrg                           1, 1, &transform_mat[0][0]);
95435c4bbdfSmrg    }
95535c4bbdfSmrg    else {
95635c4bbdfSmrg        glUniformMatrix3fv(transform_mat_uniform_location,
95735c4bbdfSmrg                           1, 1, &identity_mat[0][0]);
95835c4bbdfSmrg    }
95935c4bbdfSmrg
96035c4bbdfSmrg    if (!_glamor_gradient_set_pixmap_destination
96135c4bbdfSmrg        (screen, glamor_priv, dst_picture, &xscale, &yscale, x_source, y_source,
96235c4bbdfSmrg         0))
96335c4bbdfSmrg        goto GRADIENT_FAIL;
96435c4bbdfSmrg
96535c4bbdfSmrg    glamor_set_alu(screen, GXcopy);
96635c4bbdfSmrg
96735c4bbdfSmrg    /* Set all the stops and colors to shader. */
96835c4bbdfSmrg    if (stops_count > RADIAL_SMALL_STOPS) {
96935c4bbdfSmrg        stop_colors = xallocarray(stops_count, 4 * sizeof(float));
97035c4bbdfSmrg        if (stop_colors == NULL) {
97135c4bbdfSmrg            ErrorF("Failed to allocate stop_colors memory.\n");
97235c4bbdfSmrg            goto GRADIENT_FAIL;
97335c4bbdfSmrg        }
97435c4bbdfSmrg
97535c4bbdfSmrg        n_stops = xallocarray(stops_count, sizeof(float));
97635c4bbdfSmrg        if (n_stops == NULL) {
97735c4bbdfSmrg            ErrorF("Failed to allocate n_stops memory.\n");
97835c4bbdfSmrg            goto GRADIENT_FAIL;
97935c4bbdfSmrg        }
98035c4bbdfSmrg    }
98135c4bbdfSmrg    else {
98235c4bbdfSmrg        stop_colors = stop_colors_st;
98335c4bbdfSmrg        n_stops = n_stops_st;
98435c4bbdfSmrg    }
98535c4bbdfSmrg
98635c4bbdfSmrg    count =
98735c4bbdfSmrg        _glamor_gradient_set_stops(src_picture,
98835c4bbdfSmrg                                   &src_picture->pSourcePict->gradient,
98935c4bbdfSmrg                                   stop_colors, n_stops);
99035c4bbdfSmrg
99135c4bbdfSmrg    if (src_picture->pSourcePict->linear.nstops + 2 <= RADIAL_SMALL_STOPS) {
99235c4bbdfSmrg        int j = 0;
99335c4bbdfSmrg
99435c4bbdfSmrg        glUniform4f(stop_color0_uniform_location,
99535c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
99635c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
99735c4bbdfSmrg        j++;
99835c4bbdfSmrg        glUniform4f(stop_color1_uniform_location,
99935c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
100035c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
100135c4bbdfSmrg        j++;
100235c4bbdfSmrg        glUniform4f(stop_color2_uniform_location,
100335c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
100435c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
100535c4bbdfSmrg        j++;
100635c4bbdfSmrg        glUniform4f(stop_color3_uniform_location,
100735c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
100835c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
100935c4bbdfSmrg        j++;
101035c4bbdfSmrg        glUniform4f(stop_color4_uniform_location,
101135c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
101235c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
101335c4bbdfSmrg        j++;
101435c4bbdfSmrg        glUniform4f(stop_color5_uniform_location,
101535c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
101635c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
101735c4bbdfSmrg        j++;
101835c4bbdfSmrg        glUniform4f(stop_color6_uniform_location,
101935c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
102035c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
102135c4bbdfSmrg        j++;
102235c4bbdfSmrg        glUniform4f(stop_color7_uniform_location,
102335c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
102435c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
102535c4bbdfSmrg
102635c4bbdfSmrg        j = 0;
102735c4bbdfSmrg        glUniform1f(stop0_uniform_location, n_stops[j++]);
102835c4bbdfSmrg        glUniform1f(stop1_uniform_location, n_stops[j++]);
102935c4bbdfSmrg        glUniform1f(stop2_uniform_location, n_stops[j++]);
103035c4bbdfSmrg        glUniform1f(stop3_uniform_location, n_stops[j++]);
103135c4bbdfSmrg        glUniform1f(stop4_uniform_location, n_stops[j++]);
103235c4bbdfSmrg        glUniform1f(stop5_uniform_location, n_stops[j++]);
103335c4bbdfSmrg        glUniform1f(stop6_uniform_location, n_stops[j++]);
103435c4bbdfSmrg        glUniform1f(stop7_uniform_location, n_stops[j++]);
103535c4bbdfSmrg        glUniform1i(n_stop_uniform_location, count);
103635c4bbdfSmrg    }
103735c4bbdfSmrg    else {
103835c4bbdfSmrg        glUniform4fv(stop_colors_uniform_location, count, stop_colors);
103935c4bbdfSmrg        glUniform1fv(stops_uniform_location, count, n_stops);
104035c4bbdfSmrg        glUniform1i(n_stop_uniform_location, count);
104135c4bbdfSmrg    }
104235c4bbdfSmrg
104335c4bbdfSmrg    c1x = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.x);
104435c4bbdfSmrg    c1y = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.y);
104535c4bbdfSmrg    c2x = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.x);
104635c4bbdfSmrg    c2y = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.y);
104735c4bbdfSmrg
104835c4bbdfSmrg    r1 = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.
104935c4bbdfSmrg                                        radius);
105035c4bbdfSmrg    r2 = (float) pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.
105135c4bbdfSmrg                                        radius);
105235c4bbdfSmrg
105335c4bbdfSmrg    glamor_set_circle_centre(width, height, c1x, c1y, cxy);
105435c4bbdfSmrg    glUniform2fv(c1_uniform_location, 1, cxy);
105535c4bbdfSmrg    glUniform1f(r1_uniform_location, r1);
105635c4bbdfSmrg
105735c4bbdfSmrg    glamor_set_circle_centre(width, height, c2x, c2y, cxy);
105835c4bbdfSmrg    glUniform2fv(c2_uniform_location, 1, cxy);
105935c4bbdfSmrg    glUniform1f(r2_uniform_location, r2);
106035c4bbdfSmrg
106135c4bbdfSmrg    A_value =
106235c4bbdfSmrg        (c2x - c1x) * (c2x - c1x) + (c2y - c1y) * (c2y - c1y) - (r2 -
106335c4bbdfSmrg                                                                 r1) * (r2 -
106435c4bbdfSmrg                                                                        r1);
106535c4bbdfSmrg    glUniform1f(A_value_uniform_location, A_value);
106635c4bbdfSmrg
106735c4bbdfSmrg    DEBUGF("C1:(%f, %f) R1:%f\nC2:(%f, %f) R2:%f\nA = %f\n",
106835c4bbdfSmrg           c1x, c1y, r1, c2x, c2y, r2, A_value);
106935c4bbdfSmrg
107035c4bbdfSmrg    /* Now rendering. */
107135c4bbdfSmrg    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
107235c4bbdfSmrg
107335c4bbdfSmrg    /* Do the clear logic. */
107435c4bbdfSmrg    if (stops_count > RADIAL_SMALL_STOPS) {
107535c4bbdfSmrg        free(n_stops);
107635c4bbdfSmrg        free(stop_colors);
107735c4bbdfSmrg    }
107835c4bbdfSmrg
107935c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
108035c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
108135c4bbdfSmrg
108235c4bbdfSmrg    return dst_picture;
108335c4bbdfSmrg
108435c4bbdfSmrg GRADIENT_FAIL:
108535c4bbdfSmrg    if (dst_picture) {
108635c4bbdfSmrg        FreePicture(dst_picture, 0);
108735c4bbdfSmrg    }
108835c4bbdfSmrg
108935c4bbdfSmrg    if (stops_count > RADIAL_SMALL_STOPS) {
109035c4bbdfSmrg        if (n_stops)
109135c4bbdfSmrg            free(n_stops);
109235c4bbdfSmrg        if (stop_colors)
109335c4bbdfSmrg            free(stop_colors);
109435c4bbdfSmrg    }
109535c4bbdfSmrg
109635c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
109735c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
109835c4bbdfSmrg    return NULL;
109935c4bbdfSmrg}
110035c4bbdfSmrg
110135c4bbdfSmrgPicturePtr
110235c4bbdfSmrgglamor_generate_linear_gradient_picture(ScreenPtr screen,
110335c4bbdfSmrg                                        PicturePtr src_picture,
110435c4bbdfSmrg                                        int x_source, int y_source,
110535c4bbdfSmrg                                        int width, int height,
110635c4bbdfSmrg                                        PictFormatShort format)
110735c4bbdfSmrg{
110835c4bbdfSmrg    glamor_screen_private *glamor_priv;
110935c4bbdfSmrg    PicturePtr dst_picture = NULL;
111035c4bbdfSmrg    PixmapPtr pixmap = NULL;
111135c4bbdfSmrg    GLint gradient_prog = 0;
111235c4bbdfSmrg    int error;
111335c4bbdfSmrg    float pt_distance;
111435c4bbdfSmrg    float p1_distance;
111535c4bbdfSmrg    GLfloat cos_val;
111635c4bbdfSmrg    int stops_count = 0;
111735c4bbdfSmrg    GLfloat *stop_colors = NULL;
111835c4bbdfSmrg    GLfloat *n_stops = NULL;
111935c4bbdfSmrg    int count = 0;
112035c4bbdfSmrg    float slope;
112135c4bbdfSmrg    GLfloat xscale, yscale;
112235c4bbdfSmrg    GLfloat pt1[2], pt2[2];
112335c4bbdfSmrg    float transform_mat[3][3];
112435c4bbdfSmrg    static const float identity_mat[3][3] = { {1.0, 0.0, 0.0},
112535c4bbdfSmrg    {0.0, 1.0, 0.0},
112635c4bbdfSmrg    {0.0, 0.0, 1.0}
112735c4bbdfSmrg    };
112835c4bbdfSmrg    GLfloat stop_colors_st[LINEAR_SMALL_STOPS * 4];
112935c4bbdfSmrg    GLfloat n_stops_st[LINEAR_SMALL_STOPS];
113035c4bbdfSmrg
113135c4bbdfSmrg    GLint transform_mat_uniform_location = 0;
113235c4bbdfSmrg    GLint n_stop_uniform_location = 0;
113335c4bbdfSmrg    GLint stops_uniform_location = 0;
113435c4bbdfSmrg    GLint stop0_uniform_location = 0;
113535c4bbdfSmrg    GLint stop1_uniform_location = 0;
113635c4bbdfSmrg    GLint stop2_uniform_location = 0;
113735c4bbdfSmrg    GLint stop3_uniform_location = 0;
113835c4bbdfSmrg    GLint stop4_uniform_location = 0;
113935c4bbdfSmrg    GLint stop5_uniform_location = 0;
114035c4bbdfSmrg    GLint stop6_uniform_location = 0;
114135c4bbdfSmrg    GLint stop7_uniform_location = 0;
114235c4bbdfSmrg    GLint stop_colors_uniform_location = 0;
114335c4bbdfSmrg    GLint stop_color0_uniform_location = 0;
114435c4bbdfSmrg    GLint stop_color1_uniform_location = 0;
114535c4bbdfSmrg    GLint stop_color2_uniform_location = 0;
114635c4bbdfSmrg    GLint stop_color3_uniform_location = 0;
114735c4bbdfSmrg    GLint stop_color4_uniform_location = 0;
114835c4bbdfSmrg    GLint stop_color5_uniform_location = 0;
114935c4bbdfSmrg    GLint stop_color6_uniform_location = 0;
115035c4bbdfSmrg    GLint stop_color7_uniform_location = 0;
115135c4bbdfSmrg    GLint pt_slope_uniform_location = 0;
115235c4bbdfSmrg    GLint repeat_type_uniform_location = 0;
115335c4bbdfSmrg    GLint hor_ver_uniform_location = 0;
115435c4bbdfSmrg    GLint cos_val_uniform_location = 0;
115535c4bbdfSmrg    GLint p1_distance_uniform_location = 0;
115635c4bbdfSmrg    GLint pt_distance_uniform_location = 0;
115735c4bbdfSmrg
115835c4bbdfSmrg    glamor_priv = glamor_get_screen_private(screen);
115935c4bbdfSmrg    glamor_make_current(glamor_priv);
116035c4bbdfSmrg
116135c4bbdfSmrg    /* Create a pixmap with VBO. */
116235c4bbdfSmrg    pixmap = glamor_create_pixmap(screen,
116335c4bbdfSmrg                                  width, height,
116435c4bbdfSmrg                                  PIXMAN_FORMAT_DEPTH(format), 0);
116535c4bbdfSmrg
116635c4bbdfSmrg    if (!pixmap)
116735c4bbdfSmrg        goto GRADIENT_FAIL;
116835c4bbdfSmrg
116935c4bbdfSmrg    dst_picture = CreatePicture(0, &pixmap->drawable,
117035c4bbdfSmrg                                PictureMatchFormat(screen,
117135c4bbdfSmrg                                                   PIXMAN_FORMAT_DEPTH(format),
117235c4bbdfSmrg                                                   format), 0, 0, serverClient,
117335c4bbdfSmrg                                &error);
117435c4bbdfSmrg
117535c4bbdfSmrg    /* Release the reference, picture will hold the last one. */
117635c4bbdfSmrg    glamor_destroy_pixmap(pixmap);
117735c4bbdfSmrg
117835c4bbdfSmrg    if (!dst_picture)
117935c4bbdfSmrg        goto GRADIENT_FAIL;
118035c4bbdfSmrg
118135c4bbdfSmrg    ValidatePicture(dst_picture);
118235c4bbdfSmrg
118335c4bbdfSmrg    stops_count = src_picture->pSourcePict->linear.nstops + 2;
118435c4bbdfSmrg
11851b5d61b8Smrg    /* Because the max value of nstops is unknown, so create a program
118635c4bbdfSmrg       when nstops > LINEAR_LARGE_STOPS. */
118735c4bbdfSmrg    if (stops_count <= LINEAR_SMALL_STOPS) {
118835c4bbdfSmrg        gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][0];
118935c4bbdfSmrg    }
119035c4bbdfSmrg    else if (stops_count <= LINEAR_LARGE_STOPS) {
119135c4bbdfSmrg        gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][1];
119235c4bbdfSmrg    }
119335c4bbdfSmrg    else {
119435c4bbdfSmrg        _glamor_create_linear_gradient_program(screen,
119535c4bbdfSmrg                                               src_picture->pSourcePict->linear.
119635c4bbdfSmrg                                               nstops + 2, 1);
119735c4bbdfSmrg        gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2];
119835c4bbdfSmrg    }
119935c4bbdfSmrg
120035c4bbdfSmrg    /* Bind all the uniform vars . */
120135c4bbdfSmrg    n_stop_uniform_location =
120235c4bbdfSmrg        glGetUniformLocation(gradient_prog, "n_stop");
120335c4bbdfSmrg    pt_slope_uniform_location =
120435c4bbdfSmrg        glGetUniformLocation(gradient_prog, "pt_slope");
120535c4bbdfSmrg    repeat_type_uniform_location =
120635c4bbdfSmrg        glGetUniformLocation(gradient_prog, "repeat_type");
120735c4bbdfSmrg    hor_ver_uniform_location =
120835c4bbdfSmrg        glGetUniformLocation(gradient_prog, "hor_ver");
120935c4bbdfSmrg    transform_mat_uniform_location =
121035c4bbdfSmrg        glGetUniformLocation(gradient_prog, "transform_mat");
121135c4bbdfSmrg    cos_val_uniform_location =
121235c4bbdfSmrg        glGetUniformLocation(gradient_prog, "cos_val");
121335c4bbdfSmrg    p1_distance_uniform_location =
121435c4bbdfSmrg        glGetUniformLocation(gradient_prog, "p1_distance");
121535c4bbdfSmrg    pt_distance_uniform_location =
121635c4bbdfSmrg        glGetUniformLocation(gradient_prog, "pt_distance");
121735c4bbdfSmrg
121835c4bbdfSmrg    if (src_picture->pSourcePict->linear.nstops + 2 <= LINEAR_SMALL_STOPS) {
121935c4bbdfSmrg        stop0_uniform_location =
122035c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop0");
122135c4bbdfSmrg        stop1_uniform_location =
122235c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop1");
122335c4bbdfSmrg        stop2_uniform_location =
122435c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop2");
122535c4bbdfSmrg        stop3_uniform_location =
122635c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop3");
122735c4bbdfSmrg        stop4_uniform_location =
122835c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop4");
122935c4bbdfSmrg        stop5_uniform_location =
123035c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop5");
123135c4bbdfSmrg        stop6_uniform_location =
123235c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop6");
123335c4bbdfSmrg        stop7_uniform_location =
123435c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop7");
123535c4bbdfSmrg
123635c4bbdfSmrg        stop_color0_uniform_location =
123735c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color0");
123835c4bbdfSmrg        stop_color1_uniform_location =
123935c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color1");
124035c4bbdfSmrg        stop_color2_uniform_location =
124135c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color2");
124235c4bbdfSmrg        stop_color3_uniform_location =
124335c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color3");
124435c4bbdfSmrg        stop_color4_uniform_location =
124535c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color4");
124635c4bbdfSmrg        stop_color5_uniform_location =
124735c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color5");
124835c4bbdfSmrg        stop_color6_uniform_location =
124935c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color6");
125035c4bbdfSmrg        stop_color7_uniform_location =
125135c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_color7");
125235c4bbdfSmrg    }
125335c4bbdfSmrg    else {
125435c4bbdfSmrg        stops_uniform_location =
125535c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stops");
125635c4bbdfSmrg        stop_colors_uniform_location =
125735c4bbdfSmrg            glGetUniformLocation(gradient_prog, "stop_colors");
125835c4bbdfSmrg    }
125935c4bbdfSmrg
126035c4bbdfSmrg    glUseProgram(gradient_prog);
126135c4bbdfSmrg
126235c4bbdfSmrg    glUniform1i(repeat_type_uniform_location, src_picture->repeatType);
126335c4bbdfSmrg
126435c4bbdfSmrg    /* set the transform matrix. */
126535c4bbdfSmrg    if (src_picture->transform) {
126635c4bbdfSmrg        _glamor_gradient_convert_trans_matrix(src_picture->transform,
126735c4bbdfSmrg                                              transform_mat, width, height, 1);
126835c4bbdfSmrg        glUniformMatrix3fv(transform_mat_uniform_location,
126935c4bbdfSmrg                           1, 1, &transform_mat[0][0]);
127035c4bbdfSmrg    }
127135c4bbdfSmrg    else {
127235c4bbdfSmrg        glUniformMatrix3fv(transform_mat_uniform_location,
127335c4bbdfSmrg                           1, 1, &identity_mat[0][0]);
127435c4bbdfSmrg    }
127535c4bbdfSmrg
127635c4bbdfSmrg    if (!_glamor_gradient_set_pixmap_destination
127735c4bbdfSmrg        (screen, glamor_priv, dst_picture, &xscale, &yscale, x_source, y_source,
127835c4bbdfSmrg         1))
127935c4bbdfSmrg        goto GRADIENT_FAIL;
128035c4bbdfSmrg
128135c4bbdfSmrg    glamor_set_alu(screen, GXcopy);
128235c4bbdfSmrg
128335c4bbdfSmrg    /* Normalize the PTs. */
128435c4bbdfSmrg    glamor_set_normalize_pt(xscale, yscale,
128535c4bbdfSmrg                            pixman_fixed_to_double(src_picture->pSourcePict->
128635c4bbdfSmrg                                                   linear.p1.x),
128735c4bbdfSmrg                            pixman_fixed_to_double(src_picture->pSourcePict->
128835c4bbdfSmrg                                                   linear.p1.y),
128935c4bbdfSmrg                            pt1);
129035c4bbdfSmrg    DEBUGF("pt1:(%f, %f) ---> (%f %f)\n",
129135c4bbdfSmrg           pixman_fixed_to_double(src_picture->pSourcePict->linear.p1.x),
129235c4bbdfSmrg           pixman_fixed_to_double(src_picture->pSourcePict->linear.p1.y),
129335c4bbdfSmrg           pt1[0], pt1[1]);
129435c4bbdfSmrg
129535c4bbdfSmrg    glamor_set_normalize_pt(xscale, yscale,
129635c4bbdfSmrg                            pixman_fixed_to_double(src_picture->pSourcePict->
129735c4bbdfSmrg                                                   linear.p2.x),
129835c4bbdfSmrg                            pixman_fixed_to_double(src_picture->pSourcePict->
129935c4bbdfSmrg                                                   linear.p2.y),
130035c4bbdfSmrg                            pt2);
130135c4bbdfSmrg    DEBUGF("pt2:(%f, %f) ---> (%f %f)\n",
130235c4bbdfSmrg           pixman_fixed_to_double(src_picture->pSourcePict->linear.p2.x),
130335c4bbdfSmrg           pixman_fixed_to_double(src_picture->pSourcePict->linear.p2.y),
130435c4bbdfSmrg           pt2[0], pt2[1]);
130535c4bbdfSmrg
130635c4bbdfSmrg    /* Set all the stops and colors to shader. */
130735c4bbdfSmrg    if (stops_count > LINEAR_SMALL_STOPS) {
130835c4bbdfSmrg        stop_colors = xallocarray(stops_count, 4 * sizeof(float));
130935c4bbdfSmrg        if (stop_colors == NULL) {
131035c4bbdfSmrg            ErrorF("Failed to allocate stop_colors memory.\n");
131135c4bbdfSmrg            goto GRADIENT_FAIL;
131235c4bbdfSmrg        }
131335c4bbdfSmrg
131435c4bbdfSmrg        n_stops = xallocarray(stops_count, sizeof(float));
131535c4bbdfSmrg        if (n_stops == NULL) {
131635c4bbdfSmrg            ErrorF("Failed to allocate n_stops memory.\n");
131735c4bbdfSmrg            goto GRADIENT_FAIL;
131835c4bbdfSmrg        }
131935c4bbdfSmrg    }
132035c4bbdfSmrg    else {
132135c4bbdfSmrg        stop_colors = stop_colors_st;
132235c4bbdfSmrg        n_stops = n_stops_st;
132335c4bbdfSmrg    }
132435c4bbdfSmrg
132535c4bbdfSmrg    count =
132635c4bbdfSmrg        _glamor_gradient_set_stops(src_picture,
132735c4bbdfSmrg                                   &src_picture->pSourcePict->gradient,
132835c4bbdfSmrg                                   stop_colors, n_stops);
132935c4bbdfSmrg
133035c4bbdfSmrg    if (src_picture->pSourcePict->linear.nstops + 2 <= LINEAR_SMALL_STOPS) {
133135c4bbdfSmrg        int j = 0;
133235c4bbdfSmrg
133335c4bbdfSmrg        glUniform4f(stop_color0_uniform_location,
133435c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
133535c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
133635c4bbdfSmrg        j++;
133735c4bbdfSmrg        glUniform4f(stop_color1_uniform_location,
133835c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
133935c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
134035c4bbdfSmrg        j++;
134135c4bbdfSmrg        glUniform4f(stop_color2_uniform_location,
134235c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
134335c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
134435c4bbdfSmrg        j++;
134535c4bbdfSmrg        glUniform4f(stop_color3_uniform_location,
134635c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
134735c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
134835c4bbdfSmrg        j++;
134935c4bbdfSmrg        glUniform4f(stop_color4_uniform_location,
135035c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
135135c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
135235c4bbdfSmrg        j++;
135335c4bbdfSmrg        glUniform4f(stop_color5_uniform_location,
135435c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
135535c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
135635c4bbdfSmrg        j++;
135735c4bbdfSmrg        glUniform4f(stop_color6_uniform_location,
135835c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
135935c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
136035c4bbdfSmrg        j++;
136135c4bbdfSmrg        glUniform4f(stop_color7_uniform_location,
136235c4bbdfSmrg                    stop_colors[4 * j + 0], stop_colors[4 * j + 1],
136335c4bbdfSmrg                    stop_colors[4 * j + 2], stop_colors[4 * j + 3]);
136435c4bbdfSmrg
136535c4bbdfSmrg        j = 0;
136635c4bbdfSmrg        glUniform1f(stop0_uniform_location, n_stops[j++]);
136735c4bbdfSmrg        glUniform1f(stop1_uniform_location, n_stops[j++]);
136835c4bbdfSmrg        glUniform1f(stop2_uniform_location, n_stops[j++]);
136935c4bbdfSmrg        glUniform1f(stop3_uniform_location, n_stops[j++]);
137035c4bbdfSmrg        glUniform1f(stop4_uniform_location, n_stops[j++]);
137135c4bbdfSmrg        glUniform1f(stop5_uniform_location, n_stops[j++]);
137235c4bbdfSmrg        glUniform1f(stop6_uniform_location, n_stops[j++]);
137335c4bbdfSmrg        glUniform1f(stop7_uniform_location, n_stops[j++]);
137435c4bbdfSmrg
137535c4bbdfSmrg        glUniform1i(n_stop_uniform_location, count);
137635c4bbdfSmrg    }
137735c4bbdfSmrg    else {
137835c4bbdfSmrg        glUniform4fv(stop_colors_uniform_location, count, stop_colors);
137935c4bbdfSmrg        glUniform1fv(stops_uniform_location, count, n_stops);
138035c4bbdfSmrg        glUniform1i(n_stop_uniform_location, count);
138135c4bbdfSmrg    }
138235c4bbdfSmrg
138335c4bbdfSmrg    if (src_picture->pSourcePict->linear.p2.y == src_picture->pSourcePict->linear.p1.y) {       // The horizontal case.
138435c4bbdfSmrg        glUniform1i(hor_ver_uniform_location, 1);
138535c4bbdfSmrg        DEBUGF("p1.y: %f, p2.y: %f, enter the horizontal case\n",
138635c4bbdfSmrg               pt1[1], pt2[1]);
138735c4bbdfSmrg
138835c4bbdfSmrg        p1_distance = pt1[0];
138935c4bbdfSmrg        pt_distance = (pt2[0] - p1_distance);
139035c4bbdfSmrg        glUniform1f(p1_distance_uniform_location, p1_distance);
139135c4bbdfSmrg        glUniform1f(pt_distance_uniform_location, pt_distance);
139235c4bbdfSmrg    }
139335c4bbdfSmrg    else {
139435c4bbdfSmrg        /* The slope need to compute here. In shader, the viewport set will change
13951b5d61b8Smrg           the original slope and the slope which is vertical to it will not be correct. */
139635c4bbdfSmrg        slope = -(float) (src_picture->pSourcePict->linear.p2.x
139735c4bbdfSmrg                          - src_picture->pSourcePict->linear.p1.x) /
139835c4bbdfSmrg            (float) (src_picture->pSourcePict->linear.p2.y
139935c4bbdfSmrg                     - src_picture->pSourcePict->linear.p1.y);
140035c4bbdfSmrg        slope = slope * yscale / xscale;
140135c4bbdfSmrg        glUniform1f(pt_slope_uniform_location, slope);
140235c4bbdfSmrg        glUniform1i(hor_ver_uniform_location, 0);
140335c4bbdfSmrg
140435c4bbdfSmrg        cos_val = sqrt(1.0 / (slope * slope + 1.0));
140535c4bbdfSmrg        glUniform1f(cos_val_uniform_location, cos_val);
140635c4bbdfSmrg
140735c4bbdfSmrg        p1_distance = (pt1[1] - pt1[0] * slope) * cos_val;
140835c4bbdfSmrg        pt_distance = (pt2[1] - pt2[0] * slope) * cos_val - p1_distance;
140935c4bbdfSmrg        glUniform1f(p1_distance_uniform_location, p1_distance);
141035c4bbdfSmrg        glUniform1f(pt_distance_uniform_location, pt_distance);
141135c4bbdfSmrg    }
141235c4bbdfSmrg
141335c4bbdfSmrg    /* Now rendering. */
141435c4bbdfSmrg    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
141535c4bbdfSmrg
141635c4bbdfSmrg    /* Do the clear logic. */
141735c4bbdfSmrg    if (stops_count > LINEAR_SMALL_STOPS) {
141835c4bbdfSmrg        free(n_stops);
141935c4bbdfSmrg        free(stop_colors);
142035c4bbdfSmrg    }
142135c4bbdfSmrg
142235c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
142335c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
142435c4bbdfSmrg
142535c4bbdfSmrg    return dst_picture;
142635c4bbdfSmrg
142735c4bbdfSmrg GRADIENT_FAIL:
142835c4bbdfSmrg    if (dst_picture) {
142935c4bbdfSmrg        FreePicture(dst_picture, 0);
143035c4bbdfSmrg    }
143135c4bbdfSmrg
143235c4bbdfSmrg    if (stops_count > LINEAR_SMALL_STOPS) {
143335c4bbdfSmrg        if (n_stops)
143435c4bbdfSmrg            free(n_stops);
143535c4bbdfSmrg        if (stop_colors)
143635c4bbdfSmrg            free(stop_colors);
143735c4bbdfSmrg    }
143835c4bbdfSmrg
143935c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
144035c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
144135c4bbdfSmrg    return NULL;
144235c4bbdfSmrg}
1443