1/* 2 * Copyright © 2011 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 "sna_render_inline.h" 35#include "fb/fbpict.h" 36 37#define NO_REDIRECT 0 38#define NO_CONVERT 0 39#define NO_FIXUP 0 40#define NO_EXTRACT 0 41 42#define DBG_FORCE_UPLOAD 0 43#define DBG_NO_CPU_BO 0 44 45#define alphaless(format) PICT_FORMAT(PICT_FORMAT_BPP(format), \ 46 PICT_FORMAT_TYPE(format), \ 47 0, \ 48 PICT_FORMAT_R(format), \ 49 PICT_FORMAT_G(format), \ 50 PICT_FORMAT_B(format)) 51 52CARD32 53sna_format_for_depth(int depth) 54{ 55 switch (depth) { 56 case 1: return PICT_a1; 57 case 4: return PICT_a4; 58 case 8: return PICT_a8; 59 case 15: return PICT_x1r5g5b5; 60 case 16: return PICT_r5g6b5; 61 default: assert(0); 62 case 24: return PICT_x8r8g8b8; 63#ifdef PICT_x2r10g10b10 64 case 30: return PICT_x2r10g10b10; 65#endif 66 case 32: return PICT_a8r8g8b8; 67 } 68} 69 70CARD32 71sna_render_format_for_depth(int depth) 72{ 73 switch (depth) { 74 case 1: return PIXMAN_a1; 75 case 4: return PIXMAN_a4; 76 case 8: return PIXMAN_a8; 77 case 15: return PIXMAN_a1r5g5b5; 78 case 16: return PIXMAN_r5g6b5; 79 case 30: return PIXMAN_a2r10g10b10; 80 default: assert(0); 81 case 24: 82 case 32: return PIXMAN_a8r8g8b8; 83 } 84} 85 86static bool 87no_render_composite(struct sna *sna, 88 uint8_t op, 89 PicturePtr src, 90 PicturePtr mask, 91 PicturePtr dst, 92 int16_t src_x, int16_t src_y, 93 int16_t mask_x, int16_t mask_y, 94 int16_t dst_x, int16_t dst_y, 95 int16_t width, int16_t height, 96 unsigned flags, 97 struct sna_composite_op *tmp) 98{ 99 DBG(("%s (op=%d, mask? %d)\n", __FUNCTION__, op, mask != NULL)); 100 101 if (mask) 102 return false; 103 104 if (!is_gpu(sna, dst->pDrawable, PREFER_GPU_BLT) && 105 (src->pDrawable == NULL || !is_gpu(sna, src->pDrawable, PREFER_GPU_BLT))) 106 return false; 107 108 return sna_blt_composite(sna, 109 op, src, dst, 110 src_x, src_y, 111 dst_x, dst_y, 112 width, height, 113 flags | COMPOSITE_FALLBACK, tmp); 114 (void)mask_x; 115 (void)mask_y; 116} 117 118static bool 119no_render_check_composite_spans(struct sna *sna, 120 uint8_t op, PicturePtr src, PicturePtr dst, 121 int16_t width, int16_t height, unsigned flags) 122{ 123 return false; 124} 125 126static bool 127no_render_copy_boxes(struct sna *sna, uint8_t alu, 128 const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 129 const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 130 const BoxRec *box, int n, unsigned flags) 131{ 132 DBG(("%s (n=%d)\n", __FUNCTION__, n)); 133 134 if (!sna_blt_compare_depth(src, dst)) 135 return false; 136 137 return sna_blt_copy_boxes(sna, alu, 138 src_bo, src_dx, src_dy, 139 dst_bo, dst_dx, dst_dy, 140 dst->bitsPerPixel, 141 box, n); 142} 143 144static bool 145no_render_copy(struct sna *sna, uint8_t alu, 146 PixmapPtr src, struct kgem_bo *src_bo, 147 PixmapPtr dst, struct kgem_bo *dst_bo, 148 struct sna_copy_op *tmp) 149{ 150 DBG(("%s ()\n", __FUNCTION__)); 151 152 if (sna_blt_compare_depth(&src->drawable, &dst->drawable) && 153 sna_blt_copy(sna, alu, 154 src_bo, dst_bo, dst->drawable.bitsPerPixel, 155 tmp)) 156 return true; 157 158 return false; 159} 160 161static bool 162no_render_fill_boxes(struct sna *sna, 163 CARD8 op, 164 PictFormat format, 165 const xRenderColor *color, 166 const DrawableRec *dst, struct kgem_bo *dst_bo, 167 const BoxRec *box, int n) 168{ 169 uint8_t alu = GXcopy; 170 uint32_t pixel; 171 172 DBG(("%s (op=%d, color=(%04x,%04x,%04x, %04x))\n", 173 __FUNCTION__, op, 174 color->red, color->green, color->blue, color->alpha)); 175 176 if (op == PictOpClear) { 177 pixel = 0; 178 alu = GXclear; 179 op = PictOpSrc; 180 } 181 182 if (op == PictOpOver) { 183 if ((color->alpha >= 0xff00)) 184 op = PictOpSrc; 185 } 186 187 if (op != PictOpSrc) 188 return false; 189 190 if (alu == GXcopy && 191 !sna_get_pixel_from_rgba(&pixel, 192 color->red, 193 color->green, 194 color->blue, 195 color->alpha, 196 format)) 197 return false; 198 199 return sna_blt_fill_boxes(sna, alu, 200 dst_bo, dst->bitsPerPixel, 201 pixel, box, n); 202} 203 204static bool 205no_render_fill(struct sna *sna, uint8_t alu, 206 PixmapPtr dst, struct kgem_bo *dst_bo, 207 uint32_t color, unsigned flags, 208 struct sna_fill_op *tmp) 209{ 210 DBG(("%s (alu=%d, color=%08x)\n", __FUNCTION__, alu, color)); 211 return sna_blt_fill(sna, alu, 212 dst_bo, dst->drawable.bitsPerPixel, 213 color, 214 tmp); 215} 216 217static bool 218no_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo, 219 uint32_t color, 220 int16_t x1, int16_t y1, int16_t x2, int16_t y2, 221 uint8_t alu) 222{ 223 BoxRec box; 224 225 box.x1 = x1; 226 box.y1 = y1; 227 box.x2 = x2; 228 box.y2 = y2; 229 230 DBG(("%s (alu=%d, color=%08x) (%d,%d), (%d, %d)\n", 231 __FUNCTION__, alu, color, x1, y1, x2, y2)); 232 return sna_blt_fill_boxes(sna, alu, 233 bo, dst->drawable.bitsPerPixel, 234 color, &box, 1); 235} 236 237static bool 238no_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo) 239{ 240 DBG(("%s: pixmap=%ld %dx%d\n", __FUNCTION__, 241 dst->drawable.serialNumber, 242 dst->drawable.width, 243 dst->drawable.height)); 244 return sna->render.fill_one(sna, dst, bo, 0, 245 0, 0, dst->drawable.width, dst->drawable.height, 246 GXclear); 247} 248 249static void no_render_reset(struct sna *sna) 250{ 251 (void)sna; 252} 253 254static void no_render_flush(struct sna *sna) 255{ 256 (void)sna; 257} 258 259static void 260no_render_context_switch(struct kgem *kgem, 261 int new_mode) 262{ 263 if (!kgem->nbatch) 264 return; 265 266 if (kgem_ring_is_idle(kgem, kgem->ring)) { 267 DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 268 _kgem_submit(kgem); 269 } 270 271 (void)new_mode; 272} 273 274static void 275no_render_retire(struct kgem *kgem) 276{ 277 (void)kgem; 278} 279 280static void 281no_render_expire(struct kgem *kgem) 282{ 283 (void)kgem; 284} 285 286static void 287no_render_fini(struct sna *sna) 288{ 289 (void)sna; 290} 291 292const char *no_render_init(struct sna *sna) 293{ 294 struct sna_render *render = &sna->render; 295 296 memset (render, 0, sizeof (*render)); 297 298 render->prefer_gpu = PREFER_GPU_BLT; 299 300 render->vertices = render->vertex_data; 301 render->vertex_size = ARRAY_SIZE(render->vertex_data); 302 303 render->composite = no_render_composite; 304 render->check_composite_spans = no_render_check_composite_spans; 305 306 render->copy_boxes = no_render_copy_boxes; 307 render->copy = no_render_copy; 308 309 render->fill_boxes = no_render_fill_boxes; 310 render->fill = no_render_fill; 311 render->fill_one = no_render_fill_one; 312 render->clear = no_render_clear; 313 314 render->reset = no_render_reset; 315 render->flush = no_render_flush; 316 render->fini = no_render_fini; 317 318 sna->kgem.context_switch = no_render_context_switch; 319 sna->kgem.retire = no_render_retire; 320 sna->kgem.expire = no_render_expire; 321 if (sna->kgem.has_blt) 322 sna->kgem.ring = KGEM_BLT; 323 324 sna_vertex_init(sna); 325 return "generic"; 326} 327 328static struct kgem_bo * 329use_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt) 330{ 331 struct sna_pixmap *priv; 332 333 if (DBG_NO_CPU_BO) 334 return NULL; 335 336 priv = sna_pixmap(pixmap); 337 if (priv == NULL || priv->cpu_bo == NULL) { 338 DBG(("%s: no cpu bo\n", __FUNCTION__)); 339 return NULL; 340 } 341 342 if (!blt && priv->cpu_bo->snoop && priv->source_count > SOURCE_BIAS) { 343 DBG(("%s: promoting snooped CPU bo due to reuse\n", 344 __FUNCTION__)); 345 return NULL; 346 } 347 348 if (priv->gpu_bo) { 349 switch (sna_damage_contains_box(&priv->cpu_damage, box)) { 350 case PIXMAN_REGION_OUT: 351 DBG(("%s: has GPU bo and no damage to upload\n", 352 __FUNCTION__)); 353 return NULL; 354 355 case PIXMAN_REGION_IN: 356 DBG(("%s: has GPU bo but box is completely on CPU\n", 357 __FUNCTION__)); 358 break; 359 default: 360 if (kgem_bo_is_busy(priv->gpu_bo)){ 361 DBG(("%s: box is partially damaged on the CPU, and the GPU is busy\n", 362 __FUNCTION__)); 363 return NULL; 364 } 365 if (sna_damage_contains_box(&priv->gpu_damage, 366 box) != PIXMAN_REGION_OUT) { 367 DBG(("%s: box is damaged on the GPU\n", 368 __FUNCTION__)); 369 return NULL; 370 } 371 break; 372 } 373 } 374 375 if (!blt) { 376 int w = box->x2 - box->x1; 377 int h = box->y2 - box->y1; 378 379 if (w < pixmap->drawable.width || 380 h < pixmap->drawable.height || 381 priv->source_count != SOURCE_BIAS) { 382 bool want_tiling; 383 384 if (priv->cpu_bo->pitch >= 4096) { 385 DBG(("%s: size=%dx%d, promoting reused (%d) CPU bo due to TLB miss (%dx%d, pitch=%d)\n", 386 __FUNCTION__, w, h, priv->source_count, 387 pixmap->drawable.width, 388 pixmap->drawable.height, 389 priv->cpu_bo->pitch)); 390 return NULL; 391 } 392 393 if (priv->gpu_bo) 394 want_tiling = priv->gpu_bo->tiling != I915_TILING_NONE; 395 else 396 want_tiling = kgem_choose_tiling(&sna->kgem, 397 I915_TILING_Y, 398 pixmap->drawable.width, 399 pixmap->drawable.height, 400 pixmap->drawable.bitsPerPixel) != I915_TILING_NONE; 401 if (want_tiling && 402 priv->source_count*w*h >= (int)pixmap->drawable.width * pixmap->drawable.height) { 403 DBG(("%s: pitch (%d) requires tiling\n", 404 __FUNCTION__, priv->cpu_bo->pitch)); 405 return NULL; 406 } 407 } 408 } 409 410 if (priv->shm) { 411 assert(!priv->flush); 412 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 413 } 414 415 DBG(("%s for box=(%d, %d), (%d, %d)\n", 416 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 417 ++priv->source_count; 418 return priv->cpu_bo; 419} 420 421static struct kgem_bo * 422move_to_gpu(PixmapPtr pixmap, const BoxRec *box, bool blt) 423{ 424 struct sna_pixmap *priv; 425 int count, w, h; 426 bool migrate = false; 427 428 if (DBG_FORCE_UPLOAD > 0) 429 return NULL; 430 431 priv = sna_pixmap(pixmap); 432 if (priv == NULL) { 433 DBG(("%s: not migrating unattached pixmap=%ld\n", 434 __FUNCTION__, pixmap->drawable.serialNumber)); 435 return NULL; 436 } 437 438 if (priv->shm) 439 blt = true; 440 441 if (priv->gpu_bo) { 442 if (priv->cpu_damage && 443 sna_damage_contains_box(&priv->cpu_damage, 444 box) != PIXMAN_REGION_OUT) 445 goto upload; 446 447 return priv->gpu_bo; 448 } 449 450 if (priv->cpu_damage == NULL) { 451 DBG(("%s: not migrating uninitialised pixmap=%ld\n", 452 __FUNCTION__, pixmap->drawable.serialNumber)); 453 return NULL; 454 } 455 456 if (pixmap->usage_hint) { 457 DBG(("%s: not migrating pixmap=%ld due to usage_hint=%d\n", 458 __FUNCTION__, 459 pixmap->drawable.serialNumber, 460 pixmap->usage_hint)); 461 return NULL; 462 } 463 464 if (DBG_FORCE_UPLOAD < 0) { 465 if (!sna_pixmap_force_to_gpu(pixmap, 466 blt ? MOVE_READ : MOVE_SOURCE_HINT | MOVE_ASYNC_HINT | MOVE_READ)) 467 return NULL; 468 469 return priv->gpu_bo; 470 } 471 472 w = box->x2 - box->x1; 473 h = box->y2 - box->y1; 474 if (priv->cpu_bo && !priv->cpu_bo->flush) { 475 migrate = true; 476 } else if (w == pixmap->drawable.width && h == pixmap->drawable.height) { 477 migrate = priv->source_count++ > SOURCE_BIAS; 478 479 DBG(("%s: migrating whole pixmap (%dx%d) for source (%d,%d),(%d,%d), count %d? %d\n", 480 __FUNCTION__, 481 pixmap->drawable.width, pixmap->drawable.height, 482 box->x1, box->y1, box->x2, box->y2, priv->source_count, 483 migrate)); 484 } else if (kgem_choose_tiling(&to_sna_from_pixmap(pixmap)->kgem, 485 blt ? I915_TILING_X : I915_TILING_Y, w, h, 486 pixmap->drawable.bitsPerPixel) != I915_TILING_NONE) { 487 count = priv->source_count++; 488 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 489 count -= SOURCE_BIAS; 490 491 DBG(("%s: migrate box (%d, %d), (%d, %d)? source count=%d, fraction=%d/%d [%d]\n", 492 __FUNCTION__, 493 box->x1, box->y1, box->x2, box->y2, 494 count, w*h, 495 pixmap->drawable.width * pixmap->drawable.height, 496 pixmap->drawable.width * pixmap->drawable.height / (w*h))); 497 498 migrate = count*w*h > pixmap->drawable.width * pixmap->drawable.height; 499 } 500 501 if (!migrate) 502 return NULL; 503 504upload: 505 if (blt) { 506 if (!sna_pixmap_move_area_to_gpu(pixmap, box, 507 __MOVE_FORCE | MOVE_READ)) 508 return NULL; 509 } else { 510 if (!sna_pixmap_move_to_gpu(pixmap, 511 __MOVE_FORCE | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ)) 512 return NULL; 513 } 514 515 return priv->gpu_bo; 516} 517 518static struct kgem_bo *upload(struct sna *sna, 519 struct sna_composite_channel *channel, 520 PixmapPtr pixmap, 521 const BoxRec *box) 522{ 523 struct sna_pixmap *priv; 524 struct kgem_bo *bo; 525 526 DBG(("%s: box=(%d, %d), (%d, %d), pixmap=%dx%d\n", 527 __FUNCTION__, box->x1, box->y1, box->x2, box->y2, pixmap->drawable.width, pixmap->drawable.height)); 528 assert(box->x1 >= 0); 529 assert(box->y1 >= 0); 530 assert(box->x2 <= pixmap->drawable.width); 531 assert(box->y2 <= pixmap->drawable.height); 532 533 priv = sna_pixmap(pixmap); 534 if (priv) { 535 RegionRec region; 536 537 if (priv->cpu_damage == NULL) 538 return NULL; /* uninitialised */ 539 540 region.extents = *box; 541 region.data = NULL; 542 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 543 ®ion, MOVE_READ)) 544 return NULL; 545 546 assert(!priv->mapped); 547 if (pixmap->devPrivate.ptr == NULL) 548 return NULL; /* uninitialised */ 549 } 550 551 bo = kgem_upload_source_image(&sna->kgem, 552 pixmap->devPrivate.ptr, box, 553 pixmap->devKind, 554 pixmap->drawable.bitsPerPixel); 555 if (channel && bo) { 556 channel->width = box->x2 - box->x1; 557 channel->height = box->y2 - box->y1; 558 channel->offset[0] -= box->x1; 559 channel->offset[1] -= box->y1; 560 561 if (priv && 562 pixmap->usage_hint == 0 && 563 channel->width == pixmap->drawable.width && 564 channel->height == pixmap->drawable.height) { 565 DBG(("%s: adding upload cache to pixmap=%ld\n", 566 __FUNCTION__, pixmap->drawable.serialNumber)); 567 assert(priv->gpu_damage == NULL); 568 assert(priv->gpu_bo == NULL); 569 assert(bo->proxy != NULL); 570 kgem_proxy_bo_attach(bo, &priv->gpu_bo); 571 } 572 } 573 574 return bo; 575} 576 577struct kgem_bo * 578__sna_render_pixmap_bo(struct sna *sna, 579 PixmapPtr pixmap, 580 const BoxRec *box, 581 bool blt) 582{ 583 struct kgem_bo *bo; 584 585 bo = use_cpu_bo(sna, pixmap, box, blt); 586 if (bo == NULL) { 587 bo = move_to_gpu(pixmap, box, blt); 588 if (bo == NULL) 589 return NULL; 590 } 591 592 return bo; 593} 594 595int 596sna_render_pixmap_bo(struct sna *sna, 597 struct sna_composite_channel *channel, 598 PixmapPtr pixmap, 599 int16_t x, int16_t y, 600 int16_t w, int16_t h, 601 int16_t dst_x, int16_t dst_y) 602{ 603 struct sna_pixmap *priv; 604 BoxRec box; 605 606 DBG(("%s pixmap=%ld, (%d, %d)x(%d, %d)/(%d, %d)\n", 607 __FUNCTION__, pixmap->drawable.serialNumber, 608 x, y, w,h, pixmap->drawable.width, pixmap->drawable.height)); 609 610 channel->width = pixmap->drawable.width; 611 channel->height = pixmap->drawable.height; 612 channel->offset[0] = x - dst_x; 613 channel->offset[1] = y - dst_y; 614 615 priv = sna_pixmap(pixmap); 616 if (priv) { 617 if (priv->gpu_bo && 618 (DAMAGE_IS_ALL(priv->gpu_damage) || !priv->cpu_damage || 619 priv->gpu_bo->proxy)) { 620 DBG(("%s: GPU all damaged\n", __FUNCTION__)); 621 channel->bo = priv->gpu_bo; 622 goto done; 623 } 624 625 if (priv->cpu_bo && 626 (DAMAGE_IS_ALL(priv->cpu_damage) || !priv->gpu_damage) && 627 !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) { 628 DBG(("%s: CPU all damaged\n", __FUNCTION__)); 629 channel->bo = priv->cpu_bo; 630 if (priv->shm) { 631 assert(!priv->flush); 632 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 633 } 634 goto done; 635 } 636 } 637 638 /* XXX handle transformed repeat */ 639 if (w == 0 || h == 0 || channel->transform) { 640 box.x1 = box.y1 = 0; 641 box.x2 = pixmap->drawable.width; 642 box.y2 = pixmap->drawable.height; 643 } else { 644 box.x1 = x; 645 box.y1 = y; 646 box.x2 = bound(x, w); 647 box.y2 = bound(y, h); 648 649 if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 650 if (box.x1 < 0) 651 box.x1 = 0; 652 if (box.y1 < 0) 653 box.y1 = 0; 654 if (box.x2 > pixmap->drawable.width) 655 box.x2 = pixmap->drawable.width; 656 if (box.y2 > pixmap->drawable.height) 657 box.y2 = pixmap->drawable.height; 658 } else { 659 if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 660 box.x1 = 0, box.x2 = pixmap->drawable.width; 661 if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 662 box.y1 = 0, box.y2 = pixmap->drawable.height; 663 } 664 } 665 666 w = box.x2 - box.x1; 667 h = box.y2 - box.y1; 668 DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 669 box.x1, box.y1, box.x2, box.y2, w, h, 670 pixmap->drawable.width, pixmap->drawable.height)); 671 if (w <= 0 || h <= 0) { 672 DBG(("%s: sample extents outside of texture -> clear\n", 673 __FUNCTION__)); 674 return 0; 675 } 676 677 DBG(("%s: offset=(%d, %d), size=(%d, %d)\n", 678 __FUNCTION__, 679 channel->offset[0], channel->offset[1], 680 pixmap->drawable.width, pixmap->drawable.height)); 681 682 channel->bo = __sna_render_pixmap_bo(sna, pixmap, &box, false); 683 if (channel->bo == NULL) { 684 DBG(("%s: uploading CPU box (%d, %d), (%d, %d)\n", 685 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 686 channel->bo = upload(sna, channel, pixmap, &box); 687 if (channel->bo == NULL) 688 return 0; 689 } else { 690done: 691 kgem_bo_reference(channel->bo); 692 } 693 694 channel->scale[0] = 1.f / channel->width; 695 channel->scale[1] = 1.f / channel->height; 696 return 1; 697} 698 699static int sna_render_picture_downsample(struct sna *sna, 700 PicturePtr picture, 701 struct sna_composite_channel *channel, 702 const int16_t x, const int16_t y, 703 const int16_t w, const int16_t h, 704 const int16_t dst_x, const int16_t dst_y) 705{ 706 PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 707 ScreenPtr screen = pixmap->drawable.pScreen; 708 PicturePtr tmp_src, tmp_dst; 709 PictFormatPtr format; 710 struct sna_pixmap *priv; 711 pixman_transform_t t; 712 PixmapPtr tmp; 713 int width, height, size, max_size; 714 int sx, sy, sw, sh; 715 int error, ret = 0; 716 BoxRec box, b; 717 718 box.x1 = x; 719 box.y1 = y; 720 box.x2 = bound(x, w); 721 box.y2 = bound(y, h); 722 if (channel->transform) { 723 pixman_vector_t v; 724 725 pixman_transform_bounds(channel->transform, &box); 726 727 v.vector[0] = x << 16; 728 v.vector[1] = y << 16; 729 v.vector[2] = 1 << 16; 730 pixman_transform_point(channel->transform, &v); 731 } 732 733 if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 734 if (box.x1 < 0) 735 box.x1 = 0; 736 if (box.y1 < 0) 737 box.y1 = 0; 738 if (box.x2 > pixmap->drawable.width) 739 box.x2 = pixmap->drawable.width; 740 if (box.y2 > pixmap->drawable.height) 741 box.y2 = pixmap->drawable.height; 742 } else { 743 /* XXX tiled repeats? */ 744 if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 745 box.x1 = 0, box.x2 = pixmap->drawable.width; 746 if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 747 box.y1 = 0, box.y2 = pixmap->drawable.height; 748 749 } 750 751 sw = box.x2 - box.x1; 752 sh = box.y2 - box.y1; 753 754 DBG(("%s: sample (%d, %d), (%d, %d)\n", 755 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 756 757 sx = (sw + sna->render.max_3d_size - 1) / sna->render.max_3d_size; 758 sy = (sh + sna->render.max_3d_size - 1) / sna->render.max_3d_size; 759 760 DBG(("%s: scaling (%d, %d) down by %dx%d\n", 761 __FUNCTION__, sw, sh, sx, sy)); 762 763 width = sw / sx; 764 height = sh / sy; 765 766 DBG(("%s: creating temporary GPU bo %dx%d\n", 767 __FUNCTION__, width, height)); 768 769 tmp = screen->CreatePixmap(screen, 770 width, height, 771 pixmap->drawable.depth, 772 SNA_CREATE_SCRATCH); 773 if (tmp == NULL) 774 goto fixup; 775 776 priv = sna_pixmap(tmp); 777 assert(priv && priv->gpu_bo); 778 779 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ)) { 780fixup: 781 DBG(("%s: unable to create GPU bo for target or temporary pixmaps\n", 782 __FUNCTION__)); 783 return sna_render_picture_fixup(sna, picture, channel, 784 x, y, w, h, 785 dst_x, dst_y); 786 } 787 788 format = PictureMatchFormat(screen, 789 pixmap->drawable.depth, 790 picture->format); 791 if (format == NULL) { 792 DBG(("%s: invalid depth=%d, format=%08x\n", 793 __FUNCTION__, pixmap->drawable.depth, picture->format)); 794 goto fixup; 795 } 796 797 tmp_dst = CreatePicture(0, &tmp->drawable, format, 0, NULL, 798 serverClient, &error); 799 if (!tmp_dst) 800 goto cleanup_tmp; 801 802 tmp_src = CreatePicture(0, &pixmap->drawable, format, 0, NULL, 803 serverClient, &error); 804 if (!tmp_src) 805 goto cleanup_dst; 806 807 tmp_src->repeat = 1; 808 tmp_src->repeatType = RepeatPad; 809 /* Prefer to use nearest as it helps reduce artefacts from 810 * interpolating and filtering twice. 811 */ 812 tmp_src->filter = PictFilterNearest; 813 memset(&t, 0, sizeof(t)); 814 t.matrix[0][0] = (sw << 16) / width; 815 t.matrix[0][2] = box.x1 << 16; 816 t.matrix[1][1] = (sh << 16) / height; 817 t.matrix[1][2] = box.y1 << 16; 818 t.matrix[2][2] = 1 << 16; 819 tmp_src->transform = &t; 820 821 ValidatePicture(tmp_dst); 822 ValidatePicture(tmp_src); 823 824 /* Use a small size to accommodate enlargement through tile alignment */ 825 max_size = sna_max_tile_copy_size(sna, sna_pixmap(pixmap)->gpu_bo, priv->gpu_bo); 826 if (max_size == 0) 827 goto cleanup_dst; 828 829 size = sna->render.max_3d_size - 4096 / pixmap->drawable.bitsPerPixel; 830 while (size * size * 4 > max_size) 831 size /= 2; 832 DBG(("%s: size=%d (max=%d), scale %dx%d\n", 833 __FUNCTION__, size, max_size, sx, sy)); 834 835 sw = size / sx - 2 * sx; 836 if (sw < 1) 837 sw = 1; 838 sh = size / sy - 2 * sy; 839 if (sh < 1) 840 sh = 1; 841 DBG(("%s %d:%d downsampling using %dx%d GPU tiles\n", 842 __FUNCTION__, (width + sw-1)/sw, (height + sh-1)/sh, sw, sh)); 843 844 for (b.y1 = 0; b.y1 < height; b.y1 = b.y2) { 845 b.y2 = b.y1 + sh; 846 if (b.y2 > height) 847 b.y2 = height; 848 849 for (b.x1 = 0; b.x1 < width; b.x1 = b.x2) { 850 struct sna_composite_op op; 851 852 b.x2 = b.x1 + sw; 853 if (b.x2 > width) 854 b.x2 = width; 855 856 DBG(("%s: tile (%d, %d), (%d, %d)\n", 857 __FUNCTION__, b.x1, b.y1, b.x2, b.y2)); 858 859 memset(&op, 0, sizeof(op)); 860 if (!sna->render.composite(sna, 861 PictOpSrc, 862 tmp_src, NULL, tmp_dst, 863 b.x1, b.y1, 864 0, 0, 865 b.x1, b.y1, 866 b.x2 - b.x1, b.y2 - b.y1, 867 0, &op)) 868 goto cleanup_src; 869 870 op.box(sna, &op, &b); 871 op.done(sna, &op); 872 } 873 } 874 875 pixman_transform_invert(&channel->embedded_transform, &t); 876 if (channel->transform) 877 pixman_transform_multiply(&channel->embedded_transform, 878 &channel->embedded_transform, 879 channel->transform); 880 channel->transform = &channel->embedded_transform; 881 882 channel->offset[0] = x - dst_x; 883 channel->offset[1] = y - dst_y; 884 channel->scale[0] = 1.f/width; 885 channel->scale[1] = 1.f/height; 886 channel->width = width; 887 channel->height = height; 888 channel->bo = kgem_bo_reference(priv->gpu_bo); 889 890 ret = 1; 891cleanup_src: 892 tmp_src->transform = NULL; 893 FreePicture(tmp_src, 0); 894cleanup_dst: 895 FreePicture(tmp_dst, 0); 896cleanup_tmp: 897 screen->DestroyPixmap(tmp); 898 return ret; 899} 900 901bool 902sna_render_pixmap_partial(struct sna *sna, 903 const DrawableRec *draw, 904 struct kgem_bo *bo, 905 struct sna_composite_channel *channel, 906 int16_t x, int16_t y, 907 int16_t w, int16_t h) 908{ 909 BoxRec box; 910 int offset; 911 912 DBG(("%s (%d, %d)x(%d, %d), pitch %d, max %d\n", 913 __FUNCTION__, x, y, w, h, bo->pitch, sna->render.max_3d_pitch)); 914 915 if (bo->pitch > sna->render.max_3d_pitch) { 916 DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch)); 917 return false; 918 } 919 920 box.x1 = x; 921 box.y1 = y; 922 box.x2 = bound(x, w); 923 box.y2 = bound(y, h); 924 DBG(("%s: unaligned box (%d, %d), (%d, %d)\n", 925 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 926 927 if (box.x1 < 0) 928 box.x1 = 0; 929 if (box.y1 < 0) 930 box.y1 = 0; 931 932 if (bo->tiling) { 933 int tile_width, tile_height, tile_size; 934 935 kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch, 936 &tile_width, &tile_height, &tile_size); 937 DBG(("%s: tile size for tiling %d: %dx%d, size=%d\n", 938 __FUNCTION__, bo->tiling, tile_width, tile_height, tile_size)); 939 940 /* Ensure we align to an even tile row */ 941 box.y1 = box.y1 & ~(2*tile_height - 1); 942 box.y2 = ALIGN(box.y2, 2*tile_height); 943 944 assert(tile_width * 8 >= draw->bitsPerPixel); 945 box.x1 = box.x1 & ~(tile_width * 8 / draw->bitsPerPixel - 1); 946 box.x2 = ALIGN(box.x2, tile_width * 8 / draw->bitsPerPixel); 947 948 offset = box.x1 * draw->bitsPerPixel / 8 / tile_width * tile_size; 949 } else { 950 box.y1 = box.y1 & ~1; 951 box.y2 = ALIGN(box.y2, 2); 952 953 box.x1 = box.x1 & ~1; 954 box.x2 = ALIGN(box.x2, 2); 955 956 offset = box.x1 * draw->bitsPerPixel / 8; 957 } 958 959 if (box.x2 > draw->width) 960 box.x2 = draw->width; 961 if (box.y2 > draw->height) 962 box.y2 = draw->height; 963 964 w = box.x2 - box.x1; 965 h = box.y2 - box.y1; 966 DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 967 box.x1, box.y1, box.x2, box.y2, w, h, 968 draw->width, draw->height)); 969 if (w <= 0 || h <= 0 || 970 w > sna->render.max_3d_size || 971 h > sna->render.max_3d_size) { 972 DBG(("%s: box too large (%dx%d) for 3D pipeline (max %d)\n", 973 __FUNCTION__, w, h, sna->render.max_3d_size)); 974 return false; 975 } 976 977 /* How many tiles across are we? */ 978 channel->bo = kgem_create_proxy(&sna->kgem, bo, 979 box.y1 * bo->pitch + offset, 980 h * bo->pitch); 981 if (channel->bo == NULL) { 982 DBG(("%s: failed to create proxy for partial (offset=%d, size=%d)\n", 983 __FUNCTION__, box.y1 * bo->pitch + offset, h * bo->pitch)); 984 return false; 985 } 986 987 channel->bo->pitch = bo->pitch; 988 989 channel->offset[0] = -box.x1; 990 channel->offset[1] = -box.y1; 991 channel->scale[0] = 1.f/w; 992 channel->scale[1] = 1.f/h; 993 channel->width = w; 994 channel->height = h; 995 return true; 996} 997 998static bool 999sna_render_picture_partial(struct sna *sna, 1000 PicturePtr picture, 1001 struct sna_composite_channel *channel, 1002 int16_t x, int16_t y, 1003 int16_t w, int16_t h, 1004 int16_t dst_x, int16_t dst_y) 1005{ 1006 struct kgem_bo *bo = NULL; 1007 PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 1008 BoxRec box; 1009 int offset; 1010 1011 DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n", 1012 __FUNCTION__, x, y, w, h, dst_x, dst_y)); 1013 1014 box.x1 = x; 1015 box.y1 = y; 1016 box.x2 = bound(x, w); 1017 box.y2 = bound(y, h); 1018 if (channel->transform) 1019 pixman_transform_bounds(channel->transform, &box); 1020 1021 DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__, 1022 box.x1, box.y1, box.x2, box.y2, w, h, 1023 pixmap->drawable.width, pixmap->drawable.height, 1024 channel->repeat)); 1025 1026 if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 1027 if (box.x1 < 0) 1028 box.x1 = 0; 1029 if (box.y1 < 0) 1030 box.y1 = 0; 1031 if (box.x2 > pixmap->drawable.width) 1032 box.x2 = pixmap->drawable.width; 1033 if (box.y2 > pixmap->drawable.height) 1034 box.y2 = pixmap->drawable.height; 1035 } else { 1036 if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 1037 box.x1 = 0, box.x2 = pixmap->drawable.width; 1038 if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 1039 box.y1 = 0, box.y2 = pixmap->drawable.height; 1040 } 1041 1042 if (use_cpu_bo(sna, pixmap, &box, false)) { 1043 bo = sna_pixmap(pixmap)->cpu_bo; 1044 } else { 1045 struct sna_pixmap *priv; 1046 1047 priv = sna_pixmap_force_to_gpu(pixmap, 1048 MOVE_READ | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT); 1049 if (priv == NULL) 1050 return false; 1051 1052 bo = priv->gpu_bo; 1053 } 1054 1055 if (bo->pitch > sna->render.max_3d_pitch) { 1056 DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch)); 1057 return false; 1058 } 1059 1060 if (bo->tiling) { 1061 int tile_width, tile_height, tile_size; 1062 1063 kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch, 1064 &tile_width, &tile_height, &tile_size); 1065 1066 DBG(("%s: tiling=%d, size=%dx%d, chunk=%d\n", 1067 __FUNCTION__, bo->tiling, 1068 tile_width, tile_height, tile_size)); 1069 1070 /* Ensure we align to an even tile row */ 1071 box.y1 = box.y1 & ~(2*tile_height - 1); 1072 box.y2 = ALIGN(box.y2, 2*tile_height); 1073 if (box.y2 > pixmap->drawable.height) 1074 box.y2 = pixmap->drawable.height; 1075 1076 box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1); 1077 box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel); 1078 if (box.x2 > pixmap->drawable.width) 1079 box.x2 = pixmap->drawable.width; 1080 1081 offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size; 1082 } else 1083 offset = box.x1 * pixmap->drawable.bitsPerPixel / 8; 1084 1085 w = box.x2 - box.x1; 1086 h = box.y2 - box.y1; 1087 DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 1088 box.x1, box.y1, box.x2, box.y2, w, h, 1089 pixmap->drawable.width, pixmap->drawable.height)); 1090 if (w <= 0 || h <= 0 || 1091 w > sna->render.max_3d_size || 1092 h > sna->render.max_3d_size) 1093 return false; 1094 1095 /* How many tiles across are we? */ 1096 channel->bo = kgem_create_proxy(&sna->kgem, bo, 1097 box.y1 * bo->pitch + offset, 1098 h * bo->pitch); 1099 if (channel->bo == NULL) 1100 return false; 1101 1102 if (channel->transform) { 1103 memset(&channel->embedded_transform, 1104 0, 1105 sizeof(channel->embedded_transform)); 1106 channel->embedded_transform.matrix[0][0] = 1 << 16; 1107 channel->embedded_transform.matrix[0][2] = -box.x1 << 16; 1108 channel->embedded_transform.matrix[1][1] = 1 << 16; 1109 channel->embedded_transform.matrix[1][2] = -box.y1 << 16; 1110 channel->embedded_transform.matrix[2][2] = 1 << 16; 1111 pixman_transform_multiply(&channel->embedded_transform, 1112 &channel->embedded_transform, 1113 channel->transform); 1114 channel->transform = &channel->embedded_transform; 1115 } else { 1116 x -= box.x1; 1117 y -= box.y1; 1118 } 1119 1120 channel->offset[0] = x - dst_x; 1121 channel->offset[1] = y - dst_y; 1122 channel->scale[0] = 1.f/w; 1123 channel->scale[1] = 1.f/h; 1124 channel->width = w; 1125 channel->height = h; 1126 return true; 1127} 1128 1129int 1130sna_render_picture_extract(struct sna *sna, 1131 PicturePtr picture, 1132 struct sna_composite_channel *channel, 1133 int16_t x, int16_t y, 1134 int16_t w, int16_t h, 1135 int16_t dst_x, int16_t dst_y) 1136{ 1137 struct kgem_bo *bo = NULL, *src_bo; 1138 PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 1139 int16_t ox, oy, ow, oh; 1140 BoxRec box; 1141 1142#if NO_EXTRACT 1143 return -1; 1144#endif 1145 1146 DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n", 1147 __FUNCTION__, x, y, w, h, dst_x, dst_y)); 1148 1149 if (w == 0 || h == 0) { 1150 DBG(("%s: fallback -- unknown bounds\n", __FUNCTION__)); 1151 return -1; 1152 } 1153 1154 if (sna_render_picture_partial(sna, picture, channel, 1155 x, y, w, h, 1156 dst_x, dst_y)) 1157 return 1; 1158 1159 ow = w; 1160 oh = h; 1161 1162 ox = box.x1 = x; 1163 oy = box.y1 = y; 1164 box.x2 = bound(x, w); 1165 box.y2 = bound(y, h); 1166 if (channel->transform) { 1167 pixman_vector_t v; 1168 1169 pixman_transform_bounds(channel->transform, &box); 1170 1171 v.vector[0] = ox << 16; 1172 v.vector[1] = oy << 16; 1173 v.vector[2] = 1 << 16; 1174 pixman_transform_point(channel->transform, &v); 1175 ox = v.vector[0] / v.vector[2]; 1176 oy = v.vector[1] / v.vector[2]; 1177 } 1178 1179 DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__, 1180 box.x1, box.y1, box.x2, box.y2, w, h, 1181 pixmap->drawable.width, pixmap->drawable.height, 1182 channel->repeat)); 1183 1184 if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 1185 if (box.x1 < 0) 1186 box.x1 = 0; 1187 if (box.y1 < 0) 1188 box.y1 = 0; 1189 if (box.x2 > pixmap->drawable.width) 1190 box.x2 = pixmap->drawable.width; 1191 if (box.y2 > pixmap->drawable.height) 1192 box.y2 = pixmap->drawable.height; 1193 } else { 1194 /* XXX tiled repeats? */ 1195 if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 1196 box.x1 = 0, box.x2 = pixmap->drawable.width; 1197 if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 1198 box.y1 = 0, box.y2 = pixmap->drawable.height; 1199 } 1200 1201 w = box.x2 - box.x1; 1202 h = box.y2 - box.y1; 1203 DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 1204 box.x1, box.y1, box.x2, box.y2, w, h, 1205 pixmap->drawable.width, pixmap->drawable.height)); 1206 if (w <= 0 || h <= 0) { 1207 DBG(("%s: sample extents outside of texture -> clear\n", 1208 __FUNCTION__)); 1209 return 0; 1210 } 1211 1212 if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) { 1213 DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n", 1214 __FUNCTION__, box.x1, box.y1, w, h)); 1215 return sna_render_picture_downsample(sna, picture, channel, 1216 x, y, ow, oh, 1217 dst_x, dst_y); 1218 } 1219 1220 src_bo = use_cpu_bo(sna, pixmap, &box, true); 1221 if (src_bo == NULL) 1222 src_bo = move_to_gpu(pixmap, &box, false); 1223 if (src_bo) { 1224 bo = kgem_create_2d(&sna->kgem, w, h, 1225 pixmap->drawable.bitsPerPixel, 1226 kgem_choose_tiling(&sna->kgem, 1227 I915_TILING_X, w, h, 1228 pixmap->drawable.bitsPerPixel), 1229 CREATE_TEMPORARY); 1230 if (bo) { 1231 DrawableRec tmp; 1232 1233 tmp.width = w; 1234 tmp.height = h; 1235 tmp.depth = pixmap->drawable.depth; 1236 tmp.bitsPerPixel = pixmap->drawable.bitsPerPixel; 1237 1238 assert(tmp.width); 1239 assert(tmp.height); 1240 1241 if (!sna->render.copy_boxes(sna, GXcopy, 1242 &pixmap->drawable, src_bo, 0, 0, 1243 &tmp, bo, -box.x1, -box.y1, 1244 &box, 1, 0)) { 1245 kgem_bo_destroy(&sna->kgem, bo); 1246 bo = NULL; 1247 } 1248 } 1249 } else { 1250 struct sna_pixmap *priv = sna_pixmap(pixmap); 1251 if (priv) { 1252 RegionRec region; 1253 1254 region.extents = box; 1255 region.data = NULL; 1256 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 1257 ®ion, MOVE_READ)) 1258 return 0; 1259 1260 assert(!priv->mapped); 1261 if (pixmap->devPrivate.ptr == NULL) 1262 return 0; /* uninitialised */ 1263 } 1264 1265 bo = kgem_upload_source_image(&sna->kgem, 1266 pixmap->devPrivate.ptr, 1267 &box, 1268 pixmap->devKind, 1269 pixmap->drawable.bitsPerPixel); 1270 if (priv != NULL && bo != NULL && 1271 box.x2 - box.x1 == pixmap->drawable.width && 1272 box.y2 - box.y1 == pixmap->drawable.height) { 1273 DBG(("%s: adding upload cache to pixmap=%ld\n", 1274 __FUNCTION__, pixmap->drawable.serialNumber)); 1275 assert(priv->gpu_damage == NULL); 1276 assert(priv->gpu_bo == NULL); 1277 assert(bo->proxy != NULL); 1278 kgem_proxy_bo_attach(bo, &priv->gpu_bo); 1279 } 1280 } 1281 1282 if (bo == NULL) { 1283 DBG(("%s: falback -- pixmap is not on the GPU\n", 1284 __FUNCTION__)); 1285 return sna_render_picture_fixup(sna, picture, channel, 1286 x, y, ow, oh, dst_x, dst_y); 1287 } 1288 1289 if (ox == x && oy == y) { 1290 x = y = 0; 1291 } else if (channel->transform) { 1292 pixman_vector_t v; 1293 pixman_transform_t m; 1294 1295 v.vector[0] = (ox - box.x1) << 16; 1296 v.vector[1] = (oy - box.y1) << 16; 1297 v.vector[2] = 1 << 16; 1298 pixman_transform_invert(&m, channel->transform); 1299 pixman_transform_point(&m, &v); 1300 x = v.vector[0] / v.vector[2]; 1301 y = v.vector[1] / v.vector[2]; 1302 } else { 1303 x = ox - box.x1; 1304 y = oy - box.y1; 1305 } 1306 1307 channel->offset[0] = x - dst_x; 1308 channel->offset[1] = y - dst_y; 1309 channel->scale[0] = 1.f/w; 1310 channel->scale[1] = 1.f/h; 1311 channel->width = w; 1312 channel->height = h; 1313 channel->bo = bo; 1314 return 1; 1315} 1316 1317static int 1318sna_render_picture_convolve(struct sna *sna, 1319 PicturePtr picture, 1320 struct sna_composite_channel *channel, 1321 int16_t x, int16_t y, 1322 int16_t w, int16_t h, 1323 int16_t dst_x, int16_t dst_y) 1324{ 1325 ScreenPtr screen = picture->pDrawable->pScreen; 1326 PixmapPtr pixmap; 1327 PicturePtr tmp; 1328 pixman_fixed_t *params = picture->filter_params; 1329 int x_off = -pixman_fixed_to_int((params[0] - pixman_fixed_1) >> 1); 1330 int y_off = -pixman_fixed_to_int((params[1] - pixman_fixed_1) >> 1); 1331 int cw = pixman_fixed_to_int(params[0]); 1332 int ch = pixman_fixed_to_int(params[1]); 1333 int i, j, error, depth; 1334 struct kgem_bo *bo; 1335 1336 /* Lame multi-pass accumulation implementation of a general convolution 1337 * that works everywhere. 1338 */ 1339 DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n", 1340 __FUNCTION__, x_off, y_off, cw, ch, w, h)); 1341 1342 assert(picture->pDrawable); 1343 assert(picture->filter == PictFilterConvolution); 1344 assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size); 1345 1346 if (PICT_FORMAT_RGB(picture->format) == 0) { 1347 channel->pict_format = PIXMAN_a8; 1348 depth = 8; 1349 } else { 1350 channel->pict_format = PIXMAN_a8r8g8b8; 1351 depth = 32; 1352 } 1353 1354 pixmap = screen->CreatePixmap(screen, w, h, depth, SNA_CREATE_SCRATCH); 1355 if (pixmap == NullPixmap) { 1356 DBG(("%s: pixmap allocation failed\n", __FUNCTION__)); 1357 return -1; 1358 } 1359 1360 tmp = NULL; 1361 bo = __sna_pixmap_get_bo(pixmap); 1362 assert(bo); 1363 if (sna->render.clear(sna, pixmap, bo)) 1364 tmp = CreatePicture(0, &pixmap->drawable, 1365 PictureMatchFormat(screen, depth, channel->pict_format), 1366 0, NULL, serverClient, &error); 1367 screen->DestroyPixmap(pixmap); 1368 if (tmp == NULL) 1369 return -1; 1370 1371 ValidatePicture(tmp); 1372 1373 picture->filter = PictFilterBilinear; 1374 params += 2; 1375 for (j = 0; j < ch; j++) { 1376 for (i = 0; i < cw; i++) { 1377 xRenderColor color; 1378 PicturePtr alpha; 1379 1380 color.alpha = *params++; 1381 color.red = color.green = color.blue = 0; 1382 DBG(("%s: (%d, %d), alpha=%x\n", 1383 __FUNCTION__, i,j, color.alpha)); 1384 1385 if (color.alpha <= 0x00ff) 1386 continue; 1387 1388 alpha = CreateSolidPicture(0, &color, &error); 1389 if (alpha) { 1390 sna_composite(PictOpAdd, picture, alpha, tmp, 1391 x, y, 1392 0, 0, 1393 x_off+i, y_off+j, 1394 w, h); 1395 FreePicture(alpha, 0); 1396 } 1397 } 1398 } 1399 picture->filter = PictFilterConvolution; 1400 1401 channel->height = h; 1402 channel->width = w; 1403 channel->filter = PictFilterNearest; 1404 channel->repeat = RepeatNone; 1405 channel->is_affine = true; 1406 channel->transform = NULL; 1407 channel->scale[0] = 1.f / w; 1408 channel->scale[1] = 1.f / h; 1409 channel->offset[0] = -dst_x; 1410 channel->offset[1] = -dst_y; 1411 channel->bo = kgem_bo_reference(bo); /* transfer ownership */ 1412 FreePicture(tmp, 0); 1413 1414 return 1; 1415} 1416 1417static bool 1418sna_render_picture_flatten(struct sna *sna, 1419 PicturePtr picture, 1420 struct sna_composite_channel *channel, 1421 int16_t x, int16_t y, 1422 int16_t w, int16_t h, 1423 int16_t dst_x, int16_t dst_y) 1424{ 1425 ScreenPtr screen = picture->pDrawable->pScreen; 1426 PixmapPtr pixmap; 1427 PicturePtr tmp, alpha; 1428 int old_format, error; 1429 1430 assert(picture->pDrawable); 1431 assert(picture->alphaMap); 1432 assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size); 1433 1434 /* XXX shortcut a8? */ 1435 DBG(("%s: %dx%d\n", __FUNCTION__, w, h)); 1436 1437 pixmap = screen->CreatePixmap(screen, w, h, 32, SNA_CREATE_SCRATCH); 1438 if (pixmap == NullPixmap) { 1439 DBG(("%s: pixmap allocation failed\n", __FUNCTION__)); 1440 return false; 1441 } 1442 1443 assert(__sna_pixmap_get_bo(pixmap)); 1444 1445 tmp = CreatePicture(0, &pixmap->drawable, 1446 PictureMatchFormat(screen, 32, PICT_a8r8g8b8), 1447 0, NULL, serverClient, &error); 1448 screen->DestroyPixmap(pixmap); 1449 if (tmp == NULL) 1450 return false; 1451 1452 ValidatePicture(tmp); 1453 1454 old_format = picture->format; 1455 picture->format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format), 1456 PICT_FORMAT_TYPE(picture->format), 1457 0, 1458 PICT_FORMAT_R(picture->format), 1459 PICT_FORMAT_G(picture->format), 1460 PICT_FORMAT_B(picture->format)); 1461 1462 alpha = picture->alphaMap; 1463 picture->alphaMap = NULL; 1464 1465 sna_composite(PictOpSrc, picture, alpha, tmp, 1466 x, y, 1467 x + picture->alphaOrigin.x, y + picture->alphaOrigin.y, 1468 0, 0, 1469 w, h); 1470 1471 picture->format = old_format; 1472 picture->alphaMap = alpha; 1473 1474 channel->height = h; 1475 channel->width = w; 1476 channel->filter = PictFilterNearest; 1477 channel->repeat = RepeatNone; 1478 channel->pict_format = PIXMAN_a8r8g8b8; 1479 channel->is_affine = true; 1480 channel->transform = NULL; 1481 channel->scale[0] = 1.f / w; 1482 channel->scale[1] = 1.f / h; 1483 channel->offset[0] = -dst_x; 1484 channel->offset[1] = -dst_y; 1485 channel->bo = kgem_bo_reference(__sna_pixmap_get_bo(pixmap)); 1486 FreePicture(tmp, 0); 1487 1488 return true; 1489} 1490 1491int 1492sna_render_picture_approximate_gradient(struct sna *sna, 1493 PicturePtr picture, 1494 struct sna_composite_channel *channel, 1495 int16_t x, int16_t y, 1496 int16_t w, int16_t h, 1497 int16_t dst_x, int16_t dst_y) 1498{ 1499 pixman_image_t *dst, *src; 1500 pixman_transform_t t; 1501 int w2 = w/2, h2 = h/2; 1502 int dx, dy; 1503 void *ptr; 1504 1505#if NO_FIXUP 1506 return -1; 1507#endif 1508 1509 DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n", 1510 __FUNCTION__, x, y, w, h, dst_x, dst_y)); 1511 1512 if (w2 == 0 || h2 == 0) { 1513 DBG(("%s: fallback - unknown bounds\n", __FUNCTION__)); 1514 return -1; 1515 } 1516 if (w2 > sna->render.max_3d_size || h2 > sna->render.max_3d_size) { 1517 DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h)); 1518 return -1; 1519 } 1520 1521 channel->is_opaque = sna_gradient_is_opaque((PictGradient*)picture->pSourcePict); 1522 channel->pict_format = 1523 channel->is_opaque ? PIXMAN_x8r8g8b8 : PIXMAN_a8r8g8b8; 1524 DBG(("%s: gradient is opaque? %d, selecting format %08x\n", 1525 __FUNCTION__, channel->is_opaque, channel->pict_format)); 1526 assert(channel->card_format == -1); 1527 1528 channel->bo = kgem_create_buffer_2d(&sna->kgem, 1529 w2, h2, 32, 1530 KGEM_BUFFER_WRITE_INPLACE, 1531 &ptr); 1532 if (!channel->bo) { 1533 DBG(("%s: failed to create upload buffer, using clear\n", 1534 __FUNCTION__)); 1535 return 0; 1536 } 1537 1538 dst = pixman_image_create_bits(channel->pict_format, 1539 w2, h2, ptr, channel->bo->pitch); 1540 if (!dst) { 1541 kgem_bo_destroy(&sna->kgem, channel->bo); 1542 channel->bo = NULL; 1543 return 0; 1544 } 1545 1546 src = image_from_pict(picture, false, &dx, &dy); 1547 if (src == NULL) { 1548 pixman_image_unref(dst); 1549 kgem_bo_destroy(&sna->kgem, channel->bo); 1550 channel->bo = NULL; 1551 return 0; 1552 } 1553 DBG(("%s: source offset (%d, %d)\n", __FUNCTION__, dx, dy)); 1554 1555 memset(&t, 0, sizeof(t)); 1556 t.matrix[0][0] = (w << 16) / w2; 1557 t.matrix[0][2] = (x + dx) << 16; 1558 t.matrix[1][1] = (h << 16) / h2; 1559 t.matrix[1][2] = (y + dy) << 16; 1560 t.matrix[2][2] = 1 << 16; 1561 if (picture->transform) 1562 pixman_transform_multiply(&t, picture->transform, &t); 1563 DBG(("%s: applying transform [(%f, %f, %f), (%f, %f, %f), (%f, %f, %f)]\n", 1564 __FUNCTION__, 1565 pixman_fixed_to_double(t.matrix[0][0]), 1566 pixman_fixed_to_double(t.matrix[0][1]), 1567 pixman_fixed_to_double(t.matrix[0][2]), 1568 pixman_fixed_to_double(t.matrix[1][0]), 1569 pixman_fixed_to_double(t.matrix[1][1]), 1570 pixman_fixed_to_double(t.matrix[1][2]), 1571 pixman_fixed_to_double(t.matrix[2][0]), 1572 pixman_fixed_to_double(t.matrix[2][1]), 1573 pixman_fixed_to_double(t.matrix[2][2]))); 1574 pixman_image_set_transform(src, &t); 1575 1576 sna_image_composite(PictOpSrc, src, NULL, dst, 1577 0, 0, 1578 0, 0, 1579 0, 0, 1580 w2, h2); 1581 free_pixman_pict(picture, src); 1582 pixman_image_unref(dst); 1583 1584 channel->width = w2; 1585 channel->height = h2; 1586 1587 channel->filter = PictFilterNearest; 1588 channel->repeat = RepeatNone; 1589 channel->is_affine = true; 1590 1591 channel->scale[0] = 1.f/w; 1592 channel->scale[1] = 1.f/h; 1593 channel->offset[0] = -dst_x; 1594 channel->offset[1] = -dst_y; 1595 channel->transform = NULL; 1596 1597 return 1; 1598} 1599 1600int 1601sna_render_picture_fixup(struct sna *sna, 1602 PicturePtr picture, 1603 struct sna_composite_channel *channel, 1604 int16_t x, int16_t y, 1605 int16_t w, int16_t h, 1606 int16_t dst_x, int16_t dst_y) 1607{ 1608 pixman_image_t *dst, *src; 1609 int dx, dy; 1610 void *ptr; 1611 1612#if NO_FIXUP 1613 return -1; 1614#endif 1615 1616 DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); 1617 1618 if (w == 0 || h == 0) { 1619 DBG(("%s: fallback - unknown bounds\n", __FUNCTION__)); 1620 return -1; 1621 } 1622 if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) { 1623 DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h)); 1624 return -1; 1625 } 1626 1627 if (picture->alphaMap) { 1628 DBG(("%s: alphamap\n", __FUNCTION__)); 1629 if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER) || 1630 is_gpu(sna, picture->alphaMap->pDrawable, PREFER_GPU_RENDER)) { 1631 if (sna_render_picture_flatten(sna, picture, channel, 1632 x, y, w, h, dst_x, dst_y)) 1633 return 1; 1634 } 1635 1636 goto do_fixup; 1637 } 1638 1639 if (picture->filter == PictFilterConvolution) { 1640 DBG(("%s: convolution\n", __FUNCTION__)); 1641 if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) { 1642 return sna_render_picture_convolve(sna, picture, channel, 1643 x, y, w, h, dst_x, dst_y); 1644 } 1645 1646 goto do_fixup; 1647 } 1648 1649do_fixup: 1650 if (PICT_FORMAT_RGB(picture->format) == 0) 1651 channel->pict_format = PIXMAN_a8; 1652 else 1653 channel->pict_format = PIXMAN_a8r8g8b8; 1654 1655 if (picture->pDrawable && 1656 !sna_drawable_move_to_cpu(picture->pDrawable, MOVE_READ)) 1657 return 0; 1658 1659 channel->bo = kgem_create_buffer_2d(&sna->kgem, 1660 w, h, PIXMAN_FORMAT_BPP(channel->pict_format), 1661 KGEM_BUFFER_WRITE_INPLACE, 1662 &ptr); 1663 if (!channel->bo) { 1664 DBG(("%s: failed to create upload buffer, using clear\n", 1665 __FUNCTION__)); 1666 return 0; 1667 } 1668 1669 /* Composite in the original format to preserve idiosyncracies */ 1670 if (!kgem_buffer_is_inplace(channel->bo) && 1671 (picture->pDrawable == NULL || 1672 alphaless(picture->format) == alphaless(channel->pict_format))) 1673 dst = pixman_image_create_bits(channel->pict_format, 1674 w, h, ptr, channel->bo->pitch); 1675 else 1676 dst = pixman_image_create_bits((pixman_format_code_t)picture->format, 1677 w, h, NULL, 0); 1678 if (!dst) { 1679 kgem_bo_destroy(&sna->kgem, channel->bo); 1680 return 0; 1681 } 1682 1683 src = image_from_pict(picture, false, &dx, &dy); 1684 if (src == NULL) { 1685 pixman_image_unref(dst); 1686 kgem_bo_destroy(&sna->kgem, channel->bo); 1687 return 0; 1688 } 1689 1690 DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n", 1691 __FUNCTION__, x, dx, y, dy, w, h)); 1692 sna_image_composite(PictOpSrc, src, NULL, dst, 1693 x + dx, y + dy, 1694 0, 0, 1695 0, 0, 1696 w, h); 1697 free_pixman_pict(picture, src); 1698 1699 /* Then convert to card format */ 1700 if (pixman_image_get_data(dst) != ptr) { 1701 DBG(("%s: performing post-conversion %08x->%08x (%d, %d)\n", 1702 __FUNCTION__, 1703 picture->format, channel->pict_format, 1704 w, h)); 1705 1706 src = dst; 1707 dst = pixman_image_create_bits(channel->pict_format, 1708 w, h, ptr, channel->bo->pitch); 1709 if (dst) { 1710 sna_image_composite(PictOpSrc, src, NULL, dst, 1711 0, 0, 1712 0, 0, 1713 0, 0, 1714 w, h); 1715 pixman_image_unref(src); 1716 } else { 1717 memset(ptr, 0, __kgem_buffer_size(channel->bo)); 1718 dst = src; 1719 } 1720 } 1721 pixman_image_unref(dst); 1722 1723 channel->width = w; 1724 channel->height = h; 1725 1726 channel->filter = PictFilterNearest; 1727 channel->repeat = RepeatNone; 1728 channel->is_affine = true; 1729 1730 channel->scale[0] = 1.f/w; 1731 channel->scale[1] = 1.f/h; 1732 channel->offset[0] = -dst_x; 1733 channel->offset[1] = -dst_y; 1734 channel->transform = NULL; 1735 1736 return 1; 1737} 1738 1739int 1740sna_render_picture_convert(struct sna *sna, 1741 PicturePtr picture, 1742 struct sna_composite_channel *channel, 1743 PixmapPtr pixmap, 1744 int16_t x, int16_t y, 1745 int16_t w, int16_t h, 1746 int16_t dst_x, int16_t dst_y, 1747 bool fixup_alpha) 1748{ 1749 BoxRec box; 1750 1751#if NO_CONVERT 1752 return -1; 1753#endif 1754 1755 if (w != 0 && h != 0) { 1756 box.x1 = x; 1757 box.y1 = y; 1758 box.x2 = bound(x, w); 1759 box.y2 = bound(y, h); 1760 1761 if (channel->transform) { 1762 DBG(("%s: has transform, converting whole surface\n", 1763 __FUNCTION__)); 1764 box.x1 = box.y1 = 0; 1765 box.x2 = pixmap->drawable.width; 1766 box.y2 = pixmap->drawable.height; 1767 } 1768 1769 if (box.x1 < 0) 1770 box.x1 = 0; 1771 if (box.y1 < 0) 1772 box.y1 = 0; 1773 if (box.x2 > pixmap->drawable.width) 1774 box.x2 = pixmap->drawable.width; 1775 if (box.y2 > pixmap->drawable.height) 1776 box.y2 = pixmap->drawable.height; 1777 } else { 1778 DBG(("%s: op no bounds, converting whole surface\n", 1779 __FUNCTION__)); 1780 box.x1 = box.y1 = 0; 1781 box.x2 = pixmap->drawable.width; 1782 box.y2 = pixmap->drawable.height; 1783 } 1784 1785 w = box.x2 - box.x1; 1786 h = box.y2 - box.y1; 1787 1788 DBG(("%s: convert (%d, %d)x(%d, %d), source size %dx%d\n", 1789 __FUNCTION__, box.x1, box.y1, w, h, 1790 pixmap->drawable.width, 1791 pixmap->drawable.height)); 1792 1793 if (w <= 0 || h <= 0) { 1794 DBG(("%s: sample extents lie outside of source, using clear\n", 1795 __FUNCTION__)); 1796 return 0; 1797 } 1798 1799 if (fixup_alpha && is_gpu(sna, &pixmap->drawable, PREFER_GPU_RENDER)) { 1800 ScreenPtr screen = pixmap->drawable.pScreen; 1801 PixmapPtr tmp; 1802 PicturePtr src, dst; 1803 int error; 1804 1805 assert(PICT_FORMAT_BPP(picture->format) == pixmap->drawable.bitsPerPixel); 1806 channel->pict_format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format), 1807 PICT_FORMAT_TYPE(picture->format), 1808 PICT_FORMAT_BPP(picture->format) - PIXMAN_FORMAT_DEPTH(picture->format), 1809 PICT_FORMAT_R(picture->format), 1810 PICT_FORMAT_G(picture->format), 1811 PICT_FORMAT_B(picture->format)); 1812 1813 DBG(("%s: converting to %08x from %08x using composite alpha-fixup\n", 1814 __FUNCTION__, 1815 (unsigned)channel->pict_format, 1816 (unsigned)picture->format)); 1817 1818 tmp = screen->CreatePixmap(screen, w, h, pixmap->drawable.bitsPerPixel, SNA_CREATE_SCRATCH); 1819 if (tmp == NULL) 1820 return -1; 1821 1822 assert(__sna_pixmap_get_bo(tmp)); 1823 1824 dst = CreatePicture(0, &tmp->drawable, 1825 PictureMatchFormat(screen, 1826 pixmap->drawable.bitsPerPixel, 1827 channel->pict_format), 1828 0, NULL, serverClient, &error); 1829 if (dst == NULL) { 1830 screen->DestroyPixmap(tmp); 1831 return 0; 1832 } 1833 1834 src = CreatePicture(0, &pixmap->drawable, 1835 PictureMatchFormat(screen, 1836 pixmap->drawable.depth, 1837 picture->format), 1838 0, NULL, serverClient, &error); 1839 if (src == NULL) { 1840 FreePicture(dst, 0); 1841 screen->DestroyPixmap(tmp); 1842 return 0; 1843 } 1844 1845 ValidatePicture(src); 1846 ValidatePicture(dst); 1847 1848 sna_composite(PictOpSrc, src, NULL, dst, 1849 box.x1, box.y1, 1850 0, 0, 1851 0, 0, 1852 w, h); 1853 FreePicture(dst, 0); 1854 FreePicture(src, 0); 1855 1856 channel->bo = __sna_pixmap_get_bo(tmp); 1857 kgem_bo_reference(channel->bo); 1858 screen->DestroyPixmap(tmp); 1859 } else { 1860 pixman_image_t *src, *dst; 1861 void *ptr; 1862 1863 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 1864 return 0; 1865 1866 src = pixman_image_create_bits((pixman_format_code_t)picture->format, 1867 pixmap->drawable.width, 1868 pixmap->drawable.height, 1869 pixmap->devPrivate.ptr, 1870 pixmap->devKind); 1871 if (!src) 1872 return 0; 1873 1874 if (PICT_FORMAT_RGB(picture->format) == 0) { 1875 channel->pict_format = PIXMAN_a8; 1876 DBG(("%s: converting to a8 from %08x\n", 1877 __FUNCTION__, picture->format)); 1878 } else { 1879 channel->pict_format = PIXMAN_a8r8g8b8; 1880 DBG(("%s: converting to a8r8g8b8 from %08x\n", 1881 __FUNCTION__, picture->format)); 1882 } 1883 1884 channel->bo = kgem_create_buffer_2d(&sna->kgem, 1885 w, h, PIXMAN_FORMAT_BPP(channel->pict_format), 1886 KGEM_BUFFER_WRITE_INPLACE, 1887 &ptr); 1888 if (!channel->bo) { 1889 pixman_image_unref(src); 1890 return 0; 1891 } 1892 1893 dst = pixman_image_create_bits(channel->pict_format, 1894 w, h, ptr, channel->bo->pitch); 1895 if (!dst) { 1896 kgem_bo_destroy(&sna->kgem, channel->bo); 1897 pixman_image_unref(src); 1898 return 0; 1899 } 1900 1901 if (sigtrap_get() == 0) { 1902 sna_image_composite(PictOpSrc, src, NULL, dst, 1903 box.x1, box.y1, 1904 0, 0, 1905 0, 0, 1906 w, h); 1907 sigtrap_put(); 1908 } 1909 pixman_image_unref(dst); 1910 pixman_image_unref(src); 1911 } 1912 1913 channel->width = w; 1914 channel->height = h; 1915 1916 channel->scale[0] = 1.f/w; 1917 channel->scale[1] = 1.f/h; 1918 channel->offset[0] = x - dst_x - box.x1; 1919 channel->offset[1] = y - dst_y - box.y1; 1920 1921 DBG(("%s: offset=(%d, %d), size=(%d, %d)\n", 1922 __FUNCTION__, 1923 channel->offset[0], channel->offset[1], 1924 channel->width, channel->height)); 1925 return 1; 1926} 1927 1928bool 1929sna_render_composite_redirect(struct sna *sna, 1930 struct sna_composite_op *op, 1931 int x, int y, int width, int height, 1932 bool partial) 1933{ 1934 struct sna_composite_redirect *t = &op->redirect; 1935 int bpp = op->dst.pixmap->drawable.bitsPerPixel; 1936 struct kgem_bo *bo; 1937 1938 assert(t->real_bo == NULL); 1939 1940#if NO_REDIRECT 1941 return false; 1942#endif 1943 1944 DBG(("%s: target too large (%dx%d), copying to temporary %dx%d, max %d / %d\n", 1945 __FUNCTION__, 1946 op->dst.width, op->dst.height, 1947 width, height, 1948 sna->render.max_3d_size, 1949 sna->render.max_3d_pitch)); 1950 1951 if (!width || !height) 1952 return false; 1953 1954 if (width > sna->render.max_3d_size || 1955 height > sna->render.max_3d_size) 1956 return false; 1957 1958 if (op->dst.bo->pitch <= sna->render.max_3d_pitch) { 1959 BoxRec box; 1960 int w, h, offset; 1961 1962 DBG(("%s: dst pitch (%d) fits within render pipeline (%d)\n", 1963 __FUNCTION__, op->dst.bo->pitch, sna->render.max_3d_pitch)); 1964 1965 box.x1 = x + op->dst.x; 1966 box.x2 = bound(box.x1, width); 1967 box.y1 = y + op->dst.y; 1968 box.y2 = bound(box.y1, height); 1969 1970 if (box.x1 < 0) 1971 box.x1 = 0; 1972 if (box.y1 < 0) 1973 box.y1 = 0; 1974 1975 /* Ensure we align to an even tile row */ 1976 if (op->dst.bo->tiling) { 1977 int tile_width, tile_height, tile_size; 1978 1979 kgem_get_tile_size(&sna->kgem, op->dst.bo->tiling, op->dst.bo->pitch, 1980 &tile_width, &tile_height, &tile_size); 1981 1982 box.y1 = box.y1 & ~(2*tile_height - 1); 1983 box.y2 = ALIGN(box.y2, 2*tile_height); 1984 1985 box.x1 = box.x1 & ~(tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel - 1); 1986 box.x2 = ALIGN(box.x2, tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel); 1987 1988 if (box.x1 > sna->render.max_3d_size && 1989 box.x2 <= 2*sna->render.max_3d_size) 1990 box.x1 = sna->render.max_3d_size; 1991 1992 if (box.y1 > sna->render.max_3d_size && 1993 box.y2 <= 2*sna->render.max_3d_size) 1994 box.y1 = sna->render.max_3d_size; 1995 1996 offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size; 1997 } else { 1998 if (sna->kgem.gen < 040) { 1999 box.y1 = box.y1 & ~3; 2000 box.y2 = ALIGN(box.y2, 4); 2001 2002 box.x1 = box.x1 & ~3; 2003 box.x2 = ALIGN(box.x2, 4); 2004 } else { 2005 box.y1 = box.y1 & ~1; 2006 box.y2 = ALIGN(box.y2, 2); 2007 2008 box.x1 = box.x1 & ~1; 2009 box.x2 = ALIGN(box.x2, 2); 2010 } 2011 2012 if (box.x1 > sna->render.max_3d_size && 2013 box.x2 <= 2*sna->render.max_3d_size) 2014 box.x1 = sna->render.max_3d_size; 2015 2016 if (box.y1 > sna->render.max_3d_size && 2017 box.y2 <= 2*sna->render.max_3d_size) 2018 box.y1 = sna->render.max_3d_size; 2019 2020 offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8; 2021 } 2022 2023 if (box.y2 > op->dst.pixmap->drawable.height) 2024 box.y2 = op->dst.pixmap->drawable.height; 2025 2026 if (box.x2 > op->dst.pixmap->drawable.width) 2027 box.x2 = op->dst.pixmap->drawable.width; 2028 2029 w = box.x2 - box.x1; 2030 h = box.y2 - box.y1; 2031 DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), max %d\n", __FUNCTION__, 2032 box.x1, box.y1, box.x2, box.y2, w, h, 2033 op->dst.pixmap->drawable.width, 2034 op->dst.pixmap->drawable.height, 2035 sna->render.max_3d_size)); 2036 if (w <= sna->render.max_3d_size && 2037 h <= sna->render.max_3d_size) { 2038 t->box.x2 = t->box.x1 = op->dst.x; 2039 t->box.y2 = t->box.y1 = op->dst.y; 2040 t->real_bo = op->dst.bo; 2041 t->real_damage = op->damage; 2042 if (op->damage) { 2043 assert(!DAMAGE_IS_ALL(op->damage)); 2044 t->damage = sna_damage_create(); 2045 op->damage = &t->damage; 2046 } 2047 2048 /* How many tiles across are we? */ 2049 op->dst.bo = kgem_create_proxy(&sna->kgem, op->dst.bo, 2050 box.y1 * op->dst.bo->pitch + offset, 2051 h * op->dst.bo->pitch); 2052 if (!op->dst.bo) { 2053 t->real_bo = NULL; 2054 if (t->damage) 2055 __sna_damage_destroy(t->damage); 2056 return false; 2057 } 2058 2059 assert(op->dst.bo != t->real_bo); 2060 op->dst.bo->pitch = t->real_bo->pitch; 2061 2062 op->dst.x -= box.x1; 2063 op->dst.y -= box.y1; 2064 op->dst.width = w; 2065 op->dst.height = h; 2066 return true; 2067 } 2068 } 2069 2070 /* We can process the operation in a single pass, 2071 * but the target is too large for the 3D pipeline. 2072 * Copy into a smaller surface and replace afterwards. 2073 */ 2074 bo = kgem_create_2d(&sna->kgem, 2075 width, height, bpp, 2076 kgem_choose_tiling(&sna->kgem, I915_TILING_X, 2077 width, height, bpp), 2078 CREATE_TEMPORARY); 2079 if (!bo) 2080 return false; 2081 2082 t->box.x1 = x + op->dst.x; 2083 t->box.y1 = y + op->dst.y; 2084 t->box.x2 = bound(t->box.x1, width); 2085 t->box.y2 = bound(t->box.y1, height); 2086 2087 DBG(("%s: original box (%d, %d), (%d, %d)\n", 2088 __FUNCTION__, t->box.x1, t->box.y1, t->box.x2, t->box.y2)); 2089 2090 if (partial && 2091 !sna_blt_copy_boxes(sna, GXcopy, 2092 op->dst.bo, 0, 0, 2093 bo, -t->box.x1, -t->box.y1, 2094 bpp, &t->box, 1)) { 2095 kgem_bo_destroy(&sna->kgem, bo); 2096 return false; 2097 } 2098 2099 t->real_bo = op->dst.bo; 2100 t->real_damage = op->damage; 2101 if (op->damage) { 2102 assert(!DAMAGE_IS_ALL(op->damage)); 2103 t->damage = sna_damage_create(); 2104 op->damage = &t->damage; 2105 } 2106 2107 op->dst.bo = bo; 2108 op->dst.x = -x; 2109 op->dst.y = -y; 2110 op->dst.width = width; 2111 op->dst.height = height; 2112 return true; 2113} 2114 2115void 2116sna_render_composite_redirect_done(struct sna *sna, 2117 const struct sna_composite_op *op) 2118{ 2119 const struct sna_composite_redirect *t = &op->redirect; 2120 2121 if (t->real_bo) { 2122 assert(op->dst.bo != t->real_bo); 2123 2124 if (t->box.x2 > t->box.x1) { 2125 bool ok; 2126 2127 DBG(("%s: copying temporary to dst\n", __FUNCTION__)); 2128 ok = sna_blt_copy_boxes(sna, GXcopy, 2129 op->dst.bo, -t->box.x1, -t->box.y1, 2130 t->real_bo, 0, 0, 2131 op->dst.pixmap->drawable.bitsPerPixel, 2132 &t->box, 1); 2133 assert(ok); 2134 (void)ok; 2135 } 2136 if (t->damage) { 2137 DBG(("%s: combining damage (all? %d), offset=(%d, %d)\n", 2138 __FUNCTION__, (int)DAMAGE_IS_ALL(t->damage), 2139 t->box.x1, t->box.y1)); 2140 sna_damage_combine(t->real_damage, 2141 DAMAGE_PTR(t->damage), 2142 t->box.x1, t->box.y1); 2143 __sna_damage_destroy(DAMAGE_PTR(t->damage)); 2144 } 2145 2146 kgem_bo_destroy(&sna->kgem, op->dst.bo); 2147 } 2148} 2149 2150static bool 2151copy_overlap(struct sna *sna, uint8_t alu, 2152 const DrawableRec *draw, struct kgem_bo *bo, 2153 int16_t src_dx, int16_t src_dy, 2154 int16_t dst_dx, int16_t dst_dy, 2155 const BoxRec *box, int n, const BoxRec *extents) 2156{ 2157 ScreenPtr screen = draw->pScreen; 2158 struct kgem_bo *tmp_bo; 2159 PixmapPtr tmp; 2160 bool ret = false; 2161 2162 if (n == 0) 2163 return true; 2164 2165 DBG(("%s: %d x %dx%d src=(%d, %d), dst=(%d, %d)\n", 2166 __FUNCTION__, n, 2167 extents->x2 - extents->x1, 2168 extents->y2 - extents->y1, 2169 src_dx, src_dy, 2170 dst_dx, dst_dy)); 2171 2172 tmp = screen->CreatePixmap(screen, 2173 extents->x2 - extents->x1, 2174 extents->y2 - extents->y1, 2175 draw->depth, 2176 SNA_CREATE_SCRATCH); 2177 if (tmp == NULL) 2178 return false; 2179 2180 tmp_bo = __sna_pixmap_get_bo(tmp); 2181 assert(tmp_bo); 2182 2183 ret = (sna->render.copy_boxes(sna, GXcopy, 2184 draw, bo, src_dx, src_dy, 2185 &tmp->drawable, tmp_bo, -extents->x1, -extents->y1, 2186 box, n , 0) && 2187 sna->render.copy_boxes(sna, alu, 2188 &tmp->drawable, tmp_bo, -extents->x1, -extents->y1, 2189 draw, bo, dst_dx, dst_dy, 2190 box, n , 0)); 2191 2192 screen->DestroyPixmap(tmp); 2193 return ret; 2194} 2195bool 2196sna_render_copy_boxes__overlap(struct sna *sna, uint8_t alu, 2197 const DrawableRec *draw, struct kgem_bo *bo, 2198 int16_t src_dx, int16_t src_dy, 2199 int16_t dst_dx, int16_t dst_dy, 2200 const BoxRec *box, int n, const BoxRec *extents) 2201{ 2202 bool ret = false; 2203 RegionRec overlap, non_overlap; 2204 pixman_region16_t region; 2205 pixman_box16_t stack_boxes[64], *boxes = stack_boxes; 2206 int num_boxes, i; 2207 2208 DBG(("%s: pixmap=%ld, handle=%d, %d x [(%d, %d), (%d, %d)], dst=(%d, %d), src=(%d, %d)\n", 2209 __FUNCTION__, draw->serialNumber, bo->handle, 2210 n, extents->x1, extents->y1, extents->x2, extents->y2, 2211 src_dx, src_dy, dst_dx, dst_dy)); 2212 2213 if ((dst_dx - src_dx < 4 && src_dx - dst_dx < 4) && 2214 (dst_dy - src_dy < 4 && src_dy - dst_dy < 4)) 2215 return copy_overlap(sna, alu, draw, bo, 2216 src_dx, src_dy, 2217 dst_dx, dst_dy, 2218 box, n, extents); 2219 2220 if (n > ARRAY_SIZE(stack_boxes)) { 2221 boxes = malloc(sizeof(pixman_box16_t) * n); 2222 if (boxes == NULL) 2223 return copy_overlap(sna, alu, draw, bo, 2224 src_dx, src_dy, 2225 dst_dx, dst_dy, 2226 box, n, extents); 2227 } 2228 2229 region.extents.x1 = extents->x1 + dst_dx; 2230 region.extents.x2 = extents->x2 + dst_dx; 2231 region.extents.y1 = extents->y1 + dst_dy; 2232 region.extents.y2 = extents->y2 + dst_dy; 2233 2234 for (i = num_boxes = 0; i < n; i++) { 2235 boxes[num_boxes].x1 = box[i].x1 + dst_dx; 2236 if (boxes[num_boxes].x1 < region.extents.x1) 2237 boxes[num_boxes].x1 = region.extents.x1; 2238 2239 boxes[num_boxes].y1 = box[i].y1 + dst_dy; 2240 if (boxes[num_boxes].y1 < region.extents.y1) 2241 boxes[num_boxes].y1 = region.extents.y1; 2242 2243 boxes[num_boxes].x2 = box[i].x2 + dst_dx; 2244 if (boxes[num_boxes].x2 > region.extents.x2) 2245 boxes[num_boxes].x2 = region.extents.x2; 2246 2247 boxes[num_boxes].y2 = box[i].y2 + dst_dy; 2248 if (boxes[num_boxes].y2 > region.extents.y2) 2249 boxes[num_boxes].y2 = region.extents.y2; 2250 2251 if (boxes[num_boxes].x2 > boxes[num_boxes].x1 && 2252 boxes[num_boxes].y2 > boxes[num_boxes].y1) 2253 num_boxes++; 2254 } 2255 2256 if (num_boxes == 0) { 2257 ret = true; 2258 goto cleanup_boxes; 2259 } 2260 2261 if (!pixman_region_init_rects(®ion, boxes, num_boxes)) 2262 goto cleanup_boxes; 2263 2264 overlap.extents.x1 = extents->x1 + src_dx; 2265 overlap.extents.x2 = extents->x2 + src_dx; 2266 overlap.extents.y1 = extents->y1 + src_dy; 2267 overlap.extents.y2 = extents->y2 + src_dy; 2268 overlap.data = NULL; 2269 2270 RegionIntersect(&overlap, &overlap, ®ion); 2271 DBG(("%s: overlapping extents: (%d, %d), (%d, %d) x %d\n", 2272 __FUNCTION__, 2273 overlap.extents.x1, overlap.extents.y1, 2274 overlap.extents.x2, overlap.extents.y2, 2275 region_num_rects(&overlap))); 2276 2277 RegionNull(&non_overlap); 2278 RegionSubtract(&non_overlap, ®ion, &overlap); 2279 DBG(("%s: non-overlapping extents: (%d, %d), (%d, %d) x %d\n", 2280 __FUNCTION__, 2281 non_overlap.extents.x1, non_overlap.extents.y1, 2282 non_overlap.extents.x2, non_overlap.extents.y2, 2283 region_num_rects(&non_overlap))); 2284 2285 n = region_num_rects(&non_overlap); 2286 box = region_rects(&non_overlap); 2287 if (n && !sna->render.copy_boxes(sna, alu, 2288 draw, bo, -dst_dx + src_dx, -dst_dy + src_dy, 2289 draw, bo, 0, 0, 2290 box, n , COPY_NO_OVERLAP)) 2291 goto cleanup_boxes; 2292 2293 n = region_num_rects(&overlap); 2294 box = region_rects(&overlap); 2295 ret = copy_overlap(sna, alu, draw, bo, 2296 -dst_dx + src_dx, -dst_dy + src_dy, 2297 0, 0, 2298 box, n, &overlap.extents); 2299 2300cleanup_boxes: 2301 if (boxes != stack_boxes) 2302 free(boxes); 2303 2304 return ret; 2305} 2306 2307static bool can_copy_cpu(struct sna *sna, 2308 struct kgem_bo *src, 2309 struct kgem_bo *dst) 2310{ 2311 if (src->tiling != dst->tiling) 2312 return false; 2313 2314 if (src->pitch != dst->pitch) 2315 return false; 2316 2317 if (!kgem_bo_can_map__cpu(&sna->kgem, src, false)) 2318 return false; 2319 2320 if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true)) 2321 return false; 2322 2323 DBG(("%s -- yes, src handle=%d, dst handle=%d\n", __FUNCTION__, src->handle, dst->handle)); 2324 return true; 2325} 2326 2327bool 2328memcpy_copy_boxes(struct sna *sna, uint8_t op, 2329 const DrawableRec *src_draw, struct kgem_bo *src_bo, int16_t sx, int16_t sy, 2330 const DrawableRec *dst_draw, struct kgem_bo *dst_bo, int16_t dx, int16_t dy, 2331 const BoxRec *box, int n, unsigned flags) 2332{ 2333 void *dst, *src; 2334 bool clipped; 2335 2336 if (op != GXcopy) 2337 return false; 2338 2339 clipped = (n > 1 || 2340 box->x1 + dx > 0 || 2341 box->y1 + dy > 0 || 2342 box->x2 + dx < dst_draw->width || 2343 box->y2 + dy < dst_draw->height); 2344 2345 dst = src = NULL; 2346 if (!clipped && can_copy_cpu(sna, src_bo, dst_bo)) { 2347 dst = kgem_bo_map__cpu(&sna->kgem, dst_bo); 2348 src = kgem_bo_map__cpu(&sna->kgem, src_bo); 2349 } 2350 2351 if (dst == NULL || src == NULL) { 2352 dst = kgem_bo_map__gtt(&sna->kgem, dst_bo); 2353 src = kgem_bo_map__gtt(&sna->kgem, src_bo); 2354 if (dst == NULL || src == NULL) 2355 return false; 2356 } else { 2357 kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true); 2358 kgem_bo_sync__cpu_full(&sna->kgem, src_bo, false); 2359 } 2360 2361 DBG(("%s: src(%d, %d), dst(%d, %d) x %d\n", 2362 __FUNCTION__, sx, sy, dx, dy, n)); 2363 2364 if (sigtrap_get() == 0) { 2365 do { 2366 memcpy_blt(src, dst, dst_draw->bitsPerPixel, 2367 src_bo->pitch, dst_bo->pitch, 2368 box->x1 + sx, box->y1 + sy, 2369 box->x1 + dx, box->y1 + dy, 2370 box->x2 - box->x1, box->y2 - box->y1); 2371 box++; 2372 } while (--n); 2373 sigtrap_put(); 2374 } 2375 2376 return true; 2377} 2378 2379void 2380sna_render_mark_wedged(struct sna *sna) 2381{ 2382 sna->render.copy_boxes = memcpy_copy_boxes; 2383} 2384