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