135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2014 Keith Packard
335c4bbdfSmrg *
435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its
535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that
635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright
735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and
835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or
935c4bbdfSmrg * publicity pertaining to distribution of the software without specific,
1035c4bbdfSmrg * written prior permission.  The copyright holders make no representations
1135c4bbdfSmrg * about the suitability of this software for any purpose.  It is provided "as
1235c4bbdfSmrg * is" without express or implied warranty.
1335c4bbdfSmrg *
1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2035c4bbdfSmrg * OF THIS SOFTWARE.
2135c4bbdfSmrg */
2235c4bbdfSmrg
2335c4bbdfSmrg#include "glamor_priv.h"
2435c4bbdfSmrg#include "glamor_transform.h"
2535c4bbdfSmrg#include "glamor_program.h"
2635c4bbdfSmrg
2735c4bbdfSmrgstatic Bool
2835c4bbdfSmrguse_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
2935c4bbdfSmrg{
3035c4bbdfSmrg    return glamor_set_solid(pixmap, gc, TRUE, prog->fg_uniform);
3135c4bbdfSmrg}
3235c4bbdfSmrg
3335c4bbdfSmrgconst glamor_facet glamor_fill_solid = {
3435c4bbdfSmrg    .name = "solid",
3535c4bbdfSmrg    .fs_exec = "       gl_FragColor = fg;\n",
3635c4bbdfSmrg    .locations = glamor_program_location_fg,
3735c4bbdfSmrg    .use = use_solid,
3835c4bbdfSmrg};
3935c4bbdfSmrg
4035c4bbdfSmrgstatic Bool
4135c4bbdfSmrguse_tile(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
4235c4bbdfSmrg{
4335c4bbdfSmrg    return glamor_set_tiled(pixmap, gc, prog->fill_offset_uniform, prog->fill_size_inv_uniform);
4435c4bbdfSmrg}
4535c4bbdfSmrg
4635c4bbdfSmrgstatic const glamor_facet glamor_fill_tile = {
4735c4bbdfSmrg    .name = "tile",
4835c4bbdfSmrg    .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
4935c4bbdfSmrg    .fs_exec =  "       gl_FragColor = texture2D(sampler, fill_pos);\n",
5035c4bbdfSmrg    .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
5135c4bbdfSmrg    .use = use_tile,
5235c4bbdfSmrg};
5335c4bbdfSmrg
5435c4bbdfSmrgstatic Bool
5535c4bbdfSmrguse_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
5635c4bbdfSmrg{
5735c4bbdfSmrg    return glamor_set_stippled(pixmap, gc, prog->fg_uniform,
5835c4bbdfSmrg                               prog->fill_offset_uniform,
5935c4bbdfSmrg                               prog->fill_size_inv_uniform);
6035c4bbdfSmrg}
6135c4bbdfSmrg
6235c4bbdfSmrgstatic const glamor_facet glamor_fill_stipple = {
6335c4bbdfSmrg    .name = "stipple",
6435c4bbdfSmrg    .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
6535c4bbdfSmrg    .fs_exec = ("       float a = texture2D(sampler, fill_pos).w;\n"
6635c4bbdfSmrg                "       if (a == 0.0)\n"
6735c4bbdfSmrg                "               discard;\n"
6835c4bbdfSmrg                "       gl_FragColor = fg;\n"),
6935c4bbdfSmrg    .locations = glamor_program_location_fg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
7035c4bbdfSmrg    .use = use_stipple,
7135c4bbdfSmrg};
7235c4bbdfSmrg
7335c4bbdfSmrgstatic Bool
7435c4bbdfSmrguse_opaque_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
7535c4bbdfSmrg{
7635c4bbdfSmrg    if (!use_stipple(pixmap, gc, prog, arg))
7735c4bbdfSmrg        return FALSE;
7835c4bbdfSmrg    glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform);
7935c4bbdfSmrg    return TRUE;
8035c4bbdfSmrg}
8135c4bbdfSmrg
8235c4bbdfSmrgstatic const glamor_facet glamor_fill_opaque_stipple = {
8335c4bbdfSmrg    .name = "opaque_stipple",
8435c4bbdfSmrg    .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
8535c4bbdfSmrg    .fs_exec = ("       float a = texture2D(sampler, fill_pos).w;\n"
8635c4bbdfSmrg                "       if (a == 0.0)\n"
8735c4bbdfSmrg                "               gl_FragColor = bg;\n"
8835c4bbdfSmrg                "       else\n"
8935c4bbdfSmrg                "               gl_FragColor = fg;\n"),
9035c4bbdfSmrg    .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
9135c4bbdfSmrg    .use = use_opaque_stipple
9235c4bbdfSmrg};
9335c4bbdfSmrg
9435c4bbdfSmrgstatic const glamor_facet *glamor_facet_fill[4] = {
9535c4bbdfSmrg    &glamor_fill_solid,
9635c4bbdfSmrg    &glamor_fill_tile,
9735c4bbdfSmrg    &glamor_fill_stipple,
9835c4bbdfSmrg    &glamor_fill_opaque_stipple,
9935c4bbdfSmrg};
10035c4bbdfSmrg
10135c4bbdfSmrgtypedef struct {
10235c4bbdfSmrg    glamor_program_location     location;
10335c4bbdfSmrg    const char                  *vs_vars;
10435c4bbdfSmrg    const char                  *fs_vars;
10535c4bbdfSmrg} glamor_location_var;
10635c4bbdfSmrg
10735c4bbdfSmrgstatic glamor_location_var location_vars[] = {
10835c4bbdfSmrg    {
10935c4bbdfSmrg        .location = glamor_program_location_fg,
11035c4bbdfSmrg        .fs_vars = "uniform vec4 fg;\n"
11135c4bbdfSmrg    },
11235c4bbdfSmrg    {
11335c4bbdfSmrg        .location = glamor_program_location_bg,
11435c4bbdfSmrg        .fs_vars = "uniform vec4 bg;\n"
11535c4bbdfSmrg    },
11635c4bbdfSmrg    {
11735c4bbdfSmrg        .location = glamor_program_location_fillsamp,
11835c4bbdfSmrg        .fs_vars = "uniform sampler2D sampler;\n"
11935c4bbdfSmrg    },
12035c4bbdfSmrg    {
12135c4bbdfSmrg        .location = glamor_program_location_fillpos,
12235c4bbdfSmrg        .vs_vars = ("uniform vec2 fill_offset;\n"
12335c4bbdfSmrg                    "uniform vec2 fill_size_inv;\n"
12435c4bbdfSmrg                    "varying vec2 fill_pos;\n"),
1251b5d61b8Smrg        .fs_vars = ("varying vec2 fill_pos;\n")
12635c4bbdfSmrg    },
12735c4bbdfSmrg    {
12835c4bbdfSmrg        .location = glamor_program_location_font,
12935c4bbdfSmrg        .fs_vars = "uniform usampler2D font;\n",
13035c4bbdfSmrg    },
13135c4bbdfSmrg    {
13235c4bbdfSmrg        .location = glamor_program_location_bitplane,
13335c4bbdfSmrg        .fs_vars = ("uniform uvec4 bitplane;\n"
13435c4bbdfSmrg                    "uniform vec4 bitmul;\n"),
13535c4bbdfSmrg    },
13635c4bbdfSmrg    {
13735c4bbdfSmrg        .location = glamor_program_location_dash,
13835c4bbdfSmrg        .vs_vars = "uniform float dash_length;\n",
13935c4bbdfSmrg        .fs_vars = "uniform sampler2D dash;\n",
14035c4bbdfSmrg    },
14135c4bbdfSmrg    {
14235c4bbdfSmrg        .location = glamor_program_location_atlas,
14335c4bbdfSmrg        .fs_vars = "uniform sampler2D atlas;\n",
14435c4bbdfSmrg    },
14535c4bbdfSmrg};
14635c4bbdfSmrg
14735c4bbdfSmrgstatic char *
14835c4bbdfSmrgadd_var(char *cur, const char *add)
14935c4bbdfSmrg{
15035c4bbdfSmrg    char *new;
15135c4bbdfSmrg
15235c4bbdfSmrg    if (!add)
15335c4bbdfSmrg        return cur;
15435c4bbdfSmrg
15535c4bbdfSmrg    new = realloc(cur, strlen(cur) + strlen(add) + 1);
15635c4bbdfSmrg    if (!new) {
15735c4bbdfSmrg        free(cur);
15835c4bbdfSmrg        return NULL;
15935c4bbdfSmrg    }
16035c4bbdfSmrg    strcat(new, add);
16135c4bbdfSmrg    return new;
16235c4bbdfSmrg}
16335c4bbdfSmrg
16435c4bbdfSmrgstatic char *
16535c4bbdfSmrgvs_location_vars(glamor_program_location locations)
16635c4bbdfSmrg{
16735c4bbdfSmrg    int l;
16835c4bbdfSmrg    char *vars = strdup("");
16935c4bbdfSmrg
17035c4bbdfSmrg    for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
17135c4bbdfSmrg        if (locations & location_vars[l].location)
17235c4bbdfSmrg            vars = add_var(vars, location_vars[l].vs_vars);
17335c4bbdfSmrg    return vars;
17435c4bbdfSmrg}
17535c4bbdfSmrg
17635c4bbdfSmrgstatic char *
17735c4bbdfSmrgfs_location_vars(glamor_program_location locations)
17835c4bbdfSmrg{
17935c4bbdfSmrg    int l;
18035c4bbdfSmrg    char *vars = strdup("");
18135c4bbdfSmrg
18235c4bbdfSmrg    for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
18335c4bbdfSmrg        if (locations & location_vars[l].location)
18435c4bbdfSmrg            vars = add_var(vars, location_vars[l].fs_vars);
18535c4bbdfSmrg    return vars;
18635c4bbdfSmrg}
18735c4bbdfSmrg
18835c4bbdfSmrgstatic const char vs_template[] =
18935c4bbdfSmrg    "%s"                                /* version */
190ed6184dfSmrg    "%s"                                /* exts */
19135c4bbdfSmrg    "%s"                                /* defines */
19235c4bbdfSmrg    "%s"                                /* prim vs_vars */
19335c4bbdfSmrg    "%s"                                /* fill vs_vars */
19435c4bbdfSmrg    "%s"                                /* location vs_vars */
19535c4bbdfSmrg    GLAMOR_DECLARE_MATRIX
19635c4bbdfSmrg    "void main() {\n"
19735c4bbdfSmrg    "%s"                                /* prim vs_exec, outputs 'pos' and gl_Position */
19835c4bbdfSmrg    "%s"                                /* fill vs_exec */
19935c4bbdfSmrg    "}\n";
20035c4bbdfSmrg
20135c4bbdfSmrgstatic const char fs_template[] =
20235c4bbdfSmrg    "%s"                                /* version */
203ed6184dfSmrg    "%s"                                /* exts */
20435c4bbdfSmrg    GLAMOR_DEFAULT_PRECISION
20535c4bbdfSmrg    "%s"                                /* defines */
20635c4bbdfSmrg    "%s"                                /* prim fs_vars */
20735c4bbdfSmrg    "%s"                                /* fill fs_vars */
20835c4bbdfSmrg    "%s"                                /* location fs_vars */
20935c4bbdfSmrg    "void main() {\n"
21035c4bbdfSmrg    "%s"                                /* prim fs_exec */
21135c4bbdfSmrg    "%s"                                /* fill fs_exec */
21235c4bbdfSmrg    "%s"                                /* combine */
21335c4bbdfSmrg    "}\n";
21435c4bbdfSmrg
21535c4bbdfSmrgstatic const char *
21635c4bbdfSmrgstr(const char *s)
21735c4bbdfSmrg{
21835c4bbdfSmrg    if (!s)
21935c4bbdfSmrg        return "";
22035c4bbdfSmrg    return s;
22135c4bbdfSmrg}
22235c4bbdfSmrg
22335c4bbdfSmrgstatic const glamor_facet facet_null_fill = {
22435c4bbdfSmrg    .name = ""
22535c4bbdfSmrg};
22635c4bbdfSmrg
22735c4bbdfSmrg#define DBG 0
22835c4bbdfSmrg
22935c4bbdfSmrgstatic GLint
23035c4bbdfSmrgglamor_get_uniform(glamor_program               *prog,
23135c4bbdfSmrg                   glamor_program_location      location,
23235c4bbdfSmrg                   const char                   *name)
23335c4bbdfSmrg{
23435c4bbdfSmrg    GLint uniform;
23535c4bbdfSmrg    if (location && (prog->locations & location) == 0)
23635c4bbdfSmrg        return -2;
23735c4bbdfSmrg    uniform = glGetUniformLocation(prog->prog, name);
23835c4bbdfSmrg#if DBG
23935c4bbdfSmrg    ErrorF("%s uniform %d\n", name, uniform);
24035c4bbdfSmrg#endif
24135c4bbdfSmrg    return uniform;
24235c4bbdfSmrg}
24335c4bbdfSmrg
24435c4bbdfSmrgBool
24535c4bbdfSmrgglamor_build_program(ScreenPtr          screen,
24635c4bbdfSmrg                     glamor_program     *prog,
24735c4bbdfSmrg                     const glamor_facet *prim,
24835c4bbdfSmrg                     const glamor_facet *fill,
24935c4bbdfSmrg                     const char         *combine,
25035c4bbdfSmrg                     const char         *defines)
25135c4bbdfSmrg{
25235c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
25335c4bbdfSmrg
25435c4bbdfSmrg    glamor_program_location     locations = prim->locations;
25535c4bbdfSmrg    glamor_program_flag         flags = prim->flags;
25635c4bbdfSmrg
25735c4bbdfSmrg    int                         version = prim->version;
25835c4bbdfSmrg    char                        *version_string = NULL;
25935c4bbdfSmrg
26035c4bbdfSmrg    char                        *fs_vars = NULL;
26135c4bbdfSmrg    char                        *vs_vars = NULL;
26235c4bbdfSmrg
263ed6184dfSmrg    char                        *vs_prog_string = NULL;
264ed6184dfSmrg    char                        *fs_prog_string = NULL;
26535c4bbdfSmrg
26635c4bbdfSmrg    GLint                       fs_prog, vs_prog;
267ed6184dfSmrg    Bool                        gpu_shader4 = FALSE;
26835c4bbdfSmrg
26935c4bbdfSmrg    if (!fill)
27035c4bbdfSmrg        fill = &facet_null_fill;
27135c4bbdfSmrg
27235c4bbdfSmrg    locations |= fill->locations;
27335c4bbdfSmrg    flags |= fill->flags;
27435c4bbdfSmrg    version = MAX(version, fill->version);
27535c4bbdfSmrg
276ed6184dfSmrg    if (version > glamor_priv->glsl_version) {
277ed6184dfSmrg        if (version == 130 && !glamor_priv->use_gpu_shader4)
278ed6184dfSmrg            goto fail;
279ed6184dfSmrg        else {
280ed6184dfSmrg            version = 120;
281ed6184dfSmrg            gpu_shader4 = TRUE;
282ed6184dfSmrg        }
283ed6184dfSmrg    }
28435c4bbdfSmrg
28535c4bbdfSmrg    vs_vars = vs_location_vars(locations);
28635c4bbdfSmrg    fs_vars = fs_location_vars(locations);
28735c4bbdfSmrg
28835c4bbdfSmrg    if (!vs_vars)
28935c4bbdfSmrg        goto fail;
29035c4bbdfSmrg    if (!fs_vars)
29135c4bbdfSmrg        goto fail;
29235c4bbdfSmrg
29335c4bbdfSmrg    if (version) {
29435c4bbdfSmrg        if (asprintf(&version_string, "#version %d\n", version) < 0)
29535c4bbdfSmrg            version_string = NULL;
29635c4bbdfSmrg        if (!version_string)
29735c4bbdfSmrg            goto fail;
29835c4bbdfSmrg    }
29935c4bbdfSmrg
30035c4bbdfSmrg    if (asprintf(&vs_prog_string,
30135c4bbdfSmrg                 vs_template,
30235c4bbdfSmrg                 str(version_string),
303ed6184dfSmrg                 gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n" : "",
30435c4bbdfSmrg                 str(defines),
30535c4bbdfSmrg                 str(prim->vs_vars),
30635c4bbdfSmrg                 str(fill->vs_vars),
30735c4bbdfSmrg                 vs_vars,
30835c4bbdfSmrg                 str(prim->vs_exec),
30935c4bbdfSmrg                 str(fill->vs_exec)) < 0)
31035c4bbdfSmrg        vs_prog_string = NULL;
31135c4bbdfSmrg
31235c4bbdfSmrg    if (asprintf(&fs_prog_string,
31335c4bbdfSmrg                 fs_template,
31435c4bbdfSmrg                 str(version_string),
315ed6184dfSmrg                 gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n#define texelFetch texelFetch2D\n#define uint unsigned int\n" : "",
31635c4bbdfSmrg                 str(defines),
31735c4bbdfSmrg                 str(prim->fs_vars),
31835c4bbdfSmrg                 str(fill->fs_vars),
31935c4bbdfSmrg                 fs_vars,
32035c4bbdfSmrg                 str(prim->fs_exec),
32135c4bbdfSmrg                 str(fill->fs_exec),
32235c4bbdfSmrg                 str(combine)) < 0)
32335c4bbdfSmrg        fs_prog_string = NULL;
32435c4bbdfSmrg
32535c4bbdfSmrg    if (!vs_prog_string || !fs_prog_string)
32635c4bbdfSmrg        goto fail;
32735c4bbdfSmrg
32835c4bbdfSmrg    prog->prog = glCreateProgram();
32935c4bbdfSmrg#if DBG
33035c4bbdfSmrg    ErrorF("\n\tProgram %d for %s %s\n\tVertex shader:\n\n\t================\n%s\n\n\tFragment Shader:\n\n%s\t================\n",
33135c4bbdfSmrg           prog->prog, prim->name, fill->name, vs_prog_string, fs_prog_string);
33235c4bbdfSmrg#endif
33335c4bbdfSmrg
33435c4bbdfSmrg    prog->flags = flags;
33535c4bbdfSmrg    prog->locations = locations;
33635c4bbdfSmrg    prog->prim_use = prim->use;
33735c4bbdfSmrg    prog->prim_use_render = prim->use_render;
33835c4bbdfSmrg    prog->fill_use = fill->use;
33935c4bbdfSmrg    prog->fill_use_render = fill->use_render;
34035c4bbdfSmrg
34135c4bbdfSmrg    vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
34235c4bbdfSmrg    fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
34335c4bbdfSmrg    glAttachShader(prog->prog, vs_prog);
34435c4bbdfSmrg    glDeleteShader(vs_prog);
34535c4bbdfSmrg    glAttachShader(prog->prog, fs_prog);
34635c4bbdfSmrg    glDeleteShader(fs_prog);
34735c4bbdfSmrg    glBindAttribLocation(prog->prog, GLAMOR_VERTEX_POS, "primitive");
34835c4bbdfSmrg
34935c4bbdfSmrg    if (prim->source_name) {
35035c4bbdfSmrg#if DBG
35135c4bbdfSmrg        ErrorF("Bind GLAMOR_VERTEX_SOURCE to %s\n", prim->source_name);
35235c4bbdfSmrg#endif
35335c4bbdfSmrg        glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name);
35435c4bbdfSmrg    }
35535c4bbdfSmrg    if (prog->alpha == glamor_program_alpha_dual_blend) {
35635c4bbdfSmrg        glBindFragDataLocationIndexed(prog->prog, 0, 0, "color0");
35735c4bbdfSmrg        glBindFragDataLocationIndexed(prog->prog, 0, 1, "color1");
35835c4bbdfSmrg    }
35935c4bbdfSmrg
36035c4bbdfSmrg    glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name);
36135c4bbdfSmrg
36235c4bbdfSmrg    prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix");
36335c4bbdfSmrg    prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg");
36435c4bbdfSmrg    prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg");
36535c4bbdfSmrg    prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_offset");
36635c4bbdfSmrg    prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_size_inv");
36735c4bbdfSmrg    prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font");
36835c4bbdfSmrg    prog->bitplane_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitplane");
36935c4bbdfSmrg    prog->bitmul_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitmul");
37035c4bbdfSmrg    prog->dash_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash");
37135c4bbdfSmrg    prog->dash_length_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash_length");
37235c4bbdfSmrg    prog->atlas_uniform = glamor_get_uniform(prog, glamor_program_location_atlas, "atlas");
37335c4bbdfSmrg
37435c4bbdfSmrg    free(version_string);
375f2346221Smrg    free(vs_prog_string);
376f2346221Smrg    free(fs_prog_string);
37735c4bbdfSmrg    free(fs_vars);
37835c4bbdfSmrg    free(vs_vars);
37935c4bbdfSmrg    return TRUE;
38035c4bbdfSmrgfail:
38135c4bbdfSmrg    prog->failed = 1;
38235c4bbdfSmrg    if (prog->prog) {
38335c4bbdfSmrg        glDeleteProgram(prog->prog);
38435c4bbdfSmrg        prog->prog = 0;
38535c4bbdfSmrg    }
386ed6184dfSmrg    free(vs_prog_string);
387ed6184dfSmrg    free(fs_prog_string);
38835c4bbdfSmrg    free(version_string);
38935c4bbdfSmrg    free(fs_vars);
39035c4bbdfSmrg    free(vs_vars);
39135c4bbdfSmrg    return FALSE;
39235c4bbdfSmrg}
39335c4bbdfSmrg
39435c4bbdfSmrgBool
39535c4bbdfSmrgglamor_use_program(PixmapPtr            pixmap,
39635c4bbdfSmrg                   GCPtr                gc,
39735c4bbdfSmrg                   glamor_program       *prog,
39835c4bbdfSmrg                   void                 *arg)
39935c4bbdfSmrg{
40035c4bbdfSmrg    glUseProgram(prog->prog);
40135c4bbdfSmrg
40235c4bbdfSmrg    if (prog->prim_use && !prog->prim_use(pixmap, gc, prog, arg))
40335c4bbdfSmrg        return FALSE;
40435c4bbdfSmrg
40535c4bbdfSmrg    if (prog->fill_use && !prog->fill_use(pixmap, gc, prog, arg))
40635c4bbdfSmrg        return FALSE;
40735c4bbdfSmrg
40835c4bbdfSmrg    return TRUE;
40935c4bbdfSmrg}
41035c4bbdfSmrg
41135c4bbdfSmrgglamor_program *
41235c4bbdfSmrgglamor_use_program_fill(PixmapPtr               pixmap,
41335c4bbdfSmrg                        GCPtr                   gc,
41435c4bbdfSmrg                        glamor_program_fill     *program_fill,
41535c4bbdfSmrg                        const glamor_facet      *prim)
41635c4bbdfSmrg{
41735c4bbdfSmrg    ScreenPtr                   screen = pixmap->drawable.pScreen;
41835c4bbdfSmrg    glamor_program              *prog = &program_fill->progs[gc->fillStyle];
41935c4bbdfSmrg
42035c4bbdfSmrg    int                         fill_style = gc->fillStyle;
42135c4bbdfSmrg    const glamor_facet          *fill;
42235c4bbdfSmrg
42335c4bbdfSmrg    if (prog->failed)
42435c4bbdfSmrg        return FALSE;
42535c4bbdfSmrg
42635c4bbdfSmrg    if (!prog->prog) {
42735c4bbdfSmrg        fill = glamor_facet_fill[fill_style];
42835c4bbdfSmrg        if (!fill)
42935c4bbdfSmrg            return NULL;
43035c4bbdfSmrg
43135c4bbdfSmrg        if (!glamor_build_program(screen, prog, prim, fill, NULL, NULL))
43235c4bbdfSmrg            return NULL;
43335c4bbdfSmrg    }
43435c4bbdfSmrg
43535c4bbdfSmrg    if (!glamor_use_program(pixmap, gc, prog, NULL))
43635c4bbdfSmrg        return NULL;
43735c4bbdfSmrg
43835c4bbdfSmrg    return prog;
43935c4bbdfSmrg}
44035c4bbdfSmrg
44135c4bbdfSmrgstatic struct blendinfo composite_op_info[] = {
44235c4bbdfSmrg    [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
44335c4bbdfSmrg    [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
44435c4bbdfSmrg    [PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
44535c4bbdfSmrg    [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
44635c4bbdfSmrg    [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
44735c4bbdfSmrg    [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
44835c4bbdfSmrg    [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
44935c4bbdfSmrg    [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
45035c4bbdfSmrg    [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
45135c4bbdfSmrg    [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
45235c4bbdfSmrg    [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
45335c4bbdfSmrg    [PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
45435c4bbdfSmrg    [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
45535c4bbdfSmrg};
45635c4bbdfSmrg
45735c4bbdfSmrgstatic void
45835c4bbdfSmrgglamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
45935c4bbdfSmrg{
46035c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(dst->pDrawable->pScreen);
46135c4bbdfSmrg    GLenum src_blend, dst_blend;
46235c4bbdfSmrg    struct blendinfo *op_info;
46335c4bbdfSmrg
46435c4bbdfSmrg    switch (alpha) {
46535c4bbdfSmrg    case glamor_program_alpha_ca_first:
46635c4bbdfSmrg        op = PictOpOutReverse;
46735c4bbdfSmrg        break;
46835c4bbdfSmrg    case glamor_program_alpha_ca_second:
46935c4bbdfSmrg        op = PictOpAdd;
47035c4bbdfSmrg        break;
47135c4bbdfSmrg    default:
47235c4bbdfSmrg        break;
47335c4bbdfSmrg    }
47435c4bbdfSmrg
475ed6184dfSmrg    if (!glamor_priv->is_gles)
47635c4bbdfSmrg        glDisable(GL_COLOR_LOGIC_OP);
47735c4bbdfSmrg
47835c4bbdfSmrg    if (op == PictOpSrc)
47935c4bbdfSmrg        return;
48035c4bbdfSmrg
48135c4bbdfSmrg    op_info = &composite_op_info[op];
48235c4bbdfSmrg
48335c4bbdfSmrg    src_blend = op_info->source_blend;
48435c4bbdfSmrg    dst_blend = op_info->dest_blend;
48535c4bbdfSmrg
48635c4bbdfSmrg    /* If there's no dst alpha channel, adjust the blend op so that we'll treat
48735c4bbdfSmrg     * it as always 1.
48835c4bbdfSmrg     */
48935c4bbdfSmrg    if (PICT_FORMAT_A(dst->format) == 0 && op_info->dest_alpha) {
49035c4bbdfSmrg        if (src_blend == GL_DST_ALPHA)
49135c4bbdfSmrg            src_blend = GL_ONE;
49235c4bbdfSmrg        else if (src_blend == GL_ONE_MINUS_DST_ALPHA)
49335c4bbdfSmrg            src_blend = GL_ZERO;
49435c4bbdfSmrg    }
49535c4bbdfSmrg
49635c4bbdfSmrg    /* Set up the source alpha value for blending in component alpha mode. */
49735c4bbdfSmrg    if (alpha == glamor_program_alpha_dual_blend) {
49835c4bbdfSmrg        switch (dst_blend) {
49935c4bbdfSmrg        case GL_SRC_ALPHA:
50035c4bbdfSmrg            dst_blend = GL_SRC1_COLOR;
50135c4bbdfSmrg            break;
50235c4bbdfSmrg        case GL_ONE_MINUS_SRC_ALPHA:
50335c4bbdfSmrg            dst_blend = GL_ONE_MINUS_SRC1_COLOR;
50435c4bbdfSmrg            break;
50535c4bbdfSmrg        }
50635c4bbdfSmrg    } else if (alpha != glamor_program_alpha_normal) {
50735c4bbdfSmrg        switch (dst_blend) {
50835c4bbdfSmrg        case GL_SRC_ALPHA:
50935c4bbdfSmrg            dst_blend = GL_SRC_COLOR;
51035c4bbdfSmrg            break;
51135c4bbdfSmrg        case GL_ONE_MINUS_SRC_ALPHA:
51235c4bbdfSmrg            dst_blend = GL_ONE_MINUS_SRC_COLOR;
51335c4bbdfSmrg            break;
51435c4bbdfSmrg        }
51535c4bbdfSmrg    }
51635c4bbdfSmrg
51735c4bbdfSmrg    glEnable(GL_BLEND);
51835c4bbdfSmrg    glBlendFunc(src_blend, dst_blend);
51935c4bbdfSmrg}
52035c4bbdfSmrg
52135c4bbdfSmrgstatic Bool
52235c4bbdfSmrguse_source_solid(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
52335c4bbdfSmrg{
5241b5d61b8Smrg    PictSolidFill *solid = &src->pSourcePict->solidFill;
5251b5d61b8Smrg    float color[4];
52635c4bbdfSmrg
5271b5d61b8Smrg    glamor_get_rgba_from_color(&solid->fullcolor, color);
52835c4bbdfSmrg    glamor_set_blend(op, prog->alpha, dst);
5291b5d61b8Smrg    glUniform4fv(prog->fg_uniform, 1, color);
53035c4bbdfSmrg
53135c4bbdfSmrg    return TRUE;
53235c4bbdfSmrg}
53335c4bbdfSmrg
53435c4bbdfSmrgstatic const glamor_facet glamor_source_solid = {
53535c4bbdfSmrg    .name = "render_solid",
53635c4bbdfSmrg    .fs_exec = "       vec4 source = fg;\n",
53735c4bbdfSmrg    .locations = glamor_program_location_fg,
53835c4bbdfSmrg    .use_render = use_source_solid,
53935c4bbdfSmrg};
54035c4bbdfSmrg
54135c4bbdfSmrgstatic Bool
54235c4bbdfSmrguse_source_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
54335c4bbdfSmrg{
54435c4bbdfSmrg    glamor_set_blend(op, prog->alpha, dst);
54535c4bbdfSmrg
54635c4bbdfSmrg    return glamor_set_texture((PixmapPtr) src->pDrawable,
54735c4bbdfSmrg                              glamor_picture_red_is_alpha(dst),
54835c4bbdfSmrg                              0, 0,
54935c4bbdfSmrg                              prog->fill_offset_uniform,
55035c4bbdfSmrg                              prog->fill_size_inv_uniform);
55135c4bbdfSmrg}
55235c4bbdfSmrg
55335c4bbdfSmrgstatic const glamor_facet glamor_source_picture = {
55435c4bbdfSmrg    .name = "render_picture",
55535c4bbdfSmrg    .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
55635c4bbdfSmrg    .fs_exec =  "       vec4 source = texture2D(sampler, fill_pos);\n",
55735c4bbdfSmrg    .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
55835c4bbdfSmrg    .use_render = use_source_picture,
55935c4bbdfSmrg};
56035c4bbdfSmrg
56135c4bbdfSmrgstatic Bool
56235c4bbdfSmrguse_source_1x1_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
56335c4bbdfSmrg{
56435c4bbdfSmrg    glamor_set_blend(op, prog->alpha, dst);
56535c4bbdfSmrg
56635c4bbdfSmrg    return glamor_set_texture_pixmap((PixmapPtr) src->pDrawable,
56735c4bbdfSmrg                                     glamor_picture_red_is_alpha(dst));
56835c4bbdfSmrg}
56935c4bbdfSmrg
57035c4bbdfSmrgstatic const glamor_facet glamor_source_1x1_picture = {
57135c4bbdfSmrg    .name = "render_picture",
57235c4bbdfSmrg    .fs_exec =  "       vec4 source = texture2D(sampler, vec2(0.5));\n",
57335c4bbdfSmrg    .locations = glamor_program_location_fillsamp,
57435c4bbdfSmrg    .use_render = use_source_1x1_picture,
57535c4bbdfSmrg};
57635c4bbdfSmrg
57735c4bbdfSmrgstatic const glamor_facet *glamor_facet_source[glamor_program_source_count] = {
57835c4bbdfSmrg    [glamor_program_source_solid] = &glamor_source_solid,
57935c4bbdfSmrg    [glamor_program_source_picture] = &glamor_source_picture,
58035c4bbdfSmrg    [glamor_program_source_1x1_picture] = &glamor_source_1x1_picture,
58135c4bbdfSmrg};
58235c4bbdfSmrg
58335c4bbdfSmrgstatic const char *glamor_combine[] = {
58435c4bbdfSmrg    [glamor_program_alpha_normal]    = "       gl_FragColor = source * mask.a;\n",
58535c4bbdfSmrg    [glamor_program_alpha_ca_first]  = "       gl_FragColor = source.a * mask;\n",
58635c4bbdfSmrg    [glamor_program_alpha_ca_second] = "       gl_FragColor = source * mask;\n",
58735c4bbdfSmrg    [glamor_program_alpha_dual_blend] = "      color0 = source * mask;\n"
58835c4bbdfSmrg                                        "      color1 = source.a * mask;\n"
58935c4bbdfSmrg};
59035c4bbdfSmrg
59135c4bbdfSmrgstatic Bool
59235c4bbdfSmrgglamor_setup_one_program_render(ScreenPtr               screen,
59335c4bbdfSmrg                                glamor_program          *prog,
59435c4bbdfSmrg                                glamor_program_source   source_type,
59535c4bbdfSmrg                                glamor_program_alpha    alpha,
59635c4bbdfSmrg                                const glamor_facet      *prim,
59735c4bbdfSmrg                                const char              *defines)
59835c4bbdfSmrg{
59935c4bbdfSmrg    if (prog->failed)
60035c4bbdfSmrg        return FALSE;
60135c4bbdfSmrg
60235c4bbdfSmrg    if (!prog->prog) {
60335c4bbdfSmrg        const glamor_facet      *fill = glamor_facet_source[source_type];
60435c4bbdfSmrg
60535c4bbdfSmrg        if (!fill)
60635c4bbdfSmrg            return FALSE;
60735c4bbdfSmrg
60835c4bbdfSmrg        prog->alpha = alpha;
60935c4bbdfSmrg        if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines))
61035c4bbdfSmrg            return FALSE;
61135c4bbdfSmrg    }
61235c4bbdfSmrg
61335c4bbdfSmrg    return TRUE;
61435c4bbdfSmrg}
61535c4bbdfSmrg
61635c4bbdfSmrgglamor_program *
61735c4bbdfSmrgglamor_setup_program_render(CARD8                 op,
61835c4bbdfSmrg                            PicturePtr            src,
61935c4bbdfSmrg                            PicturePtr            mask,
62035c4bbdfSmrg                            PicturePtr            dst,
62135c4bbdfSmrg                            glamor_program_render *program_render,
62235c4bbdfSmrg                            const glamor_facet    *prim,
62335c4bbdfSmrg                            const char            *defines)
62435c4bbdfSmrg{
62535c4bbdfSmrg    ScreenPtr                   screen = dst->pDrawable->pScreen;
62635c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
62735c4bbdfSmrg    glamor_program_alpha        alpha;
62835c4bbdfSmrg    glamor_program_source       source_type;
62935c4bbdfSmrg    glamor_program              *prog;
63035c4bbdfSmrg
63135c4bbdfSmrg    if (op > ARRAY_SIZE(composite_op_info))
63235c4bbdfSmrg        return NULL;
63335c4bbdfSmrg
63435c4bbdfSmrg    if (glamor_is_component_alpha(mask)) {
63535c4bbdfSmrg        if (glamor_priv->has_dual_blend) {
63635c4bbdfSmrg            alpha = glamor_program_alpha_dual_blend;
63735c4bbdfSmrg        } else {
63835c4bbdfSmrg            /* This only works for PictOpOver */
63935c4bbdfSmrg            if (op != PictOpOver)
64035c4bbdfSmrg                return NULL;
64135c4bbdfSmrg
64235c4bbdfSmrg            alpha = glamor_program_alpha_ca_first;
64335c4bbdfSmrg        }
64435c4bbdfSmrg    } else
64535c4bbdfSmrg        alpha = glamor_program_alpha_normal;
64635c4bbdfSmrg
64735c4bbdfSmrg    if (src->pDrawable) {
64835c4bbdfSmrg
64935c4bbdfSmrg        /* Can't do transforms, alphamaps or sourcing from non-pixmaps yet */
65035c4bbdfSmrg        if (src->transform || src->alphaMap || src->pDrawable->type != DRAWABLE_PIXMAP)
65135c4bbdfSmrg            return NULL;
65235c4bbdfSmrg
65335c4bbdfSmrg        if (src->pDrawable->width == 1 && src->pDrawable->height == 1 && src->repeat)
65435c4bbdfSmrg            source_type = glamor_program_source_1x1_picture;
65535c4bbdfSmrg        else
65635c4bbdfSmrg            source_type = glamor_program_source_picture;
65735c4bbdfSmrg    } else {
65835c4bbdfSmrg        SourcePictPtr   sp = src->pSourcePict;
65935c4bbdfSmrg        if (!sp)
66035c4bbdfSmrg            return NULL;
66135c4bbdfSmrg        switch (sp->type) {
66235c4bbdfSmrg        case SourcePictTypeSolidFill:
66335c4bbdfSmrg            source_type = glamor_program_source_solid;
66435c4bbdfSmrg            break;
66535c4bbdfSmrg        default:
66635c4bbdfSmrg            return NULL;
66735c4bbdfSmrg        }
66835c4bbdfSmrg    }
66935c4bbdfSmrg
67035c4bbdfSmrg    prog = &program_render->progs[source_type][alpha];
67135c4bbdfSmrg    if (!glamor_setup_one_program_render(screen, prog, source_type, alpha, prim, defines))
67235c4bbdfSmrg        return NULL;
67335c4bbdfSmrg
67435c4bbdfSmrg    if (alpha == glamor_program_alpha_ca_first) {
67535c4bbdfSmrg
67635c4bbdfSmrg	  /* Make sure we can also build the second program before
67735c4bbdfSmrg	   * deciding to use this path.
67835c4bbdfSmrg	   */
67935c4bbdfSmrg	  if (!glamor_setup_one_program_render(screen,
68035c4bbdfSmrg					       &program_render->progs[source_type][glamor_program_alpha_ca_second],
68135c4bbdfSmrg					       source_type, glamor_program_alpha_ca_second, prim,
68235c4bbdfSmrg					       defines))
68335c4bbdfSmrg	      return NULL;
68435c4bbdfSmrg    }
68535c4bbdfSmrg    return prog;
68635c4bbdfSmrg}
68735c4bbdfSmrg
68835c4bbdfSmrgBool
68935c4bbdfSmrgglamor_use_program_render(glamor_program        *prog,
69035c4bbdfSmrg                          CARD8                 op,
69135c4bbdfSmrg                          PicturePtr            src,
69235c4bbdfSmrg                          PicturePtr            dst)
69335c4bbdfSmrg{
69435c4bbdfSmrg    glUseProgram(prog->prog);
69535c4bbdfSmrg
69635c4bbdfSmrg    if (prog->prim_use_render && !prog->prim_use_render(op, src, dst, prog))
69735c4bbdfSmrg        return FALSE;
69835c4bbdfSmrg
69935c4bbdfSmrg    if (prog->fill_use_render && !prog->fill_use_render(op, src, dst, prog))
70035c4bbdfSmrg        return FALSE;
70135c4bbdfSmrg    return TRUE;
70235c4bbdfSmrg}
703