1/* 2 * Copyright © 2009 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 * Authors: 24 * Eric Anholt <eric@anholt.net> 25 * Zhigang Gong <zhigang.gong@linux.intel.com> 26 * Junyan He <junyan.he@linux.intel.com> 27 * 28 */ 29 30/** @file glamor_render.c 31 * 32 * Render acceleration implementation 33 */ 34 35#include "glamor_priv.h" 36 37#include "mipict.h" 38#include "fbpict.h" 39#if 0 40//#define DEBUGF(str, ...) do {} while(0) 41#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__) 42//#define DEBUGRegionPrint(x) do {} while (0) 43#define DEBUGRegionPrint RegionPrint 44#endif 45 46static struct blendinfo composite_op_info[] = { 47 [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO}, 48 [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO}, 49 [PictOpDst] = {0, 0, GL_ZERO, GL_ONE}, 50 [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, 51 [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE}, 52 [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO}, 53 [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA}, 54 [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO}, 55 [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA}, 56 [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, 57 [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA}, 58 [PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, 59 [PictOpAdd] = {0, 0, GL_ONE, GL_ONE}, 60}; 61 62#define RepeatFix 10 63static GLuint 64glamor_create_composite_fs(struct shader_key *key) 65{ 66 const char *repeat_define = 67 "#define RepeatNone 0\n" 68 "#define RepeatNormal 1\n" 69 "#define RepeatPad 2\n" 70 "#define RepeatReflect 3\n" 71 "#define RepeatFix 10\n" 72 "uniform int source_repeat_mode;\n" 73 "uniform int mask_repeat_mode;\n"; 74 const char *relocate_texture = 75 "vec2 rel_tex_coord(vec2 texture, vec4 wh, int repeat) \n" 76 "{\n" 77 " vec2 rel_tex; \n" 78 " rel_tex = texture * wh.xy; \n" 79 " if (repeat == RepeatFix + RepeatNone)\n" 80 " return rel_tex; \n" 81 " else if (repeat == RepeatFix + RepeatNormal) \n" 82 " rel_tex = floor(rel_tex) + (fract(rel_tex) / wh.xy); \n" 83 " else if (repeat == RepeatFix + RepeatPad) { \n" 84 " if (rel_tex.x >= 1.0) \n" 85 " rel_tex.x = 1.0 - wh.z * wh.x / 2.; \n" 86 " else if (rel_tex.x < 0.0) \n" 87 " rel_tex.x = 0.0; \n" 88 " if (rel_tex.y >= 1.0) \n" 89 " rel_tex.y = 1.0 - wh.w * wh.y / 2.; \n" 90 " else if (rel_tex.y < 0.0) \n" 91 " rel_tex.y = 0.0; \n" 92 " rel_tex = rel_tex / wh.xy; \n" 93 " } else if (repeat == RepeatFix + RepeatReflect) {\n" 94 " if ((1.0 - mod(abs(floor(rel_tex.x)), 2.0)) < 0.001)\n" 95 " rel_tex.x = 2.0 - (1.0 - fract(rel_tex.x)) / wh.x;\n" 96 " else \n" 97 " rel_tex.x = fract(rel_tex.x) / wh.x;\n" 98 " if ((1.0 - mod(abs(floor(rel_tex.y)), 2.0)) < 0.001)\n" 99 " rel_tex.y = 2.0 - (1.0 - fract(rel_tex.y)) / wh.y;\n" 100 " else \n" 101 " rel_tex.y = fract(rel_tex.y) / wh.y;\n" 102 " } \n" 103 " return rel_tex; \n" 104 "}\n"; 105 /* The texture and the pixmap size is not match eaxctly, so can't sample it directly. 106 * rel_sampler will recalculate the texture coords.*/ 107 const char *rel_sampler = 108 " vec4 rel_sampler_rgba(sampler2D tex_image, vec2 tex, vec4 wh, int repeat)\n" 109 "{\n" 110 " if (repeat >= RepeatFix) {\n" 111 " tex = rel_tex_coord(tex, wh, repeat);\n" 112 " if (repeat == RepeatFix + RepeatNone) {\n" 113 " if (tex.x < 0.0 || tex.x >= 1.0 || \n" 114 " tex.y < 0.0 || tex.y >= 1.0)\n" 115 " return vec4(0.0, 0.0, 0.0, 0.0);\n" 116 " tex = (fract(tex) / wh.xy);\n" 117 " }\n" 118 " }\n" 119 " return texture2D(tex_image, tex);\n" 120 "}\n" 121 " vec4 rel_sampler_rgbx(sampler2D tex_image, vec2 tex, vec4 wh, int repeat)\n" 122 "{\n" 123 " if (repeat >= RepeatFix) {\n" 124 " tex = rel_tex_coord(tex, wh, repeat);\n" 125 " if (repeat == RepeatFix + RepeatNone) {\n" 126 " if (tex.x < 0.0 || tex.x >= 1.0 || \n" 127 " tex.y < 0.0 || tex.y >= 1.0)\n" 128 " return vec4(0.0, 0.0, 0.0, 0.0);\n" 129 " tex = (fract(tex) / wh.xy);\n" 130 " }\n" 131 " }\n" 132 " return vec4(texture2D(tex_image, tex).rgb, 1.0);\n" 133 "}\n"; 134 135 const char *source_solid_fetch = 136 "uniform vec4 source;\n" 137 "vec4 get_source()\n" 138 "{\n" 139 " return source;\n" 140 "}\n"; 141 const char *source_alpha_pixmap_fetch = 142 "varying vec2 source_texture;\n" 143 "uniform sampler2D source_sampler;\n" 144 "uniform vec4 source_wh;" 145 "vec4 get_source()\n" 146 "{\n" 147 " return rel_sampler_rgba(source_sampler, source_texture,\n" 148 " source_wh, source_repeat_mode);\n" 149 "}\n"; 150 const char *source_pixmap_fetch = 151 "varying vec2 source_texture;\n" 152 "uniform sampler2D source_sampler;\n" 153 "uniform vec4 source_wh;\n" 154 "vec4 get_source()\n" 155 "{\n" 156 " return rel_sampler_rgbx(source_sampler, source_texture,\n" 157 " source_wh, source_repeat_mode);\n" 158 "}\n"; 159 const char *mask_none = 160 "vec4 get_mask()\n" 161 "{\n" 162 " return vec4(0.0, 0.0, 0.0, 1.0);\n" 163 "}\n"; 164 const char *mask_solid_fetch = 165 "uniform vec4 mask;\n" 166 "vec4 get_mask()\n" 167 "{\n" 168 " return mask;\n" 169 "}\n"; 170 const char *mask_alpha_pixmap_fetch = 171 "varying vec2 mask_texture;\n" 172 "uniform sampler2D mask_sampler;\n" 173 "uniform vec4 mask_wh;\n" 174 "vec4 get_mask()\n" 175 "{\n" 176 " return rel_sampler_rgba(mask_sampler, mask_texture,\n" 177 " mask_wh, mask_repeat_mode);\n" 178 "}\n"; 179 const char *mask_pixmap_fetch = 180 "varying vec2 mask_texture;\n" 181 "uniform sampler2D mask_sampler;\n" 182 "uniform vec4 mask_wh;\n" 183 "vec4 get_mask()\n" 184 "{\n" 185 " return rel_sampler_rgbx(mask_sampler, mask_texture,\n" 186 " mask_wh, mask_repeat_mode);\n" 187 "}\n"; 188 189 const char *dest_swizzle_default = 190 "vec4 dest_swizzle(vec4 color)\n" 191 "{" 192 " return color;" 193 "}"; 194 const char *dest_swizzle_alpha_to_red = 195 "vec4 dest_swizzle(vec4 color)\n" 196 "{" 197 " float undef;\n" 198 " return vec4(color.a, undef, undef, undef);" 199 "}"; 200 201 const char *in_normal = 202 "void main()\n" 203 "{\n" 204 " gl_FragColor = dest_swizzle(get_source() * get_mask().a);\n" 205 "}\n"; 206 const char *in_ca_source = 207 "void main()\n" 208 "{\n" 209 " gl_FragColor = dest_swizzle(get_source() * get_mask());\n" 210 "}\n"; 211 const char *in_ca_alpha = 212 "void main()\n" 213 "{\n" 214 " gl_FragColor = dest_swizzle(get_source().a * get_mask());\n" 215 "}\n"; 216 const char *in_ca_dual_blend = 217 "out vec4 color0;\n" 218 "out vec4 color1;\n" 219 "void main()\n" 220 "{\n" 221 " color0 = dest_swizzle(get_source() * get_mask());\n" 222 " color1 = dest_swizzle(get_source().a * get_mask());\n" 223 "}\n"; 224 const char *header_ca_dual_blend = 225 "#version 130\n"; 226 227 char *source; 228 const char *source_fetch; 229 const char *mask_fetch = ""; 230 const char *in; 231 const char *header; 232 const char *header_norm = ""; 233 const char *dest_swizzle; 234 GLuint prog; 235 236 switch (key->source) { 237 case SHADER_SOURCE_SOLID: 238 source_fetch = source_solid_fetch; 239 break; 240 case SHADER_SOURCE_TEXTURE_ALPHA: 241 source_fetch = source_alpha_pixmap_fetch; 242 break; 243 case SHADER_SOURCE_TEXTURE: 244 source_fetch = source_pixmap_fetch; 245 break; 246 default: 247 FatalError("Bad composite shader source"); 248 } 249 250 switch (key->mask) { 251 case SHADER_MASK_NONE: 252 mask_fetch = mask_none; 253 break; 254 case SHADER_MASK_SOLID: 255 mask_fetch = mask_solid_fetch; 256 break; 257 case SHADER_MASK_TEXTURE_ALPHA: 258 mask_fetch = mask_alpha_pixmap_fetch; 259 break; 260 case SHADER_MASK_TEXTURE: 261 mask_fetch = mask_pixmap_fetch; 262 break; 263 default: 264 FatalError("Bad composite shader mask"); 265 } 266 267 /* If we're storing to an a8 texture but our texture format is 268 * GL_RED because of a core context, then we need to make sure to 269 * put the alpha into the red channel. 270 */ 271 switch (key->dest_swizzle) { 272 case SHADER_DEST_SWIZZLE_DEFAULT: 273 dest_swizzle = dest_swizzle_default; 274 break; 275 case SHADER_DEST_SWIZZLE_ALPHA_TO_RED: 276 dest_swizzle = dest_swizzle_alpha_to_red; 277 break; 278 default: 279 FatalError("Bad composite shader dest swizzle"); 280 } 281 282 header = header_norm; 283 switch (key->in) { 284 case glamor_program_alpha_normal: 285 in = in_normal; 286 break; 287 case glamor_program_alpha_ca_first: 288 in = in_ca_source; 289 break; 290 case glamor_program_alpha_ca_second: 291 in = in_ca_alpha; 292 break; 293 case glamor_program_alpha_dual_blend: 294 in = in_ca_dual_blend; 295 header = header_ca_dual_blend; 296 break; 297 default: 298 FatalError("Bad composite IN type"); 299 } 300 301 XNFasprintf(&source, 302 "%s" 303 GLAMOR_DEFAULT_PRECISION 304 "%s%s%s%s%s%s%s", header, repeat_define, relocate_texture, 305 rel_sampler, source_fetch, mask_fetch, dest_swizzle, in); 306 307 prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, source); 308 free(source); 309 310 return prog; 311} 312 313static GLuint 314glamor_create_composite_vs(struct shader_key *key) 315{ 316 const char *main_opening = 317 "attribute vec4 v_position;\n" 318 "attribute vec4 v_texcoord0;\n" 319 "attribute vec4 v_texcoord1;\n" 320 "varying vec2 source_texture;\n" 321 "varying vec2 mask_texture;\n" 322 "void main()\n" 323 "{\n" 324 " gl_Position = v_position;\n"; 325 const char *source_coords = " source_texture = v_texcoord0.xy;\n"; 326 const char *mask_coords = " mask_texture = v_texcoord1.xy;\n"; 327 const char *main_closing = "}\n"; 328 const char *source_coords_setup = ""; 329 const char *mask_coords_setup = ""; 330 char *source; 331 GLuint prog; 332 333 if (key->source != SHADER_SOURCE_SOLID) 334 source_coords_setup = source_coords; 335 336 if (key->mask != SHADER_MASK_NONE && key->mask != SHADER_MASK_SOLID) 337 mask_coords_setup = mask_coords; 338 339 XNFasprintf(&source, 340 "%s%s%s%s", 341 main_opening, 342 source_coords_setup, mask_coords_setup, main_closing); 343 344 prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, source); 345 free(source); 346 347 return prog; 348} 349 350static void 351glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key, 352 glamor_composite_shader *shader) 353{ 354 GLuint vs, fs, prog; 355 GLint source_sampler_uniform_location, mask_sampler_uniform_location; 356 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 357 358 glamor_make_current(glamor_priv); 359 vs = glamor_create_composite_vs(key); 360 if (vs == 0) 361 return; 362 fs = glamor_create_composite_fs(key); 363 if (fs == 0) 364 return; 365 366 prog = glCreateProgram(); 367 glAttachShader(prog, vs); 368 glAttachShader(prog, fs); 369 370 glBindAttribLocation(prog, GLAMOR_VERTEX_POS, "v_position"); 371 glBindAttribLocation(prog, GLAMOR_VERTEX_SOURCE, "v_texcoord0"); 372 glBindAttribLocation(prog, GLAMOR_VERTEX_MASK, "v_texcoord1"); 373 374 if (key->in == glamor_program_alpha_dual_blend) { 375 glBindFragDataLocationIndexed(prog, 0, 0, "color0"); 376 glBindFragDataLocationIndexed(prog, 0, 1, "color1"); 377 } 378 glamor_link_glsl_prog(screen, prog, "composite"); 379 380 shader->prog = prog; 381 382 glUseProgram(prog); 383 384 if (key->source == SHADER_SOURCE_SOLID) { 385 shader->source_uniform_location = glGetUniformLocation(prog, "source"); 386 } 387 else { 388 source_sampler_uniform_location = 389 glGetUniformLocation(prog, "source_sampler"); 390 glUniform1i(source_sampler_uniform_location, 0); 391 shader->source_wh = glGetUniformLocation(prog, "source_wh"); 392 shader->source_repeat_mode = 393 glGetUniformLocation(prog, "source_repeat_mode"); 394 } 395 396 if (key->mask != SHADER_MASK_NONE) { 397 if (key->mask == SHADER_MASK_SOLID) { 398 shader->mask_uniform_location = glGetUniformLocation(prog, "mask"); 399 } 400 else { 401 mask_sampler_uniform_location = 402 glGetUniformLocation(prog, "mask_sampler"); 403 glUniform1i(mask_sampler_uniform_location, 1); 404 shader->mask_wh = glGetUniformLocation(prog, "mask_wh"); 405 shader->mask_repeat_mode = 406 glGetUniformLocation(prog, "mask_repeat_mode"); 407 } 408 } 409} 410 411static glamor_composite_shader * 412glamor_lookup_composite_shader(ScreenPtr screen, struct 413 shader_key 414 *key) 415{ 416 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 417 glamor_composite_shader *shader; 418 419 shader = &glamor_priv->composite_shader[key->source][key->mask][key->in][key->dest_swizzle]; 420 if (shader->prog == 0) 421 glamor_create_composite_shader(screen, key, shader); 422 423 return shader; 424} 425 426static GLenum 427glamor_translate_blend_alpha_to_red(GLenum blend) 428{ 429 switch (blend) { 430 case GL_SRC_ALPHA: 431 return GL_SRC_COLOR; 432 case GL_DST_ALPHA: 433 return GL_DST_COLOR; 434 case GL_ONE_MINUS_SRC_ALPHA: 435 return GL_ONE_MINUS_SRC_COLOR; 436 case GL_ONE_MINUS_DST_ALPHA: 437 return GL_ONE_MINUS_DST_COLOR; 438 default: 439 return blend; 440 } 441} 442 443static Bool 444glamor_set_composite_op(ScreenPtr screen, 445 CARD8 op, struct blendinfo *op_info_result, 446 PicturePtr dest, PicturePtr mask, 447 enum ca_state ca_state, 448 struct shader_key *key) 449{ 450 GLenum source_blend, dest_blend; 451 struct blendinfo *op_info; 452 453 if (op >= ARRAY_SIZE(composite_op_info)) { 454 glamor_fallback("unsupported render op %d \n", op); 455 return GL_FALSE; 456 } 457 458 op_info = &composite_op_info[op]; 459 460 source_blend = op_info->source_blend; 461 dest_blend = op_info->dest_blend; 462 463 /* If there's no dst alpha channel, adjust the blend op so that we'll treat 464 * it as always 1. 465 */ 466 if (PICT_FORMAT_A(dest->format) == 0 && op_info->dest_alpha) { 467 if (source_blend == GL_DST_ALPHA) 468 source_blend = GL_ONE; 469 else if (source_blend == GL_ONE_MINUS_DST_ALPHA) 470 source_blend = GL_ZERO; 471 } 472 473 /* Set up the source alpha value for blending in component alpha mode. */ 474 if (ca_state == CA_DUAL_BLEND) { 475 switch (dest_blend) { 476 case GL_SRC_ALPHA: 477 dest_blend = GL_SRC1_COLOR; 478 break; 479 case GL_ONE_MINUS_SRC_ALPHA: 480 dest_blend = GL_ONE_MINUS_SRC1_COLOR; 481 break; 482 } 483 } else if (mask && mask->componentAlpha 484 && PICT_FORMAT_RGB(mask->format) != 0 && op_info->source_alpha) { 485 switch (dest_blend) { 486 case GL_SRC_ALPHA: 487 dest_blend = GL_SRC_COLOR; 488 break; 489 case GL_ONE_MINUS_SRC_ALPHA: 490 dest_blend = GL_ONE_MINUS_SRC_COLOR; 491 break; 492 } 493 } 494 495 /* If we're outputting our alpha to the red channel, then any 496 * reads of alpha for blending need to come from the red channel. 497 */ 498 if (key->dest_swizzle == SHADER_DEST_SWIZZLE_ALPHA_TO_RED) { 499 source_blend = glamor_translate_blend_alpha_to_red(source_blend); 500 dest_blend = glamor_translate_blend_alpha_to_red(dest_blend); 501 } 502 503 op_info_result->source_blend = source_blend; 504 op_info_result->dest_blend = dest_blend; 505 op_info_result->source_alpha = op_info->source_alpha; 506 op_info_result->dest_alpha = op_info->dest_alpha; 507 508 return TRUE; 509} 510 511static void 512glamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit, 513 PicturePtr picture, 514 PixmapPtr pixmap, 515 GLuint wh_location, GLuint repeat_location, 516 glamor_pixmap_private *dest_priv) 517{ 518 glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 519 glamor_pixmap_fbo *fbo = pixmap_priv->fbo; 520 float wh[4]; 521 int repeat_type; 522 523 glamor_make_current(glamor_priv); 524 525 /* The red channel swizzling doesn't depend on whether we're using 526 * 'fbo' as source or mask as we must have the same answer in case 527 * the same fbo is being used for both. That means the mask 528 * channel will sometimes get red bits in the R channel, and 529 * sometimes get zero bits in the R channel, which is harmless. 530 */ 531 glamor_bind_texture(glamor_priv, GL_TEXTURE0 + unit, fbo, 532 dest_priv->fbo->is_red); 533 repeat_type = picture->repeatType; 534 switch (picture->repeatType) { 535 case RepeatNone: 536 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); 537 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); 538 break; 539 case RepeatNormal: 540 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 541 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 542 break; 543 case RepeatPad: 544 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 545 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 546 break; 547 case RepeatReflect: 548 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); 549 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); 550 break; 551 } 552 553 switch (picture->filter) { 554 default: 555 case PictFilterFast: 556 case PictFilterNearest: 557 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 558 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 559 break; 560 case PictFilterGood: 561 case PictFilterBest: 562 case PictFilterBilinear: 563 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 564 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 565 break; 566 } 567 568 /* Handle RepeatNone in the shader when the source is missing the 569 * alpha channel, as GL will return an alpha for 1 if the texture 570 * is RGB (no alpha), which we use for 16bpp textures. 571 */ 572 if (glamor_pixmap_priv_is_large(pixmap_priv) || 573 (!PICT_FORMAT_A(picture->format) && 574 repeat_type == RepeatNone && picture->transform)) { 575 glamor_pixmap_fbo_fix_wh_ratio(wh, pixmap, pixmap_priv); 576 glUniform4fv(wh_location, 1, wh); 577 578 repeat_type += RepeatFix; 579 } 580 581 glUniform1i(repeat_location, repeat_type); 582} 583 584static void 585glamor_set_composite_solid(float *color, GLint uniform_location) 586{ 587 glUniform4fv(uniform_location, 1, color); 588} 589 590static char 591glamor_get_picture_location(PicturePtr picture) 592{ 593 if (picture == NULL) 594 return ' '; 595 596 if (picture->pDrawable == NULL) { 597 switch (picture->pSourcePict->type) { 598 case SourcePictTypeSolidFill: 599 return 'c'; 600 case SourcePictTypeLinear: 601 return 'l'; 602 case SourcePictTypeRadial: 603 return 'r'; 604 default: 605 return '?'; 606 } 607 } 608 return glamor_get_drawable_location(picture->pDrawable); 609} 610 611static void * 612glamor_setup_composite_vbo(ScreenPtr screen, int n_verts) 613{ 614 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 615 int vert_size; 616 char *vbo_offset; 617 float *vb; 618 619 glamor_priv->render_nr_quads = 0; 620 glamor_priv->vb_stride = 2 * sizeof(float); 621 if (glamor_priv->has_source_coords) 622 glamor_priv->vb_stride += 2 * sizeof(float); 623 if (glamor_priv->has_mask_coords) 624 glamor_priv->vb_stride += 2 * sizeof(float); 625 626 vert_size = n_verts * glamor_priv->vb_stride; 627 628 glamor_make_current(glamor_priv); 629 vb = glamor_get_vbo_space(screen, vert_size, &vbo_offset); 630 631 glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE, 632 glamor_priv->vb_stride, vbo_offset); 633 glEnableVertexAttribArray(GLAMOR_VERTEX_POS); 634 635 if (glamor_priv->has_source_coords) { 636 glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, 637 GL_FLOAT, GL_FALSE, 638 glamor_priv->vb_stride, 639 vbo_offset + 2 * sizeof(float)); 640 glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); 641 } 642 643 if (glamor_priv->has_mask_coords) { 644 glVertexAttribPointer(GLAMOR_VERTEX_MASK, 2, GL_FLOAT, GL_FALSE, 645 glamor_priv->vb_stride, 646 vbo_offset + (glamor_priv->has_source_coords ? 647 4 : 2) * sizeof(float)); 648 glEnableVertexAttribArray(GLAMOR_VERTEX_MASK); 649 } 650 651 return vb; 652} 653 654static void 655glamor_flush_composite_rects(ScreenPtr screen) 656{ 657 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 658 659 glamor_make_current(glamor_priv); 660 661 if (!glamor_priv->render_nr_quads) 662 return; 663 664 glamor_glDrawArrays_GL_QUADS(glamor_priv, glamor_priv->render_nr_quads); 665} 666 667static const int pict_format_combine_tab[][3] = { 668 {PICT_TYPE_ARGB, PICT_TYPE_A, PICT_TYPE_ARGB}, 669 {PICT_TYPE_ABGR, PICT_TYPE_A, PICT_TYPE_ABGR}, 670}; 671 672static Bool 673combine_pict_format(PictFormatShort * des, const PictFormatShort src, 674 const PictFormatShort mask, glamor_program_alpha in_ca) 675{ 676 PictFormatShort new_vis; 677 int src_type, mask_type, src_bpp; 678 int i; 679 680 if (src == mask) { 681 *des = src; 682 return TRUE; 683 } 684 src_bpp = PICT_FORMAT_BPP(src); 685 686 assert(src_bpp == PICT_FORMAT_BPP(mask)); 687 688 new_vis = PICT_FORMAT_VIS(src) | PICT_FORMAT_VIS(mask); 689 690 switch (in_ca) { 691 case glamor_program_alpha_normal: 692 src_type = PICT_FORMAT_TYPE(src); 693 mask_type = PICT_TYPE_A; 694 break; 695 case glamor_program_alpha_ca_first: 696 src_type = PICT_FORMAT_TYPE(src); 697 mask_type = PICT_FORMAT_TYPE(mask); 698 break; 699 case glamor_program_alpha_ca_second: 700 src_type = PICT_TYPE_A; 701 mask_type = PICT_FORMAT_TYPE(mask); 702 break; 703 case glamor_program_alpha_dual_blend: 704 src_type = PICT_FORMAT_TYPE(src); 705 mask_type = PICT_FORMAT_TYPE(mask); 706 break; 707 default: 708 return FALSE; 709 } 710 711 if (src_type == mask_type) { 712 *des = PICT_VISFORMAT(src_bpp, src_type, new_vis); 713 return TRUE; 714 } 715 716 for (i = 0; i < ARRAY_SIZE(pict_format_combine_tab); i++) { 717 if ((src_type == pict_format_combine_tab[i][0] 718 && mask_type == pict_format_combine_tab[i][1]) 719 || (src_type == pict_format_combine_tab[i][1] 720 && mask_type == pict_format_combine_tab[i][0])) { 721 *des = PICT_VISFORMAT(src_bpp, pict_format_combine_tab[i] 722 [2], new_vis); 723 return TRUE; 724 } 725 } 726 return FALSE; 727} 728 729static void 730glamor_set_normalize_tcoords_generic(PixmapPtr pixmap, 731 glamor_pixmap_private *priv, 732 int repeat_type, 733 float *matrix, 734 float xscale, float yscale, 735 int x1, int y1, int x2, int y2, 736 float *texcoords, 737 int stride) 738{ 739 if (!matrix && repeat_type == RepeatNone) 740 glamor_set_normalize_tcoords_ext(priv, xscale, yscale, 741 x1, y1, 742 x2, y2, texcoords, stride); 743 else if (matrix && repeat_type == RepeatNone) 744 glamor_set_transformed_normalize_tcoords_ext(priv, matrix, xscale, 745 yscale, x1, y1, 746 x2, y2, 747 texcoords, stride); 748 else if (!matrix && repeat_type != RepeatNone) 749 glamor_set_repeat_normalize_tcoords_ext(pixmap, priv, repeat_type, 750 xscale, yscale, 751 x1, y1, 752 x2, y2, 753 texcoords, stride); 754 else if (matrix && repeat_type != RepeatNone) 755 glamor_set_repeat_transformed_normalize_tcoords_ext(pixmap, priv, repeat_type, 756 matrix, xscale, 757 yscale, x1, y1, x2, 758 y2, 759 texcoords, stride); 760} 761 762/** 763 * Returns whether the general composite path supports this picture 764 * format for a pixmap that is permanently stored in an FBO (as 765 * opposed to the dynamic upload path). 766 * 767 * We could support many more formats by using GL_ARB_texture_view to 768 * parse the same bits as different formats. For now, we only support 769 * tweaking whether we sample the alpha bits, or just force them to 1. 770 */ 771static Bool 772glamor_render_format_is_supported(PicturePtr picture) 773{ 774 PictFormatShort storage_format; 775 glamor_screen_private *glamor_priv; 776 struct glamor_format *f; 777 778 /* Source-only pictures should always work */ 779 if (!picture->pDrawable) 780 return TRUE; 781 782 glamor_priv = glamor_get_screen_private(picture->pDrawable->pScreen); 783 f = &glamor_priv->formats[picture->pDrawable->depth]; 784 785 if (!f->rendering_supported) 786 return FALSE; 787 788 storage_format = f->render_format; 789 790 switch (picture->format) { 791 case PICT_a2r10g10b10: 792 return storage_format == PICT_x2r10g10b10; 793 case PICT_a8r8g8b8: 794 case PICT_x8r8g8b8: 795 return storage_format == PICT_a8r8g8b8 || storage_format == PICT_x8r8g8b8; 796 case PICT_a1r5g5b5: 797 return storage_format == PICT_x1r5g5b5; 798 default: 799 return picture->format == storage_format; 800 } 801} 802 803static Bool 804glamor_composite_choose_shader(CARD8 op, 805 PicturePtr source, 806 PicturePtr mask, 807 PicturePtr dest, 808 PixmapPtr source_pixmap, 809 PixmapPtr mask_pixmap, 810 PixmapPtr dest_pixmap, 811 glamor_pixmap_private *source_pixmap_priv, 812 glamor_pixmap_private *mask_pixmap_priv, 813 glamor_pixmap_private *dest_pixmap_priv, 814 struct shader_key *s_key, 815 glamor_composite_shader ** shader, 816 struct blendinfo *op_info, 817 PictFormatShort *psaved_source_format, 818 enum ca_state ca_state) 819{ 820 ScreenPtr screen = dest->pDrawable->pScreen; 821 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 822 Bool source_needs_upload = FALSE; 823 Bool mask_needs_upload = FALSE; 824 PictFormatShort saved_source_format = 0; 825 struct shader_key key; 826 GLfloat source_solid_color[4]; 827 GLfloat mask_solid_color[4]; 828 Bool ret = FALSE; 829 830 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) { 831 glamor_fallback("dest has no fbo.\n"); 832 goto fail; 833 } 834 835 if (!glamor_render_format_is_supported(dest)) { 836 glamor_fallback("Unsupported dest picture format.\n"); 837 goto fail; 838 } 839 840 memset(&key, 0, sizeof(key)); 841 if (!source) { 842 key.source = SHADER_SOURCE_SOLID; 843 source_solid_color[0] = 0.0; 844 source_solid_color[1] = 0.0; 845 source_solid_color[2] = 0.0; 846 source_solid_color[3] = 0.0; 847 } 848 else if (!source->pDrawable) { 849 SourcePictPtr sp = source->pSourcePict; 850 if (sp->type == SourcePictTypeSolidFill) { 851 key.source = SHADER_SOURCE_SOLID; 852 glamor_get_rgba_from_color(&sp->solidFill.fullcolor, 853 source_solid_color); 854 } 855 else 856 goto fail; 857 } 858 else { 859 if (PICT_FORMAT_A(source->format)) 860 key.source = SHADER_SOURCE_TEXTURE_ALPHA; 861 else 862 key.source = SHADER_SOURCE_TEXTURE; 863 } 864 865 if (mask) { 866 if (!mask->pDrawable) { 867 SourcePictPtr sp = mask->pSourcePict; 868 if (sp->type == SourcePictTypeSolidFill) { 869 key.mask = SHADER_MASK_SOLID; 870 glamor_get_rgba_from_color(&sp->solidFill.fullcolor, 871 mask_solid_color); 872 } 873 else 874 goto fail; 875 } 876 else { 877 if (PICT_FORMAT_A(mask->format)) 878 key.mask = SHADER_MASK_TEXTURE_ALPHA; 879 else 880 key.mask = SHADER_MASK_TEXTURE; 881 } 882 883 if (!mask->componentAlpha) { 884 key.in = glamor_program_alpha_normal; 885 } 886 else { 887 if (op == PictOpClear) 888 key.mask = SHADER_MASK_NONE; 889 else if (glamor_priv->has_dual_blend) 890 key.in = glamor_program_alpha_dual_blend; 891 else if (op == PictOpSrc || op == PictOpAdd 892 || op == PictOpIn || op == PictOpOut 893 || op == PictOpOverReverse) 894 key.in = glamor_program_alpha_ca_second; 895 else if (op == PictOpOutReverse || op == PictOpInReverse) { 896 key.in = glamor_program_alpha_ca_first; 897 } 898 else { 899 glamor_fallback("Unsupported component alpha op: %d\n", op); 900 goto fail; 901 } 902 } 903 } 904 else { 905 key.mask = SHADER_MASK_NONE; 906 } 907 908 if (dest_pixmap->drawable.bitsPerPixel <= 8 && 909 glamor_priv->formats[8].format == GL_RED) { 910 key.dest_swizzle = SHADER_DEST_SWIZZLE_ALPHA_TO_RED; 911 } else { 912 key.dest_swizzle = SHADER_DEST_SWIZZLE_DEFAULT; 913 } 914 915 if (source && source->alphaMap) { 916 glamor_fallback("source alphaMap\n"); 917 goto fail; 918 } 919 if (mask && mask->alphaMap) { 920 glamor_fallback("mask alphaMap\n"); 921 goto fail; 922 } 923 924 if (key.source == SHADER_SOURCE_TEXTURE || 925 key.source == SHADER_SOURCE_TEXTURE_ALPHA) { 926 if (source_pixmap == dest_pixmap) { 927 /* XXX source and the dest share the same texture. 928 * Does it need special handle? */ 929 glamor_fallback("source == dest\n"); 930 } 931 if (source_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) { 932 source_needs_upload = TRUE; 933 } 934 } 935 936 if (key.mask == SHADER_MASK_TEXTURE || 937 key.mask == SHADER_MASK_TEXTURE_ALPHA) { 938 if (mask_pixmap == dest_pixmap) { 939 glamor_fallback("mask == dest\n"); 940 goto fail; 941 } 942 if (mask_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) { 943 mask_needs_upload = TRUE; 944 } 945 } 946 947 if (source_needs_upload && mask_needs_upload 948 && source_pixmap == mask_pixmap) { 949 950 if (source->format != mask->format) { 951 saved_source_format = source->format; 952 953 if (!combine_pict_format(&source->format, source->format, 954 mask->format, key.in)) { 955 glamor_fallback("combine source %x mask %x failed.\n", 956 source->format, mask->format); 957 goto fail; 958 } 959 960 /* XXX 961 * By default, glamor_upload_picture_to_texture will wire alpha to 1 962 * if one picture doesn't have alpha. So we don't do that again in 963 * rendering function. But here is a special case, as source and 964 * mask share the same texture but may have different formats. For 965 * example, source doesn't have alpha, but mask has alpha. Then the 966 * texture will have the alpha value for the mask. And will not wire 967 * to 1 for the source. In this case, we have to use different shader 968 * to wire the source's alpha to 1. 969 * 970 * But this may cause a potential problem if the source's repeat mode 971 * is REPEAT_NONE, and if the source is smaller than the dest, then 972 * for the region not covered by the source may be painted incorrectly. 973 * because we wire the alpha to 1. 974 * 975 **/ 976 if (!PICT_FORMAT_A(saved_source_format) 977 && PICT_FORMAT_A(mask->format)) 978 key.source = SHADER_SOURCE_TEXTURE; 979 980 if (!PICT_FORMAT_A(mask->format) 981 && PICT_FORMAT_A(saved_source_format)) 982 key.mask = SHADER_MASK_TEXTURE; 983 } 984 985 if (!glamor_upload_picture_to_texture(source)) { 986 glamor_fallback("Failed to upload source texture.\n"); 987 goto fail; 988 } 989 mask_needs_upload = FALSE; 990 } 991 else { 992 if (source_needs_upload) { 993 if (!glamor_upload_picture_to_texture(source)) { 994 glamor_fallback("Failed to upload source texture.\n"); 995 goto fail; 996 } 997 } else { 998 if (source && !glamor_render_format_is_supported(source)) { 999 glamor_fallback("Unsupported source picture format.\n"); 1000 goto fail; 1001 } 1002 } 1003 1004 if (mask_needs_upload) { 1005 if (!glamor_upload_picture_to_texture(mask)) { 1006 glamor_fallback("Failed to upload mask texture.\n"); 1007 goto fail; 1008 } 1009 } else if (mask) { 1010 if (!glamor_render_format_is_supported(mask)) { 1011 glamor_fallback("Unsupported mask picture format.\n"); 1012 goto fail; 1013 } 1014 } 1015 } 1016 1017 /* If the source and mask are two differently-formatted views of 1018 * the same pixmap bits, and the pixmap was already uploaded (so 1019 * the dynamic code above doesn't apply), then fall back to 1020 * software. We should use texture views to fix this properly. 1021 */ 1022 if (source_pixmap && source_pixmap == mask_pixmap && 1023 source->format != mask->format) { 1024 goto fail; 1025 } 1026 1027 if (!glamor_set_composite_op(screen, op, op_info, dest, mask, ca_state, 1028 &key)) { 1029 goto fail; 1030 } 1031 1032 *shader = glamor_lookup_composite_shader(screen, &key); 1033 if ((*shader)->prog == 0) { 1034 glamor_fallback("no shader program for this render acccel mode\n"); 1035 goto fail; 1036 } 1037 1038 if (key.source == SHADER_SOURCE_SOLID) 1039 memcpy(&(*shader)->source_solid_color[0], 1040 source_solid_color, 4 * sizeof(float)); 1041 else { 1042 (*shader)->source_pixmap = source_pixmap; 1043 (*shader)->source = source; 1044 } 1045 1046 if (key.mask == SHADER_MASK_SOLID) 1047 memcpy(&(*shader)->mask_solid_color[0], 1048 mask_solid_color, 4 * sizeof(float)); 1049 else { 1050 (*shader)->mask_pixmap = mask_pixmap; 1051 (*shader)->mask = mask; 1052 } 1053 1054 ret = TRUE; 1055 memcpy(s_key, &key, sizeof(key)); 1056 *psaved_source_format = saved_source_format; 1057 goto done; 1058 1059 fail: 1060 if (saved_source_format) 1061 source->format = saved_source_format; 1062 done: 1063 return ret; 1064} 1065 1066static void 1067glamor_composite_set_shader_blend(glamor_screen_private *glamor_priv, 1068 glamor_pixmap_private *dest_priv, 1069 struct shader_key *key, 1070 glamor_composite_shader *shader, 1071 struct blendinfo *op_info) 1072{ 1073 glamor_make_current(glamor_priv); 1074 glUseProgram(shader->prog); 1075 1076 if (key->source == SHADER_SOURCE_SOLID) { 1077 glamor_set_composite_solid(shader->source_solid_color, 1078 shader->source_uniform_location); 1079 } 1080 else { 1081 glamor_set_composite_texture(glamor_priv, 0, 1082 shader->source, 1083 shader->source_pixmap, shader->source_wh, 1084 shader->source_repeat_mode, 1085 dest_priv); 1086 } 1087 1088 if (key->mask != SHADER_MASK_NONE) { 1089 if (key->mask == SHADER_MASK_SOLID) { 1090 glamor_set_composite_solid(shader->mask_solid_color, 1091 shader->mask_uniform_location); 1092 } 1093 else { 1094 glamor_set_composite_texture(glamor_priv, 1, 1095 shader->mask, 1096 shader->mask_pixmap, shader->mask_wh, 1097 shader->mask_repeat_mode, 1098 dest_priv); 1099 } 1100 } 1101 1102 if (!glamor_priv->is_gles) 1103 glDisable(GL_COLOR_LOGIC_OP); 1104 1105 if (op_info->source_blend == GL_ONE && op_info->dest_blend == GL_ZERO) { 1106 glDisable(GL_BLEND); 1107 } 1108 else { 1109 glEnable(GL_BLEND); 1110 glBlendFunc(op_info->source_blend, op_info->dest_blend); 1111 } 1112} 1113 1114static Bool 1115glamor_composite_with_shader(CARD8 op, 1116 PicturePtr source, 1117 PicturePtr mask, 1118 PicturePtr dest, 1119 PixmapPtr source_pixmap, 1120 PixmapPtr mask_pixmap, 1121 PixmapPtr dest_pixmap, 1122 glamor_pixmap_private *source_pixmap_priv, 1123 glamor_pixmap_private *mask_pixmap_priv, 1124 glamor_pixmap_private *dest_pixmap_priv, 1125 int nrect, glamor_composite_rect_t *rects, 1126 enum ca_state ca_state) 1127{ 1128 ScreenPtr screen = dest->pDrawable->pScreen; 1129 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 1130 GLfloat dst_xscale, dst_yscale; 1131 GLfloat mask_xscale = 1, mask_yscale = 1, src_xscale = 1, src_yscale = 1; 1132 struct shader_key key, key_ca; 1133 int dest_x_off, dest_y_off; 1134 int source_x_off, source_y_off; 1135 int mask_x_off, mask_y_off; 1136 PictFormatShort saved_source_format = 0; 1137 float src_matrix[9], mask_matrix[9]; 1138 float *psrc_matrix = NULL, *pmask_matrix = NULL; 1139 int nrect_max; 1140 Bool ret = FALSE; 1141 glamor_composite_shader *shader = NULL, *shader_ca = NULL; 1142 struct blendinfo op_info, op_info_ca; 1143 1144 if (!glamor_composite_choose_shader(op, source, mask, dest, 1145 source_pixmap, mask_pixmap, dest_pixmap, 1146 source_pixmap_priv, mask_pixmap_priv, 1147 dest_pixmap_priv, 1148 &key, &shader, &op_info, 1149 &saved_source_format, ca_state)) { 1150 glamor_fallback("glamor_composite_choose_shader failed\n"); 1151 goto fail; 1152 } 1153 if (ca_state == CA_TWO_PASS) { 1154 if (!glamor_composite_choose_shader(PictOpAdd, source, mask, dest, 1155 source_pixmap, mask_pixmap, dest_pixmap, 1156 source_pixmap_priv, 1157 mask_pixmap_priv, dest_pixmap_priv, 1158 &key_ca, &shader_ca, &op_info_ca, 1159 &saved_source_format, ca_state)) { 1160 glamor_fallback("glamor_composite_choose_shader failed\n"); 1161 goto fail; 1162 } 1163 } 1164 1165 glamor_make_current(glamor_priv); 1166 1167 glamor_set_destination_pixmap_priv_nc(glamor_priv, dest_pixmap, dest_pixmap_priv); 1168 glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, &key, shader, &op_info); 1169 glamor_set_alu(screen, GXcopy); 1170 1171 glamor_priv->has_source_coords = key.source != SHADER_SOURCE_SOLID; 1172 glamor_priv->has_mask_coords = (key.mask != SHADER_MASK_NONE && 1173 key.mask != SHADER_MASK_SOLID); 1174 1175 dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable); 1176 dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); 1177 glamor_get_drawable_deltas(dest->pDrawable, dest_pixmap, 1178 &dest_x_off, &dest_y_off); 1179 pixmap_priv_get_dest_scale(dest_pixmap, dest_pixmap_priv, &dst_xscale, &dst_yscale); 1180 1181 if (glamor_priv->has_source_coords) { 1182 glamor_get_drawable_deltas(source->pDrawable, 1183 source_pixmap, &source_x_off, &source_y_off); 1184 pixmap_priv_get_scale(source_pixmap_priv, &src_xscale, &src_yscale); 1185 if (source->transform) { 1186 psrc_matrix = src_matrix; 1187 glamor_picture_get_matrixf(source, psrc_matrix); 1188 } 1189 } 1190 1191 if (glamor_priv->has_mask_coords) { 1192 glamor_get_drawable_deltas(mask->pDrawable, mask_pixmap, 1193 &mask_x_off, &mask_y_off); 1194 pixmap_priv_get_scale(mask_pixmap_priv, &mask_xscale, &mask_yscale); 1195 if (mask->transform) { 1196 pmask_matrix = mask_matrix; 1197 glamor_picture_get_matrixf(mask, pmask_matrix); 1198 } 1199 } 1200 1201 nrect_max = MIN(nrect, GLAMOR_COMPOSITE_VBO_VERT_CNT / 4); 1202 1203 if (nrect < 100) { 1204 BoxRec bounds = glamor_start_rendering_bounds(); 1205 1206 for (int i = 0; i < nrect; i++) { 1207 BoxRec box = { 1208 .x1 = rects[i].x_dst, 1209 .y1 = rects[i].y_dst, 1210 .x2 = rects[i].x_dst + rects[i].width, 1211 .y2 = rects[i].y_dst + rects[i].height, 1212 }; 1213 glamor_bounds_union_box(&bounds, &box); 1214 } 1215 1216 if (bounds.x1 >= bounds.x2 || bounds.y1 >= bounds.y2) 1217 goto disable_va; 1218 1219 glEnable(GL_SCISSOR_TEST); 1220 glScissor(bounds.x1 + dest_x_off, 1221 bounds.y1 + dest_y_off, 1222 bounds.x2 - bounds.x1, 1223 bounds.y2 - bounds.y1); 1224 } 1225 1226 while (nrect) { 1227 int mrect, rect_processed; 1228 int vb_stride; 1229 float *vertices; 1230 1231 mrect = nrect > nrect_max ? nrect_max : nrect; 1232 vertices = glamor_setup_composite_vbo(screen, mrect * 4); 1233 rect_processed = mrect; 1234 vb_stride = glamor_priv->vb_stride / sizeof(float); 1235 while (mrect--) { 1236 INT16 x_source; 1237 INT16 y_source; 1238 INT16 x_mask; 1239 INT16 y_mask; 1240 INT16 x_dest; 1241 INT16 y_dest; 1242 CARD16 width; 1243 CARD16 height; 1244 1245 x_dest = rects->x_dst + dest_x_off; 1246 y_dest = rects->y_dst + dest_y_off; 1247 x_source = rects->x_src + source_x_off; 1248 y_source = rects->y_src + source_y_off; 1249 x_mask = rects->x_mask + mask_x_off; 1250 y_mask = rects->y_mask + mask_y_off; 1251 width = rects->width; 1252 height = rects->height; 1253 1254 DEBUGF 1255 ("dest(%d,%d) source(%d %d) mask (%d %d), width %d height %d \n", 1256 x_dest, y_dest, x_source, y_source, x_mask, y_mask, width, 1257 height); 1258 1259 glamor_set_normalize_vcoords_ext(dest_pixmap_priv, dst_xscale, 1260 dst_yscale, x_dest, y_dest, 1261 x_dest + width, y_dest + height, 1262 vertices, 1263 vb_stride); 1264 vertices += 2; 1265 if (key.source != SHADER_SOURCE_SOLID) { 1266 glamor_set_normalize_tcoords_generic(source_pixmap, 1267 source_pixmap_priv, 1268 source->repeatType, 1269 psrc_matrix, src_xscale, 1270 src_yscale, x_source, 1271 y_source, x_source + width, 1272 y_source + height, 1273 vertices, vb_stride); 1274 vertices += 2; 1275 } 1276 1277 if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID) { 1278 glamor_set_normalize_tcoords_generic(mask_pixmap, 1279 mask_pixmap_priv, 1280 mask->repeatType, 1281 pmask_matrix, mask_xscale, 1282 mask_yscale, x_mask, 1283 y_mask, x_mask + width, 1284 y_mask + height, 1285 vertices, vb_stride); 1286 vertices += 2; 1287 } 1288 glamor_priv->render_nr_quads++; 1289 rects++; 1290 1291 /* We've incremented by one of our 4 verts, now do the other 3. */ 1292 vertices += 3 * vb_stride; 1293 } 1294 glamor_put_vbo_space(screen); 1295 glamor_flush_composite_rects(screen); 1296 nrect -= rect_processed; 1297 if (ca_state == CA_TWO_PASS) { 1298 glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, 1299 &key_ca, shader_ca, &op_info_ca); 1300 glamor_flush_composite_rects(screen); 1301 if (nrect) 1302 glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, 1303 &key, shader, &op_info); 1304 } 1305 } 1306 1307 glDisable(GL_SCISSOR_TEST); 1308disable_va: 1309 glDisableVertexAttribArray(GLAMOR_VERTEX_POS); 1310 glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); 1311 glDisableVertexAttribArray(GLAMOR_VERTEX_MASK); 1312 glDisable(GL_BLEND); 1313 DEBUGF("finish rendering.\n"); 1314 if (saved_source_format) 1315 source->format = saved_source_format; 1316 1317 ret = TRUE; 1318 1319fail: 1320 if (mask_pixmap && glamor_pixmap_is_memory(mask_pixmap)) 1321 glamor_pixmap_destroy_fbo(mask_pixmap); 1322 if (source_pixmap && glamor_pixmap_is_memory(source_pixmap)) 1323 glamor_pixmap_destroy_fbo(source_pixmap); 1324 1325 return ret; 1326} 1327 1328static PicturePtr 1329glamor_convert_gradient_picture(ScreenPtr screen, 1330 PicturePtr source, 1331 int x_source, 1332 int y_source, int width, int height) 1333{ 1334 PixmapPtr pixmap; 1335 PicturePtr dst = NULL; 1336 int error; 1337 PictFormatPtr pFormat; 1338 PictFormatShort format; 1339 1340 if (source->pDrawable) { 1341 pFormat = source->pFormat; 1342 format = pFormat->format; 1343 } else { 1344 format = PICT_a8r8g8b8; 1345 pFormat = PictureMatchFormat(screen, 32, format); 1346 } 1347 1348 if (!source->pDrawable) { 1349 if (source->pSourcePict->type == SourcePictTypeLinear) { 1350 dst = glamor_generate_linear_gradient_picture(screen, 1351 source, x_source, 1352 y_source, width, 1353 height, format); 1354 } 1355 else if (source->pSourcePict->type == SourcePictTypeRadial) { 1356 dst = glamor_generate_radial_gradient_picture(screen, 1357 source, x_source, 1358 y_source, width, 1359 height, format); 1360 } 1361 1362 if (dst) { 1363 return dst; 1364 } 1365 } 1366 1367 pixmap = glamor_create_pixmap(screen, 1368 width, 1369 height, 1370 PIXMAN_FORMAT_DEPTH(format), 1371 GLAMOR_CREATE_PIXMAP_CPU); 1372 1373 if (!pixmap) 1374 return NULL; 1375 1376 dst = CreatePicture(0, 1377 &pixmap->drawable, pFormat, 0, 0, serverClient, &error); 1378 glamor_destroy_pixmap(pixmap); 1379 if (!dst) 1380 return NULL; 1381 1382 ValidatePicture(dst); 1383 1384 fbComposite(PictOpSrc, source, NULL, dst, x_source, y_source, 1385 0, 0, 0, 0, width, height); 1386 return dst; 1387} 1388 1389Bool 1390glamor_composite_clipped_region(CARD8 op, 1391 PicturePtr source, 1392 PicturePtr mask, 1393 PicturePtr dest, 1394 PixmapPtr source_pixmap, 1395 PixmapPtr mask_pixmap, 1396 PixmapPtr dest_pixmap, 1397 RegionPtr region, 1398 int x_source, 1399 int y_source, 1400 int x_mask, int y_mask, int x_dest, int y_dest) 1401{ 1402 glamor_pixmap_private *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); 1403 glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap); 1404 glamor_pixmap_private *dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); 1405 glamor_screen_private *glamor_priv = glamor_get_screen_private(dest_pixmap->drawable.pScreen); 1406 ScreenPtr screen = dest->pDrawable->pScreen; 1407 PicturePtr temp_src = source, temp_mask = mask; 1408 PixmapPtr temp_src_pixmap = source_pixmap; 1409 PixmapPtr temp_mask_pixmap = mask_pixmap; 1410 glamor_pixmap_private *temp_src_priv = source_pixmap_priv; 1411 glamor_pixmap_private *temp_mask_priv = mask_pixmap_priv; 1412 int x_temp_src, y_temp_src, x_temp_mask, y_temp_mask; 1413 BoxPtr extent; 1414 glamor_composite_rect_t rect[10]; 1415 glamor_composite_rect_t *prect = rect; 1416 int prect_size = ARRAY_SIZE(rect); 1417 int ok = FALSE; 1418 int i; 1419 int width; 1420 int height; 1421 BoxPtr box; 1422 int nbox; 1423 enum ca_state ca_state = CA_NONE; 1424 1425 extent = RegionExtents(region); 1426 box = RegionRects(region); 1427 nbox = RegionNumRects(region); 1428 width = extent->x2 - extent->x1; 1429 height = extent->y2 - extent->y1; 1430 1431 x_temp_src = x_source; 1432 y_temp_src = y_source; 1433 x_temp_mask = x_mask; 1434 y_temp_mask = y_mask; 1435 1436 DEBUGF("clipped (%d %d) (%d %d) (%d %d) width %d height %d \n", 1437 x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height); 1438 1439 /* Is the composite operation equivalent to a copy? */ 1440 if (source && 1441 !mask && !source->alphaMap && !dest->alphaMap 1442 && source->pDrawable && !source->transform 1443 /* CopyArea is only defined with matching depths. */ 1444 && dest->pDrawable->depth == source->pDrawable->depth 1445 && ((op == PictOpSrc 1446 && (source->format == dest->format 1447 || (PICT_FORMAT_COLOR(dest->format) 1448 && PICT_FORMAT_COLOR(source->format) 1449 && dest->format == PICT_FORMAT(PICT_FORMAT_BPP(source->format), 1450 PICT_FORMAT_TYPE(source->format), 1451 0, 1452 PICT_FORMAT_R(source->format), 1453 PICT_FORMAT_G(source->format), 1454 PICT_FORMAT_B(source->format))))) 1455 || (op == PictOpOver 1456 && source->format == dest->format 1457 && !PICT_FORMAT_A(source->format))) 1458 && x_source >= 0 && y_source >= 0 1459 && (x_source + width) <= source->pDrawable->width 1460 && (y_source + height) <= source->pDrawable->height) { 1461 x_source += source->pDrawable->x; 1462 y_source += source->pDrawable->y; 1463 x_dest += dest->pDrawable->x; 1464 y_dest += dest->pDrawable->y; 1465 glamor_copy(source->pDrawable, dest->pDrawable, NULL, 1466 box, nbox, x_source - x_dest, 1467 y_source - y_dest, FALSE, FALSE, 0, NULL); 1468 ok = TRUE; 1469 goto out; 1470 } 1471 1472 /* XXX is it possible source mask have non-zero drawable.x/y? */ 1473 if (source 1474 && ((!source->pDrawable 1475 && (source->pSourcePict->type != SourcePictTypeSolidFill)) 1476 || (source->pDrawable 1477 && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv) 1478 && (source_pixmap->drawable.width != width 1479 || source_pixmap->drawable.height != height)))) { 1480 temp_src = 1481 glamor_convert_gradient_picture(screen, source, 1482 extent->x1 + x_source - x_dest - dest->pDrawable->x, 1483 extent->y1 + y_source - y_dest - dest->pDrawable->y, 1484 width, height); 1485 if (!temp_src) { 1486 temp_src = source; 1487 goto out; 1488 } 1489 temp_src_pixmap = (PixmapPtr) (temp_src->pDrawable); 1490 temp_src_priv = glamor_get_pixmap_private(temp_src_pixmap); 1491 x_temp_src = -extent->x1 + x_dest + dest->pDrawable->x; 1492 y_temp_src = -extent->y1 + y_dest + dest->pDrawable->y; 1493 } 1494 1495 if (mask 1496 && 1497 ((!mask->pDrawable 1498 && (mask->pSourcePict->type != SourcePictTypeSolidFill)) 1499 || (mask->pDrawable && !GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv) 1500 && (mask_pixmap->drawable.width != width 1501 || mask_pixmap->drawable.height != height)))) { 1502 /* XXX if mask->pDrawable is the same as source->pDrawable, we have an opportunity 1503 * to do reduce one conversion. */ 1504 temp_mask = 1505 glamor_convert_gradient_picture(screen, mask, 1506 extent->x1 + x_mask - x_dest - dest->pDrawable->x, 1507 extent->y1 + y_mask - y_dest - dest->pDrawable->y, 1508 width, height); 1509 if (!temp_mask) { 1510 temp_mask = mask; 1511 goto out; 1512 } 1513 temp_mask_pixmap = (PixmapPtr) (temp_mask->pDrawable); 1514 temp_mask_priv = glamor_get_pixmap_private(temp_mask_pixmap); 1515 x_temp_mask = -extent->x1 + x_dest + dest->pDrawable->x; 1516 y_temp_mask = -extent->y1 + y_dest + dest->pDrawable->y; 1517 } 1518 1519 if (mask && mask->componentAlpha) { 1520 if (glamor_priv->has_dual_blend) { 1521 ca_state = CA_DUAL_BLEND; 1522 } else { 1523 if (op == PictOpOver) { 1524 if (glamor_pixmap_is_memory(mask_pixmap)) { 1525 glamor_fallback("two pass not supported on memory pximaps\n"); 1526 goto out; 1527 } 1528 ca_state = CA_TWO_PASS; 1529 op = PictOpOutReverse; 1530 } 1531 } 1532 } 1533 1534 if (temp_src_pixmap == dest_pixmap) { 1535 glamor_fallback("source and dest pixmaps are the same\n"); 1536 goto out; 1537 } 1538 if (temp_mask_pixmap == dest_pixmap) { 1539 glamor_fallback("mask and dest pixmaps are the same\n"); 1540 goto out; 1541 } 1542 1543 x_dest += dest->pDrawable->x; 1544 y_dest += dest->pDrawable->y; 1545 if (temp_src && temp_src->pDrawable) { 1546 x_temp_src += temp_src->pDrawable->x; 1547 y_temp_src += temp_src->pDrawable->y; 1548 } 1549 if (temp_mask && temp_mask->pDrawable) { 1550 x_temp_mask += temp_mask->pDrawable->x; 1551 y_temp_mask += temp_mask->pDrawable->y; 1552 } 1553 1554 if (nbox > ARRAY_SIZE(rect)) { 1555 prect = calloc(nbox, sizeof(*prect)); 1556 if (prect) 1557 prect_size = nbox; 1558 else { 1559 prect = rect; 1560 prect_size = ARRAY_SIZE(rect); 1561 } 1562 } 1563 while (nbox) { 1564 int box_cnt; 1565 1566 box_cnt = nbox > prect_size ? prect_size : nbox; 1567 for (i = 0; i < box_cnt; i++) { 1568 prect[i].x_src = box[i].x1 + x_temp_src - x_dest; 1569 prect[i].y_src = box[i].y1 + y_temp_src - y_dest; 1570 prect[i].x_mask = box[i].x1 + x_temp_mask - x_dest; 1571 prect[i].y_mask = box[i].y1 + y_temp_mask - y_dest; 1572 prect[i].x_dst = box[i].x1; 1573 prect[i].y_dst = box[i].y1; 1574 prect[i].width = box[i].x2 - box[i].x1; 1575 prect[i].height = box[i].y2 - box[i].y1; 1576 DEBUGF("dest %d %d \n", prect[i].x_dst, prect[i].y_dst); 1577 } 1578 ok = glamor_composite_with_shader(op, temp_src, temp_mask, dest, 1579 temp_src_pixmap, temp_mask_pixmap, dest_pixmap, 1580 temp_src_priv, temp_mask_priv, 1581 dest_pixmap_priv, 1582 box_cnt, prect, ca_state); 1583 if (!ok) 1584 break; 1585 nbox -= box_cnt; 1586 box += box_cnt; 1587 } 1588 1589 if (prect != rect) 1590 free(prect); 1591 out: 1592 if (temp_src != source) 1593 FreePicture(temp_src, 0); 1594 if (temp_mask != mask) 1595 FreePicture(temp_mask, 0); 1596 1597 return ok; 1598} 1599 1600void 1601glamor_composite(CARD8 op, 1602 PicturePtr source, 1603 PicturePtr mask, 1604 PicturePtr dest, 1605 INT16 x_source, 1606 INT16 y_source, 1607 INT16 x_mask, 1608 INT16 y_mask, 1609 INT16 x_dest, INT16 y_dest, CARD16 width, CARD16 height) 1610{ 1611 ScreenPtr screen = dest->pDrawable->pScreen; 1612 PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable); 1613 PixmapPtr source_pixmap = NULL, mask_pixmap = NULL; 1614 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 1615 RegionRec region; 1616 BoxPtr extent; 1617 int nbox, ok = FALSE; 1618 int force_clip = 0; 1619 1620 if (source->pDrawable) { 1621 source_pixmap = glamor_get_drawable_pixmap(source->pDrawable); 1622 if (glamor_pixmap_drm_only(source_pixmap)) 1623 goto fail; 1624 } 1625 1626 if (mask && mask->pDrawable) { 1627 mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable); 1628 if (glamor_pixmap_drm_only(mask_pixmap)) 1629 goto fail; 1630 } 1631 1632 DEBUGF 1633 ("source pixmap %p (%d %d) mask(%d %d) dest(%d %d) width %d height %d \n", 1634 source_pixmap, x_source, y_source, x_mask, y_mask, x_dest, y_dest, 1635 width, height); 1636 1637 if (!glamor_pixmap_has_fbo(dest_pixmap)) 1638 goto fail; 1639 1640 if (op >= ARRAY_SIZE(composite_op_info)) { 1641 glamor_fallback("Unsupported composite op %x\n", op); 1642 goto fail; 1643 } 1644 1645 if (mask && mask->componentAlpha && !glamor_priv->has_dual_blend) { 1646 if (op == PictOpAtop 1647 || op == PictOpAtopReverse 1648 || op == PictOpXor || op >= PictOpSaturate) { 1649 glamor_fallback("glamor_composite(): component alpha op %x\n", op); 1650 goto fail; 1651 } 1652 } 1653 1654 if ((source && source->filter >= PictFilterConvolution) 1655 || (mask && mask->filter >= PictFilterConvolution)) { 1656 glamor_fallback("glamor_composite(): unsupported filter\n"); 1657 goto fail; 1658 } 1659 1660 if (!miComputeCompositeRegion(®ion, 1661 source, mask, dest, 1662 x_source + 1663 (source_pixmap ? source->pDrawable->x : 0), 1664 y_source + 1665 (source_pixmap ? source->pDrawable->y : 0), 1666 x_mask + 1667 (mask_pixmap ? mask->pDrawable->x : 0), 1668 y_mask + 1669 (mask_pixmap ? mask->pDrawable->y : 0), 1670 x_dest + dest->pDrawable->x, 1671 y_dest + dest->pDrawable->y, width, height)) { 1672 return; 1673 } 1674 1675 nbox = REGION_NUM_RECTS(®ion); 1676 DEBUGF("first clipped when compositing.\n"); 1677 DEBUGRegionPrint(®ion); 1678 extent = RegionExtents(®ion); 1679 if (nbox == 0) 1680 return; 1681 1682 /* If destination is not a large pixmap, but the region is larger 1683 * than texture size limitation, and source or mask is memory pixmap, 1684 * then there may be need to load a large memory pixmap to a 1685 * texture, and this is not permitted. Then we force to clip the 1686 * destination and make sure latter will not upload a large memory 1687 * pixmap. */ 1688 if (!glamor_check_fbo_size(glamor_priv, 1689 extent->x2 - extent->x1, extent->y2 - extent->y1) 1690 && glamor_pixmap_is_large(dest_pixmap) 1691 && ((source_pixmap 1692 && (glamor_pixmap_is_memory(source_pixmap) || 1693 source->repeatType == RepeatPad)) 1694 || (mask_pixmap && 1695 (glamor_pixmap_is_memory(mask_pixmap) || 1696 mask->repeatType == RepeatPad)) 1697 || (!source_pixmap && 1698 (source->pSourcePict->type != SourcePictTypeSolidFill)) 1699 || (!mask_pixmap && mask && 1700 mask->pSourcePict->type != SourcePictTypeSolidFill))) 1701 force_clip = 1; 1702 1703 if (force_clip || glamor_pixmap_is_large(dest_pixmap) 1704 || (source_pixmap 1705 && glamor_pixmap_is_large(source_pixmap)) 1706 || (mask_pixmap && glamor_pixmap_is_large(mask_pixmap))) 1707 ok = glamor_composite_largepixmap_region(op, 1708 source, mask, dest, 1709 source_pixmap, 1710 mask_pixmap, 1711 dest_pixmap, 1712 ®ion, force_clip, 1713 x_source, y_source, 1714 x_mask, y_mask, 1715 x_dest, y_dest, width, height); 1716 else 1717 ok = glamor_composite_clipped_region(op, source, 1718 mask, dest, 1719 source_pixmap, 1720 mask_pixmap, 1721 dest_pixmap, 1722 ®ion, 1723 x_source, y_source, 1724 x_mask, y_mask, x_dest, y_dest); 1725 1726 REGION_UNINIT(dest->pDrawable->pScreen, ®ion); 1727 1728 if (ok) 1729 return; 1730 1731 fail: 1732 1733 glamor_fallback 1734 ("from picts %p:%p %dx%d / %p:%p %d x %d (%c,%c) to pict %p:%p %dx%d (%c)\n", 1735 source, source->pDrawable, 1736 source->pDrawable ? source->pDrawable->width : 0, 1737 source->pDrawable ? source->pDrawable->height : 0, mask, 1738 (!mask) ? NULL : mask->pDrawable, 1739 (!mask || !mask->pDrawable) ? 0 : mask->pDrawable->width, 1740 (!mask || !mask->pDrawable) ? 0 : mask->pDrawable->height, 1741 glamor_get_picture_location(source), 1742 glamor_get_picture_location(mask), 1743 dest, dest->pDrawable, 1744 dest->pDrawable->width, dest->pDrawable->height, 1745 glamor_get_picture_location(dest)); 1746 1747 if (glamor_prepare_access_picture_box(dest, GLAMOR_ACCESS_RW, 1748 x_dest, y_dest, width, height) && 1749 glamor_prepare_access_picture_box(source, GLAMOR_ACCESS_RO, 1750 x_source, y_source, width, height) && 1751 glamor_prepare_access_picture_box(mask, GLAMOR_ACCESS_RO, 1752 x_mask, y_mask, width, height)) 1753 { 1754 fbComposite(op, 1755 source, mask, dest, 1756 x_source, y_source, 1757 x_mask, y_mask, x_dest, y_dest, width, height); 1758 } 1759 glamor_finish_access_picture(mask); 1760 glamor_finish_access_picture(source); 1761 glamor_finish_access_picture(dest); 1762} 1763