/** * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. * * This is probably the only case we actually care about. The rest fall through * to migration and fbGetImage, which hopefully will result in migration pushing * the pixmap out of framebuffer. */ void exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, unsigned int format, unsigned long planeMask, char *d) { ExaScreenPriv(pDrawable->pScreen); PixmapPtr pPix = exaGetDrawablePixmap(pDrawable); ExaPixmapPriv(pPix); int xoff, yoff; Bool ok; if (pExaScr->fallback_counter || pExaScr->swappedOut) goto fallback; /* If there's a system copy, we want to save the result there */ if (pExaPixmap->pDamage) goto fallback; pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff); if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) goto fallback; /* Only cover the ZPixmap, solid copy case. */ if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) goto fallback; /* Only try to handle the 8bpp and up cases, since we don't want to think * about <8bpp. */ if (pDrawable->bitsPerPixel < 8) goto fallback; ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, pDrawable->y + y + yoff, w, h, d, PixmapBytePad(w, pDrawable->depth)); if (ok) { exaWaitSync(pDrawable->pScreen); return; } fallback: ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); }
static void exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, DDXPointPtr ppt, int *pwidth, int fSorted) { ScreenPtr pScreen = pDrawable->pScreen; ExaScreenPriv(pScreen); RegionPtr pClip = fbGetCompositeClip(pGC); PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); ExaPixmapPriv(pPixmap); BoxPtr pextent, pbox; int nbox; int extentX1, extentX2, extentY1, extentY2; int fullX1, fullX2, fullY1; int partX1, partX2; int off_x, off_y; if (pExaScr->fallback_counter || pExaScr->swappedOut || pGC->fillStyle != FillSolid || pExaPixmap->accel_blocked) { ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted); return; } if (pExaScr->do_migration) { ExaMigrationRec pixmaps[1]; pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; pixmaps[0].pPix = pPixmap; pixmaps[0].pReg = NULL; exaDoMigration(pixmaps, 1, TRUE); } if (!(pPixmap = exaGetOffscreenPixmap(pDrawable, &off_x, &off_y)) || !(*pExaScr->info->PrepareSolid) (pPixmap, pGC->alu, pGC->planemask, pGC->fgPixel)) { ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted); return; } pextent = RegionExtents(pClip); extentX1 = pextent->x1; extentY1 = pextent->y1; extentX2 = pextent->x2; extentY2 = pextent->y2; while (n--) { fullX1 = ppt->x; fullY1 = ppt->y; fullX2 = fullX1 + (int) *pwidth; ppt++; pwidth++; if (fullY1 < extentY1 || extentY2 <= fullY1) continue; if (fullX1 < extentX1) fullX1 = extentX1; if (fullX2 > extentX2) fullX2 = extentX2; if (fullX1 >= fullX2) continue; nbox = RegionNumRects(pClip); if (nbox == 1) { (*pExaScr->info->Solid) (pPixmap, fullX1 + off_x, fullY1 + off_y, fullX2 + off_x, fullY1 + 1 + off_y); } else { pbox = RegionRects(pClip); while (nbox--) { if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) { partX1 = pbox->x1; if (partX1 < fullX1) partX1 = fullX1; partX2 = pbox->x2; if (partX2 > fullX2) partX2 = fullX2; if (partX2 > partX1) { (*pExaScr->info->Solid) (pPixmap, partX1 + off_x, fullY1 + off_y, partX2 + off_x, fullY1 + 1 + off_y); } } pbox++; } } } (*pExaScr->info->DoneSolid) (pPixmap); exaMarkSync(pScreen); }
static Bool inline exaCopyNtoNTwoDir(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) { ExaScreenPriv(pDstDrawable->pScreen); PixmapPtr pSrcPixmap, pDstPixmap; int src_off_x, src_off_y, dst_off_x, dst_off_y; int dirsetup; /* Need to get both pixmaps to call the driver routines */ pSrcPixmap = exaGetOffscreenPixmap(pSrcDrawable, &src_off_x, &src_off_y); pDstPixmap = exaGetOffscreenPixmap(pDstDrawable, &dst_off_x, &dst_off_y); if (!pSrcPixmap || !pDstPixmap) return FALSE; /* * Now the case of a chip that only supports xdir = ydir = 1 or * xdir = ydir = -1, but we have xdir != ydir. */ dirsetup = 0; /* No direction set up yet. */ for (; nbox; pbox++, nbox--) { if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { /* Do a xdir = ydir = -1 blit instead. */ if (dirsetup != -1) { if (dirsetup != 0) pExaScr->info->DoneCopy(pDstPixmap); dirsetup = -1; if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, -1, -1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) return FALSE; } (*pExaScr->info->Copy) (pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy, dst_off_x + pbox->x1, dst_off_y + pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { /* Do a xdir = ydir = 1 blit instead. */ if (dirsetup != 1) { if (dirsetup != 0) pExaScr->info->DoneCopy(pDstPixmap); dirsetup = 1; if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, 1, 1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) return FALSE; } (*pExaScr->info->Copy) (pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy, dst_off_x + pbox->x1, dst_off_y + pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); } else if (dx >= 0) { /* * xdir = 1, ydir = -1. * Perform line-by-line xdir = ydir = 1 blits, going up. */ int i; if (dirsetup != 1) { if (dirsetup != 0) pExaScr->info->DoneCopy(pDstPixmap); dirsetup = 1; if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, 1, 1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) return FALSE; } for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) (*pExaScr->info->Copy) (pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy + i, dst_off_x + pbox->x1, dst_off_y + pbox->y1 + i, pbox->x2 - pbox->x1, 1); } else { /* * xdir = -1, ydir = 1. * Perform line-by-line xdir = ydir = -1 blits, going down. */ int i; if (dirsetup != -1) { if (dirsetup != 0) pExaScr->info->DoneCopy(pDstPixmap); dirsetup = -1; if (!(*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, -1, -1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) return FALSE; } for (i = 0; i < pbox->y2 - pbox->y1; i++) (*pExaScr->info->Copy) (pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy + i, dst_off_x + pbox->x1, dst_off_y + pbox->y1 + i, pbox->x2 - pbox->x1, 1); } } if (dirsetup != 0) pExaScr->info->DoneCopy(pDstPixmap); exaMarkSync(pDstDrawable->pScreen); return TRUE; }
static Bool exaDoPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int format, char *bits, int src_stride) { ExaScreenPriv(pDrawable->pScreen); PixmapPtr pPix = exaGetDrawablePixmap(pDrawable); ExaPixmapPriv(pPix); RegionPtr pClip; BoxPtr pbox; int nbox; int xoff, yoff; int bpp = pDrawable->bitsPerPixel; Bool ret = TRUE; if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || !pExaScr->info->UploadToScreen) return FALSE; /* If there's a system copy, we want to save the result there */ if (pExaPixmap->pDamage) return FALSE; /* Don't bother with under 8bpp, XYPixmaps. */ if (format != ZPixmap || bpp < 8) return FALSE; /* Only accelerate copies: no rop or planemask. */ if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) return FALSE; if (pExaScr->swappedOut) return FALSE; if (pExaScr->do_migration) { ExaMigrationRec pixmaps[1]; pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; pixmaps[0].pPix = pPix; pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage); exaDoMigration(pixmaps, 1, TRUE); } pPix = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff); if (!pPix) return FALSE; x += pDrawable->x; y += pDrawable->y; pClip = fbGetCompositeClip(pGC); for (nbox = RegionNumRects(pClip), pbox = RegionRects(pClip); nbox--; pbox++) { int x1 = x; int y1 = y; int x2 = x + w; int y2 = y + h; char *src; Bool ok; if (x1 < pbox->x1) x1 = pbox->x1; if (y1 < pbox->y1) y1 = pbox->y1; if (x2 > pbox->x2) x2 = pbox->x2; if (y2 > pbox->y2) y2 = pbox->y2; if (x1 >= x2 || y1 >= y2) continue; src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, x2 - x1, y2 - y1, src, src_stride); /* We have to fall back completely, and ignore what has already been completed. * Messing with the fb layer directly like we used to is completely unacceptable. */ if (!ok) { ret = FALSE; break; } } if (ret) exaMarkSync(pDrawable->pScreen); return ret; }
/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. * Based on fbFillRegionTiled(), fbTile(). */ Bool exaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu, Bool hasClientClip) { ExaScreenPriv(pDrawable->pScreen); PixmapPtr pPixmap; ExaPixmapPrivPtr pExaPixmap; ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile); int xoff, yoff; int tileWidth, tileHeight; int nbox = RegionNumRects(pRegion); BoxPtr pBox = RegionRects(pRegion); Bool ret = FALSE; int i; tileWidth = pTile->drawable.width; tileHeight = pTile->drawable.height; /* If we're filling with a solid color, grab it out and go to * FillRegionSolid, saving numerous copies. */ if (tileWidth == 1 && tileHeight == 1) return exaFillRegionSolid(pDrawable, pRegion, exaGetPixmapFirstPixel(pTile), planemask, alu, hasClientClip); pPixmap = exaGetDrawablePixmap(pDrawable); pExaPixmap = ExaGetPixmapPriv(pPixmap); if (pExaScr->fallback_counter || pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked) return FALSE; if (pExaScr->do_migration) { ExaMigrationRec pixmaps[2]; pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; pixmaps[0].pPix = pPixmap; pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled, alu, hasClientClip) ? NULL : pRegion; pixmaps[1].as_dst = FALSE; pixmaps[1].as_src = TRUE; pixmaps[1].pPix = pTile; pixmaps[1].pReg = NULL; exaDoMigration(pixmaps, 2, TRUE); } pPixmap = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff); if (!pPixmap || !exaPixmapHasGpuCopy(pTile)) return FALSE; if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) { if (xoff || yoff) RegionTranslate(pRegion, xoff, yoff); for (i = 0; i < nbox; i++) { int height = pBox[i].y2 - pBox[i].y1; int dstY = pBox[i].y1; int tileY; if (alu == GXcopy) height = min(height, tileHeight); modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); while (height > 0) { int width = pBox[i].x2 - pBox[i].x1; int dstX = pBox[i].x1; int tileX; int h = tileHeight - tileY; if (alu == GXcopy) width = min(width, tileWidth); if (h > height) h = height; height -= h; modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, tileX); while (width > 0) { int w = tileWidth - tileX; if (w > width) w = width; width -= w; (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, w, h); dstX += w; tileX = 0; } dstY += h; tileY = 0; } } (*pExaScr->info->DoneCopy) (pPixmap); /* With GXcopy, we only need to do the basic algorithm up to the tile * size; then, we can just keep doubling the destination in each * direction until it fills the box. This way, the number of copy * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where * rx/ry is the ratio between box and tile width/height. This can make * a big difference if each driver copy incurs a significant constant * overhead. */ if (alu != GXcopy) ret = TRUE; else { Bool more_copy = FALSE; for (i = 0; i < nbox; i++) { int dstX = pBox[i].x1 + tileWidth; int dstY = pBox[i].y1 + tileHeight; if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) { more_copy = TRUE; break; } } if (more_copy == FALSE) ret = TRUE; if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, 1, 1, alu, planemask)) { for (i = 0; i < nbox; i++) { int dstX = pBox[i].x1 + tileWidth; int dstY = pBox[i].y1 + tileHeight; int width = min(pBox[i].x2 - dstX, tileWidth); int height = min(pBox[i].y2 - pBox[i].y1, tileHeight); while (dstX < pBox[i].x2) { (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, dstX, pBox[i].y1, width, height); dstX += width; width = min(pBox[i].x2 - dstX, width * 2); } width = pBox[i].x2 - pBox[i].x1; height = min(pBox[i].y2 - dstY, tileHeight); while (dstY < pBox[i].y2) { (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1, pBox[i].x1, dstY, width, height); dstY += height; height = min(pBox[i].y2 - dstY, height * 2); } } (*pExaScr->info->DoneCopy) (pPixmap); ret = TRUE; } } exaMarkSync(pDrawable->pScreen); if (xoff || yoff) RegionTranslate(pRegion, -xoff, -yoff); } return ret; }
/** * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. * * This is probably the only case we actually care about. The rest fall through * to migration and fbGetImage, which hopefully will result in migration pushing * the pixmap out of framebuffer. */ void exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h, unsigned int format, unsigned long planeMask, char *d) { ExaScreenPriv (pDrawable->pScreen); PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); int xoff, yoff; Bool ok; if (pExaScr->fallback_counter || pExaScr->swappedOut) goto fallback; exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff); if (pExaScr->do_migration) { BoxRec Box; RegionRec Reg; ExaMigrationRec pixmaps[1]; Box.x1 = pDrawable->y + x + xoff; Box.y1 = pDrawable->y + y + yoff; Box.x2 = Box.x1 + w; Box.y2 = Box.y1 + h; REGION_INIT(pScreen, &Reg, &Box, 1); pixmaps[0].as_dst = FALSE; pixmaps[0].as_src = TRUE; pixmaps[0].pPix = pPix; pixmaps[0].pReg = &Reg; exaDoMigration(pixmaps, 1, FALSE); REGION_UNINIT(pScreen, &Reg); } pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL) goto fallback; /* Only cover the ZPixmap, solid copy case. */ if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask)) goto fallback; /* Only try to handle the 8bpp and up cases, since we don't want to think * about <8bpp. */ if (pDrawable->bitsPerPixel < 8) goto fallback; ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, pDrawable->y + y + yoff, w, h, d, PixmapBytePad(w, pDrawable->depth)); if (ok) { exaWaitSync(pDrawable->pScreen); return; } fallback: ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); }