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