Move migration logic to a new function, exaDoMigration(). This is largely a

manual conversion to allow for different migration schemes to be
    implemented reasonably, but does include some minor improvements such
    as accounting for pinned pixmaps not being acceleratable, and for our
    current GetImage and GetSpans not being accelerated.
This commit is contained in:
Eric Anholt 2006-03-14 21:30:12 +00:00
parent d309054780
commit 693e42114f
7 changed files with 317 additions and 87 deletions

View File

@ -1,3 +1,22 @@
2006-03-14 Eric Anholt <anholt@FreeBSD.org>
* exa/exa.c: (exaDriverInit):
* exa/exa_accel.c: (exaFillSpans), (exaCopyNtoN),
(exaPolyFillRect), (exaSolidBoxClipped), (exaFillRegionSolid),
(exaFillRegionTiled), (exaGetImage), (exaGetSpans):
* exa/exa_migration.c: (exaPixmapIsPinned), (exaMigrateTowardFb),
(exaMigrateTowardSys), (exaDoMigration):
* exa/exa_priv.h:
* exa/exa_render.c: (exaOpReadsDestination),
(exaTryDriverSolidFill), (exaTryDriverComposite), (exaComposite),
(exaGlyphs):
* exa/exa_unaccel.c: (exaGetPixmapFirstPixel):
Move migration logic to a new function, exaDoMigration(). This is
largely a manual conversion to allow for different migration schemes
to be implemented reasonably, but does include some minor improvements
such as accounting for pinned pixmaps not being acceleratable, and for
our current GetImage and GetSpans not being accelerated.
2006-03-14 Eric Anholt <anholt@FreeBSD.org>
* exa/exa_accel.c: (exaFillRegionTiled):

View File

