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