exa_accel.c revision 7b683adc
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; 4187b683adcSmrg int ordering; 4194642e01fSmrg 4204642e01fSmrg for (i = 0; i < nbox; i++) { 4214642e01fSmrg rects[i].x = pbox[i].x1 + dx + src_off_x; 4224642e01fSmrg rects[i].y = pbox[i].y1 + dy + src_off_y; 4234642e01fSmrg rects[i].width = pbox[i].x2 - pbox[i].x1; 4244642e01fSmrg rects[i].height = pbox[i].y2 - pbox[i].y1; 4254642e01fSmrg } 4264642e01fSmrg 4277b683adcSmrg /* This must match the miRegionCopy() logic for reversing rect order */ 4287b683adcSmrg if (nbox == 1 || (dx > 0 && dy > 0) || 4297b683adcSmrg (pDstDrawable != pSrcDrawable && 4307b683adcSmrg (pDstDrawable->type != DRAWABLE_WINDOW || 4317b683adcSmrg pSrcDrawable->type != DRAWABLE_WINDOW))) 4327b683adcSmrg ordering = CT_YXBANDED; 4337b683adcSmrg else 4347b683adcSmrg ordering = CT_UNSORTED; 4357b683adcSmrg 4367b683adcSmrg srcregion = RECTS_TO_REGION(pScreen, nbox, rects, ordering); 4374642e01fSmrg xfree(rects); 4384642e01fSmrg 4394642e01fSmrg if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, 44052397711Smrg pGC->fillStyle, pGC->alu, 44152397711Smrg pGC->clientClipType)) { 4424642e01fSmrg dstregion = REGION_CREATE(pScreen, NullBox, 0); 4434642e01fSmrg REGION_COPY(pScreen, dstregion, srcregion); 4444642e01fSmrg REGION_TRANSLATE(pScreen, dstregion, dst_off_x - dx - src_off_x, 4454642e01fSmrg dst_off_y - dy - src_off_y); 4464642e01fSmrg } 4474642e01fSmrg } 44805b261ecSmrg 44905b261ecSmrg pixmaps[0].as_dst = TRUE; 45005b261ecSmrg pixmaps[0].as_src = FALSE; 4514642e01fSmrg pixmaps[0].pPix = pDstPixmap; 4524642e01fSmrg pixmaps[0].pReg = dstregion; 45305b261ecSmrg pixmaps[1].as_dst = FALSE; 45405b261ecSmrg pixmaps[1].as_src = TRUE; 4554642e01fSmrg pixmaps[1].pPix = pSrcPixmap; 4564642e01fSmrg pixmaps[1].pReg = srcregion; 45705b261ecSmrg 4584642e01fSmrg pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap); 4594642e01fSmrg pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); 4604642e01fSmrg 4614642e01fSmrg /* Check whether the accelerator can use this pixmap. 4624642e01fSmrg * If the pitch of the pixmaps is out of range, there's nothing 4634642e01fSmrg * we can do but fall back to software rendering. 46405b261ecSmrg */ 4654642e01fSmrg if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || 4664642e01fSmrg pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) 4674642e01fSmrg goto fallback; 4684642e01fSmrg 4694642e01fSmrg /* If the width or the height of either of the pixmaps 4704642e01fSmrg * is out of range, check whether the boxes are actually out of the 4714642e01fSmrg * addressable range as well. If they aren't, we can still do 4724642e01fSmrg * the copying in hardware. 4734642e01fSmrg */ 4744642e01fSmrg if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { 4754642e01fSmrg int i; 4764642e01fSmrg 4774642e01fSmrg for (i = 0; i < nbox; i++) { 4784642e01fSmrg /* src */ 4794642e01fSmrg if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || 4804642e01fSmrg (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) 4814642e01fSmrg goto fallback; 4824642e01fSmrg 4834642e01fSmrg /* dst */ 4844642e01fSmrg if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || 4854642e01fSmrg (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) 4864642e01fSmrg goto fallback; 4874642e01fSmrg } 48805b261ecSmrg } 48905b261ecSmrg 4904642e01fSmrg exaDoMigration (pixmaps, 2, TRUE); 4914642e01fSmrg 49205b261ecSmrg /* Mixed directions must be handled specially if the card is lame */ 4934642e01fSmrg if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && 49405b261ecSmrg reverse != upsidedown) { 49505b261ecSmrg if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, 49605b261ecSmrg dx, dy)) 4974642e01fSmrg goto out; 4984642e01fSmrg goto fallback; 49905b261ecSmrg } 50005b261ecSmrg 5014642e01fSmrg if (!exaPixmapIsOffscreen(pSrcPixmap) || 50205b261ecSmrg !exaPixmapIsOffscreen(pDstPixmap) || 50305b261ecSmrg !(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, 50405b261ecSmrg upsidedown ? -1 : 1, 50505b261ecSmrg pGC ? pGC->alu : GXcopy, 50605b261ecSmrg pGC ? pGC->planemask : FB_ALLONES)) { 5074642e01fSmrg goto fallback; 50805b261ecSmrg } 50905b261ecSmrg 51005b261ecSmrg while (nbox--) 51105b261ecSmrg { 5124642e01fSmrg (*pExaScr->info->Copy) (pDstPixmap, 5134642e01fSmrg pbox->x1 + dx + src_off_x, 5144642e01fSmrg pbox->y1 + dy + src_off_y, 5154642e01fSmrg pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, 5164642e01fSmrg pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); 51705b261ecSmrg pbox++; 51805b261ecSmrg } 51905b261ecSmrg 52005b261ecSmrg (*pExaScr->info->DoneCopy) (pDstPixmap); 52105b261ecSmrg exaMarkSync (pDstDrawable->pScreen); 5224642e01fSmrg 5234642e01fSmrg goto out; 5244642e01fSmrg 5254642e01fSmrgfallback: 5264642e01fSmrg EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, 5274642e01fSmrg exaDrawableLocation(pSrcDrawable), 5284642e01fSmrg exaDrawableLocation(pDstDrawable))); 5294642e01fSmrg exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, dstregion); 5304642e01fSmrg exaPrepareAccessReg (pSrcDrawable, EXA_PREPARE_SRC, srcregion); 5314642e01fSmrg fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, 5324642e01fSmrg upsidedown, bitplane, closure); 5334642e01fSmrg exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC); 5344642e01fSmrg exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST); 5354642e01fSmrg 5364642e01fSmrgout: 5374642e01fSmrg if (dstregion) { 5384642e01fSmrg REGION_UNINIT(pScreen, dstregion); 5394642e01fSmrg REGION_DESTROY(pScreen, dstregion); 5404642e01fSmrg } 5414642e01fSmrg if (srcregion) { 5424642e01fSmrg REGION_UNINIT(pScreen, srcregion); 5434642e01fSmrg REGION_DESTROY(pScreen, srcregion); 5444642e01fSmrg } 54505b261ecSmrg} 54605b261ecSmrg 54705b261ecSmrgRegionPtr 54805b261ecSmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, 54905b261ecSmrg int srcx, int srcy, int width, int height, int dstx, int dsty) 55005b261ecSmrg{ 55105b261ecSmrg ExaScreenPriv (pDstDrawable->pScreen); 55205b261ecSmrg 55305b261ecSmrg if (pExaScr->swappedOut) { 55405b261ecSmrg return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, 55505b261ecSmrg srcx, srcy, width, height, dstx, dsty); 55605b261ecSmrg } 55705b261ecSmrg 55805b261ecSmrg return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, 55905b261ecSmrg srcx, srcy, width, height, 56005b261ecSmrg dstx, dsty, exaCopyNtoN, 0, NULL); 56105b261ecSmrg} 56205b261ecSmrg 56305b261ecSmrgstatic void 56405b261ecSmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 56505b261ecSmrg DDXPointPtr ppt) 56605b261ecSmrg{ 56705b261ecSmrg int i; 56805b261ecSmrg xRectangle *prect; 56905b261ecSmrg 57005b261ecSmrg /* If we can't reuse the current GC as is, don't bother accelerating the 57105b261ecSmrg * points. 57205b261ecSmrg */ 57305b261ecSmrg if (pGC->fillStyle != FillSolid) { 57405b261ecSmrg ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); 57505b261ecSmrg return; 57605b261ecSmrg } 57705b261ecSmrg 5784642e01fSmrg prect = xalloc(sizeof(xRectangle) * npt); 57905b261ecSmrg for (i = 0; i < npt; i++) { 58005b261ecSmrg prect[i].x = ppt[i].x; 58105b261ecSmrg prect[i].y = ppt[i].y; 58205b261ecSmrg if (i > 0 && mode == CoordModePrevious) { 58305b261ecSmrg prect[i].x += prect[i - 1].x; 58405b261ecSmrg prect[i].y += prect[i - 1].y; 58505b261ecSmrg } 58605b261ecSmrg prect[i].width = 1; 58705b261ecSmrg prect[i].height = 1; 58805b261ecSmrg } 58905b261ecSmrg pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); 5904642e01fSmrg xfree(prect); 59105b261ecSmrg} 59205b261ecSmrg 59305b261ecSmrg/** 59405b261ecSmrg * exaPolylines() checks if it can accelerate the lines as a group of 59505b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill 59605b261ecSmrg * acceleration if so. 59705b261ecSmrg */ 59805b261ecSmrgstatic void 59905b261ecSmrgexaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 60005b261ecSmrg DDXPointPtr ppt) 60105b261ecSmrg{ 60205b261ecSmrg xRectangle *prect; 60305b261ecSmrg int x1, x2, y1, y2; 60405b261ecSmrg int i; 60505b261ecSmrg 60605b261ecSmrg /* Don't try to do wide lines or non-solid fill style. */ 60705b261ecSmrg if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 60805b261ecSmrg pGC->fillStyle != FillSolid) { 60905b261ecSmrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 61005b261ecSmrg return; 61105b261ecSmrg } 61205b261ecSmrg 6134642e01fSmrg prect = xalloc(sizeof(xRectangle) * (npt - 1)); 61405b261ecSmrg x1 = ppt[0].x; 61505b261ecSmrg y1 = ppt[0].y; 61605b261ecSmrg /* If we have any non-horizontal/vertical, fall back. */ 61705b261ecSmrg for (i = 0; i < npt - 1; i++) { 61805b261ecSmrg if (mode == CoordModePrevious) { 61905b261ecSmrg x2 = x1 + ppt[i + 1].x; 62005b261ecSmrg y2 = y1 + ppt[i + 1].y; 62105b261ecSmrg } else { 62205b261ecSmrg x2 = ppt[i + 1].x; 62305b261ecSmrg y2 = ppt[i + 1].y; 62405b261ecSmrg } 62505b261ecSmrg 62605b261ecSmrg if (x1 != x2 && y1 != y2) { 6274642e01fSmrg xfree(prect); 62805b261ecSmrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 62905b261ecSmrg return; 63005b261ecSmrg } 63105b261ecSmrg 63205b261ecSmrg if (x1 < x2) { 63305b261ecSmrg prect[i].x = x1; 63405b261ecSmrg prect[i].width = x2 - x1 + 1; 63505b261ecSmrg } else { 63605b261ecSmrg prect[i].x = x2; 63705b261ecSmrg prect[i].width = x1 - x2 + 1; 63805b261ecSmrg } 63905b261ecSmrg if (y1 < y2) { 64005b261ecSmrg prect[i].y = y1; 64105b261ecSmrg prect[i].height = y2 - y1 + 1; 64205b261ecSmrg } else { 64305b261ecSmrg prect[i].y = y2; 64405b261ecSmrg prect[i].height = y1 - y2 + 1; 64505b261ecSmrg } 64605b261ecSmrg 64705b261ecSmrg x1 = x2; 64805b261ecSmrg y1 = y2; 64905b261ecSmrg } 65005b261ecSmrg pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); 6514642e01fSmrg xfree(prect); 65205b261ecSmrg} 65305b261ecSmrg 65405b261ecSmrg/** 65505b261ecSmrg * exaPolySegment() checks if it can accelerate the lines as a group of 65605b261ecSmrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill 65705b261ecSmrg * acceleration if so. 65805b261ecSmrg */ 65905b261ecSmrgstatic void 66005b261ecSmrgexaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, 66105b261ecSmrg xSegment *pSeg) 66205b261ecSmrg{ 66305b261ecSmrg xRectangle *prect; 66405b261ecSmrg int i; 66505b261ecSmrg 66605b261ecSmrg /* Don't try to do wide lines or non-solid fill style. */ 66705b261ecSmrg if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 66805b261ecSmrg pGC->fillStyle != FillSolid) 66905b261ecSmrg { 67005b261ecSmrg ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 67105b261ecSmrg return; 67205b261ecSmrg } 67305b261ecSmrg 67405b261ecSmrg /* If we have any non-horizontal/vertical, fall back. */ 67505b261ecSmrg for (i = 0; i < nseg; i++) { 67605b261ecSmrg if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { 67705b261ecSmrg ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 67805b261ecSmrg return; 67905b261ecSmrg } 68005b261ecSmrg } 68105b261ecSmrg 6824642e01fSmrg prect = xalloc(sizeof(xRectangle) * nseg); 68305b261ecSmrg for (i = 0; i < nseg; i++) { 68405b261ecSmrg if (pSeg[i].x1 < pSeg[i].x2) { 68505b261ecSmrg prect[i].x = pSeg[i].x1; 68605b261ecSmrg prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; 68705b261ecSmrg } else { 68805b261ecSmrg prect[i].x = pSeg[i].x2; 68905b261ecSmrg prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; 69005b261ecSmrg } 69105b261ecSmrg if (pSeg[i].y1 < pSeg[i].y2) { 69205b261ecSmrg prect[i].y = pSeg[i].y1; 69305b261ecSmrg prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; 69405b261ecSmrg } else { 69505b261ecSmrg prect[i].y = pSeg[i].y2; 69605b261ecSmrg prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; 69705b261ecSmrg } 6984642e01fSmrg 6994642e01fSmrg /* don't paint last pixel */ 7004642e01fSmrg if (pGC->capStyle == CapNotLast) { 7014642e01fSmrg if (prect[i].width == 1) 7024642e01fSmrg prect[i].height--; 7034642e01fSmrg else 7044642e01fSmrg prect[i].width--; 7054642e01fSmrg } 70605b261ecSmrg } 70705b261ecSmrg pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); 7084642e01fSmrg xfree(prect); 70905b261ecSmrg} 71005b261ecSmrg 71105b261ecSmrgstatic Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, 71252397711Smrg Pixel pixel, CARD32 planemask, CARD32 alu, 71352397711Smrg unsigned int clientClipType); 71405b261ecSmrg 71505b261ecSmrgstatic void 71605b261ecSmrgexaPolyFillRect(DrawablePtr pDrawable, 71705b261ecSmrg GCPtr pGC, 71805b261ecSmrg int nrect, 71905b261ecSmrg xRectangle *prect) 72005b261ecSmrg{ 72105b261ecSmrg ExaScreenPriv (pDrawable->pScreen); 72205b261ecSmrg RegionPtr pClip = fbGetCompositeClip(pGC); 72305b261ecSmrg PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); 7244642e01fSmrg ExaPixmapPriv (pPixmap); 72505b261ecSmrg register BoxPtr pbox; 72605b261ecSmrg BoxPtr pextent; 72705b261ecSmrg int extentX1, extentX2, extentY1, extentY2; 72805b261ecSmrg int fullX1, fullX2, fullY1, fullY2; 72905b261ecSmrg int partX1, partX2, partY1, partY2; 73005b261ecSmrg int xoff, yoff; 73105b261ecSmrg int xorg, yorg; 73205b261ecSmrg int n; 73305b261ecSmrg ExaMigrationRec pixmaps[2]; 73405b261ecSmrg RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); 73505b261ecSmrg 73605b261ecSmrg /* Compute intersection of rects and clip region */ 73705b261ecSmrg REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); 73805b261ecSmrg REGION_INTERSECT(pScreen, pReg, pClip, pReg); 73905b261ecSmrg 74005b261ecSmrg if (!REGION_NUM_RECTS(pReg)) { 74105b261ecSmrg goto out; 74205b261ecSmrg } 74305b261ecSmrg 74405b261ecSmrg pixmaps[0].as_dst = TRUE; 74505b261ecSmrg pixmaps[0].as_src = FALSE; 74605b261ecSmrg pixmaps[0].pPix = pPixmap; 7474642e01fSmrg pixmaps[0].pReg = NULL; 7484642e01fSmrg 74905b261ecSmrg exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 75005b261ecSmrg 7514642e01fSmrg if (pExaScr->swappedOut || pExaPixmap->accel_blocked) 75205b261ecSmrg { 75305b261ecSmrg goto fallback; 75405b261ecSmrg } 75505b261ecSmrg 75605b261ecSmrg /* For ROPs where overlaps don't matter, convert rectangles to region and 75705b261ecSmrg * call exaFillRegion{Solid,Tiled}. 75805b261ecSmrg */ 75905b261ecSmrg if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && 7604642e01fSmrg (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || 7614642e01fSmrg pGC->alu == GXnoop || pGC->alu == GXcopyInverted || 7624642e01fSmrg pGC->alu == GXset)) { 76305b261ecSmrg if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && 76405b261ecSmrg exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? 76505b261ecSmrg pGC->fgPixel : pGC->tile.pixel, pGC->planemask, 76652397711Smrg pGC->alu, pGC->clientClipType)) || 76705b261ecSmrg (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && 76805b261ecSmrg exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, 76952397711Smrg pGC->planemask, pGC->alu, 77052397711Smrg pGC->clientClipType))) { 77105b261ecSmrg goto out; 77205b261ecSmrg } 77305b261ecSmrg } 77405b261ecSmrg 77505b261ecSmrg if (pGC->fillStyle != FillSolid && 77605b261ecSmrg !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) 77705b261ecSmrg { 77805b261ecSmrg goto fallback; 77905b261ecSmrg } 78005b261ecSmrg 78105b261ecSmrg exaDoMigration (pixmaps, 1, TRUE); 78205b261ecSmrg 78305b261ecSmrg if (!exaPixmapIsOffscreen (pPixmap) || 78405b261ecSmrg !(*pExaScr->info->PrepareSolid) (pPixmap, 78505b261ecSmrg pGC->alu, 78605b261ecSmrg pGC->planemask, 78705b261ecSmrg pGC->fgPixel)) 78805b261ecSmrg { 78905b261ecSmrgfallback: 79005b261ecSmrg ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); 79105b261ecSmrg goto out; 79205b261ecSmrg } 79305b261ecSmrg 79405b261ecSmrg xorg = pDrawable->x; 79505b261ecSmrg yorg = pDrawable->y; 79605b261ecSmrg 79705b261ecSmrg pextent = REGION_EXTENTS(pGC->pScreen, pClip); 79805b261ecSmrg extentX1 = pextent->x1; 79905b261ecSmrg extentY1 = pextent->y1; 80005b261ecSmrg extentX2 = pextent->x2; 80105b261ecSmrg extentY2 = pextent->y2; 80205b261ecSmrg while (nrect--) 80305b261ecSmrg { 80405b261ecSmrg fullX1 = prect->x + xorg; 80505b261ecSmrg fullY1 = prect->y + yorg; 80605b261ecSmrg fullX2 = fullX1 + (int) prect->width; 80705b261ecSmrg fullY2 = fullY1 + (int) prect->height; 80805b261ecSmrg prect++; 80905b261ecSmrg 81005b261ecSmrg if (fullX1 < extentX1) 81105b261ecSmrg fullX1 = extentX1; 81205b261ecSmrg 81305b261ecSmrg if (fullY1 < extentY1) 81405b261ecSmrg fullY1 = extentY1; 81505b261ecSmrg 81605b261ecSmrg if (fullX2 > extentX2) 81705b261ecSmrg fullX2 = extentX2; 81805b261ecSmrg 81905b261ecSmrg if (fullY2 > extentY2) 82005b261ecSmrg fullY2 = extentY2; 82105b261ecSmrg 82205b261ecSmrg if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) 82305b261ecSmrg continue; 82405b261ecSmrg n = REGION_NUM_RECTS (pClip); 82505b261ecSmrg if (n == 1) 82605b261ecSmrg { 82705b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 82805b261ecSmrg fullX1 + xoff, fullY1 + yoff, 82905b261ecSmrg fullX2 + xoff, fullY2 + yoff); 83005b261ecSmrg } 83105b261ecSmrg else 83205b261ecSmrg { 83305b261ecSmrg pbox = REGION_RECTS(pClip); 83405b261ecSmrg /* 83505b261ecSmrg * clip the rectangle to each box in the clip region 83605b261ecSmrg * this is logically equivalent to calling Intersect(), 83705b261ecSmrg * but rectangles may overlap each other here. 83805b261ecSmrg */ 83905b261ecSmrg while(n--) 84005b261ecSmrg { 84105b261ecSmrg partX1 = pbox->x1; 84205b261ecSmrg if (partX1 < fullX1) 84305b261ecSmrg partX1 = fullX1; 84405b261ecSmrg partY1 = pbox->y1; 84505b261ecSmrg if (partY1 < fullY1) 84605b261ecSmrg partY1 = fullY1; 84705b261ecSmrg partX2 = pbox->x2; 84805b261ecSmrg if (partX2 > fullX2) 84905b261ecSmrg partX2 = fullX2; 85005b261ecSmrg partY2 = pbox->y2; 85105b261ecSmrg if (partY2 > fullY2) 85205b261ecSmrg partY2 = fullY2; 85305b261ecSmrg 85405b261ecSmrg pbox++; 85505b261ecSmrg 85605b261ecSmrg if (partX1 < partX2 && partY1 < partY2) { 85705b261ecSmrg (*pExaScr->info->Solid) (pPixmap, 85805b261ecSmrg partX1 + xoff, partY1 + yoff, 85905b261ecSmrg partX2 + xoff, partY2 + yoff); 86005b261ecSmrg } 86105b261ecSmrg } 86205b261ecSmrg } 86305b261ecSmrg } 86405b261ecSmrg (*pExaScr->info->DoneSolid) (pPixmap); 86505b261ecSmrg exaMarkSync(pDrawable->pScreen); 86605b261ecSmrg 86705b261ecSmrgout: 8684642e01fSmrg REGION_UNINIT(pScreen, pReg); 86905b261ecSmrg REGION_DESTROY(pScreen, pReg); 87005b261ecSmrg} 87105b261ecSmrg 87205b261ecSmrgconst GCOps exaOps = { 87305b261ecSmrg exaFillSpans, 87405b261ecSmrg ExaCheckSetSpans, 87505b261ecSmrg exaPutImage, 87605b261ecSmrg exaCopyArea, 87705b261ecSmrg ExaCheckCopyPlane, 87805b261ecSmrg exaPolyPoint, 87905b261ecSmrg exaPolylines, 88005b261ecSmrg exaPolySegment, 88105b261ecSmrg miPolyRectangle, 88205b261ecSmrg ExaCheckPolyArc, 88305b261ecSmrg miFillPolygon, 88405b261ecSmrg exaPolyFillRect, 88505b261ecSmrg miPolyFillArc, 88605b261ecSmrg miPolyText8, 88705b261ecSmrg miPolyText16, 88805b261ecSmrg miImageText8, 88905b261ecSmrg miImageText16, 8904642e01fSmrg ExaCheckImageGlyphBlt, 89105b261ecSmrg ExaCheckPolyGlyphBlt, 89205b261ecSmrg ExaCheckPushPixels, 89305b261ecSmrg}; 89405b261ecSmrg 89505b261ecSmrgvoid 89605b261ecSmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 89705b261ecSmrg{ 89805b261ecSmrg RegionRec rgnDst; 89905b261ecSmrg int dx, dy; 90005b261ecSmrg PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); 90105b261ecSmrg 90205b261ecSmrg dx = ptOldOrg.x - pWin->drawable.x; 90305b261ecSmrg dy = ptOldOrg.y - pWin->drawable.y; 90405b261ecSmrg REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); 90505b261ecSmrg 90605b261ecSmrg REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); 90705b261ecSmrg 90805b261ecSmrg REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); 90905b261ecSmrg#ifdef COMPOSITE 91005b261ecSmrg if (pPixmap->screen_x || pPixmap->screen_y) 91105b261ecSmrg REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, 91205b261ecSmrg -pPixmap->screen_x, -pPixmap->screen_y); 91305b261ecSmrg#endif 91405b261ecSmrg 91505b261ecSmrg fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable, 91605b261ecSmrg NULL, 91705b261ecSmrg &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); 91805b261ecSmrg 91905b261ecSmrg REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); 92005b261ecSmrg} 92105b261ecSmrg 92205b261ecSmrgstatic Bool 92352397711SmrgexaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, 92452397711Smrg CARD32 planemask, CARD32 alu, unsigned int clientClipType) 92505b261ecSmrg{ 92605b261ecSmrg ExaScreenPriv(pDrawable->pScreen); 9274642e01fSmrg PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); 9284642e01fSmrg ExaPixmapPriv (pPixmap); 92905b261ecSmrg int xoff, yoff; 93005b261ecSmrg ExaMigrationRec pixmaps[1]; 9314642e01fSmrg Bool ret = FALSE; 93205b261ecSmrg 93305b261ecSmrg pixmaps[0].as_dst = TRUE; 93405b261ecSmrg pixmaps[0].as_src = FALSE; 9354642e01fSmrg pixmaps[0].pPix = pPixmap; 9364642e01fSmrg pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, 93752397711Smrg alu, clientClipType) 93852397711Smrg ? NULL : pRegion; 9394642e01fSmrg 9404642e01fSmrg exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 9414642e01fSmrg REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); 9424642e01fSmrg 9434642e01fSmrg if (pExaPixmap->accel_blocked) 94405b261ecSmrg { 9454642e01fSmrg goto out; 94605b261ecSmrg } else { 94705b261ecSmrg exaDoMigration (pixmaps, 1, TRUE); 94805b261ecSmrg } 94905b261ecSmrg 9504642e01fSmrg if (exaPixmapIsOffscreen (pPixmap) && 95105b261ecSmrg (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) 95205b261ecSmrg { 9534642e01fSmrg int nbox; 9544642e01fSmrg BoxPtr pBox; 9554642e01fSmrg 9564642e01fSmrg nbox = REGION_NUM_RECTS (pRegion); 9574642e01fSmrg pBox = REGION_RECTS (pRegion); 9584642e01fSmrg 95905b261ecSmrg while (nbox--) 96005b261ecSmrg { 9614642e01fSmrg (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, 9624642e01fSmrg pBox->y2); 96305b261ecSmrg pBox++; 96405b261ecSmrg } 96505b261ecSmrg (*pExaScr->info->DoneSolid) (pPixmap); 96605b261ecSmrg exaMarkSync(pDrawable->pScreen); 9674642e01fSmrg 9684642e01fSmrg if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && 9694642e01fSmrg pDrawable->width == 1 && pDrawable->height == 1 && 9704642e01fSmrg pDrawable->bitsPerPixel != 24) { 9714642e01fSmrg ExaPixmapPriv(pPixmap); 9724642e01fSmrg 9734642e01fSmrg switch (pDrawable->bitsPerPixel) { 9744642e01fSmrg case 32: 9754642e01fSmrg *(CARD32*)pExaPixmap->sys_ptr = pixel; 9764642e01fSmrg break; 9774642e01fSmrg case 16: 9784642e01fSmrg *(CARD16*)pExaPixmap->sys_ptr = pixel; 9794642e01fSmrg break; 9804642e01fSmrg case 8: 9814642e01fSmrg *(CARD8*)pExaPixmap->sys_ptr = pixel; 9824642e01fSmrg } 9834642e01fSmrg 9844642e01fSmrg REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, 9854642e01fSmrg pRegion); 9864642e01fSmrg } 9874642e01fSmrg 9884642e01fSmrg ret = TRUE; 98905b261ecSmrg } 99005b261ecSmrg 9914642e01fSmrgout: 9924642e01fSmrg REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); 9934642e01fSmrg 9944642e01fSmrg return ret; 99505b261ecSmrg} 99605b261ecSmrg 99705b261ecSmrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. 99805b261ecSmrg * Based on fbFillRegionTiled(), fbTile(). 99905b261ecSmrg */ 100005b261ecSmrgBool 100152397711SmrgexaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, 100252397711Smrg DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, 100352397711Smrg unsigned int clientClipType) 100405b261ecSmrg{ 100505b261ecSmrg ExaScreenPriv(pDrawable->pScreen); 100605b261ecSmrg PixmapPtr pPixmap; 10074642e01fSmrg ExaPixmapPrivPtr pExaPixmap; 10084642e01fSmrg ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); 10094642e01fSmrg int xoff, yoff; 101005b261ecSmrg int tileWidth, tileHeight; 101105b261ecSmrg ExaMigrationRec pixmaps[2]; 101205b261ecSmrg int nbox = REGION_NUM_RECTS (pRegion); 101305b261ecSmrg BoxPtr pBox = REGION_RECTS (pRegion); 10144642e01fSmrg Bool ret = FALSE; 10154642e01fSmrg int i; 101605b261ecSmrg 101705b261ecSmrg tileWidth = pTile->drawable.width; 101805b261ecSmrg tileHeight = pTile->drawable.height; 101905b261ecSmrg 102005b261ecSmrg /* If we're filling with a solid color, grab it out and go to 102105b261ecSmrg * FillRegionSolid, saving numerous copies. 102205b261ecSmrg */ 102305b261ecSmrg if (tileWidth == 1 && tileHeight == 1) 102405b261ecSmrg return exaFillRegionSolid(pDrawable, pRegion, 102505b261ecSmrg exaGetPixmapFirstPixel (pTile), planemask, 102652397711Smrg alu, clientClipType); 102705b261ecSmrg 102805b261ecSmrg pixmaps[0].as_dst = TRUE; 102905b261ecSmrg pixmaps[0].as_src = FALSE; 103005b261ecSmrg pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); 10314642e01fSmrg pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, 103252397711Smrg alu, clientClipType) 103352397711Smrg ? NULL : pRegion; 103405b261ecSmrg pixmaps[1].as_dst = FALSE; 103505b261ecSmrg pixmaps[1].as_src = TRUE; 103605b261ecSmrg pixmaps[1].pPix = pTile; 10374642e01fSmrg pixmaps[1].pReg = NULL; 103805b261ecSmrg 10394642e01fSmrg pExaPixmap = ExaGetPixmapPriv (pPixmap); 10404642e01fSmrg 10414642e01fSmrg if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked) 104205b261ecSmrg { 10434642e01fSmrg return FALSE; 104405b261ecSmrg } else { 104505b261ecSmrg exaDoMigration (pixmaps, 2, TRUE); 104605b261ecSmrg } 104705b261ecSmrg 104805b261ecSmrg pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 104905b261ecSmrg 10504642e01fSmrg if (!pPixmap || !exaPixmapIsOffscreen(pTile)) 10514642e01fSmrg return FALSE; 105205b261ecSmrg 10534642e01fSmrg if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) 105405b261ecSmrg { 10554642e01fSmrg if (xoff || yoff) 10564642e01fSmrg REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); 10574642e01fSmrg 10584642e01fSmrg for (i = 0; i < nbox; i++) 105905b261ecSmrg { 10604642e01fSmrg int height = pBox[i].y2 - pBox[i].y1; 10614642e01fSmrg int dstY = pBox[i].y1; 106205b261ecSmrg int tileY; 106305b261ecSmrg 10644642e01fSmrg if (alu == GXcopy) 10654642e01fSmrg height = min(height, tileHeight); 10664642e01fSmrg 10674642e01fSmrg modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); 106805b261ecSmrg 106905b261ecSmrg while (height > 0) { 10704642e01fSmrg int width = pBox[i].x2 - pBox[i].x1; 10714642e01fSmrg int dstX = pBox[i].x1; 107205b261ecSmrg int tileX; 107305b261ecSmrg int h = tileHeight - tileY; 107405b261ecSmrg 10754642e01fSmrg if (alu == GXcopy) 10764642e01fSmrg width = min(width, tileWidth); 10774642e01fSmrg 107805b261ecSmrg if (h > height) 107905b261ecSmrg h = height; 108005b261ecSmrg height -= h; 108105b261ecSmrg 10824642e01fSmrg modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, 10834642e01fSmrg tileX); 108405b261ecSmrg 108505b261ecSmrg while (width > 0) { 108605b261ecSmrg int w = tileWidth - tileX; 108705b261ecSmrg if (w > width) 108805b261ecSmrg w = width; 108905b261ecSmrg width -= w; 109005b261ecSmrg 10914642e01fSmrg (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, 109205b261ecSmrg w, h); 109305b261ecSmrg dstX += w; 109405b261ecSmrg tileX = 0; 109505b261ecSmrg } 109605b261ecSmrg dstY += h; 109705b261ecSmrg tileY = 0; 109805b261ecSmrg } 109905b261ecSmrg } 110005b261ecSmrg (*pExaScr->info->DoneCopy) (pPixmap); 110105b261ecSmrg 11024642e01fSmrg /* With GXcopy, we only need to do the basic algorithm up to the tile 11034642e01fSmrg * size; then, we can just keep doubling the destination in each 11044642e01fSmrg * direction until it fills the box. This way, the number of copy 11054642e01fSmrg * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where 11064642e01fSmrg * rx/ry is the ratio between box and tile width/height. This can make 11074642e01fSmrg * a big difference if each driver copy incurs a significant constant 11084642e01fSmrg * overhead. 11094642e01fSmrg */ 11104642e01fSmrg if (alu != GXcopy) 11114642e01fSmrg ret = TRUE; 11124642e01fSmrg else { 11134642e01fSmrg Bool more_copy = FALSE; 11144642e01fSmrg 11154642e01fSmrg for (i = 0; i < nbox; i++) { 11164642e01fSmrg int dstX = pBox[i].x1 + tileWidth; 11174642e01fSmrg int dstY = pBox[i].y1 + tileHeight; 11184642e01fSmrg 11194642e01fSmrg if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { 11204642e01fSmrg more_copy = TRUE; 11214642e01fSmrg break; 11224642e01fSmrg } 11234642e01fSmrg } 112405b261ecSmrg 11254642e01fSmrg if (more_copy == FALSE) 11264642e01fSmrg ret = TRUE; 112705b261ecSmrg 11284642e01fSmrg if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, 11294642e01fSmrg 1, 1, alu, planemask)) { 11304642e01fSmrg for (i = 0; i < nbox; i++) 11314642e01fSmrg { 11324642e01fSmrg int dstX = pBox[i].x1 + tileWidth; 11334642e01fSmrg int dstY = pBox[i].y1 + tileHeight; 11344642e01fSmrg int width = min(pBox[i].x2 - dstX, tileWidth); 11354642e01fSmrg int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); 11364642e01fSmrg 11374642e01fSmrg while (dstX < pBox[i].x2) { 11384642e01fSmrg (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 11394642e01fSmrg dstX, pBox[i].y1, width, height); 11404642e01fSmrg dstX += width; 11414642e01fSmrg width = min(pBox[i].x2 - dstX, width * 2); 11424642e01fSmrg } 114305b261ecSmrg 11444642e01fSmrg width = pBox[i].x2 - pBox[i].x1; 11454642e01fSmrg height = min(pBox[i].y2 - dstY, tileHeight); 114605b261ecSmrg 11474642e01fSmrg while (dstY < pBox[i].y2) { 11484642e01fSmrg (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 11494642e01fSmrg pBox[i].x1, dstY, width, height); 11504642e01fSmrg dstY += height; 11514642e01fSmrg height = min(pBox[i].y2 - dstY, height * 2); 11524642e01fSmrg } 11534642e01fSmrg } 115405b261ecSmrg 11554642e01fSmrg (*pExaScr->info->DoneCopy) (pPixmap); 11564642e01fSmrg 11574642e01fSmrg ret = TRUE; 11584642e01fSmrg } 11594642e01fSmrg } 116005b261ecSmrg 11614642e01fSmrg exaMarkSync(pDrawable->pScreen); 116205b261ecSmrg 11634642e01fSmrg if (xoff || yoff) 11644642e01fSmrg REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); 116505b261ecSmrg } 11664642e01fSmrg 11674642e01fSmrg return ret; 116805b261ecSmrg} 116905b261ecSmrg 11704642e01fSmrg 117105b261ecSmrg/** 117205b261ecSmrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. 117305b261ecSmrg * 117405b261ecSmrg * This is probably the only case we actually care about. The rest fall through 11754642e01fSmrg * to migration and fbGetImage, which hopefully will result in migration pushing 11764642e01fSmrg * the pixmap out of framebuffer. 117705b261ecSmrg */ 117805b261ecSmrgvoid 117905b261ecSmrgexaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, 118005b261ecSmrg unsigned int format, unsigned long planeMask, char *d) 118105b261ecSmrg{ 118205b261ecSmrg ExaScreenPriv (pDrawable->pScreen); 118305b261ecSmrg ExaMigrationRec pixmaps[1]; 11844642e01fSmrg BoxRec Box; 11854642e01fSmrg RegionRec Reg; 118605b261ecSmrg PixmapPtr pPix; 118705b261ecSmrg int xoff, yoff; 118805b261ecSmrg Bool ok; 118905b261ecSmrg 11904642e01fSmrg pixmaps[0].as_dst = FALSE; 11914642e01fSmrg pixmaps[0].as_src = TRUE; 11924642e01fSmrg pixmaps[0].pPix = pPix = exaGetDrawablePixmap (pDrawable); 11934642e01fSmrg pixmaps[0].pReg = &Reg; 11944642e01fSmrg 11954642e01fSmrg exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff); 11964642e01fSmrg 11974642e01fSmrg Box.x1 = pDrawable->y + x + xoff; 11984642e01fSmrg Box.y1 = pDrawable->y + y + yoff; 11994642e01fSmrg Box.x2 = Box.x1 + w; 12004642e01fSmrg Box.y2 = Box.y1 + h; 12014642e01fSmrg 12024642e01fSmrg REGION_INIT(pScreen, &Reg, &Box, 1); 12034642e01fSmrg 12044642e01fSmrg if (pExaScr->swappedOut) 120505b261ecSmrg goto fallback; 120605b261ecSmrg 12074642e01fSmrg exaDoMigration(pixmaps, 1, FALSE); 12084642e01fSmrg 12094642e01fSmrg pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 12104642e01fSmrg 12114642e01fSmrg if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) 12124642e01fSmrg goto fallback; 121305b261ecSmrg 121405b261ecSmrg /* Only cover the ZPixmap, solid copy case. */ 121505b261ecSmrg if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) 12164642e01fSmrg goto fallback; 121705b261ecSmrg 121805b261ecSmrg /* Only try to handle the 8bpp and up cases, since we don't want to think 121905b261ecSmrg * about <8bpp. 122005b261ecSmrg */ 122105b261ecSmrg if (pDrawable->bitsPerPixel < 8) 122205b261ecSmrg goto fallback; 122305b261ecSmrg 12244642e01fSmrg ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, 12254642e01fSmrg pDrawable->y + y + yoff, w, h, d, 122605b261ecSmrg PixmapBytePad(w, pDrawable->depth)); 122705b261ecSmrg if (ok) { 122805b261ecSmrg exaWaitSync(pDrawable->pScreen); 12294642e01fSmrg goto out; 123005b261ecSmrg } 123105b261ecSmrg 123205b261ecSmrgfallback: 12334642e01fSmrg EXA_FALLBACK(("from %p (%c)\n", pDrawable, 12344642e01fSmrg exaDrawableLocation(pDrawable))); 123505b261ecSmrg 12364642e01fSmrg exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg); 12374642e01fSmrg fbGetImage (pDrawable, x, y, w, h, format, planeMask, d); 12384642e01fSmrg exaFinishAccess (pDrawable, EXA_PREPARE_SRC); 123905b261ecSmrg 12404642e01fSmrgout: 12414642e01fSmrg REGION_UNINIT(pScreen, &Reg); 124205b261ecSmrg} 1243