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