sna_tiling.c revision 428d7b3d
1/* 2 * Copyright © 2010 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Chris Wilson <chris@chris-wilson.co.uk> 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include "sna.h" 33#include "sna_render.h" 34#include "fb/fbpict.h" 35 36struct sna_tile_span { 37 BoxRec box; 38 float opacity; 39}; 40 41struct sna_tile_state { 42 int op; 43 PicturePtr src, mask, dst; 44 PixmapPtr dst_pixmap; 45 uint32_t dst_format; 46 int16_t src_x, src_y; 47 int16_t mask_x, mask_y; 48 int16_t dst_x, dst_y; 49 int16_t width, height; 50 unsigned flags; 51 52 int rect_count; 53 int rect_size; 54 struct sna_composite_rectangles rects_embedded[16], *rects; 55}; 56 57static void 58sna_tiling_composite_add_rect(struct sna_tile_state *tile, 59 const struct sna_composite_rectangles *r) 60{ 61 if (tile->rect_count == tile->rect_size) { 62 struct sna_composite_rectangles *a; 63 int newsize = tile->rect_size * 2; 64 65 if (tile->rects == tile->rects_embedded) { 66 a = malloc (sizeof(struct sna_composite_rectangles) * newsize); 67 if (a == NULL) 68 return; 69 70 memcpy(a, 71 tile->rects_embedded, 72 sizeof(struct sna_composite_rectangles) * tile->rect_count); 73 } else { 74 a = realloc(tile->rects, 75 sizeof(struct sna_composite_rectangles) * newsize); 76 if (a == NULL) 77 return; 78 } 79 80 tile->rects = a; 81 tile->rect_size = newsize; 82 } 83 84 tile->rects[tile->rect_count++] = *r; 85} 86 87fastcall static void 88sna_tiling_composite_blt(struct sna *sna, 89 const struct sna_composite_op *op, 90 const struct sna_composite_rectangles *r) 91{ 92 sna_tiling_composite_add_rect(op->priv, r); 93 (void)sna; 94} 95 96fastcall static void 97sna_tiling_composite_box(struct sna *sna, 98 const struct sna_composite_op *op, 99 const BoxRec *box) 100{ 101 struct sna_composite_rectangles r; 102 103 r.dst.x = box->x1; 104 r.dst.y = box->y1; 105 r.mask = r.src = r.dst; 106 107 r.width = box->x2 - box->x1; 108 r.height = box->y2 - box->y1; 109 110 sna_tiling_composite_add_rect(op->priv, &r); 111 (void)sna; 112} 113 114static void 115sna_tiling_composite_boxes(struct sna *sna, 116 const struct sna_composite_op *op, 117 const BoxRec *box, int nbox) 118{ 119 while (nbox--) { 120 struct sna_composite_rectangles r; 121 122 r.dst.x = box->x1; 123 r.dst.y = box->y1; 124 r.mask = r.src = r.dst; 125 126 r.width = box->x2 - box->x1; 127 r.height = box->y2 - box->y1; 128 129 sna_tiling_composite_add_rect(op->priv, &r); 130 box++; 131 } 132 (void)sna; 133} 134 135static void 136sna_tiling_composite_done(struct sna *sna, 137 const struct sna_composite_op *op) 138{ 139 struct sna_tile_state *tile = op->priv; 140 struct sna_composite_op tmp; 141 int x, y, n, step, max_size; 142 143 /* Use a small step to accommodate enlargement through tile alignment */ 144 step = sna->render.max_3d_size; 145 if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) || 146 tile->dst_y & 63) 147 step /= 2; 148 149 max_size = sna_max_tile_copy_size(sna, op->dst.bo, op->dst.bo); 150 if (max_size == 0) 151 goto done; 152 153 while (step * step * 4 > max_size) 154 step /= 2; 155 156 DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__, 157 tile->width, tile->height, tile->rect_count, step)); 158 159 if (tile->rect_count == 0) 160 goto done; 161 162 for (y = 0; y < tile->height; y += step) { 163 int height = step; 164 if (y + height > tile->height) 165 height = tile->height - y; 166 for (x = 0; x < tile->width; x += step) { 167 int width = step; 168 if (x + width > tile->width) 169 width = tile->width - x; 170 if (sna->render.composite(sna, tile->op, 171 tile->src, tile->mask, tile->dst, 172 tile->src_x + x, tile->src_y + y, 173 tile->mask_x + x, tile->mask_y + y, 174 tile->dst_x + x, tile->dst_y + y, 175 width, height, 176 COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) { 177 for (n = 0; n < tile->rect_count; n++) { 178 const struct sna_composite_rectangles *r = &tile->rects[n]; 179 int x1, x2, dx, y1, y2, dy; 180 181 x1 = r->dst.x - tile->dst_x, dx = 0; 182 if (x1 < x) 183 dx = x - x1, x1 = x; 184 y1 = r->dst.y - tile->dst_y, dy = 0; 185 if (y1 < y) 186 dy = y - y1, y1 = y; 187 188 x2 = r->dst.x + r->width - tile->dst_x; 189 if (x2 > x + width) 190 x2 = x + width; 191 y2 = r->dst.y + r->height - tile->dst_y; 192 if (y2 > y + height) 193 y2 = y + height; 194 195 DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d), delta=(%d,%d)\n", 196 __FUNCTION__, n, 197 r->dst.x, r->dst.y, 198 r->width, r->height, 199 x, y, width, height, 200 x1, y1, x2, y2, 201 dx, dy)); 202 203 if (y2 > y1 && x2 > x1) { 204 struct sna_composite_rectangles rr; 205 rr.src.x = dx + r->src.x; 206 rr.src.y = dy + r->src.y; 207 208 rr.mask.x = dx + r->mask.x; 209 rr.mask.y = dy + r->mask.y; 210 211 rr.dst.x = dx + r->dst.x; 212 rr.dst.y = dy + r->dst.y; 213 214 rr.width = x2 - x1; 215 rr.height = y2 - y1; 216 217 tmp.blt(sna, &tmp, &rr); 218 } 219 } 220 tmp.done(sna, &tmp); 221 } else { 222 unsigned int flags; 223 DBG(("%s -- falback\n", __FUNCTION__)); 224 225 if (tile->op <= PictOpSrc) 226 flags = MOVE_WRITE; 227 else 228 flags = MOVE_WRITE | MOVE_READ; 229 if (!sna_drawable_move_to_cpu(tile->dst->pDrawable, 230 flags)) 231 goto done; 232 if (tile->dst->alphaMap && 233 !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable, 234 flags)) 235 goto done; 236 237 if (tile->src->pDrawable && 238 !sna_drawable_move_to_cpu(tile->src->pDrawable, 239 MOVE_READ)) 240 goto done; 241 if (tile->src->alphaMap && 242 !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable, 243 MOVE_READ)) 244 goto done; 245 246 if (tile->mask && tile->mask->pDrawable && 247 !sna_drawable_move_to_cpu(tile->mask->pDrawable, 248 MOVE_READ)) 249 goto done; 250 251 if (tile->mask && tile->mask->alphaMap && 252 !sna_drawable_move_to_cpu(tile->mask->alphaMap->pDrawable, 253 MOVE_READ)) 254 goto done; 255 256 if (sigtrap_get() == 0) { 257 fbComposite(tile->op, 258 tile->src, tile->mask, tile->dst, 259 tile->src_x + x, tile->src_y + y, 260 tile->mask_x + x, tile->mask_y + y, 261 tile->dst_x + x, tile->dst_y + y, 262 width, height); 263 sigtrap_put(); 264 } 265 } 266 } 267 } 268 269done: 270 if (tile->rects != tile->rects_embedded) 271 free(tile->rects); 272 free(tile); 273} 274 275bool 276sna_tiling_composite(uint32_t op, 277 PicturePtr src, 278 PicturePtr mask, 279 PicturePtr dst, 280 int16_t src_x, int16_t src_y, 281 int16_t mask_x, int16_t mask_y, 282 int16_t dst_x, int16_t dst_y, 283 int16_t width, int16_t height, 284 struct sna_composite_op *tmp) 285{ 286 struct sna_tile_state *tile; 287 struct sna_pixmap *priv; 288 289 DBG(("%s size=(%d, %d), tile=%d\n", 290 __FUNCTION__, width, height, 291 to_sna_from_drawable(dst->pDrawable)->render.max_3d_size)); 292 293 priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 294 if (priv == NULL || priv->gpu_bo == NULL) 295 return false; 296 297 tile = malloc(sizeof(*tile)); 298 if (!tile) 299 return false; 300 301 tile->op = op; 302 303 tile->src = src; 304 tile->mask = mask; 305 tile->dst = dst; 306 307 tile->src_x = src_x; 308 tile->src_y = src_y; 309 tile->mask_x = mask_x; 310 tile->mask_y = mask_y; 311 tile->dst_x = dst_x; 312 tile->dst_y = dst_y; 313 tile->width = width; 314 tile->height = height; 315 tile->rects = tile->rects_embedded; 316 tile->rect_count = 0; 317 tile->rect_size = ARRAY_SIZE(tile->rects_embedded); 318 319 tmp->blt = sna_tiling_composite_blt; 320 tmp->box = sna_tiling_composite_box; 321 tmp->boxes = sna_tiling_composite_boxes; 322 tmp->done = sna_tiling_composite_done; 323 324 tmp->priv = tile; 325 tmp->dst.bo = priv->gpu_bo; 326 return true; 327} 328 329fastcall static void 330sna_tiling_composite_spans_box(struct sna *sna, 331 const struct sna_composite_spans_op *op, 332 const BoxRec *box, float opacity) 333{ 334 struct sna_tile_state *tile = op->base.priv; 335 struct sna_tile_span *a; 336 337 if (tile->rect_count == tile->rect_size) { 338 int newsize = tile->rect_size * 2; 339 340 if (tile->rects == tile->rects_embedded) { 341 a = malloc (sizeof(struct sna_tile_span) * newsize); 342 if (a == NULL) 343 return; 344 345 memcpy(a, 346 tile->rects_embedded, 347 sizeof(struct sna_tile_span) * tile->rect_count); 348 } else { 349 a = realloc(tile->rects, 350 sizeof(struct sna_tile_span) * newsize); 351 if (a == NULL) 352 return; 353 } 354 355 tile->rects = (void *)a; 356 tile->rect_size = newsize; 357 } else 358 a = (void *)tile->rects; 359 360 a[tile->rect_count].box = *box; 361 a[tile->rect_count].opacity = opacity; 362 tile->rect_count++; 363 (void)sna; 364} 365 366static void 367sna_tiling_composite_spans_boxes(struct sna *sna, 368 const struct sna_composite_spans_op *op, 369 const BoxRec *box, int nbox, float opacity) 370{ 371 while (nbox--) 372 sna_tiling_composite_spans_box(sna, op->base.priv, box++, opacity); 373 (void)sna; 374} 375 376fastcall static void 377sna_tiling_composite_spans_done(struct sna *sna, 378 const struct sna_composite_spans_op *op) 379{ 380 struct sna_tile_state *tile = op->base.priv; 381 struct sna_composite_spans_op tmp; 382 int x, y, n, step, max_size; 383 bool force_fallback = false; 384 385 /* Use a small step to accommodate enlargement through tile alignment */ 386 step = sna->render.max_3d_size; 387 if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) || 388 tile->dst_y & 63) 389 step /= 2; 390 391 max_size = sna_max_tile_copy_size(sna, op->base.dst.bo, op->base.dst.bo); 392 if (max_size == 0) 393 goto done; 394 395 while (step * step * 4 > max_size) 396 step /= 2; 397 398 DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__, 399 tile->width, tile->height, tile->rect_count, step)); 400 401 if (tile->rect_count == 0) 402 goto done; 403 404 for (y = 0; y < tile->height; y += step) { 405 int height = step; 406 if (y + height > tile->height) 407 height = tile->height - y; 408 for (x = 0; x < tile->width; x += step) { 409 const struct sna_tile_span *r = (void *)tile->rects; 410 int width = step; 411 if (x + width > tile->width) 412 width = tile->width - x; 413 if (!force_fallback && 414 sna->render.composite_spans(sna, tile->op, 415 tile->src, tile->dst, 416 tile->src_x + x, tile->src_y + y, 417 tile->dst_x + x, tile->dst_y + y, 418 width, height, tile->flags, 419 memset(&tmp, 0, sizeof(tmp)))) { 420 for (n = 0; n < tile->rect_count; n++) { 421 BoxRec b; 422 423 b.x1 = r->box.x1 - tile->dst_x; 424 if (b.x1 < x) 425 b.x1 = x; 426 427 b.y1 = r->box.y1 - tile->dst_y; 428 if (b.y1 < y) 429 b.y1 = y; 430 431 b.x2 = r->box.x2 - tile->dst_x; 432 if (b.x2 > x + width) 433 b.x2 = x + width; 434 435 b.y2 = r->box.y2 - tile->dst_y; 436 if (b.y2 > y + height) 437 b.y2 = y + height; 438 439 DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n", 440 __FUNCTION__, n, 441 r->box.x1, r->box.y1, 442 r->box.x2-r->box.x1, r->box.y2-r->box.y1, 443 x, y, width, height, 444 b.x1, b.y1, b.x2, b.y2)); 445 446 if (b.y2 > b.y1 && b.x2 > b.x1) 447 tmp.box(sna, &tmp, &b, r->opacity); 448 r++; 449 } 450 tmp.done(sna, &tmp); 451 } else { 452 unsigned int flags; 453 454 DBG(("%s -- falback\n", __FUNCTION__)); 455 456 if (tile->op <= PictOpSrc) 457 flags = MOVE_WRITE; 458 else 459 flags = MOVE_WRITE | MOVE_READ; 460 if (!sna_drawable_move_to_cpu(tile->dst->pDrawable, 461 flags)) 462 goto done; 463 if (tile->dst->alphaMap && 464 !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable, 465 flags)) 466 goto done; 467 468 if (tile->src->pDrawable && 469 !sna_drawable_move_to_cpu(tile->src->pDrawable, 470 MOVE_READ)) 471 goto done; 472 if (tile->src->alphaMap && 473 !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable, 474 MOVE_READ)) 475 goto done; 476 477 for (n = 0; n < tile->rect_count; n++) { 478 BoxRec b; 479 480 b.x1 = r->box.x1 - tile->dst_x; 481 if (b.x1 < x) 482 b.x1 = x; 483 484 b.y1 = r->box.y1 - tile->dst_y; 485 if (b.y1 < y) 486 b.y1 = y; 487 488 b.x2 = r->box.x2 - tile->dst_x; 489 if (b.x2 > x + width) 490 b.x2 = x + width; 491 492 b.y2 = r->box.y2 - tile->dst_y; 493 if (b.y2 > y + height) 494 b.y2 = y + height; 495 496 DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n", 497 __FUNCTION__, n, 498 r->box.x1, r->box.y1, 499 r->box.x2-r->box.x1, r->box.y2-r->box.y1, 500 x, y, width, height, 501 b.x1, b.y1, b.x2, b.y2)); 502 503 if (b.y2 > b.y1 && b.x2 > b.x1) { 504 xRenderColor alpha; 505 PicturePtr mask; 506 int error; 507 508 alpha.red = alpha.green = alpha.blue = 0; 509 alpha.alpha = r->opacity * 0xffff; 510 511 mask = CreateSolidPicture(0, &alpha, &error); 512 if (!mask) 513 goto done; 514 515 if (sigtrap_get() == 0) { 516 fbComposite(tile->op, 517 tile->src, mask, tile->dst, 518 tile->src_x + x, tile->src_y + y, 519 0, 0, 520 tile->dst_x + x, tile->dst_y + y, 521 width, height); 522 sigtrap_put(); 523 } 524 525 FreePicture(mask, 0); 526 } 527 r++; 528 } 529 530 force_fallback = true; 531 } 532 } 533 } 534 535done: 536 if (tile->rects != tile->rects_embedded) 537 free(tile->rects); 538 free(tile); 539} 540 541bool 542sna_tiling_composite_spans(uint32_t op, 543 PicturePtr src, 544 PicturePtr dst, 545 int16_t src_x, int16_t src_y, 546 int16_t dst_x, int16_t dst_y, 547 int16_t width, int16_t height, 548 unsigned flags, 549 struct sna_composite_spans_op *tmp) 550{ 551 struct sna_tile_state *tile; 552 struct sna_pixmap *priv; 553 554 DBG(("%s size=(%d, %d), tile=%d\n", 555 __FUNCTION__, width, height, 556 to_sna_from_drawable(dst->pDrawable)->render.max_3d_size)); 557 558 priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 559 if (priv == NULL || priv->gpu_bo == NULL) 560 return false; 561 562 tile = malloc(sizeof(*tile)); 563 if (!tile) 564 return false; 565 566 tile->op = op; 567 tile->flags = flags; 568 569 tile->src = src; 570 tile->mask = NULL; 571 tile->dst = dst; 572 573 tile->src_x = src_x; 574 tile->src_y = src_y; 575 tile->mask_x = 0; 576 tile->mask_y = 0; 577 tile->dst_x = dst_x; 578 tile->dst_y = dst_y; 579 tile->width = width; 580 tile->height = height; 581 tile->rects = tile->rects_embedded; 582 tile->rect_count = 0; 583 tile->rect_size = ARRAY_SIZE(tile->rects_embedded); 584 585 tmp->box = sna_tiling_composite_spans_box; 586 tmp->boxes = sna_tiling_composite_spans_boxes; 587 tmp->done = sna_tiling_composite_spans_done; 588 589 tmp->base.priv = tile; 590 tmp->base.dst.bo = priv->gpu_bo; 591 return true; 592} 593 594bool 595sna_tiling_fill_boxes(struct sna *sna, 596 CARD8 op, 597 PictFormat format, 598 const xRenderColor *color, 599 const DrawableRec *dst, struct kgem_bo *dst_bo, 600 const BoxRec *box, int n) 601{ 602 RegionRec region, tile, this; 603 struct kgem_bo *bo; 604 int step, max_size; 605 bool ret = false; 606 607 pixman_region_init_rects(®ion, box, n); 608 609 /* Use a small step to accommodate enlargement through tile alignment */ 610 step = sna->render.max_3d_size; 611 if (region.extents.x1 & (8*512 / dst->bitsPerPixel - 1) || 612 region.extents.y1 & 63) 613 step /= 2; 614 615 max_size = sna_max_tile_copy_size(sna, dst_bo, dst_bo); 616 if (max_size == 0) 617 goto done; 618 619 while (step * step * 4 > max_size) 620 step /= 2; 621 622 DBG(("%s (op=%d, format=%x, color=(%04x,%04x,%04x, %04x), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", 623 __FUNCTION__, op, (int)format, 624 color->red, color->green, color->blue, color->alpha, 625 step, n, 626 region.extents.x1, region.extents.y1, 627 region.extents.x2, region.extents.y2)); 628 629 for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; 630 tile.extents.y2 < region.extents.y2; 631 tile.extents.y1 = tile.extents.y2) { 632 int y2 = tile.extents.y1 + step; 633 if (y2 > region.extents.y2) 634 y2 = region.extents.y2; 635 tile.extents.y2 = y2; 636 637 for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; 638 tile.extents.x2 < region.extents.x2; 639 tile.extents.x1 = tile.extents.x2) { 640 DrawableRec tmp; 641 int x2 = tile.extents.x1 + step; 642 if (x2 > region.extents.x2) 643 x2 = region.extents.x2; 644 tile.extents.x2 = x2; 645 646 tile.data = NULL; 647 648 RegionNull(&this); 649 RegionIntersect(&this, ®ion, &tile); 650 if (RegionNil(&this)) 651 continue; 652 653 tmp.width = this.extents.x2 - this.extents.x1; 654 tmp.height = this.extents.y2 - this.extents.y1; 655 tmp.depth = dst->depth; 656 tmp.bitsPerPixel = dst->bitsPerPixel; 657 658 bo = kgem_create_2d(&sna->kgem, 659 tmp.width, 660 tmp.height, 661 dst->bitsPerPixel, 662 kgem_choose_tiling(&sna->kgem, 663 I915_TILING_X, 664 tmp.width, 665 tmp.height, 666 dst->bitsPerPixel), 667 CREATE_TEMPORARY); 668 if (bo) { 669 int16_t dx = this.extents.x1; 670 int16_t dy = this.extents.y1; 671 672 assert(kgem_bo_can_blt(&sna->kgem, bo)); 673 674 if (op > PictOpSrc && 675 !sna->render.copy_boxes(sna, GXcopy, 676 dst, dst_bo, 0, 0, 677 &tmp, bo, -dx, -dy, 678 region_rects(&this), region_num_rects(&this), 0)) 679 goto err; 680 681 RegionTranslate(&this, -dx, -dy); 682 if (!sna->render.fill_boxes(sna, op, format, color, &tmp, bo, 683 region_rects(&this), region_num_rects(&this))) 684 goto err; 685 686 if (!sna->render.copy_boxes(sna, GXcopy, 687 &tmp, bo, 0, 0, 688 dst, dst_bo, dx, dy, 689 region_rects(&this), region_num_rects(&this), 0)) 690 goto err; 691 692 kgem_bo_destroy(&sna->kgem, bo); 693 } 694 RegionUninit(&this); 695 } 696 } 697 698 ret = true; 699 goto done; 700err: 701 kgem_bo_destroy(&sna->kgem, bo); 702 RegionUninit(&this); 703done: 704 pixman_region_fini(®ion); 705 return ret; 706} 707 708fastcall static void 709tiling_blt(struct sna *sna, 710 const struct sna_composite_op *op, 711 const struct sna_composite_rectangles *r) 712{ 713 int x1, x2, y1, y2; 714 int src_x, src_y; 715 BoxRec box; 716 717 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", 718 __FUNCTION__, 719 r->src.x, r->src.y, 720 r->dst.x, r->dst.y, 721 r->width, r->height)); 722 723 /* XXX higher layer should have clipped? */ 724 725 x1 = r->dst.x + op->dst.x; 726 y1 = r->dst.y + op->dst.y; 727 x2 = x1 + r->width; 728 y2 = y1 + r->height; 729 730 src_x = r->src.x - x1 + op->u.blt.sx; 731 src_y = r->src.y - y1 + op->u.blt.sy; 732 733 /* clip against dst */ 734 if (x1 < 0) 735 x1 = 0; 736 if (y1 < 0) 737 y1 = 0; 738 739 if (x2 > op->dst.width) 740 x2 = op->dst.width; 741 742 if (y2 > op->dst.height) 743 y2 = op->dst.height; 744 745 DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2)); 746 747 if (x2 <= x1 || y2 <= y1) 748 return; 749 750 box.x1 = x1; box.y1 = y1; 751 box.x2 = x2; box.y2 = y2; 752 sna_tiling_blt_copy_boxes(sna, GXcopy, 753 op->src.bo, src_x, src_y, 754 op->dst.bo, 0, 0, 755 op->u.blt.bpp, 756 &box, 1); 757} 758 759fastcall static void 760tiling_blt_box(struct sna *sna, 761 const struct sna_composite_op *op, 762 const BoxRec *box) 763{ 764 DBG(("%s: box (%d, %d), (%d, %d)\n", 765 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 766 sna_tiling_blt_copy_boxes(sna, GXcopy, 767 op->src.bo, op->u.blt.sx, op->u.blt.sy, 768 op->dst.bo, op->dst.x, op->dst.y, 769 op->u.blt.bpp, 770 box, 1); 771} 772 773static void 774tiling_blt_boxes(struct sna *sna, 775 const struct sna_composite_op *op, 776 const BoxRec *box, int nbox) 777{ 778 DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 779 sna_tiling_blt_copy_boxes(sna, GXcopy, 780 op->src.bo, op->u.blt.sx, op->u.blt.sy, 781 op->dst.bo, op->dst.x, op->dst.y, 782 op->u.blt.bpp, 783 box, nbox); 784} 785 786static bool 787sna_tiling_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu, 788 struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 789 struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 790 int bpp, int alpha_fixup, 791 const BoxRec *box, int nbox) 792{ 793 RegionRec region, tile, this; 794 struct kgem_bo *bo; 795 int max_size, step; 796 bool ret = false; 797 798 if (wedged(sna) || 799 !kgem_bo_can_blt(&sna->kgem, src_bo) || 800 !kgem_bo_can_blt(&sna->kgem, dst_bo)) { 801 /* XXX */ 802 DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n", 803 __FUNCTION__, 804 kgem_bo_can_blt(&sna->kgem, src_bo), 805 kgem_bo_can_blt(&sna->kgem, dst_bo))); 806 return false; 807 } 808 809 max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo); 810 if (max_size == 0) 811 return false; 812 813 pixman_region_init_rects(®ion, box, nbox); 814 815 /* Use a small step to accommodate enlargement through tile alignment */ 816 step = sna->render.max_3d_size; 817 if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63) 818 step /= 2; 819 while (step * step * 4 > max_size) 820 step /= 2; 821 if (sna->kgem.gen < 033) 822 step /= 2; /* accommodate severe fence restrictions */ 823 if (step == 0) { 824 DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__)); 825 return false; 826 } 827 828 DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", 829 __FUNCTION__, alu, step, nbox, 830 region.extents.x1, region.extents.y1, 831 region.extents.x2, region.extents.y2)); 832 833 for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; 834 tile.extents.y2 < region.extents.y2; 835 tile.extents.y1 = tile.extents.y2) { 836 int y2 = tile.extents.y1 + step; 837 if (y2 > region.extents.y2) 838 y2 = region.extents.y2; 839 tile.extents.y2 = y2; 840 841 for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; 842 tile.extents.x2 < region.extents.x2; 843 tile.extents.x1 = tile.extents.x2) { 844 int w, h; 845 int x2 = tile.extents.x1 + step; 846 if (x2 > region.extents.x2) 847 x2 = region.extents.x2; 848 tile.extents.x2 = x2; 849 850 tile.data = NULL; 851 852 RegionNull(&this); 853 RegionIntersect(&this, ®ion, &tile); 854 if (RegionNil(&this)) 855 continue; 856 857 w = this.extents.x2 - this.extents.x1; 858 h = this.extents.y2 - this.extents.y1; 859 bo = kgem_create_2d(&sna->kgem, w, h, bpp, 860 kgem_choose_tiling(&sna->kgem, 861 I915_TILING_X, 862 w, h, bpp), 863 CREATE_TEMPORARY); 864 if (bo) { 865 int16_t dx = this.extents.x1; 866 int16_t dy = this.extents.y1; 867 868 assert(kgem_bo_can_blt(&sna->kgem, bo)); 869 870 if (!sna_blt_copy_boxes(sna, GXcopy, 871 src_bo, src_dx, src_dy, 872 bo, -dx, -dy, 873 bpp, region_rects(&this), region_num_rects(&this))) 874 goto err; 875 876 if (!sna_blt_copy_boxes__with_alpha(sna, alu, 877 bo, -dx, -dy, 878 dst_bo, dst_dx, dst_dy, 879 bpp, alpha_fixup, 880 region_rects(&this), region_num_rects(&this))) 881 goto err; 882 883 kgem_bo_destroy(&sna->kgem, bo); 884 } 885 RegionUninit(&this); 886 } 887 } 888 889 ret = true; 890 goto done; 891err: 892 kgem_bo_destroy(&sna->kgem, bo); 893 RegionUninit(&this); 894done: 895 pixman_region_fini(®ion); 896 return ret; 897} 898 899fastcall static void 900tiling_blt__with_alpha(struct sna *sna, 901 const struct sna_composite_op *op, 902 const struct sna_composite_rectangles *r) 903{ 904 int x1, x2, y1, y2; 905 int src_x, src_y; 906 BoxRec box; 907 908 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", 909 __FUNCTION__, 910 r->src.x, r->src.y, 911 r->dst.x, r->dst.y, 912 r->width, r->height)); 913 914 /* XXX higher layer should have clipped? */ 915 916 x1 = r->dst.x + op->dst.x; 917 y1 = r->dst.y + op->dst.y; 918 x2 = x1 + r->width; 919 y2 = y1 + r->height; 920 921 src_x = r->src.x - x1 + op->u.blt.sx; 922 src_y = r->src.y - y1 + op->u.blt.sy; 923 924 /* clip against dst */ 925 if (x1 < 0) 926 x1 = 0; 927 if (y1 < 0) 928 y1 = 0; 929 930 if (x2 > op->dst.width) 931 x2 = op->dst.width; 932 933 if (y2 > op->dst.height) 934 y2 = op->dst.height; 935 936 DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2)); 937 938 if (x2 <= x1 || y2 <= y1) 939 return; 940 941 box.x1 = x1; box.y1 = y1; 942 box.x2 = x2; box.y2 = y2; 943 sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy, 944 op->src.bo, src_x, src_y, 945 op->dst.bo, 0, 0, 946 op->u.blt.bpp, op->u.blt.pixel, 947 &box, 1); 948} 949 950fastcall static void 951tiling_blt_box__with_alpha(struct sna *sna, 952 const struct sna_composite_op *op, 953 const BoxRec *box) 954{ 955 DBG(("%s: box (%d, %d), (%d, %d)\n", 956 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 957 sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy, 958 op->src.bo, op->u.blt.sx, op->u.blt.sy, 959 op->dst.bo, op->dst.x, op->dst.y, 960 op->u.blt.bpp, op->u.blt.pixel, 961 box, 1); 962} 963 964static void 965tiling_blt_boxes__with_alpha(struct sna *sna, 966 const struct sna_composite_op *op, 967 const BoxRec *box, int nbox) 968{ 969 DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 970 sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy, 971 op->src.bo, op->u.blt.sx, op->u.blt.sy, 972 op->dst.bo, op->dst.x, op->dst.y, 973 op->u.blt.bpp, op->u.blt.pixel, 974 box, nbox); 975} 976 977static void nop_done(struct sna *sna, const struct sna_composite_op *op) 978{ 979 assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem)); 980 (void)op; 981} 982 983bool 984sna_tiling_blt_composite(struct sna *sna, 985 struct sna_composite_op *op, 986 struct kgem_bo *bo, 987 int bpp, 988 uint32_t alpha_fixup) 989{ 990 assert(op->dst.bo); 991 assert(kgem_bo_can_blt(&sna->kgem, op->dst.bo)); 992 assert(kgem_bo_can_blt(&sna->kgem, bo)); 993 994 op->src.bo = bo; 995 op->u.blt.bpp = bpp; 996 op->u.blt.pixel = alpha_fixup; 997 998 if (alpha_fixup) { 999 op->blt = tiling_blt__with_alpha; 1000 op->box = tiling_blt_box__with_alpha; 1001 op->boxes = tiling_blt_boxes__with_alpha; 1002 } else { 1003 op->blt = tiling_blt; 1004 op->box = tiling_blt_box; 1005 op->boxes = tiling_blt_boxes; 1006 } 1007 op->done = nop_done; 1008 1009 return true; 1010} 1011 1012bool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu, 1013 struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 1014 struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 1015 int bpp, const BoxRec *box, int nbox) 1016{ 1017 RegionRec region, tile, this; 1018 struct kgem_bo *bo; 1019 int max_size, step; 1020 bool ret = false; 1021 1022 DBG(("%s: alu=%d, src size=%d, dst size=%d\n", __FUNCTION__, 1023 alu, kgem_bo_size(src_bo), kgem_bo_size(dst_bo))); 1024 1025 if (wedged(sna) || 1026 !kgem_bo_can_blt(&sna->kgem, src_bo) || 1027 !kgem_bo_can_blt(&sna->kgem, dst_bo)) { 1028 /* XXX */ 1029 DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n", 1030 __FUNCTION__, 1031 kgem_bo_can_blt(&sna->kgem, src_bo), 1032 kgem_bo_can_blt(&sna->kgem, dst_bo))); 1033 return false; 1034 } 1035 1036 max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo); 1037 if (max_size == 0) 1038 return false; 1039 1040 pixman_region_init_rects(®ion, box, nbox); 1041 1042 /* Use a small step to accommodate enlargement through tile alignment */ 1043 step = sna->render.max_3d_size; 1044 if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63) 1045 step /= 2; 1046 while (step * step * 4 > max_size) 1047 step /= 2; 1048 if (sna->kgem.gen < 033) 1049 step /= 2; /* accommodate severe fence restrictions */ 1050 if (step == 0) { 1051 DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__)); 1052 return false; 1053 } 1054 1055 DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", 1056 __FUNCTION__, alu, step, nbox, 1057 region.extents.x1, region.extents.y1, 1058 region.extents.x2, region.extents.y2)); 1059 1060 for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; 1061 tile.extents.y2 < region.extents.y2; 1062 tile.extents.y1 = tile.extents.y2) { 1063 int y2 = tile.extents.y1 + step; 1064 if (y2 > region.extents.y2) 1065 y2 = region.extents.y2; 1066 tile.extents.y2 = y2; 1067 1068 for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; 1069 tile.extents.x2 < region.extents.x2; 1070 tile.extents.x1 = tile.extents.x2) { 1071 int w, h; 1072 int x2 = tile.extents.x1 + step; 1073 if (x2 > region.extents.x2) 1074 x2 = region.extents.x2; 1075 tile.extents.x2 = x2; 1076 1077 tile.data = NULL; 1078 1079 RegionNull(&this); 1080 RegionIntersect(&this, ®ion, &tile); 1081 if (RegionNil(&this)) 1082 continue; 1083 1084 w = this.extents.x2 - this.extents.x1; 1085 h = this.extents.y2 - this.extents.y1; 1086 bo = kgem_create_2d(&sna->kgem, w, h, bpp, 1087 kgem_choose_tiling(&sna->kgem, 1088 I915_TILING_X, 1089 w, h, bpp), 1090 CREATE_TEMPORARY); 1091 if (bo) { 1092 int16_t dx = this.extents.x1; 1093 int16_t dy = this.extents.y1; 1094 1095 assert(kgem_bo_can_blt(&sna->kgem, bo)); 1096 1097 if (!sna_blt_copy_boxes(sna, GXcopy, 1098 src_bo, src_dx, src_dy, 1099 bo, -dx, -dy, 1100 bpp, region_rects(&this), region_num_rects(&this))) 1101 goto err; 1102 1103 if (!sna_blt_copy_boxes(sna, alu, 1104 bo, -dx, -dy, 1105 dst_bo, dst_dx, dst_dy, 1106 bpp, region_rects(&this), region_num_rects(&this))) 1107 goto err; 1108 1109 kgem_bo_destroy(&sna->kgem, bo); 1110 } 1111 RegionUninit(&this); 1112 } 1113 } 1114 1115 ret = true; 1116 goto done; 1117err: 1118 kgem_bo_destroy(&sna->kgem, bo); 1119 RegionUninit(&this); 1120done: 1121 pixman_region_fini(®ion); 1122 return ret; 1123} 1124 1125bool 1126sna_tiling_copy_boxes(struct sna *sna, uint8_t alu, 1127 const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 1128 const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 1129 const BoxRec *box, int n) 1130{ 1131 BoxRec extents, tile, stack[64], *clipped, *c; 1132 DrawableRec p; 1133 int i, step, tiling; 1134 bool create = true; 1135 bool ret = false; 1136 1137 extents = box[0]; 1138 for (i = 1; i < n; i++) { 1139 if (box[i].x1 < extents.x1) 1140 extents.x1 = box[i].x1; 1141 if (box[i].y1 < extents.y1) 1142 extents.y1 = box[i].y1; 1143 1144 if (box[i].x2 > extents.x2) 1145 extents.x2 = box[i].x2; 1146 if (box[i].y2 > extents.y2) 1147 extents.y2 = box[i].y2; 1148 } 1149 1150 tiling = I915_TILING_X; 1151 if (!kgem_bo_can_blt(&sna->kgem, src_bo) || 1152 !kgem_bo_can_blt(&sna->kgem, dst_bo)) 1153 tiling = I915_TILING_Y; 1154 1155 create = (src_bo->pitch > sna->render.max_3d_pitch || 1156 dst_bo->pitch > sna->render.max_3d_pitch); 1157 1158 step = sna->render.max_3d_size / 2; 1159 if (create) { 1160 while (step * step * 4 > sna->kgem.max_upload_tile_size) 1161 step /= 2; 1162 } 1163 1164 DBG(("%s: tiling copy %dx%d, %s %dx%d %c tiles\n", __FUNCTION__, 1165 extents.x2-extents.x1, extents.y2-extents.y1, 1166 create ? "creating" : "using", 1167 step, step, tiling == I915_TILING_X ? 'X' : 'Y')); 1168 1169 if (n > ARRAY_SIZE(stack)) { 1170 clipped = malloc(sizeof(BoxRec) * n); 1171 if (clipped == NULL) 1172 goto tiled_error; 1173 } else 1174 clipped = stack; 1175 1176 p.depth = src->depth; 1177 p.bitsPerPixel = src->bitsPerPixel; 1178 1179 for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) { 1180 int y2 = tile.y1 + step; 1181 if (y2 > extents.y2) 1182 y2 = extents.y2; 1183 tile.y2 = y2; 1184 1185 for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { 1186 struct kgem_bo *tmp_bo; 1187 int x2 = tile.x1 + step; 1188 if (x2 > extents.x2) 1189 x2 = extents.x2; 1190 tile.x2 = x2; 1191 1192 c = clipped; 1193 for (i = 0; i < n; i++) { 1194 *c = box[i]; 1195 if (!box_intersect(c, &tile)) 1196 continue; 1197 1198 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 1199 __FUNCTION__, 1200 c->x1, c->y1, 1201 c->x2, c->y2, 1202 src_dx, src_dy, 1203 c->x1 - tile.x1, 1204 c->y1 - tile.y1)); 1205 c++; 1206 } 1207 if (c == clipped) 1208 continue; 1209 1210 p.width = tile.x2 - tile.x1; 1211 p.height = tile.y2 - tile.y1; 1212 1213 DBG(("%s: tile (%d, %d), (%d, %d)\n", 1214 __FUNCTION__, tile.x1, tile.y1, tile.x2, tile.y2)); 1215 1216 if (create) { 1217 tmp_bo = kgem_create_2d(&sna->kgem, 1218 p.width, 1219 p.height, 1220 p.bitsPerPixel, 1221 tiling, CREATE_TEMPORARY); 1222 if (!tmp_bo) 1223 goto tiled_error; 1224 1225 i = (sna->render.copy_boxes(sna, GXcopy, 1226 src, src_bo, src_dx, src_dy, 1227 &p, tmp_bo, -tile.x1, -tile.y1, 1228 clipped, c - clipped, 0) && 1229 sna->render.copy_boxes(sna, alu, 1230 &p, tmp_bo, -tile.x1, -tile.y1, 1231 dst, dst_bo, dst_dx, dst_dy, 1232 clipped, c - clipped, 0)); 1233 1234 kgem_bo_destroy(&sna->kgem, tmp_bo); 1235 } else { 1236 i = sna->render.copy_boxes(sna, GXcopy, 1237 src, src_bo, src_dx, src_dy, 1238 dst, dst_bo, dst_dx, dst_dy, 1239 clipped, c - clipped, 0); 1240 } 1241 1242 if (!i) 1243 goto tiled_error; 1244 } 1245 } 1246 1247 ret = true; 1248tiled_error: 1249 if (clipped != stack) 1250 free(clipped); 1251 1252 return ret; 1253} 1254