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