xserver: Branch 'master' - 5 commits

Maarten Maathuis madman2003 at kemper.freedesktop.org
Thu Aug 6 15:35:11 PDT 2009


 exa/Makefile.am             |    7 
 exa/exa.c                   |  384 +++++-----------------
 exa/exa.h                   |    9 
 exa/exa_accel.c             |   35 +-
 exa/exa_classic.c           |  258 +++++++++++++++
 exa/exa_driver.c            |  211 ++++++++++++
 exa/exa_glyphs.c            |    4 
 exa/exa_migration.c         |  741 --------------------------------------------
 exa/exa_migration_classic.c |  720 ++++++++++++++++++++++++++++++++++++++++++
 exa/exa_migration_mixed.c   |  189 +++++++++++
 exa/exa_mixed.c             |  247 ++++++++++++++
 exa/exa_priv.h              |  147 ++++++--
 exa/exa_render.c            |   17 -
 13 files changed, 1877 insertions(+), 1092 deletions(-)

New commits:
commit 3047bd067464efb9857960d3fa6324b947faa970
Author: Maarten Maathuis <madman2003 at gmail.com>
Date:   Wed Aug 5 18:39:47 2009 +0200

    exa: delay malloc for "mixed"

diff --git a/exa/exa.c b/exa/exa.c
index 32a1c3e..c8fe12e 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -333,8 +333,18 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
     pExaScr->access[index].pixmap = pPixmap;
     pExaScr->access[index].count = 1;
 
-    if (!offscreen)
+    if (!offscreen) {
+	/* Do we need to allocate our system buffer? */
+	if ((pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && (pExaScr->info->flags & EXA_MIXED_PIXMAPS)) {
+	    if (!pExaPixmap->sys_ptr) {
+		pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * pDrawable->height);
+		if (!pExaPixmap->sys_ptr)
+		    FatalError("EXA: malloc failed for size %d bytes\n", pExaPixmap->sys_pitch * pDrawable->height);
+		pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+	    }
+	}
 	return FALSE;
+    }
 
     exaWaitSync (pDrawable->pScreen);
 
diff --git a/exa/exa_migration_mixed.c b/exa/exa_migration_mixed.c
index 771c2c3..915bed9 100644
--- a/exa/exa_migration_mixed.c
+++ b/exa/exa_migration_mixed.c
@@ -109,6 +109,10 @@ exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
     if (!w || !h)
 	goto finish;
 
+    /* we do not malloc memory by default. */
+    if (!sys_buffer)
+	goto finish;
+
     if (!pExaScr->info->UploadToScreen)
 	goto fallback;
 
diff --git a/exa/exa_mixed.c b/exa/exa_mixed.c
index 7e02abc..47fa6d4 100644
--- a/exa/exa_mixed.c
+++ b/exa/exa_mixed.c
@@ -81,17 +81,10 @@ exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
 
     datasize = h * paddedWidth;
 
-    /* Allocate temporary pixmap. */
-    pExaPixmap->sys_ptr = malloc(datasize);
+    /* We will allocate the system pixmap later if needed. */
+    pExaPixmap->sys_ptr = NULL;
     pExaPixmap->sys_pitch = paddedWidth;
 
-    if (!pExaPixmap->sys_ptr) {
-	swap(pExaScr, pScreen, DestroyPixmap);
-	pScreen->DestroyPixmap (pPixmap);
-	swap(pExaScr, pScreen, DestroyPixmap);
-	return NULL;
-    }
-
     pExaPixmap->area = NULL;
     pExaPixmap->offscreen = FALSE;
     pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
commit e8ac2ed5dc4c2ac0a5e1e1f371f94c15b1c729dd
Author: Maarten Maathuis <madman2003 at gmail.com>
Date:   Wed Aug 5 16:12:16 2009 +0200

    exa: implement exaMoveInPixmap for "mixed"
    
    - This can be used to force creation of driver pixmap.
    - Not for 1 or 4 bpp.
    - Driver can still fail (driver) pixmap creation.

diff --git a/exa/exa.c b/exa/exa.c
index fd9ba90..32a1c3e 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -1059,12 +1059,16 @@ exaDriverInit (ScreenPtr		pScreen,
 		wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_mixed);
 		pExaScr->do_migration = exaDoMigration_mixed;
 		pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_mixed;
+		pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed;
+		pExaScr->do_move_out_pixmap = NULL;
 	    } else {
 		wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver);
 		wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver);
 		wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_driver);
 		pExaScr->do_migration = NULL;
 		pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_driver;
+		pExaScr->do_move_in_pixmap = NULL;
+		pExaScr->do_move_out_pixmap = NULL;
 	    }
 	} else {
 	    wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic);
@@ -1072,6 +1076,8 @@ exaDriverInit (ScreenPtr		pScreen,
 	    wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_classic);
 	    pExaScr->do_migration = exaDoMigration_classic;
 	    pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_classic;
+	    pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic;
+	    pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic;
 	}
 	if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
 	    LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n",
@@ -1188,3 +1194,29 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
     if (pExaScr->do_migration)
 	(*pExaScr->do_migration)(pixmaps, npixmaps, can_accel);
 }
+
+void
+exaMoveInPixmap (PixmapPtr pPixmap)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+
+    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
+	return;
+
+    if (pExaScr->do_move_in_pixmap)
+	(*pExaScr->do_move_in_pixmap)(pPixmap);
+}
+
+void
+exaMoveOutPixmap (PixmapPtr pPixmap)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+
+    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
+	return;
+
+    if (pExaScr->do_move_out_pixmap)
+	(*pExaScr->do_move_out_pixmap)(pPixmap);
+}
diff --git a/exa/exa.h b/exa/exa.h
index 40ac1dd..46d12b7 100644
--- a/exa/exa.h
+++ b/exa/exa.h
@@ -815,7 +815,7 @@ exaEnableDisableFBAccess (int index, Bool enable);
 extern _X_EXPORT Bool
 exaDrawableIsOffscreen (DrawablePtr pDrawable);
 
-/* in exa_migration.c */
+/* in exa.c */
 extern _X_EXPORT void
 exaMoveInPixmap (PixmapPtr pPixmap);
 
diff --git a/exa/exa_migration_classic.c b/exa/exa_migration_classic.c
index 8355959..d8e1e86 100644
--- a/exa/exa_migration_classic.c
+++ b/exa/exa_migration_classic.c
@@ -366,7 +366,7 @@ exaDoMoveInPixmap (ExaMigrationPtr migrate)
 }
 
 void
-exaMoveInPixmap (PixmapPtr pPixmap)
+exaMoveInPixmap_classic (PixmapPtr pPixmap)
 {
     static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE,
 				       .pReg = NULL };
@@ -407,7 +407,7 @@ exaDoMoveOutPixmap (ExaMigrationPtr migrate)
 }
 
 void
-exaMoveOutPixmap (PixmapPtr pPixmap)
+exaMoveOutPixmap_classic (PixmapPtr pPixmap)
 {
     static ExaMigrationRec migrate = { .as_dst = FALSE, .as_src = TRUE,
 				       .pReg = NULL };
diff --git a/exa/exa_migration_mixed.c b/exa/exa_migration_mixed.c
index 24bdafb..771c2c3 100644
--- a/exa/exa_migration_mixed.c
+++ b/exa/exa_migration_mixed.c
@@ -170,3 +170,16 @@ exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
 	    exaCreateDriverPixmap_mixed(pPixmap);
     }
 }
+
+void
+exaMoveInPixmap_mixed(PixmapPtr pPixmap)
+{
+    ExaMigrationRec pixmaps[1];
+
+    pixmaps[0].as_dst = FALSE;
+    pixmaps[0].as_src = TRUE;
+    pixmaps[0].pPix = pPixmap;
+    pixmaps[0].pReg = NULL;
+
+    exaDoMigration(pixmaps, 1, TRUE);
+}
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 620bc67..869cf17 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -174,6 +174,8 @@ typedef struct {
 #endif
     void (*do_migration) (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
     Bool (*pixmap_is_offscreen) (PixmapPtr pPixmap);
+    void (*do_move_in_pixmap) (PixmapPtr pPixmap);
+    void (*do_move_out_pixmap) (PixmapPtr pPixmap);
 
     Bool			 swappedOut;
     enum ExaMigrationHeuristic	 migration;
@@ -604,6 +606,9 @@ exaCreateDriverPixmap_mixed(PixmapPtr pPixmap);
 void
 exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
 
+void
+exaMoveInPixmap_mixed(PixmapPtr pPixmap);
+
 /* exa_render.c */
 Bool
 exaOpReadsDestination (CARD8 op);
@@ -665,4 +670,10 @@ exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
 void
 exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area);
 
+void
+exaMoveOutPixmap_classic (PixmapPtr pPixmap);
+
+void
+exaMoveInPixmap_classic (PixmapPtr pPixmap);
+
 #endif /* EXAPRIV_H */
commit 9d2a7128d3e66b8c076a714d69f84bcad49391b9
Author: Maarten Maathuis <madman2003 at gmail.com>
Date:   Sun Aug 2 02:35:46 2009 +0200

    exa: Use damage to optimise away useless copies.

diff --git a/exa/exa_migration_mixed.c b/exa/exa_migration_mixed.c
index 475b76a..24bdafb 100644
--- a/exa/exa_migration_mixed.c
+++ b/exa/exa_migration_mixed.c
@@ -35,12 +35,28 @@ static void
 exaUploadFallback(PixmapPtr pPixmap, CARD8 *src, int src_pitch,
 	      CARD8 *dst, int dst_pitch)
  {
-    int i;
+    ExaPixmapPriv(pPixmap);
+    RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
+    int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
+    int bytes, nbox;
+    BoxPtr pbox;
+
+    pbox = REGION_RECTS(damage);
+    nbox = REGION_NUM_RECTS(damage);
+
+    while (nbox--) {
+	bytes = (pbox->x2 - pbox->x1) * cpp;
+
+	src += pbox->y1 * src_pitch + pbox->x1 * cpp;
+	dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
+
+	for (i = pbox->y2 - pbox->y1; i; i--) {
+	    memcpy (dst, src, bytes);
+	    src += src_pitch;
+	    dst += dst_pitch;
+	}
 
-    for (i = pPixmap->drawable.height; i; i--) {
-	memcpy (dst, src, min(src_pitch, dst_pitch));
-	src += src_pitch;
-	dst += dst_pitch;
+	pbox++;
     }
 }
 
@@ -50,12 +66,15 @@ exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
     ScreenPtr pScreen = pPixmap->drawable.pScreen;
     ExaScreenPriv(pScreen);
     ExaPixmapPriv(pPixmap);
+    RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
     void *sys_buffer = pExaPixmap->sys_ptr;
     int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
     int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
     int usage_hint = pPixmap->usage_hint;
     int sys_pitch = pExaPixmap->sys_pitch;
     int paddedWidth = sys_pitch;
+    int nbox;
+    BoxPtr pbox;
 
     /* Already done. */
     if (pExaPixmap->driverPriv)
@@ -93,8 +112,18 @@ exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
     if (!pExaScr->info->UploadToScreen)
 	goto fallback;
 
-    if (pExaScr->info->UploadToScreen(pPixmap, 0, 0, w, h, sys_buffer, sys_pitch))
-	goto finish;
+    pbox = REGION_RECTS(damage);
+    nbox = REGION_NUM_RECTS(damage);
+
+    while (nbox--) {
+	if (!pExaScr->info->UploadToScreen(pPixmap, pbox->x1, pbox->y1, pbox->x2 - pbox->x1,
+		pbox->y2 - pbox->y1, (char *) (sys_buffer) + pbox->y1 * sys_pitch + pbox->x1 * (bpp / 8), sys_pitch))
+	    goto fallback;
+
+	pbox++;
+    }
+
+    goto finish;
 
 fallback:
     ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
@@ -104,6 +133,13 @@ fallback:
 
 finish:
     free(sys_buffer);
+
+    /* We no longer need this. */
+    if (pExaPixmap->pDamage) {
+	DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
+	DamageDestroy(pExaPixmap->pDamage);
+	pExaPixmap->pDamage = NULL;
+    }
 }
 
 void
diff --git a/exa/exa_mixed.c b/exa/exa_mixed.c
index 26406c4..7e02abc 100644
--- a/exa/exa_mixed.c
+++ b/exa/exa_mixed.c
@@ -114,6 +114,23 @@ exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
 
 	/* We want to be able to copy the pixmap to driver memory later on. */
 	pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
+
+	/* Set up damage tracking */
+	pExaPixmap->pDamage = DamageCreate (NULL, NULL,
+					    DamageReportNone, TRUE,
+					    pScreen, pPixmap);
+
+	if (pExaPixmap->pDamage == NULL) {
+	    swap(pExaScr, pScreen, DestroyPixmap);
+	    pScreen->DestroyPixmap (pPixmap);
+	    swap(pExaScr, pScreen, DestroyPixmap);
+	    return NULL;
+	}
+
+	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);
     }
 
     return pPixmap;
