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