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