exa_accel.c revision 05b261ec
1/*
2 * Copyright � 2001 Keith Packard
3 *
4 * Partly based on code that is Copyright � The XFree86 Project Inc.
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission.  Keith Packard makes no
13 * representations about the suitability of this software for any purpose.  It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Authors:
25 *    Eric Anholt <eric@anholt.net>
26 *    Michel D�nzer <michel@tungstengraphics.com>
27 *
28 */
29
30#ifdef HAVE_DIX_CONFIG_H
31#include <dix-config.h>
32#endif
33#include "exa_priv.h"
34#include <X11/fonts/fontstruct.h>
35#include "dixfontstr.h"
36#include "exa.h"
37#include "cw.h"
38
39static void
40exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
41	     DDXPointPtr ppt, int *pwidth, int fSorted)
42{
43    ScreenPtr	    pScreen = pDrawable->pScreen;
44    ExaScreenPriv (pScreen);
45    RegionPtr	    pClip = fbGetCompositeClip(pGC);
46    PixmapPtr	    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;
53    ExaMigrationRec pixmaps[1];
54
55    pixmaps[0].as_dst = TRUE;
56    pixmaps[0].as_src = FALSE;
57    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
58
59    if (pExaScr->swappedOut ||
60	pGC->fillStyle != FillSolid ||
61	pPixmap->drawable.width > pExaScr->info->maxX ||
62	pPixmap->drawable.height > pExaScr->info->maxY)
63    {
64	exaDoMigration (pixmaps, 1, FALSE);
65	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
66	return;
67    } else {
68	exaDoMigration (pixmaps, 1, TRUE);
69    }
70
71    if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
72	!(*pExaScr->info->PrepareSolid) (pPixmap,
73					 pGC->alu,
74					 pGC->planemask,
75					 pGC->fgPixel))
76    {
77	exaDoMigration (pixmaps, 1, FALSE);
78	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
79	return;
80    }
81
82    pextent = REGION_EXTENTS(pGC->pScreen, pClip);
83    extentX1 = pextent->x1;
84    extentY1 = pextent->y1;
85    extentX2 = pextent->x2;
86    extentY2 = pextent->y2;
87    while (n--)
88    {
89	fullX1 = ppt->x;
90	fullY1 = ppt->y;
91	fullX2 = fullX1 + (int) *pwidth;
92	ppt++;
93	pwidth++;
94
95	if (fullY1 < extentY1 || extentY2 <= fullY1)
96	    continue;
97
98	if (fullX1 < extentX1)
99	    fullX1 = extentX1;
100
101	if (fullX2 > extentX2)
102	    fullX2 = extentX2;
103
104	if (fullX1 >= fullX2)
105	    continue;
106
107	nbox = REGION_NUM_RECTS (pClip);
108	if (nbox == 1)
109	{
110	    (*pExaScr->info->Solid) (pPixmap,
111				     fullX1 + off_x, fullY1 + off_y,
112				     fullX2 + off_x, fullY1 + 1 + off_y);
113	}
114	else
115	{
116	    pbox = REGION_RECTS(pClip);
117	    while(nbox--)
118	    {
119		if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
120		{
121		    partX1 = pbox->x1;
122		    if (partX1 < fullX1)
123			partX1 = fullX1;
124		    partX2 = pbox->x2;
125		    if (partX2 > fullX2)
126			partX2 = fullX2;
127		    if (partX2 > partX1) {
128			(*pExaScr->info->Solid) (pPixmap,
129						 partX1 + off_x, fullY1 + off_y,
130						 partX2 + off_x, fullY1 + 1 + off_y);
131		    }
132		}
133		pbox++;
134	    }
135	}
136    }
137    (*pExaScr->info->DoneSolid) (pPixmap);
138    exaMarkSync(pScreen);
139}
140
141static void
142exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
143	     int w, int h, int leftPad, int format, char *bits)
144{
145    ExaScreenPriv (pDrawable->pScreen);
146    PixmapPtr pPix;
147    ExaMigrationRec pixmaps[1];
148    RegionPtr pClip;
149    BoxPtr pbox;
150    int nbox;
151    int xoff, yoff;
152    int src_stride, bpp = pDrawable->bitsPerPixel;
153
154    pixmaps[0].as_dst = TRUE;
155    pixmaps[0].as_src = FALSE;
156    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
157
158    /* Don't bother with under 8bpp, XYPixmaps. */
159    if (format != ZPixmap || bpp < 8)
160	goto migrate_and_fallback;
161
162    /* Only accelerate copies: no rop or planemask. */
163    if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
164	goto migrate_and_fallback;
165
166    if (pExaScr->swappedOut)
167	goto fallback;
168
169    exaDoMigration (pixmaps, 1, TRUE);
170
171    if (pExaScr->info->UploadToScreen == NULL)
172	goto fallback;
173
174    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
175
176    if (pPix == NULL)
177	goto fallback;
178
179    x += pDrawable->x;
180    y += pDrawable->y;
181
182    pClip = fbGetCompositeClip(pGC);
183    src_stride = PixmapBytePad(w, pDrawable->depth);
184    for (nbox = REGION_NUM_RECTS(pClip),
185	 pbox = REGION_RECTS(pClip);
186	 nbox--;
187	 pbox++)
188    {
189	int x1 = x;
190	int y1 = y;
191	int x2 = x + w;
192	int y2 = y + h;
193	char *src;
194	Bool ok;
195
196	if (x1 < pbox->x1)
197	    x1 = pbox->x1;
198	if (y1 < pbox->y1)
199	    y1 = pbox->y1;
200	if (x2 > pbox->x2)
201	    x2 = pbox->x2;
202	if (y2 > pbox->y2)
203	    y2 = pbox->y2;
204	if (x1 >= x2 || y1 >= y2)
205	    continue;
206
207	src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
208	ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
209					   x2 - x1, y2 - y1, src, src_stride);
210	/* If we fail to accelerate the upload, fall back to using unaccelerated
211	 * fb calls.
212	 */
213	if (!ok) {
214	    FbStip *dst;
215	    FbStride dst_stride;
216	    int	dstBpp;
217	    int	dstXoff, dstYoff;
218
219	    exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
220
221	    fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp,
222			      dstXoff, dstYoff);
223
224	    fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)),
225		      src_stride / sizeof(FbStip),
226		      (x1 - x) * dstBpp,
227		      dst + (y1 + dstYoff) * dst_stride,
228		      dst_stride,
229		      (x1 + dstXoff) * dstBpp,
230		      (x2 - x1) * dstBpp,
231		      y2 - y1,
232		      GXcopy, FB_ALLONES, dstBpp);
233
234	    exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
235	}
236
237	exaPixmapDirty(pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
238    }
239
240    return;
241
242migrate_and_fallback:
243    exaDoMigration (pixmaps, 1, FALSE);
244
245fallback:
246    ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
247}
248
249static Bool inline
250exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
251		   GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
252{
253    ExaScreenPriv (pDstDrawable->pScreen);
254    PixmapPtr pSrcPixmap, pDstPixmap;
255    int src_off_x, src_off_y, dst_off_x, dst_off_y;
256    int dirsetup;
257
258    /* Need to get both pixmaps to call the driver routines */
259    pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
260    pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
261    if (!pSrcPixmap || !pDstPixmap)
262	return FALSE;
263
264    /*
265     * Now the case of a chip that only supports xdir = ydir = 1 or
266     * xdir = ydir = -1, but we have xdir != ydir.
267     */
268    dirsetup = 0;	/* No direction set up yet. */
269    for (; nbox; pbox++, nbox--) {
270	if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
271	    /* Do a xdir = ydir = -1 blit instead. */
272	    if (dirsetup != -1) {
273		if (dirsetup != 0)
274		    pExaScr->info->DoneCopy(pDstPixmap);
275		dirsetup = -1;
276		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
277						   pDstPixmap,
278						   -1, -1,
279						   pGC ? pGC->alu : GXcopy,
280						   pGC ? pGC->planemask :
281							 FB_ALLONES))
282		    return FALSE;
283	    }
284	    (*pExaScr->info->Copy)(pDstPixmap,
285				   src_off_x + pbox->x1 + dx,
286				   src_off_y + pbox->y1 + dy,
287				   dst_off_x + pbox->x1,
288				   dst_off_y + pbox->y1,
289				   pbox->x2 - pbox->x1,
290				   pbox->y2 - pbox->y1);
291	} else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
292	    /* Do a xdir = ydir = 1 blit instead. */
293	    if (dirsetup != 1) {
294		if (dirsetup != 0)
295		    pExaScr->info->DoneCopy(pDstPixmap);
296		dirsetup = 1;
297		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
298						   pDstPixmap,
299						   1, 1,
300						   pGC ? pGC->alu : GXcopy,
301						   pGC ? pGC->planemask :
302							 FB_ALLONES))
303		    return FALSE;
304	    }
305	    (*pExaScr->info->Copy)(pDstPixmap,
306				   src_off_x + pbox->x1 + dx,
307				   src_off_y + pbox->y1 + dy,
308				   dst_off_x + pbox->x1,
309				   dst_off_y + pbox->y1,
310				   pbox->x2 - pbox->x1,
311				   pbox->y2 - pbox->y1);
312	} else if (dx >= 0) {
313	    /*
314	     * xdir = 1, ydir = -1.
315	     * Perform line-by-line xdir = ydir = 1 blits, going up.
316	     */
317	    int i;
318	    if (dirsetup != 1) {
319		if (dirsetup != 0)
320		    pExaScr->info->DoneCopy(pDstPixmap);
321		dirsetup = 1;
322		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
323						   pDstPixmap,
324						   1, 1,
325						   pGC ? pGC->alu : GXcopy,
326						   pGC ? pGC->planemask :
327							 FB_ALLONES))
328		    return FALSE;
329	    }
330	    for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
331		(*pExaScr->info->Copy)(pDstPixmap,
332				       src_off_x + pbox->x1 + dx,
333				       src_off_y + pbox->y1 + dy + i,
334				       dst_off_x + pbox->x1,
335				       dst_off_y + pbox->y1 + i,
336				       pbox->x2 - pbox->x1, 1);
337	} else {
338	    /*
339	     * xdir = -1, ydir = 1.
340	     * Perform line-by-line xdir = ydir = -1 blits, going down.
341	     */
342	    int i;
343	    if (dirsetup != -1) {
344		if (dirsetup != 0)
345		    pExaScr->info->DoneCopy(pDstPixmap);
346		dirsetup = -1;
347		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
348						   pDstPixmap,
349						   -1, -1,
350						   pGC ? pGC->alu : GXcopy,
351						   pGC ? pGC->planemask :
352							 FB_ALLONES))
353		    return FALSE;
354	    }
355	    for (i = 0; i < pbox->y2 - pbox->y1; i++)
356		(*pExaScr->info->Copy)(pDstPixmap,
357				       src_off_x + pbox->x1 + dx,
358				       src_off_y + pbox->y1 + dy + i,
359				       dst_off_x + pbox->x1,
360				       dst_off_y + pbox->y1 + i,
361				       pbox->x2 - pbox->x1, 1);
362	}
363	exaPixmapDirty(pDstPixmap, dst_off_x + pbox->x1, dst_off_y + pbox->y1,
364		       dst_off_x + pbox->x2, dst_off_y + pbox->y2);
365    }
366    if (dirsetup != 0)
367	pExaScr->info->DoneCopy(pDstPixmap);
368    exaMarkSync(pDstDrawable->pScreen);
369    return TRUE;
370}
371
372void
373exaCopyNtoN (DrawablePtr    pSrcDrawable,
374	     DrawablePtr    pDstDrawable,
375	     GCPtr	    pGC,
376	     BoxPtr	    pbox,
377	     int	    nbox,
378	     int	    dx,
379	     int	    dy,
380	     Bool	    reverse,
381	     Bool	    upsidedown,
382	     Pixel	    bitplane,
383	     void	    *closure)
384{
385    ExaScreenPriv (pDstDrawable->pScreen);
386    PixmapPtr pSrcPixmap, pDstPixmap;
387    int	    src_off_x, src_off_y;
388    int	    dst_off_x, dst_off_y;
389    ExaMigrationRec pixmaps[2];
390    Bool fallback = FALSE;
391
392    pixmaps[0].as_dst = TRUE;
393    pixmaps[0].as_src = FALSE;
394    pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
395    pixmaps[1].as_dst = FALSE;
396    pixmaps[1].as_src = TRUE;
397    pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
398
399    /* Respect maxX/maxY in a trivial way: don't set up drawing when we might
400     * violate the limits.  The proper solution would be a temporary pixmap
401     * adjusted so that the drawing happened within limits.
402     */
403    if (pSrcPixmap->drawable.width > pExaScr->info->maxX ||
404	pSrcPixmap->drawable.height > pExaScr->info->maxY ||
405	pDstPixmap->drawable.width > pExaScr->info->maxX ||
406	pDstPixmap->drawable.height > pExaScr->info->maxY)
407    {
408	fallback = TRUE;
409    } else {
410	exaDoMigration (pixmaps, 2, TRUE);
411    }
412
413    /* Mixed directions must be handled specially if the card is lame */
414    if (!fallback && (pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
415	reverse != upsidedown) {
416	if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
417			       dx, dy))
418	    return;
419	fallback = TRUE;
420    }
421
422    pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
423    pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
424
425    exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
426    exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
427
428    if (fallback || !exaPixmapIsOffscreen(pSrcPixmap) ||
429	!exaPixmapIsOffscreen(pDstPixmap) ||
430	!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
431					upsidedown ? -1 : 1,
432					pGC ? pGC->alu : GXcopy,
433					pGC ? pGC->planemask : FB_ALLONES)) {
434	fallback = TRUE;
435	EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
436		      exaDrawableLocation(pSrcDrawable),
437		      exaDrawableLocation(pDstDrawable)));
438	exaDoMigration (pixmaps, 2, FALSE);
439	exaPrepareAccess (pDstDrawable, EXA_PREPARE_DEST);
440	exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC);
441	fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
442		    pbox, nbox, dx, dy, reverse, upsidedown,
443		    bitplane, closure);
444	exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC);
445	exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST);
446    }
447
448    while (nbox--)
449    {
450	if (!fallback)
451	    (*pExaScr->info->Copy) (pDstPixmap,
452				    pbox->x1 + dx + src_off_x,
453				    pbox->y1 + dy + src_off_y,
454				    pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
455				    pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
456	exaPixmapDirty (pDstPixmap, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
457			pbox->x2  + dst_off_x, pbox->y2 + dst_off_y);
458	pbox++;
459    }
460
461    if (fallback)
462	return;
463
464    (*pExaScr->info->DoneCopy) (pDstPixmap);
465    exaMarkSync (pDstDrawable->pScreen);
466}
467
468RegionPtr
469exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
470	    int srcx, int srcy, int width, int height, int dstx, int dsty)
471{
472    ExaScreenPriv (pDstDrawable->pScreen);
473
474    if (pExaScr->swappedOut) {
475        return  ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
476                                 srcx, srcy, width, height, dstx, dsty);
477    }
478
479    return  fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
480                      srcx, srcy, width, height,
481                      dstx, dsty, exaCopyNtoN, 0, NULL);
482}
483
484static void
485exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
486	     DDXPointPtr ppt)
487{
488    int i;
489    xRectangle *prect;
490
491    /* If we can't reuse the current GC as is, don't bother accelerating the
492     * points.
493     */
494    if (pGC->fillStyle != FillSolid) {
495	ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
496	return;
497    }
498
499    prect = ALLOCATE_LOCAL(sizeof(xRectangle) * npt);
500    for (i = 0; i < npt; i++) {
501	prect[i].x = ppt[i].x;
502	prect[i].y = ppt[i].y;
503	if (i > 0 && mode == CoordModePrevious) {
504	    prect[i].x += prect[i - 1].x;
505	    prect[i].y += prect[i - 1].y;
506	}
507	prect[i].width = 1;
508	prect[i].height = 1;
509    }
510    pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
511    DEALLOCATE_LOCAL(prect);
512}
513
514/**
515 * exaPolylines() checks if it can accelerate the lines as a group of
516 * horizontal or vertical lines (rectangles), and uses existing rectangle fill
517 * acceleration if so.
518 */
519static void
520exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
521	     DDXPointPtr ppt)
522{
523    xRectangle *prect;
524    int x1, x2, y1, y2;
525    int i;
526
527    /* Don't try to do wide lines or non-solid fill style. */
528    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
529	pGC->fillStyle != FillSolid) {
530	ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
531	return;
532    }
533
534    prect = ALLOCATE_LOCAL(sizeof(xRectangle) * (npt - 1));
535    x1 = ppt[0].x;
536    y1 = ppt[0].y;
537    /* If we have any non-horizontal/vertical, fall back. */
538    for (i = 0; i < npt - 1; i++) {
539	if (mode == CoordModePrevious) {
540	    x2 = x1 + ppt[i + 1].x;
541	    y2 = y1 + ppt[i + 1].y;
542	} else {
543	    x2 = ppt[i + 1].x;
544	    y2 = ppt[i + 1].y;
545	}
546
547	if (x1 != x2 && y1 != y2) {
548	    DEALLOCATE_LOCAL(prect);
549	    ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
550	    return;
551	}
552
553	if (x1 < x2) {
554	    prect[i].x = x1;
555	    prect[i].width = x2 - x1 + 1;
556	} else {
557	    prect[i].x = x2;
558	    prect[i].width = x1 - x2 + 1;
559	}
560	if (y1 < y2) {
561	    prect[i].y = y1;
562	    prect[i].height = y2 - y1 + 1;
563	} else {
564	    prect[i].y = y2;
565	    prect[i].height = y1 - y2 + 1;
566	}
567
568	x1 = x2;
569	y1 = y2;
570    }
571    pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
572    DEALLOCATE_LOCAL(prect);
573}
574
575/**
576 * exaPolySegment() checks if it can accelerate the lines as a group of
577 * horizontal or vertical lines (rectangles), and uses existing rectangle fill
578 * acceleration if so.
579 */
580static void
581exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
582		xSegment *pSeg)
583{
584    xRectangle *prect;
585    int i;
586
587    /* Don't try to do wide lines or non-solid fill style. */
588    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
589	pGC->fillStyle != FillSolid)
590    {
591	ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
592	return;
593    }
594
595    /* If we have any non-horizontal/vertical, fall back. */
596    for (i = 0; i < nseg; i++) {
597	if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
598	    ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
599	    return;
600	}
601    }
602
603    prect = ALLOCATE_LOCAL(sizeof(xRectangle) * nseg);
604    for (i = 0; i < nseg; i++) {
605	if (pSeg[i].x1 < pSeg[i].x2) {
606	    prect[i].x = pSeg[i].x1;
607	    prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
608	} else {
609	    prect[i].x = pSeg[i].x2;
610	    prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
611	}
612	if (pSeg[i].y1 < pSeg[i].y2) {
613	    prect[i].y = pSeg[i].y1;
614	    prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
615	} else {
616	    prect[i].y = pSeg[i].y2;
617	    prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
618	}
619    }
620    pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
621    DEALLOCATE_LOCAL(prect);
622}
623
624static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
625				Pixel pixel, CARD32 planemask, CARD32 alu);
626
627static void
628exaPolyFillRect(DrawablePtr pDrawable,
629		GCPtr	    pGC,
630		int	    nrect,
631		xRectangle  *prect)
632{
633    ExaScreenPriv (pDrawable->pScreen);
634    RegionPtr	    pClip = fbGetCompositeClip(pGC);
635    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
636    register BoxPtr pbox;
637    BoxPtr	    pextent;
638    int		    extentX1, extentX2, extentY1, extentY2;
639    int		    fullX1, fullX2, fullY1, fullY2;
640    int		    partX1, partX2, partY1, partY2;
641    int		    xoff, yoff;
642    int		    xorg, yorg;
643    int		    n;
644    ExaMigrationRec pixmaps[2];
645    RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);
646
647    /* Compute intersection of rects and clip region */
648    REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
649    REGION_INTERSECT(pScreen, pReg, pClip, pReg);
650
651    if (!REGION_NUM_RECTS(pReg)) {
652	goto out;
653    }
654
655    pixmaps[0].as_dst = TRUE;
656    pixmaps[0].as_src = FALSE;
657    pixmaps[0].pPix = pPixmap;
658
659    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
660
661    if (pExaScr->swappedOut ||
662	pPixmap->drawable.width > pExaScr->info->maxX ||
663	pPixmap->drawable.height > pExaScr->info->maxY)
664    {
665	goto fallback;
666    }
667
668    /* For ROPs where overlaps don't matter, convert rectangles to region and
669     * call exaFillRegion{Solid,Tiled}.
670     */
671    if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
672	(pGC->alu == GXcopy || pGC->alu == GXclear || pGC->alu == GXnoop ||
673	 pGC->alu == GXcopyInverted || pGC->alu == GXset)) {
674	if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
675	     exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
676				pGC->fgPixel : pGC->tile.pixel,	pGC->planemask,
677				pGC->alu)) ||
678	    (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
679	     exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
680				pGC->planemask, pGC->alu))) {
681	    goto out;
682	}
683    }
684
685    if (pGC->fillStyle != FillSolid &&
686	!(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
687    {
688	goto fallback;
689    }
690
691    exaDoMigration (pixmaps, 1, TRUE);
692
693    if (!exaPixmapIsOffscreen (pPixmap) ||
694	!(*pExaScr->info->PrepareSolid) (pPixmap,
695					 pGC->alu,
696					 pGC->planemask,
697					 pGC->fgPixel))
698    {
699fallback:
700	if (pGC->fillStyle == FillTiled && !pGC->tileIsPixel) {
701	    pixmaps[1].as_dst = FALSE;
702	    pixmaps[1].as_src = TRUE;
703	    pixmaps[1].pPix = pGC->tile.pixmap;
704	    exaDoMigration (pixmaps, 2, FALSE);
705	} else {
706	    exaDoMigration (pixmaps, 1, FALSE);
707	}
708
709	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
710	goto out;
711    }
712
713    xorg = pDrawable->x;
714    yorg = pDrawable->y;
715
716    pextent = REGION_EXTENTS(pGC->pScreen, pClip);
717    extentX1 = pextent->x1;
718    extentY1 = pextent->y1;
719    extentX2 = pextent->x2;
720    extentY2 = pextent->y2;
721    while (nrect--)
722    {
723	fullX1 = prect->x + xorg;
724	fullY1 = prect->y + yorg;
725	fullX2 = fullX1 + (int) prect->width;
726	fullY2 = fullY1 + (int) prect->height;
727	prect++;
728
729	if (fullX1 < extentX1)
730	    fullX1 = extentX1;
731
732	if (fullY1 < extentY1)
733	    fullY1 = extentY1;
734
735	if (fullX2 > extentX2)
736	    fullX2 = extentX2;
737
738	if (fullY2 > extentY2)
739	    fullY2 = extentY2;
740
741	if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
742	    continue;
743	n = REGION_NUM_RECTS (pClip);
744	if (n == 1)
745	{
746	    (*pExaScr->info->Solid) (pPixmap,
747				     fullX1 + xoff, fullY1 + yoff,
748				     fullX2 + xoff, fullY2 + yoff);
749	}
750	else
751	{
752	    pbox = REGION_RECTS(pClip);
753	    /*
754	     * clip the rectangle to each box in the clip region
755	     * this is logically equivalent to calling Intersect(),
756	     * but rectangles may overlap each other here.
757	     */
758	    while(n--)
759	    {
760		partX1 = pbox->x1;
761		if (partX1 < fullX1)
762		    partX1 = fullX1;
763		partY1 = pbox->y1;
764		if (partY1 < fullY1)
765		    partY1 = fullY1;
766		partX2 = pbox->x2;
767		if (partX2 > fullX2)
768		    partX2 = fullX2;
769		partY2 = pbox->y2;
770		if (partY2 > fullY2)
771		    partY2 = fullY2;
772
773		pbox++;
774
775		if (partX1 < partX2 && partY1 < partY2) {
776		    (*pExaScr->info->Solid) (pPixmap,
777					     partX1 + xoff, partY1 + yoff,
778					     partX2 + xoff, partY2 + yoff);
779		}
780	    }
781	}
782    }
783    (*pExaScr->info->DoneSolid) (pPixmap);
784    exaMarkSync(pDrawable->pScreen);
785
786out:
787    REGION_DESTROY(pScreen, pReg);
788}
789
790static void
791exaSolidBoxClipped (DrawablePtr	pDrawable,
792		    RegionPtr	pClip,
793		    FbBits	pm,
794		    FbBits	fg,
795		    int		x1,
796		    int		y1,
797		    int		x2,
798		    int		y2)
799{
800    ExaScreenPriv (pDrawable->pScreen);
801    PixmapPtr   pPixmap;
802    BoxPtr	pbox;
803    int		nbox;
804    int		xoff, yoff;
805    int		partX1, partX2, partY1, partY2;
806    ExaMigrationRec pixmaps[1];
807    Bool	fallback = FALSE;
808
809    pixmaps[0].as_dst = TRUE;
810    pixmaps[0].as_src = FALSE;
811    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
812
813    if (pExaScr->swappedOut ||
814	pPixmap->drawable.width > pExaScr->info->maxX ||
815	pPixmap->drawable.height > pExaScr->info->maxY)
816    {
817	fallback = TRUE;
818    } else {
819	exaDoMigration (pixmaps, 1, TRUE);
820    }
821
822    exaGetDrawableDeltas (pDrawable, pPixmap, &xoff, &yoff);
823
824    if (fallback || !exaPixmapIsOffscreen(pPixmap) ||
825	!(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, pm, fg))
826    {
827	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
828		      exaDrawableLocation(pDrawable)));
829	exaDoMigration (pixmaps, 1, FALSE);
830	fallback = TRUE;
831	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
832	fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
833	fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2,
834			   fbAnd (GXcopy, fg, pm),
835			   fbXor (GXcopy, fg, pm));
836	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
837    }
838    for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
839	 nbox--;
840	 pbox++)
841    {
842	partX1 = pbox->x1;
843	if (partX1 < x1)
844	    partX1 = x1;
845
846	partX2 = pbox->x2;
847	if (partX2 > x2)
848	    partX2 = x2;
849
850	if (partX2 <= partX1)
851	    continue;
852
853	partY1 = pbox->y1;
854	if (partY1 < y1)
855	    partY1 = y1;
856
857	partY2 = pbox->y2;
858	if (partY2 > y2)
859	    partY2 = y2;
860
861	if (partY2 <= partY1)
862	    continue;
863
864	if (!fallback) {
865	    (*pExaScr->info->Solid) (pPixmap,
866				     partX1 + xoff, partY1 + yoff,
867				     partX2 + xoff, partY2 + yoff);
868	}
869
870	exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff, partX2 + xoff,
871			partY2 + yoff);
872    }
873
874    if (fallback)
875	return;
876
877    (*pExaScr->info->DoneSolid) (pPixmap);
878    exaMarkSync(pDrawable->pScreen);
879}
880
881static void
882exaImageGlyphBlt (DrawablePtr	pDrawable,
883		  GCPtr		pGC,
884		  int		x,
885		  int		y,
886		  unsigned int	nglyph,
887		  CharInfoPtr	*ppciInit,
888		  pointer	pglyphBase)
889{
890    FbGCPrivPtr	    pPriv = fbGetGCPrivate(pGC);
891    CharInfoPtr	    *ppci;
892    CharInfoPtr	    pci;
893    unsigned char   *pglyph;		/* pointer bits in glyph */
894    int		    gWidth, gHeight;	/* width and height of glyph */
895    FbStride	    gStride;		/* stride of glyph */
896    Bool	    opaque;
897    int		    n;
898    int		    gx, gy;
899    void	    (*glyph) (FbBits *,
900			      FbStride,
901			      int,
902			      FbStip *,
903			      FbBits,
904			      int,
905			      int);
906    FbBits	    *dst;
907    FbStride	    dstStride;
908    int		    dstBpp;
909    int		    dstXoff, dstYoff;
910    FbBits	    depthMask;
911    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
912    ExaMigrationRec pixmaps[1];
913    int		    xBack, widthBack, yBack, heightBack;
914
915    for (ppci = ppciInit, n = nglyph, widthBack = 0; n; n--)
916	widthBack += (*ppci++)->metrics.characterWidth;
917
918    xBack = x;
919    if (widthBack < 0)
920    {
921	xBack += widthBack;
922	widthBack = -widthBack;
923    }
924    yBack = y - FONTASCENT(pGC->font);
925    heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
926
927    if (xBack >= pDrawable->width || yBack >= pDrawable->height ||
928	(xBack + widthBack) <= 0 || (yBack + heightBack) <= 0)
929	return;
930
931    pixmaps[0].as_dst = TRUE;
932    pixmaps[0].as_src = TRUE;
933    pixmaps[0].pPix = pPixmap;
934
935    depthMask = FbFullMask(pDrawable->depth);
936    if ((pGC->planemask & depthMask) != depthMask)
937    {
938	exaDoMigration(pixmaps, 1, FALSE);
939	ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
940	goto damage;
941    }
942    glyph = NULL;
943    switch (pDrawable->bitsPerPixel) {
944    case 8:	glyph = fbGlyph8; break;
945    case 16:    glyph = fbGlyph16; break;
946    case 24:    glyph = fbGlyph24; break;
947    case 32:    glyph = fbGlyph32; break;
948    }
949
950    x += pDrawable->x;
951    y += pDrawable->y;
952    xBack += pDrawable->x;
953    yBack += pDrawable->y;
954
955    if (TERMINALFONT (pGC->font) && !glyph)
956    {
957	opaque = TRUE;
958    }
959    else
960    {
961        exaSolidBoxClipped (pDrawable,
962			    fbGetCompositeClip(pGC),
963			    pGC->planemask,
964			    pGC->bgPixel,
965			    xBack,
966			    yBack,
967			    xBack + widthBack,
968			    yBack + heightBack);
969	opaque = FALSE;
970    }
971
972    EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
973    exaDoMigration(pixmaps, 1, FALSE);
974    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
975    exaPrepareAccessGC (pGC);
976
977    fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
978
979    for (ppci = ppciInit; nglyph; nglyph--, x += pci->metrics.characterWidth)
980    {
981	pci = *ppci++;
982	gWidth = GLYPHWIDTHPIXELS(pci);
983	gHeight = GLYPHHEIGHTPIXELS(pci);
984	gx = x + pci->metrics.leftSideBearing;
985	gy = y - pci->metrics.ascent;
986
987	if (!gWidth || !gHeight || (gx + gWidth) <= xBack ||
988	    (gy + gHeight) <= yBack || gx >= (xBack + widthBack) ||
989	    gy >= (yBack + heightBack))
990	    continue;
991
992	pglyph = FONTGLYPHBITS(pglyphBase, pci);
993
994	if (glyph && gWidth <= sizeof (FbStip) * 8 &&
995	    fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
996	{
997	    (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
998		      (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight);
999	}
1000	else
1001	{
1002	    RegionPtr pClip = fbGetCompositeClip(pGC);
1003
1004	    gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
1005	    fbPutXYImage (pDrawable, pClip, pPriv->fg, pPriv->bg, pPriv->pm,
1006			  GXcopy, opaque, gx, gy, gWidth, gHeight,
1007			  (FbStip *) pglyph, gStride, 0);
1008	}
1009    }
1010    exaFinishAccessGC (pGC);
1011    exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
1012
1013damage:
1014    exaGetDrawableDeltas(pDrawable, pPixmap, &dstXoff, &dstYoff);
1015    exaPixmapDirty(pPixmap, xBack + dstXoff, yBack + dstYoff,
1016		   xBack + dstXoff + widthBack, yBack + dstYoff + heightBack);
1017}
1018
1019const GCOps exaOps = {
1020    exaFillSpans,
1021    ExaCheckSetSpans,
1022    exaPutImage,
1023    exaCopyArea,
1024    ExaCheckCopyPlane,
1025    exaPolyPoint,
1026    exaPolylines,
1027    exaPolySegment,
1028    miPolyRectangle,
1029    ExaCheckPolyArc,
1030    miFillPolygon,
1031    exaPolyFillRect,
1032    miPolyFillArc,
1033    miPolyText8,
1034    miPolyText16,
1035    miImageText8,
1036    miImageText16,
1037    exaImageGlyphBlt,
1038    ExaCheckPolyGlyphBlt,
1039    ExaCheckPushPixels,
1040};
1041
1042void
1043exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
1044{
1045    RegionRec	rgnDst;
1046    int		dx, dy;
1047    PixmapPtr	pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
1048
1049    dx = ptOldOrg.x - pWin->drawable.x;
1050    dy = ptOldOrg.y - pWin->drawable.y;
1051    REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
1052
1053    REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
1054
1055    REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
1056#ifdef COMPOSITE
1057    if (pPixmap->screen_x || pPixmap->screen_y)
1058	REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
1059			  -pPixmap->screen_x, -pPixmap->screen_y);
1060#endif
1061
1062    fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
1063		  NULL,
1064		  &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
1065
1066    REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
1067}
1068
1069static Bool
1070exaFillRegionSolid (DrawablePtr	pDrawable,
1071		    RegionPtr	pRegion,
1072		    Pixel	pixel,
1073		    CARD32	planemask,
1074		    CARD32	alu)
1075{
1076    ExaScreenPriv(pDrawable->pScreen);
1077    PixmapPtr pPixmap;
1078    int xoff, yoff;
1079    ExaMigrationRec pixmaps[1];
1080    int nbox = REGION_NUM_RECTS (pRegion);
1081    BoxPtr pBox = REGION_RECTS (pRegion);
1082
1083    pixmaps[0].as_dst = TRUE;
1084    pixmaps[0].as_src = FALSE;
1085    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
1086
1087    if (pPixmap->drawable.width > pExaScr->info->maxX ||
1088	pPixmap->drawable.height > pExaScr->info->maxY)
1089    {
1090	goto fallback;
1091    } else {
1092	exaDoMigration (pixmaps, 1, TRUE);
1093    }
1094
1095    if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
1096	(*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
1097    {
1098	while (nbox--)
1099	{
1100	    (*pExaScr->info->Solid) (pPixmap,
1101				     pBox->x1 + xoff, pBox->y1 + yoff,
1102				     pBox->x2 + xoff, pBox->y2 + yoff);
1103	    pBox++;
1104	}
1105	(*pExaScr->info->DoneSolid) (pPixmap);
1106	exaMarkSync(pDrawable->pScreen);
1107    }
1108    else
1109    {
1110fallback:
1111	if (alu != GXcopy || planemask != FB_ALLONES)
1112	    return FALSE;
1113	EXA_FALLBACK(("to %p (%c)\n", pDrawable,
1114		      exaDrawableLocation(pDrawable)));
1115	exaDoMigration (pixmaps, 1, FALSE);
1116	exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
1117	fbFillRegionSolid (pDrawable, pRegion, 0,
1118			   fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
1119	exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
1120    }
1121
1122    return TRUE;
1123}
1124
1125/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
1126 * Based on fbFillRegionTiled(), fbTile().
1127 */
1128Bool
1129exaFillRegionTiled (DrawablePtr	pDrawable,
1130		    RegionPtr	pRegion,
1131		    PixmapPtr	pTile,
1132		    DDXPointPtr pPatOrg,
1133		    CARD32	planemask,
1134		    CARD32	alu)
1135{
1136    ExaScreenPriv(pDrawable->pScreen);
1137    PixmapPtr pPixmap;
1138    int xoff, yoff, tileXoff, tileYoff;
1139    int tileWidth, tileHeight;
1140    ExaMigrationRec pixmaps[2];
1141    int nbox = REGION_NUM_RECTS (pRegion);
1142    BoxPtr pBox = REGION_RECTS (pRegion);
1143
1144    tileWidth = pTile->drawable.width;
1145    tileHeight = pTile->drawable.height;
1146
1147    /* If we're filling with a solid color, grab it out and go to
1148     * FillRegionSolid, saving numerous copies.
1149     */
1150    if (tileWidth == 1 && tileHeight == 1)
1151	return exaFillRegionSolid(pDrawable, pRegion,
1152				  exaGetPixmapFirstPixel (pTile), planemask,
1153				  alu);
1154
1155    pixmaps[0].as_dst = TRUE;
1156    pixmaps[0].as_src = FALSE;
1157    pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
1158    pixmaps[1].as_dst = FALSE;
1159    pixmaps[1].as_src = TRUE;
1160    pixmaps[1].pPix = pTile;
1161
1162    if (pPixmap->drawable.width > pExaScr->info->maxX ||
1163	pPixmap->drawable.height > pExaScr->info->maxY ||
1164	tileWidth > pExaScr->info->maxX ||
1165	tileHeight > pExaScr->info->maxY)
1166    {
1167	goto fallback;
1168    } else {
1169	exaDoMigration (pixmaps, 2, TRUE);
1170    }
1171
1172    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
1173
1174    if (!pPixmap)
1175	goto fallback;
1176
1177    if (!exaPixmapIsOffscreen(pTile))
1178	goto fallback;
1179
1180    if ((*pExaScr->info->PrepareCopy) (exaGetOffscreenPixmap((DrawablePtr)pTile,
1181							     &tileXoff, &tileYoff),
1182				       pPixmap, 0, 0, alu, planemask))
1183    {
1184	while (nbox--)
1185	{
1186	    int height = pBox->y2 - pBox->y1;
1187	    int dstY = pBox->y1;
1188	    int tileY;
1189
1190	    modulus(dstY - pDrawable->y - pPatOrg->y, tileHeight, tileY);
1191
1192	    while (height > 0) {
1193		int width = pBox->x2 - pBox->x1;
1194		int dstX = pBox->x1;
1195		int tileX;
1196		int h = tileHeight - tileY;
1197
1198		if (h > height)
1199		    h = height;
1200		height -= h;
1201
1202		modulus(dstX - pDrawable->x - pPatOrg->x, tileWidth, tileX);
1203
1204		while (width > 0) {
1205		    int w = tileWidth - tileX;
1206		    if (w > width)
1207			w = width;
1208		    width -= w;
1209
1210		    (*pExaScr->info->Copy) (pPixmap,
1211					    tileX + tileXoff, tileY + tileYoff,
1212					    dstX + xoff, dstY + yoff,
1213					    w, h);
1214		    dstX += w;
1215		    tileX = 0;
1216		}
1217		dstY += h;
1218		tileY = 0;
1219	    }
1220	    pBox++;
1221	}
1222	(*pExaScr->info->DoneCopy) (pPixmap);
1223	exaMarkSync(pDrawable->pScreen);
1224	return TRUE;
1225    }
1226
1227fallback:
1228    if (alu != GXcopy || planemask != FB_ALLONES || pPatOrg->x != 0 ||
1229	pPatOrg->y != 0)
1230	return FALSE;
1231    EXA_FALLBACK(("from %p to %p (%c,%c)\n", pTile, pDrawable,
1232		  exaDrawableLocation(&pTile->drawable),
1233		  exaDrawableLocation(pDrawable)));
1234    exaDoMigration (pixmaps, 2, FALSE);
1235    exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
1236    exaPrepareAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
1237    fbFillRegionTiled (pDrawable, pRegion, pTile);
1238    exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
1239    exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
1240
1241    return TRUE;
1242}
1243
1244void
1245exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
1246{
1247    ExaScreenPriv (pWin->drawable.pScreen);
1248    PixmapPtr pPixmap = exaGetDrawablePixmap((DrawablePtr)pWin);
1249    int xoff, yoff;
1250    BoxPtr pBox;
1251    int nbox = REGION_NUM_RECTS(pRegion);
1252
1253    if (!nbox)
1254	return;
1255
1256    if (!pExaScr->swappedOut) {
1257	DDXPointRec zeros = { 0, 0 };
1258
1259        switch (what) {
1260        case PW_BACKGROUND:
1261            switch (pWin->backgroundState) {
1262            case None:
1263                return;
1264            case ParentRelative:
1265                do {
1266                    pWin = pWin->parent;
1267                } while (pWin->backgroundState == ParentRelative);
1268                (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
1269                                                                 what);
1270                return;
1271            case BackgroundPixel:
1272		exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->background.pixel,
1273				   FB_ALLONES, GXcopy);
1274                goto damage;
1275            case BackgroundPixmap:
1276                exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->background.pixmap,
1277				   &zeros, FB_ALLONES, GXcopy);
1278                goto damage;
1279            }
1280            break;
1281        case PW_BORDER:
1282            if (pWin->borderIsPixel) {
1283                exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->border.pixel,
1284				   FB_ALLONES, GXcopy);
1285                goto damage;
1286            } else {
1287                exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->border.pixmap,
1288				   &zeros, FB_ALLONES, GXcopy);
1289                goto damage;
1290            }
1291            break;
1292        }
1293    }
1294    ExaCheckPaintWindow (pWin, pRegion, what);
1295
1296damage:
1297    exaGetDrawableDeltas((DrawablePtr)pWin, pPixmap, &xoff, &yoff);
1298
1299    pBox = REGION_RECTS(pRegion);
1300
1301    while (nbox--)
1302    {
1303	exaPixmapDirty (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff,
1304			pBox->x2 + xoff, pBox->y2 + yoff);
1305	pBox++;
1306    }
1307}
1308
1309/**
1310 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
1311 *
1312 * This is probably the only case we actually care about.  The rest fall through
1313 * to migration and ExaCheckGetImage, which hopefully will result in migration
1314 * pushing the pixmap out of framebuffer.
1315 */
1316void
1317exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
1318	     unsigned int format, unsigned long planeMask, char *d)
1319{
1320    ExaScreenPriv (pDrawable->pScreen);
1321    ExaMigrationRec pixmaps[1];
1322    PixmapPtr pPix;
1323    int xoff, yoff;
1324    Bool ok;
1325
1326    if (pExaScr->swappedOut || (w == 1 && h == 1))
1327	goto fallback;
1328
1329    if (pExaScr->info->DownloadFromScreen == NULL)
1330	goto migrate_and_fallback;
1331
1332    /* Only cover the ZPixmap, solid copy case. */
1333    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
1334	goto migrate_and_fallback;
1335
1336    /* Only try to handle the 8bpp and up cases, since we don't want to think
1337     * about <8bpp.
1338     */
1339    if (pDrawable->bitsPerPixel < 8)
1340	goto migrate_and_fallback;
1341
1342    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
1343    if (pPix == NULL)
1344	goto fallback;
1345
1346    xoff += pDrawable->x;
1347    yoff += pDrawable->y;
1348
1349    ok = pExaScr->info->DownloadFromScreen(pPix, x + xoff, y + yoff, w, h, d,
1350					   PixmapBytePad(w, pDrawable->depth));
1351    if (ok) {
1352	exaWaitSync(pDrawable->pScreen);
1353	return;
1354    }
1355
1356migrate_and_fallback:
1357    pixmaps[0].as_dst = FALSE;
1358    pixmaps[0].as_src = TRUE;
1359    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
1360    exaDoMigration (pixmaps, 1, FALSE);
1361fallback:
1362    ExaCheckGetImage (pDrawable, x, y, w, h, format, planeMask, d);
1363}
1364
1365/**
1366 * GetSpans isn't accelerated yet, but performs migration so that we'll
1367 * hopefully avoid the read-from-framebuffer cost.
1368 */
1369void
1370exaGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth,
1371	     int nspans, char *pdstStart)
1372{
1373    ExaMigrationRec pixmaps[1];
1374
1375    pixmaps[0].as_dst = FALSE;
1376    pixmaps[0].as_src = TRUE;
1377    pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
1378    exaDoMigration (pixmaps, 1, FALSE);
1379
1380    ExaCheckGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
1381}
1382