1/* 2 * Copyright ® 2001 Keith Packard 3 * 4 * Partly based on code that is Copyright ® The XFree86 Project Inc. 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of Keith Packard not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. Keith Packard makes no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 * 24 * Authors: 25 * Eric Anholt <eric@anholt.net> 26 * Michel Dänzer <michel@tungstengraphics.com> 27 * 28 */ 29 30#ifdef HAVE_DIX_CONFIG_H 31#include <dix-config.h> 32#endif 33#include "uxa-priv.h" 34#include <X11/fonts/fontstruct.h> 35#include "dixfontstr.h" 36#include "uxa.h" 37 38static void 39uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, 40 DDXPointPtr ppt, int *pwidth, int fSorted) 41{ 42 ScreenPtr pScreen = pDrawable->pScreen; 43 uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 44 RegionPtr pClip = fbGetCompositeClip(pGC); 45 PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable); 46 BoxPtr pextent, pbox; 47 int nbox; 48 int extentX1, extentX2, extentY1, extentY2; 49 int fullX1, fullX2, fullY1; 50 int partX1, partX2; 51 int off_x, off_y; 52 53 if (uxa_screen->swappedOut || pGC->fillStyle != FillSolid || 54 !(pPixmap = uxa_get_offscreen_pixmap (pDrawable, &off_x, &off_y)) || 55 !(*uxa_screen->info->prepare_solid) (pPixmap, 56 pGC->alu, 57 pGC->planemask, 58 pGC->fgPixel)) 59 { 60 uxa_check_fill_spans (pDrawable, pGC, n, ppt, pwidth, fSorted); 61 return; 62 } 63 64 pextent = REGION_EXTENTS(pGC->pScreen, pClip); 65 extentX1 = pextent->x1; 66 extentY1 = pextent->y1; 67 extentX2 = pextent->x2; 68 extentY2 = pextent->y2; 69 while (n--) 70 { 71 fullX1 = ppt->x; 72 fullY1 = ppt->y; 73 fullX2 = fullX1 + (int) *pwidth; 74 ppt++; 75 pwidth++; 76 77 if (fullY1 < extentY1 || extentY2 <= fullY1) 78 continue; 79 80 if (fullX1 < extentX1) 81 fullX1 = extentX1; 82 83 if (fullX2 > extentX2) 84 fullX2 = extentX2; 85 86 if (fullX1 >= fullX2) 87 continue; 88 89 nbox = REGION_NUM_RECTS (pClip); 90 if (nbox == 1) 91 { 92 (*uxa_screen->info->solid) (pPixmap, 93 fullX1 + off_x, fullY1 + off_y, 94 fullX2 + off_x, fullY1 + 1 + off_y); 95 } 96 else 97 { 98 pbox = REGION_RECTS(pClip); 99 while(nbox--) 100 { 101 if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) 102 { 103 partX1 = pbox->x1; 104 if (partX1 < fullX1) 105 partX1 = fullX1; 106 partX2 = pbox->x2; 107 if (partX2 > fullX2) 108 partX2 = fullX2; 109 if (partX2 > partX1) { 110 (*uxa_screen->info->solid) (pPixmap, 111 partX1 + off_x, fullY1 + off_y, 112 partX2 + off_x, fullY1 + 1 + off_y); 113 } 114 } 115 pbox++; 116 } 117 } 118 } 119 (*uxa_screen->info->done_solid) (pPixmap); 120} 121 122static Bool 123uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, 124 int w, int h, int format, char *bits, int src_stride) 125{ 126 uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); 127 PixmapPtr pPix = uxa_get_drawable_pixmap (pDrawable); 128 RegionPtr pClip; 129 BoxPtr pbox; 130 int nbox; 131 int xoff, yoff; 132 int bpp = pDrawable->bitsPerPixel; 133 Bool access_prepared = FALSE; 134 135 /* Don't bother with under 8bpp, XYPixmaps. */ 136 if (format != ZPixmap || bpp < 8) 137 return FALSE; 138 139 /* Only accelerate copies: no rop or planemask. */ 140 if (!UXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) 141 return FALSE; 142 143 if (uxa_screen->swappedOut) 144 return FALSE; 145 146 pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); 147 148 if (!pPix || !uxa_screen->info->put_image) 149 return FALSE; 150 151 x += pDrawable->x; 152 y += pDrawable->y; 153 154 pClip = fbGetCompositeClip(pGC); 155 for (nbox = REGION_NUM_RECTS(pClip), 156 pbox = REGION_RECTS(pClip); 157 nbox--; 158 pbox++) 159 { 160 int x1 = x; 161 int y1 = y; 162 int x2 = x + w; 163 int y2 = y + h; 164 char *src; 165 Bool ok; 166 167 if (x1 < pbox->x1) 168 x1 = pbox->x1; 169 if (y1 < pbox->y1) 170 y1 = pbox->y1; 171 if (x2 > pbox->x2) 172 x2 = pbox->x2; 173 if (y2 > pbox->y2) 174 y2 = pbox->y2; 175 if (x1 >= x2 || y1 >= y2) 176 continue; 177 178 src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); 179 ok = uxa_screen->info->put_image(pPix, x1 + xoff, y1 + yoff, 180 x2 - x1, y2 - y1, src, src_stride); 181 /* If we fail to accelerate the upload, fall back to using unaccelerated 182 * fb calls. 183 */ 184 if (!ok) { 185 FbStip *dst; 186 FbStride dst_stride; 187 int dstBpp; 188 int dstXoff, dstYoff; 189 190 if (!access_prepared) { 191 if (!uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) 192 return FALSE; 193 access_prepared = TRUE; 194 } 195 196 fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp, 197 dstXoff, dstYoff); 198 199 fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)), 200 src_stride / sizeof(FbStip), 201 (x1 - x) * dstBpp, 202 dst + (y1 + dstYoff) * dst_stride, 203 dst_stride, 204 (x1 + dstXoff) * dstBpp, 205 (x2 - x1) * dstBpp, 206 y2 - y1, 207 GXcopy, FB_ALLONES, dstBpp); 208 } 209 } 210 211 if (access_prepared) 212 uxa_finish_access(pDrawable); 213 214 return TRUE; 215} 216 217#ifdef MITSHM 218 219#include "xorgVersion.h" 220 221static Bool 222uxa_do_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, 223 unsigned int format, int w, int h, int sx, int sy, int sw, 224 int sh, int dx, int dy, char *data) 225{ 226 int src_stride = PixmapBytePad(w, depth); 227 228 if (uxa_do_put_image(pDrawable, pGC, depth, dx, dy, sw, sh, format, data + 229 sy * src_stride + sx * BitsPerPixel(depth) / 8, 230 src_stride)) 231 return TRUE; 232 233 if (format == ZPixmap) 234 { 235 PixmapPtr pPixmap; 236 237 pPixmap = GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth, 238 BitsPerPixel(depth), PixmapBytePad(w, depth), 239 (pointer)data); 240 if (!pPixmap) 241 return FALSE; 242 243 if (!uxa_prepare_access (pDrawable, UXA_ACCESS_RW)) 244 return FALSE; 245 fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy); 246 uxa_finish_access(pDrawable); 247 248 FreeScratchPixmapHeader(pPixmap); 249 250 return TRUE; 251 } 252 253 return FALSE; 254} 255 256#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0) 257 258/* The actual ShmPutImage isn't wrapped by the damage layer, so we need to 259 * inform any interested parties of the damage incurred to the drawable. 260 * 261 * We also need to set the pending damage to ensure correct migration in all 262 * cases. 263 */ 264void 265uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format, 266 int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, 267 char *data) 268{ 269 if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, 270 dx, dy, data)) { 271 if (!uxa_prepare_access (pDrawable, UXA_ACCESS_RW)) 272 return; 273 fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, 274 data); 275 uxa_finish_access(pDrawable); 276 } 277} 278#else 279#define uxa_shm_put_image NULL 280#endif 281 282ShmFuncs uxa_shm_funcs = { NULL, uxa_shm_put_image }; 283 284#endif 285 286static void 287uxa_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, 288 int w, int h, int leftPad, int format, char *bits) 289{ 290#ifdef MITSHM 291 if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, 0, 0, w, h, x, y, 292 bits)) 293#else 294 if (!uxa_do_put_image(pDrawable, pGC, depth, x, y, w, h, format, bits, 295 PixmapBytePad(w, pDrawable->depth))) 296#endif 297 uxa_check_put_image(pDrawable, pGC, depth, x, y, w, h, leftPad, format, 298 bits); 299} 300 301static Bool inline 302uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, 303 GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) 304{ 305 uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen); 306 PixmapPtr pSrcPixmap, pDstPixmap; 307 int src_off_x, src_off_y, dst_off_x, dst_off_y; 308 int dirsetup; 309 310 /* Need to get both pixmaps to call the driver routines */ 311 pSrcPixmap = uxa_get_offscreen_pixmap (pSrcDrawable, &src_off_x, &src_off_y); 312 pDstPixmap = uxa_get_offscreen_pixmap (pDstDrawable, &dst_off_x, &dst_off_y); 313 if (!pSrcPixmap || !pDstPixmap) 314 return FALSE; 315 316 /* 317 * Now the case of a chip that only supports xdir = ydir = 1 or 318 * xdir = ydir = -1, but we have xdir != ydir. 319 */ 320 dirsetup = 0; /* No direction set up yet. */ 321 for (; nbox; pbox++, nbox--) { 322 if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 323 /* Do a xdir = ydir = -1 blit instead. */ 324 if (dirsetup != -1) { 325 if (dirsetup != 0) 326 uxa_screen->info->done_copy(pDstPixmap); 327 dirsetup = -1; 328 if (!(*uxa_screen->info->prepare_copy)(pSrcPixmap, 329 pDstPixmap, 330 -1, -1, 331 pGC ? pGC->alu : GXcopy, 332 pGC ? pGC->planemask : 333 FB_ALLONES)) 334 return FALSE; 335 } 336 (*uxa_screen->info->copy)(pDstPixmap, 337 src_off_x + pbox->x1 + dx, 338 src_off_y + pbox->y1 + dy, 339 dst_off_x + pbox->x1, 340 dst_off_y + pbox->y1, 341 pbox->x2 - pbox->x1, 342 pbox->y2 - pbox->y1); 343 } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 344 /* Do a xdir = ydir = 1 blit instead. */ 345 if (dirsetup != 1) { 346 if (dirsetup != 0) 347 uxa_screen->info->done_copy(pDstPixmap); 348 dirsetup = 1; 349 if (!(*uxa_screen->info->prepare_copy)(pSrcPixmap, 350 pDstPixmap, 351 1, 1, 352 pGC ? pGC->alu : GXcopy, 353 pGC ? pGC->planemask : 354 FB_ALLONES)) 355 return FALSE; 356 } 357 (*uxa_screen->info->copy)(pDstPixmap, 358 src_off_x + pbox->x1 + dx, 359 src_off_y + pbox->y1 + dy, 360 dst_off_x + pbox->x1, 361 dst_off_y + pbox->y1, 362 pbox->x2 - pbox->x1, 363 pbox->y2 - pbox->y1); 364 } else if (dx >= 0) { 365 /* 366 * xdir = 1, ydir = -1. 367 * Perform line-by-line xdir = ydir = 1 blits, going up. 368 */ 369 int i; 370 if (dirsetup != 1) { 371 if (dirsetup != 0) 372 uxa_screen->info->done_copy(pDstPixmap); 373 dirsetup = 1; 374 if (!(*uxa_screen->info->prepare_copy)(pSrcPixmap, 375 pDstPixmap, 376 1, 1, 377 pGC ? pGC->alu : GXcopy, 378 pGC ? pGC->planemask : 379 FB_ALLONES)) 380 return FALSE; 381 } 382 for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) 383 (*uxa_screen->info->copy)(pDstPixmap, 384 src_off_x + pbox->x1 + dx, 385 src_off_y + pbox->y1 + dy + i, 386 dst_off_x + pbox->x1, 387 dst_off_y + pbox->y1 + i, 388 pbox->x2 - pbox->x1, 1); 389 } else { 390 /* 391 * xdir = -1, ydir = 1. 392 * Perform line-by-line xdir = ydir = -1 blits, going down. 393 */ 394 int i; 395 if (dirsetup != -1) { 396 if (dirsetup != 0) 397 uxa_screen->info->done_copy(pDstPixmap); 398 dirsetup = -1; 399 if (!(*uxa_screen->info->prepare_copy)(pSrcPixmap, 400 pDstPixmap, 401 -1, -1, 402 pGC ? pGC->alu : GXcopy, 403 pGC ? pGC->planemask : 404 FB_ALLONES)) 405 return FALSE; 406 } 407 for (i = 0; i < pbox->y2 - pbox->y1; i++) 408 (*uxa_screen->info->copy)(pDstPixmap, 409 src_off_x + pbox->x1 + dx, 410 src_off_y + pbox->y1 + dy + i, 411 dst_off_x + pbox->x1, 412 dst_off_y + pbox->y1 + i, 413 pbox->x2 - pbox->x1, 1); 414 } 415 } 416 if (dirsetup != 0) 417 uxa_screen->info->done_copy(pDstPixmap); 418 return TRUE; 419} 420 421void 422uxa_copy_n_to_n (DrawablePtr pSrcDrawable, 423 DrawablePtr pDstDrawable, 424 GCPtr pGC, 425 BoxPtr pbox, 426 int nbox, 427 int dx, 428 int dy, 429 Bool reverse, 430 Bool upsidedown, 431 Pixel bitplane, 432 void *closure) 433{ 434 ScreenPtr screen = pDstDrawable->pScreen; 435 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 436 int src_off_x, src_off_y; 437 int dst_off_x, dst_off_y; 438 PixmapPtr pSrcPixmap, pDstPixmap; 439 440 pSrcPixmap = uxa_get_drawable_pixmap (pSrcDrawable); 441 pDstPixmap = uxa_get_drawable_pixmap (pDstDrawable); 442 443 uxa_get_drawable_deltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); 444 uxa_get_drawable_deltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); 445 446 /* Mixed directions must be handled specially if the card is lame */ 447 if ((uxa_screen->info->flags & UXA_TWO_BITBLT_DIRECTIONS) && 448 reverse != upsidedown) { 449 if (uxa_copy_n_to_n_two_dir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, 450 dx, dy)) 451 return; 452 goto fallback; 453 } 454 455 if (!uxa_pixmap_is_offscreen(pSrcPixmap) || 456 !uxa_pixmap_is_offscreen(pDstPixmap) || 457 !(*uxa_screen->info->prepare_copy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, 458 upsidedown ? -1 : 1, 459 pGC ? pGC->alu : GXcopy, 460 pGC ? pGC->planemask : FB_ALLONES)) { 461 goto fallback; 462 } 463 464 while (nbox--) 465 { 466 (*uxa_screen->info->copy) (pDstPixmap, 467 pbox->x1 + dx + src_off_x, 468 pbox->y1 + dy + src_off_y, 469 pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, 470 pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); 471 pbox++; 472 } 473 474 (*uxa_screen->info->done_copy) (pDstPixmap); 475 476 return; 477 478fallback: 479 UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, 480 uxa_drawable_location(pSrcDrawable), 481 uxa_drawable_location(pDstDrawable))); 482 if (uxa_prepare_access (pDstDrawable, UXA_ACCESS_RW)) { 483 if (uxa_prepare_access (pSrcDrawable, UXA_ACCESS_RO)) { 484 fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, 485 reverse, upsidedown, bitplane, closure); 486 uxa_finish_access (pSrcDrawable); 487 } 488 uxa_finish_access (pDstDrawable); 489 } 490} 491 492RegionPtr 493uxa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, 494 int srcx, int srcy, int width, int height, int dstx, int dsty) 495{ 496 uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen); 497 498 if (uxa_screen->swappedOut) { 499 return uxa_check_copy_area(pSrcDrawable, pDstDrawable, pGC, 500 srcx, srcy, width, height, dstx, dsty); 501 } 502 503 return miDoCopy (pSrcDrawable, pDstDrawable, pGC, 504 srcx, srcy, width, height, 505 dstx, dsty, uxa_copy_n_to_n, 0, NULL); 506} 507 508static void 509uxa_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 510 DDXPointPtr ppt) 511{ 512 int i; 513 xRectangle *prect; 514 515 /* If we can't reuse the current GC as is, don't bother accelerating the 516 * points. 517 */ 518 if (pGC->fillStyle != FillSolid) { 519 uxa_check_poly_point(pDrawable, pGC, mode, npt, ppt); 520 return; 521 } 522 523 prect = xalloc(sizeof(xRectangle) * npt); 524 if (!prect) 525 return; 526 for (i = 0; i < npt; i++) { 527 prect[i].x = ppt[i].x; 528 prect[i].y = ppt[i].y; 529 if (i > 0 && mode == CoordModePrevious) { 530 prect[i].x += prect[i - 1].x; 531 prect[i].y += prect[i - 1].y; 532 } 533 prect[i].width = 1; 534 prect[i].height = 1; 535 } 536 pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); 537 xfree(prect); 538} 539 540/** 541 * uxa_poly_lines() checks if it can accelerate the lines as a group of 542 * horizontal or vertical lines (rectangles), and uses existing rectangle fill 543 * acceleration if so. 544 */ 545static void 546uxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 547 DDXPointPtr ppt) 548{ 549 xRectangle *prect; 550 int x1, x2, y1, y2; 551 int i; 552 553 /* Don't try to do wide lines or non-solid fill style. */ 554 if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 555 pGC->fillStyle != FillSolid) { 556 uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt); 557 return; 558 } 559 560 prect = xalloc(sizeof(xRectangle) * (npt - 1)); 561 if (!prect) 562 return; 563 x1 = ppt[0].x; 564 y1 = ppt[0].y; 565 /* If we have any non-horizontal/vertical, fall back. */ 566 for (i = 0; i < npt - 1; i++) { 567 if (mode == CoordModePrevious) { 568 x2 = x1 + ppt[i + 1].x; 569 y2 = y1 + ppt[i + 1].y; 570 } else { 571 x2 = ppt[i + 1].x; 572 y2 = ppt[i + 1].y; 573 } 574 575 if (x1 != x2 && y1 != y2) { 576 xfree(prect); 577 uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt); 578 return; 579 } 580 581 if (x1 < x2) { 582 prect[i].x = x1; 583 prect[i].width = x2 - x1 + 1; 584 } else { 585 prect[i].x = x2; 586 prect[i].width = x1 - x2 + 1; 587 } 588 if (y1 < y2) { 589 prect[i].y = y1; 590 prect[i].height = y2 - y1 + 1; 591 } else { 592 prect[i].y = y2; 593 prect[i].height = y1 - y2 + 1; 594 } 595 596 x1 = x2; 597 y1 = y2; 598 } 599 pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); 600 xfree(prect); 601} 602 603/** 604 * uxa_poly_segment() checks if it can accelerate the lines as a group of 605 * horizontal or vertical lines (rectangles), and uses existing rectangle fill 606 * acceleration if so. 607 */ 608static void 609uxa_poly_segment (DrawablePtr pDrawable, GCPtr pGC, int nseg, 610 xSegment *pSeg) 611{ 612 xRectangle *prect; 613 int i; 614 615 /* Don't try to do wide lines or non-solid fill style. */ 616 if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 617 pGC->fillStyle != FillSolid) 618 { 619 uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg); 620 return; 621 } 622 623 /* If we have any non-horizontal/vertical, fall back. */ 624 for (i = 0; i < nseg; i++) { 625 if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { 626 uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg); 627 return; 628 } 629 } 630 631 prect = xalloc(sizeof(xRectangle) * nseg); 632 if (!prect) 633 return; 634 for (i = 0; i < nseg; i++) { 635 if (pSeg[i].x1 < pSeg[i].x2) { 636 prect[i].x = pSeg[i].x1; 637 prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; 638 } else { 639 prect[i].x = pSeg[i].x2; 640 prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; 641 } 642 if (pSeg[i].y1 < pSeg[i].y2) { 643 prect[i].y = pSeg[i].y1; 644 prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; 645 } else { 646 prect[i].y = pSeg[i].y2; 647 prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; 648 } 649 650 /* don't paint last pixel */ 651 if (pGC->capStyle == CapNotLast) { 652 if (prect[i].width == 1) 653 prect[i].height--; 654 else 655 prect[i].width--; 656 } 657 } 658 pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); 659 xfree(prect); 660} 661 662static Bool uxa_fill_region_solid (DrawablePtr pDrawable, RegionPtr pRegion, 663 Pixel pixel, CARD32 planemask, CARD32 alu); 664 665static void 666uxa_poly_fill_rect(DrawablePtr pDrawable, 667 GCPtr pGC, 668 int nrect, 669 xRectangle *prect) 670{ 671 uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); 672 RegionPtr pClip = fbGetCompositeClip(pGC); 673 PixmapPtr pPixmap = uxa_get_drawable_pixmap(pDrawable); 674 register BoxPtr pbox; 675 BoxPtr pextent; 676 int extentX1, extentX2, extentY1, extentY2; 677 int fullX1, fullX2, fullY1, fullY2; 678 int partX1, partX2, partY1, partY2; 679 int xoff, yoff; 680 int xorg, yorg; 681 int n; 682 RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); 683 684 /* Compute intersection of rects and clip region */ 685 REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); 686 REGION_INTERSECT(pScreen, pReg, pClip, pReg); 687 688 if (!REGION_NUM_RECTS(pReg)) 689 goto out; 690 691 uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); 692 693 if (uxa_screen->swappedOut) 694 goto fallback; 695 696 /* For ROPs where overlaps don't matter, convert rectangles to region and 697 * call uxa_fill_region_{solid,tiled}. 698 */ 699 if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && 700 (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || 701 pGC->alu == GXnoop || pGC->alu == GXcopyInverted || 702 pGC->alu == GXset)) { 703 if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && 704 uxa_fill_region_solid(pDrawable, pReg, pGC->fillStyle == FillSolid ? 705 pGC->fgPixel : pGC->tile.pixel, pGC->planemask, 706 pGC->alu)) || 707 (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && 708 uxa_fill_region_tiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, 709 pGC->planemask, pGC->alu))) { 710 goto out; 711 } 712 } 713 714 if (pGC->fillStyle != FillSolid && 715 !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) 716 { 717 goto fallback; 718 } 719 720 if (!uxa_pixmap_is_offscreen (pPixmap) || 721 !(*uxa_screen->info->prepare_solid) (pPixmap, 722 pGC->alu, 723 pGC->planemask, 724 pGC->fgPixel)) 725 { 726fallback: 727 uxa_check_poly_fill_rect (pDrawable, pGC, nrect, prect); 728 goto out; 729 } 730 731 xorg = pDrawable->x; 732 yorg = pDrawable->y; 733 734 pextent = REGION_EXTENTS(pGC->pScreen, pClip); 735 extentX1 = pextent->x1; 736 extentY1 = pextent->y1; 737 extentX2 = pextent->x2; 738 extentY2 = pextent->y2; 739 while (nrect--) 740 { 741 fullX1 = prect->x + xorg; 742 fullY1 = prect->y + yorg; 743 fullX2 = fullX1 + (int) prect->width; 744 fullY2 = fullY1 + (int) prect->height; 745 prect++; 746 747 if (fullX1 < extentX1) 748 fullX1 = extentX1; 749 750 if (fullY1 < extentY1) 751 fullY1 = extentY1; 752 753 if (fullX2 > extentX2) 754 fullX2 = extentX2; 755 756 if (fullY2 > extentY2) 757 fullY2 = extentY2; 758 759 if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) 760 continue; 761 n = REGION_NUM_RECTS (pClip); 762 if (n == 1) 763 { 764 (*uxa_screen->info->solid) (pPixmap, 765 fullX1 + xoff, fullY1 + yoff, 766 fullX2 + xoff, fullY2 + yoff); 767 } 768 else 769 { 770 pbox = REGION_RECTS(pClip); 771 /* 772 * clip the rectangle to each box in the clip region 773 * this is logically equivalent to calling Intersect(), 774 * but rectangles may overlap each other here. 775 */ 776 while(n--) 777 { 778 partX1 = pbox->x1; 779 if (partX1 < fullX1) 780 partX1 = fullX1; 781 partY1 = pbox->y1; 782 if (partY1 < fullY1) 783 partY1 = fullY1; 784 partX2 = pbox->x2; 785 if (partX2 > fullX2) 786 partX2 = fullX2; 787 partY2 = pbox->y2; 788 if (partY2 > fullY2) 789 partY2 = fullY2; 790 791 pbox++; 792 793 if (partX1 < partX2 && partY1 < partY2) { 794 (*uxa_screen->info->solid) (pPixmap, 795 partX1 + xoff, partY1 + yoff, 796 partX2 + xoff, partY2 + yoff); 797 } 798 } 799 } 800 } 801 (*uxa_screen->info->done_solid) (pPixmap); 802 803out: 804 REGION_UNINIT(pScreen, pReg); 805 REGION_DESTROY(pScreen, pReg); 806} 807 808const GCOps uxa_ops = { 809 uxa_fill_spans, 810 uxa_check_set_spans, 811 uxa_put_image, 812 uxa_copy_area, 813 uxa_check_copy_plane, 814 uxa_poly_point, 815 uxa_poly_lines, 816 uxa_poly_segment, 817 miPolyRectangle, 818 uxa_check_poly_arc, 819 miFillPolygon, 820 uxa_poly_fill_rect, 821 miPolyFillArc, 822 miPolyText8, 823 miPolyText16, 824 miImageText8, 825 miImageText16, 826 uxa_check_image_glyph_blt, 827 uxa_check_poly_glyph_blt, 828 uxa_check_push_pixels, 829}; 830 831void 832uxa_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 833{ 834 RegionRec rgnDst; 835 int dx, dy; 836 PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); 837 838 dx = ptOldOrg.x - pWin->drawable.x; 839 dy = ptOldOrg.y - pWin->drawable.y; 840 REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); 841 842 REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); 843 844 REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); 845#ifdef COMPOSITE 846 if (pPixmap->screen_x || pPixmap->screen_y) 847 REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, 848 -pPixmap->screen_x, -pPixmap->screen_y); 849#endif 850 851 miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, 852 NULL, 853 &rgnDst, dx, dy, uxa_copy_n_to_n, 0, NULL); 854 855 REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); 856} 857 858static Bool 859uxa_fill_region_solid (DrawablePtr pDrawable, 860 RegionPtr pRegion, 861 Pixel pixel, 862 CARD32 planemask, 863 CARD32 alu) 864{ 865 uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); 866 PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable); 867 int xoff, yoff; 868 Bool ret = FALSE; 869 870 uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); 871 REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); 872 873 if (uxa_pixmap_is_offscreen (pPixmap) && 874 (*uxa_screen->info->prepare_solid) (pPixmap, alu, planemask, pixel)) 875 { 876 int nbox; 877 BoxPtr pBox; 878 879 nbox = REGION_NUM_RECTS (pRegion); 880 pBox = REGION_RECTS (pRegion); 881 882 while (nbox--) 883 { 884 (*uxa_screen->info->solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, 885 pBox->y2); 886 pBox++; 887 } 888 (*uxa_screen->info->done_solid) (pPixmap); 889 890 ret = TRUE; 891 } 892 893 REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); 894 895 return ret; 896} 897 898/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. 899 * Based on fbFillRegionTiled(), fbTile(). 900 */ 901Bool 902uxa_fill_region_tiled (DrawablePtr pDrawable, 903 RegionPtr pRegion, 904 PixmapPtr pTile, 905 DDXPointPtr pPatOrg, 906 CARD32 planemask, 907 CARD32 alu) 908{ 909 uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); 910 PixmapPtr pPixmap; 911 int xoff, yoff; 912 int tileWidth, tileHeight; 913 int nbox = REGION_NUM_RECTS (pRegion); 914 BoxPtr pBox = REGION_RECTS (pRegion); 915 Bool ret = FALSE; 916 917 tileWidth = pTile->drawable.width; 918 tileHeight = pTile->drawable.height; 919 920 /* If we're filling with a solid color, grab it out and go to 921 * FillRegionsolid, saving numerous copies. 922 */ 923 if (tileWidth == 1 && tileHeight == 1) 924 return uxa_fill_region_solid(pDrawable, pRegion, 925 uxa_get_pixmap_first_pixel (pTile), planemask, 926 alu); 927 928 pPixmap = uxa_get_drawable_pixmap (pDrawable); 929 uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); 930 REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); 931 932 pPixmap = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); 933 934 if (!pPixmap || !uxa_pixmap_is_offscreen(pTile)) 935 goto out; 936 937 if ((*uxa_screen->info->prepare_copy) (pTile, pPixmap, 1, 1, alu, planemask)) 938 { 939 while (nbox--) 940 { 941 int height = pBox->y2 - pBox->y1; 942 int dstY = pBox->y1; 943 int tileY; 944 945 modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); 946 947 while (height > 0) { 948 int width = pBox->x2 - pBox->x1; 949 int dstX = pBox->x1; 950 int tileX; 951 int h = tileHeight - tileY; 952 953 if (h > height) 954 h = height; 955 height -= h; 956 957 modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, 958 tileX); 959 960 while (width > 0) { 961 int w = tileWidth - tileX; 962 if (w > width) 963 w = width; 964 width -= w; 965 966 (*uxa_screen->info->copy) (pPixmap, tileX, tileY, dstX, dstY, 967 w, h); 968 dstX += w; 969 tileX = 0; 970 } 971 dstY += h; 972 tileY = 0; 973 } 974 pBox++; 975 } 976 (*uxa_screen->info->done_copy) (pPixmap); 977 978 ret = TRUE; 979 } 980 981out: 982 REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); 983 984 return ret; 985} 986 987/** 988 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. 989 * 990 * This is probably the only case we actually care about. The rest fall through 991 * to migration and fbGetImage, which hopefully will result in migration pushing 992 * the pixmap out of framebuffer. 993 */ 994void 995uxa_get_image (DrawablePtr pDrawable, int x, int y, int w, int h, 996 unsigned int format, unsigned long planeMask, char *d) 997{ 998 ScreenPtr screen = pDrawable->pScreen; 999 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 1000 BoxRec Box; 1001 PixmapPtr pPix = uxa_get_drawable_pixmap (pDrawable); 1002 int xoff, yoff; 1003 Bool ok; 1004 1005 uxa_get_drawable_deltas (pDrawable, pPix, &xoff, &yoff); 1006 1007 Box.x1 = pDrawable->y + x + xoff; 1008 Box.y1 = pDrawable->y + y + yoff; 1009 Box.x2 = Box.x1 + w; 1010 Box.y2 = Box.y1 + h; 1011 1012 if (uxa_screen->swappedOut) 1013 goto fallback; 1014 1015 pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); 1016 1017 if (pPix == NULL || uxa_screen->info->get_image == NULL) 1018 goto fallback; 1019 1020 /* Only cover the ZPixmap, solid copy case. */ 1021 if (format != ZPixmap || !UXA_PM_IS_SOLID(pDrawable, planeMask)) 1022 goto fallback; 1023 1024 /* Only try to handle the 8bpp and up cases, since we don't want to think 1025 * about <8bpp. 1026 */ 1027 if (pDrawable->bitsPerPixel < 8) 1028 goto fallback; 1029 1030 ok = uxa_screen->info->get_image(pPix, pDrawable->x + x + xoff, 1031 pDrawable->y + y + yoff, w, h, d, 1032 PixmapBytePad(w, pDrawable->depth)); 1033 if (ok) 1034 return; 1035 1036fallback: 1037 UXA_FALLBACK(("from %p (%c)\n", pDrawable, 1038 uxa_drawable_location(pDrawable))); 1039 1040 if (uxa_prepare_access (pDrawable, UXA_ACCESS_RO)) { 1041 fbGetImage (pDrawable, x, y, w, h, format, planeMask, d); 1042 uxa_finish_access (pDrawable); 1043 } 1044 1045 return; 1046} 1047