glamor_render.c revision 35c4bbdf
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 glamor_fbo_red_is_alpha(glamor_priv, dest_priv->fbo)); 533 repeat_type = picture->repeatType; 534 switch (picture->repeatType) { 535 case RepeatNone: 536 if (glamor_priv->gl_flavor != GLAMOR_GL_ES2) { 537 /* XXX GLES2 doesn't support GL_CLAMP_TO_BORDER. */ 538 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 539 GL_CLAMP_TO_BORDER); 540 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 541 GL_CLAMP_TO_BORDER); 542 } else { 543 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 544 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 545 } 546 break; 547 case RepeatNormal: 548 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 549 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 550 break; 551 case RepeatPad: 552 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 553 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 554 break; 555 case RepeatReflect: 556 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); 557 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); 558 break; 559 } 560 561 switch (picture->filter) { 562 default: 563 case PictFilterFast: 564 case PictFilterNearest: 565 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 566 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 567 break; 568 case PictFilterGood: 569 case PictFilterBest: 570 case PictFilterBilinear: 571 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 572 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 573 break; 574 } 575 576 /* 577 * GLES2 doesn't support RepeatNone. We need to fix it anyway. 578 * 579 **/ 580 if (glamor_pixmap_priv_is_large(pixmap_priv) || 581 ((!PICT_FORMAT_A(picture->format) || glamor_priv->gl_flavor == GLAMOR_GL_ES2) && 582 repeat_type == RepeatNone && picture->transform)) { 583 glamor_pixmap_fbo_fix_wh_ratio(wh, pixmap, pixmap_priv); 584 glUniform4fv(wh_location, 1, wh); 585 586 repeat_type += RepeatFix; 587 } 588 589 glUniform1i(repeat_location, repeat_type); 590} 591 592static void 593glamor_set_composite_solid(float *color, GLint uniform_location) 594{ 595 glUniform4fv(uniform_location, 1, color); 596} 597 598static char 599glamor_get_picture_location(PicturePtr picture) 600{ 601 if (picture == NULL) 602 return ' '; 603 604 if (picture->pDrawable == NULL) { 605 switch (picture->pSourcePict->type) { 606 case SourcePictTypeSolidFill: 607 return 'c'; 608 case SourcePictTypeLinear: 609 return 'l'; 610 case SourcePictTypeRadial: 611 return 'r'; 612 default: 613 return '?'; 614 } 615 } 616 return glamor_get_drawable_location(picture->pDrawable); 617} 618 619static void * 620glamor_setup_composite_vbo(ScreenPtr screen, int n_verts) 621{ 622 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 623 int vert_size; 624 char *vbo_offset; 625 float *vb; 626 627 glamor_priv->render_nr_quads = 0; 628 glamor_priv->vb_stride = 2 * sizeof(float); 629 if (glamor_priv->has_source_coords) 630 glamor_priv->vb_stride += 2 * sizeof(float); 631 if (glamor_priv->has_mask_coords) 632 glamor_priv->vb_stride += 2 * sizeof(float); 633 634 vert_size = n_verts * glamor_priv->vb_stride; 635 636 glamor_make_current(glamor_priv); 637 vb = glamor_get_vbo_space(screen, vert_size, &vbo_offset); 638 639 glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE, 640 glamor_priv->vb_stride, vbo_offset); 641 glEnableVertexAttribArray(GLAMOR_VERTEX_POS); 642 643 if (glamor_priv->has_source_coords) { 644 glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, 645 GL_FLOAT, GL_FALSE, 646 glamor_priv->vb_stride, 647 vbo_offset + 2 * sizeof(float)); 648 glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); 649 } 650 651 if (glamor_priv->has_mask_coords) { 652 glVertexAttribPointer(GLAMOR_VERTEX_MASK, 2, GL_FLOAT, GL_FALSE, 653 glamor_priv->vb_stride, 654 vbo_offset + (glamor_priv->has_source_coords ? 655 4 : 2) * sizeof(float)); 656 glEnableVertexAttribArray(GLAMOR_VERTEX_MASK); 657 } 658 659 return vb; 660} 661 662static void 663glamor_flush_composite_rects(ScreenPtr screen) 664{ 665 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 666 667 glamor_make_current(glamor_priv); 668 669 if (!glamor_priv->render_nr_quads) 670 return; 671 672 glamor_glDrawArrays_GL_QUADS(glamor_priv, glamor_priv->render_nr_quads); 673} 674 675static const int pict_format_combine_tab[][3] = { 676 {PICT_TYPE_ARGB, PICT_TYPE_A, PICT_TYPE_ARGB}, 677 {PICT_TYPE_ABGR, PICT_TYPE_A, PICT_TYPE_ABGR}, 678}; 679 680static Bool 681combine_pict_format(PictFormatShort * des, const PictFormatShort src, 682 const PictFormatShort mask, glamor_program_alpha in_ca) 683{ 684 PictFormatShort new_vis; 685 int src_type, mask_type, src_bpp; 686 int i; 687 688 if (src == mask) { 689 *des = src; 690 return TRUE; 691 } 692 src_bpp = PICT_FORMAT_BPP(src); 693 694 assert(src_bpp == PICT_FORMAT_BPP(mask)); 695 696 new_vis = PICT_FORMAT_VIS(src) | PICT_FORMAT_VIS(mask); 697 698 switch (in_ca) { 699 case glamor_program_alpha_normal: 700 src_type = PICT_FORMAT_TYPE(src); 701 mask_type = PICT_TYPE_A; 702 break; 703 case glamor_program_alpha_ca_first: 704 src_type = PICT_FORMAT_TYPE(src); 705 mask_type = PICT_FORMAT_TYPE(mask); 706 break; 707 case glamor_program_alpha_ca_second: 708 src_type = PICT_TYPE_A; 709 mask_type = PICT_FORMAT_TYPE(mask); 710 break; 711 case glamor_program_alpha_dual_blend: 712 src_type = PICT_FORMAT_TYPE(src); 713 mask_type = PICT_FORMAT_TYPE(mask); 714 break; 715 default: 716 return FALSE; 717 } 718 719 if (src_type == mask_type) { 720 *des = PICT_VISFORMAT(src_bpp, src_type, new_vis); 721 return TRUE; 722 } 723 724 for (i = 0; i < ARRAY_SIZE(pict_format_combine_tab); i++) { 725 if ((src_type == pict_format_combine_tab[i][0] 726 && mask_type == pict_format_combine_tab[i][1]) 727 || (src_type == pict_format_combine_tab[i][1] 728 && mask_type == pict_format_combine_tab[i][0])) { 729 *des = PICT_VISFORMAT(src_bpp, pict_format_combine_tab[i] 730 [2], new_vis); 731 return TRUE; 732 } 733 } 734 return FALSE; 735} 736 737static void 738glamor_set_normalize_tcoords_generic(PixmapPtr pixmap, 739 glamor_pixmap_private *priv, 740 int repeat_type, 741 float *matrix, 742 float xscale, float yscale, 743 int x1, int y1, int x2, int y2, 744 float *texcoords, 745 int stride) 746{ 747 if (!matrix && repeat_type == RepeatNone) 748 glamor_set_normalize_tcoords_ext(priv, xscale, yscale, 749 x1, y1, 750 x2, y2, texcoords, stride); 751 else if (matrix && repeat_type == RepeatNone) 752 glamor_set_transformed_normalize_tcoords_ext(priv, matrix, xscale, 753 yscale, x1, y1, 754 x2, y2, 755 texcoords, stride); 756 else if (!matrix && repeat_type != RepeatNone) 757 glamor_set_repeat_normalize_tcoords_ext(pixmap, priv, repeat_type, 758 xscale, yscale, 759 x1, y1, 760 x2, y2, 761 texcoords, stride); 762 else if (matrix && repeat_type != RepeatNone) 763 glamor_set_repeat_transformed_normalize_tcoords_ext(pixmap, priv, repeat_type, 764 matrix, xscale, 765 yscale, x1, y1, x2, 766 y2, 767 texcoords, stride); 768} 769 770/** 771 * Returns whether the general composite path supports this picture 772 * format for a pixmap that is permanently stored in an FBO (as 773 * opposed to the GLAMOR_PIXMAP_DYNAMIC_UPLOAD path). 774 * 775 * We could support many more formats by using GL_ARB_texture_view to 776 * parse the same bits as different formats. For now, we only support 777 * tweaking whether we sample the alpha bits of an a8r8g8b8, or just 778 * force them to 1. 779 */ 780static Bool 781glamor_render_format_is_supported(PictFormatShort format) 782{ 783 switch (format) { 784 case PICT_a8r8g8b8: 785 case PICT_x8r8g8b8: 786 case PICT_a8: 787 return TRUE; 788 default: 789 return FALSE; 790 } 791} 792 793static Bool 794glamor_composite_choose_shader(CARD8 op, 795 PicturePtr source, 796 PicturePtr mask, 797 PicturePtr dest, 798 PixmapPtr source_pixmap, 799 PixmapPtr mask_pixmap, 800 PixmapPtr dest_pixmap, 801 glamor_pixmap_private *source_pixmap_priv, 802 glamor_pixmap_private *mask_pixmap_priv, 803 glamor_pixmap_private *dest_pixmap_priv, 804 struct shader_key *s_key, 805 glamor_composite_shader ** shader, 806 struct blendinfo *op_info, 807 PictFormatShort *psaved_source_format, 808 enum ca_state ca_state) 809{ 810 ScreenPtr screen = dest->pDrawable->pScreen; 811 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 812 enum glamor_pixmap_status source_status = GLAMOR_NONE; 813 enum glamor_pixmap_status mask_status = GLAMOR_NONE; 814 PictFormatShort saved_source_format = 0; 815 struct shader_key key; 816 GLfloat source_solid_color[4]; 817 GLfloat mask_solid_color[4]; 818 Bool ret = FALSE; 819 820 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) { 821 glamor_fallback("dest has no fbo.\n"); 822 goto fail; 823 } 824 825 if (!glamor_render_format_is_supported(dest->format)) { 826 glamor_fallback("Unsupported dest picture format.\n"); 827 goto fail; 828 } 829 830 memset(&key, 0, sizeof(key)); 831 if (!source) { 832 key.source = SHADER_SOURCE_SOLID; 833 source_solid_color[0] = 0.0; 834 source_solid_color[1] = 0.0; 835 source_solid_color[2] = 0.0; 836 source_solid_color[3] = 0.0; 837 } 838 else if (!source->pDrawable) { 839 if (source->pSourcePict->type == SourcePictTypeSolidFill) { 840 key.source = SHADER_SOURCE_SOLID; 841 glamor_get_rgba_from_pixel(source->pSourcePict->solidFill.color, 842 &source_solid_color[0], 843 &source_solid_color[1], 844 &source_solid_color[2], 845 &source_solid_color[3], PICT_a8r8g8b8); 846 } 847 else 848 goto fail; 849 } 850 else { 851 if (PICT_FORMAT_A(source->format)) 852 key.source = SHADER_SOURCE_TEXTURE_ALPHA; 853 else 854 key.source = SHADER_SOURCE_TEXTURE; 855 } 856 857 if (mask) { 858 if (!mask->pDrawable) { 859 if (mask->pSourcePict->type == SourcePictTypeSolidFill) { 860 key.mask = SHADER_MASK_SOLID; 861 glamor_get_rgba_from_pixel 862 (mask->pSourcePict->solidFill.color, 863 &mask_solid_color[0], 864 &mask_solid_color[1], 865 &mask_solid_color[2], &mask_solid_color[3], PICT_a8r8g8b8); 866 } 867 else 868 goto fail; 869 } 870 else { 871 key.mask = SHADER_MASK_TEXTURE_ALPHA; 872 } 873 874 if (!mask->componentAlpha) { 875 key.in = glamor_program_alpha_normal; 876 } 877 else { 878 if (op == PictOpClear) 879 key.mask = SHADER_MASK_NONE; 880 else if (glamor_priv->has_dual_blend) 881 key.in = glamor_program_alpha_dual_blend; 882 else if (op == PictOpSrc || op == PictOpAdd 883 || op == PictOpIn || op == PictOpOut 884 || op == PictOpOverReverse) 885 key.in = glamor_program_alpha_ca_second; 886 else if (op == PictOpOutReverse || op == PictOpInReverse) { 887 key.in = glamor_program_alpha_ca_first; 888 } 889 else { 890 glamor_fallback("Unsupported component alpha op: %d\n", op); 891 goto fail; 892 } 893 } 894 } 895 else { 896 key.mask = SHADER_MASK_NONE; 897 } 898 899 if (dest_pixmap->drawable.bitsPerPixel <= 8 && 900 glamor_priv->one_channel_format == GL_RED) { 901 key.dest_swizzle = SHADER_DEST_SWIZZLE_ALPHA_TO_RED; 902 } else { 903 key.dest_swizzle = SHADER_DEST_SWIZZLE_DEFAULT; 904 } 905 906 if (source && source->alphaMap) { 907 glamor_fallback("source alphaMap\n"); 908 goto fail; 909 } 910 if (mask && mask->alphaMap) { 911 glamor_fallback("mask alphaMap\n"); 912 goto fail; 913 } 914 915 if (key.source == SHADER_SOURCE_TEXTURE || 916 key.source == SHADER_SOURCE_TEXTURE_ALPHA) { 917 if (source_pixmap == dest_pixmap) { 918 /* XXX source and the dest share the same texture. 919 * Does it need special handle? */ 920 glamor_fallback("source == dest\n"); 921 } 922 if (source_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) { 923#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD 924 source_status = GLAMOR_UPLOAD_PENDING; 925#else 926 glamor_fallback("no texture in source\n"); 927 goto fail; 928#endif 929 } 930 } 931 932 if (key.mask == SHADER_MASK_TEXTURE || 933 key.mask == SHADER_MASK_TEXTURE_ALPHA) { 934 if (mask_pixmap == dest_pixmap) { 935 glamor_fallback("mask == dest\n"); 936 goto fail; 937 } 938 if (mask_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) { 939#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD 940 mask_status = GLAMOR_UPLOAD_PENDING; 941#else 942 glamor_fallback("no texture in mask\n"); 943 goto fail; 944#endif 945 } 946 } 947 948#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD 949 if (source_status == GLAMOR_UPLOAD_PENDING 950 && mask_status == GLAMOR_UPLOAD_PENDING 951 && source_pixmap == mask_pixmap) { 952 953 if (source->format != mask->format) { 954 saved_source_format = source->format; 955 956 if (!combine_pict_format(&source->format, source->format, 957 mask->format, key.in)) { 958 glamor_fallback("combine source %x mask %x failed.\n", 959 source->format, mask->format); 960 goto fail; 961 } 962 963 /* XXX 964 * By default, glamor_upload_picture_to_texture will wire alpha to 1 965 * if one picture doesn't have alpha. So we don't do that again in 966 * rendering function. But here is a special case, as source and 967 * mask share the same texture but may have different formats. For 968 * example, source doesn't have alpha, but mask has alpha. Then the 969 * texture will have the alpha value for the mask. And will not wire 970 * to 1 for the source. In this case, we have to use different shader 971 * to wire the source's alpha to 1. 972 * 973 * But this may cause a potential problem if the source's repeat mode 974 * is REPEAT_NONE, and if the source is smaller than the dest, then 975 * for the region not covered by the source may be painted incorrectly. 976 * because we wire the alpha to 1. 977 * 978 **/ 979 if (!PICT_FORMAT_A(saved_source_format) 980 && PICT_FORMAT_A(mask->format)) 981 key.source = SHADER_SOURCE_TEXTURE; 982 983 if (!PICT_FORMAT_A(mask->format) 984 && PICT_FORMAT_A(saved_source_format)) 985 key.mask = SHADER_MASK_TEXTURE; 986 987 mask_status = GLAMOR_NONE; 988 } 989 990 source_status = glamor_upload_picture_to_texture(source); 991 if (source_status != GLAMOR_UPLOAD_DONE) { 992 glamor_fallback("Failed to upload source texture.\n"); 993 goto fail; 994 } 995 } 996 else { 997 if (source_status == GLAMOR_UPLOAD_PENDING) { 998 source_status = glamor_upload_picture_to_texture(source); 999 if (source_status != GLAMOR_UPLOAD_DONE) { 1000 glamor_fallback("Failed to upload source texture.\n"); 1001 goto fail; 1002 } 1003 } else { 1004 if (!glamor_render_format_is_supported(source->format)) { 1005 glamor_fallback("Unsupported source picture format.\n"); 1006 goto fail; 1007 } 1008 } 1009 1010 if (mask_status == GLAMOR_UPLOAD_PENDING) { 1011 mask_status = glamor_upload_picture_to_texture(mask); 1012 if (mask_status != GLAMOR_UPLOAD_DONE) { 1013 glamor_fallback("Failed to upload mask texture.\n"); 1014 goto fail; 1015 } 1016 } else if (mask) { 1017 if (!glamor_render_format_is_supported(mask->format)) { 1018 glamor_fallback("Unsupported mask picture format.\n"); 1019 goto fail; 1020 } 1021 } 1022 } 1023#endif 1024 1025 /* If the source and mask are two differently-formatted views of 1026 * the same pixmap bits, and the pixmap was already uploaded (so 1027 * the dynamic code above doesn't apply), then fall back to 1028 * software. We should use texture views to fix this properly. 1029 */ 1030 if (source_pixmap && source_pixmap == mask_pixmap && 1031 source->format != mask->format) { 1032 goto fail; 1033 } 1034 1035 if (!glamor_set_composite_op(screen, op, op_info, dest, mask, ca_state, 1036 &key)) { 1037 goto fail; 1038 } 1039 1040 *shader = glamor_lookup_composite_shader(screen, &key); 1041 if ((*shader)->prog == 0) { 1042 glamor_fallback("no shader program for this render acccel mode\n"); 1043 goto fail; 1044 } 1045 1046 if (key.source == SHADER_SOURCE_SOLID) 1047 memcpy(&(*shader)->source_solid_color[0], 1048 source_solid_color, 4 * sizeof(float)); 1049 else { 1050 (*shader)->source_pixmap = source_pixmap; 1051 (*shader)->source = source; 1052 } 1053 1054 if (key.mask == SHADER_MASK_SOLID) 1055 memcpy(&(*shader)->mask_solid_color[0], 1056 mask_solid_color, 4 * sizeof(float)); 1057 else { 1058 (*shader)->mask_pixmap = mask_pixmap; 1059 (*shader)->mask = mask; 1060 } 1061 1062 ret = TRUE; 1063 memcpy(s_key, &key, sizeof(key)); 1064 *psaved_source_format = saved_source_format; 1065 goto done; 1066 1067 fail: 1068 if (saved_source_format) 1069 source->format = saved_source_format; 1070 done: 1071 return ret; 1072} 1073 1074static void 1075glamor_composite_set_shader_blend(glamor_screen_private *glamor_priv, 1076 glamor_pixmap_private *dest_priv, 1077 struct shader_key *key, 1078 glamor_composite_shader *shader, 1079 struct blendinfo *op_info) 1080{ 1081 glamor_make_current(glamor_priv); 1082 glUseProgram(shader->prog); 1083 1084 if (key->source == SHADER_SOURCE_SOLID) { 1085 glamor_set_composite_solid(shader->source_solid_color, 1086 shader->source_uniform_location); 1087 } 1088 else { 1089 glamor_set_composite_texture(glamor_priv, 0, 1090 shader->source, 1091 shader->source_pixmap, shader->source_wh, 1092 shader->source_repeat_mode, 1093 dest_priv); 1094 } 1095 1096 if (key->mask != SHADER_MASK_NONE) { 1097 if (key->mask == SHADER_MASK_SOLID) { 1098 glamor_set_composite_solid(shader->mask_solid_color, 1099 shader->mask_uniform_location); 1100 } 1101 else { 1102 glamor_set_composite_texture(glamor_priv, 1, 1103 shader->mask, 1104 shader->mask_pixmap, shader->mask_wh, 1105 shader->mask_repeat_mode, 1106 dest_priv); 1107 } 1108 } 1109 1110 if (glamor_priv->gl_flavor != GLAMOR_GL_ES2) 1111 glDisable(GL_COLOR_LOGIC_OP); 1112 1113 if (op_info->source_blend == GL_ONE && op_info->dest_blend == GL_ZERO) { 1114 glDisable(GL_BLEND); 1115 } 1116 else { 1117 glEnable(GL_BLEND); 1118 glBlendFunc(op_info->source_blend, op_info->dest_blend); 1119 } 1120} 1121 1122static Bool 1123glamor_composite_with_shader(CARD8 op, 1124 PicturePtr source, 1125 PicturePtr mask, 1126 PicturePtr dest, 1127 PixmapPtr source_pixmap, 1128 PixmapPtr mask_pixmap, 1129 PixmapPtr dest_pixmap, 1130 glamor_pixmap_private *source_pixmap_priv, 1131 glamor_pixmap_private *mask_pixmap_priv, 1132 glamor_pixmap_private *dest_pixmap_priv, 1133 int nrect, glamor_composite_rect_t *rects, 1134 enum ca_state ca_state) 1135{ 1136 ScreenPtr screen = dest->pDrawable->pScreen; 1137 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 1138 GLfloat dst_xscale, dst_yscale; 1139 GLfloat mask_xscale = 1, mask_yscale = 1, src_xscale = 1, src_yscale = 1; 1140 struct shader_key key, key_ca; 1141 int dest_x_off, dest_y_off; 1142 int source_x_off, source_y_off; 1143 int mask_x_off, mask_y_off; 1144 PictFormatShort saved_source_format = 0; 1145 float src_matrix[9], mask_matrix[9]; 1146 float *psrc_matrix = NULL, *pmask_matrix = NULL; 1147 int nrect_max; 1148 Bool ret = FALSE; 1149 glamor_composite_shader *shader = NULL, *shader_ca = NULL; 1150 struct blendinfo op_info, op_info_ca; 1151 1152 if (!glamor_composite_choose_shader(op, source, mask, dest, 1153 source_pixmap, mask_pixmap, dest_pixmap, 1154 source_pixmap_priv, mask_pixmap_priv, 1155 dest_pixmap_priv, 1156 &key, &shader, &op_info, 1157 &saved_source_format, ca_state)) { 1158 glamor_fallback("glamor_composite_choose_shader failed\n"); 1159 return ret; 1160 } 1161 if (ca_state == CA_TWO_PASS) { 1162 if (!glamor_composite_choose_shader(PictOpAdd, source, mask, dest, 1163 source_pixmap, mask_pixmap, dest_pixmap, 1164 source_pixmap_priv, 1165 mask_pixmap_priv, dest_pixmap_priv, 1166 &key_ca, &shader_ca, &op_info_ca, 1167 &saved_source_format, ca_state)) { 1168 glamor_fallback("glamor_composite_choose_shader failed\n"); 1169 return ret; 1170 } 1171 } 1172 1173 glamor_make_current(glamor_priv); 1174 1175 glamor_set_destination_pixmap_priv_nc(glamor_priv, dest_pixmap, dest_pixmap_priv); 1176 glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, &key, shader, &op_info); 1177 glamor_set_alu(screen, GXcopy); 1178 1179 glamor_priv->has_source_coords = key.source != SHADER_SOURCE_SOLID; 1180 glamor_priv->has_mask_coords = (key.mask != SHADER_MASK_NONE && 1181 key.mask != SHADER_MASK_SOLID); 1182 1183 dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable); 1184 dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); 1185 glamor_get_drawable_deltas(dest->pDrawable, dest_pixmap, 1186 &dest_x_off, &dest_y_off); 1187 pixmap_priv_get_dest_scale(dest_pixmap, dest_pixmap_priv, &dst_xscale, &dst_yscale); 1188 1189 if (glamor_priv->has_source_coords) { 1190 glamor_get_drawable_deltas(source->pDrawable, 1191 source_pixmap, &source_x_off, &source_y_off); 1192 pixmap_priv_get_scale(source_pixmap_priv, &src_xscale, &src_yscale); 1193 if (source->transform) { 1194 psrc_matrix = src_matrix; 1195 glamor_picture_get_matrixf(source, psrc_matrix); 1196 } 1197 } 1198 1199 if (glamor_priv->has_mask_coords) { 1200 glamor_get_drawable_deltas(mask->pDrawable, mask_pixmap, 1201 &mask_x_off, &mask_y_off); 1202 pixmap_priv_get_scale(mask_pixmap_priv, &mask_xscale, &mask_yscale); 1203 if (mask->transform) { 1204 pmask_matrix = mask_matrix; 1205 glamor_picture_get_matrixf(mask, pmask_matrix); 1206 } 1207 } 1208 1209 nrect_max = MIN(nrect, GLAMOR_COMPOSITE_VBO_VERT_CNT / 4); 1210 1211 while (nrect) { 1212 int mrect, rect_processed; 1213 int vb_stride; 1214 float *vertices; 1215 1216 mrect = nrect > nrect_max ? nrect_max : nrect; 1217 vertices = glamor_setup_composite_vbo(screen, mrect * 4); 1218 rect_processed = mrect; 1219 vb_stride = glamor_priv->vb_stride / sizeof(float); 1220 while (mrect--) { 1221 INT16 x_source; 1222 INT16 y_source; 1223 INT16 x_mask; 1224 INT16 y_mask; 1225 INT16 x_dest; 1226 INT16 y_dest; 1227 CARD16 width; 1228 CARD16 height; 1229 1230 x_dest = rects->x_dst + dest_x_off; 1231 y_dest = rects->y_dst + dest_y_off; 1232 x_source = rects->x_src + source_x_off; 1233 y_source = rects->y_src + source_y_off; 1234 x_mask = rects->x_mask + mask_x_off; 1235 y_mask = rects->y_mask + mask_y_off; 1236 width = rects->width; 1237 height = rects->height; 1238 1239 DEBUGF 1240 ("dest(%d,%d) source(%d %d) mask (%d %d), width %d height %d \n", 1241 x_dest, y_dest, x_source, y_source, x_mask, y_mask, width, 1242 height); 1243 1244 glamor_set_normalize_vcoords_ext(dest_pixmap_priv, dst_xscale, 1245 dst_yscale, x_dest, y_dest, 1246 x_dest + width, y_dest + height, 1247 vertices, 1248 vb_stride); 1249 vertices += 2; 1250 if (key.source != SHADER_SOURCE_SOLID) { 1251 glamor_set_normalize_tcoords_generic(source_pixmap, 1252 source_pixmap_priv, 1253 source->repeatType, 1254 psrc_matrix, src_xscale, 1255 src_yscale, x_source, 1256 y_source, x_source + width, 1257 y_source + height, 1258 vertices, vb_stride); 1259 vertices += 2; 1260 } 1261 1262 if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID) { 1263 glamor_set_normalize_tcoords_generic(mask_pixmap, 1264 mask_pixmap_priv, 1265 mask->repeatType, 1266 pmask_matrix, mask_xscale, 1267 mask_yscale, x_mask, 1268 y_mask, x_mask + width, 1269 y_mask + height, 1270 vertices, vb_stride); 1271 vertices += 2; 1272 } 1273 glamor_priv->render_nr_quads++; 1274 rects++; 1275 1276 /* We've incremented by one of our 4 verts, now do the other 3. */ 1277 vertices += 3 * vb_stride; 1278 } 1279 glamor_put_vbo_space(screen); 1280 glamor_flush_composite_rects(screen); 1281 nrect -= rect_processed; 1282 if (ca_state == CA_TWO_PASS) { 1283 glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, 1284 &key_ca, shader_ca, &op_info_ca); 1285 glamor_flush_composite_rects(screen); 1286 if (nrect) 1287 glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, 1288 &key, shader, &op_info); 1289 } 1290 } 1291 1292 glDisableVertexAttribArray(GLAMOR_VERTEX_POS); 1293 glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); 1294 glDisableVertexAttribArray(GLAMOR_VERTEX_MASK); 1295 glDisable(GL_BLEND); 1296 DEBUGF("finish rendering.\n"); 1297 if (saved_source_format) 1298 source->format = saved_source_format; 1299 1300 ret = TRUE; 1301 return ret; 1302} 1303 1304static PicturePtr 1305glamor_convert_gradient_picture(ScreenPtr screen, 1306 PicturePtr source, 1307 int x_source, 1308 int y_source, int width, int height) 1309{ 1310 PixmapPtr pixmap; 1311 PicturePtr dst = NULL; 1312 int error; 1313 PictFormatPtr pFormat; 1314 PictFormatShort format; 1315 1316 if (source->pDrawable) { 1317 pFormat = source->pFormat; 1318 format = pFormat->format; 1319 } else { 1320 format = PICT_a8r8g8b8; 1321 pFormat = PictureMatchFormat(screen, 32, format); 1322 } 1323 1324#ifdef GLAMOR_GRADIENT_SHADER 1325 if (!source->pDrawable) { 1326 if (source->pSourcePict->type == SourcePictTypeLinear) { 1327 dst = glamor_generate_linear_gradient_picture(screen, 1328 source, x_source, 1329 y_source, width, 1330 height, format); 1331 } 1332 else if (source->pSourcePict->type == SourcePictTypeRadial) { 1333 dst = glamor_generate_radial_gradient_picture(screen, 1334 source, x_source, 1335 y_source, width, 1336 height, format); 1337 } 1338 1339 if (dst) { 1340#if 0 /* Debug to compare it to pixman, Enable it if needed. */ 1341 glamor_compare_pictures(screen, source, 1342 dst, x_source, y_source, width, height, 1343 0, 3); 1344#endif 1345 return dst; 1346 } 1347 } 1348#endif 1349 pixmap = glamor_create_pixmap(screen, 1350 width, 1351 height, 1352 PIXMAN_FORMAT_DEPTH(format), 1353 GLAMOR_CREATE_PIXMAP_CPU); 1354 1355 if (!pixmap) 1356 return NULL; 1357 1358 dst = CreatePicture(0, 1359 &pixmap->drawable, pFormat, 0, 0, serverClient, &error); 1360 glamor_destroy_pixmap(pixmap); 1361 if (!dst) 1362 return NULL; 1363 1364 ValidatePicture(dst); 1365 1366 fbComposite(PictOpSrc, source, NULL, dst, x_source, y_source, 1367 0, 0, 0, 0, width, height); 1368 return dst; 1369} 1370 1371Bool 1372glamor_composite_clipped_region(CARD8 op, 1373 PicturePtr source, 1374 PicturePtr mask, 1375 PicturePtr dest, 1376 PixmapPtr source_pixmap, 1377 PixmapPtr mask_pixmap, 1378 PixmapPtr dest_pixmap, 1379 RegionPtr region, 1380 int x_source, 1381 int y_source, 1382 int x_mask, int y_mask, int x_dest, int y_dest) 1383{ 1384 glamor_pixmap_private *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); 1385 glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap); 1386 glamor_pixmap_private *dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); 1387 glamor_screen_private *glamor_priv = glamor_get_screen_private(dest_pixmap->drawable.pScreen); 1388 ScreenPtr screen = dest->pDrawable->pScreen; 1389 PicturePtr temp_src = source, temp_mask = mask; 1390 PixmapPtr temp_src_pixmap = source_pixmap; 1391 PixmapPtr temp_mask_pixmap = mask_pixmap; 1392 glamor_pixmap_private *temp_src_priv = source_pixmap_priv; 1393 glamor_pixmap_private *temp_mask_priv = mask_pixmap_priv; 1394 int x_temp_src, y_temp_src, x_temp_mask, y_temp_mask; 1395 BoxPtr extent; 1396 glamor_composite_rect_t rect[10]; 1397 glamor_composite_rect_t *prect = rect; 1398 int prect_size = ARRAY_SIZE(rect); 1399 int ok = FALSE; 1400 int i; 1401 int width; 1402 int height; 1403 BoxPtr box; 1404 int nbox; 1405 enum ca_state ca_state = CA_NONE; 1406 1407 extent = RegionExtents(region); 1408 box = RegionRects(region); 1409 nbox = RegionNumRects(region); 1410 width = extent->x2 - extent->x1; 1411 height = extent->y2 - extent->y1; 1412 1413 x_temp_src = x_source; 1414 y_temp_src = y_source; 1415 x_temp_mask = x_mask; 1416 y_temp_mask = y_mask; 1417 1418 DEBUGF("clipped (%d %d) (%d %d) (%d %d) width %d height %d \n", 1419 x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height); 1420 1421 /* Is the composite operation equivalent to a copy? */ 1422 if (!mask && !source->alphaMap && !dest->alphaMap 1423 && source->pDrawable && !source->transform 1424 && ((op == PictOpSrc 1425 && (source->format == dest->format 1426 || (PICT_FORMAT_COLOR(dest->format) 1427 && PICT_FORMAT_COLOR(source->format) 1428 && dest->format == PICT_FORMAT(PICT_FORMAT_BPP(source->format), 1429 PICT_FORMAT_TYPE(source->format), 1430 0, 1431 PICT_FORMAT_R(source->format), 1432 PICT_FORMAT_G(source->format), 1433 PICT_FORMAT_B(source->format))))) 1434 || (op == PictOpOver 1435 && source->format == dest->format 1436 && !PICT_FORMAT_A(source->format))) 1437 && x_source >= 0 && y_source >= 0 1438 && (x_source + width) <= source->pDrawable->width 1439 && (y_source + height) <= source->pDrawable->height) { 1440 x_source += source->pDrawable->x; 1441 y_source += source->pDrawable->y; 1442 x_dest += dest->pDrawable->x; 1443 y_dest += dest->pDrawable->y; 1444 glamor_copy(source->pDrawable, dest->pDrawable, NULL, 1445 box, nbox, x_source - x_dest, 1446 y_source - y_dest, FALSE, FALSE, 0, NULL); 1447 ok = TRUE; 1448 goto out; 1449 } 1450 1451 /* XXX is it possible source mask have non-zero drawable.x/y? */ 1452 if (source 1453 && ((!source->pDrawable 1454 && (source->pSourcePict->type != SourcePictTypeSolidFill)) 1455 || (source->pDrawable 1456 && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv) 1457 && (source_pixmap->drawable.width != width 1458 || source_pixmap->drawable.height != height)))) { 1459 temp_src = 1460 glamor_convert_gradient_picture(screen, source, 1461 extent->x1 + x_source - x_dest - dest->pDrawable->x, 1462 extent->y1 + y_source - y_dest - dest->pDrawable->y, 1463 width, height); 1464 if (!temp_src) { 1465 temp_src = source; 1466 goto out; 1467 } 1468 temp_src_pixmap = (PixmapPtr) (temp_src->pDrawable); 1469 temp_src_priv = glamor_get_pixmap_private(temp_src_pixmap); 1470 x_temp_src = -extent->x1 + x_dest + dest->pDrawable->x; 1471 y_temp_src = -extent->y1 + y_dest + dest->pDrawable->y; 1472 } 1473 1474 if (mask 1475 && 1476 ((!mask->pDrawable 1477 && (mask->pSourcePict->type != SourcePictTypeSolidFill)) 1478 || (mask->pDrawable && !GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv) 1479 && (mask_pixmap->drawable.width != width 1480 || mask_pixmap->drawable.height != height)))) { 1481 /* XXX if mask->pDrawable is the same as source->pDrawable, we have an opportunity 1482 * to do reduce one convertion. */ 1483 temp_mask = 1484 glamor_convert_gradient_picture(screen, mask, 1485 extent->x1 + x_mask - x_dest - dest->pDrawable->x, 1486 extent->y1 + y_mask - y_dest - dest->pDrawable->y, 1487 width, height); 1488 if (!temp_mask) { 1489 temp_mask = mask; 1490 goto out; 1491 } 1492 temp_mask_pixmap = (PixmapPtr) (temp_mask->pDrawable); 1493 temp_mask_priv = glamor_get_pixmap_private(temp_mask_pixmap); 1494 x_temp_mask = -extent->x1 + x_dest + dest->pDrawable->x; 1495 y_temp_mask = -extent->y1 + y_dest + dest->pDrawable->y; 1496 } 1497 1498 if (mask && mask->componentAlpha) { 1499 if (glamor_priv->has_dual_blend) { 1500 ca_state = CA_DUAL_BLEND; 1501 } else { 1502 if (op == PictOpOver) { 1503 ca_state = CA_TWO_PASS; 1504 op = PictOpOutReverse; 1505 } 1506 } 1507 } 1508 1509 if (temp_src_pixmap == dest_pixmap) { 1510 glamor_fallback("source and dest pixmaps are the same\n"); 1511 goto out; 1512 } 1513 if (temp_mask_pixmap == dest_pixmap) { 1514 glamor_fallback("mask and dest pixmaps are the same\n"); 1515 goto out; 1516 } 1517 1518 x_dest += dest->pDrawable->x; 1519 y_dest += dest->pDrawable->y; 1520 if (temp_src && temp_src->pDrawable) { 1521 x_temp_src += temp_src->pDrawable->x; 1522 y_temp_src += temp_src->pDrawable->y; 1523 } 1524 if (temp_mask && temp_mask->pDrawable) { 1525 x_temp_mask += temp_mask->pDrawable->x; 1526 y_temp_mask += temp_mask->pDrawable->y; 1527 } 1528 1529 if (nbox > ARRAY_SIZE(rect)) { 1530 prect = calloc(nbox, sizeof(*prect)); 1531 if (prect) 1532 prect_size = nbox; 1533 else { 1534 prect = rect; 1535 prect_size = ARRAY_SIZE(rect); 1536 } 1537 } 1538 while (nbox) { 1539 int box_cnt; 1540 1541 box_cnt = nbox > prect_size ? prect_size : nbox; 1542 for (i = 0; i < box_cnt; i++) { 1543 prect[i].x_src = box[i].x1 + x_temp_src - x_dest; 1544 prect[i].y_src = box[i].y1 + y_temp_src - y_dest; 1545 prect[i].x_mask = box[i].x1 + x_temp_mask - x_dest; 1546 prect[i].y_mask = box[i].y1 + y_temp_mask - y_dest; 1547 prect[i].x_dst = box[i].x1; 1548 prect[i].y_dst = box[i].y1; 1549 prect[i].width = box[i].x2 - box[i].x1; 1550 prect[i].height = box[i].y2 - box[i].y1; 1551 DEBUGF("dest %d %d \n", prect[i].x_dst, prect[i].y_dst); 1552 } 1553 ok = glamor_composite_with_shader(op, temp_src, temp_mask, dest, 1554 temp_src_pixmap, temp_mask_pixmap, dest_pixmap, 1555 temp_src_priv, temp_mask_priv, 1556 dest_pixmap_priv, 1557 box_cnt, prect, ca_state); 1558 if (!ok) 1559 break; 1560 nbox -= box_cnt; 1561 box += box_cnt; 1562 } 1563 1564 if (prect != rect) 1565 free(prect); 1566 out: 1567 if (temp_src != source) 1568 FreePicture(temp_src, 0); 1569 if (temp_mask != mask) 1570 FreePicture(temp_mask, 0); 1571 1572 return ok; 1573} 1574 1575void 1576glamor_composite(CARD8 op, 1577 PicturePtr source, 1578 PicturePtr mask, 1579 PicturePtr dest, 1580 INT16 x_source, 1581 INT16 y_source, 1582 INT16 x_mask, 1583 INT16 y_mask, 1584 INT16 x_dest, INT16 y_dest, CARD16 width, CARD16 height) 1585{ 1586 ScreenPtr screen = dest->pDrawable->pScreen; 1587 PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable); 1588 PixmapPtr source_pixmap = NULL, mask_pixmap = NULL; 1589 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 1590 RegionRec region; 1591 BoxPtr extent; 1592 int nbox, ok = FALSE; 1593 int force_clip = 0; 1594 1595 if (source->pDrawable) { 1596 source_pixmap = glamor_get_drawable_pixmap(source->pDrawable); 1597 if (glamor_pixmap_drm_only(source_pixmap)) 1598 goto fail; 1599 } 1600 1601 if (mask && mask->pDrawable) { 1602 mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable); 1603 if (glamor_pixmap_drm_only(mask_pixmap)) 1604 goto fail; 1605 } 1606 1607 DEBUGF 1608 ("source pixmap %p (%d %d) mask(%d %d) dest(%d %d) width %d height %d \n", 1609 source_pixmap, x_source, y_source, x_mask, y_mask, x_dest, y_dest, 1610 width, height); 1611 1612 if (!glamor_pixmap_has_fbo(dest_pixmap)) 1613 goto fail; 1614 1615 if (op >= ARRAY_SIZE(composite_op_info)) { 1616 glamor_fallback("Unsupported composite op %x\n", op); 1617 goto fail; 1618 } 1619 1620 if (mask && mask->componentAlpha && !glamor_priv->has_dual_blend) { 1621 if (op == PictOpAtop 1622 || op == PictOpAtopReverse 1623 || op == PictOpXor || op >= PictOpSaturate) { 1624 glamor_fallback("glamor_composite(): component alpha op %x\n", op); 1625 goto fail; 1626 } 1627 } 1628 1629 if ((source && source->filter >= PictFilterConvolution) 1630 || (mask && mask->filter >= PictFilterConvolution)) { 1631 glamor_fallback("glamor_composite(): unsupported filter\n"); 1632 goto fail; 1633 } 1634 1635 if (!miComputeCompositeRegion(®ion, 1636 source, mask, dest, 1637 x_source + 1638 (source_pixmap ? source->pDrawable->x : 0), 1639 y_source + 1640 (source_pixmap ? source->pDrawable->y : 0), 1641 x_mask + 1642 (mask_pixmap ? mask->pDrawable->x : 0), 1643 y_mask + 1644 (mask_pixmap ? mask->pDrawable->y : 0), 1645 x_dest + dest->pDrawable->x, 1646 y_dest + dest->pDrawable->y, width, height)) { 1647 return; 1648 } 1649 1650 nbox = REGION_NUM_RECTS(®ion); 1651 DEBUGF("first clipped when compositing.\n"); 1652 DEBUGRegionPrint(®ion); 1653 extent = RegionExtents(®ion); 1654 if (nbox == 0) 1655 return; 1656 1657 /* If destination is not a large pixmap, but the region is larger 1658 * than texture size limitation, and source or mask is memory pixmap, 1659 * then there may be need to load a large memory pixmap to a 1660 * texture, and this is not permitted. Then we force to clip the 1661 * destination and make sure latter will not upload a large memory 1662 * pixmap. */ 1663 if (!glamor_check_fbo_size(glamor_priv, 1664 extent->x2 - extent->x1, extent->y2 - extent->y1) 1665 && glamor_pixmap_is_large(dest_pixmap) 1666 && ((source_pixmap 1667 && (glamor_pixmap_is_memory(source_pixmap) || 1668 source->repeatType == RepeatPad)) 1669 || (mask_pixmap && 1670 (glamor_pixmap_is_memory(mask_pixmap) || 1671 mask->repeatType == RepeatPad)) 1672 || (!source_pixmap && 1673 (source->pSourcePict->type != SourcePictTypeSolidFill)) 1674 || (!mask_pixmap && mask && 1675 mask->pSourcePict->type != SourcePictTypeSolidFill))) 1676 force_clip = 1; 1677 1678 if (force_clip || glamor_pixmap_is_large(dest_pixmap) 1679 || (source_pixmap 1680 && glamor_pixmap_is_large(source_pixmap)) 1681 || (mask_pixmap && glamor_pixmap_is_large(mask_pixmap))) 1682 ok = glamor_composite_largepixmap_region(op, 1683 source, mask, dest, 1684 source_pixmap, 1685 mask_pixmap, 1686 dest_pixmap, 1687 ®ion, force_clip, 1688 x_source, y_source, 1689 x_mask, y_mask, 1690 x_dest, y_dest, width, height); 1691 else 1692 ok = glamor_composite_clipped_region(op, source, 1693 mask, dest, 1694 source_pixmap, 1695 mask_pixmap, 1696 dest_pixmap, 1697 ®ion, 1698 x_source, y_source, 1699 x_mask, y_mask, x_dest, y_dest); 1700 1701 REGION_UNINIT(dest->pDrawable->pScreen, ®ion); 1702 1703 if (ok) 1704 return; 1705 1706 fail: 1707 1708 glamor_fallback 1709 ("from picts %p:%p %dx%d / %p:%p %d x %d (%c,%c) to pict %p:%p %dx%d (%c)\n", 1710 source, source->pDrawable, 1711 source->pDrawable ? source->pDrawable->width : 0, 1712 source->pDrawable ? source->pDrawable->height : 0, mask, 1713 (!mask) ? NULL : mask->pDrawable, (!mask 1714 || !mask->pDrawable) ? 0 : 1715 mask->pDrawable->width, (!mask 1716 || !mask->pDrawable) ? 0 : mask-> 1717 pDrawable->height, glamor_get_picture_location(source), 1718 glamor_get_picture_location(mask), dest, dest->pDrawable, 1719 dest->pDrawable->width, dest->pDrawable->height, 1720 glamor_get_picture_location(dest)); 1721 1722 if (glamor_prepare_access_picture_box(dest, GLAMOR_ACCESS_RW, 1723 x_dest, y_dest, width, height) && 1724 glamor_prepare_access_picture_box(source, GLAMOR_ACCESS_RO, 1725 x_source, y_source, width, height) && 1726 glamor_prepare_access_picture_box(mask, GLAMOR_ACCESS_RO, 1727 x_mask, y_mask, width, height)) 1728 { 1729 fbComposite(op, 1730 source, mask, dest, 1731 x_source, y_source, 1732 x_mask, y_mask, x_dest, y_dest, width, height); 1733 } 1734 glamor_finish_access_picture(mask); 1735 glamor_finish_access_picture(source); 1736 glamor_finish_access_picture(dest); 1737} 1738