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.
25 * Eric Anholt <eric@anholt.net>
26 * Michel Dänzer <michel@tungstengraphics.com>
30 #include <dix-config.h>
32 #include <X11/fonts/fontstruct.h>
33 #include "dixfontstr.h"
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
);
49 int extentX1
, extentX2
, extentY1
, extentY2
;
50 int fullX1
, fullX2
, fullY1
;
54 if (pExaScr
->fallback_counter
||
55 pExaScr
->swappedOut
||
56 pGC
->fillStyle
!= FillSolid
|| pExaPixmap
->accel_blocked
) {
57 ExaCheckFillSpans(pDrawable
, pGC
, n
, ppt
, pwidth
, fSorted
);
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
,
75 pGC
->planemask
, pGC
->fgPixel
)) {
76 ExaCheckFillSpans(pDrawable
, pGC
, n
, ppt
, pwidth
, fSorted
);
80 pextent
= RegionExtents(pClip
);
81 extentX1
= pextent
->x1
;
82 extentY1
= pextent
->y1
;
83 extentX2
= pextent
->x2
;
84 extentY2
= pextent
->y2
;
88 fullX2
= fullX1
+ (int) *pwidth
;
92 if (fullY1
< extentY1
|| extentY2
<= fullY1
)
95 if (fullX1
< extentX1
)
98 if (fullX2
> extentX2
)
101 if (fullX1
>= fullX2
)
104 nbox
= RegionNumRects(pClip
);
106 (*pExaScr
->info
->Solid
) (pPixmap
,
107 fullX1
+ off_x
, fullY1
+ off_y
,
108 fullX2
+ off_x
, fullY1
+ 1 + off_y
);
111 pbox
= RegionRects(pClip
);
113 if (pbox
->y1
<= fullY1
&& fullY1
< pbox
->y2
) {
120 if (partX2
> partX1
) {
121 (*pExaScr
->info
->Solid
) (pPixmap
,
122 partX1
+ off_x
, fullY1
+ off_y
,
131 (*pExaScr
->info
->DoneSolid
) (pPixmap
);
132 exaMarkSync(pScreen
);
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
);
147 int bpp
= pDrawable
->bitsPerPixel
;
150 if (pExaScr
->fallback_counter
|| pExaPixmap
->accel_blocked
||
151 !pExaScr
->info
->UploadToScreen
)
154 /* If there's a system copy, we want to save the result there */
155 if (pExaPixmap
->pDamage
)
158 /* Don't bother with under 8bpp, XYPixmaps. */
159 if (format
!= ZPixmap
|| bpp
< 8)
162 /* Only accelerate copies: no rop or planemask. */
163 if (!EXA_PM_IS_SOLID(pDrawable
, pGC
->planemask
) || pGC
->alu
!= GXcopy
)
166 if (pExaScr
->swappedOut
)
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
);
188 pClip
= fbGetCompositeClip(pGC
);
189 for (nbox
= RegionNumRects(pClip
),
190 pbox
= RegionRects(pClip
); nbox
--; pbox
++) {
206 if (x1
>= x2
|| y1
>= y2
)
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.
222 exaMarkSync(pDrawable
->pScreen
);
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
,
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
;
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
)
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) {
262 pExaScr
->info
->DoneCopy(pDstPixmap
);
264 if (!(*pExaScr
->info
->PrepareCopy
) (pSrcPixmap
,
267 pGC
? pGC
->alu
: GXcopy
,
268 pGC
? pGC
->planemask
:
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. */
283 pExaScr
->info
->DoneCopy(pDstPixmap
);
285 if (!(*pExaScr
->info
->PrepareCopy
) (pSrcPixmap
,
288 pGC
? pGC
->alu
: GXcopy
,
289 pGC
? pGC
->planemask
:
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
);
302 * xdir = 1, ydir = -1.
303 * Perform line-by-line xdir = ydir = 1 blits, going up.
309 pExaScr
->info
->DoneCopy(pDstPixmap
);
311 if (!(*pExaScr
->info
->PrepareCopy
) (pSrcPixmap
,
314 pGC
? pGC
->alu
: GXcopy
,
315 pGC
? pGC
->planemask
:
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);
329 * xdir = -1, ydir = 1.
330 * Perform line-by-line xdir = ydir = -1 blits, going down.
334 if (dirsetup
!= -1) {
336 pExaScr
->info
->DoneCopy(pDstPixmap
);
338 if (!(*pExaScr
->info
->PrepareCopy
) (pSrcPixmap
,
341 pGC
? pGC
->alu
: GXcopy
,
342 pGC
? pGC
->planemask
:
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);
356 pExaScr
->info
->DoneCopy(pDstPixmap
);
357 exaMarkSync(pDstDrawable
->pScreen
);
362 exaHWCopyNtoN(DrawablePtr pSrcDrawable
,
363 DrawablePtr pDstDrawable
,
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
;
377 /* avoid doing copy operations if no boxes */
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
));
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
;
407 ordering
= CT_UNSORTED
;
409 srcregion
= RegionFromRects(nbox
, rects
, ordering
);
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
)
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
) {
441 for (i
= 0; i
< nbox
; i
++) {
443 if ((pbox
[i
].x2
+ dx
+ src_off_x
) >= pExaScr
->info
->maxX
||
444 (pbox
[i
].y2
+ dy
+ src_off_y
) >= pExaScr
->info
->maxY
)
448 if ((pbox
[i
].x2
+ dst_off_x
) >= pExaScr
->info
->maxX
||
449 (pbox
[i
].y2
+ dst_off_y
) >= pExaScr
->info
->maxY
)
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
,
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
)) {
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
,
494 pbox
->y2
- pbox
->y1
);
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
);
510 if (!pExaScr
->info
->UploadToScreen
)
513 if (pSrcDrawable
->bitsPerPixel
!= pDstDrawable
->bitsPerPixel
)
516 if (pSrcDrawable
->bitsPerPixel
< 8)
520 !(pGC
->alu
== GXcopy
&&
521 EXA_PM_IS_SOLID(pSrcDrawable
, pGC
->planemask
)))
526 pSrcExaPixmap
->sys_ptr
+ (pbox
->y1
+ dy
+
527 src_off_y
) * src_stride
+
528 (pbox
->x1
+ dx
+ src_off_x
) * (bpp
/ 8);
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
,
552 RegionUninit(dstregion
);
553 RegionDestroy(dstregion
);
556 RegionUninit(srcregion
);
557 RegionDestroy(srcregion
);
564 exaCopyNtoN(DrawablePtr pSrcDrawable
,
565 DrawablePtr pDstDrawable
,
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
))
580 (pSrcDrawable
, pDstDrawable
, pGC
, pbox
, nbox
, dx
, dy
, reverse
,
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
;
591 ExaCheckCopyNtoN(pSrcDrawable
, pDstDrawable
, pGC
, pbox
, nbox
, dx
, dy
,
592 reverse
, upsidedown
, bitplane
, closure
);
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
);
612 exaPolyPoint(DrawablePtr pDrawable
, GCPtr pGC
, int mode
, int npt
,
615 ExaScreenPriv(pDrawable
->pScreen
);
619 /* If we can't reuse the current GC as is, don't bother accelerating the
622 if (pExaScr
->fallback_counter
|| pGC
->fillStyle
!= FillSolid
) {
623 ExaCheckPolyPoint(pDrawable
, pGC
, mode
, npt
, ppt
);
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
;
638 pGC
->ops
->PolyFillRect(pDrawable
, pGC
, npt
, 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.
648 exaPolylines(DrawablePtr pDrawable
, GCPtr pGC
, int mode
, int npt
,
651 ExaScreenPriv(pDrawable
->pScreen
);
656 if (pExaScr
->fallback_counter
) {
657 ExaCheckPolylines(pDrawable
, pGC
, mode
, npt
, ppt
);
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
);
668 prect
= xallocarray(npt
- 1, sizeof(xRectangle
));
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
;
682 if (x1
!= x2
&& y1
!= y2
) {
684 ExaCheckPolylines(pDrawable
, pGC
, mode
, npt
, ppt
);
690 prect
[i
].width
= x2
- x1
+ 1;
694 prect
[i
].width
= x1
- x2
+ 1;
698 prect
[i
].height
= y2
- y1
+ 1;
702 prect
[i
].height
= y1
- y2
+ 1;
708 pGC
->ops
->PolyFillRect(pDrawable
, pGC
, npt
- 1, 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.
718 exaPolySegment(DrawablePtr pDrawable
, GCPtr pGC
, int nseg
, xSegment
* pSeg
)
720 ExaScreenPriv(pDrawable
->pScreen
);
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
);
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
);
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;
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;
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)
766 pGC
->ops
->PolyFillRect(pDrawable
, pGC
, nseg
, prect
);
770 static Bool
exaFillRegionSolid(DrawablePtr pDrawable
, RegionPtr pRegion
,
771 Pixel pixel
, CARD32 planemask
, CARD32 alu
,
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
;
784 int extentX1
, extentX2
, extentY1
, extentY2
;
785 int fullX1
, fullX2
, fullY1
, fullY2
;
786 int partX1
, partX2
, partY1
, partY2
;
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
)) {
800 exaGetDrawableDeltas(pDrawable
, pPixmap
, &xoff
, &yoff
);
802 if (pExaScr
->fallback_counter
|| pExaScr
->swappedOut
||
803 pExaPixmap
->accel_blocked
) {
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
))) {
826 if (pGC
->fillStyle
!= FillSolid
&&
827 !(pGC
->tileIsPixel
&& pGC
->fillStyle
== FillTiled
)) {
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
,
845 pGC
->planemask
, pGC
->fgPixel
)) {
847 ExaCheckPolyFillRect(pDrawable
, pGC
, nrect
, prect
);
854 pextent
= RegionExtents(pClip
);
855 extentX1
= pextent
->x1
;
856 extentY1
= pextent
->y1
;
857 extentX2
= pextent
->x2
;
858 extentY2
= pextent
->y2
;
860 fullX1
= prect
->x
+ xorg
;
861 fullY1
= prect
->y
+ yorg
;
862 fullX2
= fullX1
+ (int) prect
->width
;
863 fullY2
= fullY1
+ (int) prect
->height
;
866 if (fullX1
< extentX1
)
869 if (fullY1
< extentY1
)
872 if (fullX2
> extentX2
)
875 if (fullY2
> extentY2
)
878 if ((fullX1
>= fullX2
) || (fullY1
>= fullY2
))
880 n
= RegionNumRects(pClip
);
882 (*pExaScr
->info
->Solid
) (pPixmap
,
883 fullX1
+ xoff
, fullY1
+ yoff
,
884 fullX2
+ xoff
, fullY2
+ yoff
);
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.
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
);
925 const GCOps exaOps
= {
943 ExaCheckImageGlyphBlt
,
944 ExaCheckPolyGlyphBlt
,
949 exaCopyWindow(WindowPtr pWin
, DDXPointRec ptOldOrg
, RegionPtr prgnSrc
)
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
);
969 if (pExaScr
->fallback_counter
) {
970 pExaScr
->fallback_flags
|= EXA_FALLBACK_COPYWINDOW
;
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
;
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
);
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
);
1000 exaGetDrawableDeltas(pDrawable
, pPixmap
, &xoff
, &yoff
);
1001 RegionTranslate(pRegion
, xoff
, yoff
);
1003 if (pExaScr
->fallback_counter
|| pExaPixmap
->accel_blocked
)
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
,
1014 hasClientClip
) ? NULL
: pRegion
;
1016 exaDoMigration(pixmaps
, 1, TRUE
);
1019 if (exaPixmapHasGpuCopy(pPixmap
) &&
1020 (*pExaScr
->info
->PrepareSolid
) (pPixmap
, alu
, planemask
, pixel
)) {
1024 nbox
= RegionNumRects(pRegion
);
1025 pBox
= RegionRects(pRegion
);
1028 (*pExaScr
->info
->Solid
) (pPixmap
, pBox
->x1
, pBox
->y1
, pBox
->x2
,
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
) {
1043 *(CARD32
*) pExaPixmap
->sys_ptr
= pixel
;
1046 *(CARD16
*) pExaPixmap
->sys_ptr
= pixel
;
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
);
1063 RegionTranslate(pRegion
, -xoff
, -yoff
);
1068 /* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
1069 * Based on fbFillRegionTiled(), fbTile().
1072 exaFillRegionTiled(DrawablePtr pDrawable
, RegionPtr pRegion
, PixmapPtr pTile
,
1073 DDXPointPtr pPatOrg
, CARD32 planemask
, CARD32 alu
,
1076 ExaScreenPriv(pDrawable
->pScreen
);
1078 ExaPixmapPrivPtr pExaPixmap
;
1079 ExaPixmapPrivPtr pTileExaPixmap
= ExaGetPixmapPriv(pTile
);
1081 int tileWidth
, tileHeight
;
1082 int nbox
= RegionNumRects(pRegion
);
1083 BoxPtr pBox
= RegionRects(pRegion
);
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
)
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
,
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
))
1127 if ((*pExaScr
->info
->PrepareCopy
) (pTile
, pPixmap
, 1, 1, alu
, planemask
)) {
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
;
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
;
1145 int h
= tileHeight
- tileY
;
1148 width
= min(width
, tileWidth
);
1154 modulus(dstX
- xoff
- pDrawable
->x
- pPatOrg
->x
, tileWidth
,
1158 int w
= tileWidth
- tileX
;
1164 (*pExaScr
->info
->Copy
) (pPixmap
, tileX
, tileY
, dstX
, dstY
,
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
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
)) {
1198 if (more_copy
== FALSE
)
1201 if (more_copy
&& (*pExaScr
->info
->PrepareCopy
) (pPixmap
, pPixmap
,
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
,
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
,
1226 height
= min(pBox
[i
].y2
- dstY
, height
* 2);
1230 (*pExaScr
->info
->DoneCopy
) (pPixmap
);
1236 exaMarkSync(pDrawable
->pScreen
);
1239 RegionTranslate(pRegion
, -xoff
, -yoff
);
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.
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
);
1263 if (pExaScr
->fallback_counter
|| pExaScr
->swappedOut
)
1266 /* If there's a system copy, we want to save the result there */
1267 if (pExaPixmap
->pDamage
)
1270 pPix
= exaGetOffscreenPixmap(pDrawable
, &xoff
, &yoff
);
1272 if (pPix
== NULL
|| pExaScr
->info
->DownloadFromScreen
== NULL
)
1275 /* Only cover the ZPixmap, solid copy case. */
1276 if (format
!= ZPixmap
|| !EXA_PM_IS_SOLID(pDrawable
, planeMask
))
1279 /* Only try to handle the 8bpp and up cases, since we don't want to think
1282 if (pDrawable
->bitsPerPixel
< 8)
1285 ok
= pExaScr
->info
->DownloadFromScreen(pPix
, pDrawable
->x
+ x
+ xoff
,
1286 pDrawable
->y
+ y
+ yoff
, w
, h
, d
,
1287 PixmapBytePad(w
, pDrawable
->depth
));
1289 exaWaitSync(pDrawable
->pScreen
);
1294 ExaCheckGetImage(pDrawable
, x
, y
, w
, h
, format
, planeMask
, d
);