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	    case 4:
1061	    case 1:
1062		*(CARD8*)pExaPixmap->sys_ptr = pixel;
1063	    }
1064
1065	    RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys,
1066			 pRegion);
1067	    RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB,
1068			 pRegion);
1069	    RegionSubtract(pending_damage, pending_damage, pRegion);
1070	}
1071
1072	ret = TRUE;
1073    }
1074
1075out:
1076    RegionTranslate(pRegion, -xoff, -yoff);
1077
1078    return ret;
1079}
1080
1081/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
1082 * Based on fbFillRegionTiled(), fbTile().
1083 */
1084Bool
1085exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
1086		    DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
1087		    unsigned int clientClipType)
1088{
1089    ExaScreenPriv(pDrawable->pScreen);
1090    PixmapPtr pPixmap;
1091    ExaPixmapPrivPtr pExaPixmap;
1092    ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
1093    int xoff, yoff;
1094    int tileWidth, tileHeight;
1095    int nbox = RegionNumRects (pRegion);
1096    BoxPtr pBox = RegionRects (pRegion);
1097    Bool ret = FALSE;
1098    int i;
1099
1100    tileWidth = pTile->drawable.width;
1101    tileHeight = pTile->drawable.height;
1102
1103    /* If we're filling with a solid color, grab it out and go to
1104     * FillRegionSolid, saving numerous copies.
1105     */
1106    if (tileWidth == 1 && tileHeight == 1)
1107	return exaFillRegionSolid(pDrawable, pRegion,
1108				  exaGetPixmapFirstPixel (pTile), planemask,
1109				  alu, clientClipType);
1110
1111    pPixmap = exaGetDrawablePixmap (pDrawable);
1112    pExaPixmap = ExaGetPixmapPriv (pPixmap);
1113
1114    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
1115	    pTileExaPixmap->accel_blocked)
1116	return FALSE;
1117
1118    if (pExaScr->do_migration) {
1119	ExaMigrationRec pixmaps[2];
1120
1121	pixmaps[0].as_dst = TRUE;
1122	pixmaps[0].as_src = FALSE;
1123	pixmaps[0].pPix = pPixmap;
1124	pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
1125						alu, clientClipType) ? NULL : pRegion;
1126	pixmaps[1].as_dst = FALSE;
1127	pixmaps[1].as_src = TRUE;
1128	pixmaps[1].pPix = pTile;
1129	pixmaps[1].pReg = NULL;
1130
1131	exaDoMigration (pixmaps, 2, TRUE);
1132    }
1133
1134    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
1135
1136    if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
1137	return FALSE;
1138
1139    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
1140    {
1141	if (xoff || yoff)
1142	    RegionTranslate(pRegion, xoff, yoff);
1143
1144	for (i = 0; i < nbox; i++)
1145	{
1146	    int height = pBox[i].y2 - pBox[i].y1;
1147	    int dstY = pBox[i].y1;
1148	    int tileY;
1149
1150	    if (alu == GXcopy)
1151		height = min(height, tileHeight);
1152
1153	    modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
1154
1155	    while (height > 0) {
1156		int width = pBox[i].x2 - pBox[i].x1;
1157		int dstX = pBox[i].x1;
1158		int tileX;
1159		int h = tileHeight - tileY;
1160
1161		if (alu == GXcopy)
1162		    width = min(width, tileWidth);
1163
1164		if (h > height)
1165		    h = height;
1166		height -= h;
1167
1168		modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
1169			tileX);
1170
1171		while (width > 0) {
1172		    int w = tileWidth - tileX;
1173		    if (w > width)
1174			w = width;
1175		    width -= w;
1176
1177		    (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
1178					    w, h);
1179		    dstX += w;
1180		    tileX = 0;
1181		}
1182		dstY += h;
1183		tileY = 0;
1184	    }
1185	}
1186	(*pExaScr->info->DoneCopy) (pPixmap);
1187
1188	/* With GXcopy, we only need to do the basic algorithm up to the tile
1189	 * size; then, we can just keep doubling the destination in each
1190	 * direction until it fills the box. This way, the number of copy
1191	 * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
1192	 * rx/ry is the ratio between box and tile width/height. This can make
1193	 * a big difference if each driver copy incurs a significant constant
1194	 * overhead.
1195	 */
1196	if (alu != GXcopy)
1197	    ret = TRUE;
1198	else {
1199	    Bool more_copy = FALSE;
1200
1201	    for (i = 0; i < nbox; i++) {
1202		int dstX = pBox[i].x1 + tileWidth;
1203		int dstY = pBox[i].y1 + tileHeight;
1204
1205		if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
1206		    more_copy = TRUE;
1207		    break;
1208		}
1209	    }
1210
1211	    if (more_copy == FALSE)
1212		ret = TRUE;
1213
1214	    if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
1215							    1, 1, alu, planemask)) {
1216		for (i = 0; i < nbox; i++)
1217		{
1218		    int dstX = pBox[i].x1 + tileWidth;
1219		    int dstY = pBox[i].y1 + tileHeight;
1220		    int width = min(pBox[i].x2 - dstX, tileWidth);
1221		    int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
1222
1223		    while (dstX < pBox[i].x2) {
1224			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1225						dstX, pBox[i].y1, width, height);
1226			dstX += width;
1227			width = min(pBox[i].x2 - dstX, width * 2);
1228		    }
1229
1230		    width = pBox[i].x2 - pBox[i].x1;
1231		    height = min(pBox[i].y2 - dstY, tileHeight);
1232
1233		    while (dstY < pBox[i].y2) {
1234			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1235						pBox[i].x1, dstY, width, height);
1236			dstY += height;
1237			height = min(pBox[i].y2 - dstY, height * 2);
1238		    }
1239		}
1240
1241		(*pExaScr->info->DoneCopy) (pPixmap);
1242
1243		ret = TRUE;
1244	    }
1245	}
1246
1247	exaMarkSync(pDrawable->pScreen);
1248
1249	if (xoff || yoff)
1250	    RegionTranslate(pRegion, -xoff, -yoff);
1251    }
1252
1253    return ret;
1254}
1255
1256
1257/**
1258 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
1259 *
1260 * This is probably the only case we actually care about.  The rest fall through
1261 * to migration and fbGetImage, which hopefully will result in migration pushing
1262 * the pixmap out of framebuffer.
1263 */
1264void
1265exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
1266	     unsigned int format, unsigned long planeMask, char *d)
1267{
1268    ExaScreenPriv (pDrawable->pScreen);
1269    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
1270    ExaPixmapPriv(pPix);
1271    int xoff, yoff;
1272    Bool ok;
1273
1274    if (pExaScr->fallback_counter || pExaScr->swappedOut)
1275	goto fallback;
1276
1277    /* If there's a system copy, we want to save the result there */
1278    if (pExaPixmap->pDamage)
1279	goto fallback;
1280
1281    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
1282
1283    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
1284	goto fallback;
1285
1286    /* Only cover the ZPixmap, solid copy case. */
1287    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
1288	goto fallback;
1289
1290    /* Only try to handle the 8bpp and up cases, since we don't want to think
1291     * about <8bpp.
1292     */
1293    if (pDrawable->bitsPerPixel < 8)
1294	goto fallback;
1295
1296    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
1297					   pDrawable->y + y + yoff, w, h, d,
1298					   PixmapBytePad(w, pDrawable->depth));
1299    if (ok) {
1300	exaWaitSync(pDrawable->pScreen);
1301	return;
1302    }
1303
1304fallback:
1305    ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
1306}
1307