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