glamor_render.c revision 1b5d61b8
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 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 of an a8r8g8b8, or just 770 * force them to 1. 771 */ 772static Bool 773glamor_render_format_is_supported(PictFormatShort format) 774{ 775 switch (format) { 776 case PICT_x2r10g10b10: 777 case PICT_a8r8g8b8: 778 case PICT_x8r8g8b8: 779 case PICT_a8: 780 return TRUE; 781 default: 782 return FALSE; 783 } 784} 785 786static Bool 787glamor_composite_choose_shader(CARD8 op, 788 PicturePtr source, 789 PicturePtr mask, 790 PicturePtr dest, 791 PixmapPtr source_pixmap, 792 PixmapPtr mask_pixmap, 793 PixmapPtr dest_pixmap, 794 glamor_pixmap_private *source_pixmap_priv, 795 glamor_pixmap_private *mask_pixmap_priv, 796 glamor_pixmap_private *dest_pixmap_priv, 797 struct shader_key *s_key, 798 glamor_composite_shader ** shader, 799 struct blendinfo *op_info, 800 PictFormatShort *psaved_source_format, 801 enum ca_state ca_state) 802{ 803 ScreenPtr screen = dest->pDrawable->pScreen; 804 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 805 Bool source_needs_upload = FALSE; 806 Bool mask_needs_upload = FALSE; 807 PictFormatShort saved_source_format = 0; 808 struct shader_key key; 809 GLfloat source_solid_color[4]; 810 GLfloat mask_solid_color[4]; 811 Bool ret = FALSE; 812 813 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) { 814 glamor_fallback("dest has no fbo.\n"); 815 goto fail; 816 } 817 818 if (!glamor_render_format_is_supported(dest->format)) { 819 glamor_fallback("Unsupported dest picture format.\n"); 820 goto fail; 821 } 822 823 memset(&key, 0, sizeof(key)); 824 if (!source) { 825 key.source = SHADER_SOURCE_SOLID; 826 source_solid_color[0] = 0.0; 827 source_solid_color[1] = 0.0; 828 source_solid_color[2] = 0.0; 829 source_solid_color[3] = 0.0; 830 } 831 else if (!source->pDrawable) { 832 SourcePictPtr sp = source->pSourcePict; 833 if (sp->type == SourcePictTypeSolidFill) { 834 key.source = SHADER_SOURCE_SOLID; 835 glamor_get_rgba_from_color(&sp->solidFill.fullcolor, 836 source_solid_color); 837 } 838 else 839 goto fail; 840 } 841 else { 842 if (PICT_FORMAT_A(source->format)) 843 key.source = SHADER_SOURCE_TEXTURE_ALPHA; 844 else 845 key.source = SHADER_SOURCE_TEXTURE; 846 } 847 848 if (mask) { 849 if (!mask->pDrawable) { 850 SourcePictPtr sp = mask->pSourcePict; 851 if (sp->type == SourcePictTypeSolidFill) { 852 key.mask = SHADER_MASK_SOLID; 853 glamor_get_rgba_from_color(&sp->solidFill.fullcolor, 854 mask_solid_color); 855 } 856 else 857 goto fail; 858 } 859 else { 860 if (PICT_FORMAT_A(mask->format)) 861 key.mask = SHADER_MASK_TEXTURE_ALPHA; 862 else 863 key.mask = SHADER_MASK_TEXTURE; 864 } 865 866 if (!mask->componentAlpha) { 867 key.in = glamor_program_alpha_normal; 868 } 869 else { 870 if (op == PictOpClear) 871 key.mask = SHADER_MASK_NONE; 872 else if (glamor_priv->has_dual_blend) 873 key.in = glamor_program_alpha_dual_blend; 874 else if (op == PictOpSrc || op == PictOpAdd 875 || op == PictOpIn || op == PictOpOut 876 || op == PictOpOverReverse) 877 key.in = glamor_program_alpha_ca_second; 878 else if (op == PictOpOutReverse || op == PictOpInReverse) { 879 key.in = glamor_program_alpha_ca_first; 880 } 881 else { 882 glamor_fallback("Unsupported component alpha op: %d\n", op); 883 goto fail; 884 } 885 } 886 } 887 else { 888 key.mask = SHADER_MASK_NONE; 889 } 890 891 if (dest_pixmap->drawable.bitsPerPixel <= 8 && 892 glamor_priv->one_channel_format == GL_RED) { 893 key.dest_swizzle = SHADER_DEST_SWIZZLE_ALPHA_TO_RED; 894 } else { 895 key.dest_swizzle = SHADER_DEST_SWIZZLE_DEFAULT; 896 } 897 898 if (source && source->alphaMap) { 899 glamor_fallback("source alphaMap\n"); 900 goto fail; 901 } 902 if (mask && mask->alphaMap) { 903 glamor_fallback("mask alphaMap\n"); 904 goto fail; 905 } 906 907 if (key.source == SHADER_SOURCE_TEXTURE || 908 key.source == SHADER_SOURCE_TEXTURE_ALPHA) { 909 if (source_pixmap == dest_pixmap) { 910 /* XXX source and the dest share the same texture. 911 * Does it need special handle? */ 912 glamor_fallback("source == dest\n"); 913 } 914 if (source_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) { 915 source_needs_upload = TRUE; 916 } 917 } 918 919 if (key.mask == SHADER_MASK_TEXTURE || 920 key.mask == SHADER_MASK_TEXTURE_ALPHA) { 921 if (mask_pixmap == dest_pixmap) { 922 glamor_fallback("mask == dest\n"); 923 goto fail; 924 } 925 if (mask_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) { 926 mask_needs_upload = TRUE; 927 } 928 } 929 930 if (source_needs_upload && mask_needs_upload 931 && source_pixmap == mask_pixmap) { 932 933 if (source->format != mask->format) { 934 saved_source_format = source->format; 935 936 if (!combine_pict_format(&source->format, source->format, 937 mask->format, key.in)) { 938 glamor_fallback("combine source %x mask %x failed.\n", 939 source->format, mask->format); 940 goto fail; 941 } 942 943 /* XXX 944 * By default, glamor_upload_picture_to_texture will wire alpha to 1 945 * if one picture doesn't have alpha. So we don't do that again in 946 * rendering function. But here is a special case, as source and 947 * mask share the same texture but may have different formats. For 948 * example, source doesn't have alpha, but mask has alpha. Then the 949 * texture will have the alpha value for the mask. And will not wire 950 * to 1 for the source. In this case, we have to use different shader 951 * to wire the source's alpha to 1. 952 * 953 * But this may cause a potential problem if the source's repeat mode 954 * is REPEAT_NONE, and if the source is smaller than the dest, then 955 * for the region not covered by the source may be painted incorrectly. 956 * because we wire the alpha to 1. 957 * 958 **/ 959 if (!PICT_FORMAT_A(saved_source_format) 960 && PICT_FORMAT_A(mask->format)) 961 key.source = SHADER_SOURCE_TEXTURE; 962 963 if (!PICT_FORMAT_A(mask->format) 964 && PICT_FORMAT_A(saved_source_format)) 965 key.mask = SHADER_MASK_TEXTURE; 966 } 967 968 if (!glamor_upload_picture_to_texture(source)) { 969 glamor_fallback("Failed to upload source texture.\n"); 970 goto fail; 971 } 972 mask_needs_upload = FALSE; 973 } 974 else { 975 if (source_needs_upload) { 976 if (!glamor_upload_picture_to_texture(source)) { 977 glamor_fallback("Failed to upload source texture.\n"); 978 goto fail; 979 } 980 } else { 981 if (source && !glamor_render_format_is_supported(source->format)) { 982 glamor_fallback("Unsupported source picture format.\n"); 983 goto fail; 984 } 985 } 986 987 if (mask_needs_upload) { 988 if (!glamor_upload_picture_to_texture(mask)) { 989 glamor_fallback("Failed to upload mask texture.\n"); 990 goto fail; 991 } 992 } else if (mask) { 993 if (!glamor_render_format_is_supported(mask->format)) { 994 glamor_fallback("Unsupported mask picture format.\n"); 995 goto fail; 996 } 997 } 998 } 999 1000 /* If the source and mask are two differently-formatted views of 1001 * the same pixmap bits, and the pixmap was already uploaded (so 1002 * the dynamic code above doesn't apply), then fall back to 1003 * software. We should use texture views to fix this properly. 1004 */ 1005 if (source_pixmap && source_pixmap == mask_pixmap && 1006 source->format != mask->format) { 1007 goto fail; 1008 } 1009 1010 if (!glamor_set_composite_op(screen, op, op_info, dest, mask, ca_state, 1011 &key)) { 1012 goto fail; 1013 } 1014 1015 *shader = glamor_lookup_composite_shader(screen, &key); 1016 if ((*shader)->prog == 0) { 1017 glamor_fallback("no shader program for this render acccel mode\n"); 1018 goto fail; 1019 } 1020 1021 if (key.source == SHADER_SOURCE_SOLID) 1022 memcpy(&(*shader)->source_solid_color[0], 1023 source_solid_color, 4 * sizeof(float)); 1024 else { 1025 (*shader)->source_pixmap = source_pixmap; 1026 (*shader)->source = source; 1027 } 1028 1029 if (key.mask == SHADER_MASK_SOLID) 1030 memcpy(&(*shader)->mask_solid_color[0], 1031 mask_solid_color, 4 * sizeof(float)); 1032 else { 1033 (*shader)->mask_pixmap = mask_pixmap; 1034 (*shader)->mask = mask; 1035 } 1036 1037 ret = TRUE; 1038 memcpy(s_key, &key, sizeof(key)); 1039 *psaved_source_format = saved_source_format; 1040 goto done; 1041 1042 fail: 1043 if (saved_source_format) 1044 source->format = saved_source_format; 1045 done: 1046 return ret; 1047} 1048 1049static void 1050glamor_composite_set_shader_blend(glamor_screen_private *glamor_priv, 1051 glamor_pixmap_private *dest_priv, 1052 struct shader_key *key, 1053 glamor_composite_shader *shader, 1054 struct blendinfo *op_info) 1055{ 1056 glamor_make_current(glamor_priv); 1057 glUseProgram(shader->prog); 1058 1059 if (key->source == SHADER_SOURCE_SOLID) { 1060 glamor_set_composite_solid(shader->source_solid_color, 1061 shader->source_uniform_location); 1062 } 1063 else { 1064 glamor_set_composite_texture(glamor_priv, 0, 1065 shader->source, 1066 shader->source_pixmap, shader->source_wh, 1067 shader->source_repeat_mode, 1068 dest_priv); 1069 } 1070 1071 if (key->mask != SHADER_MASK_NONE) { 1072 if (key->mask == SHADER_MASK_SOLID) { 1073 glamor_set_composite_solid(shader->mask_solid_color, 1074 shader->mask_uniform_location); 1075 } 1076 else { 1077 glamor_set_composite_texture(glamor_priv, 1, 1078 shader->mask, 1079 shader->mask_pixmap, shader->mask_wh, 1080 shader->mask_repeat_mode, 1081 dest_priv); 1082 } 1083 } 1084 1085 if (glamor_priv->gl_flavor != GLAMOR_GL_ES2) 1086 glDisable(GL_COLOR_LOGIC_OP); 1087 1088 if (op_info->source_blend == GL_ONE && op_info->dest_blend == GL_ZERO) { 1089 glDisable(GL_BLEND); 1090 } 1091 else { 1092 glEnable(GL_BLEND); 1093 glBlendFunc(op_info->source_blend, op_info->dest_blend); 1094 } 1095} 1096 1097static Bool 1098glamor_composite_with_shader(CARD8 op, 1099 PicturePtr source, 1100 PicturePtr mask, 1101 PicturePtr dest, 1102 PixmapPtr source_pixmap, 1103 PixmapPtr mask_pixmap, 1104 PixmapPtr dest_pixmap, 1105 glamor_pixmap_private *source_pixmap_priv, 1106 glamor_pixmap_private *mask_pixmap_priv, 1107 glamor_pixmap_private *dest_pixmap_priv, 1108 int nrect, glamor_composite_rect_t *rects, 1109 enum ca_state ca_state) 1110{ 1111 ScreenPtr screen = dest->pDrawable->pScreen; 1112 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 1113 GLfloat dst_xscale, dst_yscale; 1114 GLfloat mask_xscale = 1, mask_yscale = 1, src_xscale = 1, src_yscale = 1; 1115 struct shader_key key, key_ca; 1116 int dest_x_off, dest_y_off; 1117 int source_x_off, source_y_off; 1118 int mask_x_off, mask_y_off; 1119 PictFormatShort saved_source_format = 0; 1120 float src_matrix[9], mask_matrix[9]; 1121 float *psrc_matrix = NULL, *pmask_matrix = NULL; 1122 int nrect_max; 1123 Bool ret = FALSE; 1124 glamor_composite_shader *shader = NULL, *shader_ca = NULL; 1125 struct blendinfo op_info, op_info_ca; 1126 1127 if (!glamor_composite_choose_shader(op, source, mask, dest, 1128 source_pixmap, mask_pixmap, dest_pixmap, 1129 source_pixmap_priv, mask_pixmap_priv, 1130 dest_pixmap_priv, 1131 &key, &shader, &op_info, 1132 &saved_source_format, ca_state)) { 1133 glamor_fallback("glamor_composite_choose_shader failed\n"); 1134 goto fail; 1135 } 1136 if (ca_state == CA_TWO_PASS) { 1137 if (!glamor_composite_choose_shader(PictOpAdd, source, mask, dest, 1138 source_pixmap, mask_pixmap, dest_pixmap, 1139 source_pixmap_priv, 1140 mask_pixmap_priv, dest_pixmap_priv, 1141 &key_ca, &shader_ca, &op_info_ca, 1142 &saved_source_format, ca_state)) { 1143 glamor_fallback("glamor_composite_choose_shader failed\n"); 1144 goto fail; 1145 } 1146 } 1147 1148 glamor_make_current(glamor_priv); 1149 1150 glamor_set_destination_pixmap_priv_nc(glamor_priv, dest_pixmap, dest_pixmap_priv); 1151 glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, &key, shader, &op_info); 1152 glamor_set_alu(screen, GXcopy); 1153 1154 glamor_priv->has_source_coords = key.source != SHADER_SOURCE_SOLID; 1155 glamor_priv->has_mask_coords = (key.mask != SHADER_MASK_NONE && 1156 key.mask != SHADER_MASK_SOLID); 1157 1158 dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable); 1159 dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); 1160 glamor_get_drawable_deltas(dest->pDrawable, dest_pixmap, 1161 &dest_x_off, &dest_y_off); 1162 pixmap_priv_get_dest_scale(dest_pixmap, dest_pixmap_priv, &dst_xscale, &dst_yscale); 1163 1164 if (glamor_priv->has_source_coords) { 1165 glamor_get_drawable_deltas(source->pDrawable, 1166 source_pixmap, &source_x_off, &source_y_off); 1167 pixmap_priv_get_scale(source_pixmap_priv, &src_xscale, &src_yscale); 1168 if (source->transform) { 1169 psrc_matrix = src_matrix; 1170 glamor_picture_get_matrixf(source, psrc_matrix); 1171 } 1172 } 1173 1174 if (glamor_priv->has_mask_coords) { 1175 glamor_get_drawable_deltas(mask->pDrawable, mask_pixmap, 1176 &mask_x_off, &mask_y_off); 1177 pixmap_priv_get_scale(mask_pixmap_priv, &mask_xscale, &mask_yscale); 1178 if (mask->transform) { 1179 pmask_matrix = mask_matrix; 1180 glamor_picture_get_matrixf(mask, pmask_matrix); 1181 } 1182 } 1183 1184 nrect_max = MIN(nrect, GLAMOR_COMPOSITE_VBO_VERT_CNT / 4); 1185 1186 if (nrect < 100) { 1187 BoxRec bounds = glamor_start_rendering_bounds(); 1188 1189 for (int i = 0; i < nrect; i++) { 1190 BoxRec box = { 1191 .x1 = rects[i].x_dst, 1192 .y1 = rects[i].y_dst, 1193 .x2 = rects[i].x_dst + rects[i].width, 1194 .y2 = rects[i].y_dst + rects[i].height, 1195 }; 1196 glamor_bounds_union_box(&bounds, &box); 1197 } 1198 1199 if (bounds.x1 >= bounds.x2 || bounds.y1 >= bounds.y2) 1200 goto disable_va; 1201 1202 glEnable(GL_SCISSOR_TEST); 1203 glScissor(bounds.x1 + dest_x_off, 1204 bounds.y1 + dest_y_off, 1205 bounds.x2 - bounds.x1, 1206 bounds.y2 - bounds.y1); 1207 } 1208 1209 while (nrect) { 1210 int mrect, rect_processed; 1211 int vb_stride; 1212 float *vertices; 1213 1214 mrect = nrect > nrect_max ? nrect_max : nrect; 1215 vertices = glamor_setup_composite_vbo(screen, mrect * 4); 1216 rect_processed = mrect; 1217 vb_stride = glamor_priv->vb_stride / sizeof(float); 1218 while (mrect--) { 1219 INT16 x_source; 1220 INT16 y_source; 1221 INT16 x_mask; 1222 INT16 y_mask; 1223 INT16 x_dest; 1224 INT16 y_dest; 1225 CARD16 width; 1226 CARD16 height; 1227 1228 x_dest = rects->x_dst + dest_x_off; 1229 y_dest = rects->y_dst + dest_y_off; 1230 x_source = rects->x_src + source_x_off; 1231 y_source = rects->y_src + source_y_off; 1232 x_mask = rects->x_mask + mask_x_off; 1233 y_mask = rects->y_mask + mask_y_off; 1234 width = rects->width; 1235 height = rects->height; 1236 1237 DEBUGF 1238 ("dest(%d,%d) source(%d %d) mask (%d %d), width %d height %d \n", 1239 x_dest, y_dest, x_source, y_source, x_mask, y_mask, width, 1240 height); 1241 1242 glamor_set_normalize_vcoords_ext(dest_pixmap_priv, dst_xscale, 1243 dst_yscale, x_dest, y_dest, 1244 x_dest + width, y_dest + height, 1245 vertices, 1246 vb_stride); 1247 vertices += 2; 1248 if (key.source != SHADER_SOURCE_SOLID) { 1249 glamor_set_normalize_tcoords_generic(source_pixmap, 1250 source_pixmap_priv, 1251 source->repeatType, 1252 psrc_matrix, src_xscale, 1253 src_yscale, x_source, 1254 y_source, x_source + width, 1255 y_source + height, 1256 vertices, vb_stride); 1257 vertices += 2; 1258 } 1259 1260 if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID) { 1261 glamor_set_normalize_tcoords_generic(mask_pixmap, 1262 mask_pixmap_priv, 1263 mask->repeatType, 1264 pmask_matrix, mask_xscale, 1265 mask_yscale, x_mask, 1266 y_mask, x_mask + width, 1267 y_mask + height, 1268 vertices, vb_stride); 1269 vertices += 2; 1270 } 1271 glamor_priv->render_nr_quads++; 1272 rects++; 1273 1274 /* We've incremented by one of our 4 verts, now do the other 3. */ 1275 vertices += 3 * vb_stride; 1276 } 1277 glamor_put_vbo_space(screen); 1278 glamor_flush_composite_rects(screen); 1279 nrect -= rect_processed; 1280 if (ca_state == CA_TWO_PASS) { 1281 glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, 1282 &key_ca, shader_ca, &op_info_ca); 1283 glamor_flush_composite_rects(screen); 1284 if (nrect) 1285 glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, 1286 &key, shader, &op_info); 1287 } 1288 } 1289 1290 glDisable(GL_SCISSOR_TEST); 1291disable_va: 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 1302fail: 1303 if (mask_pixmap && glamor_pixmap_is_memory(mask_pixmap)) 1304 glamor_pixmap_destroy_fbo(mask_pixmap); 1305 if (source_pixmap && glamor_pixmap_is_memory(source_pixmap)) 1306 glamor_pixmap_destroy_fbo(source_pixmap); 1307 1308 return ret; 1309} 1310 1311static PicturePtr 1312glamor_convert_gradient_picture(ScreenPtr screen, 1313 PicturePtr source, 1314 int x_source, 1315 int y_source, int width, int height) 1316{ 1317 PixmapPtr pixmap; 1318 PicturePtr dst = NULL; 1319 int error; 1320 PictFormatPtr pFormat; 1321 PictFormatShort format; 1322 1323 if (source->pDrawable) { 1324 pFormat = source->pFormat; 1325 format = pFormat->format; 1326 } else { 1327 format = PICT_a8r8g8b8; 1328 pFormat = PictureMatchFormat(screen, 32, format); 1329 } 1330 1331 if (!source->pDrawable) { 1332 if (source->pSourcePict->type == SourcePictTypeLinear) { 1333 dst = glamor_generate_linear_gradient_picture(screen, 1334 source, x_source, 1335 y_source, width, 1336 height, format); 1337 } 1338 else if (source->pSourcePict->type == SourcePictTypeRadial) { 1339 dst = glamor_generate_radial_gradient_picture(screen, 1340 source, x_source, 1341 y_source, width, 1342 height, format); 1343 } 1344 1345 if (dst) { 1346 return dst; 1347 } 1348 } 1349 1350 pixmap = glamor_create_pixmap(screen, 1351 width, 1352 height, 1353 PIXMAN_FORMAT_DEPTH(format), 1354 GLAMOR_CREATE_PIXMAP_CPU); 1355 1356 if (!pixmap) 1357 return NULL; 1358 1359 dst = CreatePicture(0, 1360 &pixmap->drawable, pFormat, 0, 0, serverClient, &error); 1361 glamor_destroy_pixmap(pixmap); 1362 if (!dst) 1363 return NULL; 1364 1365 ValidatePicture(dst); 1366 1367 fbComposite(PictOpSrc, source, NULL, dst, x_source, y_source, 1368 0, 0, 0, 0, width, height); 1369 return dst; 1370} 1371 1372Bool 1373glamor_composite_clipped_region(CARD8 op, 1374 PicturePtr source, 1375 PicturePtr mask, 1376 PicturePtr dest, 1377 PixmapPtr source_pixmap, 1378 PixmapPtr mask_pixmap, 1379 PixmapPtr dest_pixmap, 1380 RegionPtr region, 1381 int x_source, 1382 int y_source, 1383 int x_mask, int y_mask, int x_dest, int y_dest) 1384{ 1385 glamor_pixmap_private *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); 1386 glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap); 1387 glamor_pixmap_private *dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); 1388 glamor_screen_private *glamor_priv = glamor_get_screen_private(dest_pixmap->drawable.pScreen); 1389 ScreenPtr screen = dest->pDrawable->pScreen; 1390 PicturePtr temp_src = source, temp_mask = mask; 1391 PixmapPtr temp_src_pixmap = source_pixmap; 1392 PixmapPtr temp_mask_pixmap = mask_pixmap; 1393 glamor_pixmap_private *temp_src_priv = source_pixmap_priv; 1394 glamor_pixmap_private *temp_mask_priv = mask_pixmap_priv; 1395 int x_temp_src, y_temp_src, x_temp_mask, y_temp_mask; 1396 BoxPtr extent; 1397 glamor_composite_rect_t rect[10]; 1398 glamor_composite_rect_t *prect = rect; 1399 int prect_size = ARRAY_SIZE(rect); 1400 int ok = FALSE; 1401 int i; 1402 int width; 1403 int height; 1404 BoxPtr box; 1405 int nbox; 1406 enum ca_state ca_state = CA_NONE; 1407 1408 extent = RegionExtents(region); 1409 box = RegionRects(region); 1410 nbox = RegionNumRects(region); 1411 width = extent->x2 - extent->x1; 1412 height = extent->y2 - extent->y1; 1413 1414 x_temp_src = x_source; 1415 y_temp_src = y_source; 1416 x_temp_mask = x_mask; 1417 y_temp_mask = y_mask; 1418 1419 DEBUGF("clipped (%d %d) (%d %d) (%d %d) width %d height %d \n", 1420 x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height); 1421 1422 /* Is the composite operation equivalent to a copy? */ 1423 if (source && 1424 !mask && !source->alphaMap && !dest->alphaMap 1425 && source->pDrawable && !source->transform 1426 /* CopyArea is only defined with matching depths. */ 1427 && dest->pDrawable->depth == source->pDrawable->depth 1428 && ((op == PictOpSrc 1429 && (source->format == dest->format 1430 || (PICT_FORMAT_COLOR(dest->format) 1431 && PICT_FORMAT_COLOR(source->format) 1432 && dest->format == PICT_FORMAT(PICT_FORMAT_BPP(source->format), 1433 PICT_FORMAT_TYPE(source->format), 1434 0, 1435 PICT_FORMAT_R(source->format), 1436 PICT_FORMAT_G(source->format), 1437 PICT_FORMAT_B(source->format))))) 1438 || (op == PictOpOver 1439 && source->format == dest->format 1440 && !PICT_FORMAT_A(source->format))) 1441 && x_source >= 0 && y_source >= 0 1442 && (x_source + width) <= source->pDrawable->width 1443 && (y_source + height) <= source->pDrawable->height) { 1444 x_source += source->pDrawable->x; 1445 y_source += source->pDrawable->y; 1446 x_dest += dest->pDrawable->x; 1447 y_dest += dest->pDrawable->y; 1448 glamor_copy(source->pDrawable, dest->pDrawable, NULL, 1449 box, nbox, x_source - x_dest, 1450 y_source - y_dest, FALSE, FALSE, 0, NULL); 1451 ok = TRUE; 1452 goto out; 1453 } 1454 1455 /* XXX is it possible source mask have non-zero drawable.x/y? */ 1456 if (source 1457 && ((!source->pDrawable 1458 && (source->pSourcePict->type != SourcePictTypeSolidFill)) 1459 || (source->pDrawable 1460 && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv) 1461 && (source_pixmap->drawable.width != width 1462 || source_pixmap->drawable.height != height)))) { 1463 temp_src = 1464 glamor_convert_gradient_picture(screen, source, 1465 extent->x1 + x_source - x_dest - dest->pDrawable->x, 1466 extent->y1 + y_source - y_dest - dest->pDrawable->y, 1467 width, height); 1468 if (!temp_src) { 1469 temp_src = source; 1470 goto out; 1471 } 1472 temp_src_pixmap = (PixmapPtr) (temp_src->pDrawable); 1473 temp_src_priv = glamor_get_pixmap_private(temp_src_pixmap); 1474 x_temp_src = -extent->x1 + x_dest + dest->pDrawable->x; 1475 y_temp_src = -extent->y1 + y_dest + dest->pDrawable->y; 1476 } 1477 1478 if (mask 1479 && 1480 ((!mask->pDrawable 1481 && (mask->pSourcePict->type != SourcePictTypeSolidFill)) 1482 || (mask->pDrawable && !GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv) 1483 && (mask_pixmap->drawable.width != width 1484 || mask_pixmap->drawable.height != height)))) { 1485 /* XXX if mask->pDrawable is the same as source->pDrawable, we have an opportunity 1486 * to do reduce one conversion. */ 1487 temp_mask = 1488 glamor_convert_gradient_picture(screen, mask, 1489 extent->x1 + x_mask - x_dest - dest->pDrawable->x, 1490 extent->y1 + y_mask - y_dest - dest->pDrawable->y, 1491 width, height); 1492 if (!temp_mask) { 1493 temp_mask = mask; 1494 goto out; 1495 } 1496 temp_mask_pixmap = (PixmapPtr) (temp_mask->pDrawable); 1497 temp_mask_priv = glamor_get_pixmap_private(temp_mask_pixmap); 1498 x_temp_mask = -extent->x1 + x_dest + dest->pDrawable->x; 1499 y_temp_mask = -extent->y1 + y_dest + dest->pDrawable->y; 1500 } 1501 1502 if (mask && mask->componentAlpha) { 1503 if (glamor_priv->has_dual_blend) { 1504 ca_state = CA_DUAL_BLEND; 1505 } else { 1506 if (op == PictOpOver) { 1507 if (glamor_pixmap_is_memory(mask_pixmap)) { 1508 glamor_fallback("two pass not supported on memory pximaps\n"); 1509 goto out; 1510 } 1511 ca_state = CA_TWO_PASS; 1512 op = PictOpOutReverse; 1513 } 1514 } 1515 } 1516 1517 if (temp_src_pixmap == dest_pixmap) { 1518 glamor_fallback("source and dest pixmaps are the same\n"); 1519 goto out; 1520 } 1521 if (temp_mask_pixmap == dest_pixmap) { 1522 glamor_fallback("mask and dest pixmaps are the same\n"); 1523 goto out; 1524 } 1525 1526 x_dest += dest->pDrawable->x; 1527 y_dest += dest->pDrawable->y; 1528 if (temp_src && temp_src->pDrawable) { 1529 x_temp_src += temp_src->pDrawable->x; 1530 y_temp_src += temp_src->pDrawable->y; 1531 } 1532 if (temp_mask && temp_mask->pDrawable) { 1533 x_temp_mask += temp_mask->pDrawable->x; 1534 y_temp_mask += temp_mask->pDrawable->y; 1535 } 1536 1537 if (nbox > ARRAY_SIZE(rect)) { 1538 prect = calloc(nbox, sizeof(*prect)); 1539 if (prect) 1540 prect_size = nbox; 1541 else { 1542 prect = rect; 1543 prect_size = ARRAY_SIZE(rect); 1544 } 1545 } 1546 while (nbox) { 1547 int box_cnt; 1548 1549 box_cnt = nbox > prect_size ? prect_size : nbox; 1550 for (i = 0; i < box_cnt; i++) { 1551 prect[i].x_src = box[i].x1 + x_temp_src - x_dest; 1552 prect[i].y_src = box[i].y1 + y_temp_src - y_dest; 1553 prect[i].x_mask = box[i].x1 + x_temp_mask - x_dest; 1554 prect[i].y_mask = box[i].y1 + y_temp_mask - y_dest; 1555 prect[i].x_dst = box[i].x1; 1556 prect[i].y_dst = box[i].y1; 1557 prect[i].width = box[i].x2 - box[i].x1; 1558 prect[i].height = box[i].y2 - box[i].y1; 1559 DEBUGF("dest %d %d \n", prect[i].x_dst, prect[i].y_dst); 1560 } 1561 ok = glamor_composite_with_shader(op, temp_src, temp_mask, dest, 1562 temp_src_pixmap, temp_mask_pixmap, dest_pixmap, 1563 temp_src_priv, temp_mask_priv, 1564 dest_pixmap_priv, 1565 box_cnt, prect, ca_state); 1566 if (!ok) 1567 break; 1568 nbox -= box_cnt; 1569 box += box_cnt; 1570 } 1571 1572 if (prect != rect) 1573 free(prect); 1574 out: 1575 if (temp_src != source) 1576 FreePicture(temp_src, 0); 1577 if (temp_mask != mask) 1578 FreePicture(temp_mask, 0); 1579 1580 return ok; 1581} 1582 1583void 1584glamor_composite(CARD8 op, 1585 PicturePtr source, 1586 PicturePtr mask, 1587 PicturePtr dest, 1588 INT16 x_source, 1589 INT16 y_source, 1590 INT16 x_mask, 1591 INT16 y_mask, 1592 INT16 x_dest, INT16 y_dest, CARD16 width, CARD16 height) 1593{ 1594 ScreenPtr screen = dest->pDrawable->pScreen; 1595 PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable); 1596 PixmapPtr source_pixmap = NULL, mask_pixmap = NULL; 1597 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 1598 RegionRec region; 1599 BoxPtr extent; 1600 int nbox, ok = FALSE; 1601 int force_clip = 0; 1602 1603 if (source->pDrawable) { 1604 source_pixmap = glamor_get_drawable_pixmap(source->pDrawable); 1605 if (glamor_pixmap_drm_only(source_pixmap)) 1606 goto fail; 1607 } 1608 1609 if (mask && mask->pDrawable) { 1610 mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable); 1611 if (glamor_pixmap_drm_only(mask_pixmap)) 1612 goto fail; 1613 } 1614 1615 DEBUGF 1616 ("source pixmap %p (%d %d) mask(%d %d) dest(%d %d) width %d height %d \n", 1617 source_pixmap, x_source, y_source, x_mask, y_mask, x_dest, y_dest, 1618 width, height); 1619 1620 if (!glamor_pixmap_has_fbo(dest_pixmap)) 1621 goto fail; 1622 1623 if (op >= ARRAY_SIZE(composite_op_info)) { 1624 glamor_fallback("Unsupported composite op %x\n", op); 1625 goto fail; 1626 } 1627 1628 if (mask && mask->componentAlpha && !glamor_priv->has_dual_blend) { 1629 if (op == PictOpAtop 1630 || op == PictOpAtopReverse 1631 || op == PictOpXor || op >= PictOpSaturate) { 1632 glamor_fallback("glamor_composite(): component alpha op %x\n", op); 1633 goto fail; 1634 } 1635 } 1636 1637 if ((source && source->filter >= PictFilterConvolution) 1638 || (mask && mask->filter >= PictFilterConvolution)) { 1639 glamor_fallback("glamor_composite(): unsupported filter\n"); 1640 goto fail; 1641 } 1642 1643 if (!miComputeCompositeRegion(®ion, 1644 source, mask, dest, 1645 x_source + 1646 (source_pixmap ? source->pDrawable->x : 0), 1647 y_source + 1648 (source_pixmap ? source->pDrawable->y : 0), 1649 x_mask + 1650 (mask_pixmap ? mask->pDrawable->x : 0), 1651 y_mask + 1652 (mask_pixmap ? mask->pDrawable->y : 0), 1653 x_dest + dest->pDrawable->x, 1654 y_dest + dest->pDrawable->y, width, height)) { 1655 return; 1656 } 1657 1658 nbox = REGION_NUM_RECTS(®ion); 1659 DEBUGF("first clipped when compositing.\n"); 1660 DEBUGRegionPrint(®ion); 1661 extent = RegionExtents(®ion); 1662 if (nbox == 0) 1663 return; 1664 1665 /* If destination is not a large pixmap, but the region is larger 1666 * than texture size limitation, and source or mask is memory pixmap, 1667 * then there may be need to load a large memory pixmap to a 1668 * texture, and this is not permitted. Then we force to clip the 1669 * destination and make sure latter will not upload a large memory 1670 * pixmap. */ 1671 if (!glamor_check_fbo_size(glamor_priv, 1672 extent->x2 - extent->x1, extent->y2 - extent->y1) 1673 && glamor_pixmap_is_large(dest_pixmap) 1674 && ((source_pixmap 1675 && (glamor_pixmap_is_memory(source_pixmap) || 1676 source->repeatType == RepeatPad)) 1677 || (mask_pixmap && 1678 (glamor_pixmap_is_memory(mask_pixmap) || 1679 mask->repeatType == RepeatPad)) 1680 || (!source_pixmap && 1681 (source->pSourcePict->type != SourcePictTypeSolidFill)) 1682 || (!mask_pixmap && mask && 1683 mask->pSourcePict->type != SourcePictTypeSolidFill))) 1684 force_clip = 1; 1685 1686 if (force_clip || glamor_pixmap_is_large(dest_pixmap) 1687 || (source_pixmap 1688 && glamor_pixmap_is_large(source_pixmap)) 1689 || (mask_pixmap && glamor_pixmap_is_large(mask_pixmap))) 1690 ok = glamor_composite_largepixmap_region(op, 1691 source, mask, dest, 1692 source_pixmap, 1693 mask_pixmap, 1694 dest_pixmap, 1695 ®ion, force_clip, 1696 x_source, y_source, 1697 x_mask, y_mask, 1698 x_dest, y_dest, width, height); 1699 else 1700 ok = glamor_composite_clipped_region(op, source, 1701 mask, dest, 1702 source_pixmap, 1703 mask_pixmap, 1704 dest_pixmap, 1705 ®ion, 1706 x_source, y_source, 1707 x_mask, y_mask, x_dest, y_dest); 1708 1709 REGION_UNINIT(dest->pDrawable->pScreen, ®ion); 1710 1711 if (ok) 1712 return; 1713 1714 fail: 1715 1716 glamor_fallback 1717 ("from picts %p:%p %dx%d / %p:%p %d x %d (%c,%c) to pict %p:%p %dx%d (%c)\n", 1718 source, source->pDrawable, 1719 source->pDrawable ? source->pDrawable->width : 0, 1720 source->pDrawable ? source->pDrawable->height : 0, mask, 1721 (!mask) ? NULL : mask->pDrawable, 1722 (!mask || !mask->pDrawable) ? 0 : mask->pDrawable->width, 1723 (!mask || !mask->pDrawable) ? 0 : mask->pDrawable->height, 1724 glamor_get_picture_location(source), 1725 glamor_get_picture_location(mask), 1726 dest, dest->pDrawable, 1727 dest->pDrawable->width, dest->pDrawable->height, 1728 glamor_get_picture_location(dest)); 1729 1730 if (glamor_prepare_access_picture_box(dest, GLAMOR_ACCESS_RW, 1731 x_dest, y_dest, width, height) && 1732 glamor_prepare_access_picture_box(source, GLAMOR_ACCESS_RO, 1733 x_source, y_source, width, height) && 1734 glamor_prepare_access_picture_box(mask, GLAMOR_ACCESS_RO, 1735 x_mask, y_mask, width, height)) 1736 { 1737 fbComposite(op, 1738 source, mask, dest, 1739 x_source, y_source, 1740 x_mask, y_mask, x_dest, y_dest, width, height); 1741 } 1742 glamor_finish_access_picture(mask); 1743 glamor_finish_access_picture(source); 1744 glamor_finish_access_picture(dest); 1745} 1746