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 
38 static void
exaFillSpans(DrawablePtr pDrawable,GCPtr pGC,int n,DDXPointPtr ppt,int * pwidth,int fSorted)39 exaFillSpans(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 
137 static Bool
exaDoPutImage(DrawablePtr pDrawable,GCPtr pGC,int depth,int x,int y,int w,int h,int format,char * bits,int src_stride)138 exaDoPutImage(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 
229 static void
exaPutImage(DrawablePtr pDrawable,GCPtr pGC,int depth,int x,int y,int w,int h,int leftPad,int format,char * bits)230 exaPutImage(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 
239 static Bool inline
exaCopyNtoNTwoDir(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,BoxPtr pbox,int nbox,int dx,int dy)240 exaCopyNtoNTwoDir(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 
363 Bool
exaHWCopyNtoN(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,BoxPtr pbox,int nbox,int dx,int dy,Bool reverse,Bool upsidedown)364 exaHWCopyNtoN(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 
565 void
exaCopyNtoN(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,BoxPtr pbox,int nbox,int dx,int dy,Bool reverse,Bool upsidedown,Pixel bitplane,void * closure)566 exaCopyNtoN(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 
597 RegionPtr
exaCopyArea(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,int srcx,int srcy,int width,int height,int dstx,int dsty)598 exaCopyArea(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 
613 static void
exaPolyPoint(DrawablePtr pDrawable,GCPtr pGC,int mode,int npt,DDXPointPtr ppt)614 exaPolyPoint(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  */
649 static void
exaPolylines(DrawablePtr pDrawable,GCPtr pGC,int mode,int npt,DDXPointPtr ppt)650 exaPolylines(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  */
719 static void
exaPolySegment(DrawablePtr pDrawable,GCPtr pGC,int nseg,xSegment * pSeg)720 exaPolySegment(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(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 
772 static Bool exaFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion,
773                                Pixel pixel, CARD32 planemask, CARD32 alu,
774                                Bool hasClientClip);
775 
776 static void
exaPolyFillRect(DrawablePtr pDrawable,GCPtr pGC,int nrect,xRectangle * prect)777 exaPolyFillRect(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 
927 const 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 
950 void
exaCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)951 exaCopyWindow(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 
991 static Bool
exaFillRegionSolid(DrawablePtr pDrawable,RegionPtr pRegion,Pixel pixel,CARD32 planemask,CARD32 alu,Bool hasClientClip)992 exaFillRegionSolid(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  */
1073 Bool
exaFillRegionTiled(DrawablePtr pDrawable,RegionPtr pRegion,PixmapPtr pTile,DDXPointPtr pPatOrg,CARD32 planemask,CARD32 alu,Bool hasClientClip)1074 exaFillRegionTiled(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  */
1254 void
exaGetImage(DrawablePtr pDrawable,int x,int y,int w,int h,unsigned int format,unsigned long planeMask,char * d)1255 exaGetImage(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