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