Home | History | Annotate | Line # | Download | only in glamor
      1 /*
      2  * Copyright  2014 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that copyright
      7  * notice and this permission notice appear in supporting documentation, and
      8  * that the name of the copyright holders not be used in advertising or
      9  * publicity pertaining to distribution of the software without specific,
     10  * written prior permission.  The copyright holders make no representations
     11  * about the suitability of this software for any purpose.  It is provided "as
     12  * is" without express or implied warranty.
     13  *
     14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     20  * OF THIS SOFTWARE.
     21  */
     22 
     23 #include "glamor_priv.h"
     24 #include "glamor_transform.h"
     25 #include "glamor_program.h"
     26 
     27 static Bool
     28 use_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
     29 {
     30     return glamor_set_solid(pixmap, gc, TRUE, prog->fg_uniform);
     31 }
     32 
     33 const glamor_facet glamor_fill_solid = {
     34     .name = "solid",
     35     .fs_exec = "       frag_color = fg;\n",
     36     .locations = glamor_program_location_fg,
     37     .use = use_solid,
     38 };
     39 
     40 static Bool
     41 use_tile(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
     42 {
     43     return glamor_set_tiled(pixmap, gc, prog->fill_offset_uniform, prog->fill_size_inv_uniform);
     44 }
     45 
     46 static const glamor_facet glamor_fill_tile = {
     47     .name = "tile",
     48     .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
     49     .fs_exec =  "       frag_color = texture(sampler, fill_pos);\n",
     50     .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
     51     .use = use_tile,
     52 };
     53 
     54 static Bool
     55 use_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
     56 {
     57     return glamor_set_stippled(pixmap, gc, prog->fg_uniform,
     58                                prog->fill_offset_uniform,
     59                                prog->fill_size_inv_uniform);
     60 }
     61 
     62 static const glamor_facet glamor_fill_stipple = {
     63     .name = "stipple",
     64     .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
     65     .fs_exec = ("       float a = texture(sampler, fill_pos).w;\n"
     66                 "       if (a == 0.0)\n"
     67                 "               discard;\n"
     68                 "       frag_color = fg;\n"),
     69     .locations = glamor_program_location_fg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
     70     .use = use_stipple,
     71 };
     72 
     73 static Bool
     74 use_opaque_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
     75 {
     76     if (!use_stipple(pixmap, gc, prog, arg))
     77         return FALSE;
     78     glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform);
     79     return TRUE;
     80 }
     81 
     82 static const glamor_facet glamor_fill_opaque_stipple = {
     83     .name = "opaque_stipple",
     84     .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
     85     .fs_exec = ("       float a = texture(sampler, fill_pos).w;\n"
     86                 "       if (a == 0.0)\n"
     87                 "               frag_color = bg;\n"
     88                 "       else\n"
     89                 "               frag_color = fg;\n"),
     90     .locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
     91     .use = use_opaque_stipple
     92 };
     93 
     94 static const glamor_facet *glamor_facet_fill[4] = {
     95     &glamor_fill_solid,
     96     &glamor_fill_tile,
     97     &glamor_fill_stipple,
     98     &glamor_fill_opaque_stipple,
     99 };
    100 
    101 typedef struct {
    102     glamor_program_location     location;
    103     const char                  *vs_vars;
    104     const char                  *fs_vars;
    105 } glamor_location_var;
    106 
    107 static glamor_location_var location_vars[] = {
    108     {
    109         .location = glamor_program_location_fg,
    110         .fs_vars = "uniform vec4 fg;\n"
    111     },
    112     {
    113         .location = glamor_program_location_bg,
    114         .fs_vars = "uniform vec4 bg;\n"
    115     },
    116     {
    117         .location = glamor_program_location_fillsamp,
    118         .fs_vars = "uniform sampler2D sampler;\n"
    119     },
    120     {
    121         .location = glamor_program_location_fillpos,
    122         .vs_vars = ("uniform vec2 fill_offset;\n"
    123                     "uniform vec2 fill_size_inv;\n"
    124                     "out vec2 fill_pos;\n"),
    125         .fs_vars = ("in vec2 fill_pos;\n")
    126     },
    127     {
    128         .location = glamor_program_location_font,
    129         .fs_vars = ("#ifdef GL_ES\n"
    130                     "precision mediump usampler2D;\n"
    131                     "#endif\n"
    132                     "uniform usampler2D font;\n"),
    133     },
    134     {
    135         .location = glamor_program_location_bitplane,
    136         .fs_vars = ("uniform uvec4 bitplane;\n"
    137                     "uniform vec4 bitmul;\n"),
    138     },
    139     {
    140         .location = glamor_program_location_dash,
    141         .vs_vars = "uniform float dash_length;\n",
    142         .fs_vars = "uniform sampler2D dash;\n",
    143     },
    144     {
    145         .location = glamor_program_location_atlas,
    146         .fs_vars = "uniform sampler2D atlas;\n",
    147     },
    148 };
    149 
    150 static char *
    151 add_var(char *cur, const char *add)
    152 {
    153     char *new;
    154 
    155     if (!add)
    156         return cur;
    157 
    158     new = realloc(cur, strlen(cur) + strlen(add) + 1);
    159     if (!new) {
    160         free(cur);
    161         return NULL;
    162     }
    163     strcat(new, add);
    164     return new;
    165 }
    166 
    167 static char *
    168 vs_location_vars(glamor_program_location locations)
    169 {
    170     int l;
    171     char *vars = strdup("");
    172 
    173     for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
    174         if (locations & location_vars[l].location)
    175             vars = add_var(vars, location_vars[l].vs_vars);
    176     return vars;
    177 }
    178 
    179 static char *
    180 fs_location_vars(glamor_program_location locations)
    181 {
    182     int l;
    183     char *vars = strdup("");
    184 
    185     for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
    186         if (locations & location_vars[l].location)
    187             vars = add_var(vars, location_vars[l].fs_vars);
    188     return vars;
    189 }
    190 
    191 static const char vs_template[] =
    192     "%s"                                /* version */
    193     "%s"                                /* exts */
    194     "%s"                                /* in/out defines */
    195     "%s"                                /* defines */
    196     "%s"                                /* prim vs_vars */
    197     "%s"                                /* fill vs_vars */
    198     "%s"                                /* location vs_vars */
    199     GLAMOR_DECLARE_MATRIX
    200     "void main() {\n"
    201     "%s"                                /* prim vs_exec, outputs 'pos' and gl_Position */
    202     "%s"                                /* fill vs_exec */
    203     "}\n";
    204 
    205 static const char fs_template[] =
    206     "%s"                                /* version */
    207     "%s"                                /* exts */
    208     "%s"                                /* prim fs_extensions */
    209     "%s"                                /* fill fs_extensions */
    210     GLAMOR_DEFAULT_PRECISION
    211     "%s"                                /* in/out defines */
    212     "%s"                                /* defines */
    213     "%s"                                /* prim fs_vars */
    214     "%s"                                /* fill fs_vars */
    215     "%s"                                /* location fs_vars */
    216     "void main() {\n"
    217     "%s"                                /* prim fs_exec */
    218     "%s"                                /* fill fs_exec */
    219     "%s"                                /* combine */
    220     "}\n";
    221 
    222 static const char *
    223 str(const char *s)
    224 {
    225     if (!s)
    226         return "";
    227     return s;
    228 }
    229 
    230 static const glamor_facet facet_null_fill = {
    231     .name = ""
    232 };
    233 
    234 #define DBG 0
    235 
    236 static GLint
    237 glamor_get_uniform(glamor_program               *prog,
    238                    glamor_program_location      location,
    239                    const char                   *name)
    240 {
    241     GLint uniform;
    242     if (location && (prog->locations & location) == 0)
    243         return -2;
    244     uniform = glGetUniformLocation(prog->prog, name);
    245 #if DBG
    246     ErrorF("%s uniform %d\n", name, uniform);
    247 #endif
    248     return uniform;
    249 }
    250 
    251 Bool
    252 glamor_build_program(ScreenPtr          screen,
    253                      glamor_program     *prog,
    254                      const glamor_facet *prim,
    255                      const glamor_facet *fill,
    256                      const char         *combine,
    257                      const char         *defines)
    258 {
    259     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    260 
    261     glamor_program_location     locations = prim->locations;
    262     glamor_program_flag         flags = prim->flags;
    263 
    264     int                         version = prim->version;
    265     char                        *version_string = NULL;
    266 
    267     char                        *fs_vars = NULL;
    268     char                        *vs_vars = NULL;
    269 
    270     char                        *vs_prog_string = NULL;
    271     char                        *fs_prog_string = NULL;
    272 
    273     GLint                       fs_prog, vs_prog;
    274     Bool                        gpu_shader4 = FALSE;
    275 
    276     if (!fill)
    277         fill = &facet_null_fill;
    278 
    279     locations |= fill->locations;
    280     flags |= fill->flags;
    281     version = MAX(version, fill->version);
    282 
    283     if (version > glamor_priv->glsl_version) {
    284         if (version == 130 && !glamor_priv->use_gpu_shader4)
    285             goto fail;
    286         else {
    287             version = 120;
    288             gpu_shader4 = TRUE;
    289         }
    290     }
    291 
    292     if (version == 130 && glamor_priv->is_gles && glamor_priv->glsl_version > 110)
    293         version = 300;
    294     else if (glamor_priv->is_gles)
    295         version = 100;
    296     else if (!version)
    297         version = 120;
    298 
    299     vs_vars = vs_location_vars(locations);
    300     fs_vars = fs_location_vars(locations);
    301 
    302     if (!vs_vars)
    303         goto fail;
    304     if (!fs_vars)
    305         goto fail;
    306 
    307     if (version) {
    308         if (asprintf(&version_string, "#version %d %s\n", version,
    309                      glamor_priv->is_gles && version > 100 ? "es" : "") < 0)
    310             version_string = NULL;
    311         if (!version_string)
    312             goto fail;
    313     }
    314 
    315     if (asprintf(&vs_prog_string,
    316                  vs_template,
    317                  str(version_string),
    318                  gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n" : "",
    319                  version < 130 ? GLAMOR_COMPAT_DEFINES_VS : "",
    320                  str(defines),
    321                  str(prim->vs_vars),
    322                  str(fill->vs_vars),
    323                  vs_vars,
    324                  str(prim->vs_exec),
    325                  str(fill->vs_exec)) < 0)
    326         vs_prog_string = NULL;
    327 
    328     if (asprintf(&fs_prog_string,
    329                  fs_template,
    330                  str(version_string),
    331                  str(prim->fs_extensions),
    332                  str(fill->fs_extensions),
    333                  gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n#define texelFetch texelFetch2D\n#define uint unsigned int\n" : "",
    334                  GLAMOR_COMPAT_DEFINES_FS,
    335                  str(defines),
    336                  str(prim->fs_vars),
    337                  str(fill->fs_vars),
    338                  fs_vars,
    339                  str(prim->fs_exec),
    340                  str(fill->fs_exec),
    341                  str(combine)) < 0)
    342         fs_prog_string = NULL;
    343 
    344     if (!vs_prog_string || !fs_prog_string)
    345         goto fail;
    346 
    347     prog->prog = glCreateProgram();
    348 #if DBG
    349     ErrorF("\n\tProgram %d for %s %s\n\tVertex shader:\n\n\t================\n%s\n\n\tFragment Shader:\n\n%s\t================\n",
    350            prog->prog, prim->name, fill->name, vs_prog_string, fs_prog_string);
    351 #endif
    352 
    353     prog->flags = flags;
    354     prog->locations = locations;
    355     prog->prim_use = prim->use;
    356     prog->prim_use_render = prim->use_render;
    357     prog->fill_use = fill->use;
    358     prog->fill_use_render = fill->use_render;
    359 
    360     vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
    361     fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
    362     glAttachShader(prog->prog, vs_prog);
    363     glDeleteShader(vs_prog);
    364     glAttachShader(prog->prog, fs_prog);
    365     glDeleteShader(fs_prog);
    366     glBindAttribLocation(prog->prog, GLAMOR_VERTEX_POS, "primitive");
    367 
    368     if (prim->source_name) {
    369 #if DBG
    370         ErrorF("Bind GLAMOR_VERTEX_SOURCE to %s\n", prim->source_name);
    371 #endif
    372         glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name);
    373     }
    374     if (prog->alpha == glamor_program_alpha_dual_blend) {
    375         glBindFragDataLocationIndexed(prog->prog, 0, 0, "color0");
    376         glBindFragDataLocationIndexed(prog->prog, 0, 1, "color1");
    377     }
    378 
    379     if (!glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name))
    380         goto fail;
    381 
    382     prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix");
    383     prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg");
    384     prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg");
    385     prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_offset");
    386     prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_size_inv");
    387     prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font");
    388     prog->bitplane_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitplane");
    389     prog->bitmul_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitmul");
    390     prog->dash_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash");
    391     prog->dash_length_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash_length");
    392     prog->atlas_uniform = glamor_get_uniform(prog, glamor_program_location_atlas, "atlas");
    393 
    394     free(version_string);
    395     free(vs_prog_string);
    396     free(fs_prog_string);
    397     free(fs_vars);
    398     free(vs_vars);
    399     return TRUE;
    400 fail:
    401     prog->failed = 1;
    402     if (prog->prog) {
    403         glDeleteProgram(prog->prog);
    404         prog->prog = 0;
    405     }
    406     free(vs_prog_string);
    407     free(fs_prog_string);
    408     free(version_string);
    409     free(fs_vars);
    410     free(vs_vars);
    411     return FALSE;
    412 }
    413 
    414 Bool
    415 glamor_use_program(PixmapPtr            pixmap,
    416                    GCPtr                gc,
    417                    glamor_program       *prog,
    418                    void                 *arg)
    419 {
    420     glUseProgram(prog->prog);
    421 
    422     if (prog->prim_use && !prog->prim_use(pixmap, gc, prog, arg))
    423         return FALSE;
    424 
    425     if (prog->fill_use && !prog->fill_use(pixmap, gc, prog, arg))
    426         return FALSE;
    427 
    428     return TRUE;
    429 }
    430 
    431 glamor_program *
    432 glamor_use_program_fill(PixmapPtr               pixmap,
    433                         GCPtr                   gc,
    434                         glamor_program_fill     *program_fill,
    435                         const glamor_facet      *prim)
    436 {
    437     ScreenPtr                   screen = pixmap->drawable.pScreen;
    438     glamor_program              *prog = &program_fill->progs[gc->fillStyle];
    439 
    440     int                         fill_style = gc->fillStyle;
    441     const glamor_facet          *fill;
    442 
    443     if (prog->failed)
    444         return FALSE;
    445 
    446     if (!prog->prog) {
    447         fill = glamor_facet_fill[fill_style];
    448         if (!fill)
    449             return NULL;
    450 
    451         if (!glamor_build_program(screen, prog, prim, fill, NULL, NULL))
    452             return NULL;
    453     }
    454 
    455     if (!glamor_use_program(pixmap, gc, prog, NULL))
    456         return NULL;
    457 
    458     return prog;
    459 }
    460 
    461 static struct blendinfo composite_op_info[] = {
    462     [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
    463     [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
    464     [PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
    465     [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
    466     [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
    467     [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
    468     [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
    469     [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
    470     [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
    471     [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
    472     [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
    473     [PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
    474     [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
    475 };
    476 
    477 static void
    478 glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
    479 {
    480     glamor_screen_private *glamor_priv = glamor_get_screen_private(dst->pDrawable->pScreen);
    481     GLenum src_blend, dst_blend;
    482     struct blendinfo *op_info;
    483 
    484     switch (alpha) {
    485     case glamor_program_alpha_ca_first:
    486         op = PictOpOutReverse;
    487         break;
    488     case glamor_program_alpha_ca_second:
    489         op = PictOpAdd;
    490         break;
    491     default:
    492         break;
    493     }
    494 
    495     if (!glamor_priv->is_gles)
    496         glDisable(GL_COLOR_LOGIC_OP);
    497 
    498     if (op == PictOpSrc)
    499         return;
    500 
    501     op_info = &composite_op_info[op];
    502 
    503     src_blend = op_info->source_blend;
    504     dst_blend = op_info->dest_blend;
    505 
    506     /* If there's no dst alpha channel, adjust the blend op so that we'll treat
    507      * it as always 1.
    508      */
    509     if (PICT_FORMAT_A(dst->format) == 0 && op_info->dest_alpha) {
    510         if (src_blend == GL_DST_ALPHA)
    511             src_blend = GL_ONE;
    512         else if (src_blend == GL_ONE_MINUS_DST_ALPHA)
    513             src_blend = GL_ZERO;
    514     }
    515 
    516     /* Set up the source alpha value for blending in component alpha mode. */
    517     if (alpha == glamor_program_alpha_dual_blend ||
    518         alpha == glamor_program_alpha_dual_blend_gles2) {
    519         switch (dst_blend) {
    520         case GL_SRC_ALPHA:
    521             dst_blend = GL_SRC1_COLOR;
    522             break;
    523         case GL_ONE_MINUS_SRC_ALPHA:
    524             dst_blend = GL_ONE_MINUS_SRC1_COLOR;
    525             break;
    526         }
    527     } else if (alpha != glamor_program_alpha_normal) {
    528         switch (dst_blend) {
    529         case GL_SRC_ALPHA:
    530             dst_blend = GL_SRC_COLOR;
    531             break;
    532         case GL_ONE_MINUS_SRC_ALPHA:
    533             dst_blend = GL_ONE_MINUS_SRC_COLOR;
    534             break;
    535         }
    536     }
    537 
    538     glEnable(GL_BLEND);
    539     glBlendFunc(src_blend, dst_blend);
    540 }
    541 
    542 static Bool
    543 use_source_solid(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
    544 {
    545     PictSolidFill *solid = &src->pSourcePict->solidFill;
    546     float color[4];
    547 
    548     glamor_get_rgba_from_color(&solid->fullcolor, color);
    549     glamor_set_blend(op, prog->alpha, dst);
    550     glUniform4fv(prog->fg_uniform, 1, color);
    551 
    552     return TRUE;
    553 }
    554 
    555 static const glamor_facet glamor_source_solid = {
    556     .name = "render_solid",
    557     .fs_exec = "       vec4 source = fg;\n",
    558     .locations = glamor_program_location_fg,
    559     .use_render = use_source_solid,
    560 };
    561 
    562 static Bool
    563 use_source_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
    564 {
    565     glamor_set_blend(op, prog->alpha, dst);
    566 
    567     return glamor_set_texture((PixmapPtr) src->pDrawable,
    568                               glamor_picture_red_is_alpha(dst),
    569                               0, 0,
    570                               prog->fill_offset_uniform,
    571                               prog->fill_size_inv_uniform);
    572 }
    573 
    574 static const glamor_facet glamor_source_picture = {
    575     .name = "render_picture",
    576     .vs_exec =  "       fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
    577     .fs_exec =  "       vec4 source = texture(sampler, fill_pos);\n",
    578     .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
    579     .use_render = use_source_picture,
    580 };
    581 
    582 static Bool
    583 use_source_1x1_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
    584 {
    585     glamor_set_blend(op, prog->alpha, dst);
    586 
    587     return glamor_set_texture_pixmap((PixmapPtr) src->pDrawable,
    588                                      glamor_picture_red_is_alpha(dst));
    589 }
    590 
    591 static const glamor_facet glamor_source_1x1_picture = {
    592     .name = "render_picture",
    593     .fs_exec =  "       vec4 source = texture(sampler, vec2(0.5));\n",
    594     .locations = glamor_program_location_fillsamp,
    595     .use_render = use_source_1x1_picture,
    596 };
    597 
    598 static const glamor_facet *glamor_facet_source[glamor_program_source_count] = {
    599     [glamor_program_source_solid] = &glamor_source_solid,
    600     [glamor_program_source_picture] = &glamor_source_picture,
    601     [glamor_program_source_1x1_picture] = &glamor_source_1x1_picture,
    602 };
    603 
    604 static const char *glamor_combine[] = {
    605     [glamor_program_alpha_normal]    = "       frag_color = source * mask.a;\n",
    606     [glamor_program_alpha_ca_first]  = "       frag_color = source.a * mask;\n",
    607     [glamor_program_alpha_ca_second] = "       frag_color = source * mask;\n",
    608     [glamor_program_alpha_dual_blend] = "      color0 = source * mask;\n"
    609                                         "      color1 = source.a * mask;\n",
    610     [glamor_program_alpha_dual_blend_gles2] = " gl_FragColor = source * mask;\n"
    611                                               " gl_SecondaryFragColorEXT = source.a * mask;\n"
    612 };
    613 
    614 static Bool
    615 glamor_setup_one_program_render(ScreenPtr               screen,
    616                                 glamor_program          *prog,
    617                                 glamor_program_source   source_type,
    618                                 glamor_program_alpha    alpha,
    619                                 const glamor_facet      *prim,
    620                                 const char              *defines)
    621 {
    622     if (prog->failed)
    623         return FALSE;
    624 
    625     if (!prog->prog) {
    626         const glamor_facet      *fill = glamor_facet_source[source_type];
    627 
    628         if (!fill)
    629             return FALSE;
    630 
    631         prog->alpha = alpha;
    632         if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines))
    633             return FALSE;
    634     }
    635 
    636     return TRUE;
    637 }
    638 
    639 glamor_program *
    640 glamor_setup_program_render(CARD8                 op,
    641                             PicturePtr            src,
    642                             PicturePtr            mask,
    643                             PicturePtr            dst,
    644                             glamor_program_render *program_render,
    645                             const glamor_facet    *prim,
    646                             const char            *defines)
    647 {
    648     ScreenPtr                   screen = dst->pDrawable->pScreen;
    649     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    650     glamor_program_alpha        alpha;
    651     glamor_program_source       source_type;
    652     glamor_program              *prog;
    653 
    654     if (op > ARRAY_SIZE(composite_op_info))
    655         return NULL;
    656 
    657     if (glamor_is_component_alpha(mask)) {
    658         if (glamor_priv->has_dual_blend) {
    659             alpha = glamor_glsl_has_ints(glamor_priv) ?
    660                     glamor_program_alpha_dual_blend :
    661                     glamor_program_alpha_dual_blend_gles2;
    662         } else {
    663             /* This only works for PictOpOver */
    664             if (op != PictOpOver)
    665                 return NULL;
    666 
    667             alpha = glamor_program_alpha_ca_first;
    668         }
    669     } else
    670         alpha = glamor_program_alpha_normal;
    671 
    672     if (src->pDrawable) {
    673 
    674         /* Can't do transforms, alphamaps or sourcing from non-pixmaps yet */
    675         if (src->transform || src->alphaMap || src->pDrawable->type != DRAWABLE_PIXMAP)
    676             return NULL;
    677 
    678         if (src->pDrawable->width == 1 && src->pDrawable->height == 1 && src->repeat)
    679             source_type = glamor_program_source_1x1_picture;
    680         else
    681             source_type = glamor_program_source_picture;
    682     } else {
    683         SourcePictPtr   sp = src->pSourcePict;
    684         if (!sp)
    685             return NULL;
    686         switch (sp->type) {
    687         case SourcePictTypeSolidFill:
    688             source_type = glamor_program_source_solid;
    689             break;
    690         default:
    691             return NULL;
    692         }
    693     }
    694 
    695     prog = &program_render->progs[source_type][alpha];
    696     if (!glamor_setup_one_program_render(screen, prog, source_type, alpha, prim, defines))
    697         return NULL;
    698 
    699     if (alpha == glamor_program_alpha_ca_first) {
    700 
    701 	  /* Make sure we can also build the second program before
    702 	   * deciding to use this path.
    703 	   */
    704 	  if (!glamor_setup_one_program_render(screen,
    705 					       &program_render->progs[source_type][glamor_program_alpha_ca_second],
    706 					       source_type, glamor_program_alpha_ca_second, prim,
    707 					       defines))
    708 	      return NULL;
    709     }
    710     return prog;
    711 }
    712 
    713 Bool
    714 glamor_use_program_render(glamor_program        *prog,
    715                           CARD8                 op,
    716                           PicturePtr            src,
    717                           PicturePtr            dst)
    718 {
    719     glUseProgram(prog->prog);
    720 
    721     if (prog->prim_use_render && !prog->prim_use_render(op, src, dst, prog))
    722         return FALSE;
    723 
    724     if (prog->fill_use_render && !prog->fill_use_render(op, src, dst, prog))
    725         return FALSE;
    726     return TRUE;
    727 }
    728