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