exa_accel.c revision 52397711
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 ExaMigrationRec pixmaps[1]; 5405b261ecSmrg 5505b261ecSmrg pixmaps[0].as_dst = TRUE; 5605b261ecSmrg pixmaps[0].as_src = FALSE; 574642e01fSmrg pixmaps[0].pPix = pPixmap; 584642e01fSmrg pixmaps[0].pReg = NULL; 5905b261ecSmrg 6005b261ecSmrg if (pExaScr->swappedOut || 6105b261ecSmrg pGC->fillStyle != FillSolid || 624642e01fSmrg pExaPixmap->accel_blocked) 6305b261ecSmrg { 6405b261ecSmrg ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); 6505b261ecSmrg return; 6605b261ecSmrg } else { 6705b261ecSmrg exaDoMigration (pixmaps, 1, TRUE); 6805b261ecSmrg } 6905b261ecSmrg 7005b261ecSmrg if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) || 7105b261ecSmrg !(*pExaScr->info->PrepareSolid) (pPixmap, 7205b261ecSmrg pGC->alu, 7305b261ecSmrg pGC->planemask, 7405b261ecSmrg pGC->fgPixel)) 7505b261ecSmrg { 7605b261ecSmrg ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); 7705b261ecSmrg return; 7805b261ecSmrg } 7905b261ecSmrg 8005b261ecSmrg pextent = REGION_EXTENTS(pGC->pScreen, pClip); 8105b261ecSmrg extentX1 = pextent->x1; 8205b261ecSmrg extentY1 = pextent->y1; 8305b261ecSmrg extentX2 = pextent->x2; 8405b261ecSmrg extentY2 = pextent->y2; 8505b261ecSmrg while (n--) 8605b261ecSmrg { 8705b261ecSmrg fullX1 = ppt->x; 8805b261ecSmrg fullY1 = ppt->y; 8905b261ecSmrg fullX2 = fullX1 + (int) *pwidth; 9005b261ecSmrg ppt++; 9105b261ecSmrg pwidth++; 9205b261ecSmrg 9305b261ecSmrg if (fullY1 < extentY1 || extentY2 <= fullY1) 9405b261ecSmrg continue; 9505b261ecSmrg 9605b261ecSmrg if (fullX1 < extentX1) 9705b261ecSmrg fullX1 = extentX1; 9805b261ecSmrg 9905b261ecSmrg if (fullX2 > extentX2) 10005b261ecSmrg fullX2 = extentX2; 10105b261ecSmrg 10205b261ecSmrg if (fullX1 >= fullX2) 10305b261ecSmrg continue; 10405b261ecSmrg 10505b261ecSmrg nbox = REGION_NUM_RECTS (pClip); 10605b261ecSmrg if (nbox == 1) 10705b261ecSmrg { 10805b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 10905b261ecSmrg fullX1 + off_x, fullY1 + off_y, 11005b261ecSmrg fullX2 + off_x, fullY1 + 1 + off_y); 11105b261ecSmrg } 11205b261ecSmrg else 11305b261ecSmrg { 11405b261ecSmrg pbox = REGION_RECTS(pClip); 11505b261ecSmrg while(nbox--) 11605b261ecSmrg { 11705b261ecSmrg if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) 11805b261ecSmrg { 11905b261ecSmrg partX1 = pbox->x1; 12005b261ecSmrg if (partX1 < fullX1) 12105b261ecSmrg partX1 = fullX1; 12205b261ecSmrg partX2 = pbox->x2; 12305b261ecSmrg if (partX2 > fullX2) 12405b261ecSmrg partX2 = fullX2; 12505b261ecSmrg if (partX2 > partX1) { 12605b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 12705b261ecSmrg partX1 + off_x, fullY1 + off_y, 12805b261ecSmrg partX2 + off_x, fullY1 + 1 + off_y); 12905b261ecSmrg } 13005b261ecSmrg } 13105b261ecSmrg pbox++; 13205b261ecSmrg } 13305b261ecSmrg } 13405b261ecSmrg } 13505b261ecSmrg (*pExaScr->info->DoneSolid) (pPixmap); 13605b261ecSmrg exaMarkSync(pScreen); 13705b261ecSmrg} 13805b261ecSmrg 1394642e01fSmrgstatic Bool 1404642e01fSmrgexaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, 1414642e01fSmrg int w, int h, int format, char *bits, int src_stride) 14205b261ecSmrg{ 14305b261ecSmrg ExaScreenPriv (pDrawable->pScreen); 1444642e01fSmrg PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); 1454642e01fSmrg ExaPixmapPriv(pPix); 14605b261ecSmrg RegionPtr pClip; 14705b261ecSmrg BoxPtr pbox; 14805b261ecSmrg int nbox; 14905b261ecSmrg int xoff, yoff; 1504642e01fSmrg int bpp = pDrawable->bitsPerPixel; 1514642e01fSmrg Bool access_prepared = FALSE; 15205b261ecSmrg 1534642e01fSmrg if (pExaPixmap->accel_blocked) 1544642e01fSmrg return FALSE; 15505b261ecSmrg 15605b261ecSmrg /* Don't bother with under 8bpp, XYPixmaps. */ 15705b261ecSmrg if (format != ZPixmap || bpp < 8) 1584642e01fSmrg return FALSE; 15905b261ecSmrg 16005b261ecSmrg /* Only accelerate copies: no rop or planemask. */ 16105b261ecSmrg if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) 1624642e01fSmrg return FALSE; 16305b261ecSmrg 16405b261ecSmrg if (pExaScr->swappedOut) 1654642e01fSmrg return FALSE; 16605b261ecSmrg 1674642e01fSmrg if (pExaPixmap->pDamage) { 1684642e01fSmrg ExaMigrationRec pixmaps[1]; 16905b261ecSmrg 1704642e01fSmrg pixmaps[0].as_dst = TRUE; 1714642e01fSmrg pixmaps[0].as_src = FALSE; 1724642e01fSmrg pixmaps[0].pPix = pPix; 1734642e01fSmrg pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); 1744642e01fSmrg 1754642e01fSmrg exaDoMigration (pixmaps, 1, TRUE); 1764642e01fSmrg } 17705b261ecSmrg 17805b261ecSmrg pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 17905b261ecSmrg 1804642e01fSmrg if (!pPix || !pExaScr->info->UploadToScreen) 1814642e01fSmrg return FALSE; 18205b261ecSmrg 18305b261ecSmrg x += pDrawable->x; 18405b261ecSmrg y += pDrawable->y; 18505b261ecSmrg 18605b261ecSmrg pClip = fbGetCompositeClip(pGC); 18705b261ecSmrg for (nbox = REGION_NUM_RECTS(pClip), 18805b261ecSmrg pbox = REGION_RECTS(pClip); 18905b261ecSmrg nbox--; 19005b261ecSmrg pbox++) 19105b261ecSmrg { 19205b261ecSmrg int x1 = x; 19305b261ecSmrg int y1 = y; 19405b261ecSmrg int x2 = x + w; 19505b261ecSmrg int y2 = y + h; 19605b261ecSmrg char *src; 19705b261ecSmrg Bool ok; 19805b261ecSmrg 19905b261ecSmrg if (x1 < pbox->x1) 20005b261ecSmrg x1 = pbox->x1; 20105b261ecSmrg if (y1 < pbox->y1) 20205b261ecSmrg y1 = pbox->y1; 20305b261ecSmrg if (x2 > pbox->x2) 20405b261ecSmrg x2 = pbox->x2; 20505b261ecSmrg if (y2 > pbox->y2) 20605b261ecSmrg y2 = pbox->y2; 20705b261ecSmrg if (x1 >= x2 || y1 >= y2) 20805b261ecSmrg continue; 20905b261ecSmrg 21005b261ecSmrg src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); 21105b261ecSmrg ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, 21205b261ecSmrg x2 - x1, y2 - y1, src, src_stride); 21305b261ecSmrg /* If we fail to accelerate the upload, fall back to using unaccelerated 21405b261ecSmrg * fb calls. 21505b261ecSmrg */ 21605b261ecSmrg if (!ok) { 21705b261ecSmrg FbStip *dst; 21805b261ecSmrg FbStride dst_stride; 21905b261ecSmrg int dstBpp; 22005b261ecSmrg int dstXoff, dstYoff; 22105b261ecSmrg 2224642e01fSmrg if (!access_prepared) { 2234642e01fSmrg ExaDoPrepareAccess(pDrawable, EXA_PREPARE_DEST); 2244642e01fSmrg 2254642e01fSmrg access_prepared = TRUE; 2264642e01fSmrg } 22705b261ecSmrg 22805b261ecSmrg fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp, 22905b261ecSmrg dstXoff, dstYoff); 23005b261ecSmrg 23105b261ecSmrg fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)), 23205b261ecSmrg src_stride / sizeof(FbStip), 23305b261ecSmrg (x1 - x) * dstBpp, 23405b261ecSmrg dst + (y1 + dstYoff) * dst_stride, 23505b261ecSmrg dst_stride, 23605b261ecSmrg (x1 + dstXoff) * dstBpp, 23705b261ecSmrg (x2 - x1) * dstBpp, 23805b261ecSmrg y2 - y1, 23905b261ecSmrg GXcopy, FB_ALLONES, dstBpp); 24005b261ecSmrg } 24105b261ecSmrg } 24205b261ecSmrg 2434642e01fSmrg if (access_prepared) 2444642e01fSmrg exaFinishAccess(pDrawable, EXA_PREPARE_DEST); 2454642e01fSmrg else 2464642e01fSmrg exaMarkSync(pDrawable->pScreen); 24705b261ecSmrg 2484642e01fSmrg return TRUE; 2494642e01fSmrg} 25005b261ecSmrg 2514642e01fSmrgstatic void 2524642e01fSmrgexaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, 2534642e01fSmrg int w, int h, int leftPad, int format, char *bits) 2544642e01fSmrg{ 2554642e01fSmrg if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits, 2564642e01fSmrg PixmapBytePad(w, pDrawable->depth))) 2574642e01fSmrg ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, 2584642e01fSmrg bits); 25905b261ecSmrg} 26005b261ecSmrg 26105b261ecSmrgstatic Bool inline 26205b261ecSmrgexaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, 26305b261ecSmrg GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) 26405b261ecSmrg{ 26505b261ecSmrg ExaScreenPriv (pDstDrawable->pScreen); 26605b261ecSmrg PixmapPtr pSrcPixmap, pDstPixmap; 26705b261ecSmrg int src_off_x, src_off_y, dst_off_x, dst_off_y; 26805b261ecSmrg int dirsetup; 26905b261ecSmrg 27005b261ecSmrg /* Need to get both pixmaps to call the driver routines */ 27105b261ecSmrg pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y); 27205b261ecSmrg pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y); 27305b261ecSmrg if (!pSrcPixmap || !pDstPixmap) 27405b261ecSmrg return FALSE; 27505b261ecSmrg 27605b261ecSmrg /* 27705b261ecSmrg * Now the case of a chip that only supports xdir = ydir = 1 or 27805b261ecSmrg * xdir = ydir = -1, but we have xdir != ydir. 27905b261ecSmrg */ 28005b261ecSmrg dirsetup = 0; /* No direction set up yet. */ 28105b261ecSmrg for (; nbox; pbox++, nbox--) { 28205b261ecSmrg if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 28305b261ecSmrg /* Do a xdir = ydir = -1 blit instead. */ 28405b261ecSmrg if (dirsetup != -1) { 28505b261ecSmrg if (dirsetup != 0) 28605b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 28705b261ecSmrg dirsetup = -1; 28805b261ecSmrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 28905b261ecSmrg pDstPixmap, 29005b261ecSmrg -1, -1, 29105b261ecSmrg pGC ? pGC->alu : GXcopy, 29205b261ecSmrg pGC ? pGC->planemask : 29305b261ecSmrg FB_ALLONES)) 29405b261ecSmrg return FALSE; 29505b261ecSmrg } 29605b261ecSmrg (*pExaScr->info->Copy)(pDstPixmap, 29705b261ecSmrg src_off_x + pbox->x1 + dx, 29805b261ecSmrg src_off_y + pbox->y1 + dy, 29905b261ecSmrg dst_off_x + pbox->x1, 30005b261ecSmrg dst_off_y + pbox->y1, 30105b261ecSmrg pbox->x2 - pbox->x1, 30205b261ecSmrg pbox->y2 - pbox->y1); 30305b261ecSmrg } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 30405b261ecSmrg /* Do a xdir = ydir = 1 blit instead. */ 30505b261ecSmrg if (dirsetup != 1) { 30605b261ecSmrg if (dirsetup != 0) 30705b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 30805b261ecSmrg dirsetup = 1; 30905b261ecSmrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 31005b261ecSmrg pDstPixmap, 31105b261ecSmrg 1, 1, 31205b261ecSmrg pGC ? pGC->alu : GXcopy, 31305b261ecSmrg pGC ? pGC->planemask : 31405b261ecSmrg FB_ALLONES)) 31505b261ecSmrg return FALSE; 31605b261ecSmrg } 31705b261ecSmrg (*pExaScr->info->Copy)(pDstPixmap, 31805b261ecSmrg src_off_x + pbox->x1 + dx, 31905b261ecSmrg src_off_y + pbox->y1 + dy, 32005b261ecSmrg dst_off_x + pbox->x1, 32105b261ecSmrg dst_off_y + pbox->y1, 32205b261ecSmrg pbox->x2 - pbox->x1, 32305b261ecSmrg pbox->y2 - pbox->y1); 32405b261ecSmrg } else if (dx >= 0) { 32505b261ecSmrg /* 32605b261ecSmrg * xdir = 1, ydir = -1. 32705b261ecSmrg * Perform line-by-line xdir = ydir = 1 blits, going up. 32805b261ecSmrg */ 32905b261ecSmrg int i; 33005b261ecSmrg if (dirsetup != 1) { 33105b261ecSmrg if (dirsetup != 0) 33205b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 33305b261ecSmrg dirsetup = 1; 33405b261ecSmrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 33505b261ecSmrg pDstPixmap, 33605b261ecSmrg 1, 1, 33705b261ecSmrg pGC ? pGC->alu : GXcopy, 33805b261ecSmrg pGC ? pGC->planemask : 33905b261ecSmrg FB_ALLONES)) 34005b261ecSmrg return FALSE; 34105b261ecSmrg } 34205b261ecSmrg for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) 34305b261ecSmrg (*pExaScr->info->Copy)(pDstPixmap, 34405b261ecSmrg src_off_x + pbox->x1 + dx, 34505b261ecSmrg src_off_y + pbox->y1 + dy + i, 34605b261ecSmrg dst_off_x + pbox->x1, 34705b261ecSmrg dst_off_y + pbox->y1 + i, 34805b261ecSmrg pbox->x2 - pbox->x1, 1); 34905b261ecSmrg } else { 35005b261ecSmrg /* 35105b261ecSmrg * xdir = -1, ydir = 1. 35205b261ecSmrg * Perform line-by-line xdir = ydir = -1 blits, going down. 35305b261ecSmrg */ 35405b261ecSmrg int i; 35505b261ecSmrg if (dirsetup != -1) { 35605b261ecSmrg if (dirsetup != 0) 35705b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 35805b261ecSmrg dirsetup = -1; 35905b261ecSmrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 36005b261ecSmrg pDstPixmap, 36105b261ecSmrg -1, -1, 36205b261ecSmrg pGC ? pGC->alu : GXcopy, 36305b261ecSmrg pGC ? pGC->planemask : 36405b261ecSmrg FB_ALLONES)) 36505b261ecSmrg return FALSE; 36605b261ecSmrg } 36705b261ecSmrg for (i = 0; i < pbox->y2 - pbox->y1; i++) 36805b261ecSmrg (*pExaScr->info->Copy)(pDstPixmap, 36905b261ecSmrg src_off_x + pbox->x1 + dx, 37005b261ecSmrg src_off_y + pbox->y1 + dy + i, 37105b261ecSmrg dst_off_x + pbox->x1, 37205b261ecSmrg dst_off_y + pbox->y1 + i, 37305b261ecSmrg pbox->x2 - pbox->x1, 1); 37405b261ecSmrg } 37505b261ecSmrg } 37605b261ecSmrg if (dirsetup != 0) 37705b261ecSmrg pExaScr->info->DoneCopy(pDstPixmap); 37805b261ecSmrg exaMarkSync(pDstDrawable->pScreen); 37905b261ecSmrg return TRUE; 38005b261ecSmrg} 38105b261ecSmrg 38205b261ecSmrgvoid 38305b261ecSmrgexaCopyNtoN (DrawablePtr pSrcDrawable, 38405b261ecSmrg DrawablePtr pDstDrawable, 38505b261ecSmrg GCPtr pGC, 38605b261ecSmrg BoxPtr pbox, 38705b261ecSmrg int nbox, 38805b261ecSmrg int dx, 38905b261ecSmrg int dy, 39005b261ecSmrg Bool reverse, 39105b261ecSmrg Bool upsidedown, 39205b261ecSmrg Pixel bitplane, 39305b261ecSmrg void *closure) 39405b261ecSmrg{ 39505b261ecSmrg ExaScreenPriv (pDstDrawable->pScreen); 39605b261ecSmrg PixmapPtr pSrcPixmap, pDstPixmap; 3974642e01fSmrg ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap; 39805b261ecSmrg int src_off_x, src_off_y; 39905b261ecSmrg int dst_off_x, dst_off_y; 40005b261ecSmrg ExaMigrationRec pixmaps[2]; 4014642e01fSmrg RegionPtr srcregion = NULL, dstregion = NULL; 4024642e01fSmrg xRectangle *rects; 4034642e01fSmrg 4044642e01fSmrg /* avoid doing copy operations if no boxes */ 4054642e01fSmrg if (nbox == 0) 4064642e01fSmrg return; 4074642e01fSmrg 4084642e01fSmrg pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); 4094642e01fSmrg pDstPixmap = exaGetDrawablePixmap (pDstDrawable); 4104642e01fSmrg 4114642e01fSmrg exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); 4124642e01fSmrg exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); 4134642e01fSmrg 4144642e01fSmrg rects = xalloc(nbox * sizeof(xRectangle)); 4154642e01fSmrg 4164642e01fSmrg if (rects) { 4174642e01fSmrg int i; 4184642e01fSmrg 4194642e01fSmrg for (i = 0; i < nbox; i++) { 4204642e01fSmrg rects[i].x = pbox[i].x1 + dx + src_off_x; 4214642e01fSmrg rects[i].y = pbox[i].y1 + dy + src_off_y; 4224642e01fSmrg rects[i].width = pbox[i].x2 - pbox[i].x1; 4234642e01fSmrg rects[i].height = pbox[i].y2 - pbox[i].y1; 4244642e01fSmrg } 4254642e01fSmrg 4264642e01fSmrg srcregion = RECTS_TO_REGION(pScreen, nbox, rects, CT_YXBANDED); 4274642e01fSmrg xfree(rects); 4284642e01fSmrg 4294642e01fSmrg if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, 43052397711Smrg pGC->fillStyle, pGC->alu, 43152397711Smrg pGC->clientClipType)) { 4324642e01fSmrg dstregion = REGION_CREATE(pScreen, NullBox, 0); 4334642e01fSmrg REGION_COPY(pScreen, dstregion, srcregion); 4344642e01fSmrg REGION_TRANSLATE(pScreen, dstregion, dst_off_x - dx - src_off_x, 4354642e01fSmrg dst_off_y - dy - src_off_y); 4364642e01fSmrg } 4374642e01fSmrg } 43805b261ecSmrg 43905b261ecSmrg pixmaps[0].as_dst = TRUE; 44005b261ecSmrg pixmaps[0].as_src = FALSE; 4414642e01fSmrg pixmaps[0].pPix = pDstPixmap; 4424642e01fSmrg pixmaps[0].pReg = dstregion; 44305b261ecSmrg pixmaps[1].as_dst = FALSE; 44405b261ecSmrg pixmaps[1].as_src = TRUE; 4454642e01fSmrg pixmaps[1].pPix = pSrcPixmap; 4464642e01fSmrg pixmaps[1].pReg = srcregion; 44705b261ecSmrg 4484642e01fSmrg pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap); 4494642e01fSmrg pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); 4504642e01fSmrg 4514642e01fSmrg /* Check whether the accelerator can use this pixmap. 4524642e01fSmrg * If the pitch of the pixmaps is out of range, there's nothing 4534642e01fSmrg * we can do but fall back to software rendering. 45405b261ecSmrg */ 4554642e01fSmrg if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || 4564642e01fSmrg pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) 4574642e01fSmrg goto fallback; 4584642e01fSmrg 4594642e01fSmrg /* If the width or the height of either of the pixmaps 4604642e01fSmrg * is out of range, check whether the boxes are actually out of the 4614642e01fSmrg * addressable range as well. If they aren't, we can still do 4624642e01fSmrg * the copying in hardware. 4634642e01fSmrg */ 4644642e01fSmrg if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { 4654642e01fSmrg int i; 4664642e01fSmrg 4674642e01fSmrg for (i = 0; i < nbox; i++) { 4684642e01fSmrg /* src */ 4694642e01fSmrg if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || 4704642e01fSmrg (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) 4714642e01fSmrg goto fallback; 4724642e01fSmrg 4734642e01fSmrg /* dst */ 4744642e01fSmrg if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || 4754642e01fSmrg (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) 4764642e01fSmrg goto fallback; 4774642e01fSmrg } 47805b261ecSmrg } 47905b261ecSmrg 4804642e01fSmrg exaDoMigration (pixmaps, 2, TRUE); 4814642e01fSmrg 48205b261ecSmrg /* Mixed directions must be handled specially if the card is lame */ 4834642e01fSmrg if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && 48405b261ecSmrg reverse != upsidedown) { 48505b261ecSmrg if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, 48605b261ecSmrg dx, dy)) 4874642e01fSmrg goto out; 4884642e01fSmrg goto fallback; 48905b261ecSmrg } 49005b261ecSmrg 4914642e01fSmrg if (!exaPixmapIsOffscreen(pSrcPixmap) || 49205b261ecSmrg !exaPixmapIsOffscreen(pDstPixmap) || 49305b261ecSmrg !(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, 49405b261ecSmrg upsidedown ? -1 : 1, 49505b261ecSmrg pGC ? pGC->alu : GXcopy, 49605b261ecSmrg pGC ? pGC->planemask : FB_ALLONES)) { 4974642e01fSmrg goto fallback; 49805b261ecSmrg } 49905b261ecSmrg 50005b261ecSmrg while (nbox--) 50105b261ecSmrg { 5024642e01fSmrg (*pExaScr->info->Copy) (pDstPixmap, 5034642e01fSmrg pbox->x1 + dx + src_off_x, 5044642e01fSmrg pbox->y1 + dy + src_off_y, 5054642e01fSmrg pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, 5064642e01fSmrg pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); 50705b261ecSmrg pbox++; 50805b261ecSmrg } 50905b261ecSmrg 51005b261ecSmrg (*pExaScr->info->DoneCopy) (pDstPixmap); 51105b261ecSmrg exaMarkSync (pDstDrawable->pScreen); 5124642e01fSmrg 5134642e01fSmrg goto out; 5144642e01fSmrg 5154642e01fSmrgfallback: 5164642e01fSmrg EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, 5174642e01fSmrg exaDrawableLocation(pSrcDrawable), 5184642e01fSmrg exaDrawableLocation(pDstDrawable))); 5194642e01fSmrg exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, dstregion); 5204642e01fSmrg exaPrepareAccessReg (pSrcDrawable, EXA_PREPARE_SRC, srcregion); 5214642e01fSmrg fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, 5224642e01fSmrg upsidedown, bitplane, closure); 5234642e01fSmrg exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC); 5244642e01fSmrg exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST); 5254642e01fSmrg 5264642e01fSmrgout: 5274642e01fSmrg if (dstregion) { 5284642e01fSmrg REGION_UNINIT(pScreen, dstregion); 5294642e01fSmrg REGION_DESTROY(pScreen, dstregion); 5304642e01fSmrg } 5314642e01fSmrg if (srcregion) { 5324642e01fSmrg REGION_UNINIT(pScreen, srcregion); 5334642e01fSmrg REGION_DESTROY(pScreen, srcregion); 5344642e01fSmrg } 53505b261ecSmrg} 53605b261ecSmrg 53705b261ecSmrgRegionPtr 53805b261ecSmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, 53905b261ecSmrg int srcx, int srcy, int width, int height, int dstx, int dsty) 54005b261ecSmrg{ 54105b261ecSmrg ExaScreenPriv (pDstDrawable->pScreen); 54205b261ecSmrg 54305b261ecSmrg if (pExaScr->swappedOut) { 54405b261ecSmrg return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, 54505b261ecSmrg srcx, srcy, width, height, dstx, dsty); 54605b261ecSmrg } 54705b261ecSmrg 54805b261ecSmrg return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, 54905b261ecSmrg srcx, srcy, width, height, 55005b261ecSmrg dstx, dsty, exaCopyNtoN, 0, NULL); 55105b261ecSmrg} 55205b261ecSmrg 55305b261ecSmrgstatic void 55405b261ecSmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 55505b261ecSmrg DDXPointPtr ppt) 55605b261ecSmrg{ 55705b261ecSmrg int i; 55805b261ecSmrg xRectangle *prect; 55905b261ecSmrg 56005b261ecSmrg /* If we can't reuse the current GC as is, don't bother accelerating the 56105b261ecSmrg * points. 56205b261ecSmrg */ 56305b261ecSmrg if (pGC->fillStyle != FillSolid) { 56405b261ecSmrg ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); 56505b261ecSmrg return; 56605b261ecSmrg } 56705b261ecSmrg 5684642e01fSmrg prect = xalloc(sizeof(xRectangle) * npt); 56905b261ecSmrg for (i = 0; i < npt; i++) { 57005b261ecSmrg prect[i].x = ppt[i].x; 57105b261ecSmrg prect[i].y = ppt[i].y; 57205b261ecSmrg if (i > 0 && mode == CoordModePrevious) { 57305b261ecSmrg prect[i].x += prect[i - 1].x; 57405b261ecSmrg prect[i].y += prect[i - 1].y; 57505b261ecSmrg } 57605b261ecSmrg prect[i].width = 1; 57705b261ecSmrg prect[i].height = 1; 57805b261ecSmrg } 57905b261ecSmrg pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); 5804642e01fSmrg xfree(prect); 58105b261ecSmrg} 58205b261ecSmrg 58305b261ecSmrg/** 58405b261ecSmrg * exaPolylines() checks if it can accelerate the lines as a group of 58505b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill 58605b261ecSmrg * acceleration if so. 58705b261ecSmrg */ 58805b261ecSmrgstatic void 58905b261ecSmrgexaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 59005b261ecSmrg DDXPointPtr ppt) 59105b261ecSmrg{ 59205b261ecSmrg xRectangle *prect; 59305b261ecSmrg int x1, x2, y1, y2; 59405b261ecSmrg int i; 59505b261ecSmrg 59605b261ecSmrg /* Don't try to do wide lines or non-solid fill style. */ 59705b261ecSmrg if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 59805b261ecSmrg pGC->fillStyle != FillSolid) { 59905b261ecSmrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 60005b261ecSmrg return; 60105b261ecSmrg } 60205b261ecSmrg 6034642e01fSmrg prect = xalloc(sizeof(xRectangle) * (npt - 1)); 60405b261ecSmrg x1 = ppt[0].x; 60505b261ecSmrg y1 = ppt[0].y; 60605b261ecSmrg /* If we have any non-horizontal/vertical, fall back. */ 60705b261ecSmrg for (i = 0; i < npt - 1; i++) { 60805b261ecSmrg if (mode == CoordModePrevious) { 60905b261ecSmrg x2 = x1 + ppt[i + 1].x; 61005b261ecSmrg y2 = y1 + ppt[i + 1].y; 61105b261ecSmrg } else { 61205b261ecSmrg x2 = ppt[i + 1].x; 61305b261ecSmrg y2 = ppt[i + 1].y; 61405b261ecSmrg } 61505b261ecSmrg 61605b261ecSmrg if (x1 != x2 && y1 != y2) { 6174642e01fSmrg xfree(prect); 61805b261ecSmrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 61905b261ecSmrg return; 62005b261ecSmrg } 62105b261ecSmrg 62205b261ecSmrg if (x1 < x2) { 62305b261ecSmrg prect[i].x = x1; 62405b261ecSmrg prect[i].width = x2 - x1 + 1; 62505b261ecSmrg } else { 62605b261ecSmrg prect[i].x = x2; 62705b261ecSmrg prect[i].width = x1 - x2 + 1; 62805b261ecSmrg } 62905b261ecSmrg if (y1 < y2) { 63005b261ecSmrg prect[i].y = y1; 63105b261ecSmrg prect[i].height = y2 - y1 + 1; 63205b261ecSmrg } else { 63305b261ecSmrg prect[i].y = y2; 63405b261ecSmrg prect[i].height = y1 - y2 + 1; 63505b261ecSmrg } 63605b261ecSmrg 63705b261ecSmrg x1 = x2; 63805b261ecSmrg y1 = y2; 63905b261ecSmrg } 64005b261ecSmrg pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); 6414642e01fSmrg xfree(prect); 64205b261ecSmrg} 64305b261ecSmrg 64405b261ecSmrg/** 64505b261ecSmrg * exaPolySegment() 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 65005b261ecSmrgexaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, 65105b261ecSmrg xSegment *pSeg) 65205b261ecSmrg{ 65305b261ecSmrg xRectangle *prect; 65405b261ecSmrg int i; 65505b261ecSmrg 65605b261ecSmrg /* Don't try to do wide lines or non-solid fill style. */ 65705b261ecSmrg if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 65805b261ecSmrg pGC->fillStyle != FillSolid) 65905b261ecSmrg { 66005b261ecSmrg ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 66105b261ecSmrg return; 66205b261ecSmrg } 66305b261ecSmrg 66405b261ecSmrg /* If we have any non-horizontal/vertical, fall back. */ 66505b261ecSmrg for (i = 0; i < nseg; i++) { 66605b261ecSmrg if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { 66705b261ecSmrg ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 66805b261ecSmrg return; 66905b261ecSmrg } 67005b261ecSmrg } 67105b261ecSmrg 6724642e01fSmrg prect = xalloc(sizeof(xRectangle) * nseg); 67305b261ecSmrg for (i = 0; i < nseg; i++) { 67405b261ecSmrg if (pSeg[i].x1 < pSeg[i].x2) { 67505b261ecSmrg prect[i].x = pSeg[i].x1; 67605b261ecSmrg prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; 67705b261ecSmrg } else { 67805b261ecSmrg prect[i].x = pSeg[i].x2; 67905b261ecSmrg prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; 68005b261ecSmrg } 68105b261ecSmrg if (pSeg[i].y1 < pSeg[i].y2) { 68205b261ecSmrg prect[i].y = pSeg[i].y1; 68305b261ecSmrg prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; 68405b261ecSmrg } else { 68505b261ecSmrg prect[i].y = pSeg[i].y2; 68605b261ecSmrg prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; 68705b261ecSmrg } 6884642e01fSmrg 6894642e01fSmrg /* don't paint last pixel */ 6904642e01fSmrg if (pGC->capStyle == CapNotLast) { 6914642e01fSmrg if (prect[i].width == 1) 6924642e01fSmrg prect[i].height--; 6934642e01fSmrg else 6944642e01fSmrg prect[i].width--; 6954642e01fSmrg } 69605b261ecSmrg } 69705b261ecSmrg pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); 6984642e01fSmrg xfree(prect); 69905b261ecSmrg} 70005b261ecSmrg 70105b261ecSmrgstatic Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, 70252397711Smrg Pixel pixel, CARD32 planemask, CARD32 alu, 70352397711Smrg unsigned int clientClipType); 70405b261ecSmrg 70505b261ecSmrgstatic void 70605b261ecSmrgexaPolyFillRect(DrawablePtr pDrawable, 70705b261ecSmrg GCPtr pGC, 70805b261ecSmrg int nrect, 70905b261ecSmrg xRectangle *prect) 71005b261ecSmrg{ 71105b261ecSmrg ExaScreenPriv (pDrawable->pScreen); 71205b261ecSmrg RegionPtr pClip = fbGetCompositeClip(pGC); 71305b261ecSmrg PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); 7144642e01fSmrg ExaPixmapPriv (pPixmap); 71505b261ecSmrg register BoxPtr pbox; 71605b261ecSmrg BoxPtr pextent; 71705b261ecSmrg int extentX1, extentX2, extentY1, extentY2; 71805b261ecSmrg int fullX1, fullX2, fullY1, fullY2; 71905b261ecSmrg int partX1, partX2, partY1, partY2; 72005b261ecSmrg int xoff, yoff; 72105b261ecSmrg int xorg, yorg; 72205b261ecSmrg int n; 72305b261ecSmrg ExaMigrationRec pixmaps[2]; 72405b261ecSmrg RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); 72505b261ecSmrg 72605b261ecSmrg /* Compute intersection of rects and clip region */ 72705b261ecSmrg REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); 72805b261ecSmrg REGION_INTERSECT(pScreen, pReg, pClip, pReg); 72905b261ecSmrg 73005b261ecSmrg if (!REGION_NUM_RECTS(pReg)) { 73105b261ecSmrg goto out; 73205b261ecSmrg } 73305b261ecSmrg 73405b261ecSmrg pixmaps[0].as_dst = TRUE; 73505b261ecSmrg pixmaps[0].as_src = FALSE; 73605b261ecSmrg pixmaps[0].pPix = pPixmap; 7374642e01fSmrg pixmaps[0].pReg = NULL; 7384642e01fSmrg 73905b261ecSmrg exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 74005b261ecSmrg 7414642e01fSmrg if (pExaScr->swappedOut || pExaPixmap->accel_blocked) 74205b261ecSmrg { 74305b261ecSmrg goto fallback; 74405b261ecSmrg } 74505b261ecSmrg 74605b261ecSmrg /* For ROPs where overlaps don't matter, convert rectangles to region and 74705b261ecSmrg * call exaFillRegion{Solid,Tiled}. 74805b261ecSmrg */ 74905b261ecSmrg if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && 7504642e01fSmrg (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || 7514642e01fSmrg pGC->alu == GXnoop || pGC->alu == GXcopyInverted || 7524642e01fSmrg pGC->alu == GXset)) { 75305b261ecSmrg if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && 75405b261ecSmrg exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? 75505b261ecSmrg pGC->fgPixel : pGC->tile.pixel, pGC->planemask, 75652397711Smrg pGC->alu, pGC->clientClipType)) || 75705b261ecSmrg (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && 75805b261ecSmrg exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, 75952397711Smrg pGC->planemask, pGC->alu, 76052397711Smrg pGC->clientClipType))) { 76105b261ecSmrg goto out; 76205b261ecSmrg } 76305b261ecSmrg } 76405b261ecSmrg 76505b261ecSmrg if (pGC->fillStyle != FillSolid && 76605b261ecSmrg !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) 76705b261ecSmrg { 76805b261ecSmrg goto fallback; 76905b261ecSmrg } 77005b261ecSmrg 77105b261ecSmrg exaDoMigration (pixmaps, 1, TRUE); 77205b261ecSmrg 77305b261ecSmrg if (!exaPixmapIsOffscreen (pPixmap) || 77405b261ecSmrg !(*pExaScr->info->PrepareSolid) (pPixmap, 77505b261ecSmrg pGC->alu, 77605b261ecSmrg pGC->planemask, 77705b261ecSmrg pGC->fgPixel)) 77805b261ecSmrg { 77905b261ecSmrgfallback: 78005b261ecSmrg ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); 78105b261ecSmrg goto out; 78205b261ecSmrg } 78305b261ecSmrg 78405b261ecSmrg xorg = pDrawable->x; 78505b261ecSmrg yorg = pDrawable->y; 78605b261ecSmrg 78705b261ecSmrg pextent = REGION_EXTENTS(pGC->pScreen, pClip); 78805b261ecSmrg extentX1 = pextent->x1; 78905b261ecSmrg extentY1 = pextent->y1; 79005b261ecSmrg extentX2 = pextent->x2; 79105b261ecSmrg extentY2 = pextent->y2; 79205b261ecSmrg while (nrect--) 79305b261ecSmrg { 79405b261ecSmrg fullX1 = prect->x + xorg; 79505b261ecSmrg fullY1 = prect->y + yorg; 79605b261ecSmrg fullX2 = fullX1 + (int) prect->width; 79705b261ecSmrg fullY2 = fullY1 + (int) prect->height; 79805b261ecSmrg prect++; 79905b261ecSmrg 80005b261ecSmrg if (fullX1 < extentX1) 80105b261ecSmrg fullX1 = extentX1; 80205b261ecSmrg 80305b261ecSmrg if (fullY1 < extentY1) 80405b261ecSmrg fullY1 = extentY1; 80505b261ecSmrg 80605b261ecSmrg if (fullX2 > extentX2) 80705b261ecSmrg fullX2 = extentX2; 80805b261ecSmrg 80905b261ecSmrg if (fullY2 > extentY2) 81005b261ecSmrg fullY2 = extentY2; 81105b261ecSmrg 81205b261ecSmrg if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) 81305b261ecSmrg continue; 81405b261ecSmrg n = REGION_NUM_RECTS (pClip); 81505b261ecSmrg if (n == 1) 81605b261ecSmrg { 81705b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 81805b261ecSmrg fullX1 + xoff, fullY1 + yoff, 81905b261ecSmrg fullX2 + xoff, fullY2 + yoff); 82005b261ecSmrg } 82105b261ecSmrg else 82205b261ecSmrg { 82305b261ecSmrg pbox = REGION_RECTS(pClip); 82405b261ecSmrg /* 82505b261ecSmrg * clip the rectangle to each box in the clip region 82605b261ecSmrg * this is logically equivalent to calling Intersect(), 82705b261ecSmrg * but rectangles may overlap each other here. 82805b261ecSmrg */ 82905b261ecSmrg while(n--) 83005b261ecSmrg { 83105b261ecSmrg partX1 = pbox->x1; 83205b261ecSmrg if (partX1 < fullX1) 83305b261ecSmrg partX1 = fullX1; 83405b261ecSmrg partY1 = pbox->y1; 83505b261ecSmrg if (partY1 < fullY1) 83605b261ecSmrg partY1 = fullY1; 83705b261ecSmrg partX2 = pbox->x2; 83805b261ecSmrg if (partX2 > fullX2) 83905b261ecSmrg partX2 = fullX2; 84005b261ecSmrg partY2 = pbox->y2; 84105b261ecSmrg if (partY2 > fullY2) 84205b261ecSmrg partY2 = fullY2; 84305b261ecSmrg 84405b261ecSmrg pbox++; 84505b261ecSmrg 84605b261ecSmrg if (partX1 < partX2 && partY1 < partY2) { 84705b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 84805b261ecSmrg partX1 + xoff, partY1 + yoff, 84905b261ecSmrg partX2 + xoff, partY2 + yoff); 85005b261ecSmrg } 85105b261ecSmrg } 85205b261ecSmrg } 85305b261ecSmrg } 85405b261ecSmrg (*pExaScr->info->DoneSolid) (pPixmap); 85505b261ecSmrg exaMarkSync(pDrawable->pScreen); 85605b261ecSmrg 85705b261ecSmrgout: 8584642e01fSmrg REGION_UNINIT(pScreen, pReg); 85905b261ecSmrg REGION_DESTROY(pScreen, pReg); 86005b261ecSmrg} 86105b261ecSmrg 86205b261ecSmrgconst GCOps exaOps = { 86305b261ecSmrg exaFillSpans, 86405b261ecSmrg ExaCheckSetSpans, 86505b261ecSmrg exaPutImage, 86605b261ecSmrg exaCopyArea, 86705b261ecSmrg ExaCheckCopyPlane, 86805b261ecSmrg exaPolyPoint, 86905b261ecSmrg exaPolylines, 87005b261ecSmrg exaPolySegment, 87105b261ecSmrg miPolyRectangle, 87205b261ecSmrg ExaCheckPolyArc, 87305b261ecSmrg miFillPolygon, 87405b261ecSmrg exaPolyFillRect, 87505b261ecSmrg miPolyFillArc, 87605b261ecSmrg miPolyText8, 87705b261ecSmrg miPolyText16, 87805b261ecSmrg miImageText8, 87905b261ecSmrg miImageText16, 8804642e01fSmrg ExaCheckImageGlyphBlt, 88105b261ecSmrg ExaCheckPolyGlyphBlt, 88205b261ecSmrg ExaCheckPushPixels, 88305b261ecSmrg}; 88405b261ecSmrg 88505b261ecSmrgvoid 88605b261ecSmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 88705b261ecSmrg{ 88805b261ecSmrg RegionRec rgnDst; 88905b261ecSmrg int dx, dy; 89005b261ecSmrg PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); 89105b261ecSmrg 89205b261ecSmrg dx = ptOldOrg.x - pWin->drawable.x; 89305b261ecSmrg dy = ptOldOrg.y - pWin->drawable.y; 89405b261ecSmrg REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); 89505b261ecSmrg 89605b261ecSmrg REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); 89705b261ecSmrg 89805b261ecSmrg REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); 89905b261ecSmrg#ifdef COMPOSITE 90005b261ecSmrg if (pPixmap->screen_x || pPixmap->screen_y) 90105b261ecSmrg REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, 90205b261ecSmrg -pPixmap->screen_x, -pPixmap->screen_y); 90305b261ecSmrg#endif 90405b261ecSmrg 90505b261ecSmrg fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable, 90605b261ecSmrg NULL, 90705b261ecSmrg &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); 90805b261ecSmrg 90905b261ecSmrg REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); 91005b261ecSmrg} 91105b261ecSmrg 91205b261ecSmrgstatic Bool 91352397711SmrgexaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, 91452397711Smrg CARD32 planemask, CARD32 alu, unsigned int clientClipType) 91505b261ecSmrg{ 91605b261ecSmrg ExaScreenPriv(pDrawable->pScreen); 9174642e01fSmrg PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); 9184642e01fSmrg ExaPixmapPriv (pPixmap); 91905b261ecSmrg int xoff, yoff; 92005b261ecSmrg ExaMigrationRec pixmaps[1]; 9214642e01fSmrg Bool ret = FALSE; 92205b261ecSmrg 92305b261ecSmrg pixmaps[0].as_dst = TRUE; 92405b261ecSmrg pixmaps[0].as_src = FALSE; 9254642e01fSmrg pixmaps[0].pPix = pPixmap; 9264642e01fSmrg pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, 92752397711Smrg alu, clientClipType) 92852397711Smrg ? NULL : pRegion; 9294642e01fSmrg 9304642e01fSmrg exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 9314642e01fSmrg REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); 9324642e01fSmrg 9334642e01fSmrg if (pExaPixmap->accel_blocked) 93405b261ecSmrg { 9354642e01fSmrg goto out; 93605b261ecSmrg } else { 93705b261ecSmrg exaDoMigration (pixmaps, 1, TRUE); 93805b261ecSmrg } 93905b261ecSmrg 9404642e01fSmrg if (exaPixmapIsOffscreen (pPixmap) && 94105b261ecSmrg (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) 94205b261ecSmrg { 9434642e01fSmrg int nbox; 9444642e01fSmrg BoxPtr pBox; 9454642e01fSmrg 9464642e01fSmrg nbox = REGION_NUM_RECTS (pRegion); 9474642e01fSmrg pBox = REGION_RECTS (pRegion); 9484642e01fSmrg 94905b261ecSmrg while (nbox--) 95005b261ecSmrg { 9514642e01fSmrg (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, 9524642e01fSmrg pBox->y2); 95305b261ecSmrg pBox++; 95405b261ecSmrg } 95505b261ecSmrg (*pExaScr->info->DoneSolid) (pPixmap); 95605b261ecSmrg exaMarkSync(pDrawable->pScreen); 9574642e01fSmrg 9584642e01fSmrg if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && 9594642e01fSmrg pDrawable->width == 1 && pDrawable->height == 1 && 9604642e01fSmrg pDrawable->bitsPerPixel != 24) { 9614642e01fSmrg ExaPixmapPriv(pPixmap); 9624642e01fSmrg 9634642e01fSmrg switch (pDrawable->bitsPerPixel) { 9644642e01fSmrg case 32: 9654642e01fSmrg *(CARD32*)pExaPixmap->sys_ptr = pixel; 9664642e01fSmrg break; 9674642e01fSmrg case 16: 9684642e01fSmrg *(CARD16*)pExaPixmap->sys_ptr = pixel; 9694642e01fSmrg break; 9704642e01fSmrg case 8: 9714642e01fSmrg *(CARD8*)pExaPixmap->sys_ptr = pixel; 9724642e01fSmrg } 9734642e01fSmrg 9744642e01fSmrg REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, 9754642e01fSmrg pRegion); 9764642e01fSmrg } 9774642e01fSmrg 9784642e01fSmrg ret = TRUE; 97905b261ecSmrg } 98005b261ecSmrg 9814642e01fSmrgout: 9824642e01fSmrg REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); 9834642e01fSmrg 9844642e01fSmrg return ret; 98505b261ecSmrg} 98605b261ecSmrg 98705b261ecSmrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. 98805b261ecSmrg * Based on fbFillRegionTiled(), fbTile(). 98905b261ecSmrg */ 99005b261ecSmrgBool 99152397711SmrgexaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, 99252397711Smrg DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, 99352397711Smrg unsigned int clientClipType) 99405b261ecSmrg{ 99505b261ecSmrg ExaScreenPriv(pDrawable->pScreen); 99605b261ecSmrg PixmapPtr pPixmap; 9974642e01fSmrg ExaPixmapPrivPtr pExaPixmap; 9984642e01fSmrg ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); 9994642e01fSmrg int xoff, yoff; 100005b261ecSmrg int tileWidth, tileHeight; 100105b261ecSmrg ExaMigrationRec pixmaps[2]; 100205b261ecSmrg int nbox = REGION_NUM_RECTS (pRegion); 100305b261ecSmrg BoxPtr pBox = REGION_RECTS (pRegion); 10044642e01fSmrg Bool ret = FALSE; 10054642e01fSmrg int i; 100605b261ecSmrg 100705b261ecSmrg tileWidth = pTile->drawable.width; 100805b261ecSmrg tileHeight = pTile->drawable.height; 100905b261ecSmrg 101005b261ecSmrg /* If we're filling with a solid color, grab it out and go to 101105b261ecSmrg * FillRegionSolid, saving numerous copies. 101205b261ecSmrg */ 101305b261ecSmrg if (tileWidth == 1 && tileHeight == 1) 101405b261ecSmrg return exaFillRegionSolid(pDrawable, pRegion, 101505b261ecSmrg exaGetPixmapFirstPixel (pTile), planemask, 101652397711Smrg alu, clientClipType); 101705b261ecSmrg 101805b261ecSmrg pixmaps[0].as_dst = TRUE; 101905b261ecSmrg pixmaps[0].as_src = FALSE; 102005b261ecSmrg pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); 10214642e01fSmrg pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, 102252397711Smrg alu, clientClipType) 102352397711Smrg ? NULL : pRegion; 102405b261ecSmrg pixmaps[1].as_dst = FALSE; 102505b261ecSmrg pixmaps[1].as_src = TRUE; 102605b261ecSmrg pixmaps[1].pPix = pTile; 10274642e01fSmrg pixmaps[1].pReg = NULL; 102805b261ecSmrg 10294642e01fSmrg pExaPixmap = ExaGetPixmapPriv (pPixmap); 10304642e01fSmrg 10314642e01fSmrg if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked) 103205b261ecSmrg { 10334642e01fSmrg return FALSE; 103405b261ecSmrg } else { 103505b261ecSmrg exaDoMigration (pixmaps, 2, TRUE); 103605b261ecSmrg } 103705b261ecSmrg 103805b261ecSmrg pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 103905b261ecSmrg 10404642e01fSmrg if (!pPixmap || !exaPixmapIsOffscreen(pTile)) 10414642e01fSmrg return FALSE; 104205b261ecSmrg 10434642e01fSmrg if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) 104405b261ecSmrg { 10454642e01fSmrg if (xoff || yoff) 10464642e01fSmrg REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); 10474642e01fSmrg 10484642e01fSmrg for (i = 0; i < nbox; i++) 104905b261ecSmrg { 10504642e01fSmrg int height = pBox[i].y2 - pBox[i].y1; 10514642e01fSmrg int dstY = pBox[i].y1; 105205b261ecSmrg int tileY; 105305b261ecSmrg 10544642e01fSmrg if (alu == GXcopy) 10554642e01fSmrg height = min(height, tileHeight); 10564642e01fSmrg 10574642e01fSmrg modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); 105805b261ecSmrg 105905b261ecSmrg while (height > 0) { 10604642e01fSmrg int width = pBox[i].x2 - pBox[i].x1; 10614642e01fSmrg int dstX = pBox[i].x1; 106205b261ecSmrg int tileX; 106305b261ecSmrg int h = tileHeight - tileY; 106405b261ecSmrg 10654642e01fSmrg if (alu == GXcopy) 10664642e01fSmrg width = min(width, tileWidth); 10674642e01fSmrg 106805b261ecSmrg if (h > height) 106905b261ecSmrg h = height; 107005b261ecSmrg height -= h; 107105b261ecSmrg 10724642e01fSmrg modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, 10734642e01fSmrg tileX); 107405b261ecSmrg 107505b261ecSmrg while (width > 0) { 107605b261ecSmrg int w = tileWidth - tileX; 107705b261ecSmrg if (w > width) 107805b261ecSmrg w = width; 107905b261ecSmrg width -= w; 108005b261ecSmrg 10814642e01fSmrg (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, 108205b261ecSmrg w, h); 108305b261ecSmrg dstX += w; 108405b261ecSmrg tileX = 0; 108505b261ecSmrg } 108605b261ecSmrg dstY += h; 108705b261ecSmrg tileY = 0; 108805b261ecSmrg } 108905b261ecSmrg } 109005b261ecSmrg (*pExaScr->info->DoneCopy) (pPixmap); 109105b261ecSmrg 10924642e01fSmrg /* With GXcopy, we only need to do the basic algorithm up to the tile 10934642e01fSmrg * size; then, we can just keep doubling the destination in each 10944642e01fSmrg * direction until it fills the box. This way, the number of copy 10954642e01fSmrg * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where 10964642e01fSmrg * rx/ry is the ratio between box and tile width/height. This can make 10974642e01fSmrg * a big difference if each driver copy incurs a significant constant 10984642e01fSmrg * overhead. 10994642e01fSmrg */ 11004642e01fSmrg if (alu != GXcopy) 11014642e01fSmrg ret = TRUE; 11024642e01fSmrg else { 11034642e01fSmrg Bool more_copy = FALSE; 11044642e01fSmrg 11054642e01fSmrg for (i = 0; i < nbox; i++) { 11064642e01fSmrg int dstX = pBox[i].x1 + tileWidth; 11074642e01fSmrg int dstY = pBox[i].y1 + tileHeight; 11084642e01fSmrg 11094642e01fSmrg if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { 11104642e01fSmrg more_copy = TRUE; 11114642e01fSmrg break; 11124642e01fSmrg } 11134642e01fSmrg } 111405b261ecSmrg 11154642e01fSmrg if (more_copy == FALSE) 11164642e01fSmrg ret = TRUE; 111705b261ecSmrg 11184642e01fSmrg if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, 11194642e01fSmrg 1, 1, alu, planemask)) { 11204642e01fSmrg for (i = 0; i < nbox; i++) 11214642e01fSmrg { 11224642e01fSmrg int dstX = pBox[i].x1 + tileWidth; 11234642e01fSmrg int dstY = pBox[i].y1 + tileHeight; 11244642e01fSmrg int width = min(pBox[i].x2 - dstX, tileWidth); 11254642e01fSmrg int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); 11264642e01fSmrg 11274642e01fSmrg while (dstX < pBox[i].x2) { 11284642e01fSmrg (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 11294642e01fSmrg dstX, pBox[i].y1, width, height); 11304642e01fSmrg dstX += width; 11314642e01fSmrg width = min(pBox[i].x2 - dstX, width * 2); 11324642e01fSmrg } 113305b261ecSmrg 11344642e01fSmrg width = pBox[i].x2 - pBox[i].x1; 11354642e01fSmrg height = min(pBox[i].y2 - dstY, tileHeight); 113605b261ecSmrg 11374642e01fSmrg while (dstY < pBox[i].y2) { 11384642e01fSmrg (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 11394642e01fSmrg pBox[i].x1, dstY, width, height); 11404642e01fSmrg dstY += height; 11414642e01fSmrg height = min(pBox[i].y2 - dstY, height * 2); 11424642e01fSmrg } 11434642e01fSmrg } 114405b261ecSmrg 11454642e01fSmrg (*pExaScr->info->DoneCopy) (pPixmap); 11464642e01fSmrg 11474642e01fSmrg ret = TRUE; 11484642e01fSmrg } 11494642e01fSmrg } 115005b261ecSmrg 11514642e01fSmrg exaMarkSync(pDrawable->pScreen); 115205b261ecSmrg 11534642e01fSmrg if (xoff || yoff) 11544642e01fSmrg REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); 115505b261ecSmrg } 11564642e01fSmrg 11574642e01fSmrg return ret; 115805b261ecSmrg} 115905b261ecSmrg 11604642e01fSmrg 116105b261ecSmrg/** 116205b261ecSmrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. 116305b261ecSmrg * 116405b261ecSmrg * This is probably the only case we actually care about. The rest fall through 11654642e01fSmrg * to migration and fbGetImage, which hopefully will result in migration pushing 11664642e01fSmrg * the pixmap out of framebuffer. 116705b261ecSmrg */ 116805b261ecSmrgvoid 116905b261ecSmrgexaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, 117005b261ecSmrg unsigned int format, unsigned long planeMask, char *d) 117105b261ecSmrg{ 117205b261ecSmrg ExaScreenPriv (pDrawable->pScreen); 117305b261ecSmrg ExaMigrationRec pixmaps[1]; 11744642e01fSmrg BoxRec Box; 11754642e01fSmrg RegionRec Reg; 117605b261ecSmrg PixmapPtr pPix; 117705b261ecSmrg int xoff, yoff; 117805b261ecSmrg Bool ok; 117905b261ecSmrg 11804642e01fSmrg pixmaps[0].as_dst = FALSE; 11814642e01fSmrg pixmaps[0].as_src = TRUE; 11824642e01fSmrg pixmaps[0].pPix = pPix = exaGetDrawablePixmap (pDrawable); 11834642e01fSmrg pixmaps[0].pReg = &Reg; 11844642e01fSmrg 11854642e01fSmrg exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff); 11864642e01fSmrg 11874642e01fSmrg Box.x1 = pDrawable->y + x + xoff; 11884642e01fSmrg Box.y1 = pDrawable->y + y + yoff; 11894642e01fSmrg Box.x2 = Box.x1 + w; 11904642e01fSmrg Box.y2 = Box.y1 + h; 11914642e01fSmrg 11924642e01fSmrg REGION_INIT(pScreen, &Reg, &Box, 1); 11934642e01fSmrg 11944642e01fSmrg if (pExaScr->swappedOut) 119505b261ecSmrg goto fallback; 119605b261ecSmrg 11974642e01fSmrg exaDoMigration(pixmaps, 1, FALSE); 11984642e01fSmrg 11994642e01fSmrg pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 12004642e01fSmrg 12014642e01fSmrg if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) 12024642e01fSmrg goto fallback; 120305b261ecSmrg 120405b261ecSmrg /* Only cover the ZPixmap, solid copy case. */ 120505b261ecSmrg if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) 12064642e01fSmrg goto fallback; 120705b261ecSmrg 120805b261ecSmrg /* Only try to handle the 8bpp and up cases, since we don't want to think 120905b261ecSmrg * about <8bpp. 121005b261ecSmrg */ 121105b261ecSmrg if (pDrawable->bitsPerPixel < 8) 121205b261ecSmrg goto fallback; 121305b261ecSmrg 12144642e01fSmrg ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, 12154642e01fSmrg pDrawable->y + y + yoff, w, h, d, 121605b261ecSmrg PixmapBytePad(w, pDrawable->depth)); 121705b261ecSmrg if (ok) { 121805b261ecSmrg exaWaitSync(pDrawable->pScreen); 12194642e01fSmrg goto out; 122005b261ecSmrg } 122105b261ecSmrg 122205b261ecSmrgfallback: 12234642e01fSmrg EXA_FALLBACK(("from %p (%c)\n", pDrawable, 12244642e01fSmrg exaDrawableLocation(pDrawable))); 122505b261ecSmrg 12264642e01fSmrg exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg); 12274642e01fSmrg fbGetImage (pDrawable, x, y, w, h, format, planeMask, d); 12284642e01fSmrg exaFinishAccess (pDrawable, EXA_PREPARE_SRC); 122905b261ecSmrg 12304642e01fSmrgout: 12314642e01fSmrg REGION_UNINIT(pScreen, &Reg); 123205b261ecSmrg} 1233