glamor_largepixmap.c revision 35c4bbdf
1#include <stdlib.h> 2 3#include "glamor_priv.h" 4 5static void 6glamor_get_transform_extent_from_box(struct pixman_box32 *box, 7 struct pixman_transform *transform); 8 9static inline glamor_pixmap_private * 10__glamor_large(glamor_pixmap_private *pixmap_priv) { 11 assert(glamor_pixmap_priv_is_large(pixmap_priv)); 12 return pixmap_priv; 13} 14 15/** 16 * Clip the boxes regards to each pixmap's block array. 17 * 18 * Should translate the region to relative coords to the pixmap, 19 * start at (0,0). 20 */ 21#if 0 22//#define DEBUGF(str, ...) do {} while(0) 23#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__) 24//#define DEBUGRegionPrint(x) do {} while (0) 25#define DEBUGRegionPrint RegionPrint 26#endif 27 28static glamor_pixmap_clipped_regions * 29__glamor_compute_clipped_regions(int block_w, 30 int block_h, 31 int block_stride, 32 int x, int y, 33 int w, int h, 34 RegionPtr region, 35 int *n_region, int reverse, int upsidedown) 36{ 37 glamor_pixmap_clipped_regions *clipped_regions; 38 BoxPtr extent; 39 int start_x, start_y, end_x, end_y; 40 int start_block_x, start_block_y; 41 int end_block_x, end_block_y; 42 int loop_start_block_x, loop_start_block_y; 43 int loop_end_block_x, loop_end_block_y; 44 int loop_block_stride; 45 int i, j, delta_i, delta_j; 46 RegionRec temp_region; 47 RegionPtr current_region; 48 int block_idx; 49 int k = 0; 50 int temp_block_idx; 51 52 extent = RegionExtents(region); 53 start_x = MAX(x, extent->x1); 54 start_y = MAX(y, extent->y1); 55 end_x = MIN(x + w, extent->x2); 56 end_y = MIN(y + h, extent->y2); 57 58 DEBUGF("start compute clipped regions:\n"); 59 DEBUGF("block w %d h %d x %d y %d w %d h %d, block_stride %d \n", 60 block_w, block_h, x, y, w, h, block_stride); 61 DEBUGRegionPrint(region); 62 63 DEBUGF("start_x %d start_y %d end_x %d end_y %d \n", start_x, start_y, 64 end_x, end_y); 65 66 if (start_x >= end_x || start_y >= end_y) { 67 *n_region = 0; 68 return NULL; 69 } 70 71 start_block_x = (start_x - x) / block_w; 72 start_block_y = (start_y - y) / block_h; 73 end_block_x = (end_x - x) / block_w; 74 end_block_y = (end_y - y) / block_h; 75 76 clipped_regions = calloc((end_block_x - start_block_x + 1) 77 * (end_block_y - start_block_y + 1), 78 sizeof(*clipped_regions)); 79 80 DEBUGF("startx %d starty %d endx %d endy %d \n", 81 start_x, start_y, end_x, end_y); 82 DEBUGF("start_block_x %d end_block_x %d \n", start_block_x, end_block_x); 83 DEBUGF("start_block_y %d end_block_y %d \n", start_block_y, end_block_y); 84 85 if (!reverse) { 86 loop_start_block_x = start_block_x; 87 loop_end_block_x = end_block_x + 1; 88 delta_i = 1; 89 } 90 else { 91 loop_start_block_x = end_block_x; 92 loop_end_block_x = start_block_x - 1; 93 delta_i = -1; 94 } 95 96 if (!upsidedown) { 97 loop_start_block_y = start_block_y; 98 loop_end_block_y = end_block_y + 1; 99 delta_j = 1; 100 } 101 else { 102 loop_start_block_y = end_block_y; 103 loop_end_block_y = start_block_y - 1; 104 delta_j = -1; 105 } 106 107 loop_block_stride = delta_j * block_stride; 108 block_idx = (loop_start_block_y - delta_j) * block_stride; 109 110 for (j = loop_start_block_y; j != loop_end_block_y; j += delta_j) { 111 block_idx += loop_block_stride; 112 temp_block_idx = block_idx + loop_start_block_x; 113 for (i = loop_start_block_x; 114 i != loop_end_block_x; i += delta_i, temp_block_idx += delta_i) { 115 BoxRec temp_box; 116 117 temp_box.x1 = x + i * block_w; 118 temp_box.y1 = y + j * block_h; 119 temp_box.x2 = MIN(temp_box.x1 + block_w, end_x); 120 temp_box.y2 = MIN(temp_box.y1 + block_h, end_y); 121 RegionInitBoxes(&temp_region, &temp_box, 1); 122 DEBUGF("block idx %d \n", temp_block_idx); 123 DEBUGRegionPrint(&temp_region); 124 current_region = RegionCreate(NULL, 4); 125 RegionIntersect(current_region, &temp_region, region); 126 DEBUGF("i %d j %d region: \n", i, j); 127 DEBUGRegionPrint(current_region); 128 if (RegionNumRects(current_region)) { 129 clipped_regions[k].region = current_region; 130 clipped_regions[k].block_idx = temp_block_idx; 131 k++; 132 } 133 else 134 RegionDestroy(current_region); 135 RegionUninit(&temp_region); 136 } 137 } 138 139 *n_region = k; 140 return clipped_regions; 141} 142 143/** 144 * Do a two round clipping, 145 * first is to clip the region regard to current pixmap's 146 * block array. Then for each clipped region, do a inner 147 * block clipping. This is to make sure the final result 148 * will be shapped by inner_block_w and inner_block_h, and 149 * the final region also will not cross the pixmap's block 150 * boundary. 151 * 152 * This is mainly used by transformation support when do 153 * compositing. 154 */ 155 156glamor_pixmap_clipped_regions * 157glamor_compute_clipped_regions_ext(PixmapPtr pixmap, 158 RegionPtr region, 159 int *n_region, 160 int inner_block_w, int inner_block_h, 161 int reverse, int upsidedown) 162{ 163 glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 164 glamor_pixmap_clipped_regions *clipped_regions, *inner_regions, 165 *result_regions; 166 int i, j, x, y, k, inner_n_regions; 167 int width, height; 168 BoxPtr box_array; 169 BoxRec small_box; 170 int block_w, block_h; 171 172 DEBUGF("ext called \n"); 173 174 if (glamor_pixmap_priv_is_small(pixmap_priv)) { 175 clipped_regions = calloc(1, sizeof(*clipped_regions)); 176 if (clipped_regions == NULL) { 177 *n_region = 0; 178 return NULL; 179 } 180 clipped_regions[0].region = RegionCreate(NULL, 1); 181 clipped_regions[0].block_idx = 0; 182 RegionCopy(clipped_regions[0].region, region); 183 *n_region = 1; 184 block_w = pixmap->drawable.width; 185 block_h = pixmap->drawable.height; 186 box_array = &small_box; 187 small_box.x1 = small_box.y1 = 0; 188 small_box.x2 = block_w; 189 small_box.y2 = block_h; 190 } 191 else { 192 glamor_pixmap_private *priv = __glamor_large(pixmap_priv); 193 194 clipped_regions = __glamor_compute_clipped_regions(priv->block_w, 195 priv->block_h, 196 priv->block_wcnt, 197 0, 0, 198 pixmap->drawable.width, 199 pixmap->drawable.height, 200 region, n_region, 201 reverse, upsidedown); 202 203 if (clipped_regions == NULL) { 204 *n_region = 0; 205 return NULL; 206 } 207 block_w = priv->block_w; 208 block_h = priv->block_h; 209 box_array = priv->box_array; 210 } 211 if (inner_block_w >= block_w && inner_block_h >= block_h) 212 return clipped_regions; 213 result_regions = calloc(*n_region 214 * ((block_w + inner_block_w - 1) / 215 inner_block_w) 216 * ((block_h + inner_block_h - 1) / 217 inner_block_h), sizeof(*result_regions)); 218 k = 0; 219 for (i = 0; i < *n_region; i++) { 220 x = box_array[clipped_regions[i].block_idx].x1; 221 y = box_array[clipped_regions[i].block_idx].y1; 222 width = box_array[clipped_regions[i].block_idx].x2 - x; 223 height = box_array[clipped_regions[i].block_idx].y2 - y; 224 inner_regions = __glamor_compute_clipped_regions(inner_block_w, 225 inner_block_h, 226 0, x, y, 227 width, 228 height, 229 clipped_regions[i]. 230 region, 231 &inner_n_regions, 232 reverse, upsidedown); 233 for (j = 0; j < inner_n_regions; j++) { 234 result_regions[k].region = inner_regions[j].region; 235 result_regions[k].block_idx = clipped_regions[i].block_idx; 236 k++; 237 } 238 free(inner_regions); 239 } 240 *n_region = k; 241 free(clipped_regions); 242 return result_regions; 243} 244 245/* 246 * 247 * For the repeat pad mode, we can simply convert the region and 248 * let the out-of-box region can cover the needed edge of the source/mask 249 * Then apply a normal clip we can get what we want. 250 */ 251static RegionPtr 252_glamor_convert_pad_region(RegionPtr region, int w, int h) 253{ 254 RegionPtr pad_region; 255 int nrect; 256 BoxPtr box; 257 int overlap; 258 259 nrect = RegionNumRects(region); 260 box = RegionRects(region); 261 pad_region = RegionCreate(NULL, 4); 262 if (pad_region == NULL) 263 return NULL; 264 while (nrect--) { 265 BoxRec pad_box; 266 RegionRec temp_region; 267 268 pad_box = *box; 269 if (pad_box.x1 < 0 && pad_box.x2 <= 0) 270 pad_box.x2 = 1; 271 else if (pad_box.x1 >= w && pad_box.x2 > w) 272 pad_box.x1 = w - 1; 273 if (pad_box.y1 < 0 && pad_box.y2 <= 0) 274 pad_box.y2 = 1; 275 else if (pad_box.y1 >= h && pad_box.y2 > h) 276 pad_box.y1 = h - 1; 277 RegionInitBoxes(&temp_region, &pad_box, 1); 278 RegionAppend(pad_region, &temp_region); 279 RegionUninit(&temp_region); 280 box++; 281 } 282 RegionValidate(pad_region, &overlap); 283 return pad_region; 284} 285 286/* 287 * For one type of large pixmap, its one direction is not exceed the 288 * size limitation, and in another word, on one direction it has only 289 * one block. 290 * 291 * This case of reflect repeating, we can optimize it and avoid repeat 292 * clip on that direction. We can just enlarge the repeat box and can 293 * cover all the dest region on that direction. But latter, we need to 294 * fixup the clipped result to get a correct coords for the subsequent 295 * processing. This function is to do the coords correction. 296 * 297 * */ 298static void 299_glamor_largepixmap_reflect_fixup(short *xy1, short *xy2, int wh) 300{ 301 int odd1, odd2; 302 int c1, c2; 303 304 if (*xy2 - *xy1 > wh) { 305 *xy1 = 0; 306 *xy2 = wh; 307 return; 308 } 309 modulus(*xy1, wh, c1); 310 odd1 = ((*xy1 - c1) / wh) & 0x1; 311 modulus(*xy2, wh, c2); 312 odd2 = ((*xy2 - c2) / wh) & 0x1; 313 314 if (odd1 && odd2) { 315 *xy1 = wh - c2; 316 *xy2 = wh - c1; 317 } 318 else if (odd1 && !odd2) { 319 *xy1 = 0; 320 *xy2 = MAX(c2, wh - c1); 321 } 322 else if (!odd1 && odd2) { 323 *xy2 = wh; 324 *xy1 = MIN(c1, wh - c2); 325 } 326 else { 327 *xy1 = c1; 328 *xy2 = c2; 329 } 330} 331 332/** 333 * Clip the boxes regards to each pixmap's block array. 334 * 335 * Should translate the region to relative coords to the pixmap, 336 * start at (0,0). 337 * 338 * @is_transform: if it is set, it has a transform matrix. 339 * 340 */ 341static glamor_pixmap_clipped_regions * 342_glamor_compute_clipped_regions(PixmapPtr pixmap, 343 glamor_pixmap_private *pixmap_priv, 344 RegionPtr region, int *n_region, 345 int repeat_type, int is_transform, 346 int reverse, int upsidedown) 347{ 348 glamor_pixmap_clipped_regions *clipped_regions; 349 BoxPtr extent; 350 int i, j; 351 RegionPtr current_region; 352 int pixmap_width, pixmap_height; 353 int m; 354 BoxRec repeat_box; 355 RegionRec repeat_region; 356 int right_shift = 0; 357 int down_shift = 0; 358 int x_center_shift = 0, y_center_shift = 0; 359 glamor_pixmap_private *priv; 360 361 DEBUGRegionPrint(region); 362 if (glamor_pixmap_priv_is_small(pixmap_priv)) { 363 clipped_regions = calloc(1, sizeof(*clipped_regions)); 364 clipped_regions[0].region = RegionCreate(NULL, 1); 365 clipped_regions[0].block_idx = 0; 366 RegionCopy(clipped_regions[0].region, region); 367 *n_region = 1; 368 return clipped_regions; 369 } 370 371 priv = __glamor_large(pixmap_priv); 372 373 pixmap_width = pixmap->drawable.width; 374 pixmap_height = pixmap->drawable.height; 375 if (repeat_type == 0 || repeat_type == RepeatPad) { 376 RegionPtr saved_region = NULL; 377 378 if (repeat_type == RepeatPad) { 379 saved_region = region; 380 region = 381 _glamor_convert_pad_region(saved_region, pixmap_width, 382 pixmap_height); 383 if (region == NULL) { 384 *n_region = 0; 385 return NULL; 386 } 387 } 388 clipped_regions = __glamor_compute_clipped_regions(priv->block_w, 389 priv->block_h, 390 priv->block_wcnt, 391 0, 0, 392 pixmap->drawable.width, 393 pixmap->drawable.height, 394 region, n_region, 395 reverse, upsidedown); 396 if (saved_region) 397 RegionDestroy(region); 398 return clipped_regions; 399 } 400 extent = RegionExtents(region); 401 402 x_center_shift = extent->x1 / pixmap_width; 403 if (x_center_shift < 0) 404 x_center_shift--; 405 if (abs(x_center_shift) & 1) 406 x_center_shift++; 407 y_center_shift = extent->y1 / pixmap_height; 408 if (y_center_shift < 0) 409 y_center_shift--; 410 if (abs(y_center_shift) & 1) 411 y_center_shift++; 412 413 if (extent->x1 < 0) 414 right_shift = ((-extent->x1 + pixmap_width - 1) / pixmap_width); 415 if (extent->y1 < 0) 416 down_shift = ((-extent->y1 + pixmap_height - 1) / pixmap_height); 417 418 if (right_shift != 0 || down_shift != 0) { 419 if (repeat_type == RepeatReflect) { 420 right_shift = (right_shift + 1) & ~1; 421 down_shift = (down_shift + 1) & ~1; 422 } 423 RegionTranslate(region, right_shift * pixmap_width, 424 down_shift * pixmap_height); 425 } 426 427 extent = RegionExtents(region); 428 /* Tile a large pixmap to another large pixmap. 429 * We can't use the target large pixmap as the 430 * loop variable, instead we need to loop for all 431 * the blocks in the tile pixmap. 432 * 433 * simulate repeat each single block to cover the 434 * target's blocks. Two special case: 435 * a block_wcnt == 1 or block_hcnt ==1, then we 436 * only need to loop one direction as the other 437 * direction is fully included in the first block. 438 * 439 * For the other cases, just need to start 440 * from a proper shiftx/shifty, and then increase 441 * y by tile_height each time to walk trhough the 442 * target block and then walk trhough the target 443 * at x direction by increate tile_width each time. 444 * 445 * This way, we can consolidate all the sub blocks 446 * of the target boxes into one tile source's block. 447 * 448 * */ 449 m = 0; 450 clipped_regions = calloc(priv->block_wcnt * priv->block_hcnt, 451 sizeof(*clipped_regions)); 452 if (clipped_regions == NULL) { 453 *n_region = 0; 454 return NULL; 455 } 456 if (right_shift != 0 || down_shift != 0) { 457 DEBUGF("region to be repeated shifted \n"); 458 DEBUGRegionPrint(region); 459 } 460 DEBUGF("repeat pixmap width %d height %d \n", pixmap_width, pixmap_height); 461 DEBUGF("extent x1 %d y1 %d x2 %d y2 %d \n", extent->x1, extent->y1, 462 extent->x2, extent->y2); 463 for (j = 0; j < priv->block_hcnt; j++) { 464 for (i = 0; i < priv->block_wcnt; i++) { 465 int dx = pixmap_width; 466 int dy = pixmap_height; 467 int idx; 468 int shift_x; 469 int shift_y; 470 int saved_y1, saved_y2; 471 int x_idx = 0, y_idx = 0, saved_y_idx = 0; 472 RegionRec temp_region; 473 BoxRec reflect_repeat_box; 474 BoxPtr valid_repeat_box; 475 476 shift_x = (extent->x1 / pixmap_width) * pixmap_width; 477 shift_y = (extent->y1 / pixmap_height) * pixmap_height; 478 idx = j * priv->block_wcnt + i; 479 if (repeat_type == RepeatReflect) { 480 x_idx = (extent->x1 / pixmap_width); 481 y_idx = (extent->y1 / pixmap_height); 482 } 483 484 /* Construct a rect to clip the target region. */ 485 repeat_box.x1 = shift_x + priv->box_array[idx].x1; 486 repeat_box.y1 = shift_y + priv->box_array[idx].y1; 487 if (priv->block_wcnt == 1) { 488 repeat_box.x2 = extent->x2; 489 dx = extent->x2 - repeat_box.x1; 490 } 491 else 492 repeat_box.x2 = shift_x + priv->box_array[idx].x2; 493 if (priv->block_hcnt == 1) { 494 repeat_box.y2 = extent->y2; 495 dy = extent->y2 - repeat_box.y1; 496 } 497 else 498 repeat_box.y2 = shift_y + priv->box_array[idx].y2; 499 500 current_region = RegionCreate(NULL, 4); 501 RegionInit(&temp_region, NULL, 4); 502 DEBUGF("init repeat box %d %d %d %d \n", 503 repeat_box.x1, repeat_box.y1, repeat_box.x2, repeat_box.y2); 504 505 if (repeat_type == RepeatNormal) { 506 saved_y1 = repeat_box.y1; 507 saved_y2 = repeat_box.y2; 508 for (; repeat_box.x1 < extent->x2; 509 repeat_box.x1 += dx, repeat_box.x2 += dx) { 510 repeat_box.y1 = saved_y1; 511 repeat_box.y2 = saved_y2; 512 for (repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2; 513 repeat_box.y1 < extent->y2; 514 repeat_box.y1 += dy, repeat_box.y2 += dy) { 515 516 RegionInitBoxes(&repeat_region, &repeat_box, 1); 517 DEBUGF("Start to clip repeat region: \n"); 518 DEBUGRegionPrint(&repeat_region); 519 RegionIntersect(&temp_region, &repeat_region, region); 520 DEBUGF("clip result:\n"); 521 DEBUGRegionPrint(&temp_region); 522 RegionAppend(current_region, &temp_region); 523 RegionUninit(&repeat_region); 524 } 525 } 526 } 527 else if (repeat_type == RepeatReflect) { 528 saved_y1 = repeat_box.y1; 529 saved_y2 = repeat_box.y2; 530 saved_y_idx = y_idx; 531 for (;; repeat_box.x1 += dx, repeat_box.x2 += dx) { 532 repeat_box.y1 = saved_y1; 533 repeat_box.y2 = saved_y2; 534 y_idx = saved_y_idx; 535 reflect_repeat_box.x1 = (x_idx & 1) ? 536 ((2 * x_idx + 1) * dx - repeat_box.x2) : repeat_box.x1; 537 reflect_repeat_box.x2 = (x_idx & 1) ? 538 ((2 * x_idx + 1) * dx - repeat_box.x1) : repeat_box.x2; 539 valid_repeat_box = &reflect_repeat_box; 540 541 if (valid_repeat_box->x1 >= extent->x2) 542 break; 543 for (repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;; 544 repeat_box.y1 += dy, repeat_box.y2 += dy) { 545 546 DEBUGF("x_idx %d y_idx %d dx %d dy %d\n", x_idx, y_idx, 547 dx, dy); 548 DEBUGF("repeat box %d %d %d %d \n", repeat_box.x1, 549 repeat_box.y1, repeat_box.x2, repeat_box.y2); 550 551 if (priv->block_hcnt > 1) { 552 reflect_repeat_box.y1 = (y_idx & 1) ? 553 ((2 * y_idx + 1) * dy - 554 repeat_box.y2) : repeat_box.y1; 555 reflect_repeat_box.y2 = 556 (y_idx & 1) ? ((2 * y_idx + 1) * dy - 557 repeat_box.y1) : repeat_box.y2; 558 } 559 else { 560 reflect_repeat_box.y1 = repeat_box.y1; 561 reflect_repeat_box.y2 = repeat_box.y2; 562 } 563 564 DEBUGF("valid_repeat_box x1 %d y1 %d \n", 565 valid_repeat_box->x1, valid_repeat_box->y1); 566 if (valid_repeat_box->y1 >= extent->y2) 567 break; 568 RegionInitBoxes(&repeat_region, valid_repeat_box, 1); 569 DEBUGF("start to clip repeat[reflect] region: \n"); 570 DEBUGRegionPrint(&repeat_region); 571 RegionIntersect(&temp_region, &repeat_region, region); 572 DEBUGF("result:\n"); 573 DEBUGRegionPrint(&temp_region); 574 if (is_transform && RegionNumRects(&temp_region)) { 575 BoxRec temp_box; 576 BoxPtr temp_extent; 577 578 temp_extent = RegionExtents(&temp_region); 579 if (priv->block_wcnt > 1) { 580 if (x_idx & 1) { 581 temp_box.x1 = 582 ((2 * x_idx + 1) * dx - 583 temp_extent->x2); 584 temp_box.x2 = 585 ((2 * x_idx + 1) * dx - 586 temp_extent->x1); 587 } 588 else { 589 temp_box.x1 = temp_extent->x1; 590 temp_box.x2 = temp_extent->x2; 591 } 592 modulus(temp_box.x1, pixmap_width, temp_box.x1); 593 modulus(temp_box.x2, pixmap_width, temp_box.x2); 594 if (temp_box.x2 == 0) 595 temp_box.x2 = pixmap_width; 596 } 597 else { 598 temp_box.x1 = temp_extent->x1; 599 temp_box.x2 = temp_extent->x2; 600 _glamor_largepixmap_reflect_fixup(&temp_box.x1, 601 &temp_box.x2, 602 pixmap_width); 603 } 604 605 if (priv->block_hcnt > 1) { 606 if (y_idx & 1) { 607 temp_box.y1 = 608 ((2 * y_idx + 1) * dy - 609 temp_extent->y2); 610 temp_box.y2 = 611 ((2 * y_idx + 1) * dy - 612 temp_extent->y1); 613 } 614 else { 615 temp_box.y1 = temp_extent->y1; 616 temp_box.y2 = temp_extent->y2; 617 } 618 619 modulus(temp_box.y1, pixmap_height, 620 temp_box.y1); 621 modulus(temp_box.y2, pixmap_height, 622 temp_box.y2); 623 if (temp_box.y2 == 0) 624 temp_box.y2 = pixmap_height; 625 } 626 else { 627 temp_box.y1 = temp_extent->y1; 628 temp_box.y2 = temp_extent->y2; 629 _glamor_largepixmap_reflect_fixup(&temp_box.y1, 630 &temp_box.y2, 631 pixmap_height); 632 } 633 634 RegionInitBoxes(&temp_region, &temp_box, 1); 635 RegionTranslate(&temp_region, 636 x_center_shift * pixmap_width, 637 y_center_shift * pixmap_height); 638 DEBUGF("for transform result:\n"); 639 DEBUGRegionPrint(&temp_region); 640 } 641 RegionAppend(current_region, &temp_region); 642 RegionUninit(&repeat_region); 643 y_idx++; 644 } 645 x_idx++; 646 } 647 } 648 DEBUGF("dx %d dy %d \n", dx, dy); 649 650 if (RegionNumRects(current_region)) { 651 652 if ((right_shift != 0 || down_shift != 0) && 653 !(is_transform && repeat_type == RepeatReflect)) 654 RegionTranslate(current_region, -right_shift * pixmap_width, 655 -down_shift * pixmap_height); 656 clipped_regions[m].region = current_region; 657 clipped_regions[m].block_idx = idx; 658 m++; 659 } 660 else 661 RegionDestroy(current_region); 662 RegionUninit(&temp_region); 663 } 664 } 665 666 if (right_shift != 0 || down_shift != 0) 667 RegionTranslate(region, -right_shift * pixmap_width, 668 -down_shift * pixmap_height); 669 *n_region = m; 670 671 return clipped_regions; 672} 673 674glamor_pixmap_clipped_regions * 675glamor_compute_clipped_regions(PixmapPtr pixmap, 676 RegionPtr region, 677 int *n_region, int repeat_type, 678 int reverse, int upsidedown) 679{ 680 glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 681 return _glamor_compute_clipped_regions(pixmap, priv, region, n_region, repeat_type, 682 0, reverse, upsidedown); 683} 684 685/* XXX overflow still exist. maybe we need to change to use region32. 686 * by default. Or just use region32 for repeat cases? 687 **/ 688static glamor_pixmap_clipped_regions * 689glamor_compute_transform_clipped_regions(PixmapPtr pixmap, 690 struct pixman_transform *transform, 691 RegionPtr region, int *n_region, 692 int dx, int dy, int repeat_type, 693 int reverse, int upsidedown) 694{ 695 glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 696 BoxPtr temp_extent; 697 struct pixman_box32 temp_box; 698 struct pixman_box16 short_box; 699 RegionPtr temp_region; 700 glamor_pixmap_clipped_regions *ret; 701 702 temp_region = RegionCreate(NULL, 4); 703 temp_extent = RegionExtents(region); 704 DEBUGF("dest region \n"); 705 DEBUGRegionPrint(region); 706 /* dx/dy may exceed MAX SHORT. we have to use 707 * a box32 to represent it.*/ 708 temp_box.x1 = temp_extent->x1 + dx; 709 temp_box.x2 = temp_extent->x2 + dx; 710 temp_box.y1 = temp_extent->y1 + dy; 711 temp_box.y2 = temp_extent->y2 + dy; 712 713 DEBUGF("source box %d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2, 714 temp_box.y2); 715 if (transform) 716 glamor_get_transform_extent_from_box(&temp_box, transform); 717 if (repeat_type == RepeatNone) { 718 if (temp_box.x1 < 0) 719 temp_box.x1 = 0; 720 if (temp_box.y1 < 0) 721 temp_box.y1 = 0; 722 temp_box.x2 = MIN(temp_box.x2, pixmap->drawable.width); 723 temp_box.y2 = MIN(temp_box.y2, pixmap->drawable.height); 724 } 725 /* Now copy back the box32 to a box16 box. */ 726 short_box.x1 = temp_box.x1; 727 short_box.y1 = temp_box.y1; 728 short_box.x2 = temp_box.x2; 729 short_box.y2 = temp_box.y2; 730 RegionInitBoxes(temp_region, &short_box, 1); 731 DEBUGF("copy to temp source region \n"); 732 DEBUGRegionPrint(temp_region); 733 ret = _glamor_compute_clipped_regions(pixmap, 734 priv, 735 temp_region, 736 n_region, 737 repeat_type, 1, reverse, upsidedown); 738 DEBUGF("n_regions = %d \n", *n_region); 739 RegionDestroy(temp_region); 740 741 return ret; 742} 743 744/* 745 * As transform and repeatpad mode. 746 * We may get a clipped result which in multipe regions. 747 * It's not easy to do a 2nd round clipping just as we do 748 * without transform/repeatPad. As it's not easy to reverse 749 * the 2nd round clipping result with a transform/repeatPad mode, 750 * or even impossible for some transformation. 751 * 752 * So we have to merge the fragmental region into one region 753 * if the clipped result cross the region boundary. 754 */ 755static void 756glamor_merge_clipped_regions(PixmapPtr pixmap, 757 glamor_pixmap_private *pixmap_priv, 758 int repeat_type, 759 glamor_pixmap_clipped_regions *clipped_regions, 760 int *n_regions, int *need_clean_fbo) 761{ 762 BoxRec temp_box, copy_box; 763 RegionPtr temp_region; 764 glamor_pixmap_private *temp_priv; 765 PixmapPtr temp_pixmap; 766 int overlap; 767 int i; 768 int pixmap_width, pixmap_height; 769 glamor_pixmap_private *priv; 770 771 priv = __glamor_large(pixmap_priv); 772 pixmap_width = pixmap->drawable.width; 773 pixmap_height =pixmap->drawable.height; 774 775 temp_region = RegionCreate(NULL, 4); 776 for (i = 0; i < *n_regions; i++) { 777 DEBUGF("Region %d:\n", i); 778 DEBUGRegionPrint(clipped_regions[i].region); 779 RegionAppend(temp_region, clipped_regions[i].region); 780 } 781 782 RegionValidate(temp_region, &overlap); 783 DEBUGF("temp region: \n"); 784 DEBUGRegionPrint(temp_region); 785 786 temp_box = *RegionExtents(temp_region); 787 788 DEBUGF("need copy region: \n"); 789 DEBUGF("%d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2, 790 temp_box.y2); 791 temp_pixmap = 792 glamor_create_pixmap(pixmap->drawable.pScreen, 793 temp_box.x2 - temp_box.x1, 794 temp_box.y2 - temp_box.y1, 795 pixmap->drawable.depth, 796 GLAMOR_CREATE_PIXMAP_FIXUP); 797 if (temp_pixmap == NULL) { 798 assert(0); 799 return; 800 } 801 802 temp_priv = glamor_get_pixmap_private(temp_pixmap); 803 assert(glamor_pixmap_priv_is_small(temp_priv)); 804 805 priv->box = temp_box; 806 if (temp_box.x1 >= 0 && temp_box.x2 <= pixmap_width 807 && temp_box.y1 >= 0 && temp_box.y2 <= pixmap_height) { 808 int dx, dy; 809 810 copy_box.x1 = 0; 811 copy_box.y1 = 0; 812 copy_box.x2 = temp_box.x2 - temp_box.x1; 813 copy_box.y2 = temp_box.y2 - temp_box.y1; 814 dx = temp_box.x1; 815 dy = temp_box.y1; 816 glamor_copy(&pixmap->drawable, 817 &temp_pixmap->drawable, 818 NULL, ©_box, 1, dx, dy, 0, 0, 0, NULL); 819// glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width, 820// temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff00); 821 } 822 else { 823 for (i = 0; i < *n_regions; i++) { 824 BoxPtr box; 825 int nbox; 826 827 box = REGION_RECTS(clipped_regions[i].region); 828 nbox = REGION_NUM_RECTS(clipped_regions[i].region); 829 while (nbox--) { 830 int dx, dy, c, d; 831 832 DEBUGF("box x1 %d y1 %d x2 %d y2 %d \n", 833 box->x1, box->y1, box->x2, box->y2); 834 modulus(box->x1, pixmap_width, c); 835 dx = c - (box->x1 - temp_box.x1); 836 copy_box.x1 = box->x1 - temp_box.x1; 837 copy_box.x2 = box->x2 - temp_box.x1; 838 839 modulus(box->y1, pixmap_height, d); 840 dy = d - (box->y1 - temp_box.y1); 841 copy_box.y1 = box->y1 - temp_box.y1; 842 copy_box.y2 = box->y2 - temp_box.y1; 843 844 DEBUGF("copying box %d %d %d %d, dx %d dy %d\n", 845 copy_box.x1, copy_box.y1, copy_box.x2, 846 copy_box.y2, dx, dy); 847 848 glamor_copy(&pixmap->drawable, 849 &temp_pixmap->drawable, 850 NULL, ©_box, 1, dx, dy, 0, 0, 0, NULL); 851 852 box++; 853 } 854 } 855 //glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width, 856 // temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff); 857 } 858 /* The first region will be released at caller side. */ 859 for (i = 1; i < *n_regions; i++) 860 RegionDestroy(clipped_regions[i].region); 861 RegionDestroy(temp_region); 862 priv->box = temp_box; 863 priv->fbo = glamor_pixmap_detach_fbo(temp_priv); 864 DEBUGF("priv box x1 %d y1 %d x2 %d y2 %d \n", 865 priv->box.x1, priv->box.y1, priv->box.x2, priv->box.y2); 866 glamor_destroy_pixmap(temp_pixmap); 867 *need_clean_fbo = 1; 868 *n_regions = 1; 869} 870 871/** 872 * Given an expected transformed block width and block height, 873 * 874 * This function calculate a new block width and height which 875 * guarantee the transform result will not exceed the given 876 * block width and height. 877 * 878 * For large block width and height (> 2048), we choose a 879 * smaller new width and height and to reduce the cross region 880 * boundary and can avoid some overhead. 881 * 882 **/ 883static Bool 884glamor_get_transform_block_size(struct pixman_transform *transform, 885 int block_w, int block_h, 886 int *transformed_block_w, 887 int *transformed_block_h) 888{ 889 double a, b, c, d, e, f, g, h; 890 double scale; 891 int width, height; 892 893 a = pixman_fixed_to_double(transform->matrix[0][0]); 894 b = pixman_fixed_to_double(transform->matrix[0][1]); 895 c = pixman_fixed_to_double(transform->matrix[1][0]); 896 d = pixman_fixed_to_double(transform->matrix[1][1]); 897 scale = pixman_fixed_to_double(transform->matrix[2][2]); 898 if (block_w > 2048) { 899 /* For large block size, we shrink it to smaller box, 900 * thus latter we may get less cross boundary regions and 901 * thus can avoid some extra copy. 902 * 903 **/ 904 width = block_w / 4; 905 height = block_h / 4; 906 } 907 else { 908 width = block_w - 2; 909 height = block_h - 2; 910 } 911 e = a + b; 912 f = c + d; 913 914 g = a - b; 915 h = c - d; 916 917 e = MIN(block_w, floor(width * scale) / MAX(fabs(e), fabs(g))); 918 f = MIN(block_h, floor(height * scale) / MAX(fabs(f), fabs(h))); 919 *transformed_block_w = MIN(e, f) - 1; 920 *transformed_block_h = *transformed_block_w; 921 if (*transformed_block_w <= 0 || *transformed_block_h <= 0) 922 return FALSE; 923 DEBUGF("original block_w/h %d %d, fixed %d %d \n", block_w, block_h, 924 *transformed_block_w, *transformed_block_h); 925 return TRUE; 926} 927 928#define VECTOR_FROM_POINT(p, x, y) do {\ 929 p.v[0] = x; \ 930 p.v[1] = y; \ 931 p.v[2] = 1.0; } while (0) 932static void 933glamor_get_transform_extent_from_box(struct pixman_box32 *box, 934 struct pixman_transform *transform) 935{ 936 struct pixman_f_vector p0, p1, p2, p3; 937 float min_x, min_y, max_x, max_y; 938 939 struct pixman_f_transform ftransform; 940 941 VECTOR_FROM_POINT(p0, box->x1, box->y1); 942 VECTOR_FROM_POINT(p1, box->x2, box->y1); 943 VECTOR_FROM_POINT(p2, box->x2, box->y2); 944 VECTOR_FROM_POINT(p3, box->x1, box->y2); 945 946 pixman_f_transform_from_pixman_transform(&ftransform, transform); 947 pixman_f_transform_point(&ftransform, &p0); 948 pixman_f_transform_point(&ftransform, &p1); 949 pixman_f_transform_point(&ftransform, &p2); 950 pixman_f_transform_point(&ftransform, &p3); 951 952 min_x = MIN(p0.v[0], p1.v[0]); 953 min_x = MIN(min_x, p2.v[0]); 954 min_x = MIN(min_x, p3.v[0]); 955 956 min_y = MIN(p0.v[1], p1.v[1]); 957 min_y = MIN(min_y, p2.v[1]); 958 min_y = MIN(min_y, p3.v[1]); 959 960 max_x = MAX(p0.v[0], p1.v[0]); 961 max_x = MAX(max_x, p2.v[0]); 962 max_x = MAX(max_x, p3.v[0]); 963 964 max_y = MAX(p0.v[1], p1.v[1]); 965 max_y = MAX(max_y, p2.v[1]); 966 max_y = MAX(max_y, p3.v[1]); 967 box->x1 = floor(min_x) - 1; 968 box->y1 = floor(min_y) - 1; 969 box->x2 = ceil(max_x) + 1; 970 box->y2 = ceil(max_y) + 1; 971} 972 973static void 974_glamor_process_transformed_clipped_region(PixmapPtr pixmap, 975 glamor_pixmap_private *priv, 976 int repeat_type, 977 glamor_pixmap_clipped_regions * 978 clipped_regions, int *n_regions, 979 int *need_clean_fbo) 980{ 981 int shift_x, shift_y; 982 983 if (*n_regions != 1) { 984 /* Merge all source regions into one region. */ 985 glamor_merge_clipped_regions(pixmap, priv, repeat_type, 986 clipped_regions, n_regions, 987 need_clean_fbo); 988 } 989 else { 990 glamor_set_pixmap_fbo_current(priv, clipped_regions[0].block_idx); 991 if (repeat_type == RepeatReflect || repeat_type == RepeatNormal) { 992 /* The required source areas are in one region, 993 * we need to shift the corresponding box's coords to proper position, 994 * thus we can calculate the relative coords correctly.*/ 995 BoxPtr temp_box; 996 int rem; 997 998 temp_box = RegionExtents(clipped_regions[0].region); 999 modulus(temp_box->x1, pixmap->drawable.width, rem); 1000 shift_x = (temp_box->x1 - rem) / pixmap->drawable.width; 1001 modulus(temp_box->y1, pixmap->drawable.height, rem); 1002 shift_y = (temp_box->y1 - rem) / pixmap->drawable.height; 1003 1004 if (shift_x != 0) { 1005 __glamor_large(priv)->box.x1 += 1006 shift_x * pixmap->drawable.width; 1007 __glamor_large(priv)->box.x2 += 1008 shift_x * pixmap->drawable.width; 1009 } 1010 if (shift_y != 0) { 1011 __glamor_large(priv)->box.y1 += 1012 shift_y * pixmap->drawable.height; 1013 __glamor_large(priv)->box.y2 += 1014 shift_y * pixmap->drawable.height; 1015 } 1016 } 1017 } 1018} 1019 1020Bool 1021glamor_composite_largepixmap_region(CARD8 op, 1022 PicturePtr source, 1023 PicturePtr mask, 1024 PicturePtr dest, 1025 PixmapPtr source_pixmap, 1026 PixmapPtr mask_pixmap, 1027 PixmapPtr dest_pixmap, 1028 RegionPtr region, Bool force_clip, 1029 INT16 x_source, 1030 INT16 y_source, 1031 INT16 x_mask, 1032 INT16 y_mask, 1033 INT16 x_dest, INT16 y_dest, 1034 CARD16 width, CARD16 height) 1035{ 1036 ScreenPtr screen = dest_pixmap->drawable.pScreen; 1037 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 1038 glamor_pixmap_private *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); 1039 glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap); 1040 glamor_pixmap_private *dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); 1041 glamor_pixmap_clipped_regions *clipped_dest_regions; 1042 glamor_pixmap_clipped_regions *clipped_source_regions; 1043 glamor_pixmap_clipped_regions *clipped_mask_regions; 1044 int n_dest_regions; 1045 int n_mask_regions; 1046 int n_source_regions; 1047 int i, j, k; 1048 int need_clean_source_fbo = 0; 1049 int need_clean_mask_fbo = 0; 1050 int is_normal_source_fbo = 0; 1051 int is_normal_mask_fbo = 0; 1052 int fixed_block_width, fixed_block_height; 1053 int dest_block_width, dest_block_height; 1054 int null_source, null_mask; 1055 glamor_pixmap_private *need_free_source_pixmap_priv = NULL; 1056 glamor_pixmap_private *need_free_mask_pixmap_priv = NULL; 1057 int source_repeat_type = 0, mask_repeat_type = 0; 1058 int ok = TRUE; 1059 1060 if (source_pixmap == dest_pixmap) { 1061 glamor_fallback("source and dest pixmaps are the same\n"); 1062 return FALSE; 1063 } 1064 if (mask_pixmap == dest_pixmap) { 1065 glamor_fallback("mask and dest pixmaps are the same\n"); 1066 return FALSE; 1067 } 1068 1069 if (source->repeat) 1070 source_repeat_type = source->repeatType; 1071 else 1072 source_repeat_type = RepeatNone; 1073 1074 if (mask && mask->repeat) 1075 mask_repeat_type = mask->repeatType; 1076 else 1077 mask_repeat_type = RepeatNone; 1078 1079 if (glamor_pixmap_priv_is_large(dest_pixmap_priv)) { 1080 dest_block_width = __glamor_large(dest_pixmap_priv)->block_w; 1081 dest_block_height = __glamor_large(dest_pixmap_priv)->block_h; 1082 } else { 1083 dest_block_width = dest_pixmap->drawable.width; 1084 dest_block_height = dest_pixmap->drawable.height; 1085 } 1086 fixed_block_width = dest_block_width; 1087 fixed_block_height = dest_block_height; 1088 1089 /* If we got an totally out-of-box region for a source or mask 1090 * region without repeat, we need to set it as null_source and 1091 * give it a solid color (0,0,0,0). */ 1092 null_source = 0; 1093 null_mask = 0; 1094 RegionTranslate(region, -dest->pDrawable->x, -dest->pDrawable->y); 1095 1096 /* need to transform the dest region to the correct sourcei/mask region. 1097 * it's a little complex, as one single edge of the 1098 * target region may be transformed to cross a block boundary of the 1099 * source or mask. Then it's impossible to handle it as usual way. 1100 * We may have to split the original dest region to smaller region, and 1101 * make sure each region's transformed region can fit into one texture, 1102 * and then continue this loop again, and each time when a transformed region 1103 * cross the bound, we need to copy it to a single pixmap and do the composition 1104 * with the new pixmap. If the transformed region doesn't cross a source/mask's 1105 * boundary then we don't need to copy. 1106 * 1107 */ 1108 if (source_pixmap_priv 1109 && source->transform 1110 && glamor_pixmap_priv_is_large(source_pixmap_priv)) { 1111 int source_transformed_block_width, source_transformed_block_height; 1112 1113 if (!glamor_get_transform_block_size(source->transform, 1114 __glamor_large(source_pixmap_priv)->block_w, 1115 __glamor_large(source_pixmap_priv)->block_h, 1116 &source_transformed_block_width, 1117 &source_transformed_block_height)) 1118 { 1119 DEBUGF("source block size less than 1, fallback.\n"); 1120 RegionTranslate(region, dest->pDrawable->x, dest->pDrawable->y); 1121 return FALSE; 1122 } 1123 fixed_block_width = 1124 min(fixed_block_width, source_transformed_block_width); 1125 fixed_block_height = 1126 min(fixed_block_height, source_transformed_block_height); 1127 DEBUGF("new source block size %d x %d \n", fixed_block_width, 1128 fixed_block_height); 1129 } 1130 1131 if (mask_pixmap_priv 1132 && mask->transform && glamor_pixmap_priv_is_large(mask_pixmap_priv)) { 1133 int mask_transformed_block_width, mask_transformed_block_height; 1134 1135 if (!glamor_get_transform_block_size(mask->transform, 1136 __glamor_large(mask_pixmap_priv)->block_w, 1137 __glamor_large(mask_pixmap_priv)->block_h, 1138 &mask_transformed_block_width, 1139 &mask_transformed_block_height)) { 1140 DEBUGF("mask block size less than 1, fallback.\n"); 1141 RegionTranslate(region, dest->pDrawable->x, dest->pDrawable->y); 1142 return FALSE; 1143 } 1144 fixed_block_width = 1145 min(fixed_block_width, mask_transformed_block_width); 1146 fixed_block_height = 1147 min(fixed_block_height, mask_transformed_block_height); 1148 DEBUGF("new mask block size %d x %d \n", fixed_block_width, 1149 fixed_block_height); 1150 } 1151 1152 /*compute the correct block width and height whose transformed source/mask 1153 *region can fit into one texture.*/ 1154 if (force_clip || fixed_block_width < dest_block_width 1155 || fixed_block_height < dest_block_height) 1156 clipped_dest_regions = 1157 glamor_compute_clipped_regions_ext(dest_pixmap, region, 1158 &n_dest_regions, 1159 fixed_block_width, 1160 fixed_block_height, 0, 0); 1161 else 1162 clipped_dest_regions = glamor_compute_clipped_regions(dest_pixmap, 1163 region, 1164 &n_dest_regions, 1165 0, 0, 0); 1166 DEBUGF("dest clipped result %d region: \n", n_dest_regions); 1167 if (source_pixmap_priv 1168 && (source_pixmap_priv == dest_pixmap_priv || 1169 source_pixmap_priv == mask_pixmap_priv) 1170 && glamor_pixmap_priv_is_large(source_pixmap_priv)) { 1171 /* XXX self-copy... */ 1172 need_free_source_pixmap_priv = source_pixmap_priv; 1173 source_pixmap_priv = malloc(sizeof(*source_pixmap_priv)); 1174 *source_pixmap_priv = *need_free_source_pixmap_priv; 1175 need_free_source_pixmap_priv = source_pixmap_priv; 1176 } 1177 assert(mask_pixmap_priv != dest_pixmap_priv); 1178 1179 for (i = 0; i < n_dest_regions; i++) { 1180 DEBUGF("dest region %d idx %d\n", i, 1181 clipped_dest_regions[i].block_idx); 1182 DEBUGRegionPrint(clipped_dest_regions[i].region); 1183 glamor_set_pixmap_fbo_current(dest_pixmap_priv, 1184 clipped_dest_regions[i].block_idx); 1185 if (source_pixmap_priv && 1186 glamor_pixmap_priv_is_large(source_pixmap_priv)) { 1187 if (!source->transform && source_repeat_type != RepeatPad) { 1188 RegionTranslate(clipped_dest_regions[i].region, 1189 x_source - x_dest, y_source - y_dest); 1190 clipped_source_regions = 1191 glamor_compute_clipped_regions(source_pixmap, 1192 clipped_dest_regions[i]. 1193 region, &n_source_regions, 1194 source_repeat_type, 0, 0); 1195 is_normal_source_fbo = 1; 1196 } 1197 else { 1198 clipped_source_regions = 1199 glamor_compute_transform_clipped_regions(source_pixmap, 1200 source->transform, 1201 clipped_dest_regions 1202 [i].region, 1203 &n_source_regions, 1204 x_source - x_dest, 1205 y_source - y_dest, 1206 source_repeat_type, 1207 0, 0); 1208 is_normal_source_fbo = 0; 1209 if (n_source_regions == 0) { 1210 /* Pad the out-of-box region to (0,0,0,0). */ 1211 null_source = 1; 1212 n_source_regions = 1; 1213 } 1214 else 1215 _glamor_process_transformed_clipped_region 1216 (source_pixmap, source_pixmap_priv, source_repeat_type, 1217 clipped_source_regions, &n_source_regions, 1218 &need_clean_source_fbo); 1219 } 1220 DEBUGF("source clipped result %d region: \n", n_source_regions); 1221 for (j = 0; j < n_source_regions; j++) { 1222 if (is_normal_source_fbo) 1223 glamor_set_pixmap_fbo_current(source_pixmap_priv, 1224 clipped_source_regions[j].block_idx); 1225 1226 if (mask_pixmap_priv && 1227 glamor_pixmap_priv_is_large(mask_pixmap_priv)) { 1228 if (is_normal_mask_fbo && is_normal_source_fbo) { 1229 /* both mask and source are normal fbo box without transform or repeatpad. 1230 * The region is clipped against source and then we clip it against mask here.*/ 1231 DEBUGF("source region %d idx %d\n", j, 1232 clipped_source_regions[j].block_idx); 1233 DEBUGRegionPrint(clipped_source_regions[j].region); 1234 RegionTranslate(clipped_source_regions[j].region, 1235 -x_source + x_mask, -y_source + y_mask); 1236 clipped_mask_regions = 1237 glamor_compute_clipped_regions(mask_pixmap, 1238 clipped_source_regions 1239 [j].region, 1240 &n_mask_regions, 1241 mask_repeat_type, 0, 1242 0); 1243 is_normal_mask_fbo = 1; 1244 } 1245 else if (is_normal_mask_fbo && !is_normal_source_fbo) { 1246 assert(n_source_regions == 1); 1247 /* The source fbo is not a normal fbo box, it has transform or repeatpad. 1248 * the valid clip region should be the clip dest region rather than the 1249 * clip source region.*/ 1250 RegionTranslate(clipped_dest_regions[i].region, 1251 -x_dest + x_mask, -y_dest + y_mask); 1252 clipped_mask_regions = 1253 glamor_compute_clipped_regions(mask_pixmap, 1254 clipped_dest_regions 1255 [i].region, 1256 &n_mask_regions, 1257 mask_repeat_type, 0, 1258 0); 1259 is_normal_mask_fbo = 1; 1260 } 1261 else { 1262 /* This mask region has transform or repeatpad, we need clip it agains the previous 1263 * valid region rather than the mask region. */ 1264 if (!is_normal_source_fbo) 1265 clipped_mask_regions = 1266 glamor_compute_transform_clipped_regions 1267 (mask_pixmap, mask->transform, 1268 clipped_dest_regions[i].region, 1269 &n_mask_regions, x_mask - x_dest, 1270 y_mask - y_dest, mask_repeat_type, 0, 0); 1271 else 1272 clipped_mask_regions = 1273 glamor_compute_transform_clipped_regions 1274 (mask_pixmap, mask->transform, 1275 clipped_source_regions[j].region, 1276 &n_mask_regions, x_mask - x_source, 1277 y_mask - y_source, mask_repeat_type, 0, 0); 1278 is_normal_mask_fbo = 0; 1279 if (n_mask_regions == 0) { 1280 /* Pad the out-of-box region to (0,0,0,0). */ 1281 null_mask = 1; 1282 n_mask_regions = 1; 1283 } 1284 else 1285 _glamor_process_transformed_clipped_region 1286 (mask_pixmap, mask_pixmap_priv, mask_repeat_type, 1287 clipped_mask_regions, &n_mask_regions, 1288 &need_clean_mask_fbo); 1289 } 1290 DEBUGF("mask clipped result %d region: \n", n_mask_regions); 1291 1292#define COMPOSITE_REGION(region) do { \ 1293 if (!glamor_composite_clipped_region(op, \ 1294 null_source ? NULL : source, \ 1295 null_mask ? NULL : mask, dest, \ 1296 null_source ? NULL : source_pixmap, \ 1297 null_mask ? NULL : mask_pixmap, \ 1298 dest_pixmap, region, \ 1299 x_source, y_source, x_mask, y_mask, \ 1300 x_dest, y_dest)) { \ 1301 assert(0); \ 1302 } \ 1303 } while(0) 1304 1305 for (k = 0; k < n_mask_regions; k++) { 1306 DEBUGF("mask region %d idx %d\n", k, 1307 clipped_mask_regions[k].block_idx); 1308 DEBUGRegionPrint(clipped_mask_regions[k].region); 1309 if (is_normal_mask_fbo) { 1310 glamor_set_pixmap_fbo_current(mask_pixmap_priv, 1311 clipped_mask_regions[k]. 1312 block_idx); 1313 DEBUGF("mask fbo off %d %d \n", 1314 __glamor_large(mask_pixmap_priv)->box.x1, 1315 __glamor_large(mask_pixmap_priv)->box.y1); 1316 DEBUGF("start composite mask hasn't transform.\n"); 1317 RegionTranslate(clipped_mask_regions[k].region, 1318 x_dest - x_mask + 1319 dest->pDrawable->x, 1320 y_dest - y_mask + 1321 dest->pDrawable->y); 1322 COMPOSITE_REGION(clipped_mask_regions[k].region); 1323 } 1324 else if (!is_normal_mask_fbo && !is_normal_source_fbo) { 1325 DEBUGF 1326 ("start composite both mask and source have transform.\n"); 1327 RegionTranslate(clipped_dest_regions[i].region, 1328 dest->pDrawable->x, 1329 dest->pDrawable->y); 1330 COMPOSITE_REGION(clipped_dest_regions[i].region); 1331 } 1332 else { 1333 DEBUGF 1334 ("start composite only mask has transform.\n"); 1335 RegionTranslate(clipped_source_regions[j].region, 1336 x_dest - x_source + 1337 dest->pDrawable->x, 1338 y_dest - y_source + 1339 dest->pDrawable->y); 1340 COMPOSITE_REGION(clipped_source_regions[j].region); 1341 } 1342 RegionDestroy(clipped_mask_regions[k].region); 1343 } 1344 free(clipped_mask_regions); 1345 if (null_mask) 1346 null_mask = 0; 1347 if (need_clean_mask_fbo) { 1348 assert(is_normal_mask_fbo == 0); 1349 glamor_destroy_fbo(glamor_priv, mask_pixmap_priv->fbo); 1350 mask_pixmap_priv->fbo = NULL; 1351 need_clean_mask_fbo = 0; 1352 } 1353 } 1354 else { 1355 if (is_normal_source_fbo) { 1356 RegionTranslate(clipped_source_regions[j].region, 1357 -x_source + x_dest + dest->pDrawable->x, 1358 -y_source + y_dest + 1359 dest->pDrawable->y); 1360 COMPOSITE_REGION(clipped_source_regions[j].region); 1361 } 1362 else { 1363 /* Source has transform or repeatPad. dest regions is the right 1364 * region to do the composite. */ 1365 RegionTranslate(clipped_dest_regions[i].region, 1366 dest->pDrawable->x, dest->pDrawable->y); 1367 COMPOSITE_REGION(clipped_dest_regions[i].region); 1368 } 1369 } 1370 if (clipped_source_regions && clipped_source_regions[j].region) 1371 RegionDestroy(clipped_source_regions[j].region); 1372 } 1373 free(clipped_source_regions); 1374 if (null_source) 1375 null_source = 0; 1376 if (need_clean_source_fbo) { 1377 assert(is_normal_source_fbo == 0); 1378 glamor_destroy_fbo(glamor_priv, source_pixmap_priv->fbo); 1379 source_pixmap_priv->fbo = NULL; 1380 need_clean_source_fbo = 0; 1381 } 1382 } 1383 else { 1384 if (mask_pixmap_priv && 1385 glamor_pixmap_priv_is_large(mask_pixmap_priv)) { 1386 if (!mask->transform && mask_repeat_type != RepeatPad) { 1387 RegionTranslate(clipped_dest_regions[i].region, 1388 x_mask - x_dest, y_mask - y_dest); 1389 clipped_mask_regions = 1390 glamor_compute_clipped_regions(mask_pixmap, 1391 clipped_dest_regions[i]. 1392 region, &n_mask_regions, 1393 mask_repeat_type, 0, 0); 1394 is_normal_mask_fbo = 1; 1395 } 1396 else { 1397 clipped_mask_regions = 1398 glamor_compute_transform_clipped_regions 1399 (mask_pixmap, mask->transform, 1400 clipped_dest_regions[i].region, &n_mask_regions, 1401 x_mask - x_dest, y_mask - y_dest, mask_repeat_type, 0, 1402 0); 1403 is_normal_mask_fbo = 0; 1404 if (n_mask_regions == 0) { 1405 /* Pad the out-of-box region to (0,0,0,0). */ 1406 null_mask = 1; 1407 n_mask_regions = 1; 1408 } 1409 else 1410 _glamor_process_transformed_clipped_region 1411 (mask_pixmap, mask_pixmap_priv, mask_repeat_type, 1412 clipped_mask_regions, &n_mask_regions, 1413 &need_clean_mask_fbo); 1414 } 1415 1416 for (k = 0; k < n_mask_regions; k++) { 1417 DEBUGF("mask region %d idx %d\n", k, 1418 clipped_mask_regions[k].block_idx); 1419 DEBUGRegionPrint(clipped_mask_regions[k].region); 1420 if (is_normal_mask_fbo) { 1421 glamor_set_pixmap_fbo_current(mask_pixmap_priv, 1422 clipped_mask_regions[k]. 1423 block_idx); 1424 RegionTranslate(clipped_mask_regions[k].region, 1425 x_dest - x_mask + dest->pDrawable->x, 1426 y_dest - y_mask + dest->pDrawable->y); 1427 COMPOSITE_REGION(clipped_mask_regions[k].region); 1428 } 1429 else { 1430 RegionTranslate(clipped_dest_regions[i].region, 1431 dest->pDrawable->x, dest->pDrawable->y); 1432 COMPOSITE_REGION(clipped_dest_regions[i].region); 1433 } 1434 RegionDestroy(clipped_mask_regions[k].region); 1435 } 1436 free(clipped_mask_regions); 1437 if (null_mask) 1438 null_mask = 0; 1439 if (need_clean_mask_fbo) { 1440 glamor_destroy_fbo(glamor_priv, mask_pixmap_priv->fbo); 1441 mask_pixmap_priv->fbo = NULL; 1442 need_clean_mask_fbo = 0; 1443 } 1444 } 1445 else { 1446 RegionTranslate(clipped_dest_regions[i].region, 1447 dest->pDrawable->x, dest->pDrawable->y); 1448 COMPOSITE_REGION(clipped_dest_regions[i].region); 1449 } 1450 } 1451 RegionDestroy(clipped_dest_regions[i].region); 1452 } 1453 free(clipped_dest_regions); 1454 free(need_free_source_pixmap_priv); 1455 free(need_free_mask_pixmap_priv); 1456 ok = TRUE; 1457 return ok; 1458} 1459