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