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