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