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