exa_accel.c revision 4202a189
105b261ecSmrg/* 205b261ecSmrg * Copyright � 2001 Keith Packard 305b261ecSmrg * 405b261ecSmrg * Partly based on code that is Copyright � The XFree86 Project Inc. 505b261ecSmrg * 605b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 705b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 805b261ecSmrg * the above copyright notice appear in all copies and that both that 905b261ecSmrg * copyright notice and this permission notice appear in supporting 1005b261ecSmrg * documentation, and that the name of Keith Packard not be used in 1105b261ecSmrg * advertising or publicity pertaining to distribution of the software without 1205b261ecSmrg * specific, written prior permission. Keith Packard makes no 1305b261ecSmrg * representations about the suitability of this software for any purpose. It 1405b261ecSmrg * is provided "as is" without express or implied warranty. 1505b261ecSmrg * 1605b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1705b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1805b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1905b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 2005b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2105b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2205b261ecSmrg * PERFORMANCE OF THIS SOFTWARE. 2305b261ecSmrg * 2405b261ecSmrg * Authors: 2505b261ecSmrg * Eric Anholt <eric@anholt.net> 2605b261ecSmrg * Michel D�nzer <michel@tungstengraphics.com> 2705b261ecSmrg * 2805b261ecSmrg */ 2905b261ecSmrg 3005b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 3105b261ecSmrg#include <dix-config.h> 3205b261ecSmrg#endif 3305b261ecSmrg#include "exa_priv.h" 3405b261ecSmrg#include <X11/fonts/fontstruct.h> 3505b261ecSmrg#include "dixfontstr.h" 3605b261ecSmrg#include "exa.h" 3705b261ecSmrg 3805b261ecSmrgstatic void 3905b261ecSmrgexaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, 4005b261ecSmrg DDXPointPtr ppt, int *pwidth, int fSorted) 4105b261ecSmrg{ 4205b261ecSmrg ScreenPtr pScreen = pDrawable->pScreen; 4305b261ecSmrg ExaScreenPriv (pScreen); 4405b261ecSmrg RegionPtr pClip = fbGetCompositeClip(pGC); 454642e01fSmrg PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); 464642e01fSmrg ExaPixmapPriv (pPixmap); 4705b261ecSmrg BoxPtr pextent, pbox; 4805b261ecSmrg int nbox; 4905b261ecSmrg int extentX1, extentX2, extentY1, extentY2; 5005b261ecSmrg int fullX1, fullX2, fullY1; 5105b261ecSmrg int partX1, partX2; 5205b261ecSmrg int off_x, off_y; 5305b261ecSmrg 544202a189Smrg if (pExaScr->fallback_counter || 554202a189Smrg pExaScr->swappedOut || 5605b261ecSmrg pGC->fillStyle != FillSolid || 574642e01fSmrg pExaPixmap->accel_blocked) 5805b261ecSmrg { 5905b261ecSmrg ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); 6005b261ecSmrg return; 614202a189Smrg } 624202a189Smrg 634202a189Smrg if (pExaScr->do_migration) { 644202a189Smrg ExaMigrationRec pixmaps[1]; 654202a189Smrg 664202a189Smrg pixmaps[0].as_dst = TRUE; 674202a189Smrg pixmaps[0].as_src = FALSE; 684202a189Smrg pixmaps[0].pPix = pPixmap; 694202a189Smrg pixmaps[0].pReg = NULL; 704202a189Smrg 7105b261ecSmrg exaDoMigration (pixmaps, 1, TRUE); 7205b261ecSmrg } 7305b261ecSmrg 7405b261ecSmrg if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) || 7505b261ecSmrg !(*pExaScr->info->PrepareSolid) (pPixmap, 7605b261ecSmrg pGC->alu, 7705b261ecSmrg pGC->planemask, 7805b261ecSmrg pGC->fgPixel)) 7905b261ecSmrg { 8005b261ecSmrg ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); 8105b261ecSmrg return; 8205b261ecSmrg } 8305b261ecSmrg 844202a189Smrg pextent = RegionExtents(pClip); 8505b261ecSmrg extentX1 = pextent->x1; 8605b261ecSmrg extentY1 = pextent->y1; 8705b261ecSmrg extentX2 = pextent->x2; 8805b261ecSmrg extentY2 = pextent->y2; 8905b261ecSmrg while (n--) 9005b261ecSmrg { 9105b261ecSmrg fullX1 = ppt->x; 9205b261ecSmrg fullY1 = ppt->y; 9305b261ecSmrg fullX2 = fullX1 + (int) *pwidth; 9405b261ecSmrg ppt++; 9505b261ecSmrg pwidth++; 9605b261ecSmrg 9705b261ecSmrg if (fullY1 < extentY1 || extentY2 <= fullY1) 9805b261ecSmrg continue; 9905b261ecSmrg 10005b261ecSmrg if (fullX1 < extentX1) 10105b261ecSmrg fullX1 = extentX1; 10205b261ecSmrg 10305b261ecSmrg if (fullX2 > extentX2) 10405b261ecSmrg fullX2 = extentX2; 10505b261ecSmrg 10605b261ecSmrg if (fullX1 >= fullX2) 10705b261ecSmrg continue; 10805b261ecSmrg 1094202a189Smrg nbox = RegionNumRects (pClip); 11005b261ecSmrg if (nbox == 1) 11105b261ecSmrg { 11205b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 11305b261ecSmrg fullX1 + off_x, fullY1 + off_y, 11405b261ecSmrg fullX2 + off_x, fullY1 + 1 + off_y); 11505b261ecSmrg } 11605b261ecSmrg else 11705b261ecSmrg { 1184202a189Smrg pbox = RegionRects(pClip); 11905b261ecSmrg while(nbox--) 12005b261ecSmrg { 12105b261ecSmrg if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) 12205b261ecSmrg { 12305b261ecSmrg partX1 = pbox->x1; 12405b261ecSmrg if (partX1 < fullX1) 12505b261ecSmrg partX1 = fullX1; 12605b261ecSmrg partX2 = pbox->x2; 12705b261ecSmrg if (partX2 > fullX2) 12805b261ecSmrg partX2 = fullX2; 12905b261ecSmrg if (partX2 > partX1) { 13005b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 13105b261ecSmrg partX1 + off_x, fullY1 + off_y, 13205b261ecSmrg partX2 + off_x, fullY1 + 1 + off_y); 13305b261ecSmrg } 13405b261ecSmrg } 13505b261ecSmrg pbox++; 13605b261ecSmrg } 13705b261ecSmrg } 13805b261ecSmrg } 13905b261ecSmrg (*pExaScr->info->DoneSolid) (pPixmap); 14005b261ecSmrg exaMarkSync(pScreen); 14105b261ecSmrg} 14205b261ecSmrg 1434642e01fSmrgstatic Bool 1444642e01fSmrgexaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, 1454642e01fSmrg int w, int h, int format, char *bits, int src_stride) 14605b261ecSmrg{ 14705b261ecSmrg ExaScreenPriv (pDrawable->pScreen); 1484642e01fSmrg PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); 1494642e01fSmrg ExaPixmapPriv(pPix); 15005b261ecSmrg RegionPtr pClip; 15105b261ecSmrg BoxPtr pbox; 15205b261ecSmrg int nbox; 15305b261ecSmrg int xoff, yoff; 1544642e01fSmrg int bpp = pDrawable->bitsPerPixel; 1554202a189Smrg Bool ret = TRUE; 15605b261ecSmrg 1574202a189Smrg if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen) 1584202a189Smrg return FALSE; 1594202a189Smrg 1604202a189Smrg /* If there's a system copy, we want to save the result there */ 1614202a189Smrg if (pExaPixmap->pDamage) 1624642e01fSmrg return FALSE; 16305b261ecSmrg 16405b261ecSmrg /* Don't bother with under 8bpp, XYPixmaps. */ 16505b261ecSmrg if (format != ZPixmap || bpp < 8) 1664642e01fSmrg return FALSE; 16705b261ecSmrg 16805b261ecSmrg /* Only accelerate copies: no rop or planemask. */ 16905b261ecSmrg if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) 1704642e01fSmrg return FALSE; 17105b261ecSmrg 17205b261ecSmrg if (pExaScr->swappedOut) 1734642e01fSmrg return FALSE; 17405b261ecSmrg 1754202a189Smrg if (pExaScr->do_migration) { 1764642e01fSmrg ExaMigrationRec pixmaps[1]; 17705b261ecSmrg 1784202a189Smrg pixmaps[0].as_dst = TRUE; 1794642e01fSmrg pixmaps[0].as_src = FALSE; 1804642e01fSmrg pixmaps[0].pPix = pPix; 1814642e01fSmrg pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); 1824642e01fSmrg 1834642e01fSmrg exaDoMigration (pixmaps, 1, TRUE); 1844642e01fSmrg } 18505b261ecSmrg 18605b261ecSmrg pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 18705b261ecSmrg 1884202a189Smrg if (!pPix) 1894642e01fSmrg return FALSE; 19005b261ecSmrg 19105b261ecSmrg x += pDrawable->x; 19205b261ecSmrg y += pDrawable->y; 19305b261ecSmrg 19405b261ecSmrg pClip = fbGetCompositeClip(pGC); 1954202a189Smrg for (nbox = RegionNumRects(pClip), 1964202a189Smrg pbox = RegionRects(pClip); 19705b261ecSmrg nbox--; 19805b261ecSmrg pbox++) 19905b261ecSmrg { 20005b261ecSmrg int x1 = x; 20105b261ecSmrg int y1 = y; 20205b261ecSmrg int x2 = x + w; 20305b261ecSmrg int y2 = y + h; 20405b261ecSmrg char *src; 20505b261ecSmrg Bool ok; 20605b261ecSmrg 20705b261ecSmrg if (x1 < pbox->x1) 20805b261ecSmrg x1 = pbox->x1; 20905b261ecSmrg if (y1 < pbox->y1) 21005b261ecSmrg y1 = pbox->y1; 21105b261ecSmrg if (x2 > pbox->x2) 21205b261ecSmrg x2 = pbox->x2; 21305b261ecSmrg if (y2 > pbox->y2) 21405b261ecSmrg y2 = pbox->y2; 21505b261ecSmrg if (x1 >= x2 || y1 >= y2) 21605b261ecSmrg continue; 21705b261ecSmrg 21805b261ecSmrg src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); 21905b261ecSmrg ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, 22005b261ecSmrg x2 - x1, y2 - y1, src, src_stride); 2214202a189Smrg /* We have to fall back completely, and ignore what has already been completed. 2224202a189Smrg * Messing with the fb layer directly like we used to is completely unacceptable. 22305b261ecSmrg */ 22405b261ecSmrg if (!ok) { 2254202a189Smrg ret = FALSE; 2264202a189Smrg break; 22705b261ecSmrg } 22805b261ecSmrg } 22905b261ecSmrg 2304202a189Smrg if (ret) 2314642e01fSmrg exaMarkSync(pDrawable->pScreen); 23205b261ecSmrg 2334202a189Smrg return ret; 2344642e01fSmrg} 23505b261ecSmrg 2364642e01fSmrgstatic void 2374642e01fSmrgexaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, 2384642e01fSmrg int w, int h, int leftPad, int format, char *bits) 2394642e01fSmrg{ 2404642e01fSmrg if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits, 2414642e01fSmrg PixmapBytePad(w, pDrawable->depth))) 2424642e01fSmrg ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, 2434642e01fSmrg bits); 24405b261ecSmrg} 24505b261ecSmrg 24605b261ecSmrgstatic Bool inline 24705b261ecSmrgexaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, 24805b261ecSmrg GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) 24905b261ecSmrg{ 25005b261ecSmrg ExaScreenPriv (pDstDrawable->pScreen); 25105b261ecSmrg PixmapPtr pSrcPixmap, pDstPixmap; 25205b261ecSmrg int src_off_x, src_off_y, dst_off_x, dst_off_y; 25305b261ecSmrg int dirsetup; 25405b261ecSmrg 25505b261ecSmrg /* Need to get both pixmaps to call the driver routines */ 25605b261ecSmrg pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y); 25705b261ecSmrg pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y); 25805b261ecSmrg if (!pSrcPixmap || !pDstPixmap) 25905b261ecSmrg return FALSE; 26005b261ecSmrg 26105b261ecSmrg /* 26205b261ecSmrg * Now the case of a chip that only supports xdir = ydir = 1 or 26305b261ecSmrg * xdir = ydir = -1, but we have xdir != ydir. 26405b261ecSmrg */ 26505b261ecSmrg dirsetup = 0; /* No direction set up yet. */ 26605b261ecSmrg for (; nbox; pbox++, nbox--) { 26705b261ecSmrg if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 26805b261ecSmrg /* Do a xdir = ydir = -1 blit instead. */ 26905b261ecSmrg if (dirsetup != -1) { 27005b261ecSmrg if (dirsetup != 0) 27105b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 27205b261ecSmrg dirsetup = -1; 27305b261ecSmrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 27405b261ecSmrg pDstPixmap, 27505b261ecSmrg -1, -1, 27605b261ecSmrg pGC ? pGC->alu : GXcopy, 27705b261ecSmrg pGC ? pGC->planemask : 27805b261ecSmrg FB_ALLONES)) 27905b261ecSmrg return FALSE; 28005b261ecSmrg } 28105b261ecSmrg (*pExaScr->info->Copy)(pDstPixmap, 28205b261ecSmrg src_off_x + pbox->x1 + dx, 28305b261ecSmrg src_off_y + pbox->y1 + dy, 28405b261ecSmrg dst_off_x + pbox->x1, 28505b261ecSmrg dst_off_y + pbox->y1, 28605b261ecSmrg pbox->x2 - pbox->x1, 28705b261ecSmrg pbox->y2 - pbox->y1); 28805b261ecSmrg } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 28905b261ecSmrg /* Do a xdir = ydir = 1 blit instead. */ 29005b261ecSmrg if (dirsetup != 1) { 29105b261ecSmrg if (dirsetup != 0) 29205b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 29305b261ecSmrg dirsetup = 1; 29405b261ecSmrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 29505b261ecSmrg pDstPixmap, 29605b261ecSmrg 1, 1, 29705b261ecSmrg pGC ? pGC->alu : GXcopy, 29805b261ecSmrg pGC ? pGC->planemask : 29905b261ecSmrg FB_ALLONES)) 30005b261ecSmrg return FALSE; 30105b261ecSmrg } 30205b261ecSmrg (*pExaScr->info->Copy)(pDstPixmap, 30305b261ecSmrg src_off_x + pbox->x1 + dx, 30405b261ecSmrg src_off_y + pbox->y1 + dy, 30505b261ecSmrg dst_off_x + pbox->x1, 30605b261ecSmrg dst_off_y + pbox->y1, 30705b261ecSmrg pbox->x2 - pbox->x1, 30805b261ecSmrg pbox->y2 - pbox->y1); 30905b261ecSmrg } else if (dx >= 0) { 31005b261ecSmrg /* 31105b261ecSmrg * xdir = 1, ydir = -1. 31205b261ecSmrg * Perform line-by-line xdir = ydir = 1 blits, going up. 31305b261ecSmrg */ 31405b261ecSmrg int i; 31505b261ecSmrg if (dirsetup != 1) { 31605b261ecSmrg if (dirsetup != 0) 31705b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 31805b261ecSmrg dirsetup = 1; 31905b261ecSmrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 32005b261ecSmrg pDstPixmap, 32105b261ecSmrg 1, 1, 32205b261ecSmrg pGC ? pGC->alu : GXcopy, 32305b261ecSmrg pGC ? pGC->planemask : 32405b261ecSmrg FB_ALLONES)) 32505b261ecSmrg return FALSE; 32605b261ecSmrg } 32705b261ecSmrg for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) 32805b261ecSmrg (*pExaScr->info->Copy)(pDstPixmap, 32905b261ecSmrg src_off_x + pbox->x1 + dx, 33005b261ecSmrg src_off_y + pbox->y1 + dy + i, 33105b261ecSmrg dst_off_x + pbox->x1, 33205b261ecSmrg dst_off_y + pbox->y1 + i, 33305b261ecSmrg pbox->x2 - pbox->x1, 1); 33405b261ecSmrg } else { 33505b261ecSmrg /* 33605b261ecSmrg * xdir = -1, ydir = 1. 33705b261ecSmrg * Perform line-by-line xdir = ydir = -1 blits, going down. 33805b261ecSmrg */ 33905b261ecSmrg int i; 34005b261ecSmrg if (dirsetup != -1) { 34105b261ecSmrg if (dirsetup != 0) 34205b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 34305b261ecSmrg dirsetup = -1; 34405b261ecSmrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 34505b261ecSmrg pDstPixmap, 34605b261ecSmrg -1, -1, 34705b261ecSmrg pGC ? pGC->alu : GXcopy, 34805b261ecSmrg pGC ? pGC->planemask : 34905b261ecSmrg FB_ALLONES)) 35005b261ecSmrg return FALSE; 35105b261ecSmrg } 35205b261ecSmrg for (i = 0; i < pbox->y2 - pbox->y1; i++) 35305b261ecSmrg (*pExaScr->info->Copy)(pDstPixmap, 35405b261ecSmrg src_off_x + pbox->x1 + dx, 35505b261ecSmrg src_off_y + pbox->y1 + dy + i, 35605b261ecSmrg dst_off_x + pbox->x1, 35705b261ecSmrg dst_off_y + pbox->y1 + i, 35805b261ecSmrg pbox->x2 - pbox->x1, 1); 35905b261ecSmrg } 36005b261ecSmrg } 36105b261ecSmrg if (dirsetup != 0) 36205b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 36305b261ecSmrg exaMarkSync(pDstDrawable->pScreen); 36405b261ecSmrg return TRUE; 36505b261ecSmrg} 36605b261ecSmrg 3674202a189SmrgBool 3684202a189SmrgexaHWCopyNtoN (DrawablePtr pSrcDrawable, 36905b261ecSmrg DrawablePtr pDstDrawable, 37005b261ecSmrg GCPtr pGC, 37105b261ecSmrg BoxPtr pbox, 37205b261ecSmrg int nbox, 37305b261ecSmrg int dx, 37405b261ecSmrg int dy, 37505b261ecSmrg Bool reverse, 3764202a189Smrg Bool upsidedown) 37705b261ecSmrg{ 37805b261ecSmrg ExaScreenPriv (pDstDrawable->pScreen); 37905b261ecSmrg PixmapPtr pSrcPixmap, pDstPixmap; 3804642e01fSmrg ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap; 38105b261ecSmrg int src_off_x, src_off_y; 38205b261ecSmrg int dst_off_x, dst_off_y; 3834642e01fSmrg RegionPtr srcregion = NULL, dstregion = NULL; 3844642e01fSmrg xRectangle *rects; 3854202a189Smrg Bool ret = TRUE; 3864642e01fSmrg 3874642e01fSmrg /* avoid doing copy operations if no boxes */ 3884642e01fSmrg if (nbox == 0) 3894202a189Smrg return TRUE; 3904642e01fSmrg 3914642e01fSmrg pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); 3924642e01fSmrg pDstPixmap = exaGetDrawablePixmap (pDstDrawable); 3934642e01fSmrg 3944642e01fSmrg exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); 3954642e01fSmrg exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); 3964642e01fSmrg 3974202a189Smrg rects = malloc(nbox * sizeof(xRectangle)); 3984642e01fSmrg 3994642e01fSmrg if (rects) { 4004642e01fSmrg int i; 4017b683adcSmrg int ordering; 4024642e01fSmrg 4034642e01fSmrg for (i = 0; i < nbox; i++) { 4044642e01fSmrg rects[i].x = pbox[i].x1 + dx + src_off_x; 4054642e01fSmrg rects[i].y = pbox[i].y1 + dy + src_off_y; 4064642e01fSmrg rects[i].width = pbox[i].x2 - pbox[i].x1; 4074642e01fSmrg rects[i].height = pbox[i].y2 - pbox[i].y1; 4084642e01fSmrg } 4094642e01fSmrg 4104202a189Smrg /* This must match the RegionCopy() logic for reversing rect order */ 4117b683adcSmrg if (nbox == 1 || (dx > 0 && dy > 0) || 4127b683adcSmrg (pDstDrawable != pSrcDrawable && 4137b683adcSmrg (pDstDrawable->type != DRAWABLE_WINDOW || 4147b683adcSmrg pSrcDrawable->type != DRAWABLE_WINDOW))) 4157b683adcSmrg ordering = CT_YXBANDED; 4167b683adcSmrg else 4177b683adcSmrg ordering = CT_UNSORTED; 4187b683adcSmrg 4194202a189Smrg srcregion = RegionFromRects(nbox, rects, ordering); 4204202a189Smrg free(rects); 4214642e01fSmrg 4224642e01fSmrg if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, 42352397711Smrg pGC->fillStyle, pGC->alu, 42452397711Smrg pGC->clientClipType)) { 4254202a189Smrg dstregion = RegionCreate(NullBox, 0); 4264202a189Smrg RegionCopy(dstregion, srcregion); 4274202a189Smrg RegionTranslate(dstregion, dst_off_x - dx - src_off_x, 4284642e01fSmrg dst_off_y - dy - src_off_y); 4294642e01fSmrg } 4304642e01fSmrg } 43105b261ecSmrg 43205b261ecSmrg 4334642e01fSmrg pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap); 4344642e01fSmrg pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); 4354642e01fSmrg 4364642e01fSmrg /* Check whether the accelerator can use this pixmap. 4374642e01fSmrg * If the pitch of the pixmaps is out of range, there's nothing 4384642e01fSmrg * we can do but fall back to software rendering. 43905b261ecSmrg */ 4404642e01fSmrg if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || 4414642e01fSmrg pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) 4424642e01fSmrg goto fallback; 4434642e01fSmrg 4444642e01fSmrg /* If the width or the height of either of the pixmaps 4454642e01fSmrg * is out of range, check whether the boxes are actually out of the 4464642e01fSmrg * addressable range as well. If they aren't, we can still do 4474642e01fSmrg * the copying in hardware. 4484642e01fSmrg */ 4494642e01fSmrg if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { 4504642e01fSmrg int i; 4514642e01fSmrg 4524642e01fSmrg for (i = 0; i < nbox; i++) { 4534642e01fSmrg /* src */ 4544642e01fSmrg if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || 4554642e01fSmrg (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) 4564642e01fSmrg goto fallback; 4574642e01fSmrg 4584642e01fSmrg /* dst */ 4594642e01fSmrg if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || 4604642e01fSmrg (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) 4614642e01fSmrg goto fallback; 4624642e01fSmrg } 46305b261ecSmrg } 46405b261ecSmrg 4654202a189Smrg if (pExaScr->do_migration) { 4664202a189Smrg ExaMigrationRec pixmaps[2]; 4674202a189Smrg 4684202a189Smrg pixmaps[0].as_dst = TRUE; 4694202a189Smrg pixmaps[0].as_src = FALSE; 4704202a189Smrg pixmaps[0].pPix = pDstPixmap; 4714202a189Smrg pixmaps[0].pReg = dstregion; 4724202a189Smrg pixmaps[1].as_dst = FALSE; 4734202a189Smrg pixmaps[1].as_src = TRUE; 4744202a189Smrg pixmaps[1].pPix = pSrcPixmap; 4754202a189Smrg pixmaps[1].pReg = srcregion; 4764202a189Smrg 4774202a189Smrg exaDoMigration (pixmaps, 2, TRUE); 4784202a189Smrg } 4794642e01fSmrg 48005b261ecSmrg /* Mixed directions must be handled specially if the card is lame */ 4814642e01fSmrg if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && 48205b261ecSmrg reverse != upsidedown) { 48305b261ecSmrg if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, 48405b261ecSmrg dx, dy)) 4854642e01fSmrg goto out; 4864642e01fSmrg goto fallback; 48705b261ecSmrg } 48805b261ecSmrg 4894202a189Smrg if (exaPixmapHasGpuCopy(pDstPixmap)) { 4904202a189Smrg /* Normal blitting. */ 4914202a189Smrg if (exaPixmapHasGpuCopy(pSrcPixmap)) { 4924202a189Smrg if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, 4934202a189Smrg upsidedown ? -1 : 1, 4944202a189Smrg pGC ? pGC->alu : GXcopy, 4954202a189Smrg pGC ? pGC->planemask : FB_ALLONES)) { 4964202a189Smrg goto fallback; 4974202a189Smrg } 49805b261ecSmrg 4994202a189Smrg while (nbox--) 5004202a189Smrg { 5014202a189Smrg (*pExaScr->info->Copy) (pDstPixmap, 5024202a189Smrg pbox->x1 + dx + src_off_x, 5034202a189Smrg pbox->y1 + dy + src_off_y, 5044202a189Smrg pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, 5054202a189Smrg pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); 5064202a189Smrg pbox++; 5074202a189Smrg } 5084202a189Smrg 5094202a189Smrg (*pExaScr->info->DoneCopy) (pDstPixmap); 5104202a189Smrg exaMarkSync (pDstDrawable->pScreen); 5114202a189Smrg /* UTS: mainly for SHM PutImage's secondary path. 5124202a189Smrg * 5134202a189Smrg * Only taking this path for directly accessible pixmaps. 5144202a189Smrg */ 5154202a189Smrg } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) { 5164202a189Smrg int bpp = pSrcDrawable->bitsPerPixel; 5174202a189Smrg int src_stride = exaGetPixmapPitch(pSrcPixmap); 5184202a189Smrg CARD8 *src = NULL; 5194202a189Smrg 5204202a189Smrg if (!pExaScr->info->UploadToScreen) 5214202a189Smrg goto fallback; 52205b261ecSmrg 5234202a189Smrg if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) 5244202a189Smrg goto fallback; 5254202a189Smrg 5264202a189Smrg if (pSrcDrawable->bitsPerPixel < 8) 5274202a189Smrg goto fallback; 5284202a189Smrg 5294202a189Smrg if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask))) 5304202a189Smrg goto fallback; 5314202a189Smrg 5324202a189Smrg while (nbox--) 5334202a189Smrg { 5344202a189Smrg src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8); 5354202a189Smrg if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x, 5364202a189Smrg pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, 5374202a189Smrg (char *) src, src_stride)) 5384202a189Smrg goto fallback; 5394202a189Smrg 5404202a189Smrg pbox++; 5414202a189Smrg } 5424202a189Smrg } else 5434202a189Smrg goto fallback; 5444202a189Smrg } else 5454202a189Smrg goto fallback; 5464642e01fSmrg 5474642e01fSmrg goto out; 5484642e01fSmrg 5494642e01fSmrgfallback: 5504202a189Smrg ret = FALSE; 5514642e01fSmrg 5524642e01fSmrgout: 5534642e01fSmrg if (dstregion) { 5544202a189Smrg RegionUninit(dstregion); 5554202a189Smrg RegionDestroy(dstregion); 5564642e01fSmrg } 5574642e01fSmrg if (srcregion) { 5584202a189Smrg RegionUninit(srcregion); 5594202a189Smrg RegionDestroy(srcregion); 5604642e01fSmrg } 5614202a189Smrg 5624202a189Smrg return ret; 5634202a189Smrg} 5644202a189Smrg 5654202a189Smrgvoid 5664202a189SmrgexaCopyNtoN (DrawablePtr pSrcDrawable, 5674202a189Smrg DrawablePtr pDstDrawable, 5684202a189Smrg GCPtr pGC, 5694202a189Smrg BoxPtr pbox, 5704202a189Smrg int nbox, 5714202a189Smrg int dx, 5724202a189Smrg int dy, 5734202a189Smrg Bool reverse, 5744202a189Smrg Bool upsidedown, 5754202a189Smrg Pixel bitplane, 5764202a189Smrg void *closure) 5774202a189Smrg{ 5784202a189Smrg ExaScreenPriv(pDstDrawable->pScreen); 5794202a189Smrg 5804202a189Smrg if (pExaScr->fallback_counter || 5814202a189Smrg (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW)) 5824202a189Smrg return; 5834202a189Smrg 5844202a189Smrg if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown)) 5854202a189Smrg return; 5864202a189Smrg 5874202a189Smrg /* This is a CopyWindow, it's cleaner to fallback at the original call. */ 5884202a189Smrg if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) { 5894202a189Smrg pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; 5904202a189Smrg return; 5914202a189Smrg } 5924202a189Smrg 5934202a189Smrg /* fallback */ 5944202a189Smrg ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure); 59505b261ecSmrg} 59605b261ecSmrg 59705b261ecSmrgRegionPtr 59805b261ecSmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, 59905b261ecSmrg int srcx, int srcy, int width, int height, int dstx, int dsty) 60005b261ecSmrg{ 60105b261ecSmrg ExaScreenPriv (pDstDrawable->pScreen); 60205b261ecSmrg 6034202a189Smrg if (pExaScr->fallback_counter || pExaScr->swappedOut) { 60405b261ecSmrg return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, 60505b261ecSmrg srcx, srcy, width, height, dstx, dsty); 60605b261ecSmrg } 60705b261ecSmrg 6084202a189Smrg return miDoCopy (pSrcDrawable, pDstDrawable, pGC, 60905b261ecSmrg srcx, srcy, width, height, 61005b261ecSmrg dstx, dsty, exaCopyNtoN, 0, NULL); 61105b261ecSmrg} 61205b261ecSmrg 61305b261ecSmrgstatic void 61405b261ecSmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 61505b261ecSmrg DDXPointPtr ppt) 61605b261ecSmrg{ 6174202a189Smrg ExaScreenPriv (pDrawable->pScreen); 61805b261ecSmrg int i; 61905b261ecSmrg xRectangle *prect; 62005b261ecSmrg 62105b261ecSmrg /* If we can't reuse the current GC as is, don't bother accelerating the 62205b261ecSmrg * points. 62305b261ecSmrg */ 6244202a189Smrg if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) { 62505b261ecSmrg ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); 62605b261ecSmrg return; 62705b261ecSmrg } 62805b261ecSmrg 6294202a189Smrg prect = malloc(sizeof(xRectangle) * npt); 63005b261ecSmrg for (i = 0; i < npt; i++) { 63105b261ecSmrg prect[i].x = ppt[i].x; 63205b261ecSmrg prect[i].y = ppt[i].y; 63305b261ecSmrg if (i > 0 && mode == CoordModePrevious) { 63405b261ecSmrg prect[i].x += prect[i - 1].x; 63505b261ecSmrg prect[i].y += prect[i - 1].y; 63605b261ecSmrg } 63705b261ecSmrg prect[i].width = 1; 63805b261ecSmrg prect[i].height = 1; 63905b261ecSmrg } 64005b261ecSmrg pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); 6414202a189Smrg free(prect); 64205b261ecSmrg} 64305b261ecSmrg 64405b261ecSmrg/** 64505b261ecSmrg * exaPolylines() checks if it can accelerate the lines as a group of 64605b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill 64705b261ecSmrg * acceleration if so. 64805b261ecSmrg */ 64905b261ecSmrgstatic void 65005b261ecSmrgexaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 65105b261ecSmrg DDXPointPtr ppt) 65205b261ecSmrg{ 6534202a189Smrg ExaScreenPriv (pDrawable->pScreen); 65405b261ecSmrg xRectangle *prect; 65505b261ecSmrg int x1, x2, y1, y2; 65605b261ecSmrg int i; 65705b261ecSmrg 6584202a189Smrg if (pExaScr->fallback_counter) { 6594202a189Smrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 6604202a189Smrg return; 6614202a189Smrg } 6624202a189Smrg 66305b261ecSmrg /* Don't try to do wide lines or non-solid fill style. */ 66405b261ecSmrg if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 66505b261ecSmrg pGC->fillStyle != FillSolid) { 66605b261ecSmrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 66705b261ecSmrg return; 66805b261ecSmrg } 66905b261ecSmrg 6704202a189Smrg prect = malloc(sizeof(xRectangle) * (npt - 1)); 67105b261ecSmrg x1 = ppt[0].x; 67205b261ecSmrg y1 = ppt[0].y; 67305b261ecSmrg /* If we have any non-horizontal/vertical, fall back. */ 67405b261ecSmrg for (i = 0; i < npt - 1; i++) { 67505b261ecSmrg if (mode == CoordModePrevious) { 67605b261ecSmrg x2 = x1 + ppt[i + 1].x; 67705b261ecSmrg y2 = y1 + ppt[i + 1].y; 67805b261ecSmrg } else { 67905b261ecSmrg x2 = ppt[i + 1].x; 68005b261ecSmrg y2 = ppt[i + 1].y; 68105b261ecSmrg } 68205b261ecSmrg 68305b261ecSmrg if (x1 != x2 && y1 != y2) { 6844202a189Smrg free(prect); 68505b261ecSmrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 68605b261ecSmrg return; 68705b261ecSmrg } 68805b261ecSmrg 68905b261ecSmrg if (x1 < x2) { 69005b261ecSmrg prect[i].x = x1; 69105b261ecSmrg prect[i].width = x2 - x1 + 1; 69205b261ecSmrg } else { 69305b261ecSmrg prect[i].x = x2; 69405b261ecSmrg prect[i].width = x1 - x2 + 1; 69505b261ecSmrg } 69605b261ecSmrg if (y1 < y2) { 69705b261ecSmrg prect[i].y = y1; 69805b261ecSmrg prect[i].height = y2 - y1 + 1; 69905b261ecSmrg } else { 70005b261ecSmrg prect[i].y = y2; 70105b261ecSmrg prect[i].height = y1 - y2 + 1; 70205b261ecSmrg } 70305b261ecSmrg 70405b261ecSmrg x1 = x2; 70505b261ecSmrg y1 = y2; 70605b261ecSmrg } 70705b261ecSmrg pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); 7084202a189Smrg free(prect); 70905b261ecSmrg} 71005b261ecSmrg 71105b261ecSmrg/** 71205b261ecSmrg * exaPolySegment() checks if it can accelerate the lines as a group of 71305b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill 71405b261ecSmrg * acceleration if so. 71505b261ecSmrg */ 71605b261ecSmrgstatic void 71705b261ecSmrgexaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, 71805b261ecSmrg xSegment *pSeg) 71905b261ecSmrg{ 7204202a189Smrg ExaScreenPriv (pDrawable->pScreen); 72105b261ecSmrg xRectangle *prect; 72205b261ecSmrg int i; 72305b261ecSmrg 72405b261ecSmrg /* Don't try to do wide lines or non-solid fill style. */ 7254202a189Smrg if (pExaScr->fallback_counter || pGC->lineWidth != 0 || 7264202a189Smrg pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) 72705b261ecSmrg { 72805b261ecSmrg ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 72905b261ecSmrg return; 73005b261ecSmrg } 73105b261ecSmrg 73205b261ecSmrg /* If we have any non-horizontal/vertical, fall back. */ 73305b261ecSmrg for (i = 0; i < nseg; i++) { 73405b261ecSmrg if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { 73505b261ecSmrg ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 73605b261ecSmrg return; 73705b261ecSmrg } 73805b261ecSmrg } 73905b261ecSmrg 7404202a189Smrg prect = malloc(sizeof(xRectangle) * nseg); 74105b261ecSmrg for (i = 0; i < nseg; i++) { 74205b261ecSmrg if (pSeg[i].x1 < pSeg[i].x2) { 74305b261ecSmrg prect[i].x = pSeg[i].x1; 74405b261ecSmrg prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; 74505b261ecSmrg } else { 74605b261ecSmrg prect[i].x = pSeg[i].x2; 74705b261ecSmrg prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; 74805b261ecSmrg } 74905b261ecSmrg if (pSeg[i].y1 < pSeg[i].y2) { 75005b261ecSmrg prect[i].y = pSeg[i].y1; 75105b261ecSmrg prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; 75205b261ecSmrg } else { 75305b261ecSmrg prect[i].y = pSeg[i].y2; 75405b261ecSmrg prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; 75505b261ecSmrg } 7564642e01fSmrg 7574642e01fSmrg /* don't paint last pixel */ 7584642e01fSmrg if (pGC->capStyle == CapNotLast) { 7594642e01fSmrg if (prect[i].width == 1) 7604642e01fSmrg prect[i].height--; 7614642e01fSmrg else 7624642e01fSmrg prect[i].width--; 7634642e01fSmrg } 76405b261ecSmrg } 76505b261ecSmrg pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); 7664202a189Smrg free(prect); 76705b261ecSmrg} 76805b261ecSmrg 76905b261ecSmrgstatic Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, 77052397711Smrg Pixel pixel, CARD32 planemask, CARD32 alu, 77152397711Smrg unsigned int clientClipType); 77205b261ecSmrg 77305b261ecSmrgstatic void 77405b261ecSmrgexaPolyFillRect(DrawablePtr pDrawable, 77505b261ecSmrg GCPtr pGC, 77605b261ecSmrg int nrect, 77705b261ecSmrg xRectangle *prect) 77805b261ecSmrg{ 77905b261ecSmrg ExaScreenPriv (pDrawable->pScreen); 78005b261ecSmrg RegionPtr pClip = fbGetCompositeClip(pGC); 78105b261ecSmrg PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); 7824642e01fSmrg ExaPixmapPriv (pPixmap); 78305b261ecSmrg register BoxPtr pbox; 78405b261ecSmrg BoxPtr pextent; 78505b261ecSmrg int extentX1, extentX2, extentY1, extentY2; 78605b261ecSmrg int fullX1, fullX2, fullY1, fullY2; 78705b261ecSmrg int partX1, partX2, partY1, partY2; 78805b261ecSmrg int xoff, yoff; 78905b261ecSmrg int xorg, yorg; 79005b261ecSmrg int n; 7914202a189Smrg RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED); 79205b261ecSmrg 79305b261ecSmrg /* Compute intersection of rects and clip region */ 7944202a189Smrg RegionTranslate(pReg, pDrawable->x, pDrawable->y); 7954202a189Smrg RegionIntersect(pReg, pClip, pReg); 79605b261ecSmrg 7974202a189Smrg if (!RegionNumRects(pReg)) { 79805b261ecSmrg goto out; 79905b261ecSmrg } 80005b261ecSmrg 80105b261ecSmrg exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 80205b261ecSmrg 8034202a189Smrg if (pExaScr->fallback_counter || pExaScr->swappedOut || 8044202a189Smrg pExaPixmap->accel_blocked) 80505b261ecSmrg { 80605b261ecSmrg goto fallback; 80705b261ecSmrg } 80805b261ecSmrg 80905b261ecSmrg /* For ROPs where overlaps don't matter, convert rectangles to region and 81005b261ecSmrg * call exaFillRegion{Solid,Tiled}. 81105b261ecSmrg */ 81205b261ecSmrg if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && 8134642e01fSmrg (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || 8144642e01fSmrg pGC->alu == GXnoop || pGC->alu == GXcopyInverted || 8154642e01fSmrg pGC->alu == GXset)) { 81605b261ecSmrg if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && 81705b261ecSmrg exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? 81805b261ecSmrg pGC->fgPixel : pGC->tile.pixel, pGC->planemask, 81952397711Smrg pGC->alu, pGC->clientClipType)) || 82005b261ecSmrg (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && 82105b261ecSmrg exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, 82252397711Smrg pGC->planemask, pGC->alu, 82352397711Smrg pGC->clientClipType))) { 82405b261ecSmrg goto out; 82505b261ecSmrg } 82605b261ecSmrg } 82705b261ecSmrg 82805b261ecSmrg if (pGC->fillStyle != FillSolid && 82905b261ecSmrg !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) 83005b261ecSmrg { 83105b261ecSmrg goto fallback; 83205b261ecSmrg } 83305b261ecSmrg 8344202a189Smrg if (pExaScr->do_migration) { 8354202a189Smrg ExaMigrationRec pixmaps[1]; 8364202a189Smrg 8374202a189Smrg pixmaps[0].as_dst = TRUE; 8384202a189Smrg pixmaps[0].as_src = FALSE; 8394202a189Smrg pixmaps[0].pPix = pPixmap; 8404202a189Smrg pixmaps[0].pReg = NULL; 84105b261ecSmrg 8424202a189Smrg exaDoMigration (pixmaps, 1, TRUE); 8434202a189Smrg } 8444202a189Smrg 8454202a189Smrg if (!exaPixmapHasGpuCopy (pPixmap) || 84605b261ecSmrg !(*pExaScr->info->PrepareSolid) (pPixmap, 84705b261ecSmrg pGC->alu, 84805b261ecSmrg pGC->planemask, 84905b261ecSmrg pGC->fgPixel)) 85005b261ecSmrg { 85105b261ecSmrgfallback: 85205b261ecSmrg ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); 85305b261ecSmrg goto out; 85405b261ecSmrg } 85505b261ecSmrg 85605b261ecSmrg xorg = pDrawable->x; 85705b261ecSmrg yorg = pDrawable->y; 85805b261ecSmrg 8594202a189Smrg pextent = RegionExtents(pClip); 86005b261ecSmrg extentX1 = pextent->x1; 86105b261ecSmrg extentY1 = pextent->y1; 86205b261ecSmrg extentX2 = pextent->x2; 86305b261ecSmrg extentY2 = pextent->y2; 86405b261ecSmrg while (nrect--) 86505b261ecSmrg { 86605b261ecSmrg fullX1 = prect->x + xorg; 86705b261ecSmrg fullY1 = prect->y + yorg; 86805b261ecSmrg fullX2 = fullX1 + (int) prect->width; 86905b261ecSmrg fullY2 = fullY1 + (int) prect->height; 87005b261ecSmrg prect++; 87105b261ecSmrg 87205b261ecSmrg if (fullX1 < extentX1) 87305b261ecSmrg fullX1 = extentX1; 87405b261ecSmrg 87505b261ecSmrg if (fullY1 < extentY1) 87605b261ecSmrg fullY1 = extentY1; 87705b261ecSmrg 87805b261ecSmrg if (fullX2 > extentX2) 87905b261ecSmrg fullX2 = extentX2; 88005b261ecSmrg 88105b261ecSmrg if (fullY2 > extentY2) 88205b261ecSmrg fullY2 = extentY2; 88305b261ecSmrg 88405b261ecSmrg if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) 88505b261ecSmrg continue; 8864202a189Smrg n = RegionNumRects (pClip); 88705b261ecSmrg if (n == 1) 88805b261ecSmrg { 88905b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 89005b261ecSmrg fullX1 + xoff, fullY1 + yoff, 89105b261ecSmrg fullX2 + xoff, fullY2 + yoff); 89205b261ecSmrg } 89305b261ecSmrg else 89405b261ecSmrg { 8954202a189Smrg pbox = RegionRects(pClip); 89605b261ecSmrg /* 89705b261ecSmrg * clip the rectangle to each box in the clip region 89805b261ecSmrg * this is logically equivalent to calling Intersect(), 89905b261ecSmrg * but rectangles may overlap each other here. 90005b261ecSmrg */ 90105b261ecSmrg while(n--) 90205b261ecSmrg { 90305b261ecSmrg partX1 = pbox->x1; 90405b261ecSmrg if (partX1 < fullX1) 90505b261ecSmrg partX1 = fullX1; 90605b261ecSmrg partY1 = pbox->y1; 90705b261ecSmrg if (partY1 < fullY1) 90805b261ecSmrg partY1 = fullY1; 90905b261ecSmrg partX2 = pbox->x2; 91005b261ecSmrg if (partX2 > fullX2) 91105b261ecSmrg partX2 = fullX2; 91205b261ecSmrg partY2 = pbox->y2; 91305b261ecSmrg if (partY2 > fullY2) 91405b261ecSmrg partY2 = fullY2; 91505b261ecSmrg 91605b261ecSmrg pbox++; 91705b261ecSmrg 91805b261ecSmrg if (partX1 < partX2 && partY1 < partY2) { 91905b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 92005b261ecSmrg partX1 + xoff, partY1 + yoff, 92105b261ecSmrg partX2 + xoff, partY2 + yoff); 92205b261ecSmrg } 92305b261ecSmrg } 92405b261ecSmrg } 92505b261ecSmrg } 92605b261ecSmrg (*pExaScr->info->DoneSolid) (pPixmap); 92705b261ecSmrg exaMarkSync(pDrawable->pScreen); 92805b261ecSmrg 92905b261ecSmrgout: 9304202a189Smrg RegionUninit(pReg); 9314202a189Smrg RegionDestroy(pReg); 93205b261ecSmrg} 93305b261ecSmrg 93405b261ecSmrgconst GCOps exaOps = { 93505b261ecSmrg exaFillSpans, 93605b261ecSmrg ExaCheckSetSpans, 93705b261ecSmrg exaPutImage, 93805b261ecSmrg exaCopyArea, 93905b261ecSmrg ExaCheckCopyPlane, 94005b261ecSmrg exaPolyPoint, 94105b261ecSmrg exaPolylines, 94205b261ecSmrg exaPolySegment, 94305b261ecSmrg miPolyRectangle, 94405b261ecSmrg ExaCheckPolyArc, 94505b261ecSmrg miFillPolygon, 94605b261ecSmrg exaPolyFillRect, 94705b261ecSmrg miPolyFillArc, 94805b261ecSmrg miPolyText8, 94905b261ecSmrg miPolyText16, 95005b261ecSmrg miImageText8, 95105b261ecSmrg miImageText16, 9524642e01fSmrg ExaCheckImageGlyphBlt, 95305b261ecSmrg ExaCheckPolyGlyphBlt, 95405b261ecSmrg ExaCheckPushPixels, 95505b261ecSmrg}; 95605b261ecSmrg 95705b261ecSmrgvoid 95805b261ecSmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 95905b261ecSmrg{ 96005b261ecSmrg RegionRec rgnDst; 96105b261ecSmrg int dx, dy; 96205b261ecSmrg PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); 9634202a189Smrg ExaScreenPriv(pWin->drawable.pScreen); 96405b261ecSmrg 96505b261ecSmrg dx = ptOldOrg.x - pWin->drawable.x; 96605b261ecSmrg dy = ptOldOrg.y - pWin->drawable.y; 9674202a189Smrg RegionTranslate(prgnSrc, -dx, -dy); 96805b261ecSmrg 9694202a189Smrg RegionInit(&rgnDst, NullBox, 0); 97005b261ecSmrg 9714202a189Smrg RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc); 97205b261ecSmrg#ifdef COMPOSITE 97305b261ecSmrg if (pPixmap->screen_x || pPixmap->screen_y) 9744202a189Smrg RegionTranslate(&rgnDst, 97505b261ecSmrg -pPixmap->screen_x, -pPixmap->screen_y); 97605b261ecSmrg#endif 97705b261ecSmrg 9784202a189Smrg if (pExaScr->fallback_counter) { 9794202a189Smrg pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; 9804202a189Smrg goto fallback; 9814202a189Smrg } 9824202a189Smrg 9834202a189Smrg pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW; 9844202a189Smrg miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, 98505b261ecSmrg NULL, 98605b261ecSmrg &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); 9874202a189Smrg pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW; 98805b261ecSmrg 9894202a189Smrgfallback: 9904202a189Smrg RegionUninit(&rgnDst); 9914202a189Smrg 9924202a189Smrg if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) { 9934202a189Smrg pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW; 9944202a189Smrg RegionTranslate(prgnSrc, dx, dy); 9954202a189Smrg ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc); 9964202a189Smrg } 99705b261ecSmrg} 99805b261ecSmrg 99905b261ecSmrgstatic Bool 100052397711SmrgexaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, 100152397711Smrg CARD32 planemask, CARD32 alu, unsigned int clientClipType) 100205b261ecSmrg{ 100305b261ecSmrg ExaScreenPriv(pDrawable->pScreen); 10044642e01fSmrg PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); 10054642e01fSmrg ExaPixmapPriv (pPixmap); 100605b261ecSmrg int xoff, yoff; 10074642e01fSmrg Bool ret = FALSE; 100805b261ecSmrg 10094642e01fSmrg exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 10104202a189Smrg RegionTranslate(pRegion, xoff, yoff); 10114642e01fSmrg 10124202a189Smrg if (pExaScr->fallback_counter || pExaPixmap->accel_blocked) 10134642e01fSmrg goto out; 10144202a189Smrg 10154202a189Smrg if (pExaScr->do_migration) { 10164202a189Smrg ExaMigrationRec pixmaps[1]; 10174202a189Smrg 10184202a189Smrg pixmaps[0].as_dst = TRUE; 10194202a189Smrg pixmaps[0].as_src = FALSE; 10204202a189Smrg pixmaps[0].pPix = pPixmap; 10214202a189Smrg pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, 10224202a189Smrg alu, clientClipType) ? NULL : pRegion; 10234202a189Smrg 102405b261ecSmrg exaDoMigration (pixmaps, 1, TRUE); 102505b261ecSmrg } 102605b261ecSmrg 10274202a189Smrg if (exaPixmapHasGpuCopy (pPixmap) && 102805b261ecSmrg (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) 102905b261ecSmrg { 10304642e01fSmrg int nbox; 10314642e01fSmrg BoxPtr pBox; 10324642e01fSmrg 10334202a189Smrg nbox = RegionNumRects (pRegion); 10344202a189Smrg pBox = RegionRects (pRegion); 10354642e01fSmrg 103605b261ecSmrg while (nbox--) 103705b261ecSmrg { 10384642e01fSmrg (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, 10394642e01fSmrg pBox->y2); 104005b261ecSmrg pBox++; 104105b261ecSmrg } 104205b261ecSmrg (*pExaScr->info->DoneSolid) (pPixmap); 104305b261ecSmrg exaMarkSync(pDrawable->pScreen); 10444642e01fSmrg 10454202a189Smrg if (pExaPixmap->pDamage && 10464202a189Smrg pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP && 10474642e01fSmrg pDrawable->width == 1 && pDrawable->height == 1 && 10484642e01fSmrg pDrawable->bitsPerPixel != 24) { 10494642e01fSmrg ExaPixmapPriv(pPixmap); 10504202a189Smrg RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); 10514642e01fSmrg 10524642e01fSmrg switch (pDrawable->bitsPerPixel) { 10534642e01fSmrg case 32: 10544642e01fSmrg *(CARD32*)pExaPixmap->sys_ptr = pixel; 10554642e01fSmrg break; 10564642e01fSmrg case 16: 10574642e01fSmrg *(CARD16*)pExaPixmap->sys_ptr = pixel; 10584642e01fSmrg break; 10594642e01fSmrg case 8: 10604642e01fSmrg *(CARD8*)pExaPixmap->sys_ptr = pixel; 10614642e01fSmrg } 10624642e01fSmrg 10634202a189Smrg RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, 10644202a189Smrg pRegion); 10654202a189Smrg RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, 10664642e01fSmrg pRegion); 10674202a189Smrg RegionSubtract(pending_damage, pending_damage, pRegion); 10684642e01fSmrg } 10694642e01fSmrg 10704642e01fSmrg ret = TRUE; 107105b261ecSmrg } 107205b261ecSmrg 10734642e01fSmrgout: 10744202a189Smrg RegionTranslate(pRegion, -xoff, -yoff); 10754642e01fSmrg 10764642e01fSmrg return ret; 107705b261ecSmrg} 107805b261ecSmrg 107905b261ecSmrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. 108005b261ecSmrg * Based on fbFillRegionTiled(), fbTile(). 108105b261ecSmrg */ 108205b261ecSmrgBool 108352397711SmrgexaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, 108452397711Smrg DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, 108552397711Smrg unsigned int clientClipType) 108605b261ecSmrg{ 108705b261ecSmrg ExaScreenPriv(pDrawable->pScreen); 108805b261ecSmrg PixmapPtr pPixmap; 10894642e01fSmrg ExaPixmapPrivPtr pExaPixmap; 10904642e01fSmrg ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); 10914642e01fSmrg int xoff, yoff; 109205b261ecSmrg int tileWidth, tileHeight; 10934202a189Smrg int nbox = RegionNumRects (pRegion); 10944202a189Smrg BoxPtr pBox = RegionRects (pRegion); 10954642e01fSmrg Bool ret = FALSE; 10964642e01fSmrg int i; 109705b261ecSmrg 109805b261ecSmrg tileWidth = pTile->drawable.width; 109905b261ecSmrg tileHeight = pTile->drawable.height; 110005b261ecSmrg 110105b261ecSmrg /* If we're filling with a solid color, grab it out and go to 110205b261ecSmrg * FillRegionSolid, saving numerous copies. 110305b261ecSmrg */ 110405b261ecSmrg if (tileWidth == 1 && tileHeight == 1) 110505b261ecSmrg return exaFillRegionSolid(pDrawable, pRegion, 110605b261ecSmrg exaGetPixmapFirstPixel (pTile), planemask, 110752397711Smrg alu, clientClipType); 110805b261ecSmrg 11094202a189Smrg pPixmap = exaGetDrawablePixmap (pDrawable); 11104642e01fSmrg pExaPixmap = ExaGetPixmapPriv (pPixmap); 11114642e01fSmrg 11124202a189Smrg if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || 11134202a189Smrg pTileExaPixmap->accel_blocked) 11144642e01fSmrg return FALSE; 11154202a189Smrg 11164202a189Smrg if (pExaScr->do_migration) { 11174202a189Smrg ExaMigrationRec pixmaps[2]; 11184202a189Smrg 11194202a189Smrg pixmaps[0].as_dst = TRUE; 11204202a189Smrg pixmaps[0].as_src = FALSE; 11214202a189Smrg pixmaps[0].pPix = pPixmap; 11224202a189Smrg pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, 11234202a189Smrg alu, clientClipType) ? NULL : pRegion; 11244202a189Smrg pixmaps[1].as_dst = FALSE; 11254202a189Smrg pixmaps[1].as_src = TRUE; 11264202a189Smrg pixmaps[1].pPix = pTile; 11274202a189Smrg pixmaps[1].pReg = NULL; 11284202a189Smrg 112905b261ecSmrg exaDoMigration (pixmaps, 2, TRUE); 113005b261ecSmrg } 113105b261ecSmrg 113205b261ecSmrg pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 113305b261ecSmrg 11344202a189Smrg if (!pPixmap || !exaPixmapHasGpuCopy(pTile)) 11354642e01fSmrg return FALSE; 113605b261ecSmrg 11374642e01fSmrg if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) 113805b261ecSmrg { 11394642e01fSmrg if (xoff || yoff) 11404202a189Smrg RegionTranslate(pRegion, xoff, yoff); 11414642e01fSmrg 11424642e01fSmrg for (i = 0; i < nbox; i++) 114305b261ecSmrg { 11444642e01fSmrg int height = pBox[i].y2 - pBox[i].y1; 11454642e01fSmrg int dstY = pBox[i].y1; 114605b261ecSmrg int tileY; 114705b261ecSmrg 11484642e01fSmrg if (alu == GXcopy) 11494642e01fSmrg height = min(height, tileHeight); 11504642e01fSmrg 11514642e01fSmrg modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); 115205b261ecSmrg 115305b261ecSmrg while (height > 0) { 11544642e01fSmrg int width = pBox[i].x2 - pBox[i].x1; 11554642e01fSmrg int dstX = pBox[i].x1; 115605b261ecSmrg int tileX; 115705b261ecSmrg int h = tileHeight - tileY; 115805b261ecSmrg 11594642e01fSmrg if (alu == GXcopy) 11604642e01fSmrg width = min(width, tileWidth); 11614642e01fSmrg 116205b261ecSmrg if (h > height) 116305b261ecSmrg h = height; 116405b261ecSmrg height -= h; 116505b261ecSmrg 11664642e01fSmrg modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, 11674642e01fSmrg tileX); 116805b261ecSmrg 116905b261ecSmrg while (width > 0) { 117005b261ecSmrg int w = tileWidth - tileX; 117105b261ecSmrg if (w > width) 117205b261ecSmrg w = width; 117305b261ecSmrg width -= w; 117405b261ecSmrg 11754642e01fSmrg (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, 117605b261ecSmrg w, h); 117705b261ecSmrg dstX += w; 117805b261ecSmrg tileX = 0; 117905b261ecSmrg } 118005b261ecSmrg dstY += h; 118105b261ecSmrg tileY = 0; 118205b261ecSmrg } 118305b261ecSmrg } 118405b261ecSmrg (*pExaScr->info->DoneCopy) (pPixmap); 118505b261ecSmrg 11864642e01fSmrg /* With GXcopy, we only need to do the basic algorithm up to the tile 11874642e01fSmrg * size; then, we can just keep doubling the destination in each 11884642e01fSmrg * direction until it fills the box. This way, the number of copy 11894642e01fSmrg * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where 11904642e01fSmrg * rx/ry is the ratio between box and tile width/height. This can make 11914642e01fSmrg * a big difference if each driver copy incurs a significant constant 11924642e01fSmrg * overhead. 11934642e01fSmrg */ 11944642e01fSmrg if (alu != GXcopy) 11954642e01fSmrg ret = TRUE; 11964642e01fSmrg else { 11974642e01fSmrg Bool more_copy = FALSE; 11984642e01fSmrg 11994642e01fSmrg for (i = 0; i < nbox; i++) { 12004642e01fSmrg int dstX = pBox[i].x1 + tileWidth; 12014642e01fSmrg int dstY = pBox[i].y1 + tileHeight; 12024642e01fSmrg 12034642e01fSmrg if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { 12044642e01fSmrg more_copy = TRUE; 12054642e01fSmrg break; 12064642e01fSmrg } 12074642e01fSmrg } 120805b261ecSmrg 12094642e01fSmrg if (more_copy == FALSE) 12104642e01fSmrg ret = TRUE; 121105b261ecSmrg 12124642e01fSmrg if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, 12134642e01fSmrg 1, 1, alu, planemask)) { 12144642e01fSmrg for (i = 0; i < nbox; i++) 12154642e01fSmrg { 12164642e01fSmrg int dstX = pBox[i].x1 + tileWidth; 12174642e01fSmrg int dstY = pBox[i].y1 + tileHeight; 12184642e01fSmrg int width = min(pBox[i].x2 - dstX, tileWidth); 12194642e01fSmrg int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); 12204642e01fSmrg 12214642e01fSmrg while (dstX < pBox[i].x2) { 12224642e01fSmrg (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 12234642e01fSmrg dstX, pBox[i].y1, width, height); 12244642e01fSmrg dstX += width; 12254642e01fSmrg width = min(pBox[i].x2 - dstX, width * 2); 12264642e01fSmrg } 122705b261ecSmrg 12284642e01fSmrg width = pBox[i].x2 - pBox[i].x1; 12294642e01fSmrg height = min(pBox[i].y2 - dstY, tileHeight); 123005b261ecSmrg 12314642e01fSmrg while (dstY < pBox[i].y2) { 12324642e01fSmrg (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 12334642e01fSmrg pBox[i].x1, dstY, width, height); 12344642e01fSmrg dstY += height; 12354642e01fSmrg height = min(pBox[i].y2 - dstY, height * 2); 12364642e01fSmrg } 12374642e01fSmrg } 123805b261ecSmrg 12394642e01fSmrg (*pExaScr->info->DoneCopy) (pPixmap); 12404642e01fSmrg 12414642e01fSmrg ret = TRUE; 12424642e01fSmrg } 12434642e01fSmrg } 124405b261ecSmrg 12454642e01fSmrg exaMarkSync(pDrawable->pScreen); 124605b261ecSmrg 12474642e01fSmrg if (xoff || yoff) 12484202a189Smrg RegionTranslate(pRegion, -xoff, -yoff); 124905b261ecSmrg } 12504642e01fSmrg 12514642e01fSmrg return ret; 125205b261ecSmrg} 125305b261ecSmrg 12544642e01fSmrg 125505b261ecSmrg/** 125605b261ecSmrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. 125705b261ecSmrg * 125805b261ecSmrg * This is probably the only case we actually care about. The rest fall through 12594642e01fSmrg * to migration and fbGetImage, which hopefully will result in migration pushing 12604642e01fSmrg * the pixmap out of framebuffer. 126105b261ecSmrg */ 126205b261ecSmrgvoid 126305b261ecSmrgexaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, 126405b261ecSmrg unsigned int format, unsigned long planeMask, char *d) 126505b261ecSmrg{ 126605b261ecSmrg ExaScreenPriv (pDrawable->pScreen); 12674202a189Smrg PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); 12684202a189Smrg ExaPixmapPriv(pPix); 126905b261ecSmrg int xoff, yoff; 127005b261ecSmrg Bool ok; 127105b261ecSmrg 12724202a189Smrg if (pExaScr->fallback_counter || pExaScr->swappedOut) 127305b261ecSmrg goto fallback; 127405b261ecSmrg 12754202a189Smrg /* If there's a system copy, we want to save the result there */ 12764202a189Smrg if (pExaPixmap->pDamage) 12774202a189Smrg goto fallback; 12784642e01fSmrg 12794642e01fSmrg pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 12804642e01fSmrg 12814642e01fSmrg if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) 12824642e01fSmrg goto fallback; 128305b261ecSmrg 128405b261ecSmrg /* Only cover the ZPixmap, solid copy case. */ 128505b261ecSmrg if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) 12864642e01fSmrg goto fallback; 128705b261ecSmrg 128805b261ecSmrg /* Only try to handle the 8bpp and up cases, since we don't want to think 128905b261ecSmrg * about <8bpp. 129005b261ecSmrg */ 129105b261ecSmrg if (pDrawable->bitsPerPixel < 8) 129205b261ecSmrg goto fallback; 129305b261ecSmrg 12944642e01fSmrg ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, 12954642e01fSmrg pDrawable->y + y + yoff, w, h, d, 129605b261ecSmrg PixmapBytePad(w, pDrawable->depth)); 129705b261ecSmrg if (ok) { 129805b261ecSmrg exaWaitSync(pDrawable->pScreen); 12994202a189Smrg return; 130005b261ecSmrg } 130105b261ecSmrg 130205b261ecSmrgfallback: 13034202a189Smrg ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); 130405b261ecSmrg} 1305