@ -404,10 +404,10 @@ exaDriverInit (ScreenPtr pScreen,
pScreen->CreateGC = exaCreateGC;
pExaScr->SavedGetImage = pScreen->GetImage;
pScreen->GetImage = ExaCheckGetImage;
pScreen->GetImage = exaGetImage;
pExaScr->SavedGetSpans = pScreen->GetSpans;
pScreen->GetSpans = ExaCheckGetSpans;
pScreen->GetSpans = exaGetSpans;
pExaScr->SavedCopyWindow = pScreen->CopyWindow;
pScreen->CopyWindow = exaCopyWindow;

View File

@ -45,17 +45,25 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
int fullX1, fullX2, fullY1;
int partX1, partX2;
int off_x, off_y;
ExaMigrationRec pixmaps[1];
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
if (pExaScr->swappedOut) {
ExaCheckFillSpans(pDrawable, pGC, n, ppt, pwidth, fSorted);
return;
if (pExaScr->swappedOut ||
pGC->fillStyle != FillSolid ||
pDrawable->width > pExaScr->info->maxX ||
pDrawable->height > pExaScr->info->maxY)
{
exaDoMigration (pixmaps, 1, FALSE);
ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
return;
} else {
exaDoMigration (pixmaps, 1, TRUE);
}
if (pGC->fillStyle != FillSolid ||
pDrawable->width > pExaScr->info->maxX ||
pDrawable->height > pExaScr->info->maxY ||
!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
!(*pExaScr->info->PrepareSolid) (pPixmap,
pGC->alu,
pGC->planemask,
@ -263,6 +271,14 @@ exaCopyNtoN (DrawablePtr pSrcDrawable,
PixmapPtr pSrcPixmap, pDstPixmap;
int src_off_x, src_off_y;
int dst_off_x, dst_off_y;
ExaMigrationRec pixmaps[2];
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDstDrawable);
pixmaps[1].as_dst = FALSE;
pixmaps[1].as_src = TRUE;
pixmaps[1].pPix = exaGetDrawablePixmap (pSrcDrawable);
/* 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
@ -273,22 +289,10 @@ exaCopyNtoN (DrawablePtr pSrcDrawable,
pDstDrawable->width > pExaScr->info->maxX ||
pDstDrawable->height > pExaScr->info->maxY)
{
exaDrawableUseMemory (pSrcDrawable);
exaDrawableUseMemory (pDstDrawable);
exaDoMigration (pixmaps, 2, FALSE);
goto fallback;
}
/* If either drawable is already in framebuffer, try to get both of them
* there. Otherwise, be happy with where they are.
*/
if (exaDrawableIsOffscreen(pDstDrawable) ||
exaDrawableIsOffscreen(pSrcDrawable))
{
exaDrawableUseScreen (pSrcDrawable);
exaDrawableUseScreen (pDstDrawable);
} else {
exaDrawableUseMemory (pSrcDrawable);
exaDrawableUseMemory (pDstDrawable);
exaDoMigration (pixmaps, 2, TRUE);
}
/* Mixed directions must be handled specially if the card is lame */
@ -367,12 +371,25 @@ exaPolyFillRect(DrawablePtr pDrawable,
int xoff, yoff;
int xorg, yorg;
int n;
ExaMigrationRec pixmaps[1];
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
if (pExaScr->swappedOut ||
pGC->fillStyle != FillSolid ||
pGC->fillStyle != FillSolid ||
pDrawable->width > pExaScr->info->maxX ||
pDrawable->height > pExaScr->info->maxY ||
!(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
pDrawable->height > pExaScr->info->maxY)
{
exaDoMigration (pixmaps, 1, FALSE);
ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
return;
} else {
exaDoMigration (pixmaps, 1, TRUE);
}
if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
!(*pExaScr->info->PrepareSolid) (pPixmap,
pGC->alu,
pGC->planemask,
@ -471,13 +488,27 @@ exaSolidBoxClipped (DrawablePtr pDrawable,
int nbox;
int xoff, yoff;
int partX1, partX2, partY1, partY2;
ExaMigrationRec pixmaps[1];
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
if (pExaScr->swappedOut ||
pDrawable->width > pExaScr->info->maxX ||
pDrawable->height > pExaScr->info->maxY ||
!(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
pDrawable->height > pExaScr->info->maxY)
{
EXA_FALLBACK(("to 0x%lx\n", (long)pDrawable));
exaDoMigration (pixmaps, 1, FALSE);
goto fallback;
} else {
exaDoMigration (pixmaps, 1, TRUE);
}
if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
!(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, pm, fg))
{
fallback:
EXA_FALLBACK(("to 0x%lx\n", (long)pDrawable));
exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
@ -724,10 +755,22 @@ exaFillRegionSolid (DrawablePtr pDrawable,
ExaScreenPriv(pDrawable->pScreen);
PixmapPtr pPixmap;
int xoff, yoff;
ExaMigrationRec pixmaps[1];
if (pDrawable->width <= pExaScr->info->maxX &&
pDrawable->height <= pExaScr->info->maxY &&
(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
if (pDrawable->width > pExaScr->info->maxX ||
pDrawable->height > pExaScr->info->maxY)
{
exaDoMigration (pixmaps, 1, FALSE);
goto fallback;
} else {
exaDoMigration (pixmaps, 1, TRUE);
}
if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, FB_ALLONES, pixel))
{
int nbox = REGION_NUM_RECTS (pRegion);
@ -746,6 +789,7 @@ exaFillRegionSolid (DrawablePtr pDrawable,
}
else
{
fallback:
EXA_FALLBACK(("to 0x%lx\n", (long)pDrawable));
exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
fbFillRegionSolid (pDrawable, pRegion, 0,
@ -766,18 +810,11 @@ exaFillRegionTiled (DrawablePtr pDrawable,
PixmapPtr pPixmap;
int xoff, yoff;
int tileWidth, tileHeight;
ExaMigrationRec pixmaps[2];
tileWidth = pTile->drawable.width;
tileHeight = pTile->drawable.height;
if (pDrawable->width > pExaScr->info->maxX ||
pDrawable->height > pExaScr->info->maxY ||
tileWidth > pExaScr->info->maxX ||
tileHeight > pExaScr->info->maxY)
{
goto fallback;
}
/* If we're filling with a solid color, grab it out and go to
* FillRegionSolid, saving numerous copies.
*/
@ -786,11 +823,28 @@ exaFillRegionTiled (DrawablePtr pDrawable,
return;
}
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
pixmaps[1].as_dst = FALSE;
pixmaps[1].as_src = TRUE;
pixmaps[1].pPix = pTile;
if (pDrawable->width > pExaScr->info->maxX ||
pDrawable->height > pExaScr->info->maxY ||
tileWidth > pExaScr->info->maxX ||
tileHeight > pExaScr->info->maxY)
{
exaDoMigration (pixmaps, 2, FALSE);
goto fallback;
} else {
exaDoMigration (pixmaps, 2, TRUE);
}
pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
if (!pPixmap)
goto fallback;
exaPixmapUseScreen(pTile);
if (!exaPixmapIsOffscreen(pTile))
goto fallback;
@ -891,3 +945,39 @@ exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
}
ExaCheckPaintWindow (pWin, pRegion, what);
}
/**
* GetImage isn't accelerated yet, but performs migration so that we'll
* hopefully avoid the read-from-framebuffer cost.
*/
void
exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d)
{
ExaMigrationRec pixmaps[1];
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
exaDoMigration (pixmaps, 1, FALSE);
ExaCheckGetImage (pDrawable, x, y, w, h, format, planeMask, d);
}
/**
* GetSpans isn't accelerated yet, but performs migration so that we'll
* hopefully avoid the read-from-framebuffer cost.
*/
void
exaGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth,
int nspans, char *pdstStart)
{
ExaMigrationRec pixmaps[1];
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable);
exaDoMigration (pixmaps, 1, FALSE);
ExaCheckGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
}

View File

@ -40,6 +40,20 @@
#define DBG_MIGRATE(a)
#endif
/**
* Returns TRUE if the pixmap is not movable. This is the case where it's a
* fake pixmap for the frontbuffer (no pixmap private) or it's a scratch
* pixmap created by some other X Server internals (the score says it's
* pinned).
*/
static Bool
exaPixmapIsPinned (PixmapPtr pPix)
{
ExaPixmapPriv (pPix);
return pExaPixmap == NULL || pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED;
}
static void
exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
{
@ -233,20 +247,8 @@ exaMoveOutPixmap (PixmapPtr pPixmap)
}
}
void
exaDrawableUseScreen(DrawablePtr pDrawable)
{
exaPixmapUseScreen (exaGetDrawablePixmap (pDrawable));
}
void
exaDrawableUseMemory(DrawablePtr pDrawable)
{
exaPixmapUseMemory (exaGetDrawablePixmap (pDrawable));
}
void
exaPixmapUseScreen (PixmapPtr pPixmap)
static void
exaMigrateTowardFb (PixmapPtr pPixmap)
{
ExaPixmapPriv (pPixmap);
@ -283,8 +285,8 @@ exaPixmapUseScreen (PixmapPtr pPixmap)
ExaOffscreenMarkUsed (pPixmap);
}
void
exaPixmapUseMemory (PixmapPtr pPixmap)
static void
exaMigrateTowardSys (PixmapPtr pPixmap)
{
ExaPixmapPriv (pPixmap);
@ -309,3 +311,60 @@ exaPixmapUseMemory (PixmapPtr pPixmap)
if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
exaMoveOutPixmap (pPixmap);
}
/**
* Performs migration of the pixmaps according to the operation information
* provided in pixmaps and can_accel. In the future, other migration schemes
* may be added, which is facilitated by having this logic all in one place.
*/
void
exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
{
ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
int i, j;
/* If anything is pinned in system memory, we won't be able to
* accelerate.
*/
for (i = 0; i < npixmaps; i++) {
if (exaPixmapIsPinned (pixmaps[i].pPix) &&
!exaPixmapIsOffscreen (pixmaps[i].pPix))
{
EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
pixmaps[i].pPix->drawable.width,
pixmaps[i].pPix->drawable.height));
can_accel = FALSE;
break;
}
}
/* If we can't accelerate, either because the driver can't or because one of
* the pixmaps is pinned in system memory, then we migrate everybody toward
* system memory.
*
* We also migrate toward system if all pixmaps involved are currently in
* system memory -- this can mitigate thrashing when there are significantly
* more pixmaps active than would fit in memory.
*
* If not, then we migrate toward FB so that hopefully acceleration can
* happen.
*/
if (!can_accel) {
for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys (pixmaps[i].pPix);
return;
}
for (i = 0; i < npixmaps; i++) {
if (exaPixmapIsOffscreen(pixmaps[i].pPix)) {
/* Found one in FB, so move all to FB. */
for (j = 0; j < npixmaps; j++)
exaMigrateTowardFb(pixmaps[j].pPix);
return;
}
}
/* Nobody's in FB, so move all away from FB. */
for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys(pixmaps[i].pPix);
}

View File

@ -141,6 +141,12 @@ typedef struct {
unsigned int size;
} ExaPixmapPrivRec, *ExaPixmapPrivPtr;
typedef struct _ExaMigrationRec {
Bool as_dst;
Bool as_src;
PixmapPtr pPix;
} ExaMigrationRec, *ExaMigrationPtr;
/**
* exaDDXDriverInit must be implemented by the DDX using EXA, and is the place
* to set EXA options or hook in screen functions to handle using EXA as the AA.
@ -256,6 +262,14 @@ exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
void
exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what);
void
exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d);
void
exaGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth,
int nspans, char *pdstStart);
extern const GCOps exaOps, exaAsyncPixmapGCOps;
#ifdef RENDER
@ -291,18 +305,6 @@ void
ExaOffscreenFini (ScreenPtr pScreen);
/* exa.c */
void
exaDrawableUseScreen(DrawablePtr pDrawable);
void
exaDrawableUseMemory(DrawablePtr pDrawable);
void
exaPixmapUseScreen (PixmapPtr pPixmap);
void
exaPixmapUseMemory (PixmapPtr pPixmap);
void
exaPrepareAccess(DrawablePtr pDrawable, int index);
@ -324,12 +326,6 @@ exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp);
PixmapPtr
exaGetDrawablePixmap(DrawablePtr pDrawable);
void
exaMoveInPixmap (PixmapPtr pPixmap);
void
exaMoveOutPixmap (PixmapPtr pPixmap);
RegionPtr
exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height, int dstx, int dsty);
@ -372,4 +368,14 @@ exaGlyphs (CARD8 op,
GlyphListPtr list,
GlyphPtr *glyphs);
/* exa_migration.c */
void
exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
void
exaMoveInPixmap (PixmapPtr pPixmap);
void
exaMoveOutPixmap (PixmapPtr pPixmap);
#endif /* EXAPRIV_H */

View File

@ -109,7 +109,25 @@ exaPrintCompositeFallback(CARD8 op,
" dst %s, \n",
sop, srcdesc, maskdesc, dstdesc);
}
#endif
#endif /* DEBUG_TRACE_FALL */
static Bool
exaOpReadsDestination (CARD8 op)
{
/* FALSE (does not read destination) is the list of ops in the protocol
* document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
* That's just Clear and Src. ReduceCompositeOp() will already have
* converted con/disjoint clear/src to Clear or Src.
*/
switch (op) {
case PictOpClear:
case PictOpSrc:
return FALSE;
default:
return TRUE;
}
}
static Bool
exaGetPixelFromRGBA(CARD32 *pixel,
@ -152,7 +170,6 @@ exaGetPixelFromRGBA(CARD32 *pixel,
return TRUE;
}
static Bool
exaGetRGBAFromPixel(CARD32 pixel,
CARD16 *red,
@ -232,6 +249,7 @@ exaTryDriverSolidFill(PicturePtr pSrc,
PixmapPtr pSrcPix, pDstPix;
CARD32 pixel;
CARD16 red, green, blue, alpha;
ExaMigrationRec pixmaps[1];
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
@ -246,7 +264,10 @@ exaTryDriverSolidFill(PicturePtr pSrc,
pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
pixel = exaGetPixmapFirstPixel (pSrcPix);
exaDrawableUseScreen(pDst->pDrawable);
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
exaDoMigration(pixmaps, 1, TRUE);
pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
if (!pDstPix) {
@ -309,6 +330,7 @@ exaTryDriverComposite(CARD8 op,
int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
struct _Pixmap scratch;
ExaMigrationRec pixmaps[3];
/* Bail if we might exceed coord limits by rendering from/to these. We
* should really be making some scratch pixmaps with offsets and coords
@ -347,10 +369,20 @@ exaTryDriverComposite(CARD8 op,
return -1;
}
exaDrawableUseScreen(pSrc->pDrawable);
if (pMask != NULL)
exaDrawableUseScreen(pMask->pDrawable);
exaDrawableUseScreen(pDst->pDrawable);
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = exaOpReadsDestination(op);
pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
pixmaps[1].as_dst = FALSE;
pixmaps[1].as_src = TRUE;
pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable);
if (pMask) {
pixmaps[2].as_dst = FALSE;
pixmaps[2].as_src = TRUE;
pixmaps[2].pPix = exaGetDrawablePixmap (pMask->pDrawable);
exaDoMigration(pixmaps, 3, TRUE);
} else {
exaDoMigration(pixmaps, 2, TRUE);
}
pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
if (pMask)
@ -508,13 +540,24 @@ exaComposite(CARD8 op,
}
if (ret != 0) {
ExaMigrationRec pixmaps[3];
/* failure to accelerate was not due to pixmaps being in the wrong
* locations.
*/
exaDrawableUseMemory(pSrc->pDrawable);
if (pMask != NULL)
exaDrawableUseMemory(pMask->pDrawable);
exaDrawableUseMemory(pDst->pDrawable);
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = exaOpReadsDestination(op);
pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable);
pixmaps[1].as_dst = FALSE;
pixmaps[1].as_src = TRUE;
pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable);
if (pMask) {
pixmaps[2].as_dst = FALSE;
pixmaps[2].as_src = TRUE;
pixmaps[2].pPix = exaGetDrawablePixmap (pMask->pDrawable);
exaDoMigration(pixmaps, 3, FALSE);
} else {
exaDoMigration(pixmaps, 2, FALSE);
}
}
#if DEBUG_TRACE_FALL
@ -621,6 +664,7 @@ exaGlyphs (CARD8 op,
{
GCPtr pGC;
int maxwidth = 0, maxheight = 0, i;
ExaMigrationRec pixmaps[1];
x += list->xOff;
y += list->yOff;
@ -681,7 +725,10 @@ exaGlyphs (CARD8 op,
/* Give the temporary pixmap an initial kick towards the screen, so
* it'll stick there.
*/
exaPixmapUseScreen (pPixmap);
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = TRUE;
pixmaps[0].pPix = pPixmap;
exaDoMigration (pixmaps, 1, TRUE);
while (n--)
{

View File

@ -279,6 +279,11 @@ ExaCheckRestoreAreas (PixmapPtr pPixmap,
exaFinishAccess ((DrawablePtr)pPixmap, EXA_PREPARE_DEST);
}
/* XXX: Note the lack of a prepare on the tile, if the window has a tiled
* background. This function happens to only be called if pExaScr->swappedOut,
* so we actually end up not having to do it since the tile won't be in fb.
* That doesn't make this not dirty, though.
*/
void
ExaCheckPaintWindow (WindowPtr pWin, RegionPtr pRegion, int what)
{
@ -334,8 +339,12 @@ CARD32
exaGetPixmapFirstPixel (PixmapPtr pPixmap)
{
CARD32 pixel;
ExaMigrationRec pixmaps[1];
exaDrawableUseMemory(&pPixmap->drawable);
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
pixmaps[0].pPix = pPixmap;
exaDoMigration (pixmaps, 1, TRUE);
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
switch (pPixmap->drawable.bitsPerPixel) {