/** * Finishes access to the tile in the GC, if used. */ void exaFinishAccessGC(GCPtr pGC) { if (pGC->fillStyle == FillTiled) exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC); if (pGC->stipple) exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK); }
void ExaCheckCopyNtoN(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy, Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) { RegionRec reg; int xoff, yoff; EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, exaDrawableLocation(pSrc), exaDrawableLocation(pDst))); if (pExaScr->prepare_access_reg && RegionInitBoxes(®, pbox, nbox)) { PixmapPtr pPixmap = exaGetDrawablePixmap(pSrc); exaGetDrawableDeltas(pSrc, pPixmap, &xoff, &yoff); RegionTranslate(®, xoff + dx, yoff + dy); pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, ®); RegionUninit(®); } else exaPrepareAccess(pSrc, EXA_PREPARE_SRC); if (pExaScr->prepare_access_reg && !exaGCReadsDestination(pDst, pGC->planemask, pGC->fillStyle, pGC->alu, pGC->clientClipType) && RegionInitBoxes(®, pbox, nbox)) { PixmapPtr pPixmap = exaGetDrawablePixmap(pDst); exaGetDrawableDeltas(pDst, pPixmap, &xoff, &yoff); RegionTranslate(®, xoff, yoff); pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, ®); RegionUninit(®); } else exaPrepareAccess(pDst, EXA_PREPARE_DEST); /* This will eventually call fbCopyNtoN, with some calculation overhead. */ while (nbox--) { pGC->ops->CopyArea(pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx, pbox->y1 - pSrc->y + dy, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, pbox->x1 - pDst->x, pbox->y1 - pDst->y); pbox++; } exaFinishAccess(pSrc, EXA_PREPARE_SRC); exaFinishAccess(pDst, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
void ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) { DrawablePtr pDrawable = &pWin->drawable; ScreenPtr pScreen = pDrawable->pScreen; EXA_PRE_FALLBACK(pScreen); EXA_FALLBACK(("from %p\n", pWin)); /* Only need the source bits, the destination region will be overwritten */ if (pExaScr->prepare_access_reg) { PixmapPtr pPixmap = pScreen->GetWindowPixmap(pWin); int xoff, yoff; exaGetDrawableDeltas(&pWin->drawable, pPixmap, &xoff, &yoff); RegionTranslate(prgnSrc, xoff, yoff); pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, prgnSrc); RegionTranslate(prgnSrc, -xoff, -yoff); } else exaPrepareAccess(pDrawable, EXA_PREPARE_SRC); swap(pExaScr, pScreen, CopyWindow); pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc); swap(pExaScr, pScreen, CopyWindow); exaFinishAccess(pDrawable, EXA_PREPARE_SRC); EXA_POST_FALLBACK(pScreen); }
/** * If the pixmap is currently dirty, this copies at least the dirty area from * the system memory copy to the framebuffer memory copy. Both areas must be * allocated. */ static void exaCopyDirtyToFb (PixmapPtr pPixmap) { ExaScreenPriv (pPixmap->drawable.pScreen); ExaPixmapPriv (pPixmap); RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage); CARD8 *save_ptr; int save_pitch; BoxPtr pBox = REGION_RECTS(pRegion); int nbox = REGION_NUM_RECTS(pRegion); Bool do_sync = FALSE; save_ptr = pPixmap->devPrivate.ptr; save_pitch = pPixmap->devKind; pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; pPixmap->devKind = pExaPixmap->fb_pitch; while (nbox--) { pBox->x1 = max(pBox->x1, 0); pBox->y1 = max(pBox->y1, 0); pBox->x2 = min(pBox->x2, pPixmap->drawable.width); pBox->y2 = min(pBox->y2, pPixmap->drawable.height); if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) continue; if (pExaScr->info->UploadToScreen == NULL || !pExaScr->info->UploadToScreen (pPixmap, pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, pExaPixmap->sys_ptr + pBox->y1 * pExaPixmap->sys_pitch + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8, pExaPixmap->sys_pitch)) { exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST); exaMemcpyBox (pPixmap, pBox, pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, pExaPixmap->fb_ptr, pExaPixmap->fb_pitch); exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST); } else do_sync = TRUE; pBox++; } if (do_sync) exaMarkSync (pPixmap->drawable.pScreen); pPixmap->devPrivate.ptr = save_ptr; pPixmap->devKind = save_pitch; /* The previously damaged bits are now no longer damaged but valid */ REGION_UNION(pPixmap->drawable.pScreen, &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion); DamageEmpty (pExaPixmap->pDamage); }
RegionPtr ExaCheckCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { RegionPtr ret; EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, exaDrawableLocation(pSrc), exaDrawableLocation(pDst))); ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, EXA_PREPARE_SRC, FALSE); ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, EXA_PREPARE_DEST, TRUE); ret = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); exaFinishAccess(pSrc, EXA_PREPARE_SRC); exaFinishAccess(pDst, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); return ret; }
void ExaCheckPushPixels(GCPtr pGC, PixmapPtr pBitmap, DrawablePtr pDrawable, int w, int h, int x, int y) { EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable, exaDrawableLocation(&pBitmap->drawable), exaDrawableLocation(pDrawable))); ExaFallbackPrepareReg(pDrawable, pGC, x, y, w, h, EXA_PREPARE_DEST, TRUE); ExaFallbackPrepareReg(&pBitmap->drawable, pGC, 0, 0, w, h, EXA_PREPARE_SRC, FALSE); exaPrepareAccessGC(pGC); pGC->ops->PushPixels(pGC, pBitmap, pDrawable, w, h, x, y); exaFinishAccessGC(pGC); exaFinishAccess(&pBitmap->drawable, EXA_PREPARE_SRC); exaFinishAccess(pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
void ExaCheckPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr pptInit) { EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess(pDrawable, EXA_PREPARE_DEST); pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, pptInit); exaFinishAccess(pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
void ExaCheckSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) { EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess(pDrawable, EXA_PREPARE_DEST); pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); exaFinishAccess(pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
/** * If the pixmap has both a framebuffer and system memory copy, this function * asserts that both of them are the same. */ static Bool exaAssertNotDirty (PixmapPtr pPixmap) { ExaPixmapPriv (pPixmap); CARD8 *dst, *src; RegionPtr pValidReg = &pExaPixmap->validReg; int dst_pitch, src_pitch, cpp, y, nbox = REGION_NUM_RECTS(pValidReg); BoxPtr pBox = REGION_RECTS(pValidReg); Bool ret = TRUE; if (pExaPixmap == NULL || pExaPixmap->fb_ptr == NULL) return ret; dst = pExaPixmap->sys_ptr; dst_pitch = pExaPixmap->sys_pitch; src = pExaPixmap->fb_ptr; src_pitch = pExaPixmap->fb_pitch; cpp = pPixmap->drawable.bitsPerPixel / 8; exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC); while (nbox--) { int rowbytes; pBox->x1 = max(pBox->x1, 0); pBox->y1 = max(pBox->y1, 0); pBox->x2 = min(pBox->x2, pPixmap->drawable.width); pBox->y2 = min(pBox->y2, pPixmap->drawable.height); if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) continue; rowbytes = (pBox->x2 - pBox->x1) * cpp; src += pBox->y1 * src_pitch + pBox->x1 * cpp; dst += pBox->y1 * dst_pitch + pBox->x1 * cpp; for (y = pBox->y2 - pBox->y1; y; y--) { if (memcmp(dst + pBox->y1 * dst_pitch + pBox->x1 * cpp, src + pBox->y1 * src_pitch + pBox->x1 * cpp, (pBox->x2 - pBox->x1) * cpp) != 0) { ret = FALSE; break; } src += src_pitch; dst += dst_pitch; } src -= pBox->y1 * src_pitch + pBox->x1 * cpp; dst -= pBox->y1 * dst_pitch + pBox->x1 * cpp; } exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); return ret; }
void ExaCheckPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs) { EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess(pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC(pGC); pGC->ops->PolyArc(pDrawable, pGC, narcs, pArcs); exaFinishAccessGC(pGC); exaFinishAccess(pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
void ExaCheckPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect) { EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess(pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC(pGC); pGC->ops->PolyFillRect(pDrawable, pGC, nrect, prect); exaFinishAccessGC(pGC); exaFinishAccess(pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
void ExaCheckImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr * ppci, void *pglyphBase) { EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess(pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC(pGC); pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); exaFinishAccessGC(pGC); exaFinishAccess(pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
void ExaCheckPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nsegInit, xSegment * pSegInit) { EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable, exaDrawableLocation(pDrawable), pGC->lineWidth, nsegInit)); exaPrepareAccess(pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC(pGC); pGC->ops->PolySegment(pDrawable, pGC, nsegInit, pSegInit); exaFinishAccessGC(pGC); exaFinishAccess(pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
void ExaCheckPolyGlyphBlt (DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase) { EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable, exaDrawableLocation(pDrawable), pGC->fillStyle, pGC->alu)); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC (pGC); pGC->ops->PolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); exaFinishAccessGC (pGC); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
void ExaCheckGetSpans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart) { ScreenPtr pScreen = pDrawable->pScreen; EXA_PRE_FALLBACK(pScreen); EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); exaPrepareAccess(pDrawable, EXA_PREPARE_SRC); swap(pExaScr, pScreen, GetSpans); pScreen->GetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart); swap(pExaScr, pScreen, GetSpans); exaFinishAccess(pDrawable, EXA_PREPARE_SRC); EXA_POST_FALLBACK(pScreen); }
void ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, unsigned int format, unsigned long planeMask, char *d) { ScreenPtr pScreen = pDrawable->pScreen; EXA_PRE_FALLBACK(pScreen); EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); ExaFallbackPrepareReg(pDrawable, NULL, x, y, w, h, EXA_PREPARE_SRC, FALSE); swap(pExaScr, pScreen, GetImage); pScreen->GetImage(pDrawable, x, y, w, h, format, planeMask, d); swap(pExaScr, pScreen, GetImage); exaFinishAccess(pDrawable, EXA_PREPARE_SRC); EXA_POST_FALLBACK(pScreen); }
void ExaCheckPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr ppt) { EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n", pDrawable, exaDrawableLocation(pDrawable), pGC->lineWidth, mode, npt)); exaPrepareAccess(pDrawable, EXA_PREPARE_DEST); exaPrepareAccessGC(pGC); pGC->ops->Polylines(pDrawable, pGC, mode, npt, ppt); exaFinishAccessGC(pGC); exaFinishAccess(pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
void ExaCheckAddTraps(PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntrap, xTrap * traps) { ScreenPtr pScreen = pPicture->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); EXA_PRE_FALLBACK(pScreen); EXA_FALLBACK(("to pict %p (%c)\n", exaDrawableLocation(pPicture->pDrawable))); exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); swap(pExaScr, ps, AddTraps); ps->AddTraps(pPicture, x_off, y_off, ntrap, traps); swap(pExaScr, ps, AddTraps); exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK(pScreen); }
void ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits) { PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); ExaPixmapPriv(pPixmap); EXA_PRE_FALLBACK_GC(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); if (!pExaScr->prepare_access_reg || !pExaPixmap->pDamage || exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle, pGC->alu, pGC->clientClipType)) exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); else pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, DamagePendingRegion(pExaPixmap->pDamage)); pGC->ops->PutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); EXA_POST_FALLBACK_GC(pGC); }
/** * exaValidateGC() sets the ops to EXA's implementations, which may be * accelerated or may sync the card and fall back to fb. */ static void exaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) { /* fbValidateGC will do direct access to pixmaps if the tiling has changed. * Preempt fbValidateGC by doing its work and masking the change out, so * that we can do the Prepare/FinishAccess. */ #ifdef FB_24_32BIT if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) { (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC)); fbGetRotatedPixmap(pGC) = 0; } if (pGC->fillStyle == FillTiled) { PixmapPtr pOldTile, pNewTile; pOldTile = pGC->tile.pixmap; if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel) { pNewTile = fbGetRotatedPixmap(pGC); if (!pNewTile || pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel) { if (pNewTile) (*pGC->pScreen->DestroyPixmap) (pNewTile); /* fb24_32ReformatTile will do direct access of a newly- * allocated pixmap. This isn't a problem yet, since we don't * put pixmaps in FB until at least one accelerated EXA op. */ exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC); pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel); exaPixmapDirty(pNewTile, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height); exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC); } if (pNewTile) { fbGetRotatedPixmap(pGC) = pOldTile; pGC->tile.pixmap = pNewTile; changes |= GCTile; } } } #endif if (changes & GCTile) { if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width * pDrawable->bitsPerPixel)) { /* XXX This fixes corruption with tiled pixmaps, but may just be a * workaround for broken drivers */ exaMoveOutPixmap(pGC->tile.pixmap); fbPadPixmap (pGC->tile.pixmap); exaPixmapDirty(pGC->tile.pixmap, 0, 0, pGC->tile.pixmap->drawable.width, pGC->tile.pixmap->drawable.height); } /* Mask out the GCTile change notification, now that we've done FB's * job for it. */ changes &= ~GCTile; } fbValidateGC (pGC, changes, pDrawable); pGC->ops = (GCOps *) &exaOps; }
/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we * use the DownloadFromScreen hook to retrieve contents to a copy in system * memory, perform software rendering on that and move back the results with the * UploadToScreen hook (see exaDamageReport_mixed). */ void exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg) { ExaPixmapPriv(pPixmap); Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); Bool success; success = ExaDoPrepareAccess(pPixmap, index); if (success && has_gpu_copy && pExaPixmap->pDamage) { /* You cannot do accelerated operations while a buffer is mapped. */ exaFinishAccess(&pPixmap->drawable, index); /* Update the gpu view of both deferred destination pixmaps and of * source pixmaps that were migrated with a bounding region. */ exaMoveInPixmap_mixed(pPixmap); success = ExaDoPrepareAccess(pPixmap, index); if (success) { /* We have a gpu pixmap that can be accessed, we don't need the cpu * copy anymore. Drivers that prefer DFS, should fail prepare * access. */ DamageDestroy(pExaPixmap->pDamage); pExaPixmap->pDamage = NULL; free(pExaPixmap->sys_ptr); pExaPixmap->sys_ptr = NULL; return; } } if (!success) { ExaMigrationRec pixmaps[1]; /* Do we need to allocate our system buffer? */ if (!pExaPixmap->sys_ptr) { pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * pPixmap->drawable.height); if (!pExaPixmap->sys_ptr) FatalError("EXA: malloc failed for size %d bytes\n", pExaPixmap->sys_pitch * pPixmap->drawable.height); } if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; } else { pixmaps[0].as_dst = FALSE; pixmaps[0].as_src = TRUE; } pixmaps[0].pPix = pPixmap; pixmaps[0].pReg = pReg; if (!pExaPixmap->pDamage && (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) { Bool as_dst = pixmaps[0].as_dst; /* Set up damage tracking */ pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, DamageReportNonEmpty, TRUE, pPixmap->drawable.pScreen, pPixmap); if (pExaPixmap->pDamage) { DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); /* This ensures that pending damage reflects the current * operation. This is used by exa to optimize migration. */ DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); } if (has_gpu_copy) { exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, pPixmap->drawable.height); /* We don't know which region of the destination will be damaged, * have to assume all of it */ if (as_dst) { pixmaps[0].as_dst = FALSE; pixmaps[0].as_src = TRUE; pixmaps[0].pReg = NULL; } exaCopyDirtyToSys(pixmaps); } if (as_dst) exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, pPixmap->drawable.height); } else if (has_gpu_copy) exaCopyDirtyToSys(pixmaps); pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; pPixmap->devKind = pExaPixmap->sys_pitch; pExaPixmap->use_gpu_copy = FALSE; } }
void ExaCheckComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { ScreenPtr pScreen = pDst->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); EXA_PRE_FALLBACK(pScreen); if (pExaScr->prepare_access_reg) { if (!ExaPrepareCompositeReg(pScreen, op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) goto out_no_clip; } else { /* We need to prepare access to any separate alpha maps first, * in case the driver doesn't support EXA_PREPARE_AUX*, * in which case EXA_PREPARE_SRC may be used for moving them out. */ if (pSrc->alphaMap && pSrc->alphaMap->pDrawable) exaPrepareAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC); if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK); if (pDst->alphaMap && pDst->alphaMap->pDrawable) exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST); exaPrepareAccess(pDst->pDrawable, EXA_PREPARE_DEST); EXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst)); if (pSrc->pDrawable != NULL) exaPrepareAccess(pSrc->pDrawable, EXA_PREPARE_SRC); if (pMask && pMask->pDrawable != NULL) exaPrepareAccess(pMask->pDrawable, EXA_PREPARE_MASK); } swap(pExaScr, ps, Composite); ps->Composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); swap(pExaScr, ps, Composite); if (pMask && pMask->pDrawable != NULL) exaFinishAccess(pMask->pDrawable, EXA_PREPARE_MASK); if (pSrc->pDrawable != NULL) exaFinishAccess(pSrc->pDrawable, EXA_PREPARE_SRC); exaFinishAccess(pDst->pDrawable, EXA_PREPARE_DEST); if (pDst->alphaMap && pDst->alphaMap->pDrawable) exaFinishAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST); if (pSrc->alphaMap && pSrc->alphaMap->pDrawable) exaFinishAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC); if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) exaFinishAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK); out_no_clip: EXA_POST_FALLBACK(pScreen); }
/** * If the pixmap is currently dirty, this copies at least the dirty area from * FB to system or vice versa. Both areas must be allocated. */ static void exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h, char *sys, int sys_pitch), int fallback_index, void (*sync) (ScreenPtr pScreen)) { PixmapPtr pPixmap = migrate->pPix; ExaPixmapPriv(pPixmap); RegionPtr damage = DamageRegion(pExaPixmap->pDamage); RegionRec CopyReg; Bool save_use_gpu_copy; int save_pitch; BoxPtr pBox; int nbox; Bool access_prepared = FALSE; Bool need_sync = FALSE; /* Damaged bits are valid in current copy but invalid in other one */ if (pExaPixmap->use_gpu_copy) { RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, damage); RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, damage); } else { RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, damage); RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, damage); } RegionEmpty(damage); /* Copy bits valid in source but not in destination */ RegionNull(&CopyReg); RegionSubtract(&CopyReg, pValidSrc, pValidDst); if (migrate->as_dst) { ExaScreenPriv(pPixmap->drawable.pScreen); /* XXX: The pending damage region will be marked as damaged after the * operation, so it should serve as an upper bound for the region that * needs to be synchronized for the operation. Unfortunately, this * causes corruption in some cases, e.g. when starting compiz. See * https://bugs.freedesktop.org/show_bug.cgi?id=12916 . */ if (pExaScr->optimize_migration) { RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage); #if DEBUG_MIGRATE if (RegionNil(pending_damage)) { static Bool firsttime = TRUE; if (firsttime) { ErrorF("%s: Pending damage region empty!\n", __func__); firsttime = FALSE; } } #endif /* Try to prevent destination valid region from growing too many * rects by filling it up to the extents of the union of the * destination valid region and the pending damage region. */ if (RegionNumRects(pValidDst) > 10) { BoxRec box; BoxPtr pValidExt, pDamageExt; RegionRec closure; pValidExt = RegionExtents(pValidDst); pDamageExt = RegionExtents(pending_damage); box.x1 = min(pValidExt->x1, pDamageExt->x1); box.y1 = min(pValidExt->y1, pDamageExt->y1); box.x2 = max(pValidExt->x2, pDamageExt->x2); box.y2 = max(pValidExt->y2, pDamageExt->y2); RegionInit(&closure, &box, 0); RegionIntersect(&CopyReg, &CopyReg, &closure); } else RegionIntersect(&CopyReg, &CopyReg, pending_damage); } /* The caller may provide a region to be subtracted from the calculated * dirty region. This is to avoid migration of bits that don't * contribute to the result of the operation. */ if (migrate->pReg) RegionSubtract(&CopyReg, &CopyReg, migrate->pReg); } else { /* The caller may restrict the region to be migrated for source pixmaps * to what's relevant for the operation. */ if (migrate->pReg) RegionIntersect(&CopyReg, &CopyReg, migrate->pReg); } pBox = RegionRects(&CopyReg); nbox = RegionNumRects(&CopyReg); save_use_gpu_copy = pExaPixmap->use_gpu_copy; save_pitch = pPixmap->devKind; pExaPixmap->use_gpu_copy = TRUE; pPixmap->devKind = pExaPixmap->fb_pitch; while (nbox--) { pBox->x1 = max(pBox->x1, 0); pBox->y1 = max(pBox->y1, 0); pBox->x2 = min(pBox->x2, pPixmap->drawable.width); pBox->y2 = min(pBox->y2, pPixmap->drawable.height); if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) continue; if (!transfer || !transfer(pPixmap, pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, (char *) (pExaPixmap->sys_ptr + pBox->y1 * pExaPixmap->sys_pitch + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8), pExaPixmap->sys_pitch)) { if (!access_prepared) { ExaDoPrepareAccess(pPixmap, fallback_index); access_prepared = TRUE; } if (fallback_index == EXA_PREPARE_DEST) { exaMemcpyBox(pPixmap, pBox, pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, pPixmap->devPrivate.ptr, pPixmap->devKind); } else { exaMemcpyBox(pPixmap, pBox, pPixmap->devPrivate.ptr, pPixmap->devKind, pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); } } else need_sync = TRUE; pBox++; } pExaPixmap->use_gpu_copy = save_use_gpu_copy; pPixmap->devKind = save_pitch; /* Try to prevent source valid region from growing too many rects by * removing parts of it which are also in the destination valid region. * Removing anything beyond that would lead to data loss. */ if (RegionNumRects(pValidSrc) > 20) RegionSubtract(pValidSrc, pValidSrc, pValidDst); /* The copied bits are now valid in destination */ RegionUnion(pValidDst, pValidDst, &CopyReg); RegionUninit(&CopyReg); if (access_prepared) exaFinishAccess(&pPixmap->drawable, fallback_index); else if (need_sync && sync) sync(pPixmap->drawable.pScreen); }
/** * If the pixmap has both a framebuffer and system memory copy, this function * asserts that both of them are the same. */ static Bool exaAssertNotDirty(PixmapPtr pPixmap) { ExaPixmapPriv(pPixmap); CARD8 *dst, *src; RegionRec ValidReg; int dst_pitch, src_pitch, cpp, y, nbox, save_pitch; BoxPtr pBox; Bool ret = TRUE, save_use_gpu_copy; if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL) return ret; RegionNull(&ValidReg); RegionIntersect(&ValidReg, &pExaPixmap->validFB, &pExaPixmap->validSys); nbox = RegionNumRects(&ValidReg); if (!nbox) goto out; pBox = RegionRects(&ValidReg); dst_pitch = pExaPixmap->sys_pitch; src_pitch = pExaPixmap->fb_pitch; cpp = pPixmap->drawable.bitsPerPixel / 8; save_use_gpu_copy = pExaPixmap->use_gpu_copy; save_pitch = pPixmap->devKind; pExaPixmap->use_gpu_copy = TRUE; pPixmap->devKind = pExaPixmap->fb_pitch; if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC)) goto skip; while (nbox--) { int rowbytes; pBox->x1 = max(pBox->x1, 0); pBox->y1 = max(pBox->y1, 0); pBox->x2 = min(pBox->x2, pPixmap->drawable.width); pBox->y2 = min(pBox->y2, pPixmap->drawable.height); if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) continue; rowbytes = (pBox->x2 - pBox->x1) * cpp; src = (CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch + pBox->x1 * cpp; dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp; for (y = pBox->y1; y < pBox->y2; y++, src += src_pitch, dst += dst_pitch) { if (memcmp(dst, src, rowbytes) != 0) { ret = FALSE; exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2); break; } } } skip: exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); pExaPixmap->use_gpu_copy = save_use_gpu_copy; pPixmap->devKind = save_pitch; out: RegionUninit(&ValidReg); return ret; }
/** * If the pixmap is currently dirty, this copies at least the dirty area from * the framebuffer memory copy to the system memory copy. Both areas must be * allocated. */ static void exaCopyDirtyToSys (PixmapPtr pPixmap) { ExaScreenPriv (pPixmap->drawable.pScreen); ExaPixmapPriv (pPixmap); RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage); CARD8 *save_ptr; int save_pitch; BoxPtr pBox = REGION_RECTS(pRegion); int nbox = REGION_NUM_RECTS(pRegion); Bool do_sync = FALSE; save_ptr = pPixmap->devPrivate.ptr; save_pitch = pPixmap->devKind; pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; pPixmap->devKind = pExaPixmap->fb_pitch; while (nbox--) { pBox->x1 = max(pBox->x1, 0); pBox->y1 = max(pBox->y1, 0); pBox->x2 = min(pBox->x2, pPixmap->drawable.width); pBox->y2 = min(pBox->y2, pPixmap->drawable.height); if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) continue; if (pExaScr->info->DownloadFromScreen == NULL || !pExaScr->info->DownloadFromScreen (pPixmap, pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, pExaPixmap->sys_ptr + pBox->y1 * pExaPixmap->sys_pitch + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8, pExaPixmap->sys_pitch)) { exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC); exaMemcpyBox (pPixmap, pBox, pExaPixmap->fb_ptr, pExaPixmap->fb_pitch, pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); } else do_sync = TRUE; pBox++; } /* Make sure the bits have actually landed, since we don't necessarily sync * when accessing pixmaps in system memory. */ if (do_sync) exaWaitSync (pPixmap->drawable.pScreen); pPixmap->devPrivate.ptr = save_ptr; pPixmap->devKind = save_pitch; /* The previously damaged bits are now no longer damaged but valid */ REGION_UNION(pPixmap->drawable.pScreen, &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion); DamageEmpty (pExaPixmap->pDamage); }