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 457static inline bool use_cpu(PixmapPtr pixmap, struct sna_pixmap *priv, 458 CARD8 op, INT16 width, INT16 height) 459{ 460 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) 461 return false; 462 463 if (DAMAGE_IS_ALL(priv->cpu_damage) && 464 (op > PictOpSrc || 465 width < pixmap->drawable.width || 466 height < pixmap->drawable.height)) 467 return true; 468 469 if (priv->gpu_bo) 470 return false; 471 472 return (priv->create & KGEM_CAN_CREATE_GPU) == 0; 473} 474 475static void validate_source(PicturePtr picture) 476{ 477#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,10,99,901,0) 478 miCompositeSourceValidate(picture); 479#else 480 miCompositeSourceValidate(picture, 481 0, 0, 482 picture->pDrawable ? picture->pDrawable->width : 0, 483 picture->pDrawable ? picture->pDrawable->height : 0); 484#endif 485} 486 487void 488sna_composite_fb(CARD8 op, 489 PicturePtr src, 490 PicturePtr mask, 491 PicturePtr dst, 492 RegionPtr region, 493 INT16 src_x, INT16 src_y, 494 INT16 msk_x, INT16 msk_y, 495 INT16 dst_x, INT16 dst_y, 496 CARD16 width, CARD16 height) 497{ 498 pixman_image_t *src_image, *mask_image, *dest_image; 499 int src_xoff, src_yoff; 500 int msk_xoff, msk_yoff; 501 int dst_xoff, dst_yoff; 502 int16_t tx, ty; 503 unsigned flags; 504 505 DBG(("%s -- op=%d, fallback dst=(%d, %d)+(%d, %d), size=(%d, %d): region=((%d,%d), (%d, %d))\n", 506 __FUNCTION__, op, 507 dst_x, dst_y, 508 dst->pDrawable->x, dst->pDrawable->y, 509 width, height, 510 region->extents.x1, region->extents.y1, 511 region->extents.x2, region->extents.y2)); 512 513 if (src->pDrawable) { 514 DBG(("%s: fallback -- move src to cpu\n", __FUNCTION__)); 515 if (!sna_drawable_move_to_cpu(src->pDrawable, 516 MOVE_READ)) 517 return; 518 519 if (src->alphaMap && 520 !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 521 MOVE_READ)) 522 return; 523 } 524 525 validate_source(src); 526 527 if (mask) { 528 if (mask->pDrawable) { 529 DBG(("%s: fallback -- move mask to cpu\n", __FUNCTION__)); 530 if (!sna_drawable_move_to_cpu(mask->pDrawable, 531 MOVE_READ)) 532 return; 533 534 if (mask->alphaMap && 535 !sna_drawable_move_to_cpu(mask->alphaMap->pDrawable, 536 MOVE_READ)) 537 return; 538 } 539 540 validate_source(mask); 541 } 542 543 DBG(("%s: fallback -- move dst to cpu\n", __FUNCTION__)); 544 if (op <= PictOpSrc && !dst->alphaMap) 545 flags = MOVE_WRITE | MOVE_INPLACE_HINT; 546 else 547 flags = MOVE_WRITE | MOVE_READ; 548 if (!sna_drawable_move_region_to_cpu(dst->pDrawable, region, flags)) 549 return; 550 if (dst->alphaMap && 551 !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, flags)) 552 return; 553 554 if (mask == NULL && 555 src->pDrawable && 556 dst->pDrawable->bitsPerPixel >= 8 && 557 src->filter != PictFilterConvolution && 558 (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(src->format))) && 559 (dst->format == src->format || dst->format == alphaless(src->format)) && 560 sna_transform_is_imprecise_integer_translation(src->transform, src->filter, 561 dst->polyMode == PolyModePrecise, 562 &tx, &ty)) { 563 PixmapPtr dst_pixmap = get_drawable_pixmap(dst->pDrawable); 564 PixmapPtr src_pixmap = get_drawable_pixmap(src->pDrawable); 565 int16_t sx = src_x + tx - (dst->pDrawable->x + dst_x); 566 int16_t sy = src_y + ty - (dst->pDrawable->y + dst_y); 567 568 assert(src->pDrawable->bitsPerPixel == dst->pDrawable->bitsPerPixel); 569 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 570 571 if (region->extents.x1 + sx >= 0 && 572 region->extents.y1 + sy >= 0 && 573 region->extents.x2 + sx <= src->pDrawable->width && 574 region->extents.y2 + sy <= src->pDrawable->height) { 575 if (sigtrap_get() == 0) { 576 const BoxRec *box = region_rects(region); 577 int nbox = region_num_rects(region); 578 579 sx += src->pDrawable->x; 580 sy += src->pDrawable->y; 581 if (get_drawable_deltas(src->pDrawable, src_pixmap, &tx, &ty)) 582 sx += tx, sy += ty; 583 584 assert(region->extents.x1 + sx >= 0); 585 assert(region->extents.x2 + sx <= src_pixmap->drawable.width); 586 assert(region->extents.y1 + sy >= 0); 587 assert(region->extents.y2 + sy <= src_pixmap->drawable.height); 588 589 get_drawable_deltas(dst->pDrawable, dst_pixmap, &tx, &ty); 590 591 assert(nbox); 592 do { 593 assert(box->x1 + sx >= 0); 594 assert(box->x2 + sx <= src_pixmap->drawable.width); 595 assert(box->y1 + sy >= 0); 596 assert(box->y2 + sy <= src_pixmap->drawable.height); 597 598 assert(box->x1 + tx >= 0); 599 assert(box->x2 + tx <= dst_pixmap->drawable.width); 600 assert(box->y1 + ty >= 0); 601 assert(box->y2 + ty <= dst_pixmap->drawable.height); 602 603 assert(box->x2 > box->x1 && box->y2 > box->y1); 604 605 sigtrap_assert_active(); 606 memcpy_blt(src_pixmap->devPrivate.ptr, 607 dst_pixmap->devPrivate.ptr, 608 dst_pixmap->drawable.bitsPerPixel, 609 src_pixmap->devKind, 610 dst_pixmap->devKind, 611 box->x1 + sx, box->y1 + sy, 612 box->x1 + tx, box->y1 + ty, 613 box->x2 - box->x1, box->y2 - box->y1); 614 box++; 615 } while (--nbox); 616 sigtrap_put(); 617 } 618 619 return; 620 } 621 } 622 623 src_image = image_from_pict(src, FALSE, &src_xoff, &src_yoff); 624 mask_image = image_from_pict(mask, FALSE, &msk_xoff, &msk_yoff); 625 dest_image = image_from_pict(dst, TRUE, &dst_xoff, &dst_yoff); 626 627 if (src_image && dest_image && !(mask && !mask_image)) 628 sna_image_composite(op, src_image, mask_image, dest_image, 629 src_x + src_xoff, src_y + src_yoff, 630 msk_x + msk_xoff, msk_y + msk_yoff, 631 dst_x + dst_xoff, dst_y + dst_yoff, 632 width, height); 633 634 free_pixman_pict(src, src_image); 635 free_pixman_pict(mask, mask_image); 636 free_pixman_pict(dst, dest_image); 637} 638 639void 640sna_composite(CARD8 op, 641 PicturePtr src, 642 PicturePtr mask, 643 PicturePtr dst, 644 INT16 src_x, INT16 src_y, 645 INT16 mask_x, INT16 mask_y, 646 INT16 dst_x, INT16 dst_y, 647 CARD16 width, CARD16 height) 648{ 649 PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 650 struct sna *sna = to_sna_from_pixmap(pixmap); 651 struct sna_pixmap *priv; 652 struct sna_composite_op tmp; 653 RegionRec region; 654 int dx, dy; 655 656 DBG(("%s(%d src=%ld+(%d, %d), mask=%ld+(%d, %d), dst=%ld+(%d, %d)+(%d, %d), size=(%d, %d)\n", 657 __FUNCTION__, op, 658 get_picture_id(src), src_x, src_y, 659 get_picture_id(mask), mask_x, mask_y, 660 get_picture_id(dst), dst_x, dst_y, 661 dst->pDrawable->x, dst->pDrawable->y, 662 width, height)); 663 664 if (region_is_empty(dst->pCompositeClip)) { 665 DBG(("%s: empty clip, skipping\n", __FUNCTION__)); 666 return; 667 } 668 669 if (op == PictOpClear) { 670 DBG(("%s: discarding source and mask for clear\n", __FUNCTION__)); 671 mask = NULL; 672 if (sna->clear) 673 src = sna->clear; 674 } 675 676 if (mask && sna_composite_mask_is_opaque(mask)) { 677 DBG(("%s: removing opaque %smask\n", 678 __FUNCTION__, 679 mask->componentAlpha && PICT_FORMAT_RGB(mask->format) ? "CA " : "")); 680 mask = NULL; 681 } 682 683 if (!sna_compute_composite_region(®ion, 684 src, mask, dst, 685 src_x, src_y, 686 mask_x, mask_y, 687 dst_x, dst_y, 688 width, height)) 689 return; 690 691 if (NO_COMPOSITE) 692 goto fallback; 693 694 if (wedged(sna)) { 695 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 696 goto fallback; 697 } 698 699 if (!can_render_to_picture(dst)) { 700 DBG(("%s: fallback due to unhandled picture\n", __FUNCTION__)); 701 goto fallback; 702 } 703 704 priv = sna_pixmap(pixmap); 705 if (priv == NULL) { 706 DBG(("%s: fallback as destination pixmap=%ld is unattached\n", 707 __FUNCTION__, pixmap->drawable.serialNumber)); 708 goto fallback; 709 } 710 711 if (use_cpu(pixmap, priv, op, width, height) && 712 !picture_is_gpu(sna, src, PREFER_GPU_RENDER) && 713 !picture_is_gpu(sna, mask, PREFER_GPU_RENDER)) { 714 DBG(("%s: fallback, dst pixmap=%ld is too small (or completely damaged)\n", 715 __FUNCTION__, pixmap->drawable.serialNumber)); 716 goto fallback; 717 } 718 719 dx = region.extents.x1 - (dst_x + dst->pDrawable->x); 720 dy = region.extents.y1 - (dst_y + dst->pDrawable->y); 721 722 DBG(("%s: composite region extents:+(%d, %d) -> (%d, %d), (%d, %d) + (%d, %d)\n", 723 __FUNCTION__, 724 dx, dy, 725 region.extents.x1, region.extents.y1, 726 region.extents.x2, region.extents.y2, 727 get_drawable_dx(dst->pDrawable), 728 get_drawable_dy(dst->pDrawable))); 729 730 if (op <= PictOpSrc && priv->cpu_damage) { 731 int16_t x, y; 732 733 if (get_drawable_deltas(dst->pDrawable, pixmap, &x, &y)) 734 pixman_region_translate(®ion, x, y); 735 736 sna_damage_subtract(&priv->cpu_damage, ®ion); 737 if (priv->cpu_damage == NULL) { 738 list_del(&priv->flush_list); 739 priv->cpu = false; 740 } 741 742 if (x|y) 743 pixman_region_translate(®ion, -x, -y); 744 } 745 746 if (!sna->render.composite(sna, 747 op, src, mask, dst, 748 src_x + dx, src_y + dy, 749 mask_x + dx, mask_y + dy, 750 region.extents.x1, 751 region.extents.y1, 752 region.extents.x2 - region.extents.x1, 753 region.extents.y2 - region.extents.y1, 754 region.data ? COMPOSITE_PARTIAL : 0, 755 memset(&tmp, 0, sizeof(tmp)))) { 756 DBG(("%s: fallback due unhandled composite op\n", __FUNCTION__)); 757 goto fallback; 758 } 759 760 if (region.data == NULL) 761 tmp.box(sna, &tmp, ®ion.extents); 762 else 763 tmp.boxes(sna, &tmp, 764 RegionBoxptr(®ion), 765 region_num_rects(®ion)); 766 apply_damage(&tmp, ®ion); 767 tmp.done(sna, &tmp); 768 769 goto out; 770 771fallback: 772 DBG(("%s: fallback -- fbComposite\n", __FUNCTION__)); 773 sna_composite_fb(op, src, mask, dst, ®ion, 774 src_x, src_y, 775 mask_x, mask_y, 776 dst_x, dst_y, 777 width, height); 778out: 779 REGION_UNINIT(NULL, ®ion); 780} 781 782void 783sna_composite_rectangles(CARD8 op, 784 PicturePtr dst, 785 xRenderColor *color, 786 int num_rects, 787 xRectangle *rects) 788{ 789 struct sna *sna = to_sna_from_drawable(dst->pDrawable); 790 PixmapPtr pixmap; 791 struct sna_pixmap *priv; 792 struct kgem_bo *bo; 793 struct sna_damage **damage; 794 pixman_region16_t region; 795 pixman_box16_t stack_boxes[64], *boxes = stack_boxes, *b; 796 int16_t dst_x, dst_y; 797 int i, num_boxes; 798 unsigned hint; 799 800 DBG(("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n", 801 __FUNCTION__, op, 802 (color->alpha >> 8 << 24) | 803 (color->red >> 8 << 16) | 804 (color->green >> 8 << 8) | 805 (color->blue >> 8 << 0), 806 num_rects, 807 rects[0].x, rects[0].y, rects[0].width, rects[0].height)); 808 809 if (!num_rects) 810 return; 811 812 if (region_is_empty(dst->pCompositeClip)) { 813 DBG(("%s: empty clip, skipping\n", __FUNCTION__)); 814 return; 815 } 816 817 if ((color->red|color->green|color->blue|color->alpha) <= 0x00ff) { 818 switch (op) { 819 case PictOpOver: 820 case PictOpOutReverse: 821 case PictOpAdd: 822 return; 823 case PictOpInReverse: 824 case PictOpSrc: 825 op = PictOpClear; 826 break; 827 case PictOpAtopReverse: 828 op = PictOpOut; 829 break; 830 case PictOpXor: 831 op = PictOpOverReverse; 832 break; 833 } 834 } 835 if (color->alpha <= 0x00ff) { 836 switch (op) { 837 case PictOpOver: 838 case PictOpOutReverse: 839 return; 840 case PictOpInReverse: 841 op = PictOpClear; 842 break; 843 case PictOpAtopReverse: 844 op = PictOpOut; 845 break; 846 case PictOpXor: 847 op = PictOpOverReverse; 848 break; 849 } 850 } else if (color->alpha >= 0xff00) { 851 switch (op) { 852 case PictOpOver: 853 op = PictOpSrc; 854 break; 855 case PictOpInReverse: 856 return; 857 case PictOpOutReverse: 858 op = PictOpClear; 859 break; 860 case PictOpAtopReverse: 861 op = PictOpOverReverse; 862 break; 863 case PictOpXor: 864 op = PictOpOut; 865 break; 866 } 867 } 868 869 /* Avoid reducing overlapping translucent rectangles */ 870 if (op == PictOpOver && 871 num_rects == 1 && 872 sna_drawable_is_clear(dst->pDrawable)) 873 op = PictOpSrc; 874 875 DBG(("%s: converted to op %d\n", __FUNCTION__, op)); 876 877 if (num_rects > ARRAY_SIZE(stack_boxes)) { 878 boxes = malloc(sizeof(pixman_box16_t) * num_rects); 879 if (boxes == NULL) 880 return; 881 } 882 883 for (i = num_boxes = 0; i < num_rects; i++) { 884 boxes[num_boxes].x1 = rects[i].x + dst->pDrawable->x; 885 if (boxes[num_boxes].x1 < dst->pCompositeClip->extents.x1) 886 boxes[num_boxes].x1 = dst->pCompositeClip->extents.x1; 887 888 boxes[num_boxes].y1 = rects[i].y + dst->pDrawable->y; 889 if (boxes[num_boxes].y1 < dst->pCompositeClip->extents.y1) 890 boxes[num_boxes].y1 = dst->pCompositeClip->extents.y1; 891 892 boxes[num_boxes].x2 = bound(rects[i].x + dst->pDrawable->x, rects[i].width); 893 if (boxes[num_boxes].x2 > dst->pCompositeClip->extents.x2) 894 boxes[num_boxes].x2 = dst->pCompositeClip->extents.x2; 895 896 boxes[num_boxes].y2 = bound(rects[i].y + dst->pDrawable->y, rects[i].height); 897 if (boxes[num_boxes].y2 > dst->pCompositeClip->extents.y2) 898 boxes[num_boxes].y2 = dst->pCompositeClip->extents.y2; 899 900 DBG(("%s[%d] (%d, %d)x(%d, %d) -> (%d, %d), (%d, %d)\n", 901 __FUNCTION__, i, 902 rects[i].x, rects[i].y, rects[i].width, rects[i].height, 903 boxes[num_boxes].x1, boxes[num_boxes].y1, boxes[num_boxes].x2, boxes[num_boxes].y2)); 904 905 if (boxes[num_boxes].x2 > boxes[num_boxes].x1 && 906 boxes[num_boxes].y2 > boxes[num_boxes].y1) 907 num_boxes++; 908 } 909 910 if (num_boxes == 0) 911 goto cleanup_boxes; 912 913 if (!pixman_region_init_rects(®ion, boxes, num_boxes)) 914 goto cleanup_boxes; 915 916 DBG(("%s: nrects=%d, region=(%d, %d), (%d, %d) x %d\n", 917 __FUNCTION__, num_rects, 918 region.extents.x1, region.extents.y1, 919 region.extents.x2, region.extents.y2, 920 num_boxes)); 921 922 if (dst->pCompositeClip->data && 923 (!pixman_region_intersect(®ion, ®ion, dst->pCompositeClip) || 924 region_is_empty(®ion))) { 925 DBG(("%s: zero-intersection between rectangles and clip\n", 926 __FUNCTION__)); 927 goto cleanup_region; 928 } 929 930 DBG(("%s: clipped extents (%d, %d),(%d, %d) x %d\n", 931 __FUNCTION__, 932 RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 933 RegionExtents(®ion)->x2, RegionExtents(®ion)->y2, 934 region_num_rects(®ion))); 935 936 /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must 937 * manually append the damaged regions ourselves. 938 * 939 * Note that DamageRegionAppend() will apply the drawable-deltas itself. 940 */ 941 DamageRegionAppend(dst->pDrawable, ®ion); 942 943 pixmap = get_drawable_pixmap(dst->pDrawable); 944 if (get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y)) 945 pixman_region_translate(®ion, dst_x, dst_y); 946 947 DBG(("%s: pixmap +(%d, %d) extents (%d, %d),(%d, %d)\n", 948 __FUNCTION__, dst_x, dst_y, 949 RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 950 RegionExtents(®ion)->x2, RegionExtents(®ion)->y2)); 951 assert_pixmap_contains_box(pixmap, RegionExtents(®ion)); 952 953 if (NO_COMPOSITE_RECTANGLES) 954 goto fallback; 955 956 if (wedged(sna)) 957 goto fallback; 958 959 if (!can_render_to_picture(dst)) { 960 DBG(("%s: fallback, dst has an incompatible picture\n", __FUNCTION__)); 961 goto fallback; 962 } 963 964 priv = sna_pixmap(pixmap); 965 if (priv == NULL || too_small(priv)) { 966 DBG(("%s: fallback, dst pixmap=%ld too small or not attached\n", 967 __FUNCTION__, pixmap->drawable.serialNumber)); 968 goto fallback; 969 } 970 971 /* If we going to be overwriting any CPU damage with a subsequent 972 * operation, then we may as well delete it without moving it 973 * first to the GPU. 974 */ 975 hint = can_render(sna) ? PREFER_GPU : 0; 976 if (op <= PictOpSrc) { 977 if (priv->clear) { 978 uint32_t pixel; 979 bool ok; 980 981 if (op == PictOpClear) { 982 ok = sna_get_pixel_from_rgba(&pixel, 983 0, 0, 0, 0, 984 dst->format); 985 } else { 986 ok = sna_get_pixel_from_rgba(&pixel, 987 color->red, 988 color->green, 989 color->blue, 990 color->alpha, 991 dst->format); 992 } 993 if (ok && priv->clear_color == pixel) 994 goto done; 995 } 996 997 if (region.data == NULL) { 998 hint |= IGNORE_DAMAGE; 999 if (region_subsumes_drawable(®ion, &pixmap->drawable)) 1000 hint |= REPLACES; 1001 if (priv->cpu_damage && 1002 (hint & REPLACES || 1003 region_subsumes_damage(®ion, priv->cpu_damage))) { 1004 DBG(("%s: discarding existing CPU damage\n", __FUNCTION__)); 1005 if (priv->gpu_bo && priv->gpu_bo->proxy) { 1006 assert(priv->gpu_damage == NULL); 1007 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1008 priv->gpu_bo = NULL; 1009 } 1010 sna_damage_destroy(&priv->cpu_damage); 1011 list_del(&priv->flush_list); 1012 } 1013 if (hint & REPLACES || 1014 box_inplace(pixmap, ®ion.extents)) { 1015 if (priv->gpu_bo && priv->cpu_damage == NULL) { 1016 DBG(("%s: promoting to full GPU\n", __FUNCTION__)); 1017 assert(priv->gpu_bo->proxy == NULL); 1018 sna_damage_all(&priv->gpu_damage, pixmap); 1019 } 1020 } 1021 } 1022 if (priv->cpu_damage == NULL) { 1023 DBG(("%s: dropping last-cpu hint\n", __FUNCTION__)); 1024 priv->cpu = false; 1025 } 1026 } 1027 1028 bo = sna_drawable_use_bo(&pixmap->drawable, hint, 1029 ®ion.extents, &damage); 1030 if (bo == NULL) { 1031 DBG(("%s: fallback due to no GPU bo\n", __FUNCTION__)); 1032 goto fallback; 1033 } 1034 if (hint & REPLACES) 1035 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 1036 1037 if (op <= PictOpSrc) { 1038 b = pixman_region_rectangles(®ion, &num_boxes); 1039 if (!sna->render.fill_boxes(sna, op, dst->format, color, 1040 &pixmap->drawable, bo, b, num_boxes)) { 1041 DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); 1042 goto fallback; 1043 } 1044 } else if (dst->pCompositeClip->data == NULL) { 1045 for (i = 0; i < num_boxes; i++) { 1046 boxes[i].x1 += dst_x; 1047 boxes[i].x2 += dst_x; 1048 boxes[i].y1 += dst_y; 1049 boxes[i].y2 += dst_y; 1050 } 1051 if (!sna->render.fill_boxes(sna, op, dst->format, color, 1052 &pixmap->drawable, bo, boxes, num_boxes)) { 1053 DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); 1054 goto fallback; 1055 } 1056 } else { 1057 for (i = 0; i < num_boxes; i++) { 1058 RegionRec tmp = { boxes[i] }; 1059 if (pixman_region_intersect(&tmp, &tmp, dst->pCompositeClip)) { 1060 int n = 0; 1061 1062 b = pixman_region_rectangles(&tmp, &n); 1063 if (n) { 1064 if (dst_x | dst_y) 1065 pixman_region_translate(&tmp, dst_x, dst_y); 1066 1067 n = !sna->render.fill_boxes(sna, op, dst->format, color, 1068 &pixmap->drawable, bo, b, n); 1069 } 1070 1071 pixman_region_fini(&tmp); 1072 1073 if (n) { 1074 DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); 1075 goto fallback; 1076 } 1077 } 1078 } 1079 } 1080 1081 if (damage) 1082 sna_damage_add(damage, ®ion); 1083 1084 /* Clearing a pixmap after creation is a common operation, so take 1085 * advantage and reduce further damage operations. 1086 */ 1087 if (region_subsumes_drawable(®ion, &pixmap->drawable)) { 1088 if (damage) { 1089 sna_damage_all(damage, pixmap); 1090 sna_damage_destroy(damage == &priv->gpu_damage ? 1091 &priv->cpu_damage : &priv->gpu_damage); 1092 } 1093 1094 if (op <= PictOpSrc && bo == priv->gpu_bo) { 1095 bool ok; 1096 1097 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 1098 1099 priv->clear_color = 0; 1100 ok = true; 1101 if (op == PictOpSrc) 1102 ok = sna_get_pixel_from_rgba(&priv->clear_color, 1103 color->red, 1104 color->green, 1105 color->blue, 1106 color->alpha, 1107 dst->format); 1108 priv->clear = ok; 1109 DBG(("%s: pixmap=%ld marking clear [%08x]? %d\n", 1110 __FUNCTION__, pixmap->drawable.serialNumber, 1111 priv->clear_color, ok)); 1112 } 1113 } 1114 goto done; 1115 1116fallback: 1117 DBG(("%s: fallback\n", __FUNCTION__)); 1118 if (op <= PictOpSrc) 1119 hint = MOVE_WRITE; 1120 else 1121 hint = MOVE_WRITE | MOVE_READ; 1122 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, hint)) 1123 goto done; 1124 1125 if (dst->alphaMap && 1126 !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, hint)) 1127 goto done; 1128 1129 assert(pixmap->devPrivate.ptr); 1130 1131 if (sigtrap_get() == 0) { 1132 if (op <= PictOpSrc) { 1133 int nbox = region_num_rects(®ion); 1134 const BoxRec *box = region_rects(®ion); 1135 uint32_t pixel; 1136 1137 if (op == PictOpClear) 1138 pixel = 0; 1139 else if (!sna_get_pixel_from_rgba(&pixel, 1140 color->red, 1141 color->green, 1142 color->blue, 1143 color->alpha, 1144 dst->format)) 1145 goto fallback_composite; 1146 1147 sigtrap_assert_active(); 1148 if (pixel == 0 && 1149 box->x2 - box->x1 == pixmap->drawable.width && 1150 box->y2 - box->y1 == pixmap->drawable.height) { 1151 memset(pixmap->devPrivate.ptr, 0, 1152 pixmap->devKind*pixmap->drawable.height); 1153 } else do { 1154 DBG(("%s: fallback fill: (%d, %d)x(%d, %d) %08x\n", 1155 __FUNCTION__, 1156 box->x1, box->y1, 1157 box->x2 - box->x1, 1158 box->y2 - box->y1, 1159 pixel)); 1160 1161 pixman_fill(pixmap->devPrivate.ptr, 1162 pixmap->devKind/sizeof(uint32_t), 1163 pixmap->drawable.bitsPerPixel, 1164 box->x1, box->y1, 1165 box->x2 - box->x1, 1166 box->y2 - box->y1, 1167 pixel); 1168 box++; 1169 } while (--nbox); 1170 } else { 1171 PicturePtr src; 1172 int error; 1173 1174fallback_composite: 1175 DBG(("%s: fallback -- fbComposite()\n", __FUNCTION__)); 1176 src = CreateSolidPicture(0, color, &error); 1177 if (src) { 1178 do { 1179 fbComposite(op, src, NULL, dst, 1180 0, 0, 1181 0, 0, 1182 rects->x, rects->y, 1183 rects->width, rects->height); 1184 rects++; 1185 } while (--num_rects); 1186 FreePicture(src, 0); 1187 } 1188 } 1189 sigtrap_put(); 1190 } 1191 1192done: 1193 DamageRegionProcessPending(dst->pDrawable); 1194 1195cleanup_region: 1196 pixman_region_fini(®ion); 1197cleanup_boxes: 1198 if (boxes != stack_boxes) 1199 free(boxes); 1200} 1201