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