@@ -136,8 +153,16 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
 
     if (pExaPixmap) {
         if (pPixData) {
-	    if (!exaPixmapIsPinned(pPixmap))
+	    if (!exaPixmapIsPinned(pPixmap)) {
 		free(pExaPixmap->sys_ptr);
+
+		/* We no longer need this. */
+		if (pExaPixmap->pDamage) {
+		    DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
+		    DamageDestroy(pExaPixmap->pDamage);
+		    pExaPixmap->pDamage = NULL;
+		}
+	    }
             pExaPixmap->sys_ptr = pPixData;
 	}
 
commit 03ecb164f2592c954aa408bf121e0c67b604d854
Author: Maarten Maathuis <madman2003 at gmail.com>
Date:   Sat Aug 1 19:19:19 2009 +0200

    exa: A simple 3rd backend implementation.
    
    - Based on driver pixmaps with some changes (completely transparent to driver).
    - It helps with the problem of known software fallbacks, such as trapezoids.
    - exaDoMigration is now called for all cases that provide a do_migration hook.
    - exa_migration.c is renamed to exa_migration_classic.c

diff --git a/exa/Makefile.am b/exa/Makefile.am
index bf2c138..8b759cd 100644
--- a/exa/Makefile.am
+++ b/exa/Makefile.am
@@ -18,8 +18,10 @@ libexa_la_SOURCES = \
 	exa.c \
 	exa.h \
 	exa_classic.c \
-	exa_migration.c \
+	exa_migration_classic.c \
 	exa_driver.c \
+	exa_mixed.c \
+	exa_migration_mixed.c \
 	exa_accel.c \
 	exa_glyphs.c \
 	exa_offscreen.c \
diff --git a/exa/exa.c b/exa/exa.c
index 0f37168..fd9ba90 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -217,6 +217,22 @@ exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
 }
 
 /**
+ * Returns TRUE if the pixmap is not movable.  This is the case where it's a
+ * pixmap which has no private (almost always bad) or it's a scratch pixmap created by
+ * some X Server internal component (the score says it's pinned).
+ */
+Bool
+exaPixmapIsPinned (PixmapPtr pPix)
+{
+    ExaPixmapPriv (pPix);
+
+    if (pExaPixmap == NULL)
+	EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE);
+
+    return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED;
+}
+
+/**
  * exaPixmapIsOffscreen() is used to determine if a pixmap is in offscreen
  * memory, meaning that acceleration could probably be done to it, and that it
  * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
@@ -237,7 +253,7 @@ exaPixmapIsOffscreen(PixmapPtr pPixmap)
     if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
 	return FALSE;
 
-    return pExaScr->pixmap_is_offscreen(pPixmap);
+    return (*pExaScr->pixmap_is_offscreen)(pPixmap);
 }
 
 /**
@@ -348,9 +364,9 @@ void
 exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg)
 {
     PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
-    ExaPixmapPriv(pPixmap);
+    ExaScreenPriv(pPixmap->drawable.pScreen);
 
-    if (pExaPixmap->pDamage) {
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[1];
 
 	if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
@@ -1037,11 +1053,19 @@ exaDriverInit (ScreenPtr		pScreen,
 	    return FALSE;
         }
 	if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) {
-	    wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver);
-	    wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver);
-	    wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_driver);
-	    pExaScr->do_migration = NULL;
-	    pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_driver;
+	    if (pExaScr->info->flags & EXA_MIXED_PIXMAPS) {
+		wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_mixed);
+		wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_mixed);
+		wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_mixed);
+		pExaScr->do_migration = exaDoMigration_mixed;
+		pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_mixed;
+	    } else {
+		wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver);
+		wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver);
+		wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_driver);
+		pExaScr->do_migration = NULL;
+		pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_driver;
+	    }
 	} else {
 	    wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic);
 	    wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_classic);
@@ -1162,5 +1186,5 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
 	return;
 
     if (pExaScr->do_migration)
-	pExaScr->do_migration(pixmaps, npixmaps, can_accel);
+	(*pExaScr->do_migration)(pixmaps, npixmaps, can_accel);
 }
diff --git a/exa/exa.h b/exa/exa.h
index 1d2c6a9..40ac1dd 100644
--- a/exa/exa.h
+++ b/exa/exa.h
@@ -758,6 +758,13 @@ typedef struct _ExaDriver {
  */
 #define EXA_SUPPORTS_OFFSCREEN_OVERLAPS (1 << 5)
 
+/**
+ * EXA_MIXED_PIXMAPS will hide unacceleratable pixmaps from drivers and manage the
+ * problem known software fallbacks like trapezoids. This only migrates pixmaps one way
+ * into a driver pixmap and then pins it.
+ */
+#define EXA_MIXED_PIXMAPS (1 << 6)
+
 /** @} */
 
 /* in exa.c */
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index bc970bb..33fbb98 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -57,7 +57,9 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
     {
 	ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
 	return;
-    } else if (pExaPixmap->pDamage) {
+    }
+
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[1];
 
 	pixmaps[0].as_dst = TRUE;
@@ -165,10 +167,10 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
     if (pExaScr->swappedOut)
 	return FALSE;
 
-    if (pExaPixmap->pDamage) {
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[1];
 
- 	pixmaps[0].as_dst = TRUE;
+	pixmaps[0].as_dst = TRUE;
 	pixmaps[0].as_src = FALSE;
 	pixmaps[0].pPix = pPix;
 	pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
@@ -455,7 +457,7 @@ exaHWCopyNtoN (DrawablePtr    pSrcDrawable,
         }
     }
 
-    if (pDstExaPixmap->pDamage || pSrcExaPixmap->pDamage) {
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[2];
 
 	pixmaps[0].as_dst = TRUE;
@@ -466,6 +468,7 @@ exaHWCopyNtoN (DrawablePtr    pSrcDrawable,
 	pixmaps[1].as_src = TRUE;
 	pixmaps[1].pPix = pSrcPixmap;
 	pixmaps[1].pReg = srcregion;
+
 	exaDoMigration (pixmaps, 2, TRUE);
     }
 
@@ -809,7 +812,7 @@ exaPolyFillRect(DrawablePtr pDrawable,
 	goto fallback;
     }
 
-    if (pExaPixmap->pDamage) {
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[1];
 
 	pixmaps[0].as_dst = TRUE;
@@ -982,17 +985,16 @@ exaFillRegionSolid (DrawablePtr	pDrawable, RegionPtr pRegion, Pixel pixel,
     REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
 
     if (pExaPixmap->accel_blocked)
-    {
 	goto out;
-    } else if (pExaPixmap->pDamage) {
+
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[1];
 
 	pixmaps[0].as_dst = TRUE;
 	pixmaps[0].as_src = FALSE;
 	pixmaps[0].pPix = pPixmap;
 	pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillSolid,
-						alu, clientClipType)
-	    ? NULL : pRegion;
+						alu, clientClipType) ? NULL : pRegion;
 
 	exaDoMigration (pixmaps, 1, TRUE);
     }
@@ -1078,17 +1080,16 @@ exaFillRegionTiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
     pExaPixmap = ExaGetPixmapPriv (pPixmap);
 
     if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked)
-    {
 	return FALSE;
-    } else if (pExaPixmap->pDamage || pTileExaPixmap->pDamage) {
+
+    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, clientClipType)
-	    ? NULL : pRegion;
+						alu, clientClipType) ? NULL : pRegion;
 	pixmaps[1].as_dst = FALSE;
 	pixmaps[1].as_src = TRUE;
 	pixmaps[1].pPix = pTile;
