exa_accel.c revision 4202a189
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
38static void
39exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
40	     DDXPointPtr ppt, int *pwidth, int fSorted)
41{
42    ScreenPtr	    pScreen = pDrawable->pScreen;
43    ExaScreenPriv (pScreen);
44    RegionPtr	    pClip = fbGetCompositeClip(pGC);
45    PixmapPtr	    pPixmap = exaGetDrawablePixmap (pDrawable);
46    ExaPixmapPriv (pPixmap);
47    BoxPtr	    pextent, pbox;
48    int		    nbox;
49    int		    extentX1, extentX2, extentY1, extentY2;
50    int		    fullX1, fullX2, fullY1;
51    int		    partX1, partX2;
52    int		    off_x, off_y;
53
54    if (pExaScr->fallback_counter ||
55	pExaScr->swappedOut ||
56	pGC->fillStyle != FillSolid ||
57	pExaPixmap->accel_blocked)
58    {
59	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
60	return;
61    }
62
63    if (pExaScr->do_migration) {
64	ExaMigrationRec pixmaps[1];
65
66	pixmaps[0].as_dst = TRUE;
67	pixmaps[0].as_src = FALSE;
68	pixmaps[0].pPix = pPixmap;
69	pixmaps[0].pReg = NULL;
70
71	exaDoMigration (pixmaps, 1, TRUE);
72    }
73
74    if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
75	!(*pExaScr->info->PrepareSolid) (pPixmap,
76					 pGC->alu,
77					 pGC->planemask,
78					 pGC->fgPixel))
79    {
80	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
81	return;
82    }
83
84    pextent = RegionExtents(pClip);
85    extentX1 = pextent->x1;
86    extentY1 = pextent->y1;
87    extentX2 = pextent->x2;
88    extentY2 = pextent->y2;
89    while (n--)
90    {
91	fullX1 = ppt->x;
92	fullY1 = ppt->y;
93	fullX2 = fullX1 + (int) *pwidth;
94	ppt++;
95	pwidth++;
96
97	if (fullY1 < extentY1 || extentY2 <= fullY1)
98	    continue;
99
100	if (fullX1 < extentX1)
101	    fullX1 = extentX1;
102
103	if (fullX2 > extentX2)
104	    fullX2 = extentX2;
105
106	if (fullX1 >= fullX2)
107	    continue;
108
109	nbox = RegionNumRects (pClip);
110	if (nbox == 1)
111	{
112	    (*pExaScr->info->Solid) (pPixmap,
113				     fullX1 + off_x, fullY1 + off_y,
114				     fullX2 + off_x, fullY1 + 1 + off_y);
115	}
116	else
117	{
118	    pbox = RegionRects(pClip);
119	    while(nbox--)
120	    {
121		if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
122		{
123		    partX1 = pbox->x1;
124		    if (partX1 < fullX1)
125			partX1 = fullX1;
126		    partX2 = pbox->x2;
127		    if (partX2 > fullX2)
128			partX2 = fullX2;
129		    if (partX2 > partX1) {
130			(*pExaScr->info->Solid) (pPixmap,
131						 partX1 + off_x, fullY1 + off_y,
132						 partX2 + off_x, fullY1 + 1 + off_y);
133		    }
134		}
135		pbox++;
136	    }
137	}
138    }
139    (*pExaScr->info->DoneSolid) (pPixmap);
140    exaMarkSync(pScreen);
141}
142
143static Bool
144exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
145	       int w, int h, int format, char *bits, int src_stride)
146{
147    ExaScreenPriv (pDrawable->pScreen);
148    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
149    ExaPixmapPriv(pPix);
150    RegionPtr pClip;
151    BoxPtr pbox;
152    int nbox;
153    int xoff, yoff;
154    int bpp = pDrawable->bitsPerPixel;
155    Bool ret = TRUE;
156
157    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen)
158	return FALSE;
159
160    /* If there's a system copy, we want to save the result there */
161    if (pExaPixmap->pDamage)
162	return FALSE;
163
164    /* Don't bother with under 8bpp, XYPixmaps. */
165    if (format != ZPixmap || bpp < 8)
166	return FALSE;
167
168    /* Only accelerate copies: no rop or planemask. */
169    if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
170	return FALSE;
171
172    if (pExaScr->swappedOut)
173	return FALSE;
174
175    if (pExaScr->do_migration) {
176	ExaMigrationRec pixmaps[1];
177
178	pixmaps[0].as_dst = TRUE;
179	pixmaps[0].as_src = FALSE;
180	pixmaps[0].pPix = pPix;
181	pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
182
183	exaDoMigration (pixmaps, 1, TRUE);
184    }
185
186    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
187
188    if (!pPix)
189	return FALSE;
190
191    x += pDrawable->x;
192    y += pDrawable->y;
193
194    pClip = fbGetCompositeClip(pGC);
195    for (nbox = RegionNumRects(pClip),
196	 pbox = RegionRects(pClip);
197	 nbox--;
198	 pbox++)
199    {
200	int x1 = x;
201	int y1 = y;
202	int x2 = x + w;
203	int y2 = y + h;
204	char *src;
205	Bool ok;
206
207	if (x1 < pbox->x1)
208	    x1 = pbox->x1;
209	if (y1 < pbox->y1)
210	    y1 = pbox->y1;
211	if (x2 > pbox->x2)
212	    x2 = pbox->x2;
213	if (y2 > pbox->y2)
214	    y2 = pbox->y2;
215	if (x1 >= x2 || y1 >= y2)
216	    continue;
217
218	src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
219	ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
220					   x2 - x1, y2 - y1, src, src_stride);
221	/* We have to fall back completely, and ignore what has already been completed.
222	 * Messing with the fb layer directly like we used to is completely unacceptable.
223	 */
224	if (!ok) {
225	    ret = FALSE;
226	    break;
227	}
228    }
229
230    if (ret)
231	exaMarkSync(pDrawable->pScreen);
232
233    return ret;
234}
235
236static void
237exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
238	     int w, int h, int leftPad, int format, char *bits)
239{
240    if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
241		       PixmapBytePad(w, pDrawable->depth)))
242	ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
243			 bits);
244}
245
246static Bool inline
247exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
248		   GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
249{
250    ExaScreenPriv (pDstDrawable->pScreen);
251    PixmapPtr pSrcPixmap, pDstPixmap;
252    int src_off_x, src_off_y, dst_off_x, dst_off_y;
253    int dirsetup;
254
255    /* Need to get both pixmaps to call the driver routines */
256    pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
257    pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
258    if (!pSrcPixmap || !pDstPixmap)
259	return FALSE;
260
261    /*
262     * Now the case of a chip that only supports xdir = ydir = 1 or
263     * xdir = ydir = -1, but we have xdir != ydir.
264     */
265    dirsetup = 0;	/* No direction set up yet. */
266    for (; nbox; pbox++, nbox--) {
267	if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
268	    /* Do a xdir = ydir = -1 blit instead. */
269	    if (dirsetup != -1) {
270		if (dirsetup != 0)
271		    pExaScr->info->DoneCopy(pDstPixmap);
272		dirsetup = -1;
273		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
274						   pDstPixmap,
275						   -1, -1,
276						   pGC ? pGC->alu : GXcopy,
277						   pGC ? pGC->planemask :
278							 FB_ALLONES))
279		    return FALSE;
280	    }
281	    (*pExaScr->info->Copy)(pDstPixmap,
282				   src_off_x + pbox->x1 + dx,
283				   src_off_y + pbox->y1 + dy,
284				   dst_off_x + pbox->x1,
285				   dst_off_y + pbox->y1,
286				   pbox->x2 - pbox->x1,
287				   pbox->y2 - pbox->y1);
288	} else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
289	    /* Do a xdir = ydir = 1 blit instead. */
290	    if (dirsetup != 1) {
291		if (dirsetup != 0)
292		    pExaScr->info->DoneCopy(pDstPixmap);
293		dirsetup = 1;
294		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
295						   pDstPixmap,
296						   1, 1,
297						   pGC ? pGC->alu : GXcopy,
298						   pGC ? pGC->planemask :
299							 FB_ALLONES))
300		    return FALSE;
301	    }
302	    (*pExaScr->info->Copy)(pDstPixmap,
303				   src_off_x + pbox->x1 + dx,
304				   src_off_y + pbox->y1 + dy,
305				   dst_off_x + pbox->x1,
306				   dst_off_y + pbox->y1,
307				   pbox->x2 - pbox->x1,
308				   pbox->y2 - pbox->y1);
309	} else if (dx >= 0) {
310	    /*
311	     * xdir = 1, ydir = -1.
312	     * Perform line-by-line xdir = ydir = 1 blits, going up.
313	     */
314	    int i;
315	    if (dirsetup != 1) {
316		if (dirsetup != 0)
317		    pExaScr->info->DoneCopy(pDstPixmap);
318		dirsetup = 1;
319		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
320						   pDstPixmap,
321						   1, 1,
322						   pGC ? pGC->alu : GXcopy,
323						   pGC ? pGC->planemask :
324							 FB_ALLONES))
325		    return FALSE;
326	    }
327	    for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
328		(*pExaScr->info->Copy)(pDstPixmap,
329				       src_off_x + pbox->x1 + dx,
330				       src_off_y + pbox->y1 + dy + i,
331				       dst_off_x + pbox->x1,
332				       dst_off_y + pbox->y1 + i,
333				       pbox->x2 - pbox->x1, 1);
334	} else {
335	    /*
336	     * xdir = -1, ydir = 1.
337	     * Perform line-by-line xdir = ydir = -1 blits, going down.
338	     */
339	    int i;
340	    if (dirsetup != -1) {
341		if (dirsetup != 0)
342		    pExaScr->info->DoneCopy(pDstPixmap);
343		dirsetup = -1;
344		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
345						   pDstPixmap,
346						   -1, -1,
347						   pGC ? pGC->alu : GXcopy,
348						   pGC ? pGC->planemask :
349							 FB_ALLONES))
350		    return FALSE;
351	    }
352	    for (i = 0; i < pbox->y2 - pbox->y1; i++)
353		(*pExaScr->info->Copy)(pDstPixmap,
354				       src_off_x + pbox->x1 + dx,
355				       src_off_y + pbox->y1 + dy + i,
356				       dst_off_x + pbox->x1,
357				       dst_off_y + pbox->y1 + i,
358				       pbox->x2 - pbox->x1, 1);
359	}
360    }
361    if (dirsetup != 0)
362	pExaScr->info->DoneCopy(pDstPixmap);
363    exaMarkSync(pDstDrawable->pScreen);
364    return TRUE;
365}
366
367Bool
368exaHWCopyNtoN (DrawablePtr    pSrcDrawable,
369	     DrawablePtr    pDstDrawable,
370	     GCPtr	    pGC,
371	     BoxPtr	    pbox,
372	     int	    nbox,
373	     int	    dx,
374	     int	    dy,
375	     Bool	    reverse,
376	     Bool	    upsidedown)
377{
378    ExaScreenPriv (pDstDrawable->pScreen);
379    PixmapPtr pSrcPixmap, pDstPixmap;
380    ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
381    int	    src_off_x, src_off_y;
382    int	    dst_off_x, dst_off_y;
383    RegionPtr srcregion = NULL, dstregion = NULL;
384    xRectangle *rects;
385    Bool ret = TRUE;
386
387    /* avoid doing copy operations if no boxes */
388    if (nbox == 0)
389	return TRUE;
390
391    pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
392    pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
393
394    exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
395    exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
396
397    rects = malloc(nbox * sizeof(xRectangle));
398
399    if (rects) {
400	int i;
401	int ordering;
402
403	for (i = 0; i < nbox; i++) {
404	    rects[i].x = pbox[i].x1 + dx + src_off_x;
405	    rects[i].y = pbox[i].y1 + dy + src_off_y;
406	    rects[i].width = pbox[i].x2 - pbox[i].x1;
407	    rects[i].height = pbox[i].y2 - pbox[i].y1;
408	}
409
410	/* This must match the RegionCopy() logic for reversing rect order */
411	if (nbox == 1 || (dx > 0 && dy > 0) ||
412	    (pDstDrawable != pSrcDrawable &&
413	     (pDstDrawable->type != DRAWABLE_WINDOW ||
414	      pSrcDrawable->type != DRAWABLE_WINDOW)))
415	    ordering = CT_YXBANDED;
416	else
417	    ordering = CT_UNSORTED;
418
419	srcregion  = RegionFromRects(nbox, rects, ordering);
420	free(rects);
421
422	if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
423					   pGC->fillStyle, pGC->alu,
424					   pGC->clientClipType)) {
425	    dstregion = RegionCreate(NullBox, 0);
426	    RegionCopy(dstregion, srcregion);
427	    RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
428			     dst_off_y - dy - src_off_y);
429	}
430    }
431
432
433    pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap);
434    pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap);
435
436    /* Check whether the accelerator can use this pixmap.
437     * If the pitch of the pixmaps is out of range, there's nothing
438     * we can do but fall back to software rendering.
439     */
440    if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
441        pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
442	goto fallback;
443
444    /* If the width or the height of either of the pixmaps
445     * is out of range, check whether the boxes are actually out of the
446     * addressable range as well. If they aren't, we can still do
447     * the copying in hardware.
448     */
449    if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
450        int i;
451
452        for (i = 0; i < nbox; i++) {
453            /* src */
454            if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
455                (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
456                goto fallback;
457
458            /* dst */
459            if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
460                (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
461                goto fallback;
462        }
463    }
464
465    if (pExaScr->do_migration) {
466	ExaMigrationRec pixmaps[2];
467
468	pixmaps[0].as_dst = TRUE;
469	pixmaps[0].as_src = FALSE;
470	pixmaps[0].pPix = pDstPixmap;
471	pixmaps[0].pReg = dstregion;
472	pixmaps[1].as_dst = FALSE;
473	pixmaps[1].as_src = TRUE;
474	pixmaps[1].pPix = pSrcPixmap;
475	pixmaps[1].pReg = srcregion;
476
477	exaDoMigration (pixmaps, 2, TRUE);
478    }
479
480    /* Mixed directions must be handled specially if the card is lame */
481    if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
482	reverse != upsidedown) {
483	if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
484			       dx, dy))
485	    goto out;
486	goto fallback;
487    }
488
489    if (exaPixmapHasGpuCopy(pDstPixmap)) {
490	/* Normal blitting. */
491	if (exaPixmapHasGpuCopy(pSrcPixmap)) {
492	    if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
493						upsidedown ? -1 : 1,
494						pGC ? pGC->alu : GXcopy,
495						pGC ? pGC->planemask : FB_ALLONES)) {
496		goto fallback;
497	    }
498
499	    while (nbox--)
500	    {
501		(*pExaScr->info->Copy) (pDstPixmap,
502					pbox->x1 + dx + src_off_x,
503					pbox->y1 + dy + src_off_y,
504					pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
505					pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
506		pbox++;
507	    }
508
509	    (*pExaScr->info->DoneCopy) (pDstPixmap);
510	    exaMarkSync (pDstDrawable->pScreen);
511	/* UTS: mainly for SHM PutImage's secondary path.
512	 *
513	 * Only taking this path for directly accessible pixmaps.
514	 */
515	} else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
516	    int bpp = pSrcDrawable->bitsPerPixel;
517	    int src_stride = exaGetPixmapPitch(pSrcPixmap);
518	    CARD8 *src = NULL;
519
520	    if (!pExaScr->info->UploadToScreen)
521		goto fallback;
522
523	    if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
524		goto fallback;
525
526	    if (pSrcDrawable->bitsPerPixel < 8)
527		goto fallback;
528
529	    if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable,  pGC->planemask)))
530		goto fallback;
531
532	    while (nbox--)
533	    {
534		src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8);
535		if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
536				pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
537				(char *) src, src_stride))
538		    goto fallback;
539
540		pbox++;
541	    }
542	} else
543	    goto fallback;
544    } else
545	goto fallback;
546
547    goto out;
548
549fallback:
550    ret = FALSE;
551
552out:
553    if (dstregion) {
554	RegionUninit(dstregion);
555	RegionDestroy(dstregion);
556    }
557    if (srcregion) {
558	RegionUninit(srcregion);
559	RegionDestroy(srcregion);
560    }
561
562    return ret;
563}
564
565void
566exaCopyNtoN (DrawablePtr    pSrcDrawable,
567	     DrawablePtr    pDstDrawable,
568	     GCPtr	    pGC,
569	     BoxPtr	    pbox,
570	     int	    nbox,
571	     int	    dx,
572	     int	    dy,
573	     Bool	    reverse,
574	     Bool	    upsidedown,
575	     Pixel	    bitplane,
576	     void	    *closure)
577{
578    ExaScreenPriv(pDstDrawable->pScreen);
579
580    if (pExaScr->fallback_counter ||
581	    (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW))
582	return;
583
584    if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown))
585	return;
586
587    /* This is a CopyWindow, it's cleaner to fallback at the original call. */
588    if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) {
589	pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
590	return;
591    }
592
593    /* fallback */
594    ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
595}
596
597RegionPtr
598exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
599	    int srcx, int srcy, int width, int height, int dstx, int dsty)
600{
601    ExaScreenPriv (pDstDrawable->pScreen);
602
603    if (pExaScr->fallback_counter || pExaScr->swappedOut) {
604        return  ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
605                                 srcx, srcy, width, height, dstx, dsty);
606    }
607
608    return  miDoCopy (pSrcDrawable, pDstDrawable, pGC,
609                      srcx, srcy, width, height,
610                      dstx, dsty, exaCopyNtoN, 0, NULL);
611}
612
613static void
614exaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
615	     DDXPointPtr ppt)
616{
617    ExaScreenPriv (pDrawable->pScreen);
618    int i;
619    xRectangle *prect;
620
621    /* If we can't reuse the current GC as is, don't bother accelerating the
622     * points.
623     */
624    if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) {
625	ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
626	return;
627    }
628
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;
636	}
637	prect[i].width = 1;
638	prect[i].height = 1;
639    }
640    pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
641    free(prect);
642}
643
644/**
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.
648 */
649static void
650exaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
651	     DDXPointPtr ppt)
652{
653    ExaScreenPriv (pDrawable->pScreen);
654    xRectangle *prect;
655    int x1, x2, y1, y2;
656    int i;
657
658    if (pExaScr->fallback_counter) {
659	ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
660	return;
661    }
662
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);
667	return;
668    }
669
670    prect = malloc(sizeof(xRectangle) * (npt - 1));
671    x1 = ppt[0].x;
672    y1 = ppt[0].y;
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;
678	} else {
679	    x2 = ppt[i + 1].x;
680	    y2 = ppt[i + 1].y;
681	}
682
683	if (x1 != x2 && y1 != y2) {
684	    free(prect);
685	    ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
686	    return;
687	}
688
689	if (x1 < x2) {
690	    prect[i].x = x1;
691	    prect[i].width = x2 - x1 + 1;
692	} else {
693	    prect[i].x = x2;
694	    prect[i].width = x1 - x2 + 1;
695	}
696	if (y1 < y2) {
697	    prect[i].y = y1;
698	    prect[i].height = y2 - y1 + 1;
699	} else {
700	    prect[i].y = y2;
701	    prect[i].height = y1 - y2 + 1;
702	}
703
704	x1 = x2;
705	y1 = y2;
706    }
707    pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
708    free(prect);
709}
710
711/**
712 * exaPolySegment() checks if it can accelerate the lines as a group of
713 * horizontal or vertical lines (rectangles), and uses existing rectangle fill
714 * acceleration if so.
715 */
716static void
717exaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
718		xSegment *pSeg)
719{
720    ExaScreenPriv (pDrawable->pScreen);
721    xRectangle *prect;
722    int i;
723
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    {
728	ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
729	return;
730    }
731
732    /* If we have any non-horizontal/vertical, fall back. */
733    for (i = 0; i < nseg; i++) {
734	if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
735	    ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
736	    return;
737	}
738    }
739
740    prect = malloc(sizeof(xRectangle) * nseg);
741    for (i = 0; i < nseg; i++) {
742	if (pSeg[i].x1 < pSeg[i].x2) {
743	    prect[i].x = pSeg[i].x1;
744	    prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
745	} else {
746	    prect[i].x = pSeg[i].x2;
747	    prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
748	}
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;
752	} else {
753	    prect[i].y = pSeg[i].y2;
754	    prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
755	}
756
757	/* don't paint last pixel */
758	if (pGC->capStyle == CapNotLast) {
759	    if (prect[i].width == 1)
760		prect[i].height--;
761	    else
762		prect[i].width--;
763	}
764    }
765    pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
766    free(prect);
767}
768
769static Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
770				Pixel pixel, CARD32 planemask, CARD32 alu,
771				unsigned int clientClipType);
772
773static void
774exaPolyFillRect(DrawablePtr pDrawable,
775		GCPtr	    pGC,
776		int	    nrect,
777		xRectangle  *prect)
778{
779    ExaScreenPriv (pDrawable->pScreen);
780    RegionPtr	    pClip = fbGetCompositeClip(pGC);
781    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
782    ExaPixmapPriv (pPixmap);
783    register BoxPtr pbox;
784    BoxPtr	    pextent;
785    int		    extentX1, extentX2, extentY1, extentY2;
786    int		    fullX1, fullX2, fullY1, fullY2;
787    int		    partX1, partX2, partY1, partY2;
788    int		    xoff, yoff;
789    int		    xorg, yorg;
790    int		    n;
791    RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED);
792
793    /* Compute intersection of rects and clip region */
794    RegionTranslate(pReg, pDrawable->x, pDrawable->y);
795    RegionIntersect(pReg, pClip, pReg);
796
797    if (!RegionNumRects(pReg)) {
798	goto out;
799    }
800
801    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
802
803    if (pExaScr->fallback_counter || pExaScr->swappedOut ||
804	    pExaPixmap->accel_blocked)
805    {
806	goto fallback;
807    }
808
809    /* For ROPs where overlaps don't matter, convert rectangles to region and
810     * call exaFillRegion{Solid,Tiled}.
811     */
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))) {
824	    goto out;
825	}
826    }
827
828    if (pGC->fillStyle != FillSolid &&
829	!(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
830    {
831	goto fallback;
832    }
833
834    if (pExaScr->do_migration) {
835	ExaMigrationRec pixmaps[1];
836
837	pixmaps[0].as_dst = TRUE;
838	pixmaps[0].as_src = FALSE;
839	pixmaps[0].pPix = pPixmap;
840	pixmaps[0].pReg = NULL;
841
842	exaDoMigration (pixmaps, 1, TRUE);
843    }
844
845    if (!exaPixmapHasGpuCopy (pPixmap) ||
846	!(*pExaScr->info->PrepareSolid) (pPixmap,
847					 pGC->alu,
848					 pGC->planemask,
849					 pGC->fgPixel))
850    {
851fallback:
852	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
853	goto out;
854    }
855
856    xorg = pDrawable->x;
857    yorg = pDrawable->y;
858
859    pextent = RegionExtents(pClip);
860    extentX1 = pextent->x1;
861    extentY1 = pextent->y1;
862    extentX2 = pextent->x2;
863    extentY2 = pextent->y2;
864    while (nrect--)
865    {
866	fullX1 = prect->x + xorg;
867	fullY1 = prect->y + yorg;
868	fullX2 = fullX1 + (int) prect->width;
869	fullY2 = fullY1 + (int) prect->height;
870	prect++;
871
872	if (fullX1 < extentX1)
873	    fullX1 = extentX1;
874
875	if (fullY1 < extentY1)
876	    fullY1 = extentY1;
877
878	if (fullX2 > extentX2)
879	    fullX2 = extentX2;
880
881	if (fullY2 > extentY2)
882	    fullY2 = extentY2;
883
884	if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
885	    continue;
886	n = RegionNumRects (pClip);
887	if (n == 1)
888	{
889	    (*pExaScr->info->Solid) (pPixmap,
890				     fullX1 + xoff, fullY1 + yoff,
891				     fullX2 + xoff, fullY2 + yoff);
892	}
893	else
894	{
895	    pbox = RegionRects(pClip);
896	    /*
897	     * clip the rectangle to each box in the clip region
898	     * this is logically equivalent to calling Intersect(),
899	     * but rectangles may overlap each other here.
900	     */
901	    while(n--)
902	    {
903		partX1 = pbox->x1;
904		if (partX1 < fullX1)
905		    partX1 = fullX1;
906		partY1 = pbox->y1;
907		if (partY1 < fullY1)
908		    partY1 = fullY1;
909		partX2 = pbox->x2;
910		if (partX2 > fullX2)
911		    partX2 = fullX2;
912		partY2 = pbox->y2;
913		if (partY2 > fullY2)
914		    partY2 = fullY2;
915
916		pbox++;
917
918		if (partX1 < partX2 && partY1 < partY2) {
919		    (*pExaScr->info->Solid) (pPixmap,
920					     partX1 + xoff, partY1 + yoff,
921					     partX2 + xoff, partY2 + yoff);
922		}
923	    }
924	}
925    }
926    (*pExaScr->info->DoneSolid) (pPixmap);
927    exaMarkSync(pDrawable->pScreen);
928
929out:
930    RegionUninit(pReg);
931    RegionDestroy(pReg);
932}
933
934const GCOps exaOps = {
935    exaFillSpans,
936    ExaCheckSetSpans,
937    exaPutImage,
938    exaCopyArea,
939    ExaCheckCopyPlane,
940    exaPolyPoint,
941    exaPolylines,
942    exaPolySegment,
943    miPolyRectangle,
944    ExaCheckPolyArc,
945    miFillPolygon,
946    exaPolyFillRect,
947    miPolyFillArc,
948    miPolyText8,
949    miPolyText16,
950    miImageText8,
951    miImageText16,
952    ExaCheckImageGlyphBlt,
953    ExaCheckPolyGlyphBlt,
954    ExaCheckPushPixels,
955};
956
957void
958exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
959{
960    RegionRec	rgnDst;
961    int		dx, dy;
962    PixmapPtr	pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
963    ExaScreenPriv(pWin->drawable.pScreen);
964
965    dx = ptOldOrg.x - pWin->drawable.x;
966    dy = ptOldOrg.y - pWin->drawable.y;
967    RegionTranslate(prgnSrc, -dx, -dy);
968
969    RegionInit(&rgnDst, NullBox, 0);
970
971    RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
972#ifdef COMPOSITE
973    if (pPixmap->screen_x || pPixmap->screen_y)
974	RegionTranslate(&rgnDst,
975			  -pPixmap->screen_x, -pPixmap->screen_y);
976#endif
977
978    if (pExaScr->fallback_counter) {
979	pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
980	goto fallback;
981    }
982
983    pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW;
984    miCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
985		  NULL,
986		  &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
987    pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW;
988
989fallback:
990    RegionUninit(&rgnDst);
991
992    if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) {
993	pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW;
994	RegionTranslate(prgnSrc, dx, dy);
995	ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc);
996    }
997}
998
999static Bool
1000exaFillRegionSolid (DrawablePtr	pDrawable, RegionPtr pRegion, Pixel pixel,
1001		    CARD32 planemask, CARD32 alu, unsigned int clientClipType)
1002{
1003    ExaScreenPriv(pDrawable->pScreen);
1004    PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
1005    ExaPixmapPriv (pPixmap);
1006    int xoff, yoff;
1007    Bool ret = FALSE;
1008
1009    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
1010    RegionTranslate(pRegion, xoff, yoff);
1011
1012    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
1013	goto out;
1014
1015    if (pExaScr->do_migration) {
1016	ExaMigrationRec pixmaps[1];
1017
1018	pixmaps[0].as_dst = TRUE;
1019	pixmaps[0].as_src = FALSE;
1020	pixmaps[0].pPix = pPixmap;
1021	pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
1022						alu, clientClipType) ? NULL : pRegion;
1023
1024	exaDoMigration (pixmaps, 1, TRUE);
1025    }
1026
1027    if (exaPixmapHasGpuCopy (pPixmap) &&
1028	(*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
1029    {
1030	int nbox;
1031	BoxPtr pBox;
1032
1033	nbox = RegionNumRects (pRegion);
1034	pBox = RegionRects (pRegion);
1035
1036	while (nbox--)
1037	{
1038	    (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
1039				     pBox->y2);
1040	    pBox++;
1041	}
1042	(*pExaScr->info->DoneSolid) (pPixmap);
1043	exaMarkSync(pDrawable->pScreen);
1044
1045	if (pExaPixmap->pDamage &&
1046	    pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
1047	    pDrawable->width == 1 && pDrawable->height == 1 &&
1048	    pDrawable->bitsPerPixel != 24) {
1049	    ExaPixmapPriv(pPixmap);
1050	    RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
1051
1052	    switch (pDrawable->bitsPerPixel) {
1053	    case 32:
1054		*(CARD32*)pExaPixmap->sys_ptr = pixel;
1055		break;
1056	    case 16:
1057		*(CARD16*)pExaPixmap->sys_ptr = pixel;
1058		break;
1059	    case 8:
1060		*(CARD8*)pExaPixmap->sys_ptr = pixel;
1061	    }
1062
1063	    RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys,
1064			 pRegion);
1065	    RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB,
1066			 pRegion);
1067	    RegionSubtract(pending_damage, pending_damage, pRegion);
1068	}
1069
1070	ret = TRUE;
1071    }
1072
1073out:
1074    RegionTranslate(pRegion, -xoff, -yoff);
1075
1076    return ret;
1077}
1078
1079/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
1080 * Based on fbFillRegionTiled(), fbTile().
1081 */
1082Bool
1083exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
1084		    DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
1085		    unsigned int clientClipType)
1086{
1087    ExaScreenPriv(pDrawable->pScreen);
1088    PixmapPtr pPixmap;
1089    ExaPixmapPrivPtr pExaPixmap;
1090    ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
1091    int xoff, yoff;
1092    int tileWidth, tileHeight;
1093    int nbox = RegionNumRects (pRegion);
1094    BoxPtr pBox = RegionRects (pRegion);
1095    Bool ret = FALSE;
1096    int i;
1097
1098    tileWidth = pTile->drawable.width;
1099    tileHeight = pTile->drawable.height;
1100
1101    /* If we're filling with a solid color, grab it out and go to
1102     * FillRegionSolid, saving numerous copies.
1103     */
1104    if (tileWidth == 1 && tileHeight == 1)
1105	return exaFillRegionSolid(pDrawable, pRegion,
1106				  exaGetPixmapFirstPixel (pTile), planemask,
1107				  alu, clientClipType);
1108
1109    pPixmap = exaGetDrawablePixmap (pDrawable);
1110    pExaPixmap = ExaGetPixmapPriv (pPixmap);
1111
1112    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
1113	    pTileExaPixmap->accel_blocked)
1114	return FALSE;
1115
1116    if (pExaScr->do_migration) {
1117	ExaMigrationRec pixmaps[2];
1118
1119	pixmaps[0].as_dst = TRUE;
1120	pixmaps[0].as_src = FALSE;
1121	pixmaps[0].pPix = pPixmap;
1122	pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
1123						alu, clientClipType) ? NULL : pRegion;
1124	pixmaps[1].as_dst = FALSE;
1125	pixmaps[1].as_src = TRUE;
1126	pixmaps[1].pPix = pTile;
1127	pixmaps[1].pReg = NULL;
1128
1129	exaDoMigration (pixmaps, 2, TRUE);
1130    }
1131
1132    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
1133
1134    if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
1135	return FALSE;
1136
1137    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
1138    {
1139	if (xoff || yoff)
1140	    RegionTranslate(pRegion, xoff, yoff);
1141
1142	for (i = 0; i < nbox; i++)
1143	{
1144	    int height = pBox[i].y2 - pBox[i].y1;
1145	    int dstY = pBox[i].y1;
1146	    int tileY;
1147
1148	    if (alu == GXcopy)
1149		height = min(height, tileHeight);
1150
1151	    modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
1152
1153	    while (height > 0) {
1154		int width = pBox[i].x2 - pBox[i].x1;
1155		int dstX = pBox[i].x1;
1156		int tileX;
1157		int h = tileHeight - tileY;
1158
1159		if (alu == GXcopy)
1160		    width = min(width, tileWidth);
1161
1162		if (h > height)
1163		    h = height;
1164		height -= h;
1165
1166		modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
1167			tileX);
1168
1169		while (width > 0) {
1170		    int w = tileWidth - tileX;
1171		    if (w > width)
1172			w = width;
1173		    width -= w;
1174
1175		    (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
1176					    w, h);
1177		    dstX += w;
1178		    tileX = 0;
1179		}
1180		dstY += h;
1181		tileY = 0;
1182	    }
1183	}
1184	(*pExaScr->info->DoneCopy) (pPixmap);
1185
1186	/* With GXcopy, we only need to do the basic algorithm up to the tile
1187	 * size; then, we can just keep doubling the destination in each
1188	 * direction until it fills the box. This way, the number of copy
1189	 * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
1190	 * rx/ry is the ratio between box and tile width/height. This can make
1191	 * a big difference if each driver copy incurs a significant constant
1192	 * overhead.
1193	 */
1194	if (alu != GXcopy)
1195	    ret = TRUE;
1196	else {
1197	    Bool more_copy = FALSE;
1198
1199	    for (i = 0; i < nbox; i++) {
1200		int dstX = pBox[i].x1 + tileWidth;
1201		int dstY = pBox[i].y1 + tileHeight;
1202
1203		if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
1204		    more_copy = TRUE;
1205		    break;
1206		}
1207	    }
1208
1209	    if (more_copy == FALSE)
1210		ret = TRUE;
1211
1212	    if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
1213							    1, 1, alu, planemask)) {
1214		for (i = 0; i < nbox; i++)
1215		{
1216		    int dstX = pBox[i].x1 + tileWidth;
1217		    int dstY = pBox[i].y1 + tileHeight;
1218		    int width = min(pBox[i].x2 - dstX, tileWidth);
1219		    int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
1220
1221		    while (dstX < pBox[i].x2) {
1222			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1223						dstX, pBox[i].y1, width, height);
1224			dstX += width;
1225			width = min(pBox[i].x2 - dstX, width * 2);
1226		    }
1227
1228		    width = pBox[i].x2 - pBox[i].x1;
1229		    height = min(pBox[i].y2 - dstY, tileHeight);
1230
1231		    while (dstY < pBox[i].y2) {
1232			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1233						pBox[i].x1, dstY, width, height);
1234			dstY += height;
1235			height = min(pBox[i].y2 - dstY, height * 2);
1236		    }
1237		}
1238
1239		(*pExaScr->info->DoneCopy) (pPixmap);
1240
1241		ret = TRUE;
1242	    }
1243	}
1244
1245	exaMarkSync(pDrawable->pScreen);
1246
1247	if (xoff || yoff)
1248	    RegionTranslate(pRegion, -xoff, -yoff);
1249    }
1250
1251    return ret;
1252}
1253
1254
1255/**
1256 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
1257 *
1258 * This is probably the only case we actually care about.  The rest fall through
1259 * to migration and fbGetImage, which hopefully will result in migration pushing
1260 * the pixmap out of framebuffer.
1261 */
1262void
1263exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
1264	     unsigned int format, unsigned long planeMask, char *d)
1265{
1266    ExaScreenPriv (pDrawable->pScreen);
1267    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
1268    ExaPixmapPriv(pPix);
1269    int xoff, yoff;
1270    Bool ok;
1271
1272    if (pExaScr->fallback_counter || pExaScr->swappedOut)
1273	goto fallback;
1274
1275    /* If there's a system copy, we want to save the result there */
1276    if (pExaPixmap->pDamage)
1277	goto fallback;
1278
1279    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
1280
1281    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
1282	goto fallback;
1283
1284    /* Only cover the ZPixmap, solid copy case. */
1285    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
1286	goto fallback;
1287
1288    /* Only try to handle the 8bpp and up cases, since we don't want to think
1289     * about <8bpp.
1290     */
1291    if (pDrawable->bitsPerPixel < 8)
1292	goto fallback;
1293
1294    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
1295					   pDrawable->y + y + yoff, w, h, d,
1296					   PixmapBytePad(w, pDrawable->depth));
1297    if (ok) {
1298	exaWaitSync(pDrawable->pScreen);
1299	return;
1300    }
1301
1302fallback:
1303    ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
1304}
1305