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 #ifdef HAVE_DIX_CONFIG_H
31 #include <dix-config.h>
34 #include <X11/fonts/fontstruct.h>
35 #include "dixfontstr.h"
39 exaFillSpans(DrawablePtr pDrawable
, GCPtr pGC
, int n
,
40 DDXPointPtr ppt
, int *pwidth
, int fSorted
)
42 ScreenPtr pScreen
= pDrawable
->pScreen
;
44 ExaScreenPriv(pScreen
);
45 RegionPtr pClip
= fbGetCompositeClip(pGC
);
46 PixmapPtr pPixmap
= exaGetDrawablePixmap(pDrawable
);
48 ExaPixmapPriv(pPixmap
);
51 int extentX1
, extentX2
, extentY1
, extentY2
;
52 int fullX1
, fullX2
, fullY1
;
56 if (pExaScr
->fallback_counter
||
57 pExaScr
->swappedOut
||
58 pGC
->fillStyle
!= FillSolid
|| pExaPixmap
->accel_blocked
) {
59 ExaCheckFillSpans(pDrawable
, pGC
, n
, ppt
, pwidth
, fSorted
);
63 if (pExaScr
->do_migration
) {
64 ExaMigrationRec pixmaps
[1];
66 pixmaps
[0].as_dst
= TRUE
;
67 pixmaps
[0].as_src
= FALSE
;
68 pixmaps
[0].pPix
= pPixmap
;
69 pixmaps
[0].pReg
= NULL
;
71 exaDoMigration(pixmaps
, 1, TRUE
);
74 if (!(pPixmap
= exaGetOffscreenPixmap(pDrawable
, &off_x
, &off_y
)) ||
75 !(*pExaScr
->info
->PrepareSolid
) (pPixmap
,
77 pGC
->planemask
, pGC
->fgPixel
)) {
78 ExaCheckFillSpans(pDrawable
, pGC
, n
, ppt
, pwidth
, fSorted
);
82 pextent
= RegionExtents(pClip
);
83 extentX1
= pextent
->x1
;
84 extentY1
= pextent
->y1
;
85 extentX2
= pextent
->x2
;
86 extentY2
= pextent
->y2
;
90 fullX2
= fullX1
+ (int) *pwidth
;
94 if (fullY1
< extentY1
|| extentY2
<= fullY1
)
97 if (fullX1
< extentX1
)
100 if (fullX2
> extentX2
)
103 if (fullX1
>= fullX2
)
106 nbox
= RegionNumRects(pClip
);
108 (*pExaScr
->info
->Solid
) (pPixmap
,
109 fullX1
+ off_x
, fullY1
+ off_y
,
110 fullX2
+ off_x
, fullY1
+ 1 + off_y
);
113 pbox
= RegionRects(pClip
);
115 if (pbox
->y1
<= fullY1
&& fullY1
< pbox
->y2
) {
122 if (partX2
> partX1
) {
123 (*pExaScr
->info
->Solid
) (pPixmap
,
124 partX1
+ off_x
, fullY1
+ off_y
,
133 (*pExaScr
->info
->DoneSolid
) (pPixmap
);
134 exaMarkSync(pScreen
);
138 exaDoPutImage(DrawablePtr pDrawable
, GCPtr pGC
, int depth
, int x
, int y
,
139 int w
, int h
, int format
, char *bits
, int src_stride
)
141 ExaScreenPriv(pDrawable
->pScreen
);
142 PixmapPtr pPix
= exaGetDrawablePixmap(pDrawable
);
149 int bpp
= pDrawable
->bitsPerPixel
;
152 if (pExaScr
->fallback_counter
|| pExaPixmap
->accel_blocked
||
153 !pExaScr
->info
->UploadToScreen
)
156 /* If there's a system copy, we want to save the result there */
157 if (pExaPixmap
->pDamage
)
160 /* Don't bother with under 8bpp, XYPixmaps. */
161 if (format
!= ZPixmap
|| bpp
< 8)
164 /* Only accelerate copies: no rop or planemask. */
165 if (!EXA_PM_IS_SOLID(pDrawable
, pGC
->planemask
) || pGC
->alu
!= GXcopy
)
168 if (pExaScr
->swappedOut
)
171 if (pExaScr
->do_migration
) {
172 ExaMigrationRec pixmaps
[1];
174 pixmaps
[0].as_dst
= TRUE
;
175 pixmaps
[0].as_src
= FALSE
;
176 pixmaps
[0].pPix
= pPix
;
177 pixmaps
[0].pReg
= DamagePendingRegion(pExaPixmap
->pDamage
);
179 exaDoMigration(pixmaps
, 1, TRUE
);
182 pPix
= exaGetOffscreenPixmap(pDrawable
, &xoff
, &yoff
);
190 pClip
= fbGetCompositeClip(pGC
);
191 for (nbox
= RegionNumRects(pClip
),
192 pbox
= RegionRects(pClip
); nbox
--; pbox
++) {
208 if (x1
>= x2
|| y1
>= y2
)
211 src
= bits
+ (y1
- y
) * src_stride
+ (x1
- x
) * (bpp
/ 8);
212 ok
= pExaScr
->info
->UploadToScreen(pPix
, x1
+ xoff
, y1
+ yoff
,
213 x2
- x1
, y2
- y1
, src
, src_stride
);
214 /* We have to fall back completely, and ignore what has already been completed.
215 * Messing with the fb layer directly like we used to is completely unacceptable.
224 exaMarkSync(pDrawable
->pScreen
);
230 exaPutImage(DrawablePtr pDrawable
, GCPtr pGC
, int depth
, int x
, int y
,
231 int w
, int h
, int leftPad
, int format
, char *bits
)
233 if (!exaDoPutImage(pDrawable
, pGC
, depth
, x
, y
, w
, h
, format
, bits
,
234 PixmapBytePad(w
, pDrawable
->depth
)))
235 ExaCheckPutImage(pDrawable
, pGC
, depth
, x
, y
, w
, h
, leftPad
, format
,
240 exaCopyNtoNTwoDir(DrawablePtr pSrcDrawable
, DrawablePtr pDstDrawable
,
241 GCPtr pGC
, BoxPtr pbox
, int nbox
, int dx
, int dy
)
243 ExaScreenPriv(pDstDrawable
->pScreen
);
244 PixmapPtr pSrcPixmap
, pDstPixmap
;
245 int src_off_x
, src_off_y
, dst_off_x
, dst_off_y
;
248 /* Need to get both pixmaps to call the driver routines */
249 pSrcPixmap
= exaGetOffscreenPixmap(pSrcDrawable
, &src_off_x
, &src_off_y
);
250 pDstPixmap
= exaGetOffscreenPixmap(pDstDrawable
, &dst_off_x
, &dst_off_y
);
251 if (!pSrcPixmap
|| !pDstPixmap
)
255 * Now the case of a chip that only supports xdir = ydir = 1 or
256 * xdir = ydir = -1, but we have xdir != ydir.
258 dirsetup
= 0; /* No direction set up yet. */
259 for (; nbox
; pbox
++, nbox
--) {
260 if (dx
>= 0 && (src_off_y
+ pbox
->y1
+ dy
) != pbox
->y1
) {
261 /* Do a xdir = ydir = -1 blit instead. */
262 if (dirsetup
!= -1) {
264 pExaScr
->info
->DoneCopy(pDstPixmap
);
266 if (!(*pExaScr
->info
->PrepareCopy
) (pSrcPixmap
,
269 pGC
? pGC
->alu
: GXcopy
,
270 pGC
? pGC
->planemask
:
274 (*pExaScr
->info
->Copy
) (pDstPixmap
,
275 src_off_x
+ pbox
->x1
+ dx
,
276 src_off_y
+ pbox
->y1
+ dy
,
277 dst_off_x
+ pbox
->x1
,
278 dst_off_y
+ pbox
->y1
,
279 pbox
->x2
- pbox
->x1
, pbox
->y2
- pbox
->y1
);
281 else if (dx
< 0 && (src_off_y
+ pbox
->y1
+ dy
) != pbox
->y1
) {
282 /* Do a xdir = ydir = 1 blit instead. */
285 pExaScr
->info
->DoneCopy(pDstPixmap
);
287 if (!(*pExaScr
->info
->PrepareCopy
) (pSrcPixmap
,
290 pGC
? pGC
->alu
: GXcopy
,
291 pGC
? pGC
->planemask
:
295 (*pExaScr
->info
->Copy
) (pDstPixmap
,
296 src_off_x
+ pbox
->x1
+ dx
,
297 src_off_y
+ pbox
->y1
+ dy
,
298 dst_off_x
+ pbox
->x1
,
299 dst_off_y
+ pbox
->y1
,
300 pbox
->x2
- pbox
->x1
, pbox
->y2
- pbox
->y1
);
304 * xdir = 1, ydir = -1.
305 * Perform line-by-line xdir = ydir = 1 blits, going up.
311 pExaScr
->info
->DoneCopy(pDstPixmap
);
313 if (!(*pExaScr
->info
->PrepareCopy
) (pSrcPixmap
,
316 pGC
? pGC
->alu
: GXcopy
,
317 pGC
? pGC
->planemask
:
321 for (i
= pbox
->y2
- pbox
->y1
- 1; i
>= 0; i
--)
322 (*pExaScr
->info
->Copy
) (pDstPixmap
,
323 src_off_x
+ pbox
->x1
+ dx
,
324 src_off_y
+ pbox
->y1
+ dy
+ i
,
325 dst_off_x
+ pbox
->x1
,
326 dst_off_y
+ pbox
->y1
+ i
,
327 pbox
->x2
- pbox
->x1
, 1);
331 * xdir = -1, ydir = 1.
332 * Perform line-by-line xdir = ydir = -1 blits, going down.
336 if (dirsetup
!= -1) {
338 pExaScr
->info
->DoneCopy(pDstPixmap
);
340 if (!(*pExaScr
->info
->PrepareCopy
) (pSrcPixmap
,
343 pGC
? pGC
->alu
: GXcopy
,
344 pGC
? pGC
->planemask
:
348 for (i
= 0; i
< pbox
->y2
- pbox
->y1
; i
++)
349 (*pExaScr
->info
->Copy
) (pDstPixmap
,
350 src_off_x
+ pbox
->x1
+ dx
,
351 src_off_y
+ pbox
->y1
+ dy
+ i
,
352 dst_off_x
+ pbox
->x1
,
353 dst_off_y
+ pbox
->y1
+ i
,
354 pbox
->x2
- pbox
->x1
, 1);
358 pExaScr
->info
->DoneCopy(pDstPixmap
);
359 exaMarkSync(pDstDrawable
->pScreen
);
364 exaHWCopyNtoN(DrawablePtr pSrcDrawable
,
365 DrawablePtr pDstDrawable
,
368 int nbox
, int dx
, int dy
, Bool reverse
, Bool upsidedown
)
370 ExaScreenPriv(pDstDrawable
->pScreen
);
371 PixmapPtr pSrcPixmap
, pDstPixmap
;
372 ExaPixmapPrivPtr pSrcExaPixmap
, pDstExaPixmap
;
373 int src_off_x
, src_off_y
;
374 int dst_off_x
, dst_off_y
;
375 RegionPtr srcregion
= NULL
, dstregion
= NULL
;
379 /* avoid doing copy operations if no boxes */
383 pSrcPixmap
= exaGetDrawablePixmap(pSrcDrawable
);
384 pDstPixmap
= exaGetDrawablePixmap(pDstDrawable
);
386 exaGetDrawableDeltas(pSrcDrawable
, pSrcPixmap
, &src_off_x
, &src_off_y
);
387 exaGetDrawableDeltas(pDstDrawable
, pDstPixmap
, &dst_off_x
, &dst_off_y
);
389 rects
= malloc(nbox
* sizeof(xRectangle
));
395 for (i
= 0; i
< nbox
; i
++) {
396 rects
[i
].x
= pbox
[i
].x1
+ dx
+ src_off_x
;
397 rects
[i
].y
= pbox
[i
].y1
+ dy
+ src_off_y
;
398 rects
[i
].width
= pbox
[i
].x2
- pbox
[i
].x1
;
399 rects
[i
].height
= pbox
[i
].y2
- pbox
[i
].y1
;
402 /* This must match the RegionCopy() logic for reversing rect order */
403 if (nbox
== 1 || (dx
> 0 && dy
> 0) ||
404 (pDstDrawable
!= pSrcDrawable
&&
405 (pDstDrawable
->type
!= DRAWABLE_WINDOW
||
406 pSrcDrawable
->type
!= DRAWABLE_WINDOW
)))
407 ordering
= CT_YXBANDED
;
409 ordering
= CT_UNSORTED
;
411 srcregion
= RegionFromRects(nbox
, rects
, ordering
);
414 if (!pGC
|| !exaGCReadsDestination(pDstDrawable
, pGC
->planemask
,
415 pGC
->fillStyle
, pGC
->alu
,
416 pGC
->clientClipType
)) {
417 dstregion
= RegionCreate(NullBox
, 0);
418 RegionCopy(dstregion
, srcregion
);
419 RegionTranslate(dstregion
, dst_off_x
- dx
- src_off_x
,
420 dst_off_y
- dy
- src_off_y
);
424 pSrcExaPixmap
= ExaGetPixmapPriv(pSrcPixmap
);
425 pDstExaPixmap
= ExaGetPixmapPriv(pDstPixmap
);
427 /* Check whether the accelerator can use this pixmap.
428 * If the pitch of the pixmaps is out of range, there's nothing
429 * we can do but fall back to software rendering.
431 if (pSrcExaPixmap
->accel_blocked
& EXA_RANGE_PITCH
||
432 pDstExaPixmap
->accel_blocked
& EXA_RANGE_PITCH
)
435 /* If the width or the height of either of the pixmaps
436 * is out of range, check whether the boxes are actually out of the
437 * addressable range as well. If they aren't, we can still do
438 * the copying in hardware.
440 if (pSrcExaPixmap
->accel_blocked
|| pDstExaPixmap
->accel_blocked
) {
443 for (i
= 0; i
< nbox
; i
++) {
445 if ((pbox
[i
].x2
+ dx
+ src_off_x
) >= pExaScr
->info
->maxX
||
446 (pbox
[i
].y2
+ dy
+ src_off_y
) >= pExaScr
->info
->maxY
)
450 if ((pbox
[i
].x2
+ dst_off_x
) >= pExaScr
->info
->maxX
||
451 (pbox
[i
].y2
+ dst_off_y
) >= pExaScr
->info
->maxY
)
456 if (pExaScr
->do_migration
) {
457 ExaMigrationRec pixmaps
[2];
459 pixmaps
[0].as_dst
= TRUE
;
460 pixmaps
[0].as_src
= FALSE
;
461 pixmaps
[0].pPix
= pDstPixmap
;
462 pixmaps
[0].pReg
= dstregion
;
463 pixmaps
[1].as_dst
= FALSE
;
464 pixmaps
[1].as_src
= TRUE
;
465 pixmaps
[1].pPix
= pSrcPixmap
;
466 pixmaps
[1].pReg
= srcregion
;
468 exaDoMigration(pixmaps
, 2, TRUE
);
471 /* Mixed directions must be handled specially if the card is lame */
472 if ((pExaScr
->info
->flags
& EXA_TWO_BITBLT_DIRECTIONS
) &&
473 reverse
!= upsidedown
) {
474 if (exaCopyNtoNTwoDir(pSrcDrawable
, pDstDrawable
, pGC
, pbox
, nbox
,
480 if (exaPixmapHasGpuCopy(pDstPixmap
)) {
481 /* Normal blitting. */
482 if (exaPixmapHasGpuCopy(pSrcPixmap
)) {
483 if (!(*pExaScr
->info
->PrepareCopy
)
484 (pSrcPixmap
, pDstPixmap
, reverse
? -1 : 1, upsidedown
? -1 : 1,
485 pGC
? pGC
->alu
: GXcopy
, pGC
? pGC
->planemask
: FB_ALLONES
)) {
490 (*pExaScr
->info
->Copy
) (pDstPixmap
,
491 pbox
->x1
+ dx
+ src_off_x
,
492 pbox
->y1
+ dy
+ src_off_y
,
493 pbox
->x1
+ dst_off_x
,
494 pbox
->y1
+ dst_off_y
,
496 pbox
->y2
- pbox
->y1
);
500 (*pExaScr
->info
->DoneCopy
) (pDstPixmap
);
501 exaMarkSync(pDstDrawable
->pScreen
);
502 /* UTS: mainly for SHM PutImage's secondary path.
504 * Only taking this path for directly accessible pixmaps.
507 else if (!pDstExaPixmap
->pDamage
&& pSrcExaPixmap
->sys_ptr
) {
508 int bpp
= pSrcDrawable
->bitsPerPixel
;
509 int src_stride
= exaGetPixmapPitch(pSrcPixmap
);
512 if (!pExaScr
->info
->UploadToScreen
)
515 if (pSrcDrawable
->bitsPerPixel
!= pDstDrawable
->bitsPerPixel
)
518 if (pSrcDrawable
->bitsPerPixel
< 8)
522 !(pGC
->alu
== GXcopy
&&
523 EXA_PM_IS_SOLID(pSrcDrawable
, pGC
->planemask
)))
528 pSrcExaPixmap
->sys_ptr
+ (pbox
->y1
+ dy
+
529 src_off_y
) * src_stride
+
530 (pbox
->x1
+ dx
+ src_off_x
) * (bpp
/ 8);
532 UploadToScreen(pDstPixmap
, pbox
->x1
+ dst_off_x
,
533 pbox
->y1
+ dst_off_y
, pbox
->x2
- pbox
->x1
,
534 pbox
->y2
- pbox
->y1
, (char *) src
,
554 RegionUninit(dstregion
);
555 RegionDestroy(dstregion
);
558 RegionUninit(srcregion
);
559 RegionDestroy(srcregion
);
566 exaCopyNtoN(DrawablePtr pSrcDrawable
,
567 DrawablePtr pDstDrawable
,
573 Bool reverse
, Bool upsidedown
, Pixel bitplane
, void *closure
)
575 ExaScreenPriv(pDstDrawable
->pScreen
);
577 if (pExaScr
->fallback_counter
||
578 (pExaScr
->fallback_flags
& EXA_FALLBACK_COPYWINDOW
))
582 (pSrcDrawable
, pDstDrawable
, pGC
, pbox
, nbox
, dx
, dy
, reverse
,
586 /* This is a CopyWindow, it's cleaner to fallback at the original call. */
587 if (pExaScr
->fallback_flags
& EXA_ACCEL_COPYWINDOW
) {
588 pExaScr
->fallback_flags
|= EXA_FALLBACK_COPYWINDOW
;
593 ExaCheckCopyNtoN(pSrcDrawable
, pDstDrawable
, pGC
, pbox
, nbox
, dx
, dy
,
594 reverse
, upsidedown
, bitplane
, closure
);
598 exaCopyArea(DrawablePtr pSrcDrawable
, DrawablePtr pDstDrawable
, GCPtr pGC
,
599 int srcx
, int srcy
, int width
, int height
, int dstx
, int dsty
)
601 ExaScreenPriv(pDstDrawable
->pScreen
);
603 if (pExaScr
->fallback_counter
|| pExaScr
->swappedOut
) {
604 return ExaCheckCopyArea(pSrcDrawable
, pDstDrawable
, pGC
,
605 srcx
, srcy
, width
, height
, dstx
, dsty
);
608 return miDoCopy(pSrcDrawable
, pDstDrawable
, pGC
,
609 srcx
, srcy
, width
, height
,
610 dstx
, dsty
, exaCopyNtoN
, 0, NULL
);
614 exaPolyPoint(DrawablePtr pDrawable
, GCPtr pGC
, int mode
, int npt
,
617 ExaScreenPriv(pDrawable
->pScreen
);
621 /* If we can't reuse the current GC as is, don't bother accelerating the
624 if (pExaScr
->fallback_counter
|| pGC
->fillStyle
!= FillSolid
) {
625 ExaCheckPolyPoint(pDrawable
, pGC
, mode
, npt
, ppt
);
629 prect
= malloc(sizeof(xRectangle
) * npt
);
630 for (i
= 0; i
< npt
; i
++) {
631 prect
[i
].x
= ppt
[i
].x
;
632 prect
[i
].y
= ppt
[i
].y
;
633 if (i
> 0 && mode
== CoordModePrevious
) {
634 prect
[i
].x
+= prect
[i
- 1].x
;
635 prect
[i
].y
+= prect
[i
- 1].y
;
640 pGC
->ops
->PolyFillRect(pDrawable
, pGC
, npt
, prect
);
645 * exaPolylines() checks if it can accelerate the lines as a group of
646 * horizontal or vertical lines (rectangles), and uses existing rectangle fill
647 * acceleration if so.
650 exaPolylines(DrawablePtr pDrawable
, GCPtr pGC
, int mode
, int npt
,
653 ExaScreenPriv(pDrawable
->pScreen
);
658 if (pExaScr
->fallback_counter
) {
659 ExaCheckPolylines(pDrawable
, pGC
, mode
, npt
, ppt
);
663 /* Don't try to do wide lines or non-solid fill style. */
664 if (pGC
->lineWidth
!= 0 || pGC
->lineStyle
!= LineSolid
||
665 pGC
->fillStyle
!= FillSolid
) {
666 ExaCheckPolylines(pDrawable
, pGC
, mode
, npt
, ppt
);
670 prect
= malloc(sizeof(xRectangle
) * (npt
- 1));
673 /* If we have any non-horizontal/vertical, fall back. */
674 for (i
= 0; i
< npt
- 1; i
++) {
675 if (mode
== CoordModePrevious
) {
676 x2
= x1
+ ppt
[i
+ 1].x
;
677 y2
= y1
+ ppt
[i
+ 1].y
;
684 if (x1
!= x2
&& y1
!= y2
) {
686 ExaCheckPolylines(pDrawable
, pGC
, mode
, npt
, ppt
);
692 prect
[i
].width
= x2
- x1
+ 1;
696 prect
[i
].width
= x1
- x2
+ 1;
700 prect
[i
].height
= y2
- y1
+ 1;
704 prect
[i
].height
= y1
- y2
+ 1;
710 pGC
->ops
->PolyFillRect(pDrawable
, pGC
, npt
- 1, prect
);
715 * exaPolySegment() checks if it can accelerate the lines as a group of
716 * horizontal or vertical lines (rectangles), and uses existing rectangle fill
717 * acceleration if so.
720 exaPolySegment(DrawablePtr pDrawable
, GCPtr pGC
, int nseg
, xSegment
* pSeg
)
722 ExaScreenPriv(pDrawable
->pScreen
);
726 /* Don't try to do wide lines or non-solid fill style. */
727 if (pExaScr
->fallback_counter
|| pGC
->lineWidth
!= 0 ||
728 pGC
->lineStyle
!= LineSolid
|| pGC
->fillStyle
!= FillSolid
) {
729 ExaCheckPolySegment(pDrawable
, pGC
, nseg
, pSeg
);
733 /* If we have any non-horizontal/vertical, fall back. */
734 for (i
= 0; i
< nseg
; i
++) {
735 if (pSeg
[i
].x1
!= pSeg
[i
].x2
&& pSeg
[i
].y1
!= pSeg
[i
].y2
) {
736 ExaCheckPolySegment(pDrawable
, pGC
, nseg
, pSeg
);
741 prect
= malloc(sizeof(xRectangle
) * nseg
);
742 for (i
= 0; i
< nseg
; i
++) {
743 if (pSeg
[i
].x1
< pSeg
[i
].x2
) {
744 prect
[i
].x
= pSeg
[i
].x1
;
745 prect
[i
].width
= pSeg
[i
].x2
- pSeg
[i
].x1
+ 1;
748 prect
[i
].x
= pSeg
[i
].x2
;
749 prect
[i
].width
= pSeg
[i
].x1
- pSeg
[i
].x2
+ 1;
751 if (pSeg
[i
].y1
< pSeg
[i
].y2
) {
752 prect
[i
].y
= pSeg
[i
].y1
;
753 prect
[i
].height
= pSeg
[i
].y2
- pSeg
[i
].y1
+ 1;
756 prect
[i
].y
= pSeg
[i
].y2
;
757 prect
[i
].height
= pSeg
[i
].y1
- pSeg
[i
].y2
+ 1;
760 /* don't paint last pixel */
761 if (pGC
->capStyle
== CapNotLast
) {
762 if (prect
[i
].width
== 1)
768 pGC
->ops
->PolyFillRect(pDrawable
, pGC
, nseg
, prect
);
772 static Bool
exaFillRegionSolid(DrawablePtr pDrawable
, RegionPtr pRegion
,
773 Pixel pixel
, CARD32 planemask
, CARD32 alu
,
774 unsigned int clientClipType
);
777 exaPolyFillRect(DrawablePtr pDrawable
, GCPtr pGC
, int nrect
, xRectangle
*prect
)
779 ExaScreenPriv(pDrawable
->pScreen
);
780 RegionPtr pClip
= fbGetCompositeClip(pGC
);
781 PixmapPtr pPixmap
= exaGetDrawablePixmap(pDrawable
);
783 ExaPixmapPriv(pPixmap
);
784 register BoxPtr pbox
;
786 int extentX1
, extentX2
, extentY1
, extentY2
;
787 int fullX1
, fullX2
, fullY1
, fullY2
;
788 int partX1
, partX2
, partY1
, partY2
;
792 RegionPtr pReg
= RegionFromRects(nrect
, prect
, CT_UNSORTED
);
794 /* Compute intersection of rects and clip region */
795 RegionTranslate(pReg
, pDrawable
->x
, pDrawable
->y
);
796 RegionIntersect(pReg
, pClip
, pReg
);
798 if (!RegionNumRects(pReg
)) {
802 exaGetDrawableDeltas(pDrawable
, pPixmap
, &xoff
, &yoff
);
804 if (pExaScr
->fallback_counter
|| pExaScr
->swappedOut
||
805 pExaPixmap
->accel_blocked
) {
809 /* For ROPs where overlaps don't matter, convert rectangles to region and
810 * call exaFillRegion{Solid,Tiled}.
812 if ((pGC
->fillStyle
== FillSolid
|| pGC
->fillStyle
== FillTiled
) &&
813 (nrect
== 1 || pGC
->alu
== GXcopy
|| pGC
->alu
== GXclear
||
814 pGC
->alu
== GXnoop
|| pGC
->alu
== GXcopyInverted
||
815 pGC
->alu
== GXset
)) {
816 if (((pGC
->fillStyle
== FillSolid
|| pGC
->tileIsPixel
) &&
817 exaFillRegionSolid(pDrawable
, pReg
, pGC
->fillStyle
== FillSolid
?
818 pGC
->fgPixel
: pGC
->tile
.pixel
, pGC
->planemask
,
819 pGC
->alu
, pGC
->clientClipType
)) ||
820 (pGC
->fillStyle
== FillTiled
&& !pGC
->tileIsPixel
&&
821 exaFillRegionTiled(pDrawable
, pReg
, pGC
->tile
.pixmap
, &pGC
->patOrg
,
822 pGC
->planemask
, pGC
->alu
,
823 pGC
->clientClipType
))) {
828 if (pGC
->fillStyle
!= FillSolid
&&
829 !(pGC
->tileIsPixel
&& pGC
->fillStyle
== FillTiled
)) {
833 if (pExaScr
->do_migration
) {
834 ExaMigrationRec pixmaps
[1];
836 pixmaps
[0].as_dst
= TRUE
;
837 pixmaps
[0].as_src
= FALSE
;
838 pixmaps
[0].pPix
= pPixmap
;
839 pixmaps
[0].pReg
= NULL
;
841 exaDoMigration(pixmaps
, 1, TRUE
);
844 if (!exaPixmapHasGpuCopy(pPixmap
) ||
845 !(*pExaScr
->info
->PrepareSolid
) (pPixmap
,
847 pGC
->planemask
, pGC
->fgPixel
)) {
849 ExaCheckPolyFillRect(pDrawable
, pGC
, nrect
, prect
);
856 pextent
= RegionExtents(pClip
);
857 extentX1
= pextent
->x1
;
858 extentY1
= pextent
->y1
;
859 extentX2
= pextent
->x2
;
860 extentY2
= pextent
->y2
;
862 fullX1
= prect
->x
+ xorg
;
863 fullY1
= prect
->y
+ yorg
;
864 fullX2
= fullX1
+ (int) prect
->width
;
865 fullY2
= fullY1
+ (int) prect
->height
;
868 if (fullX1
< extentX1
)
871 if (fullY1
< extentY1
)
874 if (fullX2
> extentX2
)
877 if (fullY2
> extentY2
)
880 if ((fullX1
>= fullX2
) || (fullY1
>= fullY2
))
882 n
= RegionNumRects(pClip
);
884 (*pExaScr
->info
->Solid
) (pPixmap
,
885 fullX1
+ xoff
, fullY1
+ yoff
,
886 fullX2
+ xoff
, fullY2
+ yoff
);
889 pbox
= RegionRects(pClip
);
891 * clip the rectangle to each box in the clip region
892 * this is logically equivalent to calling Intersect(),
893 * but rectangles may overlap each other here.
911 if (partX1
< partX2
&& partY1
< partY2
) {
912 (*pExaScr
->info
->Solid
) (pPixmap
,
913 partX1
+ xoff
, partY1
+ yoff
,
914 partX2
+ xoff
, partY2
+ yoff
);
919 (*pExaScr
->info
->DoneSolid
) (pPixmap
);
920 exaMarkSync(pDrawable
->pScreen
);
927 const GCOps exaOps
= {
945 ExaCheckImageGlyphBlt
,
946 ExaCheckPolyGlyphBlt
,
951 exaCopyWindow(WindowPtr pWin
, DDXPointRec ptOldOrg
, RegionPtr prgnSrc
)
955 PixmapPtr pPixmap
= (*pWin
->drawable
.pScreen
->GetWindowPixmap
) (pWin
);
957 ExaScreenPriv(pWin
->drawable
.pScreen
);
959 dx
= ptOldOrg
.x
- pWin
->drawable
.x
;
960 dy
= ptOldOrg
.y
- pWin
->drawable
.y
;
961 RegionTranslate(prgnSrc
, -dx
, -dy
);
963 RegionInit(&rgnDst
, NullBox
, 0);
965 RegionIntersect(&rgnDst
, &pWin
->borderClip
, prgnSrc
);
967 if (pPixmap
->screen_x
|| pPixmap
->screen_y
)
968 RegionTranslate(&rgnDst
, -pPixmap
->screen_x
, -pPixmap
->screen_y
);
971 if (pExaScr
->fallback_counter
) {
972 pExaScr
->fallback_flags
|= EXA_FALLBACK_COPYWINDOW
;
976 pExaScr
->fallback_flags
|= EXA_ACCEL_COPYWINDOW
;
977 miCopyRegion(&pPixmap
->drawable
, &pPixmap
->drawable
,
978 NULL
, &rgnDst
, dx
, dy
, exaCopyNtoN
, 0, NULL
);
979 pExaScr
->fallback_flags
&= ~EXA_ACCEL_COPYWINDOW
;
982 RegionUninit(&rgnDst
);
984 if (pExaScr
->fallback_flags
& EXA_FALLBACK_COPYWINDOW
) {
985 pExaScr
->fallback_flags
&= ~EXA_FALLBACK_COPYWINDOW
;
986 RegionTranslate(prgnSrc
, dx
, dy
);
987 ExaCheckCopyWindow(pWin
, ptOldOrg
, prgnSrc
);
992 exaFillRegionSolid(DrawablePtr pDrawable
, RegionPtr pRegion
, Pixel pixel
,
993 CARD32 planemask
, CARD32 alu
, unsigned int clientClipType
)
995 ExaScreenPriv(pDrawable
->pScreen
);
996 PixmapPtr pPixmap
= exaGetDrawablePixmap(pDrawable
);
998 ExaPixmapPriv(pPixmap
);
1002 exaGetDrawableDeltas(pDrawable
, pPixmap
, &xoff
, &yoff
);
1003 RegionTranslate(pRegion
, xoff
, yoff
);
1005 if (pExaScr
->fallback_counter
|| pExaPixmap
->accel_blocked
)
1008 if (pExaScr
->do_migration
) {
1009 ExaMigrationRec pixmaps
[1];
1011 pixmaps
[0].as_dst
= TRUE
;
1012 pixmaps
[0].as_src
= FALSE
;
1013 pixmaps
[0].pPix
= pPixmap
;
1014 pixmaps
[0].pReg
= exaGCReadsDestination(pDrawable
, planemask
, FillSolid
,
1016 clientClipType
) ? NULL
:
1019 exaDoMigration(pixmaps
, 1, TRUE
);
1022 if (exaPixmapHasGpuCopy(pPixmap
) &&
1023 (*pExaScr
->info
->PrepareSolid
) (pPixmap
, alu
, planemask
, pixel
)) {
1027 nbox
= RegionNumRects(pRegion
);
1028 pBox
= RegionRects(pRegion
);
1031 (*pExaScr
->info
->Solid
) (pPixmap
, pBox
->x1
, pBox
->y1
, pBox
->x2
,
1035 (*pExaScr
->info
->DoneSolid
) (pPixmap
);
1036 exaMarkSync(pDrawable
->pScreen
);
1038 if (pExaPixmap
->pDamage
&&
1039 pExaPixmap
->sys_ptr
&& pDrawable
->type
== DRAWABLE_PIXMAP
&&
1040 pDrawable
->width
== 1 && pDrawable
->height
== 1 &&
1041 pDrawable
->bitsPerPixel
!= 24) {
1042 ExaPixmapPriv(pPixmap
);
1043 RegionPtr pending_damage
= DamagePendingRegion(pExaPixmap
->pDamage
);
1045 switch (pDrawable
->bitsPerPixel
) {
1047 *(CARD32
*) pExaPixmap
->sys_ptr
= pixel
;
1050 *(CARD16
*) pExaPixmap
->sys_ptr
= pixel
;
1055 *(CARD8
*) pExaPixmap
->sys_ptr
= pixel
;
1058 RegionUnion(&pExaPixmap
->validSys
, &pExaPixmap
->validSys
, pRegion
);
1059 RegionUnion(&pExaPixmap
->validFB
, &pExaPixmap
->validFB
, pRegion
);
1060 RegionSubtract(pending_damage
, pending_damage
, pRegion
);
1067 RegionTranslate(pRegion
, -xoff
, -yoff
);
1072 /* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
1073 * Based on fbFillRegionTiled(), fbTile().
1076 exaFillRegionTiled(DrawablePtr pDrawable
, RegionPtr pRegion
, PixmapPtr pTile
,
1077 DDXPointPtr pPatOrg
, CARD32 planemask
, CARD32 alu
,
1078 unsigned int clientClipType
)
1080 ExaScreenPriv(pDrawable
->pScreen
);
1082 ExaPixmapPrivPtr pExaPixmap
;
1083 ExaPixmapPrivPtr pTileExaPixmap
= ExaGetPixmapPriv(pTile
);
1085 int tileWidth
, tileHeight
;
1086 int nbox
= RegionNumRects(pRegion
);
1087 BoxPtr pBox
= RegionRects(pRegion
);
1091 tileWidth
= pTile
->drawable
.width
;
1092 tileHeight
= pTile
->drawable
.height
;
1094 /* If we're filling with a solid color, grab it out and go to
1095 * FillRegionSolid, saving numerous copies.
1097 if (tileWidth
== 1 && tileHeight
== 1)
1098 return exaFillRegionSolid(pDrawable
, pRegion
,
1099 exaGetPixmapFirstPixel(pTile
), planemask
,
1100 alu
, clientClipType
);
1102 pPixmap
= exaGetDrawablePixmap(pDrawable
);
1103 pExaPixmap
= ExaGetPixmapPriv(pPixmap
);
1105 if (pExaScr
->fallback_counter
|| pExaPixmap
->accel_blocked
||
1106 pTileExaPixmap
->accel_blocked
)
1109 if (pExaScr
->do_migration
) {
1110 ExaMigrationRec pixmaps
[2];
1112 pixmaps
[0].as_dst
= TRUE
;
1113 pixmaps
[0].as_src
= FALSE
;
1114 pixmaps
[0].pPix
= pPixmap
;
1115 pixmaps
[0].pReg
= exaGCReadsDestination(pDrawable
, planemask
, FillTiled
,
1117 clientClipType
) ? NULL
:
1119 pixmaps
[1].as_dst
= FALSE
;
1120 pixmaps
[1].as_src
= TRUE
;
1121 pixmaps
[1].pPix
= pTile
;
1122 pixmaps
[1].pReg
= NULL
;
1124 exaDoMigration(pixmaps
, 2, TRUE
);
1127 pPixmap
= exaGetOffscreenPixmap(pDrawable
, &xoff
, &yoff
);
1129 if (!pPixmap
|| !exaPixmapHasGpuCopy(pTile
))
1132 if ((*pExaScr
->info
->PrepareCopy
) (pTile
, pPixmap
, 1, 1, alu
, planemask
)) {
1134 RegionTranslate(pRegion
, xoff
, yoff
);
1136 for (i
= 0; i
< nbox
; i
++) {
1137 int height
= pBox
[i
].y2
- pBox
[i
].y1
;
1138 int dstY
= pBox
[i
].y1
;
1142 height
= min(height
, tileHeight
);
1144 modulus(dstY
- yoff
- pDrawable
->y
- pPatOrg
->y
, tileHeight
, tileY
);
1146 while (height
> 0) {
1147 int width
= pBox
[i
].x2
- pBox
[i
].x1
;
1148 int dstX
= pBox
[i
].x1
;
1150 int h
= tileHeight
- tileY
;
1153 width
= min(width
, tileWidth
);
1159 modulus(dstX
- xoff
- pDrawable
->x
- pPatOrg
->x
, tileWidth
,
1163 int w
= tileWidth
- tileX
;
1169 (*pExaScr
->info
->Copy
) (pPixmap
, tileX
, tileY
, dstX
, dstY
,
1178 (*pExaScr
->info
->DoneCopy
) (pPixmap
);
1180 /* With GXcopy, we only need to do the basic algorithm up to the tile
1181 * size; then, we can just keep doubling the destination in each
1182 * direction until it fills the box. This way, the number of copy
1183 * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
1184 * rx/ry is the ratio between box and tile width/height. This can make
1185 * a big difference if each driver copy incurs a significant constant
1191 Bool more_copy
= FALSE
;
1193 for (i
= 0; i
< nbox
; i
++) {
1194 int dstX
= pBox
[i
].x1
+ tileWidth
;
1195 int dstY
= pBox
[i
].y1
+ tileHeight
;
1197 if ((dstX
< pBox
[i
].x2
) || (dstY
< pBox
[i
].y2
)) {
1203 if (more_copy
== FALSE
)
1206 if (more_copy
&& (*pExaScr
->info
->PrepareCopy
) (pPixmap
, pPixmap
,
1209 for (i
= 0; i
< nbox
; i
++) {
1210 int dstX
= pBox
[i
].x1
+ tileWidth
;
1211 int dstY
= pBox
[i
].y1
+ tileHeight
;
1212 int width
= min(pBox
[i
].x2
- dstX
, tileWidth
);
1213 int height
= min(pBox
[i
].y2
- pBox
[i
].y1
, tileHeight
);
1215 while (dstX
< pBox
[i
].x2
) {
1216 (*pExaScr
->info
->Copy
) (pPixmap
, pBox
[i
].x1
, pBox
[i
].y1
,
1217 dstX
, pBox
[i
].y1
, width
,
1220 width
= min(pBox
[i
].x2
- dstX
, width
* 2);
1223 width
= pBox
[i
].x2
- pBox
[i
].x1
;
1224 height
= min(pBox
[i
].y2
- dstY
, tileHeight
);
1226 while (dstY
< pBox
[i
].y2
) {
1227 (*pExaScr
->info
->Copy
) (pPixmap
, pBox
[i
].x1
, pBox
[i
].y1
,
1228 pBox
[i
].x1
, dstY
, width
,
1231 height
= min(pBox
[i
].y2
- dstY
, height
* 2);
1235 (*pExaScr
->info
->DoneCopy
) (pPixmap
);
1241 exaMarkSync(pDrawable
->pScreen
);
1244 RegionTranslate(pRegion
, -xoff
, -yoff
);
1251 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
1253 * This is probably the only case we actually care about. The rest fall through
1254 * to migration and fbGetImage, which hopefully will result in migration pushing
1255 * the pixmap out of framebuffer.
1258 exaGetImage(DrawablePtr pDrawable
, int x
, int y
, int w
, int h
,
1259 unsigned int format
, unsigned long planeMask
, char *d
)
1261 ExaScreenPriv(pDrawable
->pScreen
);
1262 PixmapPtr pPix
= exaGetDrawablePixmap(pDrawable
);
1264 ExaPixmapPriv(pPix
);
1268 if (pExaScr
->fallback_counter
|| pExaScr
->swappedOut
)
1271 /* If there's a system copy, we want to save the result there */
1272 if (pExaPixmap
->pDamage
)
1275 pPix
= exaGetOffscreenPixmap(pDrawable
, &xoff
, &yoff
);
1277 if (pPix
== NULL
|| pExaScr
->info
->DownloadFromScreen
== NULL
)
1280 /* Only cover the ZPixmap, solid copy case. */
1281 if (format
!= ZPixmap
|| !EXA_PM_IS_SOLID(pDrawable
, planeMask
))
1284 /* Only try to handle the 8bpp and up cases, since we don't want to think
1287 if (pDrawable
->bitsPerPixel
< 8)
1290 ok
= pExaScr
->info
->DownloadFromScreen(pPix
, pDrawable
->x
+ x
+ xoff
,
1291 pDrawable
->y
+ y
+ yoff
, w
, h
, d
,
1292 PixmapBytePad(w
, pDrawable
->depth
));
1294 exaWaitSync(pDrawable
->pScreen
);
1299 ExaCheckGetImage(pDrawable
, x
, y
, w
, h
, format
, planeMask
, d
);