@@ -1233,20 +1234,19 @@ exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
 {
     ExaScreenPriv (pDrawable->pScreen);
     PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
-    ExaPixmapPrivPtr pExaPixmap = ExaGetPixmapPriv (pPix);
     int xoff, yoff;
     Bool ok;
 
     if (pExaScr->swappedOut)
 	goto fallback;
 
-    if (pExaPixmap->pDamage) {
+    exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff);
+
+    if (pExaScr->do_migration) {
 	BoxRec Box;
 	RegionRec Reg;
 	ExaMigrationRec pixmaps[1];
 
-	exaGetDrawableDeltas (pDrawable, pPix, &xoff, &yoff);
-
 	Box.x1 = pDrawable->y + x + xoff;
 	Box.y1 = pDrawable->y + y + yoff;
 	Box.x2 = Box.x1 + w;
diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
index 1855de1..d621ccf 100644
--- a/exa/exa_glyphs.c
+++ b/exa/exa_glyphs.c
@@ -385,10 +385,10 @@ exaGlyphCacheUploadGlyph(ScreenPtr         pScreen,
     if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel)
 	goto composite;
 
-    /* cache pixmap must be offscreen. */
-    if (pExaPixmap->pDamage) {
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[1];
 
+	/* cache pixmap must be offscreen. */
 	pixmaps[0].as_dst = TRUE;
 	pixmaps[0].as_src = FALSE;
 	pixmaps[0].pPix = pCachePixmap;
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
deleted file mode 100644
index afab9d2..0000000
--- a/exa/exa_migration.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * Copyright © 2006 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Authors:
- *    Eric Anholt <eric at anholt.net>
- *    Michel Dänzer <michel at tungstengraphics.com>
- *
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <string.h>
-
-#include "exa_priv.h"
-#include "exa.h"
-
-#if DEBUG_MIGRATE
-#define DBG_MIGRATE(a) ErrorF a
-#else
-#define DBG_MIGRATE(a)
-#endif
-
-/**
- * Returns TRUE if the pixmap is not movable.  This is the case where it's a
- * pixmap which has no private (almost always bad) or it's a scratch pixmap created by
- * some X Server internal component (the score says it's pinned).
- */
-static Bool
-exaPixmapIsPinned (PixmapPtr pPix)
-{
-    ExaPixmapPriv (pPix);
-
-    if (pExaPixmap == NULL)
-	EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsPinned was called on a non-exa pixmap.\n"), TRUE);
-
-    return pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED;
-}
-
-/**
- * The fallback path for UTS/DFS failing is to just memcpy.  exaCopyDirtyToSys
- * and exaCopyDirtyToFb both needed to do this loop.
- */
-static void
-exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
-	      CARD8 *dst, int dst_pitch)
- {
-    int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
-    int bytes = (pbox->x2 - pbox->x1) * cpp;
-
-    src += pbox->y1 * src_pitch + pbox->x1 * cpp;
-    dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
-
-    for (i = pbox->y2 - pbox->y1; i; i--) {
-	memcpy (dst, src, bytes);
-	src += src_pitch;
-	dst += dst_pitch;
-    }
-}
- 
-/**
- * Returns TRUE if the pixmap is dirty (has been modified in its current
- * location compared to the other), or lacks a private for tracking
- * dirtiness.
- */
-static Bool
-exaPixmapIsDirty (PixmapPtr pPix)
-{
-    ExaPixmapPriv (pPix);
-
-    if (pExaPixmap == NULL)
-	EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE);
-
-    return REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage)) ||
-	!REGION_EQUAL(pScreen, &pExaPixmap->validSys, &pExaPixmap->validFB);
-}
-
-/**
- * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
- * to be considered "should be in framebuffer".  That's just anything that has
- * had more acceleration than fallbacks, or has no score yet.
- *
- * Only valid if using a migration scheme that tracks score.
- */
-static Bool
-exaPixmapShouldBeInFB (PixmapPtr pPix)
-{
-    ExaPixmapPriv (pPix);
-
-    if (exaPixmapIsPinned (pPix))
-	return TRUE;
-
-    return pExaPixmap->score >= 0;
-}
-
-/**
- * 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), CARD8 *fallback_src,
-	     CARD8 *fallback_dst, int fallback_srcpitch, int fallback_dstpitch,
-	     int fallback_index, void (*sync) (ScreenPtr pScreen))
-{
-    PixmapPtr pPixmap = migrate->pPix;
-    ExaPixmapPriv (pPixmap);
-    RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
-    RegionRec CopyReg;
-    Bool save_offscreen;
-    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 (exaPixmapIsOffscreen(pPixmap)) {
-	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);
-    }
-
-    REGION_EMPTY(pScreen, damage);
-
-    /* Copy bits valid in source but not in destination */
-    REGION_NULL(pScreen, &CopyReg);
-    REGION_SUBTRACT(pScreen, &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 (REGION_NIL(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 (REGION_NUM_RECTS(pValidDst) > 10) {
-		BoxRec box;
-		BoxPtr pValidExt, pDamageExt;
-		RegionRec closure;
-
-		pValidExt = REGION_EXTENTS(pScreen, pValidDst);
-		pDamageExt = REGION_EXTENTS(pScreen, 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);
-
-		REGION_INIT(pScreen, &closure, &box, 0);
-		REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, &closure);
-	    } else
-		REGION_INTERSECT(pScreen, &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)
-	    REGION_SUBTRACT(pScreen, &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)
-	    REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, migrate->pReg);
-    }
-
-    pBox = REGION_RECTS(&CopyReg);
-    nbox = REGION_NUM_RECTS(&CopyReg);
-
-    save_offscreen = pExaPixmap->offscreen;
-    save_pitch = pPixmap->devKind;
-    pExaPixmap->offscreen = 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->drawable, fallback_index);
-		access_prepared = TRUE;
-	    }
-	    exaMemcpyBox (pPixmap, pBox,
-			  fallback_src, fallback_srcpitch,
-			  fallback_dst, fallback_dstpitch);
-	} else
-	    need_sync = TRUE;
-
-	pBox++;
-    }
-
-    if (access_prepared)
-	exaFinishAccess(&pPixmap->drawable, fallback_index);
-    else if (need_sync && sync)
-	sync (pPixmap->drawable.pScreen);
-
-    pExaPixmap->offscreen = save_offscreen;
-    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 (REGION_NUM_RECTS(pValidSrc) > 20)
-	REGION_SUBTRACT(pScreen, pValidSrc, pValidSrc, pValidDst);
-
-    /* The copied bits are now valid in destination */
-    REGION_UNION(pScreen, pValidDst, pValidDst, &CopyReg);
-
-    REGION_UNINIT(pScreen, &CopyReg);
-}
-
-/**
- * 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 (ExaMigrationPtr migrate)
-{
-    PixmapPtr pPixmap = migrate->pPix;
-    ExaScreenPriv (pPixmap->drawable.pScreen);
-    ExaPixmapPriv (pPixmap);
-
-    exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
-		 pExaScr->info->DownloadFromScreen, pExaPixmap->fb_ptr,
-		 pExaPixmap->sys_ptr, pExaPixmap->fb_pitch,
-		 pExaPixmap->sys_pitch, EXA_PREPARE_SRC, exaWaitSync);
-}
-
-/**
- * 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 (ExaMigrationPtr migrate)
-{
-    PixmapPtr pPixmap = migrate->pPix;
-    ExaScreenPriv (pPixmap->drawable.pScreen);
-    ExaPixmapPriv (pPixmap);
-
-    exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
-		 pExaScr->info->UploadToScreen, pExaPixmap->sys_ptr,
-		 pExaPixmap->fb_ptr, pExaPixmap->sys_pitch,
-		 pExaPixmap->fb_pitch, EXA_PREPARE_DEST, NULL);
-}
-
-/**
- * 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
- * it.
- *
- * Note that when first allocated, a pixmap will have FALSE dirty flag.
- * This is intentional because pixmap data starts out undefined.  So if we move
- * it in due to the first operation against it being accelerated, it will have
- * undefined framebuffer contents that we didn't have to upload.  If we do
- * moveouts (and moveins) after the first movein, then we will only have to copy
- * back and forth if the pixmap was written to after the last synchronization of
- * the two copies.  Then, at exaPixmapSave (when the framebuffer copy goes away)
- * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
- * all the data, since it's almost surely all valid now.
- */
-static void
-exaDoMoveInPixmap (ExaMigrationPtr migrate)
-{
-    PixmapPtr pPixmap = migrate->pPix;
-    ScreenPtr pScreen = pPixmap->drawable.pScreen;
-    ExaScreenPriv (pScreen);
-    ExaPixmapPriv (pPixmap);
-
-    /* If we're VT-switched away, no touching card memory allowed. */
-    if (pExaScr->swappedOut)
-	return;
-
-    /* If we're not allowed to move, then fail. */
-    if (exaPixmapIsPinned(pPixmap))
-	return;
-
-    /* Don't migrate in pixmaps which are less than 8bpp.  This avoids a lot of
-     * fragility in EXA, and <8bpp is probably not used enough any more to care
-     * (at least, not in acceleratd paths).
-     */
-    if (pPixmap->drawable.bitsPerPixel < 8)
-	return;
-
-    if (pExaPixmap->accel_blocked)
-	return;
-
-    if (pExaPixmap->area == NULL) {
-	pExaPixmap->area =
-	    exaOffscreenAlloc (pScreen, pExaPixmap->fb_size,
-			       pExaScr->info->pixmapOffsetAlign, FALSE,
-                               exaPixmapSave, (pointer) pPixmap);
-	if (pExaPixmap->area == NULL)
-	    return;
-
-	pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
-				       pExaPixmap->area->offset;
-    }
-
-    exaCopyDirtyToFb (migrate);
-
-    if (exaPixmapIsOffscreen(pPixmap))
-	return;
-
-    DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
-		  (ExaGetPixmapPriv(pPixmap)->area ?
-                   ExaGetPixmapPriv(pPixmap)->area->offset : 0),
-		  pPixmap->drawable.width,
-		  pPixmap->drawable.height,
-		  exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
-
-    pExaPixmap->offscreen = TRUE;
-
-    pPixmap->devKind = pExaPixmap->fb_pitch;
-    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
- * updated data out if necessary.
- */
-static void
-exaDoMoveOutPixmap (ExaMigrationPtr migrate)
-{
-    PixmapPtr pPixmap = migrate->pPix;
-    ExaPixmapPriv (pPixmap);
-
-    if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
-	return;
-
-    exaCopyDirtyToSys (migrate);
-
-    if (exaPixmapIsOffscreen(pPixmap)) {
-
-	DBG_MIGRATE (("<- %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'));
-
-	pExaPixmap->offscreen = FALSE;
-
-	pPixmap->devKind = pExaPixmap->sys_pitch;
-	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
- * framebuffer memory.
- */
-static void
-exaMigrateTowardFb (ExaMigrationPtr migrate)
-{
-    PixmapPtr pPixmap = migrate->pPix;
-    ExaPixmapPriv (pPixmap);
-
-    if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
-	DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
-		     (pointer)pPixmap));
-	return;
-    }
-
-    DBG_MIGRATE(("UseScreen %p score %d\n",
-		 (pointer)pPixmap, pExaPixmap->score));
-
-    if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
-	exaDoMoveInPixmap(migrate);
-	pExaPixmap->score = 0;
-    }
-
-    if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
-	pExaPixmap->score++;
-
-    if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
-	!exaPixmapIsOffscreen(pPixmap))
-    {
-	exaDoMoveInPixmap(migrate);
-    }
-
-    if (exaPixmapIsOffscreen(pPixmap)) {
-	exaCopyDirtyToFb (migrate);
-	ExaOffscreenMarkUsed (pPixmap);
-    } else
-	exaCopyDirtyToSys (migrate);
-}
-
-/**
- * For the "greedy" migration scheme, pushes the pixmap toward being located in
- * system memory.
- */
-static void
-exaMigrateTowardSys (ExaMigrationPtr migrate)
-{
-    PixmapPtr pPixmap = migrate->pPix;
-    ExaPixmapPriv (pPixmap);
-
-    DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score));
-
-    if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
-	return;
-
-    if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
-	pExaPixmap->score = 0;
-
-    if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
-	pExaPixmap->score--;
-
-    if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
-	exaDoMoveOutPixmap(migrate);
-
-    if (exaPixmapIsOffscreen(pPixmap)) {
-	exaCopyDirtyToFb (migrate);
-	ExaOffscreenMarkUsed (pPixmap);
-    } else
-	exaCopyDirtyToSys (migrate);
-}
-
-/**
- * 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_offscreen;
-
-    if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
-	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;
-    src_pitch = pExaPixmap->fb_pitch;
-    cpp = pPixmap->drawable.bitsPerPixel / 8;
-
-    save_offscreen = pExaPixmap->offscreen;
-    save_pitch = pPixmap->devKind;
-    pExaPixmap->offscreen = TRUE;
-    pPixmap->devKind = pExaPixmap->fb_pitch;
-
-    if (!ExaDoPrepareAccess(&pPixmap->drawable, 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->offscreen = save_offscreen;
-    pPixmap->devKind = save_pitch;
-
-out:
-    REGION_UNINIT(pScreen, &ValidReg);
-    return ret;
-}
-
-/**
- * Performs migration of the pixmaps according to the operation information
- * provided in pixmaps and can_accel and the migration scheme chosen in the
- * config file.
- */
-void
-exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
-{
-    ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
-    ExaScreenPriv(pScreen);
-    int i, j;
-
-    /* If this debugging flag is set, check each pixmap for whether it is marked
-     * as clean, and if so, actually check if that's the case.  This should help
-     * catch issues with failing to mark a drawable as dirty.  While it will
-     * catch them late (after the operation happened), it at least explains what
-     * went wrong, and instrumenting the code to find what operation happened
-     * to the pixmap last shouldn't be hard.
-     */
-    if (pExaScr->checkDirtyCorrectness) {
-	for (i = 0; i < npixmaps; i++) {
-	    if (!exaPixmapIsDirty (pixmaps[i].pPix) &&
-		!exaAssertNotDirty (pixmaps[i].pPix))
-		ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i);
-	}
-    }
-    /* 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 (pExaScr->migration == ExaMigrationSmart) {
-	/* If we've got something as a destination that we shouldn't cause to
-	 * become newly dirtied, take the unaccelerated route.
-	 */
-	for (i = 0; i < npixmaps; i++) {
-	    if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) &&
-		!exaPixmapIsDirty (pixmaps[i].pPix))
-	    {
-		for (i = 0; i < npixmaps; i++) {
-		    if (!exaPixmapIsDirty (pixmaps[i].pPix))
-			exaDoMoveOutPixmap (pixmaps + i);
-		}
-		return;
-	    }
-	}
-
-	/* If we aren't going to accelerate, then we migrate everybody toward
-	 * system memory, and kick out if it's free.
-	 */
-	if (!can_accel) {
-	    for (i = 0; i < npixmaps; i++) {
-		exaMigrateTowardSys (pixmaps + i);
-		if (!exaPixmapIsDirty (pixmaps[i].pPix))
-		    exaDoMoveOutPixmap (pixmaps + i);
-	    }
-	    return;
-	}
-
-	/* Finally, the acceleration path.  Move them all in. */
-	for (i = 0; i < npixmaps; i++) {
-	    exaMigrateTowardFb(pixmaps + i);
-	    exaDoMoveInPixmap(pixmaps + i);
-	}
-    } else if (pExaScr->migration == ExaMigrationGreedy) {
-	/* 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);
-	    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 + i);
-		return;
-	    }
-	}
-
-	/* Nobody's in FB, so move all away from FB. */
-	for (i = 0; i < npixmaps; i++)
-	    exaMigrateTowardSys(pixmaps + i);
-    } else if (pExaScr->migration == ExaMigrationAlways) {
-	/* 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
-	 * back out.
-	 */
-	if (!can_accel) {
-	    for (i = 0; i < npixmaps; i++)
-		exaDoMoveOutPixmap(pixmaps + i);
-	    return;
-	}
-
-	/* Now, try to move them all into FB */
-	for (i = 0; i < npixmaps; i++) {
-	    exaDoMoveInPixmap(pixmaps + i);
-	}
-
-	/* If we couldn't fit everything in, abort */
-	for (i = 0; i < npixmaps; i++) {
-	    if (!exaPixmapIsOffscreen(pixmaps[i].pPix)) {
-		return;
-	    }
-	}
-
-	/* Yay, everything's offscreen, mark memory as used */
-	for (i = 0; i < npixmaps; i++) {
-	    ExaOffscreenMarkUsed (pixmaps[i].pPix);
-	}
-    }
-}
diff --git a/exa/exa_migration_classic.c b/exa/exa_migration_classic.c
new file mode 100644
index 0000000..8355959
--- /dev/null
+++ b/exa/exa_migration_classic.c
@@ -0,0 +1,720 @@
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric at anholt.net>
+ *    Michel Dänzer <michel at tungstengraphics.com>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <string.h>
+
+#include "exa_priv.h"
+#include "exa.h"
+
+#if DEBUG_MIGRATE
+#define DBG_MIGRATE(a) ErrorF a
+#else
+#define DBG_MIGRATE(a)
+#endif
+
+/**
+ * The fallback path for UTS/DFS failing is to just memcpy.  exaCopyDirtyToSys
+ * and exaCopyDirtyToFb both needed to do this loop.
+ */
+static void
+exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
+	      CARD8 *dst, int dst_pitch)
+ {
+    int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
+    int bytes = (pbox->x2 - pbox->x1) * cpp;
+
+    src += pbox->y1 * src_pitch + pbox->x1 * cpp;
+    dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
+
+    for (i = pbox->y2 - pbox->y1; i; i--) {
+	memcpy (dst, src, bytes);
+	src += src_pitch;
+	dst += dst_pitch;
+    }
+}
+
+/**
+ * Returns TRUE if the pixmap is dirty (has been modified in its current
+ * location compared to the other), or lacks a private for tracking
+ * dirtiness.
+ */
+static Bool
+exaPixmapIsDirty (PixmapPtr pPix)
+{
+    ExaPixmapPriv (pPix);
+
+    if (pExaPixmap == NULL)
+	EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE);
+
+    return REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage)) ||
+	!REGION_EQUAL(pScreen, &pExaPixmap->validSys, &pExaPixmap->validFB);
+}
+
+/**
+ * Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
+ * to be considered "should be in framebuffer".  That's just anything that has
+ * had more acceleration than fallbacks, or has no score yet.
+ *
+ * Only valid if using a migration scheme that tracks score.
+ */
+static Bool
+exaPixmapShouldBeInFB (PixmapPtr pPix)
+{
+    ExaPixmapPriv (pPix);
+
+    if (exaPixmapIsPinned (pPix))
+	return TRUE;
+
+    return pExaPixmap->score >= 0;
+}
+
+/**
+ * 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), CARD8 *fallback_src,
+	     CARD8 *fallback_dst, int fallback_srcpitch, int fallback_dstpitch,
+	     int fallback_index, void (*sync) (ScreenPtr pScreen))
+{
+    PixmapPtr pPixmap = migrate->pPix;
+    ExaPixmapPriv (pPixmap);
+    RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
+    RegionRec CopyReg;
+    Bool save_offscreen;
+    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 (exaPixmapIsOffscreen(pPixmap)) {
+	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);
+    }
+
+    REGION_EMPTY(pScreen, damage);
+
+    /* Copy bits valid in source but not in destination */
+    REGION_NULL(pScreen, &CopyReg);
+    REGION_SUBTRACT(pScreen, &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 (REGION_NIL(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 (REGION_NUM_RECTS(pValidDst) > 10) {
+		BoxRec box;
+		BoxPtr pValidExt, pDamageExt;
+		RegionRec closure;
+
+		pValidExt = REGION_EXTENTS(pScreen, pValidDst);
+		pDamageExt = REGION_EXTENTS(pScreen, 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);
+
+		REGION_INIT(pScreen, &closure, &box, 0);
+		REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, &closure);
+	    } else
+		REGION_INTERSECT(pScreen, &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)
+	    REGION_SUBTRACT(pScreen, &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)
+	    REGION_INTERSECT(pScreen, &CopyReg, &CopyReg, migrate->pReg);
+    }
+
+    pBox = REGION_RECTS(&CopyReg);
+    nbox = REGION_NUM_RECTS(&CopyReg);
+
+    save_offscreen = pExaPixmap->offscreen;
+    save_pitch = pPixmap->devKind;
+    pExaPixmap->offscreen = 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->drawable, fallback_index);
+		access_prepared = TRUE;
+	    }
+	    exaMemcpyBox (pPixmap, pBox,
+			  fallback_src, fallback_srcpitch,
+			  fallback_dst, fallback_dstpitch);
+	} else
+	    need_sync = TRUE;
+
+	pBox++;
+    }
+
+    if (access_prepared)
+	exaFinishAccess(&pPixmap->drawable, fallback_index);
+    else if (need_sync && sync)
+	sync (pPixmap->drawable.pScreen);
+
+    pExaPixmap->offscreen = save_offscreen;
+    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 (REGION_NUM_RECTS(pValidSrc) > 20)
+	REGION_SUBTRACT(pScreen, pValidSrc, pValidSrc, pValidDst);
+
+    /* The copied bits are now valid in destination */
+    REGION_UNION(pScreen, pValidDst, pValidDst, &CopyReg);
+
+    REGION_UNINIT(pScreen, &CopyReg);
+}
+
+/**
+ * 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 (ExaMigrationPtr migrate)
+{
+    PixmapPtr pPixmap = migrate->pPix;
+    ExaScreenPriv (pPixmap->drawable.pScreen);
+    ExaPixmapPriv (pPixmap);
+
+    exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
+		 pExaScr->info->DownloadFromScreen, pExaPixmap->fb_ptr,
+		 pExaPixmap->sys_ptr, pExaPixmap->fb_pitch,
+		 pExaPixmap->sys_pitch, EXA_PREPARE_SRC, exaWaitSync);
+}
+
+/**
+ * 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 (ExaMigrationPtr migrate)
+{
+    PixmapPtr pPixmap = migrate->pPix;
+    ExaScreenPriv (pPixmap->drawable.pScreen);
+    ExaPixmapPriv (pPixmap);
+
+    exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
+		 pExaScr->info->UploadToScreen, pExaPixmap->sys_ptr,
+		 pExaPixmap->fb_ptr, pExaPixmap->sys_pitch,
+		 pExaPixmap->fb_pitch, EXA_PREPARE_DEST, NULL);
+}
+
+/**
+ * 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
+ * it.
+ *
+ * Note that when first allocated, a pixmap will have FALSE dirty flag.
+ * This is intentional because pixmap data starts out undefined.  So if we move
+ * it in due to the first operation against it being accelerated, it will have
+ * undefined framebuffer contents that we didn't have to upload.  If we do
+ * moveouts (and moveins) after the first movein, then we will only have to copy
+ * back and forth if the pixmap was written to after the last synchronization of
+ * the two copies.  Then, at exaPixmapSave (when the framebuffer copy goes away)
+ * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
+ * all the data, since it's almost surely all valid now.
+ */
+static void
+exaDoMoveInPixmap (ExaMigrationPtr migrate)
+{
+    PixmapPtr pPixmap = migrate->pPix;
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv (pScreen);
+    ExaPixmapPriv (pPixmap);
+
+    /* If we're VT-switched away, no touching card memory allowed. */
+    if (pExaScr->swappedOut)
+	return;
+
+    /* If we're not allowed to move, then fail. */
+    if (exaPixmapIsPinned(pPixmap))
+	return;
+
+    /* Don't migrate in pixmaps which are less than 8bpp.  This avoids a lot of
+     * fragility in EXA, and <8bpp is probably not used enough any more to care
+     * (at least, not in acceleratd paths).
+     */
+    if (pPixmap->drawable.bitsPerPixel < 8)
+	return;
+
+    if (pExaPixmap->accel_blocked)
+	return;
+
+    if (pExaPixmap->area == NULL) {
+	pExaPixmap->area =
+	    exaOffscreenAlloc (pScreen, pExaPixmap->fb_size,
+			       pExaScr->info->pixmapOffsetAlign, FALSE,
+                               exaPixmapSave, (pointer) pPixmap);
+	if (pExaPixmap->area == NULL)
+	    return;
+
+	pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
+				       pExaPixmap->area->offset;
+    }
+
+    exaCopyDirtyToFb (migrate);
+
+    if (exaPixmapIsOffscreen(pPixmap))
+	return;
+
+    DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
+		  (ExaGetPixmapPriv(pPixmap)->area ?
+                   ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+		  pPixmap->drawable.width,
+		  pPixmap->drawable.height,
+		  exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
+
+    pExaPixmap->offscreen = TRUE;
+
+    pPixmap->devKind = pExaPixmap->fb_pitch;
+    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
+ * updated data out if necessary.
+ */
+static void
+exaDoMoveOutPixmap (ExaMigrationPtr migrate)
+{
+    PixmapPtr pPixmap = migrate->pPix;
+    ExaPixmapPriv (pPixmap);
+
+    if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
+	return;
+
+    exaCopyDirtyToSys (migrate);
+
+    if (exaPixmapIsOffscreen(pPixmap)) {
+
+	DBG_MIGRATE (("<- %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'));
+
+	pExaPixmap->offscreen = FALSE;
+
+	pPixmap->devKind = pExaPixmap->sys_pitch;
+	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
+ * framebuffer memory.
+ */
+static void
+exaMigrateTowardFb (ExaMigrationPtr migrate)
+{
+    PixmapPtr pPixmap = migrate->pPix;
+    ExaPixmapPriv (pPixmap);
+
+    if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
+	DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
+		     (pointer)pPixmap));
+	return;
+    }
+
+    DBG_MIGRATE(("UseScreen %p score %d\n",
+		 (pointer)pPixmap, pExaPixmap->score));
+
+    if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
+	exaDoMoveInPixmap(migrate);
+	pExaPixmap->score = 0;
+    }
+
+    if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
+	pExaPixmap->score++;
+
+    if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
+	!exaPixmapIsOffscreen(pPixmap))
+    {
+	exaDoMoveInPixmap(migrate);
+    }
+
+    if (exaPixmapIsOffscreen(pPixmap)) {
+	exaCopyDirtyToFb (migrate);
+	ExaOffscreenMarkUsed (pPixmap);
+    } else
+	exaCopyDirtyToSys (migrate);
+}
+
+/**
+ * For the "greedy" migration scheme, pushes the pixmap toward being located in
+ * system memory.
+ */
+static void
+exaMigrateTowardSys (ExaMigrationPtr migrate)
+{
+    PixmapPtr pPixmap = migrate->pPix;
+    ExaPixmapPriv (pPixmap);
+
+    DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score));
+
+    if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
+	return;
+
+    if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
+	pExaPixmap->score = 0;
+
+    if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
+	pExaPixmap->score--;
+
+    if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
+	exaDoMoveOutPixmap(migrate);
+
+    if (exaPixmapIsOffscreen(pPixmap)) {
+	exaCopyDirtyToFb (migrate);
+	ExaOffscreenMarkUsed (pPixmap);
+    } else
+	exaCopyDirtyToSys (migrate);
+}
+
+/**
+ * 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_offscreen;
+
+    if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
+	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;
+    src_pitch = pExaPixmap->fb_pitch;
+    cpp = pPixmap->drawable.bitsPerPixel / 8;
+
+    save_offscreen = pExaPixmap->offscreen;
+    save_pitch = pPixmap->devKind;
+    pExaPixmap->offscreen = TRUE;
+    pPixmap->devKind = pExaPixmap->fb_pitch;
+
+    if (!ExaDoPrepareAccess(&pPixmap->drawable, 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->offscreen = save_offscreen;
+    pPixmap->devKind = save_pitch;
+
+out:
+    REGION_UNINIT(pScreen, &ValidReg);
+    return ret;
+}
+
+/**
+ * Performs migration of the pixmaps according to the operation information
+ * provided in pixmaps and can_accel and the migration scheme chosen in the
+ * config file.
+ */
+void
+exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
+{
+    ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    int i, j;
+
+    /* If this debugging flag is set, check each pixmap for whether it is marked
+     * as clean, and if so, actually check if that's the case.  This should help
+     * catch issues with failing to mark a drawable as dirty.  While it will
+     * catch them late (after the operation happened), it at least explains what
+     * went wrong, and instrumenting the code to find what operation happened
+     * to the pixmap last shouldn't be hard.
+     */
+    if (pExaScr->checkDirtyCorrectness) {
+	for (i = 0; i < npixmaps; i++) {
+	    if (!exaPixmapIsDirty (pixmaps[i].pPix) &&
+		!exaAssertNotDirty (pixmaps[i].pPix))
+		ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i);
+	}
+    }
+    /* 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 (pExaScr->migration == ExaMigrationSmart) {
+	/* If we've got something as a destination that we shouldn't cause to
+	 * become newly dirtied, take the unaccelerated route.
+	 */
+	for (i = 0; i < npixmaps; i++) {
+	    if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) &&
+		!exaPixmapIsDirty (pixmaps[i].pPix))
+	    {
+		for (i = 0; i < npixmaps; i++) {
+		    if (!exaPixmapIsDirty (pixmaps[i].pPix))
+			exaDoMoveOutPixmap (pixmaps + i);
+		}
+		return;
+	    }
+	}
+
+	/* If we aren't going to accelerate, then we migrate everybody toward
+	 * system memory, and kick out if it's free.
+	 */
+	if (!can_accel) {
+	    for (i = 0; i < npixmaps; i++) {
+		exaMigrateTowardSys (pixmaps + i);
+		if (!exaPixmapIsDirty (pixmaps[i].pPix))
+		    exaDoMoveOutPixmap (pixmaps + i);
+	    }
+	    return;
+	}
+
+	/* Finally, the acceleration path.  Move them all in. */
+	for (i = 0; i < npixmaps; i++) {
+	    exaMigrateTowardFb(pixmaps + i);
+	    exaDoMoveInPixmap(pixmaps + i);
+	}
+    } else if (pExaScr->migration == ExaMigrationGreedy) {
+	/* 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);
+	    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 + i);
+		return;
+	    }
+	}
+
+	/* Nobody's in FB, so move all away from FB. */
+	for (i = 0; i < npixmaps; i++)
+	    exaMigrateTowardSys(pixmaps + i);
+    } else if (pExaScr->migration == ExaMigrationAlways) {
+	/* 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
+	 * back out.
+	 */
+	if (!can_accel) {
+	    for (i = 0; i < npixmaps; i++)
+		exaDoMoveOutPixmap(pixmaps + i);
+	    return;
+	}
+
+	/* Now, try to move them all into FB */
+	for (i = 0; i < npixmaps; i++) {
+	    exaDoMoveInPixmap(pixmaps + i);
+	}
+
+	/* If we couldn't fit everything in, abort */
+	for (i = 0; i < npixmaps; i++) {
+	    if (!exaPixmapIsOffscreen(pixmaps[i].pPix)) {
+		return;
+	    }
+	}
+
+	/* Yay, everything's offscreen, mark memory as used */
+	for (i = 0; i < npixmaps; i++) {
+	    ExaOffscreenMarkUsed (pixmaps[i].pPix);
+	}
+    }
+}
diff --git a/exa/exa_migration_mixed.c b/exa/exa_migration_mixed.c
new file mode 100644
index 0000000..475b76a
--- /dev/null
+++ b/exa/exa_migration_mixed.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright © 2009 Maarten Maathuis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <string.h>
+
+#include "exa_priv.h"
+#include "exa.h"
+
+static void
+exaUploadFallback(PixmapPtr pPixmap, CARD8 *src, int src_pitch,
+	      CARD8 *dst, int dst_pitch)
+ {
+    int i;
+
+    for (i = pPixmap->drawable.height; i; i--) {
+	memcpy (dst, src, min(src_pitch, dst_pitch));
+	src += src_pitch;
+	dst += dst_pitch;
+    }
+}
+
+void
+exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    ExaPixmapPriv(pPixmap);
+    void *sys_buffer = pExaPixmap->sys_ptr;
+    int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
+    int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
+    int usage_hint = pPixmap->usage_hint;
+    int sys_pitch = pExaPixmap->sys_pitch;
+    int paddedWidth = sys_pitch;
+
+    /* Already done. */
+    if (pExaPixmap->driverPriv)
+	return;
+
+    if (exaPixmapIsPinned(pPixmap))
+	return;
+
+    /* Can't accel 1/4 bpp. */
+    if (pExaPixmap->accel_blocked || bpp < 8)
+	return;
+
+    if (paddedWidth < pExaPixmap->fb_pitch)
+        paddedWidth = pExaPixmap->fb_pitch;
+
+    if (pExaScr->info->CreatePixmap2)
+	pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp);
+    else
+	pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, paddedWidth*h, 0);
+
+    if (!pExaPixmap->driverPriv)
+	return;
+
+    pExaPixmap->offscreen = TRUE;
+    pExaPixmap->sys_ptr = NULL;
+
+    pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+    (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
+				paddedWidth, NULL);
+
+    /* scratch pixmaps */
+    if (!w || !h)
+	goto finish;
+
+    if (!pExaScr->info->UploadToScreen)
+	goto fallback;
+
+    if (pExaScr->info->UploadToScreen(pPixmap, 0, 0, w, h, sys_buffer, sys_pitch))
+	goto finish;
+
+fallback:
+    ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
+    exaUploadFallback(pPixmap, sys_buffer, sys_pitch, pPixmap->devPrivate.ptr,
+	exaGetPixmapPitch(pPixmap));
+    exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
+
+finish:
+    free(sys_buffer);
+}
+
+void
+exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
+{
+    int i;
+
+    /* 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))
+	{
+	    can_accel = FALSE;
+	    break;
+	}
+    }
+
+    /* We can do nothing. */
+    if (!can_accel)
+	return;
+
+    for (i = 0; i < npixmaps; i++) {
+	PixmapPtr pPixmap = pixmaps[i].pPix;
+	ExaPixmapPriv(pPixmap);
+	if (!pExaPixmap->driverPriv)
+	    exaCreateDriverPixmap_mixed(pPixmap);
+    }
+}
diff --git a/exa/exa_mixed.c b/exa/exa_mixed.c
new file mode 100644
index 0000000..26406c4
--- /dev/null
+++ b/exa/exa_mixed.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright © 2009 Maarten Maathuis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <string.h>
+
+#include "exa_priv.h"
+#include "exa.h"
+
+/* This file holds the driver allocated pixmaps + better initial placement code.
+ * A pinned pixmap implies one that is either driver based already or otherwise altered.
+ * Proper care is taken to free the initially allocated buffer.
+ */
+
+static _X_INLINE void*
+ExaGetPixmapAddress(PixmapPtr p)
+{
+    ExaPixmapPriv(p);
+
+    return pExaPixmap->sys_ptr;
+}
+
+/**
+ * exaCreatePixmap() creates a new pixmap.
+ *
+ * Pixmaps are always marked as pinned, unless the pixmap can still be transfered to a
+ * driver pixmaps.
+ */
+PixmapPtr
+exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
+		unsigned usage_hint)
+{
+    PixmapPtr pPixmap;
+    ExaPixmapPrivPtr	pExaPixmap;
+    int bpp;
+    size_t paddedWidth, datasize;
+    ExaScreenPriv(pScreen);
+
+    if (w > 32767 || h > 32767)
+	return NullPixmap;
+
+    swap(pExaScr, pScreen, CreatePixmap);
+    pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
+    swap(pExaScr, pScreen, CreatePixmap);
+
+    if (!pPixmap)
+        return NULL;
+
+    pExaPixmap = ExaGetPixmapPriv(pPixmap);
+    pExaPixmap->driverPriv = NULL;
+
+    bpp = pPixmap->drawable.bitsPerPixel;
+
+    paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
+    if (paddedWidth / 4 > 32767 || h > 32767)
+        return NullPixmap;
+
+    datasize = h * paddedWidth;
+
+    /* Allocate temporary pixmap. */
+    pExaPixmap->sys_ptr = malloc(datasize);
+    pExaPixmap->sys_pitch = paddedWidth;
+
+    if (!pExaPixmap->sys_ptr) {
+	swap(pExaScr, pScreen, DestroyPixmap);
+	pScreen->DestroyPixmap (pPixmap);
+	swap(pExaScr, pScreen, DestroyPixmap);
+	return NULL;
+    }
+
+    pExaPixmap->area = NULL;
+    pExaPixmap->offscreen = FALSE;
+    pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
+    pExaPixmap->fb_ptr = NULL;
+    pExaPixmap->pDamage = NULL;
+
+    exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
+    exaSetAccelBlock(pExaScr, pExaPixmap,
+	w, h, bpp);
+
+    /* A scratch pixmap will become a driver pixmap right away. */
+    if (!w || !h) {
+	exaCreateDriverPixmap_mixed(pPixmap);
+    } else {
+	/* Avoid freeing sys_ptr. */
+	pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+
+	(*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
+					paddedWidth, NULL);
+
+	/* We want to be able to copy the pixmap to driver memory later on. */
+	pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
+    }
+
+    return pPixmap;
+}
+
+Bool
+exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
+		      int bitsPerPixel, int devKind, pointer pPixData)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPrivPtr pExaScr;
+    ExaPixmapPrivPtr pExaPixmap;
+    Bool ret;
+
+    if (!pPixmap)
+        return FALSE;
+
+    pExaScr = ExaGetScreenPriv(pScreen);
+    pExaPixmap = ExaGetPixmapPriv(pPixmap);
+
+    if (pExaPixmap) {
+        if (pPixData) {
+	    if (!exaPixmapIsPinned(pPixmap))
+		free(pExaPixmap->sys_ptr);
+            pExaPixmap->sys_ptr = pPixData;
+	}
+
+        if (devKind > 0)
+            pExaPixmap->sys_pitch = devKind;
+
+        if (width > 0 && height > 0 && bitsPerPixel > 0) {
+            exaSetFbPitch(pExaScr, pExaPixmap,
+                          width, height, bitsPerPixel);
+
+            exaSetAccelBlock(pExaScr, pExaPixmap,
+                             width, height, bitsPerPixel);
+        }
+
+	/* Anything can happen, don't try to predict it all. */
+	pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+    }
+
+    /* Only pass driver pixmaps to the driver. */
+    if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) {
+	ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
+						bitsPerPixel, devKind, pPixData);
+	/* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
+	 * If pPixmap->devPrivate.ptr is non-NULL, then we've got a non-offscreen pixmap.
+	 * We need to store the pointer, because PrepareAccess won't be called.
+	 */
+	if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
+	    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
+	    pExaPixmap->sys_pitch = pPixmap->devKind;
+	}
+	if (ret == TRUE)
+	    goto out;
+    }
+
+    swap(pExaScr, pScreen, ModifyPixmapHeader);
+    ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
+					    bitsPerPixel, devKind, pPixData);
+    swap(pExaScr, pScreen, ModifyPixmapHeader);
+
+out:
+    /* Always NULL this, we don't want lingering pointers. */
+    pPixmap->devPrivate.ptr = NULL;
+
+    return ret;
+}
+
+Bool
+exaDestroyPixmap_mixed(PixmapPtr pPixmap)
+{
+    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    Bool ret;
+
+    if (pPixmap->refcnt == 1)
+    {
+	ExaPixmapPriv (pPixmap);
+
+	if (pExaPixmap->driverPriv)
+	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
+	else if (pExaPixmap->sys_ptr && !exaPixmapIsPinned(pPixmap))
+	    free(pExaPixmap->sys_ptr);
+	pExaPixmap->driverPriv = NULL;
+	pExaPixmap->sys_ptr = NULL;
+    }
+
+    swap(pExaScr, pScreen, DestroyPixmap);
+    ret = pScreen->DestroyPixmap (pPixmap);
+    swap(pExaScr, pScreen, DestroyPixmap);
+
+    return ret;
+}
+
+Bool
+exaPixmapIsOffscreen_mixed(PixmapPtr pPixmap)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    ExaPixmapPriv(pPixmap);
+    Bool ret;
+
+    if (!pExaPixmap->driverPriv)
+	return FALSE;
+
+    pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
+    ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
+    pPixmap->devPrivate.ptr = NULL;
+
+    return ret;
+}
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 3c34513..620bc67 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -547,6 +547,9 @@ exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
 void
 exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
 
+Bool
+exaPixmapIsPinned (PixmapPtr pPix);
+
 extern const GCFuncs exaGCFuncs;
 
 /* exa_classic.c */
@@ -579,6 +582,28 @@ exaDestroyPixmap_driver (PixmapPtr pPixmap);
 Bool
 exaPixmapIsOffscreen_driver(PixmapPtr pPixmap);
 
+/* exa_mixed.c */
+PixmapPtr
+exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
+		unsigned usage_hint);
+
+Bool
+exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
+		      int bitsPerPixel, int devKind, pointer pPixData);
+
+Bool
+exaDestroyPixmap_mixed(PixmapPtr pPixmap);
+
+Bool
+exaPixmapIsOffscreen_mixed(PixmapPtr pPixmap);
+
+/* exa_migration_mixed.c */
+void
+exaCreateDriverPixmap_mixed(PixmapPtr pPixmap);
+
+void
+exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
+
 /* exa_render.c */
 Bool
 exaOpReadsDestination (CARD8 op);
@@ -633,7 +658,7 @@ exaGlyphs (CARD8	op,
 	  GlyphListPtr	list,
 	  GlyphPtr	*glyphs);
 
-/* exa_migration.c */
+/* exa_migration_classic.c */
 void
 exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
 
diff --git a/exa/exa_render.c b/exa/exa_render.c
index 3c822d1..1ac29f2 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -301,7 +301,7 @@ exaTryDriverSolidFill(PicturePtr	pSrc,
 
     pixel = exaGetPixmapFirstPixel (pSrcPix);
 
-    if (pDstExaPix->pDamage) {
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[1];
 
 	pixmaps[0].as_dst = TRUE;
@@ -395,8 +395,7 @@ exaTryDriverCompositeRects(CARD8	       op,
 	return -1;
     }
 
-    if (pSrcExaPix->pDamage || pDstExaPix->pDamage ||
-	(pMask && pMaskExaPix->pDamage)) {
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[3];
 
 	pixmaps[0].as_dst = TRUE;
@@ -507,8 +506,6 @@ exaCompositeRects(CARD8	              op,
 		  ExaCompositeRectPtr rects)
 {
     ExaScreenPriv (pDst->pDrawable->pScreen);
-    PixmapPtr pPixmap = exaGetDrawablePixmap(pDst->pDrawable);
-    ExaPixmapPriv(pPixmap);
     int n;
     ExaCompositeRectPtr r;
     int ret;
@@ -516,7 +513,7 @@ exaCompositeRects(CARD8	              op,
     /* If we get a mask, that means we're rendering to the exaGlyphs
      * destination directly, so the damage layer takes care of this.
      */
-    if (!pMask && pExaPixmap->pDamage) {
+    if (!pMask) {
 	RegionRec region;
 	int x1 = MAXSHORT;
 	int y1 = MAXSHORT;
@@ -610,7 +607,7 @@ exaCompositeRects(CARD8	              op,
     
     /************************************************************/
 
-    if (!pMask && pExaPixmap->pDamage) {
+    if (!pMask) {
 	/* Now we have to flush the damage out from pendingDamage => damage 
 	 * Calling DamageRegionProcessPending has that effect.
 	 */
@@ -689,8 +686,7 @@ exaTryDriverComposite(CARD8		op,
 
     REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
 
-    if (pSrcExaPix->pDamage || pDstExaPix->pDamage ||
-	(pMask && pMaskExaPix->pDamage)) {
+    if (pExaScr->do_migration) {
 	ExaMigrationRec pixmaps[3];
 
 	pixmaps[0].as_dst = TRUE;
@@ -707,9 +703,8 @@ exaTryDriverComposite(CARD8		op,
 	    pixmaps[2].pPix = pMaskPix;
 	    pixmaps[2].pReg = NULL;
 	    exaDoMigration(pixmaps, 3, TRUE);
-	} else {
+	} else
 	    exaDoMigration(pixmaps, 2, TRUE);
-	}
     }
 
     pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
commit ac7ac913fd98ea359c05c89968ab53a3223615b4
Author: Maarten Maathuis <madman2003 at gmail.com>
Date:   Wed Jul 22 21:35:41 2009 +0200

    exa: Split out some classic and driver allocated pixmap code into seperate files
    
    - Create a few seperate functions and a few private function pointers.
    - Replace a few if conditions with a check for pExaPix->pDamage instead.
    - This is in preperation of a third scheme that lies somewhere in between.
    - Code clarity would have suffered (i started working on it and didn't like the mess).

diff --git a/exa/Makefile.am b/exa/Makefile.am
index 2b3f1e4..bf2c138 100644
--- a/exa/Makefile.am
+++ b/exa/Makefile.am
@@ -17,11 +17,12 @@ AM_CFLAGS = $(XORG_CFLAGS) $(DIX_CFLAGS)
 libexa_la_SOURCES = \
 	exa.c \
 	exa.h \
+	exa_classic.c \
+	exa_migration.c \
+	exa_driver.c \
 	exa_accel.c \
 	exa_glyphs.c \
-	exa_migration.c \
 	exa_offscreen.c \
 	exa_render.c \
 	exa_priv.h \
 	exa_unaccel.c
-
diff --git a/exa/exa.c b/exa/exa.c
index daa4a7a..0f37168 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -48,17 +48,6 @@ DevPrivateKey exaGCPrivateKey = &exaGCPrivateKeyIndex;
 static ShmFuncs exaShmFuncs = { NULL, NULL };
 #endif
 
-static _X_INLINE void*
-ExaGetPixmapAddress(PixmapPtr p)
-{
-    ExaPixmapPriv(p);
-
-    if (pExaPixmap->offscreen && pExaPixmap->fb_ptr)
-	return pExaPixmap->fb_ptr;
-    else
-	return pExaPixmap->sys_ptr;
-}
-
 /**
  * exaGetPixmapOffset() returns the offset (in bytes) within the framebuffer of
  * the beginning of the given pixmap.
@@ -178,45 +167,6 @@ exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2)
     REGION_UNINIT(pScreen, &region);
 }
 
-static Bool
-exaDestroyPixmap (PixmapPtr pPixmap)
-{
-    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
-    ExaScreenPriv(pScreen);
-    Bool ret;
-
-    if (pPixmap->refcnt == 1)
-    {
-	ExaPixmapPriv (pPixmap);
-
-	if (pExaPixmap->driverPriv) {
-	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
-	    pExaPixmap->driverPriv = NULL;
-	}
-
-	if (pExaPixmap->area)
-	{
-	    DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
-                        (void*)pPixmap->drawable.id,
-			 ExaGetPixmapPriv(pPixmap)->area->offset,
-			 pPixmap->drawable.width,
-			 pPixmap->drawable.height));
-	    /* Free the offscreen area */
-	    exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area);
-	    pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
-	    pPixmap->devKind = pExaPixmap->sys_pitch;
-	}
-	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validSys);
-	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validFB);
-    }
-
-    swap(pExaScr, pScreen, DestroyPixmap);
-    ret = pScreen->DestroyPixmap (pPixmap);
-    swap(pExaScr, pScreen, DestroyPixmap);
-
-    return ret;
-}
-
 static int
 exaLog2(int val)
 {
@@ -229,7 +179,7 @@ exaLog2(int val)
     return bits - 1;
 }
 
-static void
+void
 exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
                  int w, int h, int bpp)
 {
@@ -253,7 +203,7 @@ exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
         pExaPixmap->accel_blocked |= EXA_RANGE_HEIGHT;
 }
 
-static void
+void
 exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
               int w, int h, int bpp)
 {
@@ -267,227 +217,6 @@ exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
 }
 
 /**
- * exaCreatePixmap() creates a new pixmap.
- *
- * If width and height are 0, this won't be a full-fledged pixmap and it will
- * get ModifyPixmapHeader() called on it later.  So, we mark it as pinned, because
- * ModifyPixmapHeader() would break migration.  These types of pixmaps are used
- * for scratch pixmaps, or to represent the visible screen.
- */
-static PixmapPtr
-exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth,
-		unsigned usage_hint)
-{
-    PixmapPtr		pPixmap;
-    ExaPixmapPrivPtr	pExaPixmap;
-    BoxRec box;
-    int                 driver_alloc = 0;
-    int			bpp;
-    ExaScreenPriv(pScreen);
-
-    if (w > 32767 || h > 32767)
-	return NullPixmap;
-
-    swap(pExaScr, pScreen, CreatePixmap);
-    if (!pExaScr->info->CreatePixmap && !pExaScr->info->CreatePixmap2) {
-        pPixmap = pScreen->CreatePixmap (pScreen, w, h, depth, usage_hint);
-    } else {
-        driver_alloc = 1;
-        pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
-    }
-    swap(pExaScr, pScreen, CreatePixmap);
-
-    if (!pPixmap)
-        return NULL;
-
-    pExaPixmap = ExaGetPixmapPriv(pPixmap);
-    pExaPixmap->driverPriv = NULL;
-
-    bpp = pPixmap->drawable.bitsPerPixel;
-
-    if (driver_alloc) {
-        size_t paddedWidth, datasize;
-
-	paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
-        if (paddedWidth / 4 > 32767 || h > 32767)
-            return NullPixmap;
-
-        exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
-
-        if (paddedWidth < pExaPixmap->fb_pitch)
-            paddedWidth = pExaPixmap->fb_pitch;
-
-        datasize = h * paddedWidth;
-
-	/* Set this before driver hooks, to allow for !offscreen pixmaps.
-	 * !offscreen pixmaps have a valid pointer at all times.
-	 */
-	pPixmap->devPrivate.ptr = NULL;
-
-	if (pExaScr->info->CreatePixmap2)
-        	pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp);
-	else
-        	pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0);
-        if (!pExaPixmap->driverPriv) {
-	    swap(pExaScr, pScreen, DestroyPixmap);
-	    pScreen->DestroyPixmap (pPixmap);
-	    swap(pExaScr, pScreen, DestroyPixmap);
-	    return NULL;
-        }
-
-	/* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
-	pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
-	pExaPixmap->fb_ptr = NULL;
-	pExaPixmap->pDamage = NULL;
-	pExaPixmap->sys_ptr = NULL;
-
-	(*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
-					paddedWidth, NULL);
-
-    } else {
-        pExaPixmap->driverPriv = NULL;
-        /* Scratch pixmaps may have w/h equal to zero, and may not be
-	 * migrated.
-	 */
-        if (!w || !h)
-	    pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
-        else
-            pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
-
-        pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
-        pExaPixmap->sys_pitch = pPixmap->devKind;
-
-        pPixmap->devPrivate.ptr = NULL;
-        pExaPixmap->offscreen = FALSE;
-
-        pExaPixmap->fb_ptr = NULL;
-        exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
-        pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
-
-        if (pExaPixmap->fb_pitch > 131071) {
-	    swap(pExaScr, pScreen, DestroyPixmap);
-	    pScreen->DestroyPixmap (pPixmap);
-	    swap(pExaScr, pScreen, DestroyPixmap);
-	    return NULL;
-        }
-
-	/* Set up damage tracking */
-	pExaPixmap->pDamage = DamageCreate (NULL, NULL,
-					    DamageReportNone, TRUE,
-					    pScreen, pPixmap);
-
-	if (pExaPixmap->pDamage == NULL) {
-	    swap(pExaScr, pScreen, DestroyPixmap);
-	    pScreen->DestroyPixmap (pPixmap);
-	    swap(pExaScr, pScreen, DestroyPixmap);
-	    return NULL;
-	}
-
-	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);
-    }
-
-    pExaPixmap->area = NULL;
-
-    /* We set the initial pixmap as completely valid for a simple reason.
-     * Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which
-     * could form single pixel rects as part of a region. Setting the complete region
-     * as valid is a natural defragmentation of the region.
-     */
-    box.x1 = 0;
-    box.y1 = 0;
-    box.x2 = w;
-    box.y2 = h;
-    REGION_INIT(pScreen, &pExaPixmap->validSys, &box, 0);
-    REGION_INIT(pScreen, &pExaPixmap->validFB, &box, 0);
-
-    exaSetAccelBlock(pExaScr, pExaPixmap,
-                     w, h, bpp);
-
-    return pPixmap;
-}
-
-static Bool
-exaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth,
-		      int bitsPerPixel, int devKind, pointer pPixData)
-{
-    ExaScreenPrivPtr pExaScr;
-    ExaPixmapPrivPtr pExaPixmap;
-    Bool ret;
-
-    if (!pPixmap)
-        return FALSE;
-
-    pExaScr = ExaGetScreenPriv(pPixmap->drawable.pScreen);
-    pExaPixmap = ExaGetPixmapPriv(pPixmap);
-
-    if (pExaPixmap) {
-        if (pPixData)
-            pExaPixmap->sys_ptr = pPixData;
-
-        if (devKind > 0)
-            pExaPixmap->sys_pitch = devKind;
-
-	/* Classic EXA:
-	 * - Framebuffer.
-	 * - Scratch pixmap with offscreen memory.
-	 */
-	if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) &&
-		pExaScr->info->memoryBase && pPixData) {
-	    if ((CARD8 *)pPixData >= pExaScr->info->memoryBase &&
-		((CARD8 *)pPixData - pExaScr->info->memoryBase) <
-				pExaScr->info->memorySize) {
-		pExaPixmap->fb_ptr = pPixData;
-		pExaPixmap->fb_pitch = devKind;
-		pExaPixmap->offscreen = TRUE;
-	    }
-	}
-
-        if (width > 0 && height > 0 && bitsPerPixel > 0) {
-            exaSetFbPitch(pExaScr, pExaPixmap,
-                          width, height, bitsPerPixel);
-
-            exaSetAccelBlock(pExaScr, pExaPixmap,
-                             width, height, bitsPerPixel);
-        }
-
-	/* Pixmaps subject to ModifyPixmapHeader will be pinned to system or
-	 * offscreen memory, so there's no need to track damage.
-	 */
-	if (pExaPixmap->pDamage) {
-	    DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
-	    DamageDestroy(pExaPixmap->pDamage);
-	    pExaPixmap->pDamage = NULL;
-	}
-    }
-
-    if (pExaScr->info->ModifyPixmapHeader) {
-	ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
-						bitsPerPixel, devKind, pPixData);
-	/* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
-	 * If pPixmap->devPrivate.ptr is non-NULL, then we've got a non-offscreen pixmap.
-	 * We need to store the pointer, because PrepareAccess won't be called.
-	 */
-	if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
-	    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
-	    pExaPixmap->sys_pitch = pPixmap->devKind;
-	}
-	if (ret == TRUE)
-	    goto out;
-    }
-    ret = pExaScr->SavedModifyPixmapHeader(pPixmap, width, height, depth,
-					    bitsPerPixel, devKind, pPixData);
-
-out:
-    /* Always NULL this, we don't want lingering pointers. */
-    pPixmap->devPrivate.ptr = NULL;
-
-    return ret;
-}
-
-/**
  * exaPixmapIsOffscreen() is used to determine if a pixmap is in offscreen
  * memory, meaning that acceleration could probably be done to it, and that it
  * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
@@ -500,21 +229,15 @@ out:
  * @return TRUE if the given drawable is in framebuffer memory.
  */
 Bool
-exaPixmapIsOffscreen(PixmapPtr p)
+exaPixmapIsOffscreen(PixmapPtr pPixmap)
 {
-    ScreenPtr	pScreen = p->drawable.pScreen;
+    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
     ExaScreenPriv(pScreen);
-    ExaPixmapPriv(p);
-    Bool ret;
 
-    if (pExaScr->info->PixmapIsOffscreen) {
-	p->devPrivate.ptr = ExaGetPixmapAddress(p);
-	ret = pExaScr->info->PixmapIsOffscreen(p);
-	p->devPrivate.ptr = NULL;
-    } else
-	ret = (pExaPixmap->offscreen && pExaPixmap->fb_ptr);
+    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
+	return FALSE;
 
-    return ret;
+    return pExaScr->pixmap_is_offscreen(pPixmap);
 }
 
 /**
@@ -1313,10 +1036,19 @@ exaDriverInit (ScreenPtr		pScreen,
 		       pScreen->myNum);
 	    return FALSE;
         }
-	wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap);
-	wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap);
-
-	wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader);
+	if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) {
+	    wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver);
+	    wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver);
+	    wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_driver);
+	    pExaScr->do_migration = NULL;
+	    pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_driver;
+	} else {
+	    wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic);
+	    wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_classic);
+	    wrap(pExaScr, pScreen, ModifyPixmapHeader, exaModifyPixmapHeader_classic);
+	    pExaScr->do_migration = exaDoMigration_classic;
+	    pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_classic;
+	}
 	if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
 	    LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n",
 		       pScreen->myNum,
@@ -1414,3 +1146,21 @@ void exaWaitSync(ScreenPtr pScreen)
         pExaScr->info->needsSync = FALSE;
     }
 }
+
+/**
+ * Performs migration of the pixmaps according to the operation information
+ * provided in pixmaps and can_accel and the migration scheme chosen in the
+ * config file.
+ */
+void
+exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
+{
+    ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+
+    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
+	return;
+
+    if (pExaScr->do_migration)
+	pExaScr->do_migration(pixmaps, npixmaps, can_accel);
+}
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index 3aa5578..bc970bb 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -1015,7 +1015,7 @@ exaFillRegionSolid (DrawablePtr	pDrawable, RegionPtr pRegion, Pixel pixel,
 	(*pExaScr->info->DoneSolid) (pPixmap);
 	exaMarkSync(pDrawable->pScreen);
 
-	if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) &&
+	if (pExaPixmap->pDamage &&
 	    pDrawable->width == 1 && pDrawable->height == 1 &&
 	    pDrawable->bitsPerPixel != 24) {
 	    ExaPixmapPriv(pPixmap);
@@ -1233,13 +1233,14 @@ exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
 {
     ExaScreenPriv (pDrawable->pScreen);
     PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
+    ExaPixmapPrivPtr pExaPixmap = ExaGetPixmapPriv (pPix);
     int xoff, yoff;
     Bool ok;
 
     if (pExaScr->swappedOut)
 	goto fallback;
 
-    if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
+    if (pExaPixmap->pDamage) {
 	BoxRec Box;
 	RegionRec Reg;
 	ExaMigrationRec pixmaps[1];
diff --git a/exa/exa_classic.c b/exa/exa_classic.c
new file mode 100644
index 0000000..1eff570
--- /dev/null
+++ b/exa/exa_classic.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright © 2009 Maarten Maathuis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <string.h>
+
+#include "exa_priv.h"
+#include "exa.h"
+
+/* This file holds the classic exa specific implementation. */
+
+static _X_INLINE void*
+ExaGetPixmapAddress(PixmapPtr p)
+{
+    ExaPixmapPriv(p);
+
+    if (pExaPixmap->offscreen && pExaPixmap->fb_ptr)
+	return pExaPixmap->fb_ptr;
+    else
+	return pExaPixmap->sys_ptr;
+}
+
+/**
+ * exaCreatePixmap() creates a new pixmap.
+ *
+ * If width and height are 0, this won't be a full-fledged pixmap and it will
+ * get ModifyPixmapHeader() called on it later.  So, we mark it as pinned, because
+ * ModifyPixmapHeader() would break migration.  These types of pixmaps are used
+ * for scratch pixmaps, or to represent the visible screen.
+ */
+PixmapPtr
+exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
+		unsigned usage_hint)
+{
+    PixmapPtr pPixmap;
+    ExaPixmapPrivPtr	pExaPixmap;
+    BoxRec box;
+    int bpp;
+    ExaScreenPriv(pScreen);
+
+    if (w > 32767 || h > 32767)
+	return NullPixmap;
+
+    swap(pExaScr, pScreen, CreatePixmap);
+    pPixmap = pScreen->CreatePixmap (pScreen, w, h, depth, usage_hint);
+    swap(pExaScr, pScreen, CreatePixmap);
+
+    if (!pPixmap)
+        return NULL;
+
+    pExaPixmap = ExaGetPixmapPriv(pPixmap);
+    pExaPixmap->driverPriv = NULL;
+
+    bpp = pPixmap->drawable.bitsPerPixel;
+
+    pExaPixmap->driverPriv = NULL;
+    /* Scratch pixmaps may have w/h equal to zero, and may not be
+     * migrated.
+     */
+    if (!w || !h)
+	pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+    else
+	pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
+
+    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
+    pExaPixmap->sys_pitch = pPixmap->devKind;
+
+    pPixmap->devPrivate.ptr = NULL;
+    pExaPixmap->offscreen = FALSE;
+
+    pExaPixmap->fb_ptr = NULL;
+    exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
+    pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
+
+    if (pExaPixmap->fb_pitch > 131071) {
+	swap(pExaScr, pScreen, DestroyPixmap);
+	pScreen->DestroyPixmap (pPixmap);
+	swap(pExaScr, pScreen, DestroyPixmap);
+	return NULL;
+    }
+
+    /* Set up damage tracking */
+    pExaPixmap->pDamage = DamageCreate (NULL, NULL,
+					DamageReportNone, TRUE,
+					pScreen, pPixmap);
+
+    if (pExaPixmap->pDamage == NULL) {
+	swap(pExaScr, pScreen, DestroyPixmap);
+	pScreen->DestroyPixmap (pPixmap);
+	swap(pExaScr, pScreen, DestroyPixmap);
+	return NULL;
+    }
+
+    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);
+
+    pExaPixmap->area = NULL;
+
+    /* We set the initial pixmap as completely valid for a simple reason.
+     * Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which
+     * could form single pixel rects as part of a region. Setting the complete region
+     * as valid is a natural defragmentation of the region.
+     */
+    box.x1 = 0;
+    box.y1 = 0;
+    box.x2 = w;
+    box.y2 = h;
+    REGION_INIT(pScreen, &pExaPixmap->validSys, &box, 0);
+    REGION_INIT(pScreen, &pExaPixmap->validFB, &box, 0);
+
+    exaSetAccelBlock(pExaScr, pExaPixmap,
+                     w, h, bpp);
+
+    return pPixmap;
+}
+
+Bool
+exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height, int depth,
+		      int bitsPerPixel, int devKind, pointer pPixData)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPrivPtr pExaScr;
+    ExaPixmapPrivPtr pExaPixmap;
+    Bool ret;
+
+    if (!pPixmap)
+        return FALSE;
+
+    pExaScr = ExaGetScreenPriv(pScreen);
+    pExaPixmap = ExaGetPixmapPriv(pPixmap);
+
+    if (pExaPixmap) {
+        if (pPixData)
+            pExaPixmap->sys_ptr = pPixData;
+
+        if (devKind > 0)
+            pExaPixmap->sys_pitch = devKind;
+
+	/* Classic EXA:
+	 * - Framebuffer.
+	 * - Scratch pixmap with offscreen memory.
+	 */
+	if (pExaScr->info->memoryBase && pPixData) {
+	    if ((CARD8 *)pPixData >= pExaScr->info->memoryBase &&
+		((CARD8 *)pPixData - pExaScr->info->memoryBase) <
+				pExaScr->info->memorySize) {
+		pExaPixmap->fb_ptr = pPixData;
+		pExaPixmap->fb_pitch = devKind;
+		pExaPixmap->offscreen = TRUE;
+	    }
+	}
+
+        if (width > 0 && height > 0 && bitsPerPixel > 0) {
+            exaSetFbPitch(pExaScr, pExaPixmap,
+                          width, height, bitsPerPixel);
+
+            exaSetAccelBlock(pExaScr, pExaPixmap,
+                             width, height, bitsPerPixel);
+        }
+
+	/* Pixmaps subject to ModifyPixmapHeader will be pinned to system or
+	 * offscreen memory, so there's no need to track damage.
+	 */
+	if (pExaPixmap->pDamage) {
+	    DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
+	    DamageDestroy(pExaPixmap->pDamage);
+	    pExaPixmap->pDamage = NULL;
+	}
+    }
+
+    swap(pExaScr, pScreen, ModifyPixmapHeader);
+    ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
+					    bitsPerPixel, devKind, pPixData);
+    swap(pExaScr, pScreen, ModifyPixmapHeader);
+
+    /* Always NULL this, we don't want lingering pointers. */
+    pPixmap->devPrivate.ptr = NULL;
+
+    return ret;
+}
+
+Bool
+exaDestroyPixmap_classic (PixmapPtr pPixmap)
+{
+    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    Bool ret;
+
+    if (pPixmap->refcnt == 1)
+    {
+	ExaPixmapPriv (pPixmap);
+
+	if (pExaPixmap->area)
+	{
+	    DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
+                        (void*)pPixmap->drawable.id,
+			 ExaGetPixmapPriv(pPixmap)->area->offset,
+			 pPixmap->drawable.width,
+			 pPixmap->drawable.height));
+	    /* Free the offscreen area */
+	    exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area);
+	    pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
+	    pPixmap->devKind = pExaPixmap->sys_pitch;
+	}
+	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validSys);
+	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validFB);
+    }
+
+    swap(pExaScr, pScreen, DestroyPixmap);
+    ret = pScreen->DestroyPixmap (pPixmap);
+    swap(pExaScr, pScreen, DestroyPixmap);
+
+    return ret;
+}
+
+Bool
+exaPixmapIsOffscreen_classic(PixmapPtr pPixmap)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    ExaPixmapPriv(pPixmap);
+    Bool ret;
+
+    if (pExaScr->info->PixmapIsOffscreen) {
+	pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
+	ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
+	pPixmap->devPrivate.ptr = NULL;
+    } else
+	ret = (pExaPixmap->offscreen && pExaPixmap->fb_ptr);
+
+    return ret;
+}
diff --git a/exa/exa_driver.c b/exa/exa_driver.c
new file mode 100644
index 0000000..b4ca426
--- /dev/null
+++ b/exa/exa_driver.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright © 2009 Maarten Maathuis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <string.h>
+
+#include "exa_priv.h"
+#include "exa.h"
+
+/* This file holds the driver allocated pixmaps specific implementation. */
+
+static _X_INLINE void*
+ExaGetPixmapAddress(PixmapPtr p)
+{
+    ExaPixmapPriv(p);
+
+    return pExaPixmap->sys_ptr;
+}
+
+/**
+ * exaCreatePixmap() creates a new pixmap.
+ *
+ * Pixmaps are always marked as pinned, because exa has no control over them.
+ */
+PixmapPtr
+exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
+		unsigned usage_hint)
+{
+    PixmapPtr pPixmap;
+    ExaPixmapPrivPtr	pExaPixmap;
+    int bpp;
+    size_t paddedWidth, datasize;
+    ExaScreenPriv(pScreen);
+
+    if (w > 32767 || h > 32767)
+	return NullPixmap;
+
+    swap(pExaScr, pScreen, CreatePixmap);
+    pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
+    swap(pExaScr, pScreen, CreatePixmap);
+
+    if (!pPixmap)
+        return NULL;
+
+    pExaPixmap = ExaGetPixmapPriv(pPixmap);
+    pExaPixmap->driverPriv = NULL;
+
+    bpp = pPixmap->drawable.bitsPerPixel;
+
+    paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
+    if (paddedWidth / 4 > 32767 || h > 32767)
+        return NullPixmap;
+
+    exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
+
+    if (paddedWidth < pExaPixmap->fb_pitch)
+        paddedWidth = pExaPixmap->fb_pitch;
+
+    datasize = h * paddedWidth;
+
+    /* Set this before driver hooks, to allow for !offscreen pixmaps.
+     * !offscreen pixmaps have a valid pointer at all times.
+     */
+    pPixmap->devPrivate.ptr = NULL;
+
+    if (pExaScr->info->CreatePixmap2)
+	pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp);
+    else
+	pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, datasize, 0);
+    if (!pExaPixmap->driverPriv) {
+	swap(pExaScr, pScreen, DestroyPixmap);
+	pScreen->DestroyPixmap (pPixmap);
+	swap(pExaScr, pScreen, DestroyPixmap);
+	return NULL;
+    }
+
+    /* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
+    pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+    pExaPixmap->fb_ptr = NULL;
+    pExaPixmap->pDamage = NULL;
+    pExaPixmap->sys_ptr = NULL;
+
+    (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
+				    paddedWidth, NULL);
+
+    pExaPixmap->area = NULL;
+
+    exaSetAccelBlock(pExaScr, pExaPixmap,
+                     w, h, bpp);
+
+    return pPixmap;
+}
+
+Bool
+exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height, int depth,
+		      int bitsPerPixel, int devKind, pointer pPixData)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPrivPtr pExaScr;
+    ExaPixmapPrivPtr pExaPixmap;
+    Bool ret;
+
+    if (!pPixmap)
+        return FALSE;
+
+    pExaScr = ExaGetScreenPriv(pScreen);
+    pExaPixmap = ExaGetPixmapPriv(pPixmap);
+
+    if (pExaPixmap) {
+        if (pPixData)
+            pExaPixmap->sys_ptr = pPixData;
+
+        if (devKind > 0)
+            pExaPixmap->sys_pitch = devKind;
+
+        if (width > 0 && height > 0 && bitsPerPixel > 0) {
+            exaSetFbPitch(pExaScr, pExaPixmap,
+                          width, height, bitsPerPixel);
+
+            exaSetAccelBlock(pExaScr, pExaPixmap,
+                             width, height, bitsPerPixel);
+        }
+    }
+
+    if (pExaScr->info->ModifyPixmapHeader) {
+	ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
+						bitsPerPixel, devKind, pPixData);
+	/* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
+	 * If pPixmap->devPrivate.ptr is non-NULL, then we've got a non-offscreen pixmap.
+	 * We need to store the pointer, because PrepareAccess won't be called.
+	 */
+	if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
+	    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
+	    pExaPixmap->sys_pitch = pPixmap->devKind;
+	}
+	if (ret == TRUE)
+	    goto out;
+    }
+
+    swap(pExaScr, pScreen, ModifyPixmapHeader);
+    ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
+					    bitsPerPixel, devKind, pPixData);
+    swap(pExaScr, pScreen, ModifyPixmapHeader);
+
+out:
+    /* Always NULL this, we don't want lingering pointers. */
+    pPixmap->devPrivate.ptr = NULL;
+
+    return ret;
+}
+
+Bool
+exaDestroyPixmap_driver (PixmapPtr pPixmap)
+{
+    ScreenPtr	pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    Bool ret;
+
+    if (pPixmap->refcnt == 1)
+    {
+	ExaPixmapPriv (pPixmap);
+
+	if (pExaPixmap->driverPriv)
+	    pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
+	pExaPixmap->driverPriv = NULL;
+    }
+
+    swap(pExaScr, pScreen, DestroyPixmap);
+    ret = pScreen->DestroyPixmap (pPixmap);
+    swap(pExaScr, pScreen, DestroyPixmap);
+
+    return ret;
+}
+
+Bool
+exaPixmapIsOffscreen_driver(PixmapPtr pPixmap)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    Bool ret;
+
+    pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
+    ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
+    pPixmap->devPrivate.ptr = NULL;
+
+    return ret;
+}
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
index f6805cb..afab9d2 100644
--- a/exa/exa_migration.c
+++ b/exa/exa_migration.c
@@ -607,17 +607,12 @@ out:
  * config file.
  */
 void
-exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
+exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
 {
     ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
     ExaScreenPriv(pScreen);
     int i, j;
 
-    if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
-        return;
-    if (!(pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS))
-	return;
-
     /* If this debugging flag is set, check each pixmap for whether it is marked
      * as clean, and if so, actually check if that's the case.  This should help
      * catch issues with failing to mark a drawable as dirty.  While it will
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index f67a9cb..3c34513 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -142,6 +142,13 @@ typedef struct {
 #define EXA_FALLBACK_COPYWINDOW (1 << 0)
 #define EXA_ACCEL_COPYWINDOW (1 << 1)
 
+typedef struct _ExaMigrationRec {
+    Bool as_dst;
+    Bool as_src;
+    PixmapPtr pPix;
+    RegionPtr pReg;
+} ExaMigrationRec, *ExaMigrationPtr;
+
 typedef void (*EnableDisableFBAccessProcPtr)(int, Bool);
 typedef struct {
     ExaDriverPtr info;
@@ -165,7 +172,9 @@ typedef struct {
     TrapezoidsProcPtr            SavedTrapezoids;
     AddTrapsProcPtr		 SavedAddTraps;
 #endif
-  
+    void (*do_migration) (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
+    Bool (*pixmap_is_offscreen) (PixmapPtr pPixmap);
+
     Bool			 swappedOut;
     enum ExaMigrationHeuristic	 migration;
     Bool			 checkDirtyCorrectness;
@@ -303,13 +312,6 @@ typedef struct {
     GCFuncs *Savedfuncs;
 } ExaGCPrivRec, *ExaGCPrivPtr;
 
-typedef struct _ExaMigrationRec {
-    Bool as_dst;
-    Bool as_src;
-    PixmapPtr pPix;
-    RegionPtr pReg;
-} ExaMigrationRec, *ExaMigrationPtr;
-
 typedef struct {
     PicturePtr pDst;
     INT16 xSrc;
@@ -443,6 +445,34 @@ void
 exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
 	     unsigned int format, unsigned long planeMask, char *d);
 
+RegionPtr
+exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+	    int srcx, int srcy, int width, int height, int dstx, int dsty);
+
+Bool
+exaHWCopyNtoN (DrawablePtr    pSrcDrawable,
+	     DrawablePtr    pDstDrawable,
+	     GCPtr	    pGC,
+	     BoxPtr	    pbox,
+	     int	    nbox,
+	     int	    dx,
+	     int	    dy,
+	     Bool	    reverse,
+	     Bool	    upsidedown);
+
+void
+exaCopyNtoN (DrawablePtr    pSrcDrawable,
+	     DrawablePtr    pDstDrawable,
+	     GCPtr	    pGC,
+	     BoxPtr	    pbox,
+	     int	    nbox,
+	     int	    dx,
+	     int	    dy,
+	     Bool	    reverse,
+	     Bool	    upsidedown,
+	     Pixel	    bitplane,
+	     void	    *closure);
+
 extern const GCOps exaOps;
 
 #ifdef RENDER
@@ -506,36 +536,49 @@ exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp);
 PixmapPtr
 exaGetDrawablePixmap(DrawablePtr pDrawable);
 
-RegionPtr
-exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
-	    int srcx, int srcy, int width, int height, int dstx, int dsty);
+void
+exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
+              int w, int h, int bpp);
 
-Bool
-exaHWCopyNtoN (DrawablePtr    pSrcDrawable,
-	     DrawablePtr    pDstDrawable,
-	     GCPtr	    pGC,
-	     BoxPtr	    pbox,
-	     int	    nbox,
-	     int	    dx,
-	     int	    dy,
-	     Bool	    reverse,
-	     Bool	    upsidedown);
+void
+exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
+                 int w, int h, int bpp);
 
 void
-exaCopyNtoN (DrawablePtr    pSrcDrawable,
-	     DrawablePtr    pDstDrawable,
-	     GCPtr	    pGC,
-	     BoxPtr	    pbox,
-	     int	    nbox,
-	     int	    dx,
-	     int	    dy,
-	     Bool	    reverse,
-	     Bool	    upsidedown,
-	     Pixel	    bitplane,
-	     void	    *closure);
+exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
 
 extern const GCFuncs exaGCFuncs;
 
+/* exa_classic.c */
+PixmapPtr
+exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
+		unsigned usage_hint);
+
+Bool
+exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height, int depth,
+		      int bitsPerPixel, int devKind, pointer pPixData);
+
+Bool
+exaDestroyPixmap_classic (PixmapPtr pPixmap);
+
+Bool
+exaPixmapIsOffscreen_classic(PixmapPtr pPixmap);
+
+/* exa_driver.c */
+PixmapPtr
+exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
+		unsigned usage_hint);
+
+Bool
+exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height, int depth,
+		      int bitsPerPixel, int devKind, pointer pPixData);
+
+Bool
+exaDestroyPixmap_driver (PixmapPtr pPixmap);
+
+Bool
+exaPixmapIsOffscreen_driver(PixmapPtr pPixmap);
+
 /* exa_render.c */
 Bool
 exaOpReadsDestination (CARD8 op);
@@ -592,7 +635,7 @@ exaGlyphs (CARD8	op,
 
 /* exa_migration.c */
 void
-exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
+exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
 
 void
 exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area);


More information about the xorg-commit mailing list