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