1/* 2 * Copyright (c) 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#include <mipict.h> 38 39#define NO_COMPOSITE 0 40#define NO_COMPOSITE_RECTANGLES 0 41 42#define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) 43 44bool sna_composite_create(struct sna *sna) 45{ 46 xRenderColor color = { 0 }; 47 int error; 48 49 sna->clear = CreateSolidPicture(0, &color, &error); 50 return sna->clear != NULL; 51} 52 53void sna_composite_close(struct sna *sna) 54{ 55 DBG(("%s\n", __FUNCTION__)); 56 57 if (sna->clear) { 58 FreePicture(sna->clear, 0); 59 sna->clear = NULL; 60 } 61} 62 63static inline bool 64region_is_singular(pixman_region16_t *region) 65{ 66 return region->data == NULL; 67} 68 69static inline bool 70region_is_empty(pixman_region16_t *region) 71{ 72 return region->data && region->data->numRects == 0; 73} 74 75static inline pixman_bool_t 76clip_to_dst(pixman_region16_t *region, 77 pixman_region16_t *clip, 78 int dx, 79 int dy) 80{ 81 DBG(("%s: region: %dx[(%d, %d), (%d, %d)], clip: %dx[(%d, %d), (%d, %d)]\n", 82 __FUNCTION__, 83 pixman_region_n_rects(region), 84 region->extents.x1, region->extents.y1, 85 region->extents.x2, region->extents.y2, 86 pixman_region_n_rects(clip), 87 clip->extents.x1, clip->extents.y1, 88 clip->extents.x2, clip->extents.y2)); 89 90 if (region_is_singular(region) && region_is_singular(clip)) { 91 pixman_box16_t *r = ®ion->extents; 92 pixman_box16_t *c = &clip->extents; 93 int v; 94 95 if (r->x1 < (v = c->x1 + dx)) 96 r->x1 = BOUND(v); 97 if (r->x2 > (v = c->x2 + dx)) 98 r->x2 = BOUND(v); 99 if (r->y1 < (v = c->y1 + dy)) 100 r->y1 = BOUND(v); 101 if (r->y2 > (v = c->y2 + dy)) 102 r->y2 = BOUND(v); 103 104 if (r->x1 >= r->x2 || r->y1 >= r->y2) { 105 pixman_region_init(region); 106 return FALSE; 107 } 108 109 return true; 110 } else if (region_is_empty(clip)) { 111 return FALSE; 112 } else { 113 if (dx | dy) 114 pixman_region_translate(region, -dx, -dy); 115 if (!pixman_region_intersect(region, region, clip)) 116 return FALSE; 117 if (dx | dy) 118 pixman_region_translate(region, dx, dy); 119 120 return !region_is_empty(region); 121 } 122} 123 124static inline bool 125picture_has_clip(PicturePtr p) 126{ 127#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,16,99,1,0) 128 return p->clientClip; 129#else 130 return p->clientClipType != CT_NONE; 131#endif 132} 133 134static inline bool 135clip_to_src(RegionPtr region, PicturePtr p, int dx, int dy) 136{ 137 bool result; 138 139 if (!picture_has_clip(p)) 140 return true; 141 142 pixman_region_translate(p->clientClip, 143 p->clipOrigin.x + dx, 144 p->clipOrigin.y + dy); 145 146 result = RegionIntersect(region, region, p->clientClip); 147 148 pixman_region_translate(p->clientClip, 149 -(p->clipOrigin.x + dx), 150 -(p->clipOrigin.y + dy)); 151 152 return result && !region_is_empty(region); 153} 154 155bool 156sna_compute_composite_region(RegionPtr region, 157 PicturePtr src, PicturePtr mask, PicturePtr dst, 158 INT16 src_x, INT16 src_y, 159 INT16 mask_x, INT16 mask_y, 160 INT16 dst_x, INT16 dst_y, 161 CARD16 width, CARD16 height) 162{ 163 int v; 164 165 DBG(("%s: dst=(%d, %d)x(%d, %d)\n", 166 __FUNCTION__, 167 dst_x, dst_y, 168 width, height)); 169 170 region->extents.x1 = dst_x < 0 ? 0 : dst_x; 171 v = dst_x + width; 172 if (v > dst->pDrawable->width) 173 v = dst->pDrawable->width; 174 region->extents.x2 = v; 175 176 region->extents.y1 = dst_y < 0 ? 0 : dst_y; 177 v = dst_y + height; 178 if (v > dst->pDrawable->height) 179 v = dst->pDrawable->height; 180 region->extents.y2 = v; 181 182 region->data = 0; 183 184 DBG(("%s: initial clip against dst->pDrawable: (%d, %d), (%d, %d)\n", 185 __FUNCTION__, 186 region->extents.x1, region->extents.y1, 187 region->extents.x2, region->extents.y2)); 188 189 if (region->extents.x1 >= region->extents.x2 || 190 region->extents.y1 >= region->extents.y2) 191 return false; 192 193 region->extents.x1 += dst->pDrawable->x; 194 region->extents.x2 += dst->pDrawable->x; 195 region->extents.y1 += dst->pDrawable->y; 196 region->extents.y2 += dst->pDrawable->y; 197 198 dst_x += dst->pDrawable->x; 199 dst_y += dst->pDrawable->y; 200 201 /* clip against dst */ 202 if (!clip_to_dst(region, dst->pCompositeClip, 0, 0)) 203 return false; 204 205 DBG(("%s: clip against dst->pCompositeClip: (%d, %d), (%d, %d)\n", 206 __FUNCTION__, 207 region->extents.x1, region->extents.y1, 208 region->extents.x2, region->extents.y2)); 209 210 if (dst->alphaMap) { 211 if (!clip_to_dst(region, dst->alphaMap->pCompositeClip, 212 -dst->alphaOrigin.x, 213 -dst->alphaOrigin.y)) { 214 pixman_region_fini (region); 215 return false; 216 } 217 } 218 219 /* clip against src */ 220 if (src) { 221 if (src->pDrawable) { 222 src_x += src->pDrawable->x; 223 src_y += src->pDrawable->y; 224 } 225 if (!clip_to_src(region, src, dst_x - src_x, dst_y - src_y)) { 226 pixman_region_fini (region); 227 return false; 228 } 229 DBG(("%s: clip against src (%dx%d clip=%d): (%d, %d), (%d, %d)\n", 230 __FUNCTION__, 231 src->pDrawable ? src->pDrawable->width : 0, 232 src->pDrawable ? src->pDrawable->height : 0, 233 picture_has_clip(src), 234 region->extents.x1, region->extents.y1, 235 region->extents.x2, region->extents.y2)); 236 237 if (src->alphaMap) { 238 if (!clip_to_src(region, src->alphaMap, 239 dst_x - (src_x - src->alphaOrigin.x), 240 dst_y - (src_y - src->alphaOrigin.y))) { 241 pixman_region_fini(region); 242 return false; 243 } 244 } 245 } 246 247 /* clip against mask */ 248 if (mask) { 249 if (mask->pDrawable) { 250 mask_x += mask->pDrawable->x; 251 mask_y += mask->pDrawable->y; 252 } 253 if (!clip_to_src(region, mask, dst_x - mask_x, dst_y - mask_y)) { 254 pixman_region_fini(region); 255 return false; 256 } 257 if (mask->alphaMap) { 258 if (!clip_to_src(region, mask->alphaMap, 259 dst_x - (mask_x - mask->alphaOrigin.x), 260 dst_y - (mask_y - mask->alphaOrigin.y))) { 261 pixman_region_fini(region); 262 return false; 263 } 264 } 265 266 DBG(("%s: clip against mask: (%d, %d), (%d, %d)\n", 267 __FUNCTION__, 268 region->extents.x1, region->extents.y1, 269 region->extents.x2, region->extents.y2)); 270 } 271 272 return !region_is_empty(region); 273} 274 275static void 276trim_extents(BoxPtr extents, const PicturePtr p, int dx, int dy) 277{ 278 const BoxPtr box = REGION_EXTENTS(NULL, p->pCompositeClip); 279 280 DBG(("%s: trim((%d, %d), (%d, %d)) against ((%d, %d), (%d, %d)) + (%d, %d)\n", 281 __FUNCTION__, 282 extents->x1, extents->y1, extents->x2, extents->y2, 283 box->x1, box->y1, box->x2, box->y2, 284 dx, dy)); 285 286 if (extents->x1 < box->x1 + dx) 287 extents->x1 = box->x1 + dx; 288 if (extents->x2 > box->x2 + dx) 289 extents->x2 = box->x2 + dx; 290 291 if (extents->y1 < box->y1 + dy) 292 extents->y1 = box->y1 + dy; 293 if (extents->y2 > box->y2 + dy) 294 extents->y2 = box->y2 + dy; 295} 296 297static void 298_trim_source_extents(BoxPtr extents, const PicturePtr p, int dx, int dy) 299{ 300 if (picture_has_clip(p)) 301 trim_extents(extents, p, dx, dy); 302} 303 304static void 305trim_source_extents(BoxPtr extents, const PicturePtr p, int dx, int dy) 306{ 307 if (p->pDrawable) { 308 dx += p->pDrawable->x; 309 dy += p->pDrawable->y; 310 } 311 _trim_source_extents(extents, p, dx, dy); 312 if (p->alphaMap) 313 _trim_source_extents(extents, p->alphaMap, 314 dx - p->alphaOrigin.x, 315 dy - p->alphaOrigin.y); 316 317 DBG(("%s: -> (%d, %d), (%d, %d)\n", 318 __FUNCTION__, 319 extents->x1, extents->y1, 320 extents->x2, extents->y2)); 321} 322 323bool 324sna_compute_composite_extents(BoxPtr extents, 325 PicturePtr src, PicturePtr mask, PicturePtr dst, 326 INT16 src_x, INT16 src_y, 327 INT16 mask_x, INT16 mask_y, 328 INT16 dst_x, INT16 dst_y, 329 CARD16 width, CARD16 height) 330{ 331 int v; 332 333 DBG(("%s: dst=(%d, %d)x(%d, %d)\n", 334 __FUNCTION__, 335 dst_x, dst_y, 336 width, height)); 337 338 extents->x1 = dst_x < 0 ? 0 : dst_x; 339 v = dst_x + width; 340 if (v > dst->pDrawable->width) 341 v = dst->pDrawable->width; 342 extents->x2 = v; 343 344 extents->y1 = dst_y < 0 ? 0 : dst_y; 345 v = dst_y + height; 346 if (v > dst->pDrawable->height) 347 v = dst->pDrawable->height; 348 extents->y2 = v; 349 350 DBG(("%s: initial clip against dst->pDrawable: (%d, %d), (%d, %d)\n", 351 __FUNCTION__, 352 extents->x1, extents->y1, 353 extents->x2, extents->y2)); 354 355 if (extents->x1 >= extents->x2 || extents->y1 >= extents->y2) 356 return false; 357 358 extents->x1 += dst->pDrawable->x; 359 extents->x2 += dst->pDrawable->x; 360 extents->y1 += dst->pDrawable->y; 361 extents->y2 += dst->pDrawable->y; 362 363 if (extents->x1 < dst->pCompositeClip->extents.x1) 364 extents->x1 = dst->pCompositeClip->extents.x1; 365 if (extents->x2 > dst->pCompositeClip->extents.x2) 366 extents->x2 = dst->pCompositeClip->extents.x2; 367 368 if (extents->y1 < dst->pCompositeClip->extents.y1) 369 extents->y1 = dst->pCompositeClip->extents.y1; 370 if (extents->y2 > dst->pCompositeClip->extents.y2) 371 extents->y2 = dst->pCompositeClip->extents.y2; 372 373 DBG(("%s: initial clip against dst->pCompositeClip: (%d, %d), (%d, %d)\n", 374 __FUNCTION__, 375 extents->x1, extents->y1, 376 extents->x2, extents->y2)); 377 378 if (extents->x1 >= extents->x2 || extents->y1 >= extents->y2) 379 return false; 380 381 dst_x += dst->pDrawable->x; 382 dst_y += dst->pDrawable->y; 383 384 /* clip against dst */ 385 trim_extents(extents, dst, 0, 0); 386 if (dst->alphaMap) 387 trim_extents(extents, dst->alphaMap, 388 -dst->alphaOrigin.x, 389 -dst->alphaOrigin.y); 390 391 DBG(("%s: clip against dst: (%d, %d), (%d, %d)\n", 392 __FUNCTION__, 393 extents->x1, extents->y1, 394 extents->x2, extents->y2)); 395 396 if (src) 397 trim_source_extents(extents, src, dst_x - src_x, dst_y - src_y); 398 if (mask) 399 trim_source_extents(extents, mask, 400 dst_x - mask_x, dst_y - mask_y); 401 402 if (extents->x1 >= extents->x2 || extents->y1 >= extents->y2) 403 return false; 404 405 if (region_is_singular(dst->pCompositeClip)) 406 return true; 407 408 return pixman_region_contains_rectangle(dst->pCompositeClip, 409 extents) != PIXMAN_REGION_OUT; 410} 411 412#if HAS_DEBUG_FULL 413static void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function) 414{ 415 if (box->x1 < 0 || box->y1 < 0 || 416 box->x2 > pixmap->drawable.width || 417 box->y2 > pixmap->drawable.height) 418 { 419 FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", 420 function, 421 box->x1, box->y1, box->x2, box->y2, 422 pixmap->drawable.width, 423 pixmap->drawable.height); 424 } 425} 426#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 427#else 428#define assert_pixmap_contains_box(p, b) 429#endif 430 431static void apply_damage(struct sna_composite_op *op, RegionPtr region) 432{ 433 DBG(("%s: damage=%p, region=%d [(%d, %d), (%d, %d) + (%d, %d)]\n", 434 __FUNCTION__, op->damage, region_num_rects(region), 435 region->extents.x1, region->extents.y1, 436 region->extents.x2, region->extents.y2, 437 op->dst.x, op->dst.y)); 438 439 if (op->damage == NULL) 440 return; 441 442 if (op->dst.x | op->dst.y) 443 RegionTranslate(region, op->dst.x, op->dst.y); 444 445 assert_pixmap_contains_box(op->dst.pixmap, RegionExtents(region)); 446 if (region->data == NULL && 447 region->extents.x2 - region->extents.x1 == op->dst.width && 448 region->extents.y2 - region->extents.y1 == op->dst.height) { 449 *op->damage = _sna_damage_all(*op->damage, 450 op->dst.width, 451 op->dst.height); 452 op->damage = NULL; 453 } else 454 sna_damage_add(op->damage, region); 455 456 assert(!op->damage || !DAMAGE_IS_ALL(*op->damage)); 457} 458 459static inline bool use_cpu(PixmapPtr pixmap, struct sna_pixmap *priv, 460 CARD8 op, INT16 width, INT16 height) 461{ 462 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) 463 return false; 464 465 if (DAMAGE_IS_ALL(priv->cpu_damage) && 466 (op > PictOpSrc || 467 width < pixmap->drawable.width || 468 height < pixmap->drawable.height)) 469 return true; 470 471 if (priv->gpu_bo) 472 return false; 473 474 return (priv->create & KGEM_CAN_CREATE_GPU) == 0; 475} 476 477static void validate_source(PicturePtr picture) 478{ 479#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,10,99,901,0) 480 miCompositeSourceValidate(picture); 481#else 482 miCompositeSourceValidate(picture, 483 0, 0, 484 picture->pDrawable ? picture->pDrawable->width : 0, 485 picture->pDrawable ? picture->pDrawable->height : 0); 486#endif 487} 488 489void 490sna_composite_fb(CARD8 op, 491 PicturePtr src, 492 PicturePtr mask, 493 PicturePtr dst, 494 RegionPtr region, 495 INT16 src_x, INT16 src_y, 496 INT16 msk_x, INT16 msk_y, 497 INT16 dst_x, INT16 dst_y, 498 CARD16 width, CARD16 height) 499{ 500 pixman_image_t *src_image, *mask_image, *dest_image; 501 int src_xoff, src_yoff; 502 int msk_xoff, msk_yoff; 503 int dst_xoff, dst_yoff; 504 int16_t tx, ty; 505 unsigned flags; 506 507 DBG(("%s -- op=%d, fallback dst=(%d, %d)+(%d, %d), size=(%d, %d): region=((%d,%d), (%d, %d))\n", 508 __FUNCTION__, op, 509 dst_x, dst_y, 510 dst->pDrawable->x, dst->pDrawable->y, 511 width, height, 512 region->extents.x1, region->extents.y1, 513 region->extents.x2, region->extents.y2)); 514 515 if (src->pDrawable) { 516 DBG(("%s: fallback -- move src to cpu\n", __FUNCTION__)); 517 if (!sna_drawable_move_to_cpu(src->pDrawable, 518 MOVE_READ)) 519 return; 520 521 if (src->alphaMap && 522 !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 523 MOVE_READ)) 524 return; 525 } 526 527 validate_source(src); 528 529 if (mask) { 530 if (mask->pDrawable) { 531 DBG(("%s: fallback -- move mask to cpu\n", __FUNCTION__)); 532 if (!sna_drawable_move_to_cpu(mask->pDrawable, 533 MOVE_READ)) 534 return; 535 536 if (mask->alphaMap && 537 !sna_drawable_move_to_cpu(mask->alphaMap->pDrawable, 538 MOVE_READ)) 539 return; 540 } 541 542 validate_source(mask); 543 } 544 545 DBG(("%s: fallback -- move dst to cpu\n", __FUNCTION__)); 546 if (op <= PictOpSrc && !dst->alphaMap) 547 flags = MOVE_WRITE | MOVE_INPLACE_HINT; 548 else 549 flags = MOVE_WRITE | MOVE_READ; 550 if (!sna_drawable_move_region_to_cpu(dst->pDrawable, region, flags)) 551 return; 552 if (dst->alphaMap && 553 !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, flags)) 554 return; 555 556 if (mask == NULL && 557 src->pDrawable && 558 dst->pDrawable->bitsPerPixel >= 8 && 559 src->filter != PictFilterConvolution && 560 (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(src->format))) && 561 (dst->format == src->format || dst->format == alphaless(src->format)) && 562 sna_transform_is_imprecise_integer_translation(src->transform, src->filter, 563 dst->polyMode == PolyModePrecise, 564 &tx, &ty)) { 565 PixmapPtr dst_pixmap = get_drawable_pixmap(dst->pDrawable); 566 PixmapPtr src_pixmap = get_drawable_pixmap(src->pDrawable); 567 int16_t sx = src_x + tx - (dst->pDrawable->x + dst_x); 568 int16_t sy = src_y + ty - (dst->pDrawable->y + dst_y); 569 570 assert(src->pDrawable->bitsPerPixel == dst->pDrawable->bitsPerPixel); 571 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 572 573 if (region->extents.x1 + sx >= 0 && 574 region->extents.y1 + sy >= 0 && 575 region->extents.x2 + sx <= src->pDrawable->width && 576 region->extents.y2 + sy <= src->pDrawable->height) { 577 if (sigtrap_get() == 0) { 578 const BoxRec *box = region_rects(region); 579 int nbox = region_num_rects(region); 580 581 sx += src->pDrawable->x; 582 sy += src->pDrawable->y; 583 if (get_drawable_deltas(src->pDrawable, src_pixmap, &tx, &ty)) 584 sx += tx, sy += ty; 585 586 assert(region->extents.x1 + sx >= 0); 587 assert(region->extents.x2 + sx <= src_pixmap->drawable.width); 588 assert(region->extents.y1 + sy >= 0); 589 assert(region->extents.y2 + sy <= src_pixmap->drawable.height); 590 591 get_drawable_deltas(dst->pDrawable, dst_pixmap, &tx, &ty); 592 593 assert(nbox); 594 do { 595 assert(box->x1 + sx >= 0); 596 assert(box->x2 + sx <= src_pixmap->drawable.width); 597 assert(box->y1 + sy >= 0); 598 assert(box->y2 + sy <= src_pixmap->drawable.height); 599 600 assert(box->x1 + tx >= 0); 601 assert(box->x2 + tx <= dst_pixmap->drawable.width); 602 assert(box->y1 + ty >= 0); 603 assert(box->y2 + ty <= dst_pixmap->drawable.height); 604 605 assert(box->x2 > box->x1 && box->y2 > box->y1); 606 607 sigtrap_assert_active(); 608 memcpy_blt(src_pixmap->devPrivate.ptr, 609 dst_pixmap->devPrivate.ptr, 610 dst_pixmap->drawable.bitsPerPixel, 611 src_pixmap->devKind, 612 dst_pixmap->devKind, 613 box->x1 + sx, box->y1 + sy, 614 box->x1 + tx, box->y1 + ty, 615 box->x2 - box->x1, box->y2 - box->y1); 616 box++; 617 } while (--nbox); 618 sigtrap_put(); 619 } 620 621 return; 622 } 623 } 624 625 src_image = image_from_pict(src, FALSE, &src_xoff, &src_yoff); 626 mask_image = image_from_pict(mask, FALSE, &msk_xoff, &msk_yoff); 627 dest_image = image_from_pict(dst, TRUE, &dst_xoff, &dst_yoff); 628 629 if (src_image && dest_image && !(mask && !mask_image)) 630 sna_image_composite(op, src_image, mask_image, dest_image, 631 src_x + src_xoff, src_y + src_yoff, 632 msk_x + msk_xoff, msk_y + msk_yoff, 633 dst_x + dst_xoff, dst_y + dst_yoff, 634 width, height); 635 636 free_pixman_pict(src, src_image); 637 free_pixman_pict(mask, mask_image); 638 free_pixman_pict(dst, dest_image); 639} 640 641void 642sna_composite(CARD8 op, 643 PicturePtr src, 644 PicturePtr mask, 645 PicturePtr dst, 646 INT16 src_x, INT16 src_y, 647 INT16 mask_x, INT16 mask_y, 648 INT16 dst_x, INT16 dst_y, 649 CARD16 width, CARD16 height) 650{ 651 PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 652 struct sna *sna = to_sna_from_pixmap(pixmap); 653 struct sna_pixmap *priv; 654 struct sna_composite_op tmp; 655 RegionRec region; 656 int dx, dy; 657 658 DBG(("%s(pixmap=%ld, op=%d, src=%ld+(%d, %d), mask=%ld+(%d, %d), dst=%ld+(%d, %d)+(%d, %d), size=(%d, %d)\n", 659 __FUNCTION__, 660 pixmap->drawable.serialNumber, op, 661 get_picture_id(src), src_x, src_y, 662 get_picture_id(mask), mask_x, mask_y, 663 get_picture_id(dst), dst_x, dst_y, 664 dst->pDrawable->x, dst->pDrawable->y, 665 width, height)); 666 667 if (region_is_empty(dst->pCompositeClip)) { 668 DBG(("%s: empty clip, skipping\n", __FUNCTION__)); 669 return; 670 } 671 672 if (op == PictOpClear) { 673 DBG(("%s: discarding source and mask for clear\n", __FUNCTION__)); 674 mask = NULL; 675 if (sna->clear) 676 src = sna->clear; 677 } 678 679 if (!sna_compute_composite_region(®ion, 680 src, mask, dst, 681 src_x, src_y, 682 mask_x, mask_y, 683 dst_x, dst_y, 684 width, height)) 685 return; 686 687 if (mask && sna_composite_mask_is_opaque(mask)) { 688 DBG(("%s: removing opaque %smask\n", 689 __FUNCTION__, 690 mask->componentAlpha && PICT_FORMAT_RGB(mask->format) ? "CA " : "")); 691 mask = NULL; 692 } 693 694 if (NO_COMPOSITE) 695 goto fallback; 696 697 if (wedged(sna)) { 698 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 699 goto fallback; 700 } 701 702 if (!can_render_to_picture(dst)) { 703 DBG(("%s: fallback due to unhandled picture\n", __FUNCTION__)); 704 goto fallback; 705 } 706 707 priv = sna_pixmap(pixmap); 708 if (priv == NULL) { 709 DBG(("%s: fallback as destination pixmap=%ld is unattached\n", 710 __FUNCTION__, pixmap->drawable.serialNumber)); 711 goto fallback; 712 } 713 714 if (use_cpu(pixmap, priv, op, width, height) && 715 !picture_is_gpu(sna, src, PREFER_GPU_RENDER) && 716 !picture_is_gpu(sna, mask, PREFER_GPU_RENDER)) { 717 DBG(("%s: fallback, dst pixmap=%ld is too small (or completely damaged)\n", 718 __FUNCTION__, pixmap->drawable.serialNumber)); 719 goto fallback; 720 } 721 722 dx = region.extents.x1 - (dst_x + dst->pDrawable->x); 723 dy = region.extents.y1 - (dst_y + dst->pDrawable->y); 724 725 DBG(("%s: composite region extents:+(%d, %d) -> (%d, %d), (%d, %d) + (%d, %d)\n", 726 __FUNCTION__, 727 dx, dy, 728 region.extents.x1, region.extents.y1, 729 region.extents.x2, region.extents.y2, 730 get_drawable_dx(dst->pDrawable), 731 get_drawable_dy(dst->pDrawable))); 732 733 if (op <= PictOpSrc && priv->cpu_damage) { 734 int16_t x, y; 735 736 if (get_drawable_deltas(dst->pDrawable, pixmap, &x, &y)) 737 pixman_region_translate(®ion, x, y); 738 739 sna_damage_subtract(&priv->cpu_damage, ®ion); 740 if (priv->cpu_damage == NULL) { 741 list_del(&priv->flush_list); 742 priv->cpu = false; 743 } 744 745 if (x|y) 746 pixman_region_translate(®ion, -x, -y); 747 } 748 749 if (!sna->render.composite(sna, 750 op, src, mask, dst, 751 src_x + dx, src_y + dy, 752 mask_x + dx, mask_y + dy, 753 region.extents.x1, 754 region.extents.y1, 755 region.extents.x2 - region.extents.x1, 756 region.extents.y2 - region.extents.y1, 757 region.data ? COMPOSITE_PARTIAL : 0, 758 memset(&tmp, 0, sizeof(tmp)))) { 759 DBG(("%s: fallback due unhandled composite op\n", __FUNCTION__)); 760 goto fallback; 761 } 762 assert(!tmp.damage || !DAMAGE_IS_ALL(*tmp.damage)); 763 764 if (region.data == NULL) 765 tmp.box(sna, &tmp, ®ion.extents); 766 else 767 tmp.boxes(sna, &tmp, 768 RegionBoxptr(®ion), 769 region_num_rects(®ion)); 770 apply_damage(&tmp, ®ion); 771 tmp.done(sna, &tmp); 772 773 goto out; 774 775fallback: 776 DBG(("%s: fallback -- fbComposite\n", __FUNCTION__)); 777 sna_composite_fb(op, src, mask, dst, ®ion, 778 src_x, src_y, 779 mask_x, mask_y, 780 dst_x, dst_y, 781 width, height); 782out: 783 REGION_UNINIT(NULL, ®ion); 784} 785 786void 787sna_composite_rectangles(CARD8 op, 788 PicturePtr dst, 789 xRenderColor *color, 790 int num_rects, 791 xRectangle *rects) 792{ 793 struct sna *sna = to_sna_from_drawable(dst->pDrawable); 794 PixmapPtr pixmap; 795 struct sna_pixmap *priv; 796 struct kgem_bo *bo; 797 struct sna_damage **damage; 798 pixman_region16_t region; 799 pixman_box16_t stack_boxes[64], *boxes = stack_boxes, *b; 800 int16_t dst_x, dst_y; 801 int i, num_boxes; 802 unsigned hint; 803 804 DBG(("%s(pixmap=%ld, op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n", 805 __FUNCTION__, 806 get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber, 807 op, 808 (color->alpha >> 8 << 24) | 809 (color->red >> 8 << 16) | 810 (color->green >> 8 << 8) | 811 (color->blue >> 8 << 0), 812 num_rects, 813 rects[0].x, rects[0].y, rects[0].width, rects[0].height)); 814 815 if (!num_rects) 816 return; 817 818 if (region_is_empty(dst->pCompositeClip)) { 819 DBG(("%s: empty clip, skipping\n", __FUNCTION__)); 820 return; 821 } 822 823 if (color->alpha <= 0x00ff) { 824 if (PICT_FORMAT_TYPE(dst->format) == PICT_TYPE_A || 825 (color->red|color->green|color->blue) <= 0x00ff) { 826 switch (op) { 827 case PictOpOver: 828 case PictOpOutReverse: 829 case PictOpAdd: 830 return; 831 case PictOpInReverse: 832 case PictOpSrc: 833 op = PictOpClear; 834 break; 835 case PictOpAtopReverse: 836 op = PictOpOut; 837 break; 838 case PictOpXor: 839 op = PictOpOverReverse; 840 break; 841 } 842 } else { 843 switch (op) { 844 case PictOpOver: 845 case PictOpOutReverse: 846 return; 847 case PictOpInReverse: 848 op = PictOpClear; 849 break; 850 case PictOpAtopReverse: 851 op = PictOpOut; 852 break; 853 case PictOpXor: 854 op = PictOpOverReverse; 855 break; 856 } 857 } 858 } else if (color->alpha >= 0xff00) { 859 switch (op) { 860 case PictOpOver: 861 op = PictOpSrc; 862 break; 863 case PictOpInReverse: 864 return; 865 case PictOpOutReverse: 866 op = PictOpClear; 867 break; 868 case PictOpAtopReverse: 869 op = PictOpOverReverse; 870 break; 871 case PictOpXor: 872 op = PictOpOut; 873 break; 874 case PictOpAdd: 875 if (PICT_FORMAT_TYPE(dst->format) == PICT_TYPE_A || 876 (color->red&color->green&color->blue) >= 0xff00) 877 op = PictOpSrc; 878 break; 879 } 880 } 881 882 /* Avoid reducing overlapping translucent rectangles */ 883 if ((op == PictOpOver || op == PictOpAdd) && 884 num_rects == 1 && 885 sna_drawable_is_clear(dst->pDrawable)) 886 op = PictOpSrc; 887 888 DBG(("%s: converted to op %d\n", __FUNCTION__, op)); 889 890 if (num_rects > ARRAY_SIZE(stack_boxes)) { 891 boxes = malloc(sizeof(pixman_box16_t) * num_rects); 892 if (boxes == NULL) 893 return; 894 } 895 896 for (i = num_boxes = 0; i < num_rects; i++) { 897 boxes[num_boxes].x1 = rects[i].x + dst->pDrawable->x; 898 if (boxes[num_boxes].x1 < dst->pCompositeClip->extents.x1) 899 boxes[num_boxes].x1 = dst->pCompositeClip->extents.x1; 900 901 boxes[num_boxes].y1 = rects[i].y + dst->pDrawable->y; 902 if (boxes[num_boxes].y1 < dst->pCompositeClip->extents.y1) 903 boxes[num_boxes].y1 = dst->pCompositeClip->extents.y1; 904 905 boxes[num_boxes].x2 = bound(rects[i].x + dst->pDrawable->x, rects[i].width); 906 if (boxes[num_boxes].x2 > dst->pCompositeClip->extents.x2) 907 boxes[num_boxes].x2 = dst->pCompositeClip->extents.x2; 908 909 boxes[num_boxes].y2 = bound(rects[i].y + dst->pDrawable->y, rects[i].height); 910 if (boxes[num_boxes].y2 > dst->pCompositeClip->extents.y2) 911 boxes[num_boxes].y2 = dst->pCompositeClip->extents.y2; 912 913 DBG(("%s[%d] (%d, %d)x(%d, %d) -> (%d, %d), (%d, %d)\n", 914 __FUNCTION__, i, 915 rects[i].x, rects[i].y, rects[i].width, rects[i].height, 916 boxes[num_boxes].x1, boxes[num_boxes].y1, boxes[num_boxes].x2, boxes[num_boxes].y2)); 917 918 if (boxes[num_boxes].x2 > boxes[num_boxes].x1 && 919 boxes[num_boxes].y2 > boxes[num_boxes].y1) 920 num_boxes++; 921 } 922 923 if (num_boxes == 0) 924 goto cleanup_boxes; 925 926 if (!pixman_region_init_rects(®ion, boxes, num_boxes)) 927 goto cleanup_boxes; 928 929 DBG(("%s: nrects=%d, region=(%d, %d), (%d, %d) x %d\n", 930 __FUNCTION__, num_rects, 931 region.extents.x1, region.extents.y1, 932 region.extents.x2, region.extents.y2, 933 num_boxes)); 934 935 if (dst->pCompositeClip->data && 936 (!pixman_region_intersect(®ion, ®ion, dst->pCompositeClip) || 937 region_is_empty(®ion))) { 938 DBG(("%s: zero-intersection between rectangles and clip\n", 939 __FUNCTION__)); 940 goto cleanup_region; 941 } 942 943 DBG(("%s: clipped extents (%d, %d),(%d, %d) x %d\n", 944 __FUNCTION__, 945 RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 946 RegionExtents(®ion)->x2, RegionExtents(®ion)->y2, 947 region_num_rects(®ion))); 948 949 /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must 950 * manually append the damaged regions ourselves. 951 * 952 * Note that DamageRegionAppend() will apply the drawable-deltas itself. 953 */ 954 DamageRegionAppend(dst->pDrawable, ®ion); 955 956 pixmap = get_drawable_pixmap(dst->pDrawable); 957 if (get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y)) 958 pixman_region_translate(®ion, dst_x, dst_y); 959 960 DBG(("%s: pixmap +(%d, %d) extents (%d, %d),(%d, %d)\n", 961 __FUNCTION__, dst_x, dst_y, 962 RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 963 RegionExtents(®ion)->x2, RegionExtents(®ion)->y2)); 964 assert_pixmap_contains_box(pixmap, RegionExtents(®ion)); 965 966 if (NO_COMPOSITE_RECTANGLES) 967 goto fallback; 968 969 if (wedged(sna)) 970 goto fallback; 971 972 if (!can_render_to_picture(dst)) { 973 DBG(("%s: fallback, dst has an incompatible picture\n", __FUNCTION__)); 974 goto fallback; 975 } 976 977 priv = sna_pixmap(pixmap); 978 if (priv == NULL || too_small(priv)) { 979 DBG(("%s: fallback, dst pixmap=%ld too small or not attached\n", 980 __FUNCTION__, pixmap->drawable.serialNumber)); 981 goto fallback; 982 } 983 984 /* If we going to be overwriting any CPU damage with a subsequent 985 * operation, then we may as well delete it without moving it 986 * first to the GPU. 987 */ 988 hint = can_render(sna) ? PREFER_GPU : 0; 989 if (op <= PictOpSrc) { 990 if (priv->clear) { 991 uint32_t pixel; 992 bool ok; 993 994 if (op == PictOpClear) { 995 if (priv->clear_color == 0) 996 goto done; 997 998 ok = sna_get_pixel_from_rgba(&pixel, 999 0, 0, 0, 0, 1000 dst->format); 1001 } else { 1002 ok = sna_get_pixel_from_rgba(&pixel, 1003 color->red, 1004 color->green, 1005 color->blue, 1006 color->alpha, 1007 dst->format); 1008 } 1009 if (ok && priv->clear_color == pixel) { 1010 DBG(("%s: matches current clear, skipping\n", 1011 __FUNCTION__)); 1012 goto done; 1013 } 1014 } 1015 1016 if (region.data == NULL) { 1017 hint |= IGNORE_DAMAGE; 1018 if (region_subsumes_drawable(®ion, &pixmap->drawable)) 1019 hint |= REPLACES; 1020 if (priv->cpu_damage && 1021 (hint & REPLACES || 1022 region_subsumes_damage(®ion, priv->cpu_damage))) { 1023 DBG(("%s: discarding existing CPU damage\n", __FUNCTION__)); 1024 if (priv->gpu_bo && priv->gpu_bo->proxy) { 1025 assert(priv->gpu_damage == NULL); 1026 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1027 priv->gpu_bo = NULL; 1028 } 1029 sna_damage_destroy(&priv->cpu_damage); 1030 list_del(&priv->flush_list); 1031 } 1032 if (hint & REPLACES || 1033 box_inplace(pixmap, ®ion.extents)) { 1034 if (priv->gpu_bo && priv->cpu_damage == NULL) { 1035 DBG(("%s: promoting to full GPU\n", __FUNCTION__)); 1036 assert(priv->gpu_bo->proxy == NULL); 1037 sna_damage_all(&priv->gpu_damage, pixmap); 1038 } 1039 } 1040 } 1041 if (priv->cpu_damage == NULL) { 1042 DBG(("%s: dropping last-cpu hint\n", __FUNCTION__)); 1043 priv->cpu = false; 1044 } 1045 } 1046 1047 bo = sna_drawable_use_bo(&pixmap->drawable, hint, 1048 ®ion.extents, &damage); 1049 if (bo == NULL) { 1050 DBG(("%s: fallback due to no GPU bo\n", __FUNCTION__)); 1051 goto fallback; 1052 } 1053 if (hint & REPLACES) 1054 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 1055 1056 if (op <= PictOpSrc) { 1057 b = pixman_region_rectangles(®ion, &num_boxes); 1058 if (!sna->render.fill_boxes(sna, op, dst->format, color, 1059 &pixmap->drawable, bo, b, num_boxes)) { 1060 DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); 1061 goto fallback; 1062 } 1063 } else if (dst->pCompositeClip->data == NULL) { 1064 for (i = 0; i < num_boxes; i++) { 1065 boxes[i].x1 += dst_x; 1066 boxes[i].x2 += dst_x; 1067 boxes[i].y1 += dst_y; 1068 boxes[i].y2 += dst_y; 1069 } 1070 if (!sna->render.fill_boxes(sna, op, dst->format, color, 1071 &pixmap->drawable, bo, boxes, num_boxes)) { 1072 DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); 1073 goto fallback; 1074 } 1075 } else { 1076 for (i = 0; i < num_boxes; i++) { 1077 RegionRec tmp = { boxes[i] }; 1078 if (pixman_region_intersect(&tmp, &tmp, dst->pCompositeClip)) { 1079 int n = 0; 1080 1081 b = pixman_region_rectangles(&tmp, &n); 1082 if (n) { 1083 if (dst_x | dst_y) 1084 pixman_region_translate(&tmp, dst_x, dst_y); 1085 1086 n = !sna->render.fill_boxes(sna, op, dst->format, color, 1087 &pixmap->drawable, bo, b, n); 1088 } 1089 1090 pixman_region_fini(&tmp); 1091 1092 if (n) { 1093 DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); 1094 goto fallback; 1095 } 1096 } 1097 } 1098 } 1099 1100 if (damage) 1101 sna_damage_add(damage, ®ion); 1102 1103 /* Clearing a pixmap after creation is a common operation, so take 1104 * advantage and reduce further damage operations. 1105 */ 1106 if (region_subsumes_drawable(®ion, &pixmap->drawable)) { 1107 if (damage) { 1108 sna_damage_all(damage, pixmap); 1109 sna_damage_destroy(damage == &priv->gpu_damage ? 1110 &priv->cpu_damage : &priv->gpu_damage); 1111 } 1112 1113 if (op <= PictOpSrc && bo == priv->gpu_bo) { 1114 bool ok; 1115 1116 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 1117 1118 priv->clear_color = 0; 1119 ok = true; 1120 if (op == PictOpSrc) 1121 ok = sna_get_pixel_from_rgba(&priv->clear_color, 1122 color->red, 1123 color->green, 1124 color->blue, 1125 color->alpha, 1126 dst->format); 1127 priv->clear = ok; 1128 DBG(("%s: pixmap=%ld marking clear [%08x]? %d\n", 1129 __FUNCTION__, pixmap->drawable.serialNumber, 1130 priv->clear_color, ok)); 1131 } 1132 } 1133 goto done; 1134 1135fallback: 1136 DBG(("%s: fallback\n", __FUNCTION__)); 1137 if (op <= PictOpSrc) 1138 hint = MOVE_WRITE; 1139 else 1140 hint = MOVE_WRITE | MOVE_READ; 1141 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, hint)) 1142 goto done; 1143 1144 if (dst->alphaMap && 1145 !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, hint)) 1146 goto done; 1147 1148 assert(pixmap->devPrivate.ptr); 1149 1150 if (sigtrap_get() == 0) { 1151 if (op <= PictOpSrc) { 1152 int nbox = region_num_rects(®ion); 1153 const BoxRec *box = region_rects(®ion); 1154 uint32_t pixel; 1155 1156 if (op == PictOpClear) 1157 pixel = 0; 1158 else if (!sna_get_pixel_from_rgba(&pixel, 1159 color->red, 1160 color->green, 1161 color->blue, 1162 color->alpha, 1163 dst->format)) 1164 goto fallback_composite; 1165 1166 sigtrap_assert_active(); 1167 if (pixel == 0 && 1168 box->x2 - box->x1 == pixmap->drawable.width && 1169 box->y2 - box->y1 == pixmap->drawable.height) { 1170 memset(pixmap->devPrivate.ptr, 0, 1171 pixmap->devKind*pixmap->drawable.height); 1172 } else do { 1173 DBG(("%s: fallback fill: (%d, %d)x(%d, %d) %08x\n", 1174 __FUNCTION__, 1175 box->x1, box->y1, 1176 box->x2 - box->x1, 1177 box->y2 - box->y1, 1178 pixel)); 1179 1180 pixman_fill(pixmap->devPrivate.ptr, 1181 pixmap->devKind/sizeof(uint32_t), 1182 pixmap->drawable.bitsPerPixel, 1183 box->x1, box->y1, 1184 box->x2 - box->x1, 1185 box->y2 - box->y1, 1186 pixel); 1187 box++; 1188 } while (--nbox); 1189 } else { 1190 PicturePtr src; 1191 int error; 1192 1193fallback_composite: 1194 DBG(("%s: fallback -- fbComposite()\n", __FUNCTION__)); 1195 src = CreateSolidPicture(0, color, &error); 1196 if (src) { 1197 do { 1198 fbComposite(op, src, NULL, dst, 1199 0, 0, 1200 0, 0, 1201 rects->x, rects->y, 1202 rects->width, rects->height); 1203 rects++; 1204 } while (--num_rects); 1205 FreePicture(src, 0); 1206 } 1207 } 1208 sigtrap_put(); 1209 } 1210 1211done: 1212 DamageRegionProcessPending(dst->pDrawable); 1213 1214cleanup_region: 1215 pixman_region_fini(®ion); 1216cleanup_boxes: 1217 if (boxes != stack_boxes) 1218 free(boxes); 1219} 1220