1706f2543Smrg/* 2706f2543Smrg * Copyright � 2001 Keith Packard 3706f2543Smrg * 4706f2543Smrg * Partly based on code that is Copyright � The XFree86 Project Inc. 5706f2543Smrg * 6706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 7706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 8706f2543Smrg * the above copyright notice appear in all copies and that both that 9706f2543Smrg * copyright notice and this permission notice appear in supporting 10706f2543Smrg * documentation, and that the name of Keith Packard not be used in 11706f2543Smrg * advertising or publicity pertaining to distribution of the software without 12706f2543Smrg * specific, written prior permission. Keith Packard makes no 13706f2543Smrg * representations about the suitability of this software for any purpose. It 14706f2543Smrg * is provided "as is" without express or implied warranty. 15706f2543Smrg * 16706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22706f2543Smrg * PERFORMANCE OF THIS SOFTWARE. 23706f2543Smrg * 24706f2543Smrg * Authors: 25706f2543Smrg * Eric Anholt <eric@anholt.net> 26706f2543Smrg * Michel D�nzer <michel@tungstengraphics.com> 27706f2543Smrg * 28706f2543Smrg */ 29706f2543Smrg 30706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 31706f2543Smrg#include <dix-config.h> 32706f2543Smrg#endif 33706f2543Smrg#include "exa_priv.h" 34706f2543Smrg#include <X11/fonts/fontstruct.h> 35706f2543Smrg#include "dixfontstr.h" 36706f2543Smrg#include "exa.h" 37706f2543Smrg 38706f2543Smrgstatic void 39706f2543SmrgexaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, 40706f2543Smrg DDXPointPtr ppt, int *pwidth, int fSorted) 41706f2543Smrg{ 42706f2543Smrg ScreenPtr pScreen = pDrawable->pScreen; 43706f2543Smrg ExaScreenPriv (pScreen); 44706f2543Smrg RegionPtr pClip = fbGetCompositeClip(pGC); 45706f2543Smrg PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); 46706f2543Smrg ExaPixmapPriv (pPixmap); 47706f2543Smrg BoxPtr pextent, pbox; 48706f2543Smrg int nbox; 49706f2543Smrg int extentX1, extentX2, extentY1, extentY2; 50706f2543Smrg int fullX1, fullX2, fullY1; 51706f2543Smrg int partX1, partX2; 52706f2543Smrg int off_x, off_y; 53706f2543Smrg 54706f2543Smrg if (pExaScr->fallback_counter || 55706f2543Smrg pExaScr->swappedOut || 56706f2543Smrg pGC->fillStyle != FillSolid || 57706f2543Smrg pExaPixmap->accel_blocked) 58706f2543Smrg { 59706f2543Smrg ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); 60706f2543Smrg return; 61706f2543Smrg } 62706f2543Smrg 63706f2543Smrg if (pExaScr->do_migration) { 64706f2543Smrg ExaMigrationRec pixmaps[1]; 65706f2543Smrg 66706f2543Smrg pixmaps[0].as_dst = TRUE; 67706f2543Smrg pixmaps[0].as_src = FALSE; 68706f2543Smrg pixmaps[0].pPix = pPixmap; 69706f2543Smrg pixmaps[0].pReg = NULL; 70706f2543Smrg 71706f2543Smrg exaDoMigration (pixmaps, 1, TRUE); 72706f2543Smrg } 73706f2543Smrg 74706f2543Smrg if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) || 75706f2543Smrg !(*pExaScr->info->PrepareSolid) (pPixmap, 76706f2543Smrg pGC->alu, 77706f2543Smrg pGC->planemask, 78706f2543Smrg pGC->fgPixel)) 79706f2543Smrg { 80706f2543Smrg ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); 81706f2543Smrg return; 82706f2543Smrg } 83706f2543Smrg 84706f2543Smrg pextent = RegionExtents(pClip); 85706f2543Smrg extentX1 = pextent->x1; 86706f2543Smrg extentY1 = pextent->y1; 87706f2543Smrg extentX2 = pextent->x2; 88706f2543Smrg extentY2 = pextent->y2; 89706f2543Smrg while (n--) 90706f2543Smrg { 91706f2543Smrg fullX1 = ppt->x; 92706f2543Smrg fullY1 = ppt->y; 93706f2543Smrg fullX2 = fullX1 + (int) *pwidth; 94706f2543Smrg ppt++; 95706f2543Smrg pwidth++; 96706f2543Smrg 97706f2543Smrg if (fullY1 < extentY1 || extentY2 <= fullY1) 98706f2543Smrg continue; 99706f2543Smrg 100706f2543Smrg if (fullX1 < extentX1) 101706f2543Smrg fullX1 = extentX1; 102706f2543Smrg 103706f2543Smrg if (fullX2 > extentX2) 104706f2543Smrg fullX2 = extentX2; 105706f2543Smrg 106706f2543Smrg if (fullX1 >= fullX2) 107706f2543Smrg continue; 108706f2543Smrg 109706f2543Smrg nbox = RegionNumRects (pClip); 110706f2543Smrg if (nbox == 1) 111706f2543Smrg { 112706f2543Smrg (*pExaScr->info->Solid) (pPixmap, 113706f2543Smrg fullX1 + off_x, fullY1 + off_y, 114706f2543Smrg fullX2 + off_x, fullY1 + 1 + off_y); 115706f2543Smrg } 116706f2543Smrg else 117706f2543Smrg { 118706f2543Smrg pbox = RegionRects(pClip); 119706f2543Smrg while(nbox--) 120706f2543Smrg { 121706f2543Smrg if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) 122706f2543Smrg { 123706f2543Smrg partX1 = pbox->x1; 124706f2543Smrg if (partX1 < fullX1) 125706f2543Smrg partX1 = fullX1; 126706f2543Smrg partX2 = pbox->x2; 127706f2543Smrg if (partX2 > fullX2) 128706f2543Smrg partX2 = fullX2; 129706f2543Smrg if (partX2 > partX1) { 130706f2543Smrg (*pExaScr->info->Solid) (pPixmap, 131706f2543Smrg partX1 + off_x, fullY1 + off_y, 132706f2543Smrg partX2 + off_x, fullY1 + 1 + off_y); 133706f2543Smrg } 134706f2543Smrg } 135706f2543Smrg pbox++; 136706f2543Smrg } 137706f2543Smrg } 138706f2543Smrg } 139706f2543Smrg (*pExaScr->info->DoneSolid) (pPixmap); 140706f2543Smrg exaMarkSync(pScreen); 141706f2543Smrg} 142706f2543Smrg 143706f2543Smrgstatic Bool 144706f2543SmrgexaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, 145706f2543Smrg int w, int h, int format, char *bits, int src_stride) 146706f2543Smrg{ 147706f2543Smrg ExaScreenPriv (pDrawable->pScreen); 148706f2543Smrg PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); 149706f2543Smrg ExaPixmapPriv(pPix); 150706f2543Smrg RegionPtr pClip; 151706f2543Smrg BoxPtr pbox; 152706f2543Smrg int nbox; 153706f2543Smrg int xoff, yoff; 154706f2543Smrg int bpp = pDrawable->bitsPerPixel; 155706f2543Smrg Bool ret = TRUE; 156706f2543Smrg 157706f2543Smrg if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen) 158706f2543Smrg return FALSE; 159706f2543Smrg 160706f2543Smrg /* If there's a system copy, we want to save the result there */ 161706f2543Smrg if (pExaPixmap->pDamage) 162706f2543Smrg return FALSE; 163706f2543Smrg 164706f2543Smrg /* Don't bother with under 8bpp, XYPixmaps. */ 165706f2543Smrg if (format != ZPixmap || bpp < 8) 166706f2543Smrg return FALSE; 167706f2543Smrg 168706f2543Smrg /* Only accelerate copies: no rop or planemask. */ 169706f2543Smrg if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) 170706f2543Smrg return FALSE; 171706f2543Smrg 172706f2543Smrg if (pExaScr->swappedOut) 173706f2543Smrg return FALSE; 174706f2543Smrg 175706f2543Smrg if (pExaScr->do_migration) { 176706f2543Smrg ExaMigrationRec pixmaps[1]; 177706f2543Smrg 178706f2543Smrg pixmaps[0].as_dst = TRUE; 179706f2543Smrg pixmaps[0].as_src = FALSE; 180706f2543Smrg pixmaps[0].pPix = pPix; 181706f2543Smrg pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); 182706f2543Smrg 183706f2543Smrg exaDoMigration (pixmaps, 1, TRUE); 184706f2543Smrg } 185706f2543Smrg 186706f2543Smrg pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 187706f2543Smrg 188706f2543Smrg if (!pPix) 189706f2543Smrg return FALSE; 190706f2543Smrg 191706f2543Smrg x += pDrawable->x; 192706f2543Smrg y += pDrawable->y; 193706f2543Smrg 194706f2543Smrg pClip = fbGetCompositeClip(pGC); 195706f2543Smrg for (nbox = RegionNumRects(pClip), 196706f2543Smrg pbox = RegionRects(pClip); 197706f2543Smrg nbox--; 198706f2543Smrg pbox++) 199706f2543Smrg { 200706f2543Smrg int x1 = x; 201706f2543Smrg int y1 = y; 202706f2543Smrg int x2 = x + w; 203706f2543Smrg int y2 = y + h; 204706f2543Smrg char *src; 205706f2543Smrg Bool ok; 206706f2543Smrg 207706f2543Smrg if (x1 < pbox->x1) 208706f2543Smrg x1 = pbox->x1; 209706f2543Smrg if (y1 < pbox->y1) 210706f2543Smrg y1 = pbox->y1; 211706f2543Smrg if (x2 > pbox->x2) 212706f2543Smrg x2 = pbox->x2; 213706f2543Smrg if (y2 > pbox->y2) 214706f2543Smrg y2 = pbox->y2; 215706f2543Smrg if (x1 >= x2 || y1 >= y2) 216706f2543Smrg continue; 217706f2543Smrg 218706f2543Smrg src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); 219706f2543Smrg ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, 220706f2543Smrg x2 - x1, y2 - y1, src, src_stride); 221706f2543Smrg /* We have to fall back completely, and ignore what has already been completed. 222706f2543Smrg * Messing with the fb layer directly like we used to is completely unacceptable. 223706f2543Smrg */ 224706f2543Smrg if (!ok) { 225706f2543Smrg ret = FALSE; 226706f2543Smrg break; 227706f2543Smrg } 228706f2543Smrg } 229706f2543Smrg 230706f2543Smrg if (ret) 231706f2543Smrg exaMarkSync(pDrawable->pScreen); 232706f2543Smrg 233706f2543Smrg return ret; 234706f2543Smrg} 235706f2543Smrg 236706f2543Smrgstatic void 237706f2543SmrgexaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, 238706f2543Smrg int w, int h, int leftPad, int format, char *bits) 239706f2543Smrg{ 240706f2543Smrg if (!exaDoPutImage(pDrawable, pGC, depth, x, y, w, h, format, bits, 241706f2543Smrg PixmapBytePad(w, pDrawable->depth))) 242706f2543Smrg ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, 243706f2543Smrg bits); 244706f2543Smrg} 245706f2543Smrg 246706f2543Smrgstatic Bool inline 247706f2543SmrgexaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, 248706f2543Smrg GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) 249706f2543Smrg{ 250706f2543Smrg ExaScreenPriv (pDstDrawable->pScreen); 251706f2543Smrg PixmapPtr pSrcPixmap, pDstPixmap; 252706f2543Smrg int src_off_x, src_off_y, dst_off_x, dst_off_y; 253706f2543Smrg int dirsetup; 254706f2543Smrg 255706f2543Smrg /* Need to get both pixmaps to call the driver routines */ 256706f2543Smrg pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y); 257706f2543Smrg pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y); 258706f2543Smrg if (!pSrcPixmap || !pDstPixmap) 259706f2543Smrg return FALSE; 260706f2543Smrg 261706f2543Smrg /* 262706f2543Smrg * Now the case of a chip that only supports xdir = ydir = 1 or 263706f2543Smrg * xdir = ydir = -1, but we have xdir != ydir. 264706f2543Smrg */ 265706f2543Smrg dirsetup = 0; /* No direction set up yet. */ 266706f2543Smrg for (; nbox; pbox++, nbox--) { 267706f2543Smrg if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 268706f2543Smrg /* Do a xdir = ydir = -1 blit instead. */ 269706f2543Smrg if (dirsetup != -1) { 270706f2543Smrg if (dirsetup != 0) 271706f2543Smrg pExaScr->info->DoneCopy(pDstPixmap); 272706f2543Smrg dirsetup = -1; 273706f2543Smrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 274706f2543Smrg pDstPixmap, 275706f2543Smrg -1, -1, 276706f2543Smrg pGC ? pGC->alu : GXcopy, 277706f2543Smrg pGC ? pGC->planemask : 278706f2543Smrg FB_ALLONES)) 279706f2543Smrg return FALSE; 280706f2543Smrg } 281706f2543Smrg (*pExaScr->info->Copy)(pDstPixmap, 282706f2543Smrg src_off_x + pbox->x1 + dx, 283706f2543Smrg src_off_y + pbox->y1 + dy, 284706f2543Smrg dst_off_x + pbox->x1, 285706f2543Smrg dst_off_y + pbox->y1, 286706f2543Smrg pbox->x2 - pbox->x1, 287706f2543Smrg pbox->y2 - pbox->y1); 288706f2543Smrg } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { 289706f2543Smrg /* Do a xdir = ydir = 1 blit instead. */ 290706f2543Smrg if (dirsetup != 1) { 291706f2543Smrg if (dirsetup != 0) 292706f2543Smrg pExaScr->info->DoneCopy(pDstPixmap); 293706f2543Smrg dirsetup = 1; 294706f2543Smrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 295706f2543Smrg pDstPixmap, 296706f2543Smrg 1, 1, 297706f2543Smrg pGC ? pGC->alu : GXcopy, 298706f2543Smrg pGC ? pGC->planemask : 299706f2543Smrg FB_ALLONES)) 300706f2543Smrg return FALSE; 301706f2543Smrg } 302706f2543Smrg (*pExaScr->info->Copy)(pDstPixmap, 303706f2543Smrg src_off_x + pbox->x1 + dx, 304706f2543Smrg src_off_y + pbox->y1 + dy, 305706f2543Smrg dst_off_x + pbox->x1, 306706f2543Smrg dst_off_y + pbox->y1, 307706f2543Smrg pbox->x2 - pbox->x1, 308706f2543Smrg pbox->y2 - pbox->y1); 309706f2543Smrg } else if (dx >= 0) { 310706f2543Smrg /* 311706f2543Smrg * xdir = 1, ydir = -1. 312706f2543Smrg * Perform line-by-line xdir = ydir = 1 blits, going up. 313706f2543Smrg */ 314706f2543Smrg int i; 315706f2543Smrg if (dirsetup != 1) { 316706f2543Smrg if (dirsetup != 0) 317706f2543Smrg pExaScr->info->DoneCopy(pDstPixmap); 318706f2543Smrg dirsetup = 1; 319706f2543Smrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 320706f2543Smrg pDstPixmap, 321706f2543Smrg 1, 1, 322706f2543Smrg pGC ? pGC->alu : GXcopy, 323706f2543Smrg pGC ? pGC->planemask : 324706f2543Smrg FB_ALLONES)) 325706f2543Smrg return FALSE; 326706f2543Smrg } 327706f2543Smrg for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) 328706f2543Smrg (*pExaScr->info->Copy)(pDstPixmap, 329706f2543Smrg src_off_x + pbox->x1 + dx, 330706f2543Smrg src_off_y + pbox->y1 + dy + i, 331706f2543Smrg dst_off_x + pbox->x1, 332706f2543Smrg dst_off_y + pbox->y1 + i, 333706f2543Smrg pbox->x2 - pbox->x1, 1); 334706f2543Smrg } else { 335706f2543Smrg /* 336706f2543Smrg * xdir = -1, ydir = 1. 337706f2543Smrg * Perform line-by-line xdir = ydir = -1 blits, going down. 338706f2543Smrg */ 339706f2543Smrg int i; 340706f2543Smrg if (dirsetup != -1) { 341706f2543Smrg if (dirsetup != 0) 342706f2543Smrg pExaScr->info->DoneCopy(pDstPixmap); 343706f2543Smrg dirsetup = -1; 344706f2543Smrg if (!(*pExaScr->info->PrepareCopy)(pSrcPixmap, 345706f2543Smrg pDstPixmap, 346706f2543Smrg -1, -1, 347706f2543Smrg pGC ? pGC->alu : GXcopy, 348706f2543Smrg pGC ? pGC->planemask : 349706f2543Smrg FB_ALLONES)) 350706f2543Smrg return FALSE; 351706f2543Smrg } 352706f2543Smrg for (i = 0; i < pbox->y2 - pbox->y1; i++) 353706f2543Smrg (*pExaScr->info->Copy)(pDstPixmap, 354706f2543Smrg src_off_x + pbox->x1 + dx, 355706f2543Smrg src_off_y + pbox->y1 + dy + i, 356706f2543Smrg dst_off_x + pbox->x1, 357706f2543Smrg dst_off_y + pbox->y1 + i, 358706f2543Smrg pbox->x2 - pbox->x1, 1); 359706f2543Smrg } 360706f2543Smrg } 361706f2543Smrg if (dirsetup != 0) 362706f2543Smrg pExaScr->info->DoneCopy(pDstPixmap); 363706f2543Smrg exaMarkSync(pDstDrawable->pScreen); 364706f2543Smrg return TRUE; 365706f2543Smrg} 366706f2543Smrg 367706f2543SmrgBool 368706f2543SmrgexaHWCopyNtoN (DrawablePtr pSrcDrawable, 369706f2543Smrg DrawablePtr pDstDrawable, 370706f2543Smrg GCPtr pGC, 371706f2543Smrg BoxPtr pbox, 372706f2543Smrg int nbox, 373706f2543Smrg int dx, 374706f2543Smrg int dy, 375706f2543Smrg Bool reverse, 376706f2543Smrg Bool upsidedown) 377706f2543Smrg{ 378706f2543Smrg ExaScreenPriv (pDstDrawable->pScreen); 379706f2543Smrg PixmapPtr pSrcPixmap, pDstPixmap; 380706f2543Smrg ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap; 381706f2543Smrg int src_off_x, src_off_y; 382706f2543Smrg int dst_off_x, dst_off_y; 383706f2543Smrg RegionPtr srcregion = NULL, dstregion = NULL; 384706f2543Smrg xRectangle *rects; 385706f2543Smrg Bool ret = TRUE; 386706f2543Smrg 387706f2543Smrg /* avoid doing copy operations if no boxes */ 388706f2543Smrg if (nbox == 0) 389706f2543Smrg return TRUE; 390706f2543Smrg 391706f2543Smrg pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); 392706f2543Smrg pDstPixmap = exaGetDrawablePixmap (pDstDrawable); 393706f2543Smrg 394706f2543Smrg exaGetDrawableDeltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); 395706f2543Smrg exaGetDrawableDeltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); 396706f2543Smrg 397706f2543Smrg rects = malloc(nbox * sizeof(xRectangle)); 398706f2543Smrg 399706f2543Smrg if (rects) { 400706f2543Smrg int i; 401706f2543Smrg int ordering; 402706f2543Smrg 403706f2543Smrg for (i = 0; i < nbox; i++) { 404706f2543Smrg rects[i].x = pbox[i].x1 + dx + src_off_x; 405706f2543Smrg rects[i].y = pbox[i].y1 + dy + src_off_y; 406706f2543Smrg rects[i].width = pbox[i].x2 - pbox[i].x1; 407706f2543Smrg rects[i].height = pbox[i].y2 - pbox[i].y1; 408706f2543Smrg } 409706f2543Smrg 410706f2543Smrg /* This must match the RegionCopy() logic for reversing rect order */ 411706f2543Smrg if (nbox == 1 || (dx > 0 && dy > 0) || 412706f2543Smrg (pDstDrawable != pSrcDrawable && 413706f2543Smrg (pDstDrawable->type != DRAWABLE_WINDOW || 414706f2543Smrg pSrcDrawable->type != DRAWABLE_WINDOW))) 415706f2543Smrg ordering = CT_YXBANDED; 416706f2543Smrg else 417706f2543Smrg ordering = CT_UNSORTED; 418706f2543Smrg 419706f2543Smrg srcregion = RegionFromRects(nbox, rects, ordering); 420706f2543Smrg free(rects); 421706f2543Smrg 422706f2543Smrg if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask, 423706f2543Smrg pGC->fillStyle, pGC->alu, 424706f2543Smrg pGC->clientClipType)) { 425706f2543Smrg dstregion = RegionCreate(NullBox, 0); 426706f2543Smrg RegionCopy(dstregion, srcregion); 427706f2543Smrg RegionTranslate(dstregion, dst_off_x - dx - src_off_x, 428706f2543Smrg dst_off_y - dy - src_off_y); 429706f2543Smrg } 430706f2543Smrg } 431706f2543Smrg 432706f2543Smrg 433706f2543Smrg pSrcExaPixmap = ExaGetPixmapPriv (pSrcPixmap); 434706f2543Smrg pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap); 435706f2543Smrg 436706f2543Smrg /* Check whether the accelerator can use this pixmap. 437706f2543Smrg * If the pitch of the pixmaps is out of range, there's nothing 438706f2543Smrg * we can do but fall back to software rendering. 439706f2543Smrg */ 440706f2543Smrg if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH || 441706f2543Smrg pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH) 442706f2543Smrg goto fallback; 443706f2543Smrg 444706f2543Smrg /* If the width or the height of either of the pixmaps 445706f2543Smrg * is out of range, check whether the boxes are actually out of the 446706f2543Smrg * addressable range as well. If they aren't, we can still do 447706f2543Smrg * the copying in hardware. 448706f2543Smrg */ 449706f2543Smrg if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) { 450706f2543Smrg int i; 451706f2543Smrg 452706f2543Smrg for (i = 0; i < nbox; i++) { 453706f2543Smrg /* src */ 454706f2543Smrg if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX || 455706f2543Smrg (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY) 456706f2543Smrg goto fallback; 457706f2543Smrg 458706f2543Smrg /* dst */ 459706f2543Smrg if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX || 460706f2543Smrg (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY) 461706f2543Smrg goto fallback; 462706f2543Smrg } 463706f2543Smrg } 464706f2543Smrg 465706f2543Smrg if (pExaScr->do_migration) { 466706f2543Smrg ExaMigrationRec pixmaps[2]; 467706f2543Smrg 468706f2543Smrg pixmaps[0].as_dst = TRUE; 469706f2543Smrg pixmaps[0].as_src = FALSE; 470706f2543Smrg pixmaps[0].pPix = pDstPixmap; 471706f2543Smrg pixmaps[0].pReg = dstregion; 472706f2543Smrg pixmaps[1].as_dst = FALSE; 473706f2543Smrg pixmaps[1].as_src = TRUE; 474706f2543Smrg pixmaps[1].pPix = pSrcPixmap; 475706f2543Smrg pixmaps[1].pReg = srcregion; 476706f2543Smrg 477706f2543Smrg exaDoMigration (pixmaps, 2, TRUE); 478706f2543Smrg } 479706f2543Smrg 480706f2543Smrg /* Mixed directions must be handled specially if the card is lame */ 481706f2543Smrg if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) && 482706f2543Smrg reverse != upsidedown) { 483706f2543Smrg if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, 484706f2543Smrg dx, dy)) 485706f2543Smrg goto out; 486706f2543Smrg goto fallback; 487706f2543Smrg } 488706f2543Smrg 489706f2543Smrg if (exaPixmapHasGpuCopy(pDstPixmap)) { 490706f2543Smrg /* Normal blitting. */ 491706f2543Smrg if (exaPixmapHasGpuCopy(pSrcPixmap)) { 492706f2543Smrg if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, 493706f2543Smrg upsidedown ? -1 : 1, 494706f2543Smrg pGC ? pGC->alu : GXcopy, 495706f2543Smrg pGC ? pGC->planemask : FB_ALLONES)) { 496706f2543Smrg goto fallback; 497706f2543Smrg } 498706f2543Smrg 499706f2543Smrg while (nbox--) 500706f2543Smrg { 501706f2543Smrg (*pExaScr->info->Copy) (pDstPixmap, 502706f2543Smrg pbox->x1 + dx + src_off_x, 503706f2543Smrg pbox->y1 + dy + src_off_y, 504706f2543Smrg pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, 505706f2543Smrg pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); 506706f2543Smrg pbox++; 507706f2543Smrg } 508706f2543Smrg 509706f2543Smrg (*pExaScr->info->DoneCopy) (pDstPixmap); 510706f2543Smrg exaMarkSync (pDstDrawable->pScreen); 511706f2543Smrg /* UTS: mainly for SHM PutImage's secondary path. 512706f2543Smrg * 513706f2543Smrg * Only taking this path for directly accessible pixmaps. 514706f2543Smrg */ 515706f2543Smrg } else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) { 516706f2543Smrg int bpp = pSrcDrawable->bitsPerPixel; 517706f2543Smrg int src_stride = exaGetPixmapPitch(pSrcPixmap); 518706f2543Smrg CARD8 *src = NULL; 519706f2543Smrg 520706f2543Smrg if (!pExaScr->info->UploadToScreen) 521706f2543Smrg goto fallback; 522706f2543Smrg 523706f2543Smrg if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) 524706f2543Smrg goto fallback; 525706f2543Smrg 526706f2543Smrg if (pSrcDrawable->bitsPerPixel < 8) 527706f2543Smrg goto fallback; 528706f2543Smrg 529706f2543Smrg if (pGC && !(pGC->alu == GXcopy && EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask))) 530706f2543Smrg goto fallback; 531706f2543Smrg 532706f2543Smrg while (nbox--) 533706f2543Smrg { 534706f2543Smrg src = pSrcExaPixmap->sys_ptr + (pbox->y1 + dy + src_off_y) * src_stride + (pbox->x1 + dx + src_off_x) * (bpp / 8); 535706f2543Smrg if (!pExaScr->info->UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x, 536706f2543Smrg pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, 537706f2543Smrg (char *) src, src_stride)) 538706f2543Smrg goto fallback; 539706f2543Smrg 540706f2543Smrg pbox++; 541706f2543Smrg } 542706f2543Smrg } else 543706f2543Smrg goto fallback; 544706f2543Smrg } else 545706f2543Smrg goto fallback; 546706f2543Smrg 547706f2543Smrg goto out; 548706f2543Smrg 549706f2543Smrgfallback: 550706f2543Smrg ret = FALSE; 551706f2543Smrg 552706f2543Smrgout: 553706f2543Smrg if (dstregion) { 554706f2543Smrg RegionUninit(dstregion); 555706f2543Smrg RegionDestroy(dstregion); 556706f2543Smrg } 557706f2543Smrg if (srcregion) { 558706f2543Smrg RegionUninit(srcregion); 559706f2543Smrg RegionDestroy(srcregion); 560706f2543Smrg } 561706f2543Smrg 562706f2543Smrg return ret; 563706f2543Smrg} 564706f2543Smrg 565706f2543Smrgvoid 566706f2543SmrgexaCopyNtoN (DrawablePtr pSrcDrawable, 567706f2543Smrg DrawablePtr pDstDrawable, 568706f2543Smrg GCPtr pGC, 569706f2543Smrg BoxPtr pbox, 570706f2543Smrg int nbox, 571706f2543Smrg int dx, 572706f2543Smrg int dy, 573706f2543Smrg Bool reverse, 574706f2543Smrg Bool upsidedown, 575706f2543Smrg Pixel bitplane, 576706f2543Smrg void *closure) 577706f2543Smrg{ 578706f2543Smrg ExaScreenPriv(pDstDrawable->pScreen); 579706f2543Smrg 580706f2543Smrg if (pExaScr->fallback_counter || 581706f2543Smrg (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW)) 582706f2543Smrg return; 583706f2543Smrg 584706f2543Smrg if (exaHWCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown)) 585706f2543Smrg return; 586706f2543Smrg 587706f2543Smrg /* This is a CopyWindow, it's cleaner to fallback at the original call. */ 588706f2543Smrg if (pExaScr->fallback_flags & EXA_ACCEL_COPYWINDOW) { 589706f2543Smrg pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; 590706f2543Smrg return; 591706f2543Smrg } 592706f2543Smrg 593706f2543Smrg /* fallback */ 594706f2543Smrg ExaCheckCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure); 595706f2543Smrg} 596706f2543Smrg 597706f2543SmrgRegionPtr 598706f2543SmrgexaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, 599706f2543Smrg int srcx, int srcy, int width, int height, int dstx, int dsty) 600706f2543Smrg{ 601706f2543Smrg ExaScreenPriv (pDstDrawable->pScreen); 602706f2543Smrg 603706f2543Smrg if (pExaScr->fallback_counter || pExaScr->swappedOut) { 604706f2543Smrg return ExaCheckCopyArea(pSrcDrawable, pDstDrawable, pGC, 605706f2543Smrg srcx, srcy, width, height, dstx, dsty); 606706f2543Smrg } 607706f2543Smrg 608706f2543Smrg return miDoCopy (pSrcDrawable, pDstDrawable, pGC, 609706f2543Smrg srcx, srcy, width, height, 610706f2543Smrg dstx, dsty, exaCopyNtoN, 0, NULL); 611706f2543Smrg} 612706f2543Smrg 613706f2543Smrgstatic void 614706f2543SmrgexaPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 615706f2543Smrg DDXPointPtr ppt) 616706f2543Smrg{ 617706f2543Smrg ExaScreenPriv (pDrawable->pScreen); 618706f2543Smrg int i; 619706f2543Smrg xRectangle *prect; 620706f2543Smrg 621706f2543Smrg /* If we can't reuse the current GC as is, don't bother accelerating the 622706f2543Smrg * points. 623706f2543Smrg */ 624706f2543Smrg if (pExaScr->fallback_counter || pGC->fillStyle != FillSolid) { 625706f2543Smrg ExaCheckPolyPoint(pDrawable, pGC, mode, npt, ppt); 626706f2543Smrg return; 627706f2543Smrg } 628706f2543Smrg 629706f2543Smrg prect = malloc(sizeof(xRectangle) * npt); 630706f2543Smrg for (i = 0; i < npt; i++) { 631706f2543Smrg prect[i].x = ppt[i].x; 632706f2543Smrg prect[i].y = ppt[i].y; 633706f2543Smrg if (i > 0 && mode == CoordModePrevious) { 634706f2543Smrg prect[i].x += prect[i - 1].x; 635706f2543Smrg prect[i].y += prect[i - 1].y; 636706f2543Smrg } 637706f2543Smrg prect[i].width = 1; 638706f2543Smrg prect[i].height = 1; 639706f2543Smrg } 640706f2543Smrg pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); 641706f2543Smrg free(prect); 642706f2543Smrg} 643706f2543Smrg 644706f2543Smrg/** 645706f2543Smrg * exaPolylines() checks if it can accelerate the lines as a group of 646706f2543Smrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill 647706f2543Smrg * acceleration if so. 648706f2543Smrg */ 649706f2543Smrgstatic void 650706f2543SmrgexaPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, 651706f2543Smrg DDXPointPtr ppt) 652706f2543Smrg{ 653706f2543Smrg ExaScreenPriv (pDrawable->pScreen); 654706f2543Smrg xRectangle *prect; 655706f2543Smrg int x1, x2, y1, y2; 656706f2543Smrg int i; 657706f2543Smrg 658706f2543Smrg if (pExaScr->fallback_counter) { 659706f2543Smrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 660706f2543Smrg return; 661706f2543Smrg } 662706f2543Smrg 663706f2543Smrg /* Don't try to do wide lines or non-solid fill style. */ 664706f2543Smrg if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || 665706f2543Smrg pGC->fillStyle != FillSolid) { 666706f2543Smrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 667706f2543Smrg return; 668706f2543Smrg } 669706f2543Smrg 670706f2543Smrg prect = malloc(sizeof(xRectangle) * (npt - 1)); 671706f2543Smrg x1 = ppt[0].x; 672706f2543Smrg y1 = ppt[0].y; 673706f2543Smrg /* If we have any non-horizontal/vertical, fall back. */ 674706f2543Smrg for (i = 0; i < npt - 1; i++) { 675706f2543Smrg if (mode == CoordModePrevious) { 676706f2543Smrg x2 = x1 + ppt[i + 1].x; 677706f2543Smrg y2 = y1 + ppt[i + 1].y; 678706f2543Smrg } else { 679706f2543Smrg x2 = ppt[i + 1].x; 680706f2543Smrg y2 = ppt[i + 1].y; 681706f2543Smrg } 682706f2543Smrg 683706f2543Smrg if (x1 != x2 && y1 != y2) { 684706f2543Smrg free(prect); 685706f2543Smrg ExaCheckPolylines(pDrawable, pGC, mode, npt, ppt); 686706f2543Smrg return; 687706f2543Smrg } 688706f2543Smrg 689706f2543Smrg if (x1 < x2) { 690706f2543Smrg prect[i].x = x1; 691706f2543Smrg prect[i].width = x2 - x1 + 1; 692706f2543Smrg } else { 693706f2543Smrg prect[i].x = x2; 694706f2543Smrg prect[i].width = x1 - x2 + 1; 695706f2543Smrg } 696706f2543Smrg if (y1 < y2) { 697706f2543Smrg prect[i].y = y1; 698706f2543Smrg prect[i].height = y2 - y1 + 1; 699706f2543Smrg } else { 700706f2543Smrg prect[i].y = y2; 701706f2543Smrg prect[i].height = y1 - y2 + 1; 702706f2543Smrg } 703706f2543Smrg 704706f2543Smrg x1 = x2; 705706f2543Smrg y1 = y2; 706706f2543Smrg } 707706f2543Smrg pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); 708706f2543Smrg free(prect); 709706f2543Smrg} 710706f2543Smrg 711706f2543Smrg/** 712706f2543Smrg * exaPolySegment() checks if it can accelerate the lines as a group of 713706f2543Smrg * horizontal or vertical lines (rectangles), and uses existing rectangle fill 714706f2543Smrg * acceleration if so. 715706f2543Smrg */ 716706f2543Smrgstatic void 717706f2543SmrgexaPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, 718706f2543Smrg xSegment *pSeg) 719706f2543Smrg{ 720706f2543Smrg ExaScreenPriv (pDrawable->pScreen); 721706f2543Smrg xRectangle *prect; 722706f2543Smrg int i; 723706f2543Smrg 724706f2543Smrg /* Don't try to do wide lines or non-solid fill style. */ 725706f2543Smrg if (pExaScr->fallback_counter || pGC->lineWidth != 0 || 726706f2543Smrg pGC->lineStyle != LineSolid || pGC->fillStyle != FillSolid) 727706f2543Smrg { 728706f2543Smrg ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 729706f2543Smrg return; 730706f2543Smrg } 731706f2543Smrg 732706f2543Smrg /* If we have any non-horizontal/vertical, fall back. */ 733706f2543Smrg for (i = 0; i < nseg; i++) { 734706f2543Smrg if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { 735706f2543Smrg ExaCheckPolySegment(pDrawable, pGC, nseg, pSeg); 736706f2543Smrg return; 737706f2543Smrg } 738706f2543Smrg } 739706f2543Smrg 740706f2543Smrg prect = malloc(sizeof(xRectangle) * nseg); 741706f2543Smrg for (i = 0; i < nseg; i++) { 742706f2543Smrg if (pSeg[i].x1 < pSeg[i].x2) { 743706f2543Smrg prect[i].x = pSeg[i].x1; 744706f2543Smrg prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; 745706f2543Smrg } else { 746706f2543Smrg prect[i].x = pSeg[i].x2; 747706f2543Smrg prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; 748706f2543Smrg } 749706f2543Smrg if (pSeg[i].y1 < pSeg[i].y2) { 750706f2543Smrg prect[i].y = pSeg[i].y1; 751706f2543Smrg prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; 752706f2543Smrg } else { 753706f2543Smrg prect[i].y = pSeg[i].y2; 754706f2543Smrg prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; 755706f2543Smrg } 756706f2543Smrg 757706f2543Smrg /* don't paint last pixel */ 758706f2543Smrg if (pGC->capStyle == CapNotLast) { 759706f2543Smrg if (prect[i].width == 1) 760706f2543Smrg prect[i].height--; 761706f2543Smrg else 762706f2543Smrg prect[i].width--; 763706f2543Smrg } 764706f2543Smrg } 765706f2543Smrg pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); 766706f2543Smrg free(prect); 767706f2543Smrg} 768706f2543Smrg 769706f2543Smrgstatic Bool exaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, 770706f2543Smrg Pixel pixel, CARD32 planemask, CARD32 alu, 771706f2543Smrg unsigned int clientClipType); 772706f2543Smrg 773706f2543Smrgstatic void 774706f2543SmrgexaPolyFillRect(DrawablePtr pDrawable, 775706f2543Smrg GCPtr pGC, 776706f2543Smrg int nrect, 777706f2543Smrg xRectangle *prect) 778706f2543Smrg{ 779706f2543Smrg ExaScreenPriv (pDrawable->pScreen); 780706f2543Smrg RegionPtr pClip = fbGetCompositeClip(pGC); 781706f2543Smrg PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); 782706f2543Smrg ExaPixmapPriv (pPixmap); 783706f2543Smrg register BoxPtr pbox; 784706f2543Smrg BoxPtr pextent; 785706f2543Smrg int extentX1, extentX2, extentY1, extentY2; 786706f2543Smrg int fullX1, fullX2, fullY1, fullY2; 787706f2543Smrg int partX1, partX2, partY1, partY2; 788706f2543Smrg int xoff, yoff; 789706f2543Smrg int xorg, yorg; 790706f2543Smrg int n; 791706f2543Smrg RegionPtr pReg = RegionFromRects(nrect, prect, CT_UNSORTED); 792706f2543Smrg 793706f2543Smrg /* Compute intersection of rects and clip region */ 794706f2543Smrg RegionTranslate(pReg, pDrawable->x, pDrawable->y); 795706f2543Smrg RegionIntersect(pReg, pClip, pReg); 796706f2543Smrg 797706f2543Smrg if (!RegionNumRects(pReg)) { 798706f2543Smrg goto out; 799706f2543Smrg } 800706f2543Smrg 801706f2543Smrg exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 802706f2543Smrg 803706f2543Smrg if (pExaScr->fallback_counter || pExaScr->swappedOut || 804706f2543Smrg pExaPixmap->accel_blocked) 805706f2543Smrg { 806706f2543Smrg goto fallback; 807706f2543Smrg } 808706f2543Smrg 809706f2543Smrg /* For ROPs where overlaps don't matter, convert rectangles to region and 810706f2543Smrg * call exaFillRegion{Solid,Tiled}. 811706f2543Smrg */ 812706f2543Smrg if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && 813706f2543Smrg (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || 814706f2543Smrg pGC->alu == GXnoop || pGC->alu == GXcopyInverted || 815706f2543Smrg pGC->alu == GXset)) { 816706f2543Smrg if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && 817706f2543Smrg exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ? 818706f2543Smrg pGC->fgPixel : pGC->tile.pixel, pGC->planemask, 819706f2543Smrg pGC->alu, pGC->clientClipType)) || 820706f2543Smrg (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && 821706f2543Smrg exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, 822706f2543Smrg pGC->planemask, pGC->alu, 823706f2543Smrg pGC->clientClipType))) { 824706f2543Smrg goto out; 825706f2543Smrg } 826706f2543Smrg } 827706f2543Smrg 828706f2543Smrg if (pGC->fillStyle != FillSolid && 829706f2543Smrg !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) 830706f2543Smrg { 831706f2543Smrg goto fallback; 832706f2543Smrg } 833706f2543Smrg 834706f2543Smrg if (pExaScr->do_migration) { 835706f2543Smrg ExaMigrationRec pixmaps[1]; 836706f2543Smrg 837706f2543Smrg pixmaps[0].as_dst = TRUE; 838706f2543Smrg pixmaps[0].as_src = FALSE; 839706f2543Smrg pixmaps[0].pPix = pPixmap; 840706f2543Smrg pixmaps[0].pReg = NULL; 841706f2543Smrg 842706f2543Smrg exaDoMigration (pixmaps, 1, TRUE); 843706f2543Smrg } 844706f2543Smrg 845706f2543Smrg if (!exaPixmapHasGpuCopy (pPixmap) || 846706f2543Smrg !(*pExaScr->info->PrepareSolid) (pPixmap, 847706f2543Smrg pGC->alu, 848706f2543Smrg pGC->planemask, 849706f2543Smrg pGC->fgPixel)) 850706f2543Smrg { 851706f2543Smrgfallback: 852706f2543Smrg ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); 853706f2543Smrg goto out; 854706f2543Smrg } 855706f2543Smrg 856706f2543Smrg xorg = pDrawable->x; 857706f2543Smrg yorg = pDrawable->y; 858706f2543Smrg 859706f2543Smrg pextent = RegionExtents(pClip); 860706f2543Smrg extentX1 = pextent->x1; 861706f2543Smrg extentY1 = pextent->y1; 862706f2543Smrg extentX2 = pextent->x2; 863706f2543Smrg extentY2 = pextent->y2; 864706f2543Smrg while (nrect--) 865706f2543Smrg { 866706f2543Smrg fullX1 = prect->x + xorg; 867706f2543Smrg fullY1 = prect->y + yorg; 868706f2543Smrg fullX2 = fullX1 + (int) prect->width; 869706f2543Smrg fullY2 = fullY1 + (int) prect->height; 870706f2543Smrg prect++; 871706f2543Smrg 872706f2543Smrg if (fullX1 < extentX1) 873706f2543Smrg fullX1 = extentX1; 874706f2543Smrg 875706f2543Smrg if (fullY1 < extentY1) 876706f2543Smrg fullY1 = extentY1; 877706f2543Smrg 878706f2543Smrg if (fullX2 > extentX2) 879706f2543Smrg fullX2 = extentX2; 880706f2543Smrg 881706f2543Smrg if (fullY2 > extentY2) 882706f2543Smrg fullY2 = extentY2; 883706f2543Smrg 884706f2543Smrg if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) 885706f2543Smrg continue; 886706f2543Smrg n = RegionNumRects (pClip); 887706f2543Smrg if (n == 1) 888706f2543Smrg { 889706f2543Smrg (*pExaScr->info->Solid) (pPixmap, 890706f2543Smrg fullX1 + xoff, fullY1 + yoff, 891706f2543Smrg fullX2 + xoff, fullY2 + yoff); 892706f2543Smrg } 893706f2543Smrg else 894706f2543Smrg { 895706f2543Smrg pbox = RegionRects(pClip); 896706f2543Smrg /* 897706f2543Smrg * clip the rectangle to each box in the clip region 898706f2543Smrg * this is logically equivalent to calling Intersect(), 899706f2543Smrg * but rectangles may overlap each other here. 900706f2543Smrg */ 901706f2543Smrg while(n--) 902706f2543Smrg { 903706f2543Smrg partX1 = pbox->x1; 904706f2543Smrg if (partX1 < fullX1) 905706f2543Smrg partX1 = fullX1; 906706f2543Smrg partY1 = pbox->y1; 907706f2543Smrg if (partY1 < fullY1) 908706f2543Smrg partY1 = fullY1; 909706f2543Smrg partX2 = pbox->x2; 910706f2543Smrg if (partX2 > fullX2) 911706f2543Smrg partX2 = fullX2; 912706f2543Smrg partY2 = pbox->y2; 913706f2543Smrg if (partY2 > fullY2) 914706f2543Smrg partY2 = fullY2; 915706f2543Smrg 916706f2543Smrg pbox++; 917706f2543Smrg 918706f2543Smrg if (partX1 < partX2 && partY1 < partY2) { 919706f2543Smrg (*pExaScr->info->Solid) (pPixmap, 920706f2543Smrg partX1 + xoff, partY1 + yoff, 921706f2543Smrg partX2 + xoff, partY2 + yoff); 922706f2543Smrg } 923706f2543Smrg } 924706f2543Smrg } 925706f2543Smrg } 926706f2543Smrg (*pExaScr->info->DoneSolid) (pPixmap); 927706f2543Smrg exaMarkSync(pDrawable->pScreen); 928706f2543Smrg 929706f2543Smrgout: 930706f2543Smrg RegionUninit(pReg); 931706f2543Smrg RegionDestroy(pReg); 932706f2543Smrg} 933706f2543Smrg 934706f2543Smrgconst GCOps exaOps = { 935706f2543Smrg exaFillSpans, 936706f2543Smrg ExaCheckSetSpans, 937706f2543Smrg exaPutImage, 938706f2543Smrg exaCopyArea, 939706f2543Smrg ExaCheckCopyPlane, 940706f2543Smrg exaPolyPoint, 941706f2543Smrg exaPolylines, 942706f2543Smrg exaPolySegment, 943706f2543Smrg miPolyRectangle, 944706f2543Smrg ExaCheckPolyArc, 945706f2543Smrg miFillPolygon, 946706f2543Smrg exaPolyFillRect, 947706f2543Smrg miPolyFillArc, 948706f2543Smrg miPolyText8, 949706f2543Smrg miPolyText16, 950706f2543Smrg miImageText8, 951706f2543Smrg miImageText16, 952706f2543Smrg ExaCheckImageGlyphBlt, 953706f2543Smrg ExaCheckPolyGlyphBlt, 954706f2543Smrg ExaCheckPushPixels, 955706f2543Smrg}; 956706f2543Smrg 957706f2543Smrgvoid 958706f2543SmrgexaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 959706f2543Smrg{ 960706f2543Smrg RegionRec rgnDst; 961706f2543Smrg int dx, dy; 962706f2543Smrg PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); 963706f2543Smrg ExaScreenPriv(pWin->drawable.pScreen); 964706f2543Smrg 965706f2543Smrg dx = ptOldOrg.x - pWin->drawable.x; 966706f2543Smrg dy = ptOldOrg.y - pWin->drawable.y; 967706f2543Smrg RegionTranslate(prgnSrc, -dx, -dy); 968706f2543Smrg 969706f2543Smrg RegionInit(&rgnDst, NullBox, 0); 970706f2543Smrg 971706f2543Smrg RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc); 972706f2543Smrg#ifdef COMPOSITE 973706f2543Smrg if (pPixmap->screen_x || pPixmap->screen_y) 974706f2543Smrg RegionTranslate(&rgnDst, 975706f2543Smrg -pPixmap->screen_x, -pPixmap->screen_y); 976706f2543Smrg#endif 977706f2543Smrg 978706f2543Smrg if (pExaScr->fallback_counter) { 979706f2543Smrg pExaScr->fallback_flags |= EXA_FALLBACK_COPYWINDOW; 980706f2543Smrg goto fallback; 981706f2543Smrg } 982706f2543Smrg 983706f2543Smrg pExaScr->fallback_flags |= EXA_ACCEL_COPYWINDOW; 984706f2543Smrg miCopyRegion (&pPixmap->drawable, &pPixmap->drawable, 985706f2543Smrg NULL, 986706f2543Smrg &rgnDst, dx, dy, exaCopyNtoN, 0, NULL); 987706f2543Smrg pExaScr->fallback_flags &= ~EXA_ACCEL_COPYWINDOW; 988706f2543Smrg 989706f2543Smrgfallback: 990706f2543Smrg RegionUninit(&rgnDst); 991706f2543Smrg 992706f2543Smrg if (pExaScr->fallback_flags & EXA_FALLBACK_COPYWINDOW) { 993706f2543Smrg pExaScr->fallback_flags &= ~EXA_FALLBACK_COPYWINDOW; 994706f2543Smrg RegionTranslate(prgnSrc, dx, dy); 995706f2543Smrg ExaCheckCopyWindow(pWin, ptOldOrg, prgnSrc); 996706f2543Smrg } 997706f2543Smrg} 998706f2543Smrg 999706f2543Smrgstatic Bool 1000706f2543SmrgexaFillRegionSolid (DrawablePtr pDrawable, RegionPtr pRegion, Pixel pixel, 1001706f2543Smrg CARD32 planemask, CARD32 alu, unsigned int clientClipType) 1002706f2543Smrg{ 1003706f2543Smrg ExaScreenPriv(pDrawable->pScreen); 1004706f2543Smrg PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); 1005706f2543Smrg ExaPixmapPriv (pPixmap); 1006706f2543Smrg int xoff, yoff; 1007706f2543Smrg Bool ret = FALSE; 1008706f2543Smrg 1009706f2543Smrg exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); 1010706f2543Smrg RegionTranslate(pRegion, xoff, yoff); 1011706f2543Smrg 1012706f2543Smrg if (pExaScr->fallback_counter || pExaPixmap->accel_blocked) 1013706f2543Smrg goto out; 1014706f2543Smrg 1015706f2543Smrg if (pExaScr->do_migration) { 1016706f2543Smrg ExaMigrationRec pixmaps[1]; 1017706f2543Smrg 1018706f2543Smrg pixmaps[0].as_dst = TRUE; 1019706f2543Smrg pixmaps[0].as_src = FALSE; 1020706f2543Smrg pixmaps[0].pPix = pPixmap; 1021706f2543Smrg pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid, 1022706f2543Smrg alu, clientClipType) ? NULL : pRegion; 1023706f2543Smrg 1024706f2543Smrg exaDoMigration (pixmaps, 1, TRUE); 1025706f2543Smrg } 1026706f2543Smrg 1027706f2543Smrg if (exaPixmapHasGpuCopy (pPixmap) && 1028706f2543Smrg (*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) 1029706f2543Smrg { 1030706f2543Smrg int nbox; 1031706f2543Smrg BoxPtr pBox; 1032706f2543Smrg 1033706f2543Smrg nbox = RegionNumRects (pRegion); 1034706f2543Smrg pBox = RegionRects (pRegion); 1035706f2543Smrg 1036706f2543Smrg while (nbox--) 1037706f2543Smrg { 1038706f2543Smrg (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, 1039706f2543Smrg pBox->y2); 1040706f2543Smrg pBox++; 1041706f2543Smrg } 1042706f2543Smrg (*pExaScr->info->DoneSolid) (pPixmap); 1043706f2543Smrg exaMarkSync(pDrawable->pScreen); 1044706f2543Smrg 1045706f2543Smrg if (pExaPixmap->pDamage && 1046706f2543Smrg pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP && 1047706f2543Smrg pDrawable->width == 1 && pDrawable->height == 1 && 1048706f2543Smrg pDrawable->bitsPerPixel != 24) { 1049706f2543Smrg ExaPixmapPriv(pPixmap); 1050706f2543Smrg RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); 1051706f2543Smrg 1052706f2543Smrg switch (pDrawable->bitsPerPixel) { 1053706f2543Smrg case 32: 1054706f2543Smrg *(CARD32*)pExaPixmap->sys_ptr = pixel; 1055706f2543Smrg break; 1056706f2543Smrg case 16: 1057706f2543Smrg *(CARD16*)pExaPixmap->sys_ptr = pixel; 1058706f2543Smrg break; 1059706f2543Smrg case 8: 1060706f2543Smrg case 4: 1061706f2543Smrg case 1: 1062706f2543Smrg *(CARD8*)pExaPixmap->sys_ptr = pixel; 1063706f2543Smrg } 1064706f2543Smrg 1065706f2543Smrg RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, 1066706f2543Smrg pRegion); 1067706f2543Smrg RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, 1068706f2543Smrg pRegion); 1069706f2543Smrg RegionSubtract(pending_damage, pending_damage, pRegion); 1070706f2543Smrg } 1071706f2543Smrg 1072706f2543Smrg ret = TRUE; 1073706f2543Smrg } 1074706f2543Smrg 1075706f2543Smrgout: 1076706f2543Smrg RegionTranslate(pRegion, -xoff, -yoff); 1077706f2543Smrg 1078706f2543Smrg return ret; 1079706f2543Smrg} 1080706f2543Smrg 1081706f2543Smrg/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. 1082706f2543Smrg * Based on fbFillRegionTiled(), fbTile(). 1083706f2543Smrg */ 1084706f2543SmrgBool 1085706f2543SmrgexaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, 1086706f2543Smrg DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, 1087706f2543Smrg unsigned int clientClipType) 1088706f2543Smrg{ 1089706f2543Smrg ExaScreenPriv(pDrawable->pScreen); 1090706f2543Smrg PixmapPtr pPixmap; 1091706f2543Smrg ExaPixmapPrivPtr pExaPixmap; 1092706f2543Smrg ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); 1093706f2543Smrg int xoff, yoff; 1094706f2543Smrg int tileWidth, tileHeight; 1095706f2543Smrg int nbox = RegionNumRects (pRegion); 1096706f2543Smrg BoxPtr pBox = RegionRects (pRegion); 1097706f2543Smrg Bool ret = FALSE; 1098706f2543Smrg int i; 1099706f2543Smrg 1100706f2543Smrg tileWidth = pTile->drawable.width; 1101706f2543Smrg tileHeight = pTile->drawable.height; 1102706f2543Smrg 1103706f2543Smrg /* If we're filling with a solid color, grab it out and go to 1104706f2543Smrg * FillRegionSolid, saving numerous copies. 1105706f2543Smrg */ 1106706f2543Smrg if (tileWidth == 1 && tileHeight == 1) 1107706f2543Smrg return exaFillRegionSolid(pDrawable, pRegion, 1108706f2543Smrg exaGetPixmapFirstPixel (pTile), planemask, 1109706f2543Smrg alu, clientClipType); 1110706f2543Smrg 1111706f2543Smrg pPixmap = exaGetDrawablePixmap (pDrawable); 1112706f2543Smrg pExaPixmap = ExaGetPixmapPriv (pPixmap); 1113706f2543Smrg 1114706f2543Smrg if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || 1115706f2543Smrg pTileExaPixmap->accel_blocked) 1116706f2543Smrg return FALSE; 1117706f2543Smrg 1118706f2543Smrg if (pExaScr->do_migration) { 1119706f2543Smrg ExaMigrationRec pixmaps[2]; 1120706f2543Smrg 1121706f2543Smrg pixmaps[0].as_dst = TRUE; 1122706f2543Smrg pixmaps[0].as_src = FALSE; 1123706f2543Smrg pixmaps[0].pPix = pPixmap; 1124706f2543Smrg pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, 1125706f2543Smrg alu, clientClipType) ? NULL : pRegion; 1126706f2543Smrg pixmaps[1].as_dst = FALSE; 1127706f2543Smrg pixmaps[1].as_src = TRUE; 1128706f2543Smrg pixmaps[1].pPix = pTile; 1129706f2543Smrg pixmaps[1].pReg = NULL; 1130706f2543Smrg 1131706f2543Smrg exaDoMigration (pixmaps, 2, TRUE); 1132706f2543Smrg } 1133706f2543Smrg 1134706f2543Smrg pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 1135706f2543Smrg 1136706f2543Smrg if (!pPixmap || !exaPixmapHasGpuCopy(pTile)) 1137706f2543Smrg return FALSE; 1138706f2543Smrg 1139706f2543Smrg if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) 1140706f2543Smrg { 1141706f2543Smrg if (xoff || yoff) 1142706f2543Smrg RegionTranslate(pRegion, xoff, yoff); 1143706f2543Smrg 1144706f2543Smrg for (i = 0; i < nbox; i++) 1145706f2543Smrg { 1146706f2543Smrg int height = pBox[i].y2 - pBox[i].y1; 1147706f2543Smrg int dstY = pBox[i].y1; 1148706f2543Smrg int tileY; 1149706f2543Smrg 1150706f2543Smrg if (alu == GXcopy) 1151706f2543Smrg height = min(height, tileHeight); 1152706f2543Smrg 1153706f2543Smrg modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); 1154706f2543Smrg 1155706f2543Smrg while (height > 0) { 1156706f2543Smrg int width = pBox[i].x2 - pBox[i].x1; 1157706f2543Smrg int dstX = pBox[i].x1; 1158706f2543Smrg int tileX; 1159706f2543Smrg int h = tileHeight - tileY; 1160706f2543Smrg 1161706f2543Smrg if (alu == GXcopy) 1162706f2543Smrg width = min(width, tileWidth); 1163706f2543Smrg 1164706f2543Smrg if (h > height) 1165706f2543Smrg h = height; 1166706f2543Smrg height -= h; 1167706f2543Smrg 1168706f2543Smrg modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, 1169706f2543Smrg tileX); 1170706f2543Smrg 1171706f2543Smrg while (width > 0) { 1172706f2543Smrg int w = tileWidth - tileX; 1173706f2543Smrg if (w > width) 1174706f2543Smrg w = width; 1175706f2543Smrg width -= w; 1176706f2543Smrg 1177706f2543Smrg (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, 1178706f2543Smrg w, h); 1179706f2543Smrg dstX += w; 1180706f2543Smrg tileX = 0; 1181706f2543Smrg } 1182706f2543Smrg dstY += h; 1183706f2543Smrg tileY = 0; 1184706f2543Smrg } 1185706f2543Smrg } 1186706f2543Smrg (*pExaScr->info->DoneCopy) (pPixmap); 1187706f2543Smrg 1188706f2543Smrg /* With GXcopy, we only need to do the basic algorithm up to the tile 1189706f2543Smrg * size; then, we can just keep doubling the destination in each 1190706f2543Smrg * direction until it fills the box. This way, the number of copy 1191706f2543Smrg * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where 1192706f2543Smrg * rx/ry is the ratio between box and tile width/height. This can make 1193706f2543Smrg * a big difference if each driver copy incurs a significant constant 1194706f2543Smrg * overhead. 1195706f2543Smrg */ 1196706f2543Smrg if (alu != GXcopy) 1197706f2543Smrg ret = TRUE; 1198706f2543Smrg else { 1199706f2543Smrg Bool more_copy = FALSE; 1200706f2543Smrg 1201706f2543Smrg for (i = 0; i < nbox; i++) { 1202706f2543Smrg int dstX = pBox[i].x1 + tileWidth; 1203706f2543Smrg int dstY = pBox[i].y1 + tileHeight; 1204706f2543Smrg 1205706f2543Smrg if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { 1206706f2543Smrg more_copy = TRUE; 1207706f2543Smrg break; 1208706f2543Smrg } 1209706f2543Smrg } 1210706f2543Smrg 1211706f2543Smrg if (more_copy == FALSE) 1212706f2543Smrg ret = TRUE; 1213706f2543Smrg 1214706f2543Smrg if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, 1215706f2543Smrg 1, 1, alu, planemask)) { 1216706f2543Smrg for (i = 0; i < nbox; i++) 1217706f2543Smrg { 1218706f2543Smrg int dstX = pBox[i].x1 + tileWidth; 1219706f2543Smrg int dstY = pBox[i].y1 + tileHeight; 1220706f2543Smrg int width = min(pBox[i].x2 - dstX, tileWidth); 1221706f2543Smrg int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); 1222706f2543Smrg 1223706f2543Smrg while (dstX < pBox[i].x2) { 1224706f2543Smrg (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 1225706f2543Smrg dstX, pBox[i].y1, width, height); 1226706f2543Smrg dstX += width; 1227706f2543Smrg width = min(pBox[i].x2 - dstX, width * 2); 1228706f2543Smrg } 1229706f2543Smrg 1230706f2543Smrg width = pBox[i].x2 - pBox[i].x1; 1231706f2543Smrg height = min(pBox[i].y2 - dstY, tileHeight); 1232706f2543Smrg 1233706f2543Smrg while (dstY < pBox[i].y2) { 1234706f2543Smrg (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, 1235706f2543Smrg pBox[i].x1, dstY, width, height); 1236706f2543Smrg dstY += height; 1237706f2543Smrg height = min(pBox[i].y2 - dstY, height * 2); 1238706f2543Smrg } 1239706f2543Smrg } 1240706f2543Smrg 1241706f2543Smrg (*pExaScr->info->DoneCopy) (pPixmap); 1242706f2543Smrg 1243706f2543Smrg ret = TRUE; 1244706f2543Smrg } 1245706f2543Smrg } 1246706f2543Smrg 1247706f2543Smrg exaMarkSync(pDrawable->pScreen); 1248706f2543Smrg 1249706f2543Smrg if (xoff || yoff) 1250706f2543Smrg RegionTranslate(pRegion, -xoff, -yoff); 1251706f2543Smrg } 1252706f2543Smrg 1253706f2543Smrg return ret; 1254706f2543Smrg} 1255706f2543Smrg 1256706f2543Smrg 1257706f2543Smrg/** 1258706f2543Smrg * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. 1259706f2543Smrg * 1260706f2543Smrg * This is probably the only case we actually care about. The rest fall through 1261706f2543Smrg * to migration and fbGetImage, which hopefully will result in migration pushing 1262706f2543Smrg * the pixmap out of framebuffer. 1263706f2543Smrg */ 1264706f2543Smrgvoid 1265706f2543SmrgexaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, 1266706f2543Smrg unsigned int format, unsigned long planeMask, char *d) 1267706f2543Smrg{ 1268706f2543Smrg ExaScreenPriv (pDrawable->pScreen); 1269706f2543Smrg PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); 1270706f2543Smrg ExaPixmapPriv(pPix); 1271706f2543Smrg int xoff, yoff; 1272706f2543Smrg Bool ok; 1273706f2543Smrg 1274706f2543Smrg if (pExaScr->fallback_counter || pExaScr->swappedOut) 1275706f2543Smrg goto fallback; 1276706f2543Smrg 1277706f2543Smrg /* If there's a system copy, we want to save the result there */ 1278706f2543Smrg if (pExaPixmap->pDamage) 1279706f2543Smrg goto fallback; 1280706f2543Smrg 1281706f2543Smrg pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); 1282706f2543Smrg 1283706f2543Smrg if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) 1284706f2543Smrg goto fallback; 1285706f2543Smrg 1286706f2543Smrg /* Only cover the ZPixmap, solid copy case. */ 1287706f2543Smrg if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) 1288706f2543Smrg goto fallback; 1289706f2543Smrg 1290706f2543Smrg /* Only try to handle the 8bpp and up cases, since we don't want to think 1291706f2543Smrg * about <8bpp. 1292706f2543Smrg */ 1293706f2543Smrg if (pDrawable->bitsPerPixel < 8) 1294706f2543Smrg goto fallback; 1295706f2543Smrg 1296706f2543Smrg ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, 1297706f2543Smrg pDrawable->y + y + yoff, w, h, d, 1298706f2543Smrg PixmapBytePad(w, pDrawable->depth)); 1299706f2543Smrg if (ok) { 1300706f2543Smrg exaWaitSync(pDrawable->pScreen); 1301706f2543Smrg return; 1302706f2543Smrg } 1303706f2543Smrg 1304706f2543Smrgfallback: 1305706f2543Smrg ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); 1306706f2543Smrg} 1307