xwayland: Add xdg-system-bell support
[xserver.git] / exa / exa_accel.c
blob92211964f37f1573adbdac179b5138785230a3dd
1 /*
2 * Copyright © 2001 Keith Packard
4 * Partly based on code that is Copyright © The XFree86 Project Inc.
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.
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.
24 * Authors:
25 * Eric Anholt <eric@anholt.net>
26 * Michel Dänzer <michel@tungstengraphics.com>
30 #include <dix-config.h>
31 #include "exa_priv.h"
32 #include <X11/fonts/fontstruct.h>
33 #include "dixfontstr.h"
34 #include "exa.h"
36 static void
37 exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
38 DDXPointPtr ppt, int *pwidth, int fSorted)
40 ScreenPtr pScreen = pDrawable->pScreen;
42 ExaScreenPriv(pScreen);
43 RegionPtr pClip = fbGetCompositeClip(pGC);
44 PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
46 ExaPixmapPriv(pPixmap);
47 BoxPtr pextent, pbox;
48 int nbox;
49 int extentX1, extentX2, extentY1, extentY2;
50 int fullX1, fullX2, fullY1;
51 int partX1, partX2;
52 int off_x, off_y;
54 if (pExaScr->fallback_counter ||
55 pExaScr->swappedOut ||
56 pGC->fillStyle != FillSolid || pExaPixmap->accel_blocked) {
57 ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted);
58 return;
61 if (pExaScr->do_migration) {
62 ExaMigrationRec pixmaps[1];
64 pixmaps[0].as_dst = TRUE;
65 pixmaps[0].as_src = FALSE;
66 pixmaps[0].pPix = pPixmap;
67 pixmaps[0].pReg = NULL;
69 exaDoMigration(pixmaps, 1, TRUE);
72 if (!(pPixmap = exaGetOffscreenPixmap(pDrawable, &off_x, &off_y)) ||
73 !(*pExaScr->info->PrepareSolid) (pPixmap,
74 pGC->alu,
75 pGC->planemask, pGC->fgPixel)) {
76 ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted);
77 return;
80 pextent = RegionExtents(pClip);
81 extentX1 = pextent->x1;
82 extentY1 = pextent->y1;
83 extentX2 = pextent->x2;
84 extentY2 = pextent->y2;
85 while (n--) {
86 fullX1 = ppt->x;
87 fullY1 = ppt->y;
88 fullX2 = fullX1 + (int) *pwidth;
89 ppt++;
90 pwidth++;
92 if (fullY1 < extentY1 || extentY2 <= fullY1)
93 continue;
95 if (fullX1 < extentX1)
96 fullX1 = extentX1;
98 if (fullX2 > extentX2)
99 fullX2 = extentX2;
101 if (fullX1 >= fullX2)
102 continue;
104 nbox = RegionNumRects(pClip);
105 if (nbox == 1) {
106 (*pExaScr->info->Solid) (pPixmap,
107 fullX1 + off_x, fullY1 + off_y,
108 fullX2 + off_x, fullY1 + 1 + off_y);
110 else {
111 pbox = RegionRects(pClip);
112 while (nbox--) {
113 if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) {
114 partX1 = pbox->x1;
115 if (partX1 < fullX1)
116 partX1 = fullX1;
117 partX2 = pbox->x2;
118 if (partX2 > fullX2)
119 partX2 = fullX2;
120 if (partX2 > partX1) {
121 (*pExaScr->info->Solid) (pPixmap,
122 partX1 + off_x, fullY1 + off_y,
123 partX2 + off_x,
124 fullY1 + 1 + off_y);
127 pbox++;
131 (*pExaScr->info->DoneSolid) (pPixmap);
132 exaMarkSync(pScreen);
135 static Bool
136 exaDoPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
137 int w, int h, int format, char *bits, int src_stride)
139 ExaScreenPriv(pDrawable->pScreen);
140 PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
142 ExaPixmapPriv(pPix);
143 RegionPtr pClip;
144 BoxPtr pbox;
145 int nbox;
146 int xoff, yoff;
147 int bpp = pDrawable->bitsPerPixel;
148 Bool ret = TRUE;
150 if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
151 !pExaScr->info->UploadToScreen)
152 return FALSE;
154 /* If there's a system copy, we want to save the result there */
155 if (pExaPixmap->pDamage)
156 return FALSE;
158 /* Don't bother with under 8bpp, XYPixmaps. */
159 if (format != ZPixmap || bpp < 8)
160 return FALSE;
162 /* Only accelerate copies: no rop or planemask. */
163 if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
164 return FALSE;
166 if (pExaScr->swappedOut)
167 return FALSE;
169 if (pExaScr->do_migration) {
170 ExaMigrationRec pixmaps[1];
172 pixmaps[0].as_dst = TRUE;
173 pixmaps[0].as_src = FALSE;
174 pixmaps[0].pPix = pPix;
175 pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
177 exaDoMigration(pixmaps, 1, TRUE);
180 pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);
182 if (!pPix)
183 return FALSE;
185 x += pDrawable->x;
186 y += pDrawable->y;
188 pClip = fbGetCompositeClip(pGC);
189 for (nbox = RegionNumRects(pClip),
190 pbox = RegionRects(pClip); nbox--; pbox++) {
191 int x1 = x;
192 int y1 = y;
193 int x2 = x + w;
194 int y2 = y + h;
195 char *src;
196 Bool ok;
198 if (x1 < pbox->x1)
199 x1 = pbox->x1;
200 if (y1 < pbox->y1)
201 y1 = pbox->y1;
202 if (x2 > pbox->x2)
203 x2 = pbox->x2;
204 if (y2 > pbox->y2)
205 y2 = pbox->y2;
206 if (x1 >= x2 || y1 >= y2)
207 continue;
209 src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
210 ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
211 x2 - x1, y2 - y1, src, src_stride);
212 /* We have to fall back completely, and ignore what has already been completed.
213 * Messing with the fb layer directly like we used to is completely unacceptable.
215 if (!ok) {
216 ret = FALSE;
217 break;
221 if (ret)
222 exaMarkSync(pDrawable->pScreen);
224 return ret;
227 static void
228 exaPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
229 int w, int h, int leftPad, int format, char *bits)
231 if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
232 PixmapBytePad(w, pDrawable->depth)))
233 ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
234 bits);
237 static Bool inline
238 exaCopyNtoNTwoDir(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
239 GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
241 ExaScreenPriv(pDstDrawable->pScreen);
242 PixmapPtr pSrcPixmap, pDstPixmap;
243 int src_off_x, src_off_y, dst_off_x, dst_off_y;
244 int dirsetup;
246 /* Need to get both pixmaps to call the driver routines */
247 pSrcPixmap = exaGetOffscreenPixmap(pSrcDrawable, &src_off_x, &src_off_y);
248 pDstPixmap = exaGetOffscreenPixmap(pDstDrawable, &dst_off_x, &dst_off_y);
249 if (!pSrcPixmap || !pDstPixmap)
250 return FALSE;
253 * Now the case of a chip that only supports xdir = ydir = 1 or
254 * xdir = ydir = -1, but we have xdir != ydir.
256 dirsetup = 0; /* No direction set up yet. */
257 for (; nbox; pbox++, nbox--) {
258 if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
259 /* Do a xdir = ydir = -1 blit instead. */
260 if (dirsetup != -1) {
261 if (dirsetup != 0)
262 pExaScr->info->DoneCopy(pDstPixmap);
263 dirsetup = -1;
264 if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
265 pDstPixmap,
266 -1, -1,
267 pGC ? pGC->alu : GXcopy,
268 pGC ? pGC->planemask :
269 FB_ALLONES))
270 return FALSE;
272 (*pExaScr->info->Copy) (pDstPixmap,
273 src_off_x + pbox->x1 + dx,
274 src_off_y + pbox->y1 + dy,
275 dst_off_x + pbox->x1,
276 dst_off_y + pbox->y1,
277 pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
279 else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
280 /* Do a xdir = ydir = 1 blit instead. */
281 if (dirsetup != 1) {
282 if (dirsetup != 0)
283 pExaScr->info->DoneCopy(pDstPixmap);
284 dirsetup = 1;
285 if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
286 pDstPixmap,
287 1, 1,
288 pGC ? pGC->alu : GXcopy,
289 pGC ? pGC->planemask :
290 FB_ALLONES))
291 return FALSE;
293 (*pExaScr->info->Copy) (pDstPixmap,
294 src_off_x + pbox->x1 + dx,
295 src_off_y + pbox->y1 + dy,
296 dst_off_x + pbox->x1,
297 dst_off_y + pbox->y1,
298 pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
300 else if (dx >= 0) {
302 * xdir = 1, ydir = -1.
303 * Perform line-by-line xdir = ydir = 1 blits, going up.
305 int i;
307 if (dirsetup != 1) {
308 if (dirsetup != 0)
309 pExaScr->info->DoneCopy(pDstPixmap);
310 dirsetup = 1;
311 if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
312 pDstPixmap,
313 1, 1,
314 pGC ? pGC->alu : GXcopy,
315 pGC ? pGC->planemask :
316 FB_ALLONES))
317 return FALSE;
319 for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
320 (*pExaScr->info->Copy) (pDstPixmap,
321 src_off_x + pbox->x1 + dx,
322 src_off_y + pbox->y1 + dy + i,
323 dst_off_x + pbox->x1,
324 dst_off_y + pbox->y1 + i,
325 pbox->x2 - pbox->x1, 1);
327 else {
329 * xdir = -1, ydir = 1.
330 * Perform line-by-line xdir = ydir = -1 blits, going down.
332 int i;
334 if (dirsetup != -1) {
335 if (dirsetup != 0)
336 pExaScr->info->DoneCopy(pDstPixmap);
337 dirsetup = -1;
338 if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap,
339 pDstPixmap,
340 -1, -1,
341 pGC ? pGC->alu : GXcopy,
342 pGC ? pGC->planemask :
343 FB_ALLONES))
344 return FALSE;
346 for (i = 0; i < pbox->y2 - pbox->y1; i++)
347 (*pExaScr->info->Copy) (pDstPixmap,
348 src_off_x + pbox->x1 + dx,
349 src_off_y + pbox->y1 + dy + i,
350 dst_off_x + pbox->x1,
351 dst_off_y + pbox->y1 + i,
352 pbox->x2 - pbox->x1, 1);
355 if (dirsetup != 0)
356 pExaScr->info->DoneCopy(pDstPixmap);
357 exaMarkSync(pDstDrawable->pScreen);
358 return TRUE;
361 Bool
362 exaHWCopyNtoN(DrawablePtr pSrcDrawable,
363 DrawablePtr pDstDrawable,
364 GCPtr pGC,
365 BoxPtr pbox,
366 int nbox, int dx, int dy, Bool reverse, Bool upsidedown)
368 ExaScreenPriv(pDstDrawable->pScreen);
369 PixmapPtr pSrcPixmap, pDstPixmap;
370 ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
371 int src_off_x, src_off_y;
372 int dst_off_x, dst_off_y;
373 RegionPtr srcregion = NULL, dstregion = NULL;
374 xRectangle *rects;
375 Bool ret = TRUE;
377 /* avoid doing copy operations if no boxes */
378 if (nbox == 0)
379 return TRUE;
381 pSrcPixmap = exaGetDrawablePixmap(pSrcDrawable);
382 pDstPixmap = exaGetDrawablePixmap(pDstDrawable);
384 exaGetDrawableDeltas(pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
385 exaGetDrawableDeltas(pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
387 rects = xallocarray(nbox, sizeof(xRectangle));
389 if (rects) {
390 int i;
391 int ordering;
393 for (i = 0; i < nbox; i++) {
394 rects[i].x = pbox[i].x1 + dx + src_off_x;
395 rects[i].y = pbox[i].y1 + dy + src_off_y;
396 rects[i].width = pbox[i].x2 - pbox[i].x1;
397 rects[i].height = pbox[i].y2 - pbox[i].y1;
400 /* This must match the RegionCopy() logic for reversing rect order */
401 if (nbox == 1 || (dx > 0 && dy > 0) ||
402 (pDstDrawable != pSrcDrawable &&
403 (pDstDrawable->type != DRAWABLE_WINDOW ||
404 pSrcDrawable->type != DRAWABLE_WINDOW)))
405 ordering = CT_YXBANDED;
406 else
407 ordering = CT_UNSORTED;
409 srcregion = RegionFromRects(nbox, rects, ordering);
410 free(rects);
412 if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
413 pGC->fillStyle, pGC->alu,
414 pGC->clientClip != NULL)) {
415 dstregion = RegionCreate(NullBox, 0);
416 RegionCopy(dstregion, srcregion);
417 RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
418 dst_off_y - dy - src_off_y);
422 pSrcExaPixmap = ExaGetPixmapPriv(pSrcPixmap);
423 pDstExaPixmap = ExaGetPixmapPriv(pDstPixmap);
425 /* Check whether the accelerator can use this pixmap.
426 * If the pitch of the pixmaps is out of range, there's nothing
427 * we can do but fall back to software rendering.
429 if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
430 pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
431 goto fallback;
433 /* If the width or the height of either of the pixmaps
434 * is out of range, check whether the boxes are actually out of the
435 * addressable range as well. If they aren't, we can still do
436 * the copying in hardware.
438 if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
439 int i;
441 for (i = 0; i < nbox; i++) {
442 /* src */
443 if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
444 (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
445 goto fallback;
447 /* dst */
448 if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
449 (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
450 goto fallback;
454 if (pExaScr->do_migration) {
455 ExaMigrationRec pixmaps[2];
457 pixmaps[0].as_dst = TRUE;
458 pixmaps[0].as_src = FALSE;
459 pixmaps[0].pPix = pDstPixmap;
460 pixmaps[0].pReg = dstregion;
461 pixmaps[1].as_dst = FALSE;
462 pixmaps[1].as_src = TRUE;
463 pixmaps[1].pPix = pSrcPixmap;
464 pixmaps[1].pReg = srcregion;
466 exaDoMigration(pixmaps, 2, TRUE);
469 /* Mixed directions must be handled specially if the card is lame */
470 if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
471 reverse != upsidedown) {
472 if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
473 dx, dy))
474 goto out;
475 goto fallback;
478 if (exaPixmapHasGpuCopy(pDstPixmap)) {
479 /* Normal blitting. */
480 if (exaPixmapHasGpuCopy(pSrcPixmap)) {
481 if (!(*pExaScr->info->PrepareCopy)
482 (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, upsidedown ? -1 : 1,
483 pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) {
484 goto fallback;
487 while (nbox--) {
488 (*pExaScr->info->Copy) (pDstPixmap,
489 pbox->x1 + dx + src_off_x,
490 pbox->y1 + dy + src_off_y,
491 pbox->x1 + dst_off_x,
492 pbox->y1 + dst_off_y,
493 pbox->x2 - pbox->x1,
494 pbox->y2 - pbox->y1);
495 pbox++;
498 (*pExaScr->info->DoneCopy) (pDstPixmap);
499 exaMarkSync(pDstDrawable->pScreen);
500 /* UTS: mainly for SHM PutImage's secondary path.
502 * Only taking this path for directly accessible pixmaps.
505 else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
506 int bpp = pSrcDrawable->bitsPerPixel;
507 int src_stride = exaGetPixmapPitch(pSrcPixmap);
508 CARD8 *src = NULL;
510 if (!pExaScr->info->UploadToScreen)
511 goto fallback;
513 if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
514 goto fallback;
516 if (pSrcDrawable->bitsPerPixel < 8)
517 goto fallback;
519 if (pGC &&
520 !(pGC->alu == GXcopy &&
521 EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask)))
522 goto fallback;
524 while (nbox--) {
525 src =
526 pSrcExaPixmap->sys_ptr + (pbox->y1 + dy +
527 src_off_y) * src_stride +
528 (pbox->x1 + dx + src_off_x) * (bpp / 8);
529 if (!pExaScr->info->
530 UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
531 pbox->y1 + dst_off_y, pbox->x2 - pbox->x1,
532 pbox->y2 - pbox->y1, (char *) src,
533 src_stride))
534 goto fallback;
536 pbox++;
539 else
540 goto fallback;
542 else
543 goto fallback;
545 goto out;
547 fallback:
548 ret = FALSE;
550 out:
551 if (dstregion) {
552 RegionUninit(dstregion);
553 RegionDestroy(dstregion);
555 if (srcregion) {
556 RegionUninit(srcregion);
557 RegionDestroy(srcregion);
560 return ret;
563 void
564 exaCopyNtoN(DrawablePtr pSrcDrawable,
565 DrawablePtr pDstDrawable,
566 GCPtr pGC,
567 BoxPtr pbox,
568 int nbox,
569 int dx,
570 int dy,
571 Bool reverse, Bool upsidedown, Pixel bitplane, void *closure)
573 ExaScreenPriv(pDstDrawable->pScreen);
575 if (pExaScr->fallback_counter ||
576 (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW))
577 return;
579 if (exaHWCopyNtoN
580 (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse,
581 upsidedown))
582 return;
584 /* This is a CopyWindow, it's cleaner to fallback at the original call. */
585 if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) {
586 pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
587 return;
590 /* fallback */
591 ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy,
592 reverse, upsidedown, bitplane, closure);
595 RegionPtr
596 exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
597 int srcx, int srcy, int width, int height, int dstx, int dsty)
599 ExaScreenPriv(pDstDrawable->pScreen);
601 if (pExaScr->fallback_counter || pExaScr->swappedOut) {
602 return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
603 srcx, srcy, width, height, dstx, dsty);
606 return miDoCopy(pSrcDrawable, pDstDrawable, pGC,
607 srcx, srcy, width, height,
608 dstx, dsty, exaCopyNtoN, 0, NULL);
611 static void
612 exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
613 DDXPointPtr ppt)
615 ExaScreenPriv(pDrawable->pScreen);
616 int i;
617 xRectangle *prect;
619 /* If we can't reuse the current GC as is, don't bother accelerating the
620 * points.
622 if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) {
623 ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
624 return;
627 prect = xallocarray(npt, sizeof(xRectangle));
628 for (i = 0; i < npt; i++) {
629 prect[i].x = ppt[i].x;
630 prect[i].y = ppt[i].y;
631 if (i > 0 && mode == CoordModePrevious) {
632 prect[i].x += prect[i - 1].x;
633 prect[i].y += prect[i - 1].y;
635 prect[i].width = 1;
636 prect[i].height = 1;
638 pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
639 free(prect);
643 * exaPolylines() checks if it can accelerate the lines as a group of
644 * horizontal or vertical lines (rectangles), and uses existing rectangle fill
645 * acceleration if so.
647 static void
648 exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
649 DDXPointPtr ppt)
651 ExaScreenPriv(pDrawable->pScreen);
652 xRectangle *prect;
653 int x1, x2, y1, y2;
654 int i;
656 if (pExaScr->fallback_counter) {
657 ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
658 return;
661 /* Don't try to do wide lines or non-solid fill style. */
662 if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
663 pGC->fillStyle != FillSolid) {
664 ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
665 return;
668 prect = xallocarray(npt - 1, sizeof(xRectangle));
669 x1 = ppt[0].x;
670 y1 = ppt[0].y;
671 /* If we have any non-horizontal/vertical, fall back. */
672 for (i = 0; i < npt - 1; i++) {
673 if (mode == CoordModePrevious) {
674 x2 = x1 + ppt[i + 1].x;
675 y2 = y1 + ppt[i + 1].y;
677 else {
678 x2 = ppt[i + 1].x;
679 y2 = ppt[i + 1].y;
682 if (x1 != x2 && y1 != y2) {
683 free(prect);
684 ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
685 return;
688 if (x1 < x2) {
689 prect[i].x = x1;
690 prect[i].width = x2 - x1 + 1;
692 else {
693 prect[i].x = x2;
694 prect[i].width = x1 - x2 + 1;
696 if (y1 < y2) {
697 prect[i].y = y1;
698 prect[i].height = y2 - y1 + 1;
700 else {
701 prect[i].y = y2;
702 prect[i].height = y1 - y2 + 1;
705 x1 = x2;
706 y1 = y2;
708 pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
709 free(prect);
713 * exaPolySegment() checks if it can accelerate the lines as a group of
714 * horizontal or vertical lines (rectangles), and uses existing rectangle fill
715 * acceleration if so.
717 static void
718 exaPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg)
720 ExaScreenPriv(pDrawable->pScreen);
721 xRectangle *prect;
722 int i;
724 /* Don't try to do wide lines or non-solid fill style. */
725 if (pExaScr->fallback_counter || pGC->lineWidth != 0 ||
726 pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) {
727 ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
728 return;
731 /* If we have any non-horizontal/vertical, fall back. */
732 for (i = 0; i < nseg; i++) {
733 if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
734 ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
735 return;
739 prect = xallocarray((unsigned int)nseg, sizeof(xRectangle));
740 for (i = 0; i < nseg; i++) {
741 if (pSeg[i].x1 < pSeg[i].x2) {
742 prect[i].x = pSeg[i].x1;
743 prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
745 else {
746 prect[i].x = pSeg[i].x2;
747 prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
749 if (pSeg[i].y1 < pSeg[i].y2) {
750 prect[i].y = pSeg[i].y1;
751 prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
753 else {
754 prect[i].y = pSeg[i].y2;
755 prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
758 /* don't paint last pixel */
759 if (pGC->capStyle == CapNotLast) {
760 if (prect[i].width == 1)
761 prect[i].height--;
762 else
763 prect[i].width--;
766 pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
767 free(prect);
770 static Bool exaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion,
771 Pixel pixel, CARD32 planemask, CARD32 alu,
772 Bool hasClientClip);
774 static void
775 exaPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect)
777 ExaScreenPriv(pDrawable->pScreen);
778 RegionPtr pClip = fbGetCompositeClip(pGC);
779 PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
781 ExaPixmapPriv(pPixmap);
782 register BoxPtr pbox;
783 BoxPtr pextent;
784 int extentX1, extentX2, extentY1, extentY2;
785 int fullX1, fullX2, fullY1, fullY2;
786 int partX1, partX2, partY1, partY2;
787 int xoff, yoff;
788 int xorg, yorg;
789 int n;
790 RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED);
792 /* Compute intersection of rects and clip region */
793 RegionTranslate(pReg, pDrawable->x, pDrawable->y);
794 RegionIntersect(pReg, pClip, pReg);
796 if (!RegionNumRects(pReg)) {
797 goto out;
800 exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
802 if (pExaScr->fallback_counter || pExaScr->swappedOut ||
803 pExaPixmap->accel_blocked) {
804 goto fallback;
807 /* For ROPs where overlaps don't matter, convert rectangles to region and
808 * call exaFillRegion{Solid,Tiled}.
810 if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
811 (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
812 pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
813 pGC->alu == GXset)) {
814 if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
815 exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
816 pGC->fgPixel : pGC->tile.pixel, pGC->planemask,
817 pGC->alu, pGC->clientClip != NULL)) ||
818 (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
819 exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
820 pGC->planemask, pGC->alu,
821 pGC->clientClip != NULL))) {
822 goto out;
826 if (pGC->fillStyle != FillSolid &&
827 !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) {
828 goto fallback;
831 if (pExaScr->do_migration) {
832 ExaMigrationRec pixmaps[1];
834 pixmaps[0].as_dst = TRUE;
835 pixmaps[0].as_src = FALSE;
836 pixmaps[0].pPix = pPixmap;
837 pixmaps[0].pReg = NULL;
839 exaDoMigration(pixmaps, 1, TRUE);
842 if (!exaPixmapHasGpuCopy(pPixmap) ||
843 !(*pExaScr->info->PrepareSolid) (pPixmap,
844 pGC->alu,
845 pGC->planemask, pGC->fgPixel)) {
846 fallback:
847 ExaCheckPolyFillRect(pDrawable, pGC, nrect, prect);
848 goto out;
851 xorg = pDrawable->x;
852 yorg = pDrawable->y;
854 pextent = RegionExtents(pClip);
855 extentX1 = pextent->x1;
856 extentY1 = pextent->y1;
857 extentX2 = pextent->x2;
858 extentY2 = pextent->y2;
859 while (nrect--) {
860 fullX1 = prect->x + xorg;
861 fullY1 = prect->y + yorg;
862 fullX2 = fullX1 + (int) prect->width;
863 fullY2 = fullY1 + (int) prect->height;
864 prect++;
866 if (fullX1 < extentX1)
867 fullX1 = extentX1;
869 if (fullY1 < extentY1)
870 fullY1 = extentY1;
872 if (fullX2 > extentX2)
873 fullX2 = extentX2;
875 if (fullY2 > extentY2)
876 fullY2 = extentY2;
878 if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
879 continue;
880 n = RegionNumRects(pClip);
881 if (n == 1) {
882 (*pExaScr->info->Solid) (pPixmap,
883 fullX1 + xoff, fullY1 + yoff,
884 fullX2 + xoff, fullY2 + yoff);
886 else {
887 pbox = RegionRects(pClip);
889 * clip the rectangle to each box in the clip region
890 * this is logically equivalent to calling Intersect(),
891 * but rectangles may overlap each other here.
893 while (n--) {
894 partX1 = pbox->x1;
895 if (partX1 < fullX1)
896 partX1 = fullX1;
897 partY1 = pbox->y1;
898 if (partY1 < fullY1)
899 partY1 = fullY1;
900 partX2 = pbox->x2;
901 if (partX2 > fullX2)
902 partX2 = fullX2;
903 partY2 = pbox->y2;
904 if (partY2 > fullY2)
905 partY2 = fullY2;
907 pbox++;
909 if (partX1 < partX2 && partY1 < partY2) {
910 (*pExaScr->info->Solid) (pPixmap,
911 partX1 + xoff, partY1 + yoff,
912 partX2 + xoff, partY2 + yoff);
917 (*pExaScr->info->DoneSolid) (pPixmap);
918 exaMarkSync(pDrawable->pScreen);
920 out:
921 RegionUninit(pReg);
922 RegionDestroy(pReg);
925 const GCOps exaOps = {
926 exaFillSpans,
927 ExaCheckSetSpans,
928 exaPutImage,
929 exaCopyArea,
930 ExaCheckCopyPlane,
931 exaPolyPoint,
932 exaPolylines,
933 exaPolySegment,
934 miPolyRectangle,
935 ExaCheckPolyArc,
936 miFillPolygon,
937 exaPolyFillRect,
938 miPolyFillArc,
939 miPolyText8,
940 miPolyText16,
941 miImageText8,
942 miImageText16,
943 ExaCheckImageGlyphBlt,
944 ExaCheckPolyGlyphBlt,
945 ExaCheckPushPixels,
948 void
949 exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
951 RegionRec rgnDst;
952 int dx, dy;
953 PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
955 ExaScreenPriv(pWin->drawable.pScreen);
957 dx = ptOldOrg.x - pWin->drawable.x;
958 dy = ptOldOrg.y - pWin->drawable.y;
959 RegionTranslate(prgnSrc, -dx, -dy);
961 RegionInit(&rgnDst, NullBox, 0);
963 RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
964 #if defined(COMPOSITE) || defined(ROOTLESS)
965 if (pPixmap->screen_x || pPixmap->screen_y)
966 RegionTranslate(&rgnDst, -pPixmap->screen_x, -pPixmap->screen_y);
967 #endif
969 if (pExaScr->fallback_counter) {
970 pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
971 goto fallback;
974 pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW;
975 miCopyRegion(&pPixmap->drawable, &pPixmap->drawable,
976 NULL, &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
977 pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW;
979 fallback:
980 RegionUninit(&rgnDst);
982 if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) {
983 pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW;
984 RegionTranslate(prgnSrc, dx, dy);
985 ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc);
989 static Bool
990 exaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel,
991 CARD32 planemask, CARD32 alu, Bool hasClientClip)
993 ExaScreenPriv(pDrawable->pScreen);
994 PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
996 ExaPixmapPriv(pPixmap);
997 int xoff, yoff;
998 Bool ret = FALSE;
1000 exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
1001 RegionTranslate(pRegion, xoff, yoff);
1003 if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
1004 goto out;
1006 if (pExaScr->do_migration) {
1007 ExaMigrationRec pixmaps[1];
1009 pixmaps[0].as_dst = TRUE;
1010 pixmaps[0].as_src = FALSE;
1011 pixmaps[0].pPix = pPixmap;
1012 pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
1013 alu,
1014 hasClientClip) ? NULL : pRegion;
1016 exaDoMigration(pixmaps, 1, TRUE);
1019 if (exaPixmapHasGpuCopy(pPixmap) &&
1020 (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) {
1021 int nbox;
1022 BoxPtr pBox;
1024 nbox = RegionNumRects(pRegion);
1025 pBox = RegionRects(pRegion);
1027 while (nbox--) {
1028 (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
1029 pBox->y2);
1030 pBox++;
1032 (*pExaScr->info->DoneSolid) (pPixmap);
1033 exaMarkSync(pDrawable->pScreen);
1035 if (pExaPixmap->pDamage &&
1036 pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
1037 pDrawable->width == 1 && pDrawable->height == 1 &&
1038 pDrawable->bitsPerPixel != 24 && alu == GXcopy) {
1039 RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
1041 switch (pDrawable->bitsPerPixel) {
1042 case 32:
1043 *(CARD32 *) pExaPixmap->sys_ptr = pixel;
1044 break;
1045 case 16:
1046 *(CARD16 *) pExaPixmap->sys_ptr = pixel;
1047 break;
1048 case 8:
1049 case 4:
1050 case 1:
1051 *(CARD8 *) pExaPixmap->sys_ptr = pixel;
1054 RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, pRegion);
1055 RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, pRegion);
1056 RegionSubtract(pending_damage, pending_damage, pRegion);
1059 ret = TRUE;
1062 out:
1063 RegionTranslate(pRegion, -xoff, -yoff);
1065 return ret;
1068 /* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
1069 * Based on fbFillRegionTiled(), fbTile().
1071 Bool
1072 exaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
1073 DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
1074 Bool hasClientClip)
1076 ExaScreenPriv(pDrawable->pScreen);
1077 PixmapPtr pPixmap;
1078 ExaPixmapPrivPtr pExaPixmap;
1079 ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
1080 int xoff, yoff;
1081 int tileWidth, tileHeight;
1082 int nbox = RegionNumRects(pRegion);
1083 BoxPtr pBox = RegionRects(pRegion);
1084 Bool ret = FALSE;
1085 int i;
1087 tileWidth = pTile->drawable.width;
1088 tileHeight = pTile->drawable.height;
1090 /* If we're filling with a solid color, grab it out and go to
1091 * FillRegionSolid, saving numerous copies.
1093 if (tileWidth == 1 && tileHeight == 1)
1094 return exaFillRegionSolid(pDrawable, pRegion,
1095 exaGetPixmapFirstPixel(pTile), planemask,
1096 alu, hasClientClip);
1098 pPixmap = exaGetDrawablePixmap(pDrawable);
1099 pExaPixmap = ExaGetPixmapPriv(pPixmap);
1101 if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
1102 pTileExaPixmap->accel_blocked)
1103 return FALSE;
1105 if (pExaScr->do_migration) {
1106 ExaMigrationRec pixmaps[2];
1108 pixmaps[0].as_dst = TRUE;
1109 pixmaps[0].as_src = FALSE;
1110 pixmaps[0].pPix = pPixmap;
1111 pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
1112 alu,
1113 hasClientClip) ? NULL : pRegion;
1114 pixmaps[1].as_dst = FALSE;
1115 pixmaps[1].as_src = TRUE;
1116 pixmaps[1].pPix = pTile;
1117 pixmaps[1].pReg = NULL;
1119 exaDoMigration(pixmaps, 2, TRUE);
1122 pPixmap = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);
1124 if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
1125 return FALSE;
1127 if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) {
1128 if (xoff || yoff)
1129 RegionTranslate(pRegion, xoff, yoff);
1131 for (i = 0; i < nbox; i++) {
1132 int height = pBox[i].y2 - pBox[i].y1;
1133 int dstY = pBox[i].y1;
1134 int tileY;
1136 if (alu == GXcopy)
1137 height = min(height, tileHeight);
1139 modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
1141 while (height > 0) {
1142 int width = pBox[i].x2 - pBox[i].x1;
1143 int dstX = pBox[i].x1;
1144 int tileX;
1145 int h = tileHeight - tileY;
1147 if (alu == GXcopy)
1148 width = min(width, tileWidth);
1150 if (h > height)
1151 h = height;
1152 height -= h;
1154 modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
1155 tileX);
1157 while (width > 0) {
1158 int w = tileWidth - tileX;
1160 if (w > width)
1161 w = width;
1162 width -= w;
1164 (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
1165 w, h);
1166 dstX += w;
1167 tileX = 0;
1169 dstY += h;
1170 tileY = 0;
1173 (*pExaScr->info->DoneCopy) (pPixmap);
1175 /* With GXcopy, we only need to do the basic algorithm up to the tile
1176 * size; then, we can just keep doubling the destination in each
1177 * direction until it fills the box. This way, the number of copy
1178 * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
1179 * rx/ry is the ratio between box and tile width/height. This can make
1180 * a big difference if each driver copy incurs a significant constant
1181 * overhead.
1183 if (alu != GXcopy)
1184 ret = TRUE;
1185 else {
1186 Bool more_copy = FALSE;
1188 for (i = 0; i < nbox; i++) {
1189 int dstX = pBox[i].x1 + tileWidth;
1190 int dstY = pBox[i].y1 + tileHeight;
1192 if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
1193 more_copy = TRUE;
1194 break;
1198 if (more_copy == FALSE)
1199 ret = TRUE;
1201 if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
1202 1, 1, alu,
1203 planemask)) {
1204 for (i = 0; i < nbox; i++) {
1205 int dstX = pBox[i].x1 + tileWidth;
1206 int dstY = pBox[i].y1 + tileHeight;
1207 int width = min(pBox[i].x2 - dstX, tileWidth);
1208 int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
1210 while (dstX < pBox[i].x2) {
1211 (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1212 dstX, pBox[i].y1, width,
1213 height);
1214 dstX += width;
1215 width = min(pBox[i].x2 - dstX, width * 2);
1218 width = pBox[i].x2 - pBox[i].x1;
1219 height = min(pBox[i].y2 - dstY, tileHeight);
1221 while (dstY < pBox[i].y2) {
1222 (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1223 pBox[i].x1, dstY, width,
1224 height);
1225 dstY += height;
1226 height = min(pBox[i].y2 - dstY, height * 2);
1230 (*pExaScr->info->DoneCopy) (pPixmap);
1232 ret = TRUE;
1236 exaMarkSync(pDrawable->pScreen);
1238 if (xoff || yoff)
1239 RegionTranslate(pRegion, -xoff, -yoff);
1242 return ret;
1246 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
1248 * This is probably the only case we actually care about. The rest fall through
1249 * to migration and fbGetImage, which hopefully will result in migration pushing
1250 * the pixmap out of framebuffer.
1252 void
1253 exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
1254 unsigned int format, unsigned long planeMask, char *d)
1256 ExaScreenPriv(pDrawable->pScreen);
1257 PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
1259 ExaPixmapPriv(pPix);
1260 int xoff, yoff;
1261 Bool ok;
1263 if (pExaScr->fallback_counter || pExaScr->swappedOut)
1264 goto fallback;
1266 /* If there's a system copy, we want to save the result there */
1267 if (pExaPixmap->pDamage)
1268 goto fallback;
1270 pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);
1272 if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
1273 goto fallback;
1275 /* Only cover the ZPixmap, solid copy case. */
1276 if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
1277 goto fallback;
1279 /* Only try to handle the 8bpp and up cases, since we don't want to think
1280 * about <8bpp.
1282 if (pDrawable->bitsPerPixel < 8)
1283 goto fallback;
1285 ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
1286 pDrawable->y + y + yoff, w, h, d,
1287 PixmapBytePad(w, pDrawable->depth));
1288 if (ok) {
1289 exaWaitSync(pDrawable->pScreen);
1290 return;
1293 fallback:
1294 ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);