EXA: Support partial migration of pixmap contents between Sys and FB.

The initiator of migration can pass in a region that defines the relevant area
of each source pixmap or the irrelevant area of the destination pixmap. By
default, the pending damage region is assumed relevant for the destination
pixmap, and everything for source pixmaps.

Thanks to Jarno Manninen for reassuring me that my own ideas for this were
feasible and for providing additional ideas.
This commit is contained in:
Michel Dänzer 2007-08-29 19:55:22 +02:00
parent f27931bdd2
commit 962eddd7a2
5 changed files with 196 additions and 104 deletions

View File

@ -363,6 +363,21 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
} }
} }
void
exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg)
{
ExaMigrationRec pixmaps[1];
pixmaps[0].as_dst = index == EXA_PREPARE_DEST;
pixmaps[0].as_src = index != EXA_PREPARE_DEST;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
pixmaps[0].pReg = pReg;
exaDoMigration(pixmaps, 1, FALSE);
ExaDoPrepareAccess(pDrawable, index);
}
/** /**
* exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler. * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
* *
@ -372,15 +387,7 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
void void
exaPrepareAccess(DrawablePtr pDrawable, int index) exaPrepareAccess(DrawablePtr pDrawable, int index)
{ {
ExaMigrationRec pixmaps[1]; exaPrepareAccessReg(pDrawable, index, NULL);
pixmaps[0].as_dst = index == EXA_PREPARE_DEST;
pixmaps[0].as_src = index != EXA_PREPARE_DEST;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
exaDoMigration(pixmaps, 1, FALSE);
ExaDoPrepareAccess(pDrawable, index);
} }
/** /**

View File

@ -55,6 +55,7 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE; pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
pixmaps[0].pReg = NULL;
if (pExaScr->swappedOut || if (pExaScr->swappedOut ||
pGC->fillStyle != FillSolid || pGC->fillStyle != FillSolid ||
@ -153,6 +154,7 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE; pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
pixmaps[0].pReg = NULL;
/* Don't bother with under 8bpp, XYPixmaps. */ /* Don't bother with under 8bpp, XYPixmaps. */
if (format != ZPixmap || bpp < 8) if (format != ZPixmap || bpp < 8)
@ -211,7 +213,8 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
int dstXoff, dstYoff; int dstXoff, dstYoff;
if (!access_prepared) { if (!access_prepared) {
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST); exaPrepareAccessReg(pDrawable, EXA_PREPARE_DEST,
pixmaps[0].pReg);
access_prepared = TRUE; access_prepared = TRUE;
} }
@ -232,6 +235,8 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
if (access_prepared) if (access_prepared)
exaFinishAccess(pDrawable, EXA_PREPARE_DEST); exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
else
exaMarkSync(pDrawable->pScreen);
exaPixmapDirty(pixmaps[0].pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff); exaPixmapDirty(pixmaps[0].pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff);
} }
@ -420,9 +425,11 @@ exaCopyNtoN (DrawablePtr pSrcDrawable,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE; pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable); pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable);
pixmaps[0].pReg = NULL;
pixmaps[1].as_dst = FALSE; pixmaps[1].as_dst = FALSE;
pixmaps[1].as_src = TRUE; pixmaps[1].as_src = TRUE;
pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable);
pixmaps[1].pReg = NULL;
/* Respect maxX/maxY in a trivial way: don't set up drawing when we might /* Respect maxX/maxY in a trivial way: don't set up drawing when we might
* violate the limits. The proper solution would be a temporary pixmap * violate the limits. The proper solution would be a temporary pixmap
@ -463,7 +470,7 @@ exaCopyNtoN (DrawablePtr pSrcDrawable,
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
exaDrawableLocation(pSrcDrawable), exaDrawableLocation(pSrcDrawable),
exaDrawableLocation(pDstDrawable))); exaDrawableLocation(pDstDrawable)));
exaPrepareAccess (pDstDrawable, EXA_PREPARE_DEST); exaPrepareAccessReg (pDstDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC); exaPrepareAccess (pSrcDrawable, EXA_PREPARE_SRC);
fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
pbox, nbox, dx, dy, reverse, upsidedown, pbox, nbox, dx, dy, reverse, upsidedown,
@ -682,7 +689,8 @@ exaPolyFillRect(DrawablePtr pDrawable,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE; pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pPixmap; pixmaps[0].pPix = pPixmap;
pixmaps[0].pReg = NULL;
exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff); exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
if (pExaScr->swappedOut || if (pExaScr->swappedOut ||
@ -828,6 +836,7 @@ exaSolidBoxClipped (DrawablePtr pDrawable,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE; pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
pixmaps[0].pReg = NULL;
if (pExaScr->swappedOut || if (pExaScr->swappedOut ||
pPixmap->drawable.width > pExaScr->info->maxX || pPixmap->drawable.width > pExaScr->info->maxX ||
@ -846,7 +855,7 @@ exaSolidBoxClipped (DrawablePtr pDrawable,
EXA_FALLBACK(("to %p (%c)\n", pDrawable, EXA_FALLBACK(("to %p (%c)\n", pDrawable,
exaDrawableLocation(pDrawable))); exaDrawableLocation(pDrawable)));
fallback = TRUE; fallback = TRUE;
exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel); fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2, fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2,
fbAnd (GXcopy, fg, pm), fbAnd (GXcopy, fg, pm),
@ -949,6 +958,7 @@ exaImageGlyphBlt (DrawablePtr pDrawable,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = TRUE; pixmaps[0].as_src = TRUE;
pixmaps[0].pPix = pPixmap; pixmaps[0].pPix = pPixmap;
pixmaps[0].pReg = NULL;
depthMask = FbFullMask(pDrawable->depth); depthMask = FbFullMask(pDrawable->depth);
if ((pGC->planemask & depthMask) != depthMask) if ((pGC->planemask & depthMask) != depthMask)
@ -987,7 +997,7 @@ exaImageGlyphBlt (DrawablePtr pDrawable,
} }
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
exaPrepareAccessGC (pGC); exaPrepareAccessGC (pGC);
fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
@ -1099,7 +1109,8 @@ exaFillRegionSolid (DrawablePtr pDrawable,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE; pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
pixmaps[0].pReg = NULL;
if (pPixmap->drawable.width > pExaScr->info->maxX || if (pPixmap->drawable.width > pExaScr->info->maxX ||
pPixmap->drawable.height > pExaScr->info->maxY) pPixmap->drawable.height > pExaScr->info->maxY)
{ {
@ -1128,7 +1139,7 @@ fallback:
return FALSE; return FALSE;
EXA_FALLBACK(("to %p (%c)\n", pDrawable, EXA_FALLBACK(("to %p (%c)\n", pDrawable,
exaDrawableLocation(pDrawable))); exaDrawableLocation(pDrawable)));
exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
fbFillRegionSolid (pDrawable, pRegion, 0, fbFillRegionSolid (pDrawable, pRegion, 0,
fbReplicatePixel (pixel, pDrawable->bitsPerPixel)); fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
exaFinishAccess (pDrawable, EXA_PREPARE_DEST); exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
@ -1170,9 +1181,11 @@ exaFillRegionTiled (DrawablePtr pDrawable,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE; pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable);
pixmaps[0].pReg = NULL;
pixmaps[1].as_dst = FALSE; pixmaps[1].as_dst = FALSE;
pixmaps[1].as_src = TRUE; pixmaps[1].as_src = TRUE;
pixmaps[1].pPix = pTile; pixmaps[1].pPix = pTile;
pixmaps[1].pReg = NULL;
if (pPixmap->drawable.width > pExaScr->info->maxX || if (pPixmap->drawable.width > pExaScr->info->maxX ||
pPixmap->drawable.height > pExaScr->info->maxY || pPixmap->drawable.height > pExaScr->info->maxY ||
@ -1243,7 +1256,7 @@ fallback:
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pTile, pDrawable, EXA_FALLBACK(("from %p to %p (%c,%c)\n", pTile, pDrawable,
exaDrawableLocation(&pTile->drawable), exaDrawableLocation(&pTile->drawable),
exaDrawableLocation(pDrawable))); exaDrawableLocation(pDrawable)));
exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pixmaps[0].pReg);
exaPrepareAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC); exaPrepareAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);
fbFillRegionTiled (pDrawable, pRegion, pTile); fbFillRegionTiled (pDrawable, pRegion, pTile);
exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC); exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC);

View File

@ -117,28 +117,62 @@ exaPixmapShouldBeInFB (PixmapPtr pPix)
* FB to system or vice versa. Both areas must be allocated. * FB to system or vice versa. Both areas must be allocated.
*/ */
static _X_INLINE void static _X_INLINE void
exaCopyDirty(PixmapPtr pPixmap, RegionPtr pValidDst, RegionPtr pValidSrc, exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h, Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
char *sys, int sys_pitch), CARD8 *fallback_src, char *sys, int sys_pitch), CARD8 *fallback_src,
CARD8 *fallback_dst, int fallback_srcpitch, int fallback_dstpitch, CARD8 *fallback_dst, int fallback_srcpitch, int fallback_dstpitch,
int fallback_index, void (*sync) (ScreenPtr pScreen)) int fallback_index, void (*sync) (ScreenPtr pScreen))
{ {
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv (pPixmap); ExaPixmapPriv (pPixmap);
RegionPtr pDamageReg = DamageRegion (pExaPixmap->pDamage); RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
RegionRec CopyReg; RegionRec CopyReg;
CARD8 *save_ptr; CARD8 *save_ptr;
int save_pitch; int save_pitch;
BoxPtr pBox; BoxPtr pBox;
int nbox; int nbox;
Bool do_sync = FALSE; Bool access_prepared = FALSE;
/* Damaged bits are valid in source but invalid in destination */ /* Damaged bits are valid in current copy but invalid in other one */
REGION_UNION(pScreen, pValidSrc, pValidSrc, pDamageReg); if (exaPixmapIsOffscreen(pPixmap)) {
REGION_SUBTRACT(pScreen, pValidDst, pValidDst, pDamageReg); REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB,
damage);
REGION_SUBTRACT(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
damage);
} else {
REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
damage);
REGION_SUBTRACT(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB,
damage);
}
/* Copy bits valid in ssource but not in destination */ REGION_EMPTY(pScreen, damage);
/* Copy bits valid in source but not in destination */
REGION_NULL(pScreen, &CopyReg); REGION_NULL(pScreen, &CopyReg);
REGION_SUBTRACT(pScreen, &CopyReg, pValidSrc, pValidDst); REGION_SUBTRACT(pScreen, &CopyReg, pValidSrc, pValidDst);
if (migrate->as_dst) {
RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
if (REGION_NIL(pending_damage)) {
static Bool firsttime = TRUE;
if (firsttime) {
ErrorF("%s: Pending damage region empty!\n", __func__);
firsttime = FALSE;
}
}
REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, pending_damage);
if (migrate->pReg)
REGION_SUBTRACT(pScreen, &CopyReg, &CopyReg, migrate->pReg);
} else {
if (migrate->pReg)
REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, migrate->pReg);
}
pBox = REGION_RECTS(&CopyReg); pBox = REGION_RECTS(&CopyReg);
nbox = REGION_NUM_RECTS(&CopyReg); nbox = REGION_NUM_RECTS(&CopyReg);
@ -165,29 +199,30 @@ exaCopyDirty(PixmapPtr pPixmap, RegionPtr pValidDst, RegionPtr pValidSrc,
+ pBox->x1 * pPixmap->drawable.bitsPerPixel / 8, + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
pExaPixmap->sys_pitch)) pExaPixmap->sys_pitch))
{ {
ExaDoPrepareAccess(&pPixmap->drawable, fallback_index); if (!access_prepared) {
ExaDoPrepareAccess(&pPixmap->drawable, fallback_index);
access_prepared = TRUE;
}
exaMemcpyBox (pPixmap, pBox, exaMemcpyBox (pPixmap, pBox,
fallback_src, fallback_srcpitch, fallback_src, fallback_srcpitch,
fallback_dst, fallback_dstpitch); fallback_dst, fallback_dstpitch);
exaFinishAccess(&pPixmap->drawable, fallback_index);
} }
else
do_sync = TRUE;
pBox++; pBox++;
} }
if (do_sync) if (access_prepared)
exaFinishAccess(&pPixmap->drawable, fallback_index);
else
sync (pPixmap->drawable.pScreen); sync (pPixmap->drawable.pScreen);
pPixmap->devPrivate.ptr = save_ptr; pPixmap->devPrivate.ptr = save_ptr;
pPixmap->devKind = save_pitch; pPixmap->devKind = save_pitch;
/* The copied bits are now no longer damaged but valid in destination */ /* The copied bits are now valid in destination */
REGION_UNION(pScreen, pValidDst, pValidDst, &CopyReg); REGION_UNION(pScreen, pValidDst, pValidDst, &CopyReg);
REGION_SUBTRACT(pScreen, pDamageReg, pDamageReg, &CopyReg);
REGION_NULL(pScreen, &CopyReg); REGION_UNINIT(pScreen, &CopyReg);
} }
/** /**
@ -196,12 +231,13 @@ exaCopyDirty(PixmapPtr pPixmap, RegionPtr pValidDst, RegionPtr pValidSrc,
* allocated. * allocated.
*/ */
static void static void
exaCopyDirtyToSys (PixmapPtr pPixmap) exaCopyDirtyToSys (ExaMigrationPtr migrate)
{ {
PixmapPtr pPixmap = migrate->pPix;
ExaScreenPriv (pPixmap->drawable.pScreen); ExaScreenPriv (pPixmap->drawable.pScreen);
ExaPixmapPriv (pPixmap); ExaPixmapPriv (pPixmap);
exaCopyDirty(pPixmap, &pExaPixmap->validSys, &pExaPixmap->validFB, exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
pExaScr->info->DownloadFromScreen, pExaPixmap->fb_ptr, pExaScr->info->DownloadFromScreen, pExaPixmap->fb_ptr,
pExaPixmap->sys_ptr, pExaPixmap->fb_pitch, pExaPixmap->sys_ptr, pExaPixmap->fb_pitch,
pExaPixmap->sys_pitch, EXA_PREPARE_SRC, exaWaitSync); pExaPixmap->sys_pitch, EXA_PREPARE_SRC, exaWaitSync);
@ -213,50 +249,18 @@ exaCopyDirtyToSys (PixmapPtr pPixmap)
* allocated. * allocated.
*/ */
static void static void
exaCopyDirtyToFb (PixmapPtr pPixmap) exaCopyDirtyToFb (ExaMigrationPtr migrate)
{ {
PixmapPtr pPixmap = migrate->pPix;
ExaScreenPriv (pPixmap->drawable.pScreen); ExaScreenPriv (pPixmap->drawable.pScreen);
ExaPixmapPriv (pPixmap); ExaPixmapPriv (pPixmap);
exaCopyDirty(pPixmap, &pExaPixmap->validFB, &pExaPixmap->validSys, exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
pExaScr->info->UploadToScreen, pExaPixmap->sys_ptr, pExaScr->info->UploadToScreen, pExaPixmap->sys_ptr,
pExaPixmap->fb_ptr, pExaPixmap->sys_pitch, pExaPixmap->fb_ptr, pExaPixmap->sys_pitch,
pExaPixmap->fb_pitch, EXA_PREPARE_DEST, exaMarkSync); pExaPixmap->fb_pitch, EXA_PREPARE_DEST, exaMarkSync);
} }
/**
* Copies out important pixmap data and removes references to framebuffer area.
* Called when the memory manager decides it's time to kick the pixmap out of
* framebuffer entirely.
*/
void
exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
{
PixmapPtr pPixmap = area->privData;
ExaPixmapPriv(pPixmap);
DBG_MIGRATE (("Save %p (%p) (%dx%d) (%c)\n", pPixmap,
(void*)(ExaGetPixmapPriv(pPixmap)->area ?
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
pPixmap->drawable.width,
pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
if (exaPixmapIsOffscreen(pPixmap)) {
exaCopyDirtyToSys (pPixmap);
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
pExaPixmap->fb_ptr = NULL;
pExaPixmap->area = NULL;
/* Mark all FB bits as invalid, so all valid system bits get copied to FB
* next time */
REGION_NULL(pPixmap->drawable.pScreen, &pExaPixmap->validFB);
}
/** /**
* Allocates a framebuffer copy of the pixmap if necessary, and then copies * Allocates a framebuffer copy of the pixmap if necessary, and then copies
* any necessary pixmap data into the framebuffer copy and points the pixmap at * any necessary pixmap data into the framebuffer copy and points the pixmap at
@ -272,10 +276,11 @@ exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
* we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
* all the data, since it's almost surely all valid now. * all the data, since it's almost surely all valid now.
*/ */
void static void
exaMoveInPixmap (PixmapPtr pPixmap) exaDoMoveInPixmap (ExaMigrationPtr migrate)
{ {
ScreenPtr pScreen = pPixmap->drawable.pScreen; PixmapPtr pPixmap = migrate->pPix;
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv (pScreen); ExaScreenPriv (pScreen);
ExaPixmapPriv (pPixmap); ExaPixmapPriv (pPixmap);
@ -283,10 +288,6 @@ exaMoveInPixmap (PixmapPtr pPixmap)
if (pExaScr->swappedOut) if (pExaScr->swappedOut)
return; return;
/* If we're already in FB, our work is done. */
if (exaPixmapIsOffscreen(pPixmap))
return;
/* If we're not allowed to move, then fail. */ /* If we're not allowed to move, then fail. */
if (exaPixmapIsPinned(pPixmap)) if (exaPixmapIsPinned(pPixmap))
return; return;
@ -310,6 +311,11 @@ exaMoveInPixmap (PixmapPtr pPixmap)
pExaPixmap->area->offset; pExaPixmap->area->offset;
} }
exaCopyDirtyToFb (migrate);
if (exaPixmapIsOffscreen(pPixmap))
return;
DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap, DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
(ExaGetPixmapPriv(pPixmap)->area ? (ExaGetPixmapPriv(pPixmap)->area ?
ExaGetPixmapPriv(pPixmap)->area->offset : 0), ExaGetPixmapPriv(pPixmap)->area->offset : 0),
@ -317,8 +323,6 @@ exaMoveInPixmap (PixmapPtr pPixmap)
pPixmap->drawable.height, pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
exaCopyDirtyToFb (pPixmap);
if (pExaScr->hideOffscreenPixmapData) if (pExaScr->hideOffscreenPixmapData)
pPixmap->devPrivate.ptr = NULL; pPixmap->devPrivate.ptr = NULL;
else else
@ -327,18 +331,31 @@ exaMoveInPixmap (PixmapPtr pPixmap)
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
} }
void
exaMoveInPixmap (PixmapPtr pPixmap)
{
static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE,
.pReg = NULL };
migrate.pPix = pPixmap;
exaDoMoveInPixmap (&migrate);
}
/** /**
* Switches the current active location of the pixmap to system memory, copying * Switches the current active location of the pixmap to system memory, copying
* updated data out if necessary. * updated data out if necessary.
*/ */
void static void
exaMoveOutPixmap (PixmapPtr pPixmap) exaDoMoveOutPixmap (ExaMigrationPtr migrate)
{ {
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv (pPixmap); ExaPixmapPriv (pPixmap);
if (exaPixmapIsPinned(pPixmap)) if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
return; return;
exaCopyDirtyToSys (migrate);
if (exaPixmapIsOffscreen(pPixmap)) { if (exaPixmapIsOffscreen(pPixmap)) {
DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap, DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
@ -348,21 +365,52 @@ exaMoveOutPixmap (PixmapPtr pPixmap)
pPixmap->drawable.height, pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c')); exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
exaCopyDirtyToSys (pPixmap);
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch; pPixmap->devKind = pExaPixmap->sys_pitch;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
} }
} }
void
exaMoveOutPixmap (PixmapPtr pPixmap)
{
static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE,
.pReg = NULL };
migrate.pPix = pPixmap;
exaDoMoveOutPixmap (&migrate);
}
/**
* Copies out important pixmap data and removes references to framebuffer area.
* Called when the memory manager decides it's time to kick the pixmap out of
* framebuffer entirely.
*/
void
exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
{
PixmapPtr pPixmap = area->privData;
ExaPixmapPriv(pPixmap);
exaMoveOutPixmap(pPixmap);
pExaPixmap->fb_ptr = NULL;
pExaPixmap->area = NULL;
/* Mark all FB bits as invalid, so all valid system bits get copied to FB
* next time */
REGION_EMPTY(pPixmap->drawable.pScreen, &pExaPixmap->validFB);
}
/** /**
* For the "greedy" migration scheme, pushes the pixmap toward being located in * For the "greedy" migration scheme, pushes the pixmap toward being located in
* framebuffer memory. * framebuffer memory.
*/ */
static void static void
exaMigrateTowardFb (PixmapPtr pPixmap) exaMigrateTowardFb (ExaMigrationPtr migrate)
{ {
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv (pPixmap); ExaPixmapPriv (pPixmap);
if (pExaPixmap == NULL) { if (pExaPixmap == NULL) {
@ -382,7 +430,7 @@ exaMigrateTowardFb (PixmapPtr pPixmap)
(pointer)pPixmap, pExaPixmap->score)); (pointer)pPixmap, pExaPixmap->score));
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) { if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
exaMoveInPixmap(pPixmap); exaDoMoveInPixmap(migrate);
pExaPixmap->score = 0; pExaPixmap->score = 0;
} }
@ -392,7 +440,7 @@ exaMigrateTowardFb (PixmapPtr pPixmap)
if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN && if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
!exaPixmapIsOffscreen(pPixmap)) !exaPixmapIsOffscreen(pPixmap))
{ {
exaMoveInPixmap (pPixmap); exaDoMoveInPixmap(migrate);
} }
ExaOffscreenMarkUsed (pPixmap); ExaOffscreenMarkUsed (pPixmap);
@ -403,8 +451,9 @@ exaMigrateTowardFb (PixmapPtr pPixmap)
* system memory. * system memory.
*/ */
static void static void
exaMigrateTowardSys (PixmapPtr pPixmap) exaMigrateTowardSys (ExaMigrationPtr migrate)
{ {
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv (pPixmap); ExaPixmapPriv (pPixmap);
if (pExaPixmap == NULL) { if (pExaPixmap == NULL) {
@ -426,7 +475,7 @@ exaMigrateTowardSys (PixmapPtr pPixmap)
pExaPixmap->score--; pExaPixmap->score--;
if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area) if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
exaMoveOutPixmap (pPixmap); exaDoMoveOutPixmap(migrate);
} }
/** /**
@ -438,15 +487,24 @@ exaAssertNotDirty (PixmapPtr pPixmap)
{ {
ExaPixmapPriv (pPixmap); ExaPixmapPriv (pPixmap);
CARD8 *dst, *src; CARD8 *dst, *src;
RegionPtr pValidReg = exaPixmapIsOffscreen(pPixmap) ? &pExaPixmap->validFB : RegionRec ValidReg;
&pExaPixmap->validSys; int dst_pitch, src_pitch, cpp, y, nbox;
int dst_pitch, src_pitch, cpp, y, nbox = REGION_NUM_RECTS(pValidReg); BoxPtr pBox;
BoxPtr pBox = REGION_RECTS(pValidReg);
Bool ret = TRUE; Bool ret = TRUE;
if (!nbox || exaPixmapIsPinned(pPixmap) || pExaPixmap->fb_ptr == NULL) if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
return ret; return ret;
REGION_NULL(pScreen, &ValidReg);
REGION_INTERSECT(pScreen, &ValidReg, &pExaPixmap->validFB,
&pExaPixmap->validSys);
nbox = REGION_NUM_RECTS(&ValidReg);
if (!nbox)
goto out;
pBox = REGION_RECTS(&ValidReg);
dst_pitch = pExaPixmap->sys_pitch; dst_pitch = pExaPixmap->sys_pitch;
src_pitch = pExaPixmap->fb_pitch; src_pitch = pExaPixmap->fb_pitch;
cpp = pPixmap->drawable.bitsPerPixel / 8; cpp = pPixmap->drawable.bitsPerPixel / 8;
@ -479,6 +537,8 @@ exaAssertNotDirty (PixmapPtr pPixmap)
} }
exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
out:
REGION_UNINIT(pScreen, &ValidReg);
return ret; return ret;
} }
@ -533,7 +593,7 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
{ {
for (i = 0; i < npixmaps; i++) { for (i = 0; i < npixmaps; i++) {
if (!exaPixmapIsDirty (pixmaps[i].pPix)) if (!exaPixmapIsDirty (pixmaps[i].pPix))
exaMoveOutPixmap (pixmaps[i].pPix); exaDoMoveOutPixmap (pixmaps + i);
} }
return; return;
} }
@ -544,17 +604,17 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
*/ */
if (!can_accel) { if (!can_accel) {
for (i = 0; i < npixmaps; i++) { for (i = 0; i < npixmaps; i++) {
exaMigrateTowardSys (pixmaps[i].pPix); exaMigrateTowardSys (pixmaps + i);
if (!exaPixmapIsDirty (pixmaps[i].pPix)) if (!exaPixmapIsDirty (pixmaps[i].pPix))
exaMoveOutPixmap (pixmaps[i].pPix); exaDoMoveOutPixmap (pixmaps + i);
} }
return; return;
} }
/* Finally, the acceleration path. Move them all in. */ /* Finally, the acceleration path. Move them all in. */
for (i = 0; i < npixmaps; i++) { for (i = 0; i < npixmaps; i++) {
exaMigrateTowardFb(pixmaps[i].pPix); exaMigrateTowardFb(pixmaps + i);
exaMoveInPixmap(pixmaps[i].pPix); exaDoMoveInPixmap(pixmaps + i);
} }
} else if (pExaScr->migration == ExaMigrationGreedy) { } else if (pExaScr->migration == ExaMigrationGreedy) {
/* If we can't accelerate, either because the driver can't or because one of /* If we can't accelerate, either because the driver can't or because one of
@ -570,7 +630,7 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
*/ */
if (!can_accel) { if (!can_accel) {
for (i = 0; i < npixmaps; i++) for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys (pixmaps[i].pPix); exaMigrateTowardSys (pixmaps + i);
return; return;
} }
@ -578,14 +638,14 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
if (exaPixmapIsOffscreen(pixmaps[i].pPix)) { if (exaPixmapIsOffscreen(pixmaps[i].pPix)) {
/* Found one in FB, so move all to FB. */ /* Found one in FB, so move all to FB. */
for (j = 0; j < npixmaps; j++) for (j = 0; j < npixmaps; j++)
exaMigrateTowardFb(pixmaps[j].pPix); exaMigrateTowardFb(pixmaps + i);
return; return;
} }
} }
/* Nobody's in FB, so move all away from FB. */ /* Nobody's in FB, so move all away from FB. */
for (i = 0; i < npixmaps; i++) for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys(pixmaps[i].pPix); exaMigrateTowardSys(pixmaps + i);
} else if (pExaScr->migration == ExaMigrationAlways) { } else if (pExaScr->migration == ExaMigrationAlways) {
/* Always move the pixmaps out if we can't accelerate. If we can /* Always move the pixmaps out if we can't accelerate. If we can
* accelerate, try to move them all in. If that fails, then move them * accelerate, try to move them all in. If that fails, then move them
@ -593,13 +653,13 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
*/ */
if (!can_accel) { if (!can_accel) {
for (i = 0; i < npixmaps; i++) for (i = 0; i < npixmaps; i++)
exaMoveOutPixmap(pixmaps[i].pPix); exaDoMoveOutPixmap(pixmaps + i);
return; return;
} }
/* Now, try to move them all into FB */ /* Now, try to move them all into FB */
for (i = 0; i < npixmaps; i++) { for (i = 0; i < npixmaps; i++) {
exaMoveInPixmap(pixmaps[i].pPix); exaDoMoveInPixmap(pixmaps + i);
} }
/* If we couldn't fit everything in, abort */ /* If we couldn't fit everything in, abort */

View File

@ -185,6 +185,7 @@ typedef struct _ExaMigrationRec {
Bool as_dst; Bool as_dst;
Bool as_src; Bool as_src;
PixmapPtr pPix; PixmapPtr pPix;
RegionPtr pReg;
} ExaMigrationRec, *ExaMigrationPtr; } ExaMigrationRec, *ExaMigrationPtr;
/** /**
@ -337,6 +338,9 @@ ExaOffscreenFini (ScreenPtr pScreen);
void void
ExaDoPrepareAccess(DrawablePtr pDrawable, int index); ExaDoPrepareAccess(DrawablePtr pDrawable, int index);
void
exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg);
void void
exaPrepareAccess(DrawablePtr pDrawable, int index); exaPrepareAccess(DrawablePtr pDrawable, int index);

View File

@ -267,6 +267,7 @@ exaTryDriverSolidFill(PicturePtr pSrc,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE; pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable); pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
pixmaps[0].pReg = NULL;
exaDoMigration(pixmaps, 1, TRUE); exaDoMigration(pixmaps, 1, TRUE);
pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
@ -381,13 +382,16 @@ exaTryDriverComposite(CARD8 op,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = exaOpReadsDestination(op); pixmaps[0].as_src = exaOpReadsDestination(op);
pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable); pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
pixmaps[0].pReg = NULL;
pixmaps[1].as_dst = FALSE; pixmaps[1].as_dst = FALSE;
pixmaps[1].as_src = TRUE; pixmaps[1].as_src = TRUE;
pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable); pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable);
pixmaps[1].pReg = NULL;
if (pMask) { if (pMask) {
pixmaps[2].as_dst = FALSE; pixmaps[2].as_dst = FALSE;
pixmaps[2].as_src = TRUE; pixmaps[2].as_src = TRUE;
pixmaps[2].pPix = exaGetDrawablePixmap (pMask->pDrawable); pixmaps[2].pPix = exaGetDrawablePixmap (pMask->pDrawable);
pixmaps[2].pReg = NULL;
exaDoMigration(pixmaps, 3, TRUE); exaDoMigration(pixmaps, 3, TRUE);
} else { } else {
exaDoMigration(pixmaps, 2, TRUE); exaDoMigration(pixmaps, 2, TRUE);
@ -579,12 +583,14 @@ exaComposite(CARD8 op,
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = exaOpReadsDestination(op); pixmaps[0].as_src = exaOpReadsDestination(op);
pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable); pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
pixmaps[0].pReg = NULL;
if (pSrc->pDrawable) { if (pSrc->pDrawable) {
pSrcPixmap = exaGetDrawablePixmap (pSrc->pDrawable); pSrcPixmap = exaGetDrawablePixmap (pSrc->pDrawable);
pixmaps[npixmaps].as_dst = FALSE; pixmaps[npixmaps].as_dst = FALSE;
pixmaps[npixmaps].as_src = TRUE; pixmaps[npixmaps].as_src = TRUE;
pixmaps[npixmaps].pPix = pSrcPixmap; pixmaps[npixmaps].pPix = pSrcPixmap;
pixmaps[npixmaps].pReg = NULL;
npixmaps++; npixmaps++;
} }
@ -592,6 +598,7 @@ exaComposite(CARD8 op,
pixmaps[npixmaps].as_dst = FALSE; pixmaps[npixmaps].as_dst = FALSE;
pixmaps[npixmaps].as_src = TRUE; pixmaps[npixmaps].as_src = TRUE;
pixmaps[npixmaps].pPix = exaGetDrawablePixmap (pMask->pDrawable); pixmaps[npixmaps].pPix = exaGetDrawablePixmap (pMask->pDrawable);
pixmaps[npixmaps].pReg = NULL;
npixmaps++; npixmaps++;
} }
@ -1159,8 +1166,9 @@ exaGlyphs (CARD8 op,
* it'll stick there. * it'll stick there.
*/ */
pixmaps[0].as_dst = TRUE; pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = TRUE; pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pPixmap; pixmaps[0].pPix = pPixmap;
pixmaps[0].pReg = NULL;
exaDoMigration (pixmaps, 1, pExaScr->info->PrepareComposite != NULL); exaDoMigration (pixmaps, 1, pExaScr->info->PrepareComposite != NULL);
while (n--) while (n--)