1706f2543Smrg/*
2706f2543Smrg * Copyright � 2001 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Partly based on code that is Copyright � The XFree86 Project Inc.
5706f2543Smrg *
6706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
7706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
8706f2543Smrg * the above copyright notice appear in all copies and that both that
9706f2543Smrg * copyright notice and this permission notice appear in supporting
10706f2543Smrg * documentation, and that the name of Keith Packard not be used in
11706f2543Smrg * advertising or publicity pertaining to distribution of the software without
12706f2543Smrg * specific, written prior permission.  Keith Packard makes no
13706f2543Smrg * representations about the suitability of this software for any purpose.  It
14706f2543Smrg * is provided "as is" without express or implied warranty.
15706f2543Smrg *
16706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22706f2543Smrg * PERFORMANCE OF THIS SOFTWARE.
23706f2543Smrg *
24706f2543Smrg * Authors:
25706f2543Smrg *    Eric Anholt <eric@anholt.net>
26706f2543Smrg *    Michel D�nzer <michel@tungstengraphics.com>
27706f2543Smrg *
28706f2543Smrg */
29706f2543Smrg
30706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
31706f2543Smrg#include <dix-config.h>
32706f2543Smrg#endif
33706f2543Smrg#include "exa_priv.h"
34706f2543Smrg#include <X11/fonts/fontstruct.h>
35706f2543Smrg#include "dixfontstr.h"
36706f2543Smrg#include "exa.h"
37706f2543Smrg
38706f2543Smrgstatic void
39706f2543SmrgexaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
40706f2543Smrg	     DDXPointPtr ppt, int *pwidth, int fSorted)
41706f2543Smrg{
42706f2543Smrg    ScreenPtr	    pScreen = pDrawable->pScreen;
43706f2543Smrg    ExaScreenPriv (pScreen);
44706f2543Smrg    RegionPtr	    pClip = fbGetCompositeClip(pGC);
45706f2543Smrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap (pDrawable);
46706f2543Smrg    ExaPixmapPriv (pPixmap);
47706f2543Smrg    BoxPtr	    pextent, pbox;
48706f2543Smrg    int		    nbox;
49706f2543Smrg    int		    extentX1, extentX2, extentY1, extentY2;
50706f2543Smrg    int		    fullX1, fullX2, fullY1;
51706f2543Smrg    int		    partX1, partX2;
52706f2543Smrg    int		    off_x, off_y;
53706f2543Smrg
54706f2543Smrg    if (pExaScr->fallback_counter ||
55706f2543Smrg	pExaScr->swappedOut ||
56706f2543Smrg	pGC->fillStyle != FillSolid ||
57706f2543Smrg	pExaPixmap->accel_blocked)
58706f2543Smrg    {
59706f2543Smrg	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
60706f2543Smrg	return;
61706f2543Smrg    }
62706f2543Smrg
63706f2543Smrg    if (pExaScr->do_migration) {
64706f2543Smrg	ExaMigrationRec pixmaps[1];
65706f2543Smrg
66706f2543Smrg	pixmaps[0].as_dst = TRUE;
67706f2543Smrg	pixmaps[0].as_src = FALSE;
68706f2543Smrg	pixmaps[0].pPix = pPixmap;
69706f2543Smrg	pixmaps[0].pReg = NULL;
70706f2543Smrg
71706f2543Smrg	exaDoMigration (pixmaps, 1, TRUE);
72706f2543Smrg    }
73706f2543Smrg
74706f2543Smrg    if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
75706f2543Smrg	!(*pExaScr->info->PrepareSolid) (pPixmap,
76706f2543Smrg					 pGC->alu,
77706f2543Smrg					 pGC->planemask,
78706f2543Smrg					 pGC->fgPixel))
79706f2543Smrg    {
80706f2543Smrg	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
81706f2543Smrg	return;
82706f2543Smrg    }
83706f2543Smrg
84706f2543Smrg    pextent = RegionExtents(pClip);
85706f2543Smrg    extentX1 = pextent->x1;
86706f2543Smrg    extentY1 = pextent->y1;
87706f2543Smrg    extentX2 = pextent->x2;
88706f2543Smrg    extentY2 = pextent->y2;
89706f2543Smrg    while (n--)
90706f2543Smrg    {
91706f2543Smrg	fullX1 = ppt->x;
92706f2543Smrg	fullY1 = ppt->y;
93706f2543Smrg	fullX2 = fullX1 + (int) *pwidth;
94706f2543Smrg	ppt++;
95706f2543Smrg	pwidth++;
96706f2543Smrg
97706f2543Smrg	if (fullY1 < extentY1 || extentY2 <= fullY1)
98706f2543Smrg	    continue;
99706f2543Smrg
100706f2543Smrg	if (fullX1 < extentX1)
101706f2543Smrg	    fullX1 = extentX1;
102706f2543Smrg
103706f2543Smrg	if (fullX2 > extentX2)
104706f2543Smrg	    fullX2 = extentX2;
105706f2543Smrg
106706f2543Smrg	if (fullX1 >= fullX2)
107706f2543Smrg	    continue;
108706f2543Smrg
109706f2543Smrg	nbox = RegionNumRects (pClip);
110706f2543Smrg	if (nbox == 1)
111706f2543Smrg	{
112706f2543Smrg	    (*pExaScr->info->Solid) (pPixmap,
113706f2543Smrg				     fullX1 + off_x, fullY1 + off_y,
114706f2543Smrg				     fullX2 + off_x, fullY1 + 1 + off_y);
115706f2543Smrg	}
116706f2543Smrg	else
117706f2543Smrg	{
118706f2543Smrg	    pbox = RegionRects(pClip);
119706f2543Smrg	    while(nbox--)
120706f2543Smrg	    {
121706f2543Smrg		if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
122706f2543Smrg		{
123706f2543Smrg		    partX1 = pbox->x1;
124706f2543Smrg		    if (partX1 < fullX1)
125706f2543Smrg			partX1 = fullX1;
126706f2543Smrg		    partX2 = pbox->x2;
127706f2543Smrg		    if (partX2 > fullX2)
128706f2543Smrg			partX2 = fullX2;
129706f2543Smrg		    if (partX2 > partX1) {
130706f2543Smrg			(*pExaScr->info->Solid) (pPixmap,
131706f2543Smrg						 partX1 + off_x, fullY1 + off_y,
132706f2543Smrg						 partX2 + off_x, fullY1 + 1 + off_y);
133706f2543Smrg		    }
134706f2543Smrg		}
135706f2543Smrg		pbox++;
136706f2543Smrg	    }
137706f2543Smrg	}
138706f2543Smrg    }
139706f2543Smrg    (*pExaScr->info->DoneSolid) (pPixmap);
140706f2543Smrg    exaMarkSync(pScreen);
141706f2543Smrg}
142706f2543Smrg
143706f2543Smrgstatic Bool
144706f2543SmrgexaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
145706f2543Smrg	       int w, int h, int format, char *bits, int src_stride)
146706f2543Smrg{
147706f2543Smrg    ExaScreenPriv (pDrawable->pScreen);
148706f2543Smrg    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
149706f2543Smrg    ExaPixmapPriv(pPix);
150706f2543Smrg    RegionPtr pClip;
151706f2543Smrg    BoxPtr pbox;
152706f2543Smrg    int nbox;
153706f2543Smrg    int xoff, yoff;
154706f2543Smrg    int bpp = pDrawable->bitsPerPixel;
155706f2543Smrg    Bool ret = TRUE;
156706f2543Smrg
157706f2543Smrg    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen)
158706f2543Smrg	return FALSE;
159706f2543Smrg
160706f2543Smrg    /* If there's a system copy, we want to save the result there */
161706f2543Smrg    if (pExaPixmap->pDamage)
162706f2543Smrg	return FALSE;
163706f2543Smrg
164706f2543Smrg    /* Don't bother with under 8bpp, XYPixmaps. */
165706f2543Smrg    if (format != ZPixmap || bpp < 8)
166706f2543Smrg	return FALSE;
167706f2543Smrg
168706f2543Smrg    /* Only accelerate copies: no rop or planemask. */
169706f2543Smrg    if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
170706f2543Smrg	return FALSE;
171706f2543Smrg
172706f2543Smrg    if (pExaScr->swappedOut)
173706f2543Smrg	return FALSE;
174706f2543Smrg
175706f2543Smrg    if (pExaScr->do_migration) {
176706f2543Smrg	ExaMigrationRec pixmaps[1];
177706f2543Smrg
178706f2543Smrg	pixmaps[0].as_dst = TRUE;
179706f2543Smrg	pixmaps[0].as_src = FALSE;
180706f2543Smrg	pixmaps[0].pPix = pPix;
181706f2543Smrg	pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
182706f2543Smrg
183706f2543Smrg	exaDoMigration (pixmaps, 1, TRUE);
184706f2543Smrg    }
185706f2543Smrg
186706f2543Smrg    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
187706f2543Smrg
188706f2543Smrg    if (!pPix)
189706f2543Smrg	return FALSE;
190706f2543Smrg
191706f2543Smrg    x += pDrawable->x;
192706f2543Smrg    y += pDrawable->y;
193706f2543Smrg
194706f2543Smrg    pClip = fbGetCompositeClip(pGC);
195706f2543Smrg    for (nbox = RegionNumRects(pClip),
196706f2543Smrg	 pbox = RegionRects(pClip);
197706f2543Smrg	 nbox--;
198706f2543Smrg	 pbox++)
199706f2543Smrg    {
200706f2543Smrg	int x1 = x;
201706f2543Smrg	int y1 = y;
202706f2543Smrg	int x2 = x + w;
203706f2543Smrg	int y2 = y + h;
204706f2543Smrg	char *src;
205706f2543Smrg	Bool ok;
206706f2543Smrg
207706f2543Smrg	if (x1 < pbox->x1)
208706f2543Smrg	    x1 = pbox->x1;
209706f2543Smrg	if (y1 < pbox->y1)
210706f2543Smrg	    y1 = pbox->y1;
211706f2543Smrg	if (x2 > pbox->x2)
212706f2543Smrg	    x2 = pbox->x2;
213706f2543Smrg	if (y2 > pbox->y2)
214706f2543Smrg	    y2 = pbox->y2;
215706f2543Smrg	if (x1 >= x2 || y1 >= y2)
216706f2543Smrg	    continue;
217706f2543Smrg
218706f2543Smrg	src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
219706f2543Smrg	ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
220706f2543Smrg					   x2 - x1, y2 - y1, src, src_stride);
221706f2543Smrg	/* We have to fall back completely, and ignore what has already been completed.
222706f2543Smrg	 * Messing with the fb layer directly like we used to is completely unacceptable.
223706f2543Smrg	 */
224706f2543Smrg	if (!ok) {
225706f2543Smrg	    ret = FALSE;
226706f2543Smrg	    break;
227706f2543Smrg	}
228706f2543Smrg    }
229706f2543Smrg
230706f2543Smrg    if (ret)
231706f2543Smrg	exaMarkSync(pDrawable->pScreen);
232706f2543Smrg
233706f2543Smrg    return ret;
234706f2543Smrg}
235706f2543Smrg
236706f2543Smrgstatic void
237706f2543SmrgexaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
238706f2543Smrg	     int w, int h, int leftPad, int format, char *bits)
239706f2543Smrg{
240706f2543Smrg    if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits,
241706f2543Smrg		       PixmapBytePad(w, pDrawable->depth)))
242706f2543Smrg	ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
243706f2543Smrg			 bits);
244706f2543Smrg}
245706f2543Smrg
246706f2543Smrgstatic Bool inline
247706f2543SmrgexaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
248706f2543Smrg		   GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
249706f2543Smrg{
250706f2543Smrg    ExaScreenPriv (pDstDrawable->pScreen);
251706f2543Smrg    PixmapPtr pSrcPixmap, pDstPixmap;
252706f2543Smrg    int src_off_x, src_off_y, dst_off_x, dst_off_y;
253706f2543Smrg    int dirsetup;
254706f2543Smrg
255706f2543Smrg    /* Need to get both pixmaps to call the driver routines */
256706f2543Smrg    pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
257706f2543Smrg    pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
258706f2543Smrg    if (!pSrcPixmap || !pDstPixmap)
259706f2543Smrg	return FALSE;
260706f2543Smrg
261706f2543Smrg    /*
262706f2543Smrg     * Now the case of a chip that only supports xdir = ydir = 1 or
263706f2543Smrg     * xdir = ydir = -1, but we have xdir != ydir.
264706f2543Smrg     */
265706f2543Smrg    dirsetup = 0;	/* No direction set up yet. */
266706f2543Smrg    for (; nbox; pbox++, nbox--) {
267706f2543Smrg	if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
268706f2543Smrg	    /* Do a xdir = ydir = -1 blit instead. */
269706f2543Smrg	    if (dirsetup != -1) {
270706f2543Smrg		if (dirsetup != 0)
271706f2543Smrg		    pExaScr->info->DoneCopy(pDstPixmap);
272706f2543Smrg		dirsetup = -1;
273706f2543Smrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
274706f2543Smrg						   pDstPixmap,
275706f2543Smrg						   -1, -1,
276706f2543Smrg						   pGC ? pGC->alu : GXcopy,
277706f2543Smrg						   pGC ? pGC->planemask :
278706f2543Smrg							 FB_ALLONES))
279706f2543Smrg		    return FALSE;
280706f2543Smrg	    }
281706f2543Smrg	    (*pExaScr->info->Copy)(pDstPixmap,
282706f2543Smrg				   src_off_x + pbox->x1 + dx,
283706f2543Smrg				   src_off_y + pbox->y1 + dy,
284706f2543Smrg				   dst_off_x + pbox->x1,
285706f2543Smrg				   dst_off_y + pbox->y1,
286706f2543Smrg				   pbox->x2 - pbox->x1,
287706f2543Smrg				   pbox->y2 - pbox->y1);
288706f2543Smrg	} else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
289706f2543Smrg	    /* Do a xdir = ydir = 1 blit instead. */
290706f2543Smrg	    if (dirsetup != 1) {
291706f2543Smrg		if (dirsetup != 0)
292706f2543Smrg		    pExaScr->info->DoneCopy(pDstPixmap);
293706f2543Smrg		dirsetup = 1;
294706f2543Smrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
295706f2543Smrg						   pDstPixmap,
296706f2543Smrg						   1, 1,
297706f2543Smrg						   pGC ? pGC->alu : GXcopy,
298706f2543Smrg						   pGC ? pGC->planemask :
299706f2543Smrg							 FB_ALLONES))
300706f2543Smrg		    return FALSE;
301706f2543Smrg	    }
302706f2543Smrg	    (*pExaScr->info->Copy)(pDstPixmap,
303706f2543Smrg				   src_off_x + pbox->x1 + dx,
304706f2543Smrg				   src_off_y + pbox->y1 + dy,
305706f2543Smrg				   dst_off_x + pbox->x1,
306706f2543Smrg				   dst_off_y + pbox->y1,
307706f2543Smrg				   pbox->x2 - pbox->x1,
308706f2543Smrg				   pbox->y2 - pbox->y1);
309706f2543Smrg	} else if (dx >= 0) {
310706f2543Smrg	    /*
311706f2543Smrg	     * xdir = 1, ydir = -1.
312706f2543Smrg	     * Perform line-by-line xdir = ydir = 1 blits, going up.
313706f2543Smrg	     */
314706f2543Smrg	    int i;
315706f2543Smrg	    if (dirsetup != 1) {
316706f2543Smrg		if (dirsetup != 0)
317706f2543Smrg		    pExaScr->info->DoneCopy(pDstPixmap);
318706f2543Smrg		dirsetup = 1;
319706f2543Smrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
320706f2543Smrg						   pDstPixmap,
321706f2543Smrg						   1, 1,
322706f2543Smrg						   pGC ? pGC->alu : GXcopy,
323706f2543Smrg						   pGC ? pGC->planemask :
324706f2543Smrg							 FB_ALLONES))
325706f2543Smrg		    return FALSE;
326706f2543Smrg	    }
327706f2543Smrg	    for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
328706f2543Smrg		(*pExaScr->info->Copy)(pDstPixmap,
329706f2543Smrg				       src_off_x + pbox->x1 + dx,
330706f2543Smrg				       src_off_y + pbox->y1 + dy + i,
331706f2543Smrg				       dst_off_x + pbox->x1,
332706f2543Smrg				       dst_off_y + pbox->y1 + i,
333706f2543Smrg				       pbox->x2 - pbox->x1, 1);
334706f2543Smrg	} else {
335706f2543Smrg	    /*
336706f2543Smrg	     * xdir = -1, ydir = 1.
337706f2543Smrg	     * Perform line-by-line xdir = ydir = -1 blits, going down.
338706f2543Smrg	     */
339706f2543Smrg	    int i;
340706f2543Smrg	    if (dirsetup != -1) {
341706f2543Smrg		if (dirsetup != 0)
342706f2543Smrg		    pExaScr->info->DoneCopy(pDstPixmap);
343706f2543Smrg		dirsetup = -1;
344706f2543Smrg		if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap,
345706f2543Smrg						   pDstPixmap,
346706f2543Smrg						   -1, -1,
347706f2543Smrg						   pGC ? pGC->alu : GXcopy,
348706f2543Smrg						   pGC ? pGC->planemask :
349706f2543Smrg							 FB_ALLONES))
350706f2543Smrg		    return FALSE;
351706f2543Smrg	    }
352706f2543Smrg	    for (i = 0; i < pbox->y2 - pbox->y1; i++)
353706f2543Smrg		(*pExaScr->info->Copy)(pDstPixmap,
354706f2543Smrg				       src_off_x + pbox->x1 + dx,
355706f2543Smrg				       src_off_y + pbox->y1 + dy + i,
356706f2543Smrg				       dst_off_x + pbox->x1,
357706f2543Smrg				       dst_off_y + pbox->y1 + i,
358706f2543Smrg				       pbox->x2 - pbox->x1, 1);
359706f2543Smrg	}
360706f2543Smrg    }
361706f2543Smrg    if (dirsetup != 0)
362706f2543Smrg	pExaScr->info->DoneCopy(pDstPixmap);
363706f2543Smrg    exaMarkSync(pDstDrawable->pScreen);
364706f2543Smrg    return TRUE;
365706f2543Smrg}
366706f2543Smrg
367706f2543SmrgBool
368706f2543SmrgexaHWCopyNtoN (DrawablePtr    pSrcDrawable,
369706f2543Smrg	     DrawablePtr    pDstDrawable,
370706f2543Smrg	     GCPtr	    pGC,
371706f2543Smrg	     BoxPtr	    pbox,
372706f2543Smrg	     int	    nbox,
373706f2543Smrg	     int	    dx,
374706f2543Smrg	     int	    dy,
375706f2543Smrg	     Bool	    reverse,
376706f2543Smrg	     Bool	    upsidedown)
377706f2543Smrg{
378706f2543Smrg    ExaScreenPriv (pDstDrawable->pScreen);
379706f2543Smrg    PixmapPtr pSrcPixmap, pDstPixmap;
380706f2543Smrg    ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
381706f2543Smrg    int	    src_off_x, src_off_y;
382706f2543Smrg    int	    dst_off_x, dst_off_y;
383706f2543Smrg    RegionPtr srcregion = NULL, dstregion = NULL;
384706f2543Smrg    xRectangle *rects;
385706f2543Smrg    Bool ret = TRUE;
386706f2543Smrg
387706f2543Smrg    /* avoid doing copy operations if no boxes */
388706f2543Smrg    if (nbox == 0)
389706f2543Smrg	return TRUE;
390706f2543Smrg
391706f2543Smrg    pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
392706f2543Smrg    pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
393706f2543Smrg
394706f2543Smrg    exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
395706f2543Smrg    exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
396706f2543Smrg
397706f2543Smrg    rects = malloc(nbox * sizeof(xRectangle));
398706f2543Smrg
399706f2543Smrg    if (rects) {
400706f2543Smrg	int i;
401706f2543Smrg	int ordering;
402706f2543Smrg
403706f2543Smrg	for (i = 0; i < nbox; i++) {
404706f2543Smrg	    rects[i].x = pbox[i].x1 + dx + src_off_x;
405706f2543Smrg	    rects[i].y = pbox[i].y1 + dy + src_off_y;
406706f2543Smrg	    rects[i].width = pbox[i].x2 - pbox[i].x1;
407706f2543Smrg	    rects[i].height = pbox[i].y2 - pbox[i].y1;
408706f2543Smrg	}
409706f2543Smrg
410706f2543Smrg	/* This must match the RegionCopy() logic for reversing rect order */
411706f2543Smrg	if (nbox == 1 || (dx > 0 && dy > 0) ||
412706f2543Smrg	    (pDstDrawable != pSrcDrawable &&
413706f2543Smrg	     (pDstDrawable->type != DRAWABLE_WINDOW ||
414706f2543Smrg	      pSrcDrawable->type != DRAWABLE_WINDOW)))
415706f2543Smrg	    ordering = CT_YXBANDED;
416706f2543Smrg	else
417706f2543Smrg	    ordering = CT_UNSORTED;
418706f2543Smrg
419706f2543Smrg	srcregion  = RegionFromRects(nbox, rects, ordering);
420706f2543Smrg	free(rects);
421706f2543Smrg
422706f2543Smrg	if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
423706f2543Smrg					   pGC->fillStyle, pGC->alu,
424706f2543Smrg					   pGC->clientClipType)) {
425706f2543Smrg	    dstregion = RegionCreate(NullBox, 0);
426706f2543Smrg	    RegionCopy(dstregion, srcregion);
427706f2543Smrg	    RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
428706f2543Smrg			     dst_off_y - dy - src_off_y);
429706f2543Smrg	}
430706f2543Smrg    }
431706f2543Smrg
432706f2543Smrg
433706f2543Smrg    pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap);
434706f2543Smrg    pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap);
435706f2543Smrg
436706f2543Smrg    /* Check whether the accelerator can use this pixmap.
437706f2543Smrg     * If the pitch of the pixmaps is out of range, there's nothing
438706f2543Smrg     * we can do but fall back to software rendering.
439706f2543Smrg     */
440706f2543Smrg    if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
441706f2543Smrg        pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
442706f2543Smrg	goto fallback;
443706f2543Smrg
444706f2543Smrg    /* If the width or the height of either of the pixmaps
445706f2543Smrg     * is out of range, check whether the boxes are actually out of the
446706f2543Smrg     * addressable range as well. If they aren't, we can still do
447706f2543Smrg     * the copying in hardware.
448706f2543Smrg     */
449706f2543Smrg    if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
450706f2543Smrg        int i;
451706f2543Smrg
452706f2543Smrg        for (i = 0; i < nbox; i++) {
453706f2543Smrg            /* src */
454706f2543Smrg            if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
455706f2543Smrg                (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
456706f2543Smrg                goto fallback;
457706f2543Smrg
458706f2543Smrg            /* dst */
459706f2543Smrg            if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
460706f2543Smrg                (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
461706f2543Smrg                goto fallback;
462706f2543Smrg        }
463706f2543Smrg    }
464706f2543Smrg
465706f2543Smrg    if (pExaScr->do_migration) {
466706f2543Smrg	ExaMigrationRec pixmaps[2];
467706f2543Smrg
468706f2543Smrg	pixmaps[0].as_dst = TRUE;
469706f2543Smrg	pixmaps[0].as_src = FALSE;
470706f2543Smrg	pixmaps[0].pPix = pDstPixmap;
471706f2543Smrg	pixmaps[0].pReg = dstregion;
472706f2543Smrg	pixmaps[1].as_dst = FALSE;
473706f2543Smrg	pixmaps[1].as_src = TRUE;
474706f2543Smrg	pixmaps[1].pPix = pSrcPixmap;
475706f2543Smrg	pixmaps[1].pReg = srcregion;
476706f2543Smrg
477706f2543Smrg	exaDoMigration (pixmaps, 2, TRUE);
478706f2543Smrg    }
479706f2543Smrg
480706f2543Smrg    /* Mixed directions must be handled specially if the card is lame */
481706f2543Smrg    if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
482706f2543Smrg	reverse != upsidedown) {
483706f2543Smrg	if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
484706f2543Smrg			       dx, dy))
485706f2543Smrg	    goto out;
486706f2543Smrg	goto fallback;
487706f2543Smrg    }
488706f2543Smrg
489706f2543Smrg    if (exaPixmapHasGpuCopy(pDstPixmap)) {
490706f2543Smrg	/* Normal blitting. */
491706f2543Smrg	if (exaPixmapHasGpuCopy(pSrcPixmap)) {
492706f2543Smrg	    if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
493706f2543Smrg						upsidedown ? -1 : 1,
494706f2543Smrg						pGC ? pGC->alu : GXcopy,
495706f2543Smrg						pGC ? pGC->planemask : FB_ALLONES)) {
496706f2543Smrg		goto fallback;
497706f2543Smrg	    }
498706f2543Smrg
499706f2543Smrg	    while (nbox--)
500706f2543Smrg	    {
501706f2543Smrg		(*pExaScr->info->Copy) (pDstPixmap,
502706f2543Smrg					pbox->x1 + dx + src_off_x,
503706f2543Smrg					pbox->y1 + dy + src_off_y,
504706f2543Smrg					pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
505706f2543Smrg					pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
506706f2543Smrg		pbox++;
507706f2543Smrg	    }
508706f2543Smrg
509706f2543Smrg	    (*pExaScr->info->DoneCopy) (pDstPixmap);
510706f2543Smrg	    exaMarkSync (pDstDrawable->pScreen);
511706f2543Smrg	/* UTS: mainly for SHM PutImage's secondary path.
512706f2543Smrg	 *
513706f2543Smrg	 * Only taking this path for directly accessible pixmaps.
514706f2543Smrg	 */
515706f2543Smrg	} else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
516706f2543Smrg	    int bpp = pSrcDrawable->bitsPerPixel;
517706f2543Smrg	    int src_stride = exaGetPixmapPitch(pSrcPixmap);
518706f2543Smrg	    CARD8 *src = NULL;
519706f2543Smrg
520706f2543Smrg	    if (!pExaScr->info->UploadToScreen)
521706f2543Smrg		goto fallback;
522706f2543Smrg
523706f2543Smrg	    if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
524706f2543Smrg		goto fallback;
525706f2543Smrg
526706f2543Smrg	    if (pSrcDrawable->bitsPerPixel < 8)
527706f2543Smrg		goto fallback;
528706f2543Smrg
529706f2543Smrg	    if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable,  pGC->planemask)))
530706f2543Smrg		goto fallback;
531706f2543Smrg
532706f2543Smrg	    while (nbox--)
533706f2543Smrg	    {
534706f2543Smrg		src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8);
535706f2543Smrg		if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
536706f2543Smrg				pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
537706f2543Smrg				(char *) src, src_stride))
538706f2543Smrg		    goto fallback;
539706f2543Smrg
540706f2543Smrg		pbox++;
541706f2543Smrg	    }
542706f2543Smrg	} else
543706f2543Smrg	    goto fallback;
544706f2543Smrg    } else
545706f2543Smrg	goto fallback;
546706f2543Smrg
547706f2543Smrg    goto out;
548706f2543Smrg
549706f2543Smrgfallback:
550706f2543Smrg    ret = FALSE;
551706f2543Smrg
552706f2543Smrgout:
553706f2543Smrg    if (dstregion) {
554706f2543Smrg	RegionUninit(dstregion);
555706f2543Smrg	RegionDestroy(dstregion);
556706f2543Smrg    }
557706f2543Smrg    if (srcregion) {
558706f2543Smrg	RegionUninit(srcregion);
559706f2543Smrg	RegionDestroy(srcregion);
560706f2543Smrg    }
561706f2543Smrg
562706f2543Smrg    return ret;
563706f2543Smrg}
564706f2543Smrg
565706f2543Smrgvoid
566706f2543SmrgexaCopyNtoN (DrawablePtr    pSrcDrawable,
567706f2543Smrg	     DrawablePtr    pDstDrawable,
568706f2543Smrg	     GCPtr	    pGC,
569706f2543Smrg	     BoxPtr	    pbox,
570706f2543Smrg	     int	    nbox,
571706f2543Smrg	     int	    dx,
572706f2543Smrg	     int	    dy,
573706f2543Smrg	     Bool	    reverse,
574706f2543Smrg	     Bool	    upsidedown,
575706f2543Smrg	     Pixel	    bitplane,
576706f2543Smrg	     void	    *closure)
577706f2543Smrg{
578706f2543Smrg    ExaScreenPriv(pDstDrawable->pScreen);
579706f2543Smrg
580706f2543Smrg    if (pExaScr->fallback_counter ||
581706f2543Smrg	    (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW))
582706f2543Smrg	return;
583706f2543Smrg
584706f2543Smrg    if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown))
585706f2543Smrg	return;
586706f2543Smrg
587706f2543Smrg    /* This is a CopyWindow, it's cleaner to fallback at the original call. */
588706f2543Smrg    if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) {
589706f2543Smrg	pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
590706f2543Smrg	return;
591706f2543Smrg    }
592706f2543Smrg
593706f2543Smrg    /* fallback */
594706f2543Smrg    ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
595706f2543Smrg}
596706f2543Smrg
597706f2543SmrgRegionPtr
598706f2543SmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
599706f2543Smrg	    int srcx, int srcy, int width, int height, int dstx, int dsty)
600706f2543Smrg{
601706f2543Smrg    ExaScreenPriv (pDstDrawable->pScreen);
602706f2543Smrg
603706f2543Smrg    if (pExaScr->fallback_counter || pExaScr->swappedOut) {
604706f2543Smrg        return  ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC,
605706f2543Smrg                                 srcx, srcy, width, height, dstx, dsty);
606706f2543Smrg    }
607706f2543Smrg
608706f2543Smrg    return  miDoCopy (pSrcDrawable, pDstDrawable, pGC,
609706f2543Smrg                      srcx, srcy, width, height,
610706f2543Smrg                      dstx, dsty, exaCopyNtoN, 0, NULL);
611706f2543Smrg}
612706f2543Smrg
613706f2543Smrgstatic void
614706f2543SmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
615706f2543Smrg	     DDXPointPtr ppt)
616706f2543Smrg{
617706f2543Smrg    ExaScreenPriv (pDrawable->pScreen);
618706f2543Smrg    int i;
619706f2543Smrg    xRectangle *prect;
620706f2543Smrg
621706f2543Smrg    /* If we can't reuse the current GC as is, don't bother accelerating the
622706f2543Smrg     * points.
623706f2543Smrg     */
624706f2543Smrg    if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) {
625706f2543Smrg	ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt);
626706f2543Smrg	return;
627706f2543Smrg    }
628706f2543Smrg
629706f2543Smrg    prect = malloc(sizeof(xRectangle) * npt);
630706f2543Smrg    for (i = 0; i < npt; i++) {
631706f2543Smrg	prect[i].x = ppt[i].x;
632706f2543Smrg	prect[i].y = ppt[i].y;
633706f2543Smrg	if (i > 0 && mode == CoordModePrevious) {
634706f2543Smrg	    prect[i].x += prect[i - 1].x;
635706f2543Smrg	    prect[i].y += prect[i - 1].y;
636706f2543Smrg	}
637706f2543Smrg	prect[i].width = 1;
638706f2543Smrg	prect[i].height = 1;
639706f2543Smrg    }
640706f2543Smrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
641706f2543Smrg    free(prect);
642706f2543Smrg}
643706f2543Smrg
644706f2543Smrg/**
645706f2543Smrg * exaPolylines() checks if it can accelerate the lines as a group of
646706f2543Smrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
647706f2543Smrg * acceleration if so.
648706f2543Smrg */
649706f2543Smrgstatic void
650706f2543SmrgexaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
651706f2543Smrg	     DDXPointPtr ppt)
652706f2543Smrg{
653706f2543Smrg    ExaScreenPriv (pDrawable->pScreen);
654706f2543Smrg    xRectangle *prect;
655706f2543Smrg    int x1, x2, y1, y2;
656706f2543Smrg    int i;
657706f2543Smrg
658706f2543Smrg    if (pExaScr->fallback_counter) {
659706f2543Smrg	ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
660706f2543Smrg	return;
661706f2543Smrg    }
662706f2543Smrg
663706f2543Smrg    /* Don't try to do wide lines or non-solid fill style. */
664706f2543Smrg    if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
665706f2543Smrg	pGC->fillStyle != FillSolid) {
666706f2543Smrg	ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
667706f2543Smrg	return;
668706f2543Smrg    }
669706f2543Smrg
670706f2543Smrg    prect = malloc(sizeof(xRectangle) * (npt - 1));
671706f2543Smrg    x1 = ppt[0].x;
672706f2543Smrg    y1 = ppt[0].y;
673706f2543Smrg    /* If we have any non-horizontal/vertical, fall back. */
674706f2543Smrg    for (i = 0; i < npt - 1; i++) {
675706f2543Smrg	if (mode == CoordModePrevious) {
676706f2543Smrg	    x2 = x1 + ppt[i + 1].x;
677706f2543Smrg	    y2 = y1 + ppt[i + 1].y;
678706f2543Smrg	} else {
679706f2543Smrg	    x2 = ppt[i + 1].x;
680706f2543Smrg	    y2 = ppt[i + 1].y;
681706f2543Smrg	}
682706f2543Smrg
683706f2543Smrg	if (x1 != x2 && y1 != y2) {
684706f2543Smrg	    free(prect);
685706f2543Smrg	    ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt);
686706f2543Smrg	    return;
687706f2543Smrg	}
688706f2543Smrg
689706f2543Smrg	if (x1 < x2) {
690706f2543Smrg	    prect[i].x = x1;
691706f2543Smrg	    prect[i].width = x2 - x1 + 1;
692706f2543Smrg	} else {
693706f2543Smrg	    prect[i].x = x2;
694706f2543Smrg	    prect[i].width = x1 - x2 + 1;
695706f2543Smrg	}
696706f2543Smrg	if (y1 < y2) {
697706f2543Smrg	    prect[i].y = y1;
698706f2543Smrg	    prect[i].height = y2 - y1 + 1;
699706f2543Smrg	} else {
700706f2543Smrg	    prect[i].y = y2;
701706f2543Smrg	    prect[i].height = y1 - y2 + 1;
702706f2543Smrg	}
703706f2543Smrg
704706f2543Smrg	x1 = x2;
705706f2543Smrg	y1 = y2;
706706f2543Smrg    }
707706f2543Smrg    pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
708706f2543Smrg    free(prect);
709706f2543Smrg}
710706f2543Smrg
711706f2543Smrg/**
712706f2543Smrg * exaPolySegment() checks if it can accelerate the lines as a group of
713706f2543Smrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill
714706f2543Smrg * acceleration if so.
715706f2543Smrg */
716706f2543Smrgstatic void
717706f2543SmrgexaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
718706f2543Smrg		xSegment *pSeg)
719706f2543Smrg{
720706f2543Smrg    ExaScreenPriv (pDrawable->pScreen);
721706f2543Smrg    xRectangle *prect;
722706f2543Smrg    int i;
723706f2543Smrg
724706f2543Smrg    /* Don't try to do wide lines or non-solid fill style. */
725706f2543Smrg    if (pExaScr->fallback_counter || pGC->lineWidth != 0 ||
726706f2543Smrg	pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid)
727706f2543Smrg    {
728706f2543Smrg	ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
729706f2543Smrg	return;
730706f2543Smrg    }
731706f2543Smrg
732706f2543Smrg    /* If we have any non-horizontal/vertical, fall back. */
733706f2543Smrg    for (i = 0; i < nseg; i++) {
734706f2543Smrg	if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
735706f2543Smrg	    ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg);
736706f2543Smrg	    return;
737706f2543Smrg	}
738706f2543Smrg    }
739706f2543Smrg
740706f2543Smrg    prect = malloc(sizeof(xRectangle) * nseg);
741706f2543Smrg    for (i = 0; i < nseg; i++) {
742706f2543Smrg	if (pSeg[i].x1 < pSeg[i].x2) {
743706f2543Smrg	    prect[i].x = pSeg[i].x1;
744706f2543Smrg	    prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
745706f2543Smrg	} else {
746706f2543Smrg	    prect[i].x = pSeg[i].x2;
747706f2543Smrg	    prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
748706f2543Smrg	}
749706f2543Smrg	if (pSeg[i].y1 < pSeg[i].y2) {
750706f2543Smrg	    prect[i].y = pSeg[i].y1;
751706f2543Smrg	    prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
752706f2543Smrg	} else {
753706f2543Smrg	    prect[i].y = pSeg[i].y2;
754706f2543Smrg	    prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
755706f2543Smrg	}
756706f2543Smrg
757706f2543Smrg	/* don't paint last pixel */
758706f2543Smrg	if (pGC->capStyle == CapNotLast) {
759706f2543Smrg	    if (prect[i].width == 1)
760706f2543Smrg		prect[i].height--;
761706f2543Smrg	    else
762706f2543Smrg		prect[i].width--;
763706f2543Smrg	}
764706f2543Smrg    }
765706f2543Smrg    pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
766706f2543Smrg    free(prect);
767706f2543Smrg}
768706f2543Smrg
769706f2543Smrgstatic Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion,
770706f2543Smrg				Pixel pixel, CARD32 planemask, CARD32 alu,
771706f2543Smrg				unsigned int clientClipType);
772706f2543Smrg
773706f2543Smrgstatic void
774706f2543SmrgexaPolyFillRect(DrawablePtr pDrawable,
775706f2543Smrg		GCPtr	    pGC,
776706f2543Smrg		int	    nrect,
777706f2543Smrg		xRectangle  *prect)
778706f2543Smrg{
779706f2543Smrg    ExaScreenPriv (pDrawable->pScreen);
780706f2543Smrg    RegionPtr	    pClip = fbGetCompositeClip(pGC);
781706f2543Smrg    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
782706f2543Smrg    ExaPixmapPriv (pPixmap);
783706f2543Smrg    register BoxPtr pbox;
784706f2543Smrg    BoxPtr	    pextent;
785706f2543Smrg    int		    extentX1, extentX2, extentY1, extentY2;
786706f2543Smrg    int		    fullX1, fullX2, fullY1, fullY2;
787706f2543Smrg    int		    partX1, partX2, partY1, partY2;
788706f2543Smrg    int		    xoff, yoff;
789706f2543Smrg    int		    xorg, yorg;
790706f2543Smrg    int		    n;
791706f2543Smrg    RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED);
792706f2543Smrg
793706f2543Smrg    /* Compute intersection of rects and clip region */
794706f2543Smrg    RegionTranslate(pReg, pDrawable->x, pDrawable->y);
795706f2543Smrg    RegionIntersect(pReg, pClip, pReg);
796706f2543Smrg
797706f2543Smrg    if (!RegionNumRects(pReg)) {
798706f2543Smrg	goto out;
799706f2543Smrg    }
800706f2543Smrg
801706f2543Smrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
802706f2543Smrg
803706f2543Smrg    if (pExaScr->fallback_counter || pExaScr->swappedOut ||
804706f2543Smrg	    pExaPixmap->accel_blocked)
805706f2543Smrg    {
806706f2543Smrg	goto fallback;
807706f2543Smrg    }
808706f2543Smrg
809706f2543Smrg    /* For ROPs where overlaps don't matter, convert rectangles to region and
810706f2543Smrg     * call exaFillRegion{Solid,Tiled}.
811706f2543Smrg     */
812706f2543Smrg    if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
813706f2543Smrg	(nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
814706f2543Smrg	 pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
815706f2543Smrg	 pGC->alu == GXset)) {
816706f2543Smrg	if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
817706f2543Smrg	     exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
818706f2543Smrg				pGC->fgPixel : pGC->tile.pixel,	pGC->planemask,
819706f2543Smrg				pGC->alu, pGC->clientClipType)) ||
820706f2543Smrg	    (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
821706f2543Smrg	     exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
822706f2543Smrg				pGC->planemask, pGC->alu,
823706f2543Smrg				pGC->clientClipType))) {
824706f2543Smrg	    goto out;
825706f2543Smrg	}
826706f2543Smrg    }
827706f2543Smrg
828706f2543Smrg    if (pGC->fillStyle != FillSolid &&
829706f2543Smrg	!(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
830706f2543Smrg    {
831706f2543Smrg	goto fallback;
832706f2543Smrg    }
833706f2543Smrg
834706f2543Smrg    if (pExaScr->do_migration) {
835706f2543Smrg	ExaMigrationRec pixmaps[1];
836706f2543Smrg
837706f2543Smrg	pixmaps[0].as_dst = TRUE;
838706f2543Smrg	pixmaps[0].as_src = FALSE;
839706f2543Smrg	pixmaps[0].pPix = pPixmap;
840706f2543Smrg	pixmaps[0].pReg = NULL;
841706f2543Smrg
842706f2543Smrg	exaDoMigration (pixmaps, 1, TRUE);
843706f2543Smrg    }
844706f2543Smrg
845706f2543Smrg    if (!exaPixmapHasGpuCopy (pPixmap) ||
846706f2543Smrg	!(*pExaScr->info->PrepareSolid) (pPixmap,
847706f2543Smrg					 pGC->alu,
848706f2543Smrg					 pGC->planemask,
849706f2543Smrg					 pGC->fgPixel))
850706f2543Smrg    {
851706f2543Smrgfallback:
852706f2543Smrg	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
853706f2543Smrg	goto out;
854706f2543Smrg    }
855706f2543Smrg
856706f2543Smrg    xorg = pDrawable->x;
857706f2543Smrg    yorg = pDrawable->y;
858706f2543Smrg
859706f2543Smrg    pextent = RegionExtents(pClip);
860706f2543Smrg    extentX1 = pextent->x1;
861706f2543Smrg    extentY1 = pextent->y1;
862706f2543Smrg    extentX2 = pextent->x2;
863706f2543Smrg    extentY2 = pextent->y2;
864706f2543Smrg    while (nrect--)
865706f2543Smrg    {
866706f2543Smrg	fullX1 = prect->x + xorg;
867706f2543Smrg	fullY1 = prect->y + yorg;
868706f2543Smrg	fullX2 = fullX1 + (int) prect->width;
869706f2543Smrg	fullY2 = fullY1 + (int) prect->height;
870706f2543Smrg	prect++;
871706f2543Smrg
872706f2543Smrg	if (fullX1 < extentX1)
873706f2543Smrg	    fullX1 = extentX1;
874706f2543Smrg
875706f2543Smrg	if (fullY1 < extentY1)
876706f2543Smrg	    fullY1 = extentY1;
877706f2543Smrg
878706f2543Smrg	if (fullX2 > extentX2)
879706f2543Smrg	    fullX2 = extentX2;
880706f2543Smrg
881706f2543Smrg	if (fullY2 > extentY2)
882706f2543Smrg	    fullY2 = extentY2;
883706f2543Smrg
884706f2543Smrg	if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
885706f2543Smrg	    continue;
886706f2543Smrg	n = RegionNumRects (pClip);
887706f2543Smrg	if (n == 1)
888706f2543Smrg	{
889706f2543Smrg	    (*pExaScr->info->Solid) (pPixmap,
890706f2543Smrg				     fullX1 + xoff, fullY1 + yoff,
891706f2543Smrg				     fullX2 + xoff, fullY2 + yoff);
892706f2543Smrg	}
893706f2543Smrg	else
894706f2543Smrg	{
895706f2543Smrg	    pbox = RegionRects(pClip);
896706f2543Smrg	    /*
897706f2543Smrg	     * clip the rectangle to each box in the clip region
898706f2543Smrg	     * this is logically equivalent to calling Intersect(),
899706f2543Smrg	     * but rectangles may overlap each other here.
900706f2543Smrg	     */
901706f2543Smrg	    while(n--)
902706f2543Smrg	    {
903706f2543Smrg		partX1 = pbox->x1;
904706f2543Smrg		if (partX1 < fullX1)
905706f2543Smrg		    partX1 = fullX1;
906706f2543Smrg		partY1 = pbox->y1;
907706f2543Smrg		if (partY1 < fullY1)
908706f2543Smrg		    partY1 = fullY1;
909706f2543Smrg		partX2 = pbox->x2;
910706f2543Smrg		if (partX2 > fullX2)
911706f2543Smrg		    partX2 = fullX2;
912706f2543Smrg		partY2 = pbox->y2;
913706f2543Smrg		if (partY2 > fullY2)
914706f2543Smrg		    partY2 = fullY2;
915706f2543Smrg
916706f2543Smrg		pbox++;
917706f2543Smrg
918706f2543Smrg		if (partX1 < partX2 && partY1 < partY2) {
919706f2543Smrg		    (*pExaScr->info->Solid) (pPixmap,
920706f2543Smrg					     partX1 + xoff, partY1 + yoff,
921706f2543Smrg					     partX2 + xoff, partY2 + yoff);
922706f2543Smrg		}
923706f2543Smrg	    }
924706f2543Smrg	}
925706f2543Smrg    }
926706f2543Smrg    (*pExaScr->info->DoneSolid) (pPixmap);
927706f2543Smrg    exaMarkSync(pDrawable->pScreen);
928706f2543Smrg
929706f2543Smrgout:
930706f2543Smrg    RegionUninit(pReg);
931706f2543Smrg    RegionDestroy(pReg);
932706f2543Smrg}
933706f2543Smrg
934706f2543Smrgconst GCOps exaOps = {
935706f2543Smrg    exaFillSpans,
936706f2543Smrg    ExaCheckSetSpans,
937706f2543Smrg    exaPutImage,
938706f2543Smrg    exaCopyArea,
939706f2543Smrg    ExaCheckCopyPlane,
940706f2543Smrg    exaPolyPoint,
941706f2543Smrg    exaPolylines,
942706f2543Smrg    exaPolySegment,
943706f2543Smrg    miPolyRectangle,
944706f2543Smrg    ExaCheckPolyArc,
945706f2543Smrg    miFillPolygon,
946706f2543Smrg    exaPolyFillRect,
947706f2543Smrg    miPolyFillArc,
948706f2543Smrg    miPolyText8,
949706f2543Smrg    miPolyText16,
950706f2543Smrg    miImageText8,
951706f2543Smrg    miImageText16,
952706f2543Smrg    ExaCheckImageGlyphBlt,
953706f2543Smrg    ExaCheckPolyGlyphBlt,
954706f2543Smrg    ExaCheckPushPixels,
955706f2543Smrg};
956706f2543Smrg
957706f2543Smrgvoid
958706f2543SmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
959706f2543Smrg{
960706f2543Smrg    RegionRec	rgnDst;
961706f2543Smrg    int		dx, dy;
962706f2543Smrg    PixmapPtr	pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
963706f2543Smrg    ExaScreenPriv(pWin->drawable.pScreen);
964706f2543Smrg
965706f2543Smrg    dx = ptOldOrg.x - pWin->drawable.x;
966706f2543Smrg    dy = ptOldOrg.y - pWin->drawable.y;
967706f2543Smrg    RegionTranslate(prgnSrc, -dx, -dy);
968706f2543Smrg
969706f2543Smrg    RegionInit(&rgnDst, NullBox, 0);
970706f2543Smrg
971706f2543Smrg    RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
972706f2543Smrg#ifdef COMPOSITE
973706f2543Smrg    if (pPixmap->screen_x || pPixmap->screen_y)
974706f2543Smrg	RegionTranslate(&rgnDst,
975706f2543Smrg			  -pPixmap->screen_x, -pPixmap->screen_y);
976706f2543Smrg#endif
977706f2543Smrg
978706f2543Smrg    if (pExaScr->fallback_counter) {
979706f2543Smrg	pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW;
980706f2543Smrg	goto fallback;
981706f2543Smrg    }
982706f2543Smrg
983706f2543Smrg    pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW;
984706f2543Smrg    miCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
985706f2543Smrg		  NULL,
986706f2543Smrg		  &rgnDst, dx, dy, exaCopyNtoN, 0, NULL);
987706f2543Smrg    pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW;
988706f2543Smrg
989706f2543Smrgfallback:
990706f2543Smrg    RegionUninit(&rgnDst);
991706f2543Smrg
992706f2543Smrg    if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) {
993706f2543Smrg	pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW;
994706f2543Smrg	RegionTranslate(prgnSrc, dx, dy);
995706f2543Smrg	ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc);
996706f2543Smrg    }
997706f2543Smrg}
998706f2543Smrg
999706f2543Smrgstatic Bool
1000706f2543SmrgexaFillRegionSolid (DrawablePtr	pDrawable, RegionPtr pRegion, Pixel pixel,
1001706f2543Smrg		    CARD32 planemask, CARD32 alu, unsigned int clientClipType)
1002706f2543Smrg{
1003706f2543Smrg    ExaScreenPriv(pDrawable->pScreen);
1004706f2543Smrg    PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
1005706f2543Smrg    ExaPixmapPriv (pPixmap);
1006706f2543Smrg    int xoff, yoff;
1007706f2543Smrg    Bool ret = FALSE;
1008706f2543Smrg
1009706f2543Smrg    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
1010706f2543Smrg    RegionTranslate(pRegion, xoff, yoff);
1011706f2543Smrg
1012706f2543Smrg    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
1013706f2543Smrg	goto out;
1014706f2543Smrg
1015706f2543Smrg    if (pExaScr->do_migration) {
1016706f2543Smrg	ExaMigrationRec pixmaps[1];
1017706f2543Smrg
1018706f2543Smrg	pixmaps[0].as_dst = TRUE;
1019706f2543Smrg	pixmaps[0].as_src = FALSE;
1020706f2543Smrg	pixmaps[0].pPix = pPixmap;
1021706f2543Smrg	pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
1022706f2543Smrg						alu, clientClipType) ? NULL : pRegion;
1023706f2543Smrg
1024706f2543Smrg	exaDoMigration (pixmaps, 1, TRUE);
1025706f2543Smrg    }
1026706f2543Smrg
1027706f2543Smrg    if (exaPixmapHasGpuCopy (pPixmap) &&
1028706f2543Smrg	(*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
1029706f2543Smrg    {
1030706f2543Smrg	int nbox;
1031706f2543Smrg	BoxPtr pBox;
1032706f2543Smrg
1033706f2543Smrg	nbox = RegionNumRects (pRegion);
1034706f2543Smrg	pBox = RegionRects (pRegion);
1035706f2543Smrg
1036706f2543Smrg	while (nbox--)
1037706f2543Smrg	{
1038706f2543Smrg	    (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
1039706f2543Smrg				     pBox->y2);
1040706f2543Smrg	    pBox++;
1041706f2543Smrg	}
1042706f2543Smrg	(*pExaScr->info->DoneSolid) (pPixmap);
1043706f2543Smrg	exaMarkSync(pDrawable->pScreen);
1044706f2543Smrg
1045706f2543Smrg	if (pExaPixmap->pDamage &&
1046706f2543Smrg	    pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
1047706f2543Smrg	    pDrawable->width == 1 && pDrawable->height == 1 &&
1048706f2543Smrg	    pDrawable->bitsPerPixel != 24) {
1049706f2543Smrg	    ExaPixmapPriv(pPixmap);
1050706f2543Smrg	    RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
1051706f2543Smrg
1052706f2543Smrg	    switch (pDrawable->bitsPerPixel) {
1053706f2543Smrg	    case 32:
1054706f2543Smrg		*(CARD32*)pExaPixmap->sys_ptr = pixel;
1055706f2543Smrg		break;
1056706f2543Smrg	    case 16:
1057706f2543Smrg		*(CARD16*)pExaPixmap->sys_ptr = pixel;
1058706f2543Smrg		break;
1059706f2543Smrg	    case 8:
1060706f2543Smrg	    case 4:
1061706f2543Smrg	    case 1:
1062706f2543Smrg		*(CARD8*)pExaPixmap->sys_ptr = pixel;
1063706f2543Smrg	    }
1064706f2543Smrg
1065706f2543Smrg	    RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys,
1066706f2543Smrg			 pRegion);
1067706f2543Smrg	    RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB,
1068706f2543Smrg			 pRegion);
1069706f2543Smrg	    RegionSubtract(pending_damage, pending_damage, pRegion);
1070706f2543Smrg	}
1071706f2543Smrg
1072706f2543Smrg	ret = TRUE;
1073706f2543Smrg    }
1074706f2543Smrg
1075706f2543Smrgout:
1076706f2543Smrg    RegionTranslate(pRegion, -xoff, -yoff);
1077706f2543Smrg
1078706f2543Smrg    return ret;
1079706f2543Smrg}
1080706f2543Smrg
1081706f2543Smrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
1082706f2543Smrg * Based on fbFillRegionTiled(), fbTile().
1083706f2543Smrg */
1084706f2543SmrgBool
1085706f2543SmrgexaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
1086706f2543Smrg		    DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
1087706f2543Smrg		    unsigned int clientClipType)
1088706f2543Smrg{
1089706f2543Smrg    ExaScreenPriv(pDrawable->pScreen);
1090706f2543Smrg    PixmapPtr pPixmap;
1091706f2543Smrg    ExaPixmapPrivPtr pExaPixmap;
1092706f2543Smrg    ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
1093706f2543Smrg    int xoff, yoff;
1094706f2543Smrg    int tileWidth, tileHeight;
1095706f2543Smrg    int nbox = RegionNumRects (pRegion);
1096706f2543Smrg    BoxPtr pBox = RegionRects (pRegion);
1097706f2543Smrg    Bool ret = FALSE;
1098706f2543Smrg    int i;
1099706f2543Smrg
1100706f2543Smrg    tileWidth = pTile->drawable.width;
1101706f2543Smrg    tileHeight = pTile->drawable.height;
1102706f2543Smrg
1103706f2543Smrg    /* If we're filling with a solid color, grab it out and go to
1104706f2543Smrg     * FillRegionSolid, saving numerous copies.
1105706f2543Smrg     */
1106706f2543Smrg    if (tileWidth == 1 && tileHeight == 1)
1107706f2543Smrg	return exaFillRegionSolid(pDrawable, pRegion,
1108706f2543Smrg				  exaGetPixmapFirstPixel (pTile), planemask,
1109706f2543Smrg				  alu, clientClipType);
1110706f2543Smrg
1111706f2543Smrg    pPixmap = exaGetDrawablePixmap (pDrawable);
1112706f2543Smrg    pExaPixmap = ExaGetPixmapPriv (pPixmap);
1113706f2543Smrg
1114706f2543Smrg    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
1115706f2543Smrg	    pTileExaPixmap->accel_blocked)
1116706f2543Smrg	return FALSE;
1117706f2543Smrg
1118706f2543Smrg    if (pExaScr->do_migration) {
1119706f2543Smrg	ExaMigrationRec pixmaps[2];
1120706f2543Smrg
1121706f2543Smrg	pixmaps[0].as_dst = TRUE;
1122706f2543Smrg	pixmaps[0].as_src = FALSE;
1123706f2543Smrg	pixmaps[0].pPix = pPixmap;
1124706f2543Smrg	pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
1125706f2543Smrg						alu, clientClipType) ? NULL : pRegion;
1126706f2543Smrg	pixmaps[1].as_dst = FALSE;
1127706f2543Smrg	pixmaps[1].as_src = TRUE;
1128706f2543Smrg	pixmaps[1].pPix = pTile;
1129706f2543Smrg	pixmaps[1].pReg = NULL;
1130706f2543Smrg
1131706f2543Smrg	exaDoMigration (pixmaps, 2, TRUE);
1132706f2543Smrg    }
1133706f2543Smrg
1134706f2543Smrg    pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
1135706f2543Smrg
1136706f2543Smrg    if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
1137706f2543Smrg	return FALSE;
1138706f2543Smrg
1139706f2543Smrg    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
1140706f2543Smrg    {
1141706f2543Smrg	if (xoff || yoff)
1142706f2543Smrg	    RegionTranslate(pRegion, xoff, yoff);
1143706f2543Smrg
1144706f2543Smrg	for (i = 0; i < nbox; i++)
1145706f2543Smrg	{
1146706f2543Smrg	    int height = pBox[i].y2 - pBox[i].y1;
1147706f2543Smrg	    int dstY = pBox[i].y1;
1148706f2543Smrg	    int tileY;
1149706f2543Smrg
1150706f2543Smrg	    if (alu == GXcopy)
1151706f2543Smrg		height = min(height, tileHeight);
1152706f2543Smrg
1153706f2543Smrg	    modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
1154706f2543Smrg
1155706f2543Smrg	    while (height > 0) {
1156706f2543Smrg		int width = pBox[i].x2 - pBox[i].x1;
1157706f2543Smrg		int dstX = pBox[i].x1;
1158706f2543Smrg		int tileX;
1159706f2543Smrg		int h = tileHeight - tileY;
1160706f2543Smrg
1161706f2543Smrg		if (alu == GXcopy)
1162706f2543Smrg		    width = min(width, tileWidth);
1163706f2543Smrg
1164706f2543Smrg		if (h > height)
1165706f2543Smrg		    h = height;
1166706f2543Smrg		height -= h;
1167706f2543Smrg
1168706f2543Smrg		modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
1169706f2543Smrg			tileX);
1170706f2543Smrg
1171706f2543Smrg		while (width > 0) {
1172706f2543Smrg		    int w = tileWidth - tileX;
1173706f2543Smrg		    if (w > width)
1174706f2543Smrg			w = width;
1175706f2543Smrg		    width -= w;
1176706f2543Smrg
1177706f2543Smrg		    (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
1178706f2543Smrg					    w, h);
1179706f2543Smrg		    dstX += w;
1180706f2543Smrg		    tileX = 0;
1181706f2543Smrg		}
1182706f2543Smrg		dstY += h;
1183706f2543Smrg		tileY = 0;
1184706f2543Smrg	    }
1185706f2543Smrg	}
1186706f2543Smrg	(*pExaScr->info->DoneCopy) (pPixmap);
1187706f2543Smrg
1188706f2543Smrg	/* With GXcopy, we only need to do the basic algorithm up to the tile
1189706f2543Smrg	 * size; then, we can just keep doubling the destination in each
1190706f2543Smrg	 * direction until it fills the box. This way, the number of copy
1191706f2543Smrg	 * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
1192706f2543Smrg	 * rx/ry is the ratio between box and tile width/height. This can make
1193706f2543Smrg	 * a big difference if each driver copy incurs a significant constant
1194706f2543Smrg	 * overhead.
1195706f2543Smrg	 */
1196706f2543Smrg	if (alu != GXcopy)
1197706f2543Smrg	    ret = TRUE;
1198706f2543Smrg	else {
1199706f2543Smrg	    Bool more_copy = FALSE;
1200706f2543Smrg
1201706f2543Smrg	    for (i = 0; i < nbox; i++) {
1202706f2543Smrg		int dstX = pBox[i].x1 + tileWidth;
1203706f2543Smrg		int dstY = pBox[i].y1 + tileHeight;
1204706f2543Smrg
1205706f2543Smrg		if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
1206706f2543Smrg		    more_copy = TRUE;
1207706f2543Smrg		    break;
1208706f2543Smrg		}
1209706f2543Smrg	    }
1210706f2543Smrg
1211706f2543Smrg	    if (more_copy == FALSE)
1212706f2543Smrg		ret = TRUE;
1213706f2543Smrg
1214706f2543Smrg	    if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
1215706f2543Smrg							    1, 1, alu, planemask)) {
1216706f2543Smrg		for (i = 0; i < nbox; i++)
1217706f2543Smrg		{
1218706f2543Smrg		    int dstX = pBox[i].x1 + tileWidth;
1219706f2543Smrg		    int dstY = pBox[i].y1 + tileHeight;
1220706f2543Smrg		    int width = min(pBox[i].x2 - dstX, tileWidth);
1221706f2543Smrg		    int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
1222706f2543Smrg
1223706f2543Smrg		    while (dstX < pBox[i].x2) {
1224706f2543Smrg			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1225706f2543Smrg						dstX, pBox[i].y1, width, height);
1226706f2543Smrg			dstX += width;
1227706f2543Smrg			width = min(pBox[i].x2 - dstX, width * 2);
1228706f2543Smrg		    }
1229706f2543Smrg
1230706f2543Smrg		    width = pBox[i].x2 - pBox[i].x1;
1231706f2543Smrg		    height = min(pBox[i].y2 - dstY, tileHeight);
1232706f2543Smrg
1233706f2543Smrg		    while (dstY < pBox[i].y2) {
1234706f2543Smrg			(*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
1235706f2543Smrg						pBox[i].x1, dstY, width, height);
1236706f2543Smrg			dstY += height;
1237706f2543Smrg			height = min(pBox[i].y2 - dstY, height * 2);
1238706f2543Smrg		    }
1239706f2543Smrg		}
1240706f2543Smrg
1241706f2543Smrg		(*pExaScr->info->DoneCopy) (pPixmap);
1242706f2543Smrg
1243706f2543Smrg		ret = TRUE;
1244706f2543Smrg	    }
1245706f2543Smrg	}
1246706f2543Smrg
1247706f2543Smrg	exaMarkSync(pDrawable->pScreen);
1248706f2543Smrg
1249706f2543Smrg	if (xoff || yoff)
1250706f2543Smrg	    RegionTranslate(pRegion, -xoff, -yoff);
1251706f2543Smrg    }
1252706f2543Smrg
1253706f2543Smrg    return ret;
1254706f2543Smrg}
1255706f2543Smrg
1256706f2543Smrg
1257706f2543Smrg/**
1258706f2543Smrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
1259706f2543Smrg *
1260706f2543Smrg * This is probably the only case we actually care about.  The rest fall through
1261706f2543Smrg * to migration and fbGetImage, which hopefully will result in migration pushing
1262706f2543Smrg * the pixmap out of framebuffer.
1263706f2543Smrg */
1264706f2543Smrgvoid
1265706f2543SmrgexaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
1266706f2543Smrg	     unsigned int format, unsigned long planeMask, char *d)
1267706f2543Smrg{
1268706f2543Smrg    ExaScreenPriv (pDrawable->pScreen);
1269706f2543Smrg    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
1270706f2543Smrg    ExaPixmapPriv(pPix);
1271706f2543Smrg    int xoff, yoff;
1272706f2543Smrg    Bool ok;
1273706f2543Smrg
1274706f2543Smrg    if (pExaScr->fallback_counter || pExaScr->swappedOut)
1275706f2543Smrg	goto fallback;
1276706f2543Smrg
1277706f2543Smrg    /* If there's a system copy, we want to save the result there */
1278706f2543Smrg    if (pExaPixmap->pDamage)
1279706f2543Smrg	goto fallback;
1280706f2543Smrg
1281706f2543Smrg    pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
1282706f2543Smrg
1283706f2543Smrg    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
1284706f2543Smrg	goto fallback;
1285706f2543Smrg
1286706f2543Smrg    /* Only cover the ZPixmap, solid copy case. */
1287706f2543Smrg    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
1288706f2543Smrg	goto fallback;
1289706f2543Smrg
1290706f2543Smrg    /* Only try to handle the 8bpp and up cases, since we don't want to think
1291706f2543Smrg     * about <8bpp.
1292706f2543Smrg     */
1293706f2543Smrg    if (pDrawable->bitsPerPixel < 8)
1294706f2543Smrg	goto fallback;
1295706f2543Smrg
1296706f2543Smrg    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
1297706f2543Smrg					   pDrawable->y + y + yoff, w, h, d,
1298706f2543Smrg					   PixmapBytePad(w, pDrawable->depth));
1299706f2543Smrg    if (ok) {
1300706f2543Smrg	exaWaitSync(pDrawable->pScreen);
1301706f2543Smrg	return;
1302706f2543Smrg    }
1303706f2543Smrg
1304706f2543Smrgfallback:
1305706f2543Smrg    ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
1306706f2543Smrg}
1307