xf86-video-amdgpu: Branch 'master' - 11 commits

Michel Dänzer daenzer at kemper.freedesktop.org
Mon Jun 15 01:28:13 PDT 2015


 configure.ac                 |   10 
 man/amdgpu.man               |   35 +
 src/Makefile.am              |    1 
 src/amdgpu_bo_helper.c       |   20 
 src/amdgpu_bo_helper.h       |    2 
 src/amdgpu_dri2.c            |    6 
 src/amdgpu_dri3.c            |    3 
 src/amdgpu_drv.h             |   30 +
 src/amdgpu_glamor.c          |  101 ++--
 src/amdgpu_glamor.h          |   11 
 src/amdgpu_glamor_wrappers.c |  992 +++++++++++++++++++++++++++++++++++++++++++
 src/amdgpu_kms.c             |  240 ++++++++++
 src/amdgpu_pixmap.c          |   11 
 src/amdgpu_pixmap.h          |   10 
 src/amdgpu_present.c         |    2 
 src/drmmode_display.c        |  355 +++++++++------
 src/drmmode_display.h        |   18 
 17 files changed, 1651 insertions(+), 196 deletions(-)

New commits:
commit c57da33308a81fa575179238a0415abcb8b34908
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Tue Jun 9 12:39:21 2015 +0900

    Add Option "TearFree"
    
    Avoids tearing by flipping between two scanout BOs per (non-rotated) CRTC
    
    (Cherry picked from radeon commit 43159ef400c3b18b9f4d3e6fa1c4aef2d60d38fe)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index 55be626..e7bdf7f 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -143,6 +143,7 @@ typedef enum {
 	OPTION_ACCEL_METHOD,
 	OPTION_DRI3,
 	OPTION_SHADOW_PRIMARY,
+	OPTION_TEAR_FREE,
 } AMDGPUOpts;
 
 #define AMDGPU_VSYNC_TIMEOUT	20000	/* Maximum wait for VSYNC (in usecs) */
@@ -205,6 +206,7 @@ typedef struct {
 	uint_fast32_t gpu_synced;
 	Bool use_glamor;
 	Bool shadow_primary;
+	Bool tear_free;
 
 	/* general */
 	OptionInfoPtr Options;
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 5a672c9..f6ccbd4 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -68,6 +68,7 @@ const OptionInfoRec AMDGPUOptions_KMS[] = {
 	{OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
 	{ OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE },
 	{OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE},
+	{OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE},
 	{-1, NULL, OPTV_NONE, {0}, FALSE}
 };
 
@@ -222,20 +223,9 @@ amdgpu_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h)
 	return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
 }
 
-static void
-amdgpu_scanout_update_abort(ScrnInfoPtr scrn, void *event_data)
-{
-	xf86CrtcPtr xf86_crtc = event_data;
-	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
-
-	drmmode_crtc->scanout_update_pending = FALSE;
-}
-
-static void
-amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
-			      void *event_data)
+static Bool
+amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
 {
-	xf86CrtcPtr xf86_crtc = event_data;
 	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
 	DamagePtr pDamage;
 	RegionPtr pRegion;
@@ -244,23 +234,24 @@ amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
 	GCPtr gc;
 	BoxRec extents;
 
-	if (!drmmode_crtc->scanout.pixmap ||
-	    drmmode_crtc->dpms_mode != DPMSModeOn)
-		goto out;
+	if (drmmode_crtc->dpms_mode != DPMSModeOn ||
+	    !drmmode_crtc->scanout[scanout_id].pixmap)
+		return FALSE;
 
-	pDamage = drmmode_crtc->scanout_damage;
+	pDamage = drmmode_crtc->scanout[scanout_id].damage;
 	if (!pDamage)
-		goto out;
+		return FALSE;
 
 	pRegion = DamageRegion(pDamage);
 	if (!RegionNotEmpty(pRegion))
-		goto out;
+		return FALSE;
 
-	pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+	pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
 	extents = *RegionExtents(pRegion);
+	RegionEmpty(pRegion);
 	if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
 					      pDraw->width, pDraw->height))
-		goto clear_damage;
+		return FALSE;
 
 	pScreen = pDraw->pScreen;
 	gc = GetScratchGC(pDraw->depth, pScreen);
@@ -273,16 +264,30 @@ amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
 			     extents.x1, extents.y1);
 	FreeScratchGC(gc);
 
-	amdgpu_glamor_flush(scrn);
+	amdgpu_glamor_flush(xf86_crtc->scrn);
 
-clear_damage:
-	RegionEmpty(pRegion);
+	return TRUE;
+}
+
+static void
+amdgpu_scanout_update_abort(ScrnInfoPtr scrn, void *event_data)
+{
+	xf86CrtcPtr xf86_crtc = event_data;
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
 
-out:
 	drmmode_crtc->scanout_update_pending = FALSE;
 }
 
 static void
+amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
+							  void *event_data)
+{
+	amdgpu_scanout_do_update(event_data, 0);
+
+	amdgpu_scanout_update_abort(scrn, event_data);
+}
+
+static void
 amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 {
 	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
@@ -295,11 +300,11 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 	BoxRec extents;
 
 	if (drmmode_crtc->scanout_update_pending ||
-	    !drmmode_crtc->scanout.pixmap ||
+	    !drmmode_crtc->scanout[0].pixmap ||
 	    drmmode_crtc->dpms_mode != DPMSModeOn)
 		return;
 
-	pDamage = drmmode_crtc->scanout_damage;
+	pDamage = drmmode_crtc->scanout[0].damage;
 	if (!pDamage)
 		return;
 
@@ -307,7 +312,7 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 	if (!RegionNotEmpty(pRegion))
 		return;
 
-	pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+	pDraw = &drmmode_crtc->scanout[0].pixmap->drawable;
 	extents = *RegionExtents(pRegion);
 	if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
 					      pDraw->width, pDraw->height))
@@ -339,6 +344,61 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 
 	drmmode_crtc->scanout_update_pending = TRUE;
 }
+
+static void
+amdgpu_scanout_flip_abort(ScrnInfoPtr scrn, void *event_data)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = event_data;
+
+	drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+amdgpu_scanout_flip_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, void *event_data)
+{
+	amdgpu_scanout_flip_abort(scrn, event_data);
+}
+
+static void
+amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
+					xf86CrtcPtr xf86_crtc)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+	ScrnInfoPtr scrn;
+	struct amdgpu_drm_queue_entry *drm_queue_entry;
+	unsigned scanout_id;
+
+	if (drmmode_crtc->scanout_update_pending)
+		return;
+
+	scanout_id = drmmode_crtc->scanout_id ^ 1;
+	if (!amdgpu_scanout_do_update(xf86_crtc, scanout_id))
+		return;
+
+	scrn = xf86_crtc->scrn;
+	drm_queue_entry = amdgpu_drm_queue_alloc(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+						 AMDGPU_DRM_QUEUE_ID_DEFAULT,
+						 drmmode_crtc,
+						 amdgpu_scanout_flip_handler,
+						 amdgpu_scanout_flip_abort);
+	if (!drm_queue_entry) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "Allocating DRM event queue entry failed.\n");
+		return;
+	}
+
+	if (drmModePageFlip(drmmode_crtc->drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+			    drmmode_crtc->scanout[scanout_id].fb_id,
+			    DRM_MODE_PAGE_FLIP_EVENT, drm_queue_entry)) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n",
+			   __func__, strerror(errno));
+		return;
+	}
+
+	drmmode_crtc->scanout_id = scanout_id;
+	drmmode_crtc->scanout_update_pending = TRUE;
+}
+
 static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 {
 	SCREEN_PTR(arg);
@@ -349,12 +409,16 @@ static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 	(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
 	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
 
-	if (info->shadow_primary) {
+	if (info->tear_free || info->shadow_primary) {
 		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
 		int c;
 
-		for (c = 0; c < xf86_config->num_crtc; c++)
-			amdgpu_scanout_update(xf86_config->crtc[c]);
+		for (c = 0; c < xf86_config->num_crtc; c++) {
+			if (info->tear_free)
+				amdgpu_scanout_flip(pScreen, info, xf86_config->crtc[c]);
+			else
+				amdgpu_scanout_update(xf86_config->crtc[c]);
+		}
 	}
 
 	if (info->use_glamor)
@@ -681,6 +745,13 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
 	}
 
 	if (info->use_glamor) {
+		info->tear_free = xf86ReturnOptValBool(info->Options,
+						       OPTION_TEAR_FREE, FALSE);
+
+		if (info->tear_free)
+			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+				   "TearFree enabled\n");
+
 		info->shadow_primary =
 			xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE);
 
@@ -691,11 +762,12 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
 	info->allowPageFlip = xf86ReturnOptValBool(info->Options,
 						   OPTION_PAGE_FLIP,
 						   TRUE);
-	if (info->shadow_primary) {
+	if (info->tear_free || info->shadow_primary) {
 		    xf86DrvMsg(pScrn->scrnIndex,
 			       info->allowPageFlip ? X_WARNING : X_DEFAULT,
 			       "KMS Pageflipping: disabled%s\n",
-			       info->allowPageFlip ? " because of ShadowPrimary" : "");
+			       info->allowPageFlip ?
+			       " because of ShadowPrimary/TearFree" : "");
 		    info->allowPageFlip = FALSE;
 	} else {
 		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 79fbecf..19f0f19 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -325,6 +325,10 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
 		scanout->bo = NULL;
 	}
 
+	if (scanout->damage) {
+		DamageDestroy(scanout->damage);
+		scanout->damage = NULL;
+	}
 }
 
 void
@@ -338,12 +342,9 @@ drmmode_scanout_free(ScrnInfoPtr scrn)
 			xf86_config->crtc[c]->driver_private;
 
 		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
-					     &drmmode_crtc->scanout);
-
-		if (drmmode_crtc->scanout_damage) {
-			DamageDestroy(drmmode_crtc->scanout_damage);
-			drmmode_crtc->scanout_damage = NULL;
-		}
+					     &drmmode_crtc->scanout[0]);
+		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
+					     &drmmode_crtc->scanout[1]);
 	}
 }
 
@@ -527,43 +528,51 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 			x = drmmode_crtc->prime_pixmap_x;
 			y = 0;
 
-			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout);
+			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]);
+			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]);
 		} else
 #endif
 		if (drmmode_crtc->rotate.fb_id) {
 			fb_id = drmmode_crtc->rotate.fb_id;
 			x = y = 0;
 
-			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout);
-		} else if (info->shadow_primary) {
-			drmmode_crtc_scanout_create(crtc,
-						    &drmmode_crtc->scanout,
-						    NULL, mode->HDisplay,
-						    mode->VDisplay);
-
-			if (drmmode_crtc->scanout.pixmap) {
-				RegionPtr pRegion;
-				BoxPtr pBox;
-
-				if (!drmmode_crtc->scanout_damage) {
-					drmmode_crtc->scanout_damage =
-						DamageCreate(amdgpu_screen_damage_report,
-							     NULL, DamageReportRawRegion,
-							     TRUE, pScreen, NULL);
-					DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
-						       drmmode_crtc->scanout_damage);
-				}
+			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]);
+			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]);
+		} else if (info->tear_free || info->shadow_primary) {
+			for (i = 0; i < (info->tear_free ? 2 : 1); i++) {
+				drmmode_crtc_scanout_create(crtc,
+							    &drmmode_crtc->scanout[i],
+							    NULL, mode->HDisplay,
+							    mode->VDisplay);
+
+				if (drmmode_crtc->scanout[i].pixmap) {
+					RegionPtr pRegion;
+					BoxPtr pBox;
+
+					if (!drmmode_crtc->scanout[i].damage) {
+						drmmode_crtc->scanout[i].damage =
+							DamageCreate(amdgpu_screen_damage_report,
+								     NULL, DamageReportRawRegion,
+								     TRUE, pScreen, NULL);
+						DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
+							       drmmode_crtc->scanout[i].damage);
+					}
 
-				pRegion = DamageRegion(drmmode_crtc->scanout_damage);
-				RegionUninit(pRegion);
-				pRegion->data = NULL;
-				pBox = RegionExtents(pRegion);
-				pBox->x1 = min(pBox->x1, x);
-				pBox->y1 = min(pBox->y1, y);
-				pBox->x2 = max(pBox->x2, x + mode->HDisplay);
-				pBox->y2 = max(pBox->y2, y + mode->VDisplay);
+					pRegion = DamageRegion(drmmode_crtc->scanout[i].damage);
+					RegionUninit(pRegion);
+					pRegion->data = NULL;
+					pBox = RegionExtents(pRegion);
+					pBox->x1 = min(pBox->x1, x);
+					pBox->y1 = min(pBox->y1, y);
+					pBox->x2 = max(pBox->x2, x + mode->HDisplay);
+					pBox->y2 = max(pBox->y2, y + mode->VDisplay);
+				}
+			}
 
-				fb_id = drmmode_crtc->scanout.fb_id;
+			if (drmmode_crtc->scanout[0].pixmap &&
+			    (!info->tear_free || drmmode_crtc->scanout[1].pixmap)) {
+				drmmode_crtc->scanout_id = 0;
+				fb_id = drmmode_crtc->scanout[0].fb_id;
 				x = y = 0;
 			}
 		}
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 0ba358e..8262e05 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -73,6 +73,7 @@ typedef struct {
 struct drmmode_scanout {
 	struct amdgpu_buffer *bo;
 	PixmapPtr pixmap;
+	DamagePtr damage;
 	unsigned fb_id;
 	int width, height;
 };
@@ -83,8 +84,8 @@ typedef struct {
 	int hw_id;
 	struct amdgpu_buffer *cursor_buffer;
 	struct drmmode_scanout rotate;
-	struct drmmode_scanout scanout;
-	DamagePtr scanout_damage;
+	struct drmmode_scanout scanout[2];
+	unsigned scanout_id;
 	Bool scanout_update_pending;
 	int dpms_mode;
 	CARD64 dpms_last_ust;
commit bd0aca09770543fa77b934e1728a832c9c2dc90c
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Tue Jun 9 11:57:59 2015 +0900

    glamor: Remove the stride member of struct radeon_pixmap
    
    Its value was always the same as that of the PixmapRec devKind member.
    
    (Cherry picked from radeon commit ed401f5b4f07375db17ff05e294907ec95fc946d)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c
index bdb0d37..bde36de 100644
--- a/src/amdgpu_dri2.c
+++ b/src/amdgpu_dri2.c
@@ -109,15 +109,16 @@ static PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap)
 	/* And redirect the pixmap to the new bo (for 3D). */
 	glamor_egl_exchange_buffers(old, pixmap);
 	amdgpu_set_pixmap_private(old, priv);
-	screen->DestroyPixmap(pixmap);
 	old->refcnt++;
 
 	screen->ModifyPixmapHeader(old,
 				   old->drawable.width,
 				   old->drawable.height,
-				   0, 0, priv->stride, NULL);
+				   0, 0, pixmap->devKind, NULL);
 	old->devPrivate.ptr = NULL;
 
+	screen->DestroyPixmap(pixmap);
+
 	return old;
 }
 
diff --git a/src/amdgpu_glamor.c b/src/amdgpu_glamor.c
index 0c100d4..f74aa28 100644
--- a/src/amdgpu_glamor.c
+++ b/src/amdgpu_glamor.c
@@ -136,9 +136,6 @@ amdgpu_glamor_create_textured_pixmap(PixmapPtr pixmap, struct amdgpu_pixmap *pri
 	if ((info->use_glamor) == 0)
 		return TRUE;
 
-	if (!priv->stride)
-		priv->stride = pixmap->devKind;
-
 	if (!amdgpu_bo_get_handle(priv->bo, &bo_handle))
 		return FALSE;
 
@@ -183,20 +180,21 @@ amdgpu_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 		return pixmap;
 
 	if (w && h) {
+		int stride;
+
 		priv = calloc(1, sizeof(struct amdgpu_pixmap));
 		if (priv == NULL)
 			goto fallback_pixmap;
 
 		priv->bo = amdgpu_alloc_pixmap_bo(scrn, w, h, depth, usage,
 						  pixmap->drawable.bitsPerPixel,
-						  &priv->stride);
+						  &stride);
 		if (!priv->bo)
 			goto fallback_priv;
 
 		amdgpu_set_pixmap_private(pixmap, priv);
 
-		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, priv->stride,
-					   NULL);
+		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL);
 
 		pixmap->devPrivate.ptr = NULL;
 
@@ -279,7 +277,6 @@ amdgpu_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle)
 		return FALSE;
 
 	priv = amdgpu_get_pixmap_private(pixmap);
-	priv->stride = pixmap->devKind;
 
 	if (!amdgpu_glamor_create_textured_pixmap(pixmap, priv)) {
 		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
@@ -290,7 +287,7 @@ amdgpu_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle)
 	screen->ModifyPixmapHeader(pixmap,
 				   pixmap->drawable.width,
 				   pixmap->drawable.height,
-				   0, 0, priv->stride, NULL);
+				   0, 0, 0, NULL);
 
 	return TRUE;
 }
diff --git a/src/amdgpu_pixmap.c b/src/amdgpu_pixmap.c
index 657ad33..0a1b0b1 100644
--- a/src/amdgpu_pixmap.c
+++ b/src/amdgpu_pixmap.c
@@ -53,6 +53,8 @@ amdgpu_pixmap_create(ScreenPtr screen, int w, int h, int depth,	unsigned usage)
 		return pixmap;
 
 	if (w && h) {
+		int stride;
+
 		priv = calloc(1, sizeof(struct amdgpu_pixmap));
 		if (priv == NULL)
 			goto fallback_pixmap;
@@ -62,8 +64,8 @@ amdgpu_pixmap_create(ScreenPtr screen, int w, int h, int depth,	unsigned usage)
 		if (!info->use_glamor)
 			usage |= AMDGPU_CREATE_PIXMAP_LINEAR;
 		priv->bo = amdgpu_alloc_pixmap_bo(scrn, w, h, depth, usage,
-						pixmap->drawable.bitsPerPixel,
-						&priv->stride);
+						  pixmap->drawable.bitsPerPixel,
+						  &stride);
 		if (!priv->bo)
 			goto fallback_priv;
 
@@ -74,9 +76,8 @@ amdgpu_pixmap_create(ScreenPtr screen, int w, int h, int depth,	unsigned usage)
 			goto fallback_bo;
 		}
 
-		screen->ModifyPixmapHeader(pixmap, w, h,
-				0, 0, priv->stride,
-				priv->bo->cpu_ptr);
+		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride,
+					   priv->bo->cpu_ptr);
 	}
 
 	return pixmap;
diff --git a/src/amdgpu_pixmap.h b/src/amdgpu_pixmap.h
index b269853..a8f204f 100644
--- a/src/amdgpu_pixmap.h
+++ b/src/amdgpu_pixmap.h
@@ -33,7 +33,6 @@ struct amdgpu_pixmap {
 	uint_fast32_t gpu_write;
 
 	struct amdgpu_buffer *bo;
-	int stride;
 };
 
 #if HAS_DEVPRIVATEKEYREC
commit e5dfb6c2667994701ee451bf82c4142cbf343405
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Mar 18 16:23:24 2015 +0900

    glamor: Add Option "ShadowPrimary"
    
    When this option is enabled, most pixmaps (including the screen pixmap)
    are allocated in system RAM and mostly accessed by the CPU. Changed areas
    of the screen pixmap are copied to dedicated per-CRTC scanout pixmaps
    regularly, triggered by the vblank interrupt.
    
    (Cherry picked from radeon commits ae92d1765fa370a8d94c2856ad6c45d273ec3c69
    and 1af044d7eee211fd4b248c236280274a68334da5)
    
    [ Michel Dänzer: Additional adjustements for the amdgpu driver ]
    
    Signed-off-by: Darren Powell <darren.powell at amd.com>
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/configure.ac b/configure.ac
index d9d97ef..85892fa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -145,6 +145,16 @@ else
 fi
 AM_CONDITIONAL(GLAMOR, test x$GLAMOR != xno)
 
+AC_CHECK_DECL(fbGlyphs,
+	      [AC_DEFINE(HAVE_FBGLYPHS, 1, [Have fbGlyphs API])], [],
+	      [#include <X11/Xmd.h>
+	       #include <X11/Xfuncproto.h>
+	       #include <X11/extensions/renderproto.h>
+	       #include <xorg-server.h>
+	       #include <picture.h>
+	       #include <glyphstr.h>
+	       #include <fbpict.h>])
+
 AC_CHECK_DECL(xorg_list_init,
 	      [AC_DEFINE(HAVE_XORG_LIST, 1, [Have xorg_list API])], [],
 	      [#include <X11/Xdefs.h>
diff --git a/man/amdgpu.man b/man/amdgpu.man
index bc7bf30..d280197 100644
--- a/man/amdgpu.man
+++ b/man/amdgpu.man
@@ -50,15 +50,7 @@ Enables or disables all hardware acceleration.
 The default is to
 .B enable
 hardware acceleration.
-.TP
-.BI "Option \*qAccelMethod\*q \*q" string \*q
-Setting this option to
-.B none
-disables use of the glamor acceleration architecture. In that case, all 2D
-rendering is done by the CPU, but 3D and video hardware acceleration can still
-work. This is mainly useful for OpenGL driver bring-up.
-.br
-The default is to use glamor.
+
 .TP
 .BI "Option \*qZaphodHeads\*q \*q" string \*q
 Specify the RandR output(s) to use with zaphod mode for a particular driver
@@ -77,6 +69,31 @@ Enable the DRI3 extension. The default is
 .BI "Option \*qEnablePageFlip\*q \*q" boolean \*q
 Enable DRI2 page flipping.  The default is
 .B on.
+.TP
+.BI "Option \*qAccelMethod\*q \*q" string \*q
+Setting this option to
+.B none
+disables use of the glamor acceleration architecture. In that case, all 2D
+rendering is done by the CPU, but 3D and video hardware acceleration can still
+work. This is mainly useful for OpenGL driver bring-up.
+.br
+The default is to use glamor.
+
+.PP
+The following driver
+.B Option
+is supported for
+.B glamor
+:
+.TP
+.BI "Option \*qShadowPrimary\*q \*q" boolean \*q
+This option enables a so-called "shadow primary" buffer for fast CPU access to
+pixel data, and separate scanout buffers for each display controller (CRTC).
+This may improve performance for some 2D workloads, potentially at the expense
+of other (e.g. 3D, video) workloads.
+Note in particular that enabling this option currently disables page flipping.
+The default is
+.B off.
 
 .SH SEE ALSO
 __xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__)
diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c
index 28c56e7..bdb0d37 100644
--- a/src/amdgpu_dri2.c
+++ b/src/amdgpu_dri2.c
@@ -116,6 +116,7 @@ static PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap)
 				   old->drawable.width,
 				   old->drawable.height,
 				   0, 0, priv->stride, NULL);
+	old->devPrivate.ptr = NULL;
 
 	return old;
 }
diff --git a/src/amdgpu_dri3.c b/src/amdgpu_dri3.c
index ce0f8e7..a89421e 100644
--- a/src/amdgpu_dri3.c
+++ b/src/amdgpu_dri3.c
@@ -108,7 +108,8 @@ static PixmapPtr amdgpu_dri3_pixmap_from_fd(ScreenPtr screen,
 		return NULL;
 	}
 
-	pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
+	pixmap = screen->CreatePixmap(screen, 0, 0, depth,
+				      AMDGPU_CREATE_PIXMAP_DRI2);
 	if (!pixmap)
 		return NULL;
 
diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index 467c2fb..55be626 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -142,6 +142,7 @@ typedef enum {
 	OPTION_ZAPHOD_HEADS,
 	OPTION_ACCEL_METHOD,
 	OPTION_DRI3,
+	OPTION_SHADOW_PRIMARY,
 } AMDGPUOpts;
 
 #define AMDGPU_VSYNC_TIMEOUT	20000	/* Maximum wait for VSYNC (in usecs) */
@@ -203,6 +204,7 @@ typedef struct {
 	uint_fast32_t gpu_flushed;
 	uint_fast32_t gpu_synced;
 	Bool use_glamor;
+	Bool shadow_primary;
 
 	/* general */
 	OptionInfoPtr Options;
diff --git a/src/amdgpu_glamor.c b/src/amdgpu_glamor.c
index d91effc..0c100d4 100644
--- a/src/amdgpu_glamor.c
+++ b/src/amdgpu_glamor.c
@@ -146,25 +146,27 @@ amdgpu_glamor_create_textured_pixmap(PixmapPtr pixmap, struct amdgpu_pixmap *pri
 						 pixmap->devKind);
 }
 
-#ifndef CREATE_PIXMAP_USAGE_SHARED
-#define CREATE_PIXMAP_USAGE_SHARED AMDGPU_CREATE_PIXMAP_DRI2
-#endif
-
-#define AMDGPU_CREATE_PIXMAP_SHARED(usage) \
-	((usage) & AMDGPU_CREATE_PIXMAP_DRI2 || (usage) == CREATE_PIXMAP_USAGE_SHARED)
-
 static PixmapPtr
 amdgpu_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 			    unsigned usage)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	struct amdgpu_pixmap *priv;
 	PixmapPtr pixmap, new_pixmap = NULL;
 
 	if (!AMDGPU_CREATE_PIXMAP_SHARED(usage)) {
-		pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
-		if (pixmap)
-			return pixmap;
+		if (info->shadow_primary) {
+			if (usage != CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
+				return fbCreatePixmap(screen, w, h, depth, usage);
+
+			usage |= AMDGPU_CREATE_PIXMAP_LINEAR |
+				 AMDGPU_CREATE_PIXMAP_GTT;
+		} else {
+			pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
+			if (pixmap)
+				return pixmap;
+		}
 	}
 
 	if (w > 32767 || h > 32767)
@@ -196,6 +198,8 @@ amdgpu_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, priv->stride,
 					   NULL);
 
+		pixmap->devPrivate.ptr = NULL;
+
 		if (!amdgpu_glamor_create_textured_pixmap(pixmap, priv))
 			goto fallback_glamor;
 	}
@@ -236,6 +240,13 @@ fallback_pixmap:
 static Bool amdgpu_glamor_destroy_pixmap(PixmapPtr pixmap)
 {
 	if (pixmap->refcnt == 1) {
+		if (pixmap->devPrivate.ptr) {
+			struct amdgpu_buffer *bo = amdgpu_get_pixmap_bo(pixmap);
+
+			if (bo)
+				amdgpu_bo_unmap(bo);
+		}
+
 		glamor_egl_destroy_textured_pixmap(pixmap);
 		amdgpu_set_pixmap_bo(pixmap, NULL);
 	}
@@ -289,6 +300,26 @@ amdgpu_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle)
 Bool amdgpu_glamor_init(ScreenPtr screen)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+#ifdef RENDER
+#ifdef HAVE_FBGLYPHS
+	UnrealizeGlyphProcPtr SavedUnrealizeGlyph = NULL;
+#endif
+	PictureScreenPtr ps = NULL;
+
+	if (info->shadow_primary) {
+		ps = GetPictureScreenIfSet(screen);
+
+		if (ps) {
+#ifdef HAVE_FBGLYPHS
+			SavedUnrealizeGlyph = ps->UnrealizeGlyph;
+#endif
+			info->glamor.SavedGlyphs = ps->Glyphs;
+			info->glamor.SavedTriangles = ps->Triangles;
+			info->glamor.SavedTrapezoids = ps->Trapezoids;
+		}
+	}
+#endif /* RENDER */
 
 	if (!glamor_init(screen, GLAMOR_USE_EGL_SCREEN | GLAMOR_USE_SCREEN |
 			 GLAMOR_USE_PICTURE_SCREEN | GLAMOR_INVERTED_Y_AXIS |
@@ -310,6 +341,17 @@ Bool amdgpu_glamor_init(ScreenPtr screen)
 #endif
 		return FALSE;
 
+	if (info->shadow_primary)
+		amdgpu_glamor_screen_init(screen);
+
+#if defined(RENDER) && defined(HAVE_FBGLYPHS)
+	/* For ShadowPrimary, we need fbUnrealizeGlyph instead of
+	 * glamor_unrealize_glyph
+	 */
+	if (ps)
+		ps->UnrealizeGlyph = SavedUnrealizeGlyph;
+#endif
+
 	screen->CreatePixmap = amdgpu_glamor_create_pixmap;
 	screen->DestroyPixmap = amdgpu_glamor_destroy_pixmap;
 #ifdef AMDGPU_PIXMAP_SHARING
diff --git a/src/amdgpu_glamor.h b/src/amdgpu_glamor.h
index 7959e9d..a781695 100644
--- a/src/amdgpu_glamor.h
+++ b/src/amdgpu_glamor.h
@@ -32,6 +32,14 @@
 #define GLAMOR_FOR_XORG  1
 #include <glamor.h>
 
+#ifndef CREATE_PIXMAP_USAGE_SHARED
+#define CREATE_PIXMAP_USAGE_SHARED AMDGPU_CREATE_PIXMAP_DRI2
+#endif
+
+#define AMDGPU_CREATE_PIXMAP_SHARED(usage) \
+	((usage) == AMDGPU_CREATE_PIXMAP_DRI2 || \
+	 (usage) == CREATE_PIXMAP_USAGE_SHARED)
+
 #ifndef GLAMOR_NO_DRI3
 #define GLAMOR_NO_DRI3 0
 #define glamor_fd_from_pixmap glamor_dri3_fd_from_pixmap
@@ -52,6 +60,7 @@ struct amdgpu_pixmap;
 
 Bool amdgpu_glamor_pre_init(ScrnInfoPtr scrn);
 Bool amdgpu_glamor_init(ScreenPtr screen);
+void amdgpu_glamor_screen_init(ScreenPtr screen);
 Bool amdgpu_glamor_create_screen_resources(ScreenPtr screen);
 void amdgpu_glamor_free_screen(int scrnIndex, int flags);
 
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index cfdf716..5a672c9 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -67,6 +67,7 @@ const OptionInfoRec AMDGPUOptions_KMS[] = {
 	{OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE},
 	{OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
 	{ OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE },
+	{OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE},
 	{-1, NULL, OPTV_NONE, {0}, FALSE}
 };
 
@@ -210,6 +211,134 @@ static void amdgpu_dirty_update(ScreenPtr screen)
 }
 #endif
 
+static Bool
+amdgpu_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h)
+{
+	extents->x1 = max(extents->x1 - x, 0);
+	extents->y1 = max(extents->y1 - y, 0);
+	extents->x2 = min(extents->x2 - x, w);
+	extents->y2 = min(extents->y2 - y, h);
+
+	return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
+}
+
+static void
+amdgpu_scanout_update_abort(ScrnInfoPtr scrn, void *event_data)
+{
+	xf86CrtcPtr xf86_crtc = event_data;
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+
+	drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
+			      void *event_data)
+{
+	xf86CrtcPtr xf86_crtc = event_data;
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+	DamagePtr pDamage;
+	RegionPtr pRegion;
+	DrawablePtr pDraw;
+	ScreenPtr pScreen;
+	GCPtr gc;
+	BoxRec extents;
+
+	if (!drmmode_crtc->scanout.pixmap ||
+	    drmmode_crtc->dpms_mode != DPMSModeOn)
+		goto out;
+
+	pDamage = drmmode_crtc->scanout_damage;
+	if (!pDamage)
+		goto out;
+
+	pRegion = DamageRegion(pDamage);
+	if (!RegionNotEmpty(pRegion))
+		goto out;
+
+	pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+	extents = *RegionExtents(pRegion);
+	if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
+					      pDraw->width, pDraw->height))
+		goto clear_damage;
+
+	pScreen = pDraw->pScreen;
+	gc = GetScratchGC(pDraw->depth, pScreen);
+
+	ValidateGC(pDraw, gc);
+	(*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable,
+			     pDraw, gc,
+			     xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
+			     extents.x2 - extents.x1, extents.y2 - extents.y1,
+			     extents.x1, extents.y1);
+	FreeScratchGC(gc);
+
+	amdgpu_glamor_flush(scrn);
+
+clear_damage:
+	RegionEmpty(pRegion);
+
+out:
+	drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+	struct amdgpu_drm_queue_entry *drm_queue_entry;
+	ScrnInfoPtr scrn;
+	drmVBlank vbl;
+	DamagePtr pDamage;
+	RegionPtr pRegion;
+	DrawablePtr pDraw;
+	BoxRec extents;
+
+	if (drmmode_crtc->scanout_update_pending ||
+	    !drmmode_crtc->scanout.pixmap ||
+	    drmmode_crtc->dpms_mode != DPMSModeOn)
+		return;
+
+	pDamage = drmmode_crtc->scanout_damage;
+	if (!pDamage)
+		return;
+
+	pRegion = DamageRegion(pDamage);
+	if (!RegionNotEmpty(pRegion))
+		return;
+
+	pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+	extents = *RegionExtents(pRegion);
+	if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
+					      pDraw->width, pDraw->height))
+		return;
+
+	scrn = xf86_crtc->scrn;
+	drm_queue_entry = amdgpu_drm_queue_alloc(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+						 AMDGPU_DRM_QUEUE_ID_DEFAULT,
+						 xf86_crtc,
+						 amdgpu_scanout_update_handler,
+						 amdgpu_scanout_update_abort);
+	if (!drm_queue_entry) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "amdgpu_drm_queue_alloc failed for scanout update\n");
+		return;
+	}
+
+	vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
+	vbl.request.type |= amdgpu_populate_vbl_request_type(xf86_crtc);
+	vbl.request.sequence = 1;
+	vbl.request.signal = (unsigned long)drm_queue_entry;
+	if (drmWaitVBlank(AMDGPUPTR(scrn)->dri2.drm_fd, &vbl)) {
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "drmWaitVBlank failed for scanout update: %s\n",
+			   strerror(errno));
+		amdgpu_drm_abort_entry(drm_queue_entry);
+		return;
+	}
+
+	drmmode_crtc->scanout_update_pending = TRUE;
+}
 static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 {
 	SCREEN_PTR(arg);
@@ -220,6 +349,14 @@ static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 	(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
 	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
 
+	if (info->shadow_primary) {
+		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+		int c;
+
+		for (c = 0; c < xf86_config->num_crtc; c++)
+			amdgpu_scanout_update(xf86_config->crtc[c]);
+	}
+
 	if (info->use_glamor)
 		amdgpu_glamor_flush(pScrn);
 
@@ -543,12 +680,28 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
 		amdgpu_get_tile_config(pScrn);
 	}
 
+	if (info->use_glamor) {
+		info->shadow_primary =
+			xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE);
+
+		if (info->shadow_primary)
+			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowPrimary enabled\n");
+	}
+
 	info->allowPageFlip = xf86ReturnOptValBool(info->Options,
 						   OPTION_PAGE_FLIP,
 						   TRUE);
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-		   "KMS Pageflipping: %sabled\n",
-		   info->allowPageFlip ? "en" : "dis");
+	if (info->shadow_primary) {
+		    xf86DrvMsg(pScrn->scrnIndex,
+			       info->allowPageFlip ? X_WARNING : X_DEFAULT,
+			       "KMS Pageflipping: disabled%s\n",
+			       info->allowPageFlip ? " because of ShadowPrimary" : "");
+		    info->allowPageFlip = FALSE;
+	} else {
+		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+			   "KMS Pageflipping: %sabled\n",
+			   info->allowPageFlip ? "en" : "dis");
+	}
 
 	if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) ==
 	    FALSE) {
@@ -993,6 +1146,7 @@ void AMDGPULeaveVT_KMS(VT_FUNC_ARGS_DECL)
 	drmDropMaster(info->dri2.drm_fd);
 
 	xf86RotateFreeShadow(pScrn);
+	drmmode_scanout_free(pScrn);
 
 	xf86_hide_cursors(pScrn);
 
@@ -1074,7 +1228,12 @@ static Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen)
 
 	if (info->front_buffer == NULL) {
 		int pitch;
-		int hint = info->use_glamor ? 0 : AMDGPU_CREATE_PIXMAP_LINEAR;
+		int hint = 0;
+
+		if (info->shadow_primary)
+			hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
+		else if (!info->use_glamor)
+			hint = AMDGPU_CREATE_PIXMAP_LINEAR;
 
 		info->front_buffer =
 			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 1fcf901..79fbecf 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -32,6 +32,8 @@
 #include <errno.h>
 #include <sys/ioctl.h>
 #include <time.h>
+#include "cursorstr.h"
+#include "damagestr.h"
 #include "micmap.h"
 #include "xf86cmap.h"
 #include "sarea.h"
@@ -302,17 +304,8 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
 	uint32_t size = pScrn->displayWidth * info->pixel_bytes * pScrn->virtualY;
 
 	/* memset the bo */
-	if (info->gbm) {
-		void *cpu_ptr = malloc(size);
-
-		if (cpu_ptr) {
-			memset(cpu_ptr, 0x00, size);
-			gbm_bo_write(info->front_buffer->bo.gbm, cpu_ptr, size);
-			free(cpu_ptr);
-		}
-	} else {
-		memset(info->front_buffer->cpu_ptr, 0x00, size);
-	}
+	amdgpu_bo_map(pScrn, info->front_buffer);
+	memset(info->front_buffer->cpu_ptr, 0x00, size);
 }
 
 static void
@@ -334,6 +327,26 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
 
 }
 
+void
+drmmode_scanout_free(ScrnInfoPtr scrn)
+{
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+	int c;
+
+	for (c = 0; c < xf86_config->num_crtc; c++) {
+		drmmode_crtc_private_ptr drmmode_crtc =
+			xf86_config->crtc[c]->driver_private;
+
+		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
+					     &drmmode_crtc->scanout);
+
+		if (drmmode_crtc->scanout_damage) {
+			DamageDestroy(drmmode_crtc->scanout_damage);
+			drmmode_crtc->scanout_damage = NULL;
+		}
+	}
+}
+
 static void *
 drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
                               struct drmmode_scanout *scanout,
@@ -354,6 +367,13 @@ drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
 		return NULL;
 	}
 
+	if (scanout->bo) {
+		if (scanout->width == width && scanout->height == height)
+			return scanout->bo;
+
+		drmmode_crtc_scanout_destroy(drmmode, scanout);
+	}
+
 	scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height,
 					       pScrn->depth, 0,
 					       pScrn->bitsPerPixel, &pitch);
@@ -371,6 +391,8 @@ drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
 		ErrorF("failed to add rotate fb\n");
 	}
 
+	scanout->width = width;
+	scanout->height = height;
 	return scanout->bo;
 }
 
@@ -380,8 +402,17 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc,
                             void *data, int width, int height)
 {
 	ScrnInfoPtr pScrn = crtc->scrn;
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
 	unsigned long rotate_pitch;
 
+	if (scanout->pixmap) {
+		if (scanout->width == width && scanout->height == height)
+			return scanout->pixmap;
+
+		drmmode_crtc_scanout_destroy(drmmode, scanout);
+	}
+
 	if (!data)
 		data = drmmode_crtc_scanout_allocate(crtc, scanout, width, height);
 
@@ -401,6 +432,13 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc,
 
 }
 
+static void
+amdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
+{
+	/* Only keep track of the extents */
+	RegionUninit(&damage->damage);
+	damage->damage.data = NULL;
+}
 
 static Bool
 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
@@ -460,6 +498,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 	}
 
 	if (mode) {
+		ScreenPtr pScreen = pScrn->pScreen;
+
 		for (i = 0; i < xf86_config->num_output; i++) {
 			xf86OutputPtr output = xf86_config->output[i];
 			drmmode_output_private_ptr drmmode_output;
@@ -486,11 +526,46 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
 			x = drmmode_crtc->prime_pixmap_x;
 			y = 0;
+
+			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout);
 		} else
 #endif
 		if (drmmode_crtc->rotate.fb_id) {
 			fb_id = drmmode_crtc->rotate.fb_id;
 			x = y = 0;
+
+			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout);
+		} else if (info->shadow_primary) {
+			drmmode_crtc_scanout_create(crtc,
+						    &drmmode_crtc->scanout,
+						    NULL, mode->HDisplay,
+						    mode->VDisplay);
+
+			if (drmmode_crtc->scanout.pixmap) {
+				RegionPtr pRegion;
+				BoxPtr pBox;
+
+				if (!drmmode_crtc->scanout_damage) {
+					drmmode_crtc->scanout_damage =
+						DamageCreate(amdgpu_screen_damage_report,
+							     NULL, DamageReportRawRegion,
+							     TRUE, pScreen, NULL);
+					DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
+						       drmmode_crtc->scanout_damage);
+				}
+
+				pRegion = DamageRegion(drmmode_crtc->scanout_damage);
+				RegionUninit(pRegion);
+				pRegion->data = NULL;
+				pBox = RegionExtents(pRegion);
+				pBox->x1 = min(pBox->x1, x);
+				pBox->y1 = min(pBox->y1, y);
+				pBox->x2 = max(pBox->x2, x + mode->HDisplay);
+				pBox->y2 = max(pBox->y2, y + mode->VDisplay);
+
+				fb_id = drmmode_crtc->scanout.fb_id;
+				x = y = 0;
+			}
 		}
 		ret =
 		    drmModeSetCrtc(drmmode->fd,
@@ -1313,18 +1388,23 @@ static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
 	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	struct amdgpu_buffer *old_front = NULL;
-	Bool ret;
 	ScreenPtr screen = xf86ScrnToScreen(scrn);
 	uint32_t old_fb_id;
 	int i, pitch, old_width, old_height, old_pitch;
 	int cpp = info->pixel_bytes;
 	PixmapPtr ppix = screen->GetScreenPixmap(screen);
+	uint32_t bo_handle;
 	void *fb_shadow;
-	int hint = info->use_glamor ? 0 : AMDGPU_CREATE_PIXMAP_LINEAR;
+	int hint = 0;
 
 	if (scrn->virtualX == width && scrn->virtualY == height)
 		return TRUE;
 
+	if (info->shadow_primary)
+		hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
+	else if (!info->use_glamor)
+		hint = AMDGPU_CREATE_PIXMAP_LINEAR;
+
 	xf86DrvMsg(scrn->scrnIndex, X_INFO,
 		   "Allocate new frame buffer %dx%d\n", width, height);
 
@@ -1356,35 +1436,26 @@ static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
 	xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch);
 	scrn->displayWidth = pitch / cpp;
 
-	if (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM) {
-		union gbm_bo_handle bo_handle;
+	if (!amdgpu_bo_get_handle(info->front_buffer, &bo_handle)) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "Failed to get front buffer handle\n");
+		goto fail;
+	}
 
-		bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm);
-		ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
-				   scrn->bitsPerPixel, pitch,
-				   bo_handle.u32, &drmmode->fb_id);
-		if (ret) {
-			goto fail;
-		}
+	if (drmModeAddFB(drmmode->fd, width, height, scrn->depth,
+			 scrn->bitsPerPixel, pitch,
+			 bo_handle, &drmmode->fb_id) != 0) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "drmModeAddFB failed for front buffer\n");
+		goto fail;
+	}
 
+	if (info->use_glamor ||
+	    (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) {
 		amdgpu_set_pixmap_bo(ppix, info->front_buffer);
 		screen->ModifyPixmapHeader(ppix,
 					   width, height, -1, -1, pitch, info->front_buffer->cpu_ptr);
 	} else {
-		uint32_t bo_handle;
-
-		if (amdgpu_bo_export(info->front_buffer->bo.amdgpu,
-				     amdgpu_bo_handle_type_kms,
-				     &bo_handle)) {
-			goto fail;
-		}
-		ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
-				   scrn->bitsPerPixel, pitch,
-				   bo_handle, &drmmode->fb_id);
-		if (ret) {
-			goto fail;
-		}
-
 		fb_shadow = calloc(1, pitch * scrn->virtualY);
 		if (fb_shadow == NULL)
 			goto fail;
@@ -1800,7 +1871,6 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 			int ref_crtc_hw_id, amdgpu_drm_handler_proc handler,
 			amdgpu_drm_abort_proc abort)
 {
-	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
@@ -1813,9 +1883,9 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 	union gbm_bo_handle bo_handle;
 	uint32_t handle;
 
-	if (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM) {
-		pitch = gbm_bo_get_stride(info->front_buffer->bo.gbm);
-		height = gbm_bo_get_height(info->front_buffer->bo.gbm);
+	if (new_front->flags & AMDGPU_BO_FLAGS_GBM) {
+		pitch = gbm_bo_get_stride(new_front->bo.gbm);
+		height = gbm_bo_get_height(new_front->bo.gbm);
 		bo_handle = gbm_bo_get_handle(new_front->bo.gbm);
 		handle = bo_handle.u32;
 	} else {
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 77d9c03..0ba358e 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -74,6 +74,7 @@ struct drmmode_scanout {
 	struct amdgpu_buffer *bo;
 	PixmapPtr pixmap;
 	unsigned fb_id;
+	int width, height;
 };
 
 typedef struct {
@@ -82,6 +83,9 @@ typedef struct {
 	int hw_id;
 	struct amdgpu_buffer *cursor_buffer;
 	struct drmmode_scanout rotate;
+	struct drmmode_scanout scanout;
+	DamagePtr scanout_damage;
+	Bool scanout_update_pending;
 	int dpms_mode;
 	CARD64 dpms_last_ust;
 	uint32_t dpms_last_seq;
@@ -121,6 +125,8 @@ extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 extern void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 extern Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn);
 
+extern void drmmode_scanout_free(ScrnInfoPtr scrn);
+
 extern void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode);
 extern void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode);
 
commit 08da7b691d556735dcc22b1351c886a5079dfd3f
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Jun 10 16:21:21 2015 +0900

    Add AMDGPU_CREATE_PIXMAP_GTT flag
    
    When set, the pixmap memory is allocated in GTT instead of in VRAM.
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_bo_helper.c b/src/amdgpu_bo_helper.c
index 47cd9eb..00e8643 100644
--- a/src/amdgpu_bo_helper.c
+++ b/src/amdgpu_bo_helper.c
@@ -62,7 +62,7 @@ struct amdgpu_buffer *amdgpu_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width,
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
 	struct amdgpu_buffer *pixmap_buffer;
 
-	if (info->gbm) {
+	if (!(usage_hint & AMDGPU_CREATE_PIXMAP_GTT) && info->gbm) {
 		uint32_t bo_use = GBM_BO_USE_RENDERING;
 		uint32_t gbm_format = amdgpu_get_gbm_format(depth, bitsPerPixel);
 
@@ -107,9 +107,11 @@ struct amdgpu_buffer *amdgpu_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width,
 		unsigned cpp = (bitsPerPixel + 7) / 8;
 		unsigned pitch = cpp *
 			AMDGPU_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp));
+		uint32_t domain = (usage_hint & AMDGPU_CREATE_PIXMAP_GTT) ?
+			AMDGPU_GEM_DOMAIN_GTT : AMDGPU_GEM_DOMAIN_VRAM;
 
 		pixmap_buffer = amdgpu_bo_open(pAMDGPUEnt->pDev, pitch * height,
-					       4096, AMDGPU_GEM_DOMAIN_VRAM);
+					       4096, domain);
 
 		if (new_pitch)
 			*new_pitch = pitch;
diff --git a/src/amdgpu_pixmap.h b/src/amdgpu_pixmap.h
index a5dc081..b269853 100644
--- a/src/amdgpu_pixmap.h
+++ b/src/amdgpu_pixmap.h
@@ -107,6 +107,7 @@ enum {
 	AMDGPU_CREATE_PIXMAP_DRI2    = 0x08000000,
 	AMDGPU_CREATE_PIXMAP_LINEAR  = 0x04000000,
 	AMDGPU_CREATE_PIXMAP_SCANOUT = 0x02000000,
+	AMDGPU_CREATE_PIXMAP_GTT     = 0x01000000,
 };
 
 extern Bool amdgpu_pixmap_init(ScreenPtr screen);
commit 59bdb578266a2637fda8d11168b9332f6845157c
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Jun 10 12:04:29 2015 +0900

    Factor out amdgpu_bo_get_handle helper
    
    The helper transparently handles BOs allocated from GBM and
    libdrm_amdgpu.
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_bo_helper.c b/src/amdgpu_bo_helper.c
index 54270c6..47cd9eb 100644
--- a/src/amdgpu_bo_helper.c
+++ b/src/amdgpu_bo_helper.c
@@ -118,6 +118,17 @@ struct amdgpu_buffer *amdgpu_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width,
 	return pixmap_buffer;
 }
 
+Bool amdgpu_bo_get_handle(struct amdgpu_buffer *bo, uint32_t *handle)
+{
+	if (bo->flags & AMDGPU_BO_FLAGS_GBM) {
+		*handle = gbm_bo_get_handle(bo->bo.gbm).u32;
+		return TRUE;
+	}
+
+	return amdgpu_bo_export(bo->bo.amdgpu, amdgpu_bo_handle_type_kms,
+				handle) == 0;
+}
+
 int amdgpu_bo_map(ScrnInfoPtr pScrn, struct amdgpu_buffer *bo)
 {
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
diff --git a/src/amdgpu_bo_helper.h b/src/amdgpu_bo_helper.h
index 8270d39..4dae200 100644
--- a/src/amdgpu_bo_helper.h
+++ b/src/amdgpu_bo_helper.h
@@ -29,6 +29,8 @@ extern struct amdgpu_buffer *amdgpu_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width
 						     int height, int depth, int usage_hint,
 						     int bitsPerPixel, int *new_pitch);
 
+extern Bool amdgpu_bo_get_handle(struct amdgpu_buffer *bo, uint32_t *handle);
+
 extern int amdgpu_bo_map(ScrnInfoPtr pScrn, struct amdgpu_buffer *bo);
 
 extern void amdgpu_bo_unmap(struct amdgpu_buffer *bo);
diff --git a/src/amdgpu_glamor.c b/src/amdgpu_glamor.c
index 7c45f34..d91effc 100644
--- a/src/amdgpu_glamor.c
+++ b/src/amdgpu_glamor.c
@@ -55,7 +55,7 @@ Bool amdgpu_glamor_create_screen_resources(ScreenPtr screen)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
 	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
-	union gbm_bo_handle bo_handle;
+	uint32_t bo_handle;
 
 	if (!info->use_glamor)
 		return TRUE;
@@ -65,9 +65,9 @@ Bool amdgpu_glamor_create_screen_resources(ScreenPtr screen)
 		return FALSE;
 #endif
 
-	bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm);
-	if (!glamor_egl_create_textured_screen_ext(screen,
-						   bo_handle.u32,
+	if (!amdgpu_bo_get_handle(info->front_buffer, &bo_handle) ||
+	    !glamor_egl_create_textured_screen_ext(screen,
+						   bo_handle,
 						   scrn->displayWidth *
 						   info->pixel_bytes, NULL)) {
 		return FALSE;
@@ -131,7 +131,7 @@ amdgpu_glamor_create_textured_pixmap(PixmapPtr pixmap, struct amdgpu_pixmap *pri
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
 	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
-	union gbm_bo_handle bo_handle;
+	uint32_t bo_handle;
 
 	if ((info->use_glamor) == 0)
 		return TRUE;
@@ -139,9 +139,11 @@ amdgpu_glamor_create_textured_pixmap(PixmapPtr pixmap, struct amdgpu_pixmap *pri
 	if (!priv->stride)
 		priv->stride = pixmap->devKind;
 
-	bo_handle = gbm_bo_get_handle(priv->bo->bo.gbm);
-	return glamor_egl_create_textured_pixmap(pixmap, bo_handle.u32,
-						 priv->stride);
+	if (!amdgpu_bo_get_handle(priv->bo, &bo_handle))
+		return FALSE;
+
+	return glamor_egl_create_textured_pixmap(pixmap, bo_handle,
+						 pixmap->devKind);
 }
 
 #ifndef CREATE_PIXMAP_USAGE_SHARED
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index d855787..1fcf901 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -420,18 +420,12 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 	int i;
 	int fb_id;
 	drmModeModeInfo kmode;
-	union gbm_bo_handle bo_handle;
+	uint32_t bo_handle;
 
 	if (drmmode->fb_id == 0) {
-		if (info->gbm) {
-			bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm);
-		} else {
-			if (amdgpu_bo_export(info->front_buffer->bo.amdgpu,
-					     amdgpu_bo_handle_type_kms,
-					     &bo_handle.u32)) {
-				ErrorF("failed to get BO handle for FB\n");
-				return FALSE;
-			}
+		if (!amdgpu_bo_get_handle(info->front_buffer, &bo_handle)) {
+			ErrorF("failed to get BO handle for FB\n");
+			return FALSE;
 		}
 
 		ret = drmModeAddFB(drmmode->fd,
@@ -439,7 +433,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 				   pScrn->virtualY,
 				   pScrn->depth, pScrn->bitsPerPixel,
 				   pScrn->displayWidth * info->pixel_bytes,
-				   bo_handle.u32, &drmmode->fb_id);
+				   bo_handle, &drmmode->fb_id);
 		if (ret < 0) {
 			ErrorF("failed to add fb\n");
 			return FALSE;
@@ -595,20 +589,14 @@ static void drmmode_show_cursor(xf86CrtcPtr crtc)
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
-	union gbm_bo_handle bo_handle;
+	uint32_t bo_handle;
 
-	if (info->gbm) {
-		bo_handle = gbm_bo_get_handle(drmmode_crtc->cursor_buffer->bo.gbm);
-	} else {
-		if (amdgpu_bo_export(drmmode_crtc->cursor_buffer->bo.amdgpu,
-				     amdgpu_bo_handle_type_kms,
-				     &bo_handle.u32)) {
-			ErrorF("failed to get BO handle for cursor\n");
-			return;
-		}
+	if (!amdgpu_bo_get_handle(drmmode_crtc->cursor_buffer, &bo_handle)) {
+		ErrorF("failed to get BO handle for cursor\n");
+		return;
 	}
 
-	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, bo_handle.u32,
+	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, bo_handle,
 			 info->cursor_w, info->cursor_h);
 }
 
commit 9a6eff506b6804481a6e8139d362355fc5ffdbfb
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Jun 10 12:10:24 2015 +0900

    Set AMDGPU_BO_FLAGS_GBM for cursor buffers allocated from GBM
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 1e256af..cfdf716 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -1037,6 +1037,7 @@ static Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen)
 					return FALSE;
 				}
 				info->cursor_buffer[c]->ref_count = 1;
+				info->cursor_buffer[c]->flags = AMDGPU_BO_FLAGS_GBM;
 
 				info->cursor_buffer[c]->bo.gbm = gbm_bo_create(info->gbm,
 									       info->cursor_w,
commit d3ea8a69b02b308f8f23662be6e0c7bd81c1a2c9
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri May 29 18:53:50 2015 +0900

    glamor: Add wrappers for the X server rendering hooks
    
    They can choose between using the GPU or CPU for the operation.
    
    (cherry picked from radeon commits eea79472a84672ee4dc7adc4487cec6a4037048a
    and e58fc380ccf2a581d28f041fd74b963626ca5404)
    
    Signed-off-by: Darren Powell <darren.powell at amd.com>
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/Makefile.am b/src/Makefile.am
index b953d4c..6c8d1de 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -53,6 +53,7 @@ AM_CFLAGS += @LIBGLAMOR_CFLAGS@
 amdgpu_drv_la_LIBADD += @LIBGLAMOR_LIBS@
 amdgpu_drv_la_SOURCES += \
 	amdgpu_glamor.c \
+	amdgpu_glamor_wrappers.c \
 	amdgpu_pixmap.c
 
 EXTRA_DIST = \
diff --git a/src/amdgpu_bo_helper.c b/src/amdgpu_bo_helper.c
index c778796..54270c6 100644
--- a/src/amdgpu_bo_helper.c
+++ b/src/amdgpu_bo_helper.c
@@ -123,9 +123,6 @@ int amdgpu_bo_map(ScrnInfoPtr pScrn, struct amdgpu_buffer *bo)
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
 	int ret = 0;
 
-	if (info->use_glamor)
-		return 0;
-
 	if (bo->flags & AMDGPU_BO_FLAGS_GBM) {
 		uint32_t handle, stride, height;
 		union drm_amdgpu_gem_mmap args;
diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index 5ffbc6a..467c2fb 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -200,6 +200,8 @@ typedef struct {
 	struct amdgpu_dri2 dri2;
 
 	/* accel */
+	uint_fast32_t gpu_flushed;
+	uint_fast32_t gpu_synced;
 	Bool use_glamor;
 
 	/* general */
@@ -231,6 +233,30 @@ typedef struct {
 	/* cursor size */
 	int cursor_w;
 	int cursor_h;
+
+	struct {
+		CreateGCProcPtr SavedCreateGC;
+		RegionPtr (*SavedCopyArea)(DrawablePtr, DrawablePtr, GCPtr,
+					   int, int, int, int, int, int);
+		void (*SavedPolyFillRect)(DrawablePtr, GCPtr, int, xRectangle*);
+		CloseScreenProcPtr SavedCloseScreen;
+		GetImageProcPtr SavedGetImage;
+		GetSpansProcPtr SavedGetSpans;
+		CreatePixmapProcPtr SavedCreatePixmap;
+		DestroyPixmapProcPtr SavedDestroyPixmap;
+		CopyWindowProcPtr SavedCopyWindow;
+		ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
+		BitmapToRegionProcPtr SavedBitmapToRegion;
+#ifdef RENDER
+		CompositeProcPtr SavedComposite;
+		TrianglesProcPtr SavedTriangles;
+		GlyphsProcPtr SavedGlyphs;
+		TrapezoidsProcPtr SavedTrapezoids;
+		AddTrapsProcPtr SavedAddTraps;
+		UnrealizeGlyphProcPtr SavedUnrealizeGlyph;
+#endif
+	} glamor;
+
 } AMDGPUInfoRec, *AMDGPUInfoPtr;
 
 
diff --git a/src/amdgpu_glamor.c b/src/amdgpu_glamor.c
index 296115e..7c45f34 100644
--- a/src/amdgpu_glamor.c
+++ b/src/amdgpu_glamor.c
@@ -324,8 +324,10 @@ void amdgpu_glamor_flush(ScrnInfoPtr pScrn)
 {
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
 
-	if (info->use_glamor)
+	if (info->use_glamor) {
 		glamor_block_handler(pScrn->pScreen);
+		info->gpu_flushed++;
+	}
 }
 
 XF86VideoAdaptorPtr amdgpu_glamor_xv_init(ScreenPtr pScreen, int num_adapt)
diff --git a/src/amdgpu_glamor_wrappers.c b/src/amdgpu_glamor_wrappers.c
new file mode 100644
index 0000000..8edfde0
--- /dev/null
+++ b/src/amdgpu_glamor_wrappers.c
@@ -0,0 +1,992 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *             2010 Intel Corporation
+ *             2012,2015 Advanced Micro Devices, Inc.
+ *
+ * Partly based on code Copyright © 2008 Red Hat, Inc.
+ * Partly based on code Copyright © 2000 SuSE, Inc.
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the opyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef USE_GLAMOR
+
+#include "amdgpu_drv.h"
+#include "amdgpu_glamor.h"
+#include "amdgpu_pixmap.h"
+
+
+/**
+ * get_drawable_pixmap() returns the backing pixmap for a given drawable.
+ *
+ * @param pDrawable the drawable being requested.
+ *
+ * This function returns the backing pixmap for a drawable, whether it is a
+ * redirected window, unredirected window, or already a pixmap.
+ */
+static PixmapPtr
+get_drawable_pixmap(DrawablePtr pDrawable)
+{
+	if (pDrawable->type == DRAWABLE_WINDOW)
+		return pDrawable->pScreen->
+		    GetWindowPixmap((WindowPtr) pDrawable);
+	else
+		return (PixmapPtr) pDrawable;
+}
+
+/* Are there any outstanding GPU operations for this pixmap? */
+static Bool
+amdgpu_glamor_gpu_pending(uint_fast32_t gpu_synced, uint_fast32_t gpu_access)
+{
+	return (int_fast32_t)(gpu_access - gpu_synced) > 0;
+}
+
+/*
+ * Pixmap CPU access wrappers
+ */
+
+static Bool
+amdgpu_glamor_prepare_access_cpu(ScrnInfoPtr scrn, AMDGPUInfoPtr info,
+				 PixmapPtr pixmap, struct amdgpu_pixmap *priv,
+				 Bool need_sync)
+{
+	struct amdgpu_buffer *bo = priv->bo;
+	int ret;
+
+	/* When falling back to swrast, flush all pending operations */
+	if (need_sync)
+		amdgpu_glamor_flush(scrn);
+
+	if (!pixmap->devPrivate.ptr) {
+		ret = amdgpu_bo_map(scrn, bo);
+		if (ret) {
+			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+				   "%s: bo map failed: %s\n", __FUNCTION__,
+				   strerror(-ret));
+			return FALSE;
+		}
+
+		pixmap->devPrivate.ptr = bo->cpu_ptr;
+		info->gpu_synced = info->gpu_flushed;
+	} else if (need_sync) {
+		char pixel[4];
+
+		info->glamor.SavedGetImage(&pixmap->drawable, 0, 0, 1, 1,
+					   ZPixmap, ~0, pixel);
+		info->gpu_synced = info->gpu_flushed;
+	}
+
+	return TRUE;
+}
+
+static Bool
+amdgpu_glamor_prepare_access_cpu_ro(ScrnInfoPtr scrn, PixmapPtr pixmap,
+				    struct amdgpu_pixmap *priv)
+{
+	AMDGPUInfoPtr info;
+	Bool need_sync;
+
+	if (!priv)
+		return TRUE;
+
+	info = AMDGPUPTR(scrn);
+	need_sync = amdgpu_glamor_gpu_pending(info->gpu_synced, priv->gpu_write);
+	return amdgpu_glamor_prepare_access_cpu(scrn, AMDGPUPTR(scrn), pixmap,
+						priv, need_sync);
+}
+
+static Bool
+amdgpu_glamor_prepare_access_cpu_rw(ScrnInfoPtr scrn, PixmapPtr pixmap,
+				    struct amdgpu_pixmap *priv)
+{
+	AMDGPUInfoPtr info;
+	uint_fast32_t gpu_synced;
+	Bool need_sync;
+
+	if (!priv)
+		return TRUE;
+
+	info = AMDGPUPTR(scrn);
+	gpu_synced = info->gpu_synced;
+	need_sync = amdgpu_glamor_gpu_pending(gpu_synced, priv->gpu_write) |
+		amdgpu_glamor_gpu_pending(gpu_synced, priv->gpu_read);
+	return amdgpu_glamor_prepare_access_cpu(scrn, info, pixmap, priv,
+						need_sync);
+}
+
+static void
+amdgpu_glamor_finish_access_cpu(PixmapPtr pixmap)
+{
+	/* Nothing to do */
+}
+
+/*
+ * Pixmap GPU access wrappers
+ */
+
+static Bool
+amdgpu_glamor_use_gpu(PixmapPtr pixmap)
+{
+	return (pixmap->usage_hint &
+		(AMDGPU_CREATE_PIXMAP_SCANOUT | AMDGPU_CREATE_PIXMAP_DRI2)) != 0;
+}
+
+static Bool
+amdgpu_glamor_prepare_access_gpu(struct amdgpu_pixmap *priv)
+{
+	return priv != NULL;
+}
+
+static void
+amdgpu_glamor_finish_access_gpu_ro(AMDGPUInfoPtr info,
+				   struct amdgpu_pixmap *priv)
+{
+	priv->gpu_read = info->gpu_flushed + 1;
+}
+
+static void
+amdgpu_glamor_finish_access_gpu_rw(AMDGPUInfoPtr info,
+				   struct amdgpu_pixmap *priv)
+{
+	priv->gpu_write = priv->gpu_read = info->gpu_flushed + 1;
+}
+
+/*
+ * GC CPU access wrappers
+ */
+
+static Bool
+amdgpu_glamor_prepare_access_gc(ScrnInfoPtr scrn, GCPtr pGC)
+{
+	struct amdgpu_pixmap *priv;
+
+	if (pGC->stipple) {
+		priv = amdgpu_get_pixmap_private(pGC->stipple);
+		if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pGC->stipple, priv))
+			return FALSE;
+	}
+	if (pGC->fillStyle == FillTiled) {
+		priv = amdgpu_get_pixmap_private(pGC->tile.pixmap);
+		if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pGC->tile.pixmap,
+						      priv)) {
+			if (pGC->stipple)
+				amdgpu_glamor_finish_access_cpu(pGC->stipple);
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+static void
+amdgpu_glamor_finish_access_gc(GCPtr pGC)
+{
+	if (pGC->fillStyle == FillTiled)
+		amdgpu_glamor_finish_access_cpu(pGC->tile.pixmap);
+	if (pGC->stipple)
+		amdgpu_glamor_finish_access_cpu(pGC->stipple);
+}
+
+/*
+ * Picture CPU access wrappers
+ */
+
+static void
+amdgpu_glamor_picture_finish_access_cpu(PicturePtr picture)
+{
+	/* Nothing to do */
+}
+
+static Bool
+amdgpu_glamor_picture_prepare_access_cpu_ro(ScrnInfoPtr scrn,
+					    PicturePtr picture)
+{
+	PixmapPtr pixmap;
+	struct amdgpu_pixmap *priv;
+
+	if (picture->pDrawable == NULL)
+		return TRUE;
+
+	pixmap = get_drawable_pixmap(picture->pDrawable);
+	priv = amdgpu_get_pixmap_private(pixmap);
+	if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv))
+		return FALSE;
+
+	if (picture->alphaMap) {
+		pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable);
+		priv = amdgpu_get_pixmap_private(pixmap);
+		if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) {
+			amdgpu_glamor_picture_finish_access_cpu(picture);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static Bool
+amdgpu_glamor_picture_prepare_access_cpu_rw(ScrnInfoPtr scrn,
+					    PicturePtr picture)
+{
+	PixmapPtr pixmap;
+	struct amdgpu_pixmap *priv;
+
+	pixmap = get_drawable_pixmap(picture->pDrawable);
+	priv = amdgpu_get_pixmap_private(pixmap);
+	if (!amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv))
+		return FALSE;
+
+	if (picture->alphaMap) {
+		pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable);
+		priv = amdgpu_get_pixmap_private(pixmap);
+		if (!amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+			amdgpu_glamor_picture_finish_access_cpu(picture);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+/*
+ * GC rendering wrappers
+ */
+
+static void
+amdgpu_glamor_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
+			 DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
+			fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth,
+				    fSorted);
+			amdgpu_glamor_finish_access_gc(pGC);
+		}
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+amdgpu_glamor_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+			DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+amdgpu_glamor_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
+			int x, int y, int w, int h, int leftPad, int format,
+			char *bits)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+			   bits);
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static RegionPtr
+amdgpu_glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+			 int srcx, int srcy, int w, int h, int dstx, int dsty,
+			 unsigned long bitPlane)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pScreen);
+	PixmapPtr dst_pix = get_drawable_pixmap(pDst);
+	struct amdgpu_pixmap *dst_priv = amdgpu_get_pixmap_private(dst_pix);
+	RegionPtr ret = NULL;
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, dst_pix, dst_priv)) {
+		PixmapPtr src_pix = get_drawable_pixmap(pSrc);
+		struct amdgpu_pixmap *src_priv = amdgpu_get_pixmap_private(src_pix);
+		if (amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) {
+			ret =
+			    fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
+					dsty, bitPlane);
+			amdgpu_glamor_finish_access_cpu(src_pix);
+		}
+		amdgpu_glamor_finish_access_cpu(dst_pix);
+	}
+	return ret;
+}
+
+static RegionPtr
+amdgpu_glamor_copy_plane_nodstbo(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+				 int srcx, int srcy, int w, int h,
+				 int dstx, int dsty, unsigned long bitPlane)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pScreen);
+	PixmapPtr src_pix = get_drawable_pixmap(pSrc);
+	struct amdgpu_pixmap *src_priv = amdgpu_get_pixmap_private(src_pix);
+	RegionPtr ret = NULL;
+
+	if (amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) {
+		ret = fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h,
+				  dstx,	dsty, bitPlane);
+		amdgpu_glamor_finish_access_cpu(src_pix);
+	}
+	return ret;
+}
+
+static void
+amdgpu_glamor_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+			 DDXPointPtr pptInit)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		fbPolyPoint(pDrawable, pGC, mode, npt, pptInit);
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+amdgpu_glamor_poly_lines(DrawablePtr pDrawable, GCPtr pGC,
+			 int mode, int npt, DDXPointPtr ppt)
+{
+	if (pGC->lineWidth == 0) {
+		ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+		PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+		struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+		if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+			if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
+				fbPolyLine(pDrawable, pGC, mode, npt, ppt);
+				amdgpu_glamor_finish_access_gc(pGC);
+			}
+			amdgpu_glamor_finish_access_cpu(pixmap);
+		}
+		return;
+	}
+	/* fb calls mi functions in the lineWidth != 0 case. */
+	fbPolyLine(pDrawable, pGC, mode, npt, ppt);
+}
+
+static void
+amdgpu_glamor_poly_segment(DrawablePtr pDrawable, GCPtr pGC,
+			   int nsegInit, xSegment *pSegInit)
+{
+	if (pGC->lineWidth == 0) {
+		ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+		PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+		struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+		if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+			if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
+				fbPolySegment(pDrawable, pGC, nsegInit,
+					      pSegInit);
+				amdgpu_glamor_finish_access_gc(pGC);
+			}
+			amdgpu_glamor_finish_access_cpu(pixmap);
+		}
+		return;
+	}
+	/* fb calls mi functions in the lineWidth != 0 case. */
+	fbPolySegment(pDrawable, pGC, nsegInit, pSegInit);
+}
+
+static void
+amdgpu_glamor_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
+			     int nrect, xRectangle *prect)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
+			fbPolyFillRect(pDrawable, pGC, nrect, prect);
+			amdgpu_glamor_finish_access_gc(pGC);
+		}
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+amdgpu_glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+			      int x, int y, unsigned int nglyph,
+			      CharInfoPtr *ppci, pointer pglyphBase)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
+			fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
+					pglyphBase);
+			amdgpu_glamor_finish_access_gc(pGC);
+		}
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+amdgpu_glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+			     int x, int y, unsigned int nglyph,
+			     CharInfoPtr *ppci, pointer pglyphBase)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
+			fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
+				       pglyphBase);
+			amdgpu_glamor_finish_access_gc(pGC);
+		}
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+amdgpu_glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
+			  DrawablePtr pDrawable, int w, int h, int x, int y)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		priv = amdgpu_get_pixmap_private(pBitmap);
+		if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) {
+			if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) {
+				fbPushPixels(pGC, pBitmap, pDrawable, w, h, x,
+					     y);
+				amdgpu_glamor_finish_access_gc(pGC);
+			}
+			amdgpu_glamor_finish_access_cpu(pBitmap);
+		}
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+amdgpu_glamor_push_pixels_nodstbo(GCPtr pGC, PixmapPtr pBitmap,
+				  DrawablePtr pDrawable, int w, int h,
+				  int x, int y)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pBitmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) {
+		fbPushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
+		amdgpu_glamor_finish_access_cpu(pBitmap);
+	}
+}
+
+static RegionPtr
+amdgpu_glamor_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
+			GCPtr pGC, int srcx, int srcy, int width, int height,
+			int dstx, int dsty)
+{
+	ScreenPtr screen = pDstDrawable->pScreen;
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+	PixmapPtr src_pixmap = get_drawable_pixmap(pSrcDrawable);
+	PixmapPtr dst_pixmap = get_drawable_pixmap(pDstDrawable);
+	struct amdgpu_pixmap *src_priv = amdgpu_get_pixmap_private(src_pixmap);
+	struct amdgpu_pixmap *dst_priv = amdgpu_get_pixmap_private(dst_pixmap);
+	RegionPtr ret = NULL;
+
+	if (amdgpu_glamor_use_gpu(dst_pixmap) ||
+	    amdgpu_glamor_use_gpu(src_pixmap)) {
+		if (!amdgpu_glamor_prepare_access_gpu(dst_priv))
+			goto fallback;
+		if (src_priv != dst_priv &&
+		    !amdgpu_glamor_prepare_access_gpu(src_priv))
+			goto fallback;
+
+		ret = info->glamor.SavedCopyArea(pSrcDrawable, pDstDrawable,
+						 pGC, srcx, srcy,
+						 width, height, dstx, dsty);
+		amdgpu_glamor_finish_access_gpu_rw(info, dst_priv);
+		if (src_priv != dst_priv)
+			amdgpu_glamor_finish_access_gpu_ro(info, src_priv);
+
+		return ret;
+	}
+
+fallback:
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, dst_pixmap, dst_priv)) {
+		if (pSrcDrawable == pDstDrawable ||
+			amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pixmap,
+							    src_priv)) {
+			ret = fbCopyArea(pSrcDrawable, pDstDrawable, pGC,
+					 srcx, srcy, width, height, dstx, dsty);
+			if (pSrcDrawable != pDstDrawable)
+				amdgpu_glamor_finish_access_cpu(src_pixmap);
+		}
+		amdgpu_glamor_finish_access_cpu(dst_pixmap);
+	}
+
+	return ret;
+}
+
+static RegionPtr
+amdgpu_glamor_copy_area_nodstbo(DrawablePtr pSrcDrawable,
+				DrawablePtr pDstDrawable, GCPtr pGC,
+				int srcx, int srcy, int width, int height,
+				int dstx, int dsty)
+{
+	ScreenPtr screen = pDstDrawable->pScreen;
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	PixmapPtr src_pixmap = get_drawable_pixmap(pSrcDrawable);
+	PixmapPtr dst_pixmap = get_drawable_pixmap(pDstDrawable);
+	struct amdgpu_pixmap *src_priv;
+	RegionPtr ret = NULL;
+
+	if (src_pixmap != dst_pixmap) {
+		src_priv = amdgpu_get_pixmap_private(src_pixmap);
+
+		if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pixmap,
+							 src_priv))
+			return ret;
+	}
+
+	ret = fbCopyArea(pSrcDrawable, pDstDrawable, pGC, srcx, srcy,
+			 width, height, dstx, dsty);
+
+	if (src_pixmap != dst_pixmap)
+		amdgpu_glamor_finish_access_cpu(src_pixmap);
+
+	return ret;
+}
+
+static const GCOps amdgpu_glamor_ops = {
+	amdgpu_glamor_fill_spans,
+	amdgpu_glamor_set_spans,
+	amdgpu_glamor_put_image,
+	amdgpu_glamor_copy_area,
+	amdgpu_glamor_copy_plane,
+	amdgpu_glamor_poly_point,
+	amdgpu_glamor_poly_lines,
+	amdgpu_glamor_poly_segment,
+	miPolyRectangle,
+	miPolyArc,
+	miFillPolygon,
+	amdgpu_glamor_poly_fill_rect,
+	miPolyFillArc,
+	miPolyText8,
+	miPolyText16,
+	miImageText8,
+	miImageText16,
+	amdgpu_glamor_image_glyph_blt,
+	amdgpu_glamor_poly_glyph_blt,
+	amdgpu_glamor_push_pixels,
+};
+
+static GCOps amdgpu_glamor_nodstbo_ops;
+
+/**
+ * amdgpu_glamor_validate_gc() sets the ops to our implementations, which may be
+ * accelerated or may sync the card and fall back to fb.
+ */
+static void
+amdgpu_glamor_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pGC->pScreen);
+	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+
+	glamor_validate_gc(pGC, changes, pDrawable);
+	info->glamor.SavedCopyArea = pGC->ops->CopyArea;
+
+	if (amdgpu_get_pixmap_private(get_drawable_pixmap(pDrawable)) ||
+	    (pGC->stipple && amdgpu_get_pixmap_private(pGC->stipple)) ||
+	    (pGC->fillStyle == FillTiled &&
+	     amdgpu_get_pixmap_private(pGC->tile.pixmap)))
+		pGC->ops = (GCOps *)&amdgpu_glamor_ops;
+	else
+		pGC->ops = &amdgpu_glamor_nodstbo_ops;
+}
+
+static GCFuncs glamorGCFuncs = {
+	amdgpu_glamor_validate_gc,
+	miChangeGC,
+	miCopyGC,
+	miDestroyGC,
+	miChangeClip,
+	miDestroyClip,
+	miCopyClip
+};
+
+/**
+ * amdgpu_glamor_create_gc makes a new GC and hooks up its funcs handler, so that
+ * amdgpu_glamor_validate_gc() will get called.
+ */
+static int
+amdgpu_glamor_create_gc(GCPtr pGC)
+{
+	static Bool nodstbo_ops_initialized;
+
+	if (!fbCreateGC(pGC))
+		return FALSE;
+
+	if (!nodstbo_ops_initialized) {
+		amdgpu_glamor_nodstbo_ops = amdgpu_glamor_ops;
+
+		amdgpu_glamor_nodstbo_ops.FillSpans = pGC->ops->FillSpans;
+		amdgpu_glamor_nodstbo_ops.SetSpans = pGC->ops->SetSpans;
+		amdgpu_glamor_nodstbo_ops.PutImage = pGC->ops->PutImage;
+		amdgpu_glamor_nodstbo_ops.CopyArea = amdgpu_glamor_copy_area_nodstbo;
+		amdgpu_glamor_nodstbo_ops.CopyPlane = amdgpu_glamor_copy_plane_nodstbo;
+		amdgpu_glamor_nodstbo_ops.PolyPoint = pGC->ops->PolyPoint;
+		amdgpu_glamor_nodstbo_ops.Polylines = pGC->ops->Polylines;
+		amdgpu_glamor_nodstbo_ops.PolySegment = pGC->ops->PolySegment;
+		amdgpu_glamor_nodstbo_ops.PolyFillRect = pGC->ops->PolyFillRect;
+		amdgpu_glamor_nodstbo_ops.ImageGlyphBlt = pGC->ops->ImageGlyphBlt;
+		amdgpu_glamor_nodstbo_ops.PolyGlyphBlt = pGC->ops->PolyGlyphBlt;
+		amdgpu_glamor_nodstbo_ops.PushPixels = amdgpu_glamor_push_pixels_nodstbo;
+
+		nodstbo_ops_initialized = TRUE;
+	}
+
+	pGC->funcs = &glamorGCFuncs;
+
+	return TRUE;
+}
+
+/*
+ * Screen rendering wrappers
+ */
+
+static RegionPtr
+amdgpu_glamor_bitmap_to_region(PixmapPtr pPix)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pPix->drawable.pScreen);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pPix);
+	RegionPtr ret;
+
+	if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pPix, priv))
+		return NULL;
+	ret = fbPixmapToRegion(pPix);
+	amdgpu_glamor_finish_access_cpu(pPix);
+	return ret;
+}
+
+static void
+amdgpu_glamor_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg,
+			  RegionPtr prgnSrc)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pWin->drawable.pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(&pWin->drawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		fbCopyWindow(pWin, ptOldOrg, prgnSrc);
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+amdgpu_glamor_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
+			unsigned int format, unsigned long planeMask, char *d)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) {
+		fbGetImage(pDrawable, x, y, w, h, format, planeMask, d);
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+amdgpu_glamor_get_spans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt,
+			int *pwidth, int nspans, char *pdstStart)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
+
+	if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) {
+		fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+		amdgpu_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+/*
+ * Picture screen rendering wrappers
+ */
+
+#ifdef RENDER
+
+static void
+amdgpu_glamor_composite(CARD8 op,
+			PicturePtr pSrc,
+			PicturePtr pMask,
+			PicturePtr pDst,
+			INT16 xSrc, INT16 ySrc,
+			INT16 xMask, INT16 yMask,
+			INT16 xDst, INT16 yDst,
+			CARD16 width, CARD16 height)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pDrawable->pScreen);
+	AMDGPUInfoPtr info;
+	PixmapPtr pixmap;
+	struct amdgpu_pixmap *dst_priv, *src_priv = NULL, *mask_priv = NULL;
+	Bool gpu_done = FALSE;
+
+	if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap))
+		goto fallback;
+
+	pixmap = get_drawable_pixmap(pDst->pDrawable);
+	if (&pixmap->drawable != pDst->pDrawable ||
+	    pixmap->usage_hint != AMDGPU_CREATE_PIXMAP_SCANOUT)
+		goto fallback;
+
+	dst_priv = amdgpu_get_pixmap_private(pixmap);
+	if (!amdgpu_glamor_prepare_access_gpu(dst_priv))
+		goto fallback;
+
+	info = AMDGPUPTR(scrn);
+	if (!pSrc->pDrawable ||
+	    ((pixmap = get_drawable_pixmap(pSrc->pDrawable)) &&
+	     (src_priv = amdgpu_get_pixmap_private(pixmap)) &&
+	     amdgpu_glamor_prepare_access_gpu(src_priv))) {
+		if (!pMask || !pMask->pDrawable ||
+		    ((pixmap = get_drawable_pixmap(pMask->pDrawable)) &&
+		     (mask_priv = amdgpu_get_pixmap_private(pixmap)) &&
+		     amdgpu_glamor_prepare_access_gpu(mask_priv))) {
+			info->glamor.SavedComposite(op, pSrc, pMask, pDst,
+						    xSrc, ySrc, xMask, yMask,
+						    xDst, yDst, width, height);
+			gpu_done = TRUE;
+
+			if (mask_priv)
+				amdgpu_glamor_finish_access_gpu_ro(info, mask_priv);
+		}
+
+		if (src_priv)
+			amdgpu_glamor_finish_access_gpu_ro(info, src_priv);
+	}
+	amdgpu_glamor_finish_access_gpu_rw(info, dst_priv);
+
+	if (gpu_done)
+		return;
+
+fallback:
+	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, pDst)) {
+		if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, pSrc)) {
+			if (!pMask ||
+			    amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, pMask)) {
+				fbComposite(op, pSrc, pMask, pDst,
+					    xSrc, ySrc,
+					    xMask, yMask,
+					    xDst, yDst,
+					    width, height);
+				if (pMask)
+					amdgpu_glamor_picture_finish_access_cpu(pMask);
+			}
+			amdgpu_glamor_picture_finish_access_cpu(pSrc);
+		}
+		amdgpu_glamor_picture_finish_access_cpu(pDst);
+	}
+}
+
+static void
+amdgpu_glamor_add_traps(PicturePtr pPicture,
+		    INT16 x_off, INT16 y_off, int ntrap, xTrap *traps)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pPicture->pDrawable->pScreen);
+
+	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, pPicture)) {
+		fbAddTraps(pPicture, x_off, y_off, ntrap, traps);
+		amdgpu_glamor_picture_finish_access_cpu(pPicture);
+	}
+}
+
+static void
+amdgpu_glamor_glyphs(CARD8 op,
+		     PicturePtr src,
+		     PicturePtr dst,
+		     PictFormatPtr maskFormat,
+		     INT16 xSrc,
+		     INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen);
+
+	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, dst)) {
+		if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, src)) {
+			AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+
+			info->glamor.SavedGlyphs(op, src, dst, maskFormat, xSrc,
+						 ySrc, nlist, list, glyphs);
+			amdgpu_glamor_picture_finish_access_cpu(src);
+		}
+		amdgpu_glamor_picture_finish_access_cpu(dst);
+	}
+}
+
+static void
+amdgpu_glamor_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
+			 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+			 int ntrap, xTrapezoid *traps)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen);
+
+	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, dst)) {
+		if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, src)) {
+			AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+
+			info->glamor.SavedTrapezoids(op, src, dst, maskFormat,
+						     xSrc, ySrc, ntrap, traps);
+			amdgpu_glamor_picture_finish_access_cpu(src);
+		}
+		amdgpu_glamor_picture_finish_access_cpu(dst);
+	}
+}
+
+static void
+amdgpu_glamor_triangles(CARD8 op, PicturePtr src, PicturePtr dst,
+			PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+			int ntri, xTriangle *tri)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen);
+
+	if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, dst)) {
+		if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, src)) {
+			AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+
+			info->glamor.SavedTriangles(op, src, dst, maskFormat,
+						    xSrc, ySrc, ntri, tri);
+			amdgpu_glamor_picture_finish_access_cpu(src);
+		}
+		amdgpu_glamor_picture_finish_access_cpu(dst);
+	}
+}
+
+#endif /* RENDER */
+
+
+/**
+ * amdgpu_glamor_close_screen() unwraps its wrapped screen functions and tears
+ * down our screen private, before calling down to the next CloseScreen.
+ */
+static Bool
+amdgpu_glamor_close_screen(CLOSE_SCREEN_ARGS_DECL)
+{
+	AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(pScreen));
+#ifdef RENDER
+	PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+
+	pScreen->CreateGC = info->glamor.SavedCreateGC;
+	pScreen->CloseScreen = info->glamor.SavedCloseScreen;
+	pScreen->GetImage = info->glamor.SavedGetImage;
+	pScreen->GetSpans = info->glamor.SavedGetSpans;
+	pScreen->CreatePixmap = info->glamor.SavedCreatePixmap;
+	pScreen->DestroyPixmap = info->glamor.SavedDestroyPixmap;
+	pScreen->CopyWindow = info->glamor.SavedCopyWindow;
+	pScreen->ChangeWindowAttributes =
+	    info->glamor.SavedChangeWindowAttributes;
+	pScreen->BitmapToRegion = info->glamor.SavedBitmapToRegion;
+#ifdef RENDER
+	if (ps) {
+		ps->Composite = info->glamor.SavedComposite;
+		ps->Glyphs = info->glamor.SavedGlyphs;
+		ps->UnrealizeGlyph = info->glamor.SavedUnrealizeGlyph;
+		ps->Trapezoids = info->glamor.SavedTrapezoids;
+		ps->AddTraps = info->glamor.SavedAddTraps;
+		ps->Triangles = info->glamor.SavedTriangles;
+
+		ps->UnrealizeGlyph = info->glamor.SavedUnrealizeGlyph;
+	}
+#endif
+
+	return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS);
+}
+
+/**
+ * @param screen screen being initialized
+ */
+void
+amdgpu_glamor_screen_init(ScreenPtr screen)
+{
+	AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(screen));
+
+	/*
+	 * Replace various fb screen functions
+	 */
+	info->glamor.SavedCloseScreen = screen->CloseScreen;
+	screen->CloseScreen = amdgpu_glamor_close_screen;
+
+	info->glamor.SavedCreateGC = screen->CreateGC;
+	screen->CreateGC = amdgpu_glamor_create_gc;
+
+	info->glamor.SavedGetImage = screen->GetImage;
+	screen->GetImage = amdgpu_glamor_get_image;
+
+	info->glamor.SavedGetSpans = screen->GetSpans;
+	screen->GetSpans = amdgpu_glamor_get_spans;
+
+	info->glamor.SavedCreatePixmap = screen->CreatePixmap;
+	info->glamor.SavedDestroyPixmap = screen->DestroyPixmap;
+
+	info->glamor.SavedCopyWindow = screen->CopyWindow;
+	screen->CopyWindow = amdgpu_glamor_copy_window;
+
+	info->glamor.SavedBitmapToRegion = screen->BitmapToRegion;
+	screen->BitmapToRegion = amdgpu_glamor_bitmap_to_region;
+
+#ifdef RENDER
+	{
+		PictureScreenPtr ps = GetPictureScreenIfSet(screen);
+		if (ps) {
+			info->glamor.SavedComposite = ps->Composite;
+			ps->Composite = amdgpu_glamor_composite;
+
+			info->glamor.SavedUnrealizeGlyph = ps->UnrealizeGlyph;
+
+			ps->Glyphs = amdgpu_glamor_glyphs;
+			ps->Triangles = amdgpu_glamor_triangles;
+			ps->Trapezoids = amdgpu_glamor_trapezoids;
+
+			info->glamor.SavedAddTraps = ps->AddTraps;
+			ps->AddTraps = amdgpu_glamor_add_traps;
+		}
+	}
+#endif
+}
+
+#endif /* USE_GLAMOR */
diff --git a/src/amdgpu_pixmap.h b/src/amdgpu_pixmap.h
index c5cf137..a5dc081 100644
--- a/src/amdgpu_pixmap.h
+++ b/src/amdgpu_pixmap.h
@@ -29,6 +29,9 @@
 #include "amdgpu_drv.h"
 
 struct amdgpu_pixmap {
+	uint_fast32_t gpu_read;
+	uint_fast32_t gpu_write;
+
 	struct amdgpu_buffer *bo;
 	int stride;
 };
commit 895e4d73d5f042afa13065b64a78f5625ecb5612
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri May 29 18:53:40 2015 +0900

    glamor: Remove unused function radeon_glamor_pixmap_is_offscreen
    
    (cherry picked from radeon commit 2fa021f77372ca93375a3d13a0c43a9089674899)
    
    Signed-off-by: Darren Powell <darren.powell at amd.com>
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_glamor.c b/src/amdgpu_glamor.c
index 79b3d01..296115e 100644
--- a/src/amdgpu_glamor.c
+++ b/src/amdgpu_glamor.c
@@ -144,12 +144,6 @@ amdgpu_glamor_create_textured_pixmap(PixmapPtr pixmap, struct amdgpu_pixmap *pri
 						 priv->stride);
 }
 
-Bool amdgpu_glamor_pixmap_is_offscreen(PixmapPtr pixmap)
-{
-	struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap);
-	return priv && priv->bo;
-}
-
 #ifndef CREATE_PIXMAP_USAGE_SHARED
 #define CREATE_PIXMAP_USAGE_SHARED AMDGPU_CREATE_PIXMAP_DRI2
 #endif
diff --git a/src/amdgpu_glamor.h b/src/amdgpu_glamor.h
index f2414da..7959e9d 100644
--- a/src/amdgpu_glamor.h
+++ b/src/amdgpu_glamor.h
@@ -61,8 +61,6 @@ Bool
 amdgpu_glamor_create_textured_pixmap(PixmapPtr pixmap, struct amdgpu_pixmap *priv);
 void amdgpu_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst);
 
-Bool amdgpu_glamor_pixmap_is_offscreen(PixmapPtr pixmap);
-
 XF86VideoAdaptorPtr amdgpu_glamor_xv_init(ScreenPtr pScreen, int num_adapt);
 
 #endif /* AMDGPU_GLAMOR_H */
commit cc5671c587d575b2a7d2802d17e8af0384a2cea5
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri May 29 18:53:36 2015 +0900

    Add RADEON_CREATE_PIXMAP_SCANOUT flag
    
    It means that the pixmap is used for scanout exclusively.
    
    (cherry picked from radeon commit e96349ba6281fd18b8bf9c76629128276b065e6c)
    
    Signed-off-by: Darren Powell <darren.powell at amd.com>
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_pixmap.h b/src/amdgpu_pixmap.h
index e37466c..c5cf137 100644
--- a/src/amdgpu_pixmap.h
+++ b/src/amdgpu_pixmap.h
@@ -101,8 +101,9 @@ static inline struct amdgpu_buffer *amdgpu_get_pixmap_bo(PixmapPtr pPix)
 }
 
 enum {
-	AMDGPU_CREATE_PIXMAP_DRI2 = 0x08000000,
-	AMDGPU_CREATE_PIXMAP_LINEAR = 0x04000000
+	AMDGPU_CREATE_PIXMAP_DRI2    = 0x08000000,
+	AMDGPU_CREATE_PIXMAP_LINEAR  = 0x04000000,
+	AMDGPU_CREATE_PIXMAP_SCANOUT = 0x02000000,
 };
 
 extern Bool amdgpu_pixmap_init(ScreenPtr screen);
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 7264ea0..d855787 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -97,7 +97,8 @@ static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
 	ScreenPtr pScreen = pScrn->pScreen;
 	PixmapPtr pixmap;
 
-	pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
+	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
+					  AMDGPU_CREATE_PIXMAP_SCANOUT);
 	if (!pixmap)
 		return NULL;
 
commit 21834953ee64920438dee1c94f3a1e53dc58b82d
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri May 29 18:53:32 2015 +0900

    Split out struct drmmode_scanout for rotation shadow buffer information
    
    Will be used for other kinds of dedicated scanout buffers as well.
    
    (cherry picked from radeon commit 9be7dd382e86d2b804de81d4e2af7431b2e16843)
    
    Signed-off-by: Darren Powell <darren.powell at amd.com>
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c
index c0a5a32..75a4ba3 100644
--- a/src/amdgpu_present.c
+++ b/src/amdgpu_present.c
@@ -227,7 +227,7 @@ amdgpu_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
 		drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
 
 		if (!drmmode_crtc ||
-		    drmmode_crtc->rotate_buffer != NULL ||
+		    drmmode_crtc->rotate.bo != NULL ||
 		    drmmode_crtc->dpms_mode != DPMSModeOn)
 			return FALSE;
 	}
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index c391ab2..7264ea0 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -314,6 +314,93 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
 	}
 }
 
+static void
+drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
+                             struct drmmode_scanout *scanout)
+{
+
+	if (scanout->pixmap) {
+		drmmode_destroy_bo_pixmap(scanout->pixmap);
+		scanout->pixmap = NULL;
+	}
+
+	if (scanout->bo) {
+		drmModeRmFB(drmmode->fd, scanout->fb_id);
+		scanout->fb_id = 0;
+		amdgpu_bo_unref(&scanout->bo);
+		scanout->bo = NULL;
+	}
+
+}
+
+static void *
+drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
+                              struct drmmode_scanout *scanout,
+                              int width, int height)
+{
+	ScrnInfoPtr pScrn = crtc->scrn;
+	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+	int ret;
+	int pitch;
+	union gbm_bo_handle bo_handle;
+
+	/* rotation requires acceleration */
+	if (info->shadow_fb) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "Rotation requires acceleration!\n");
+		return NULL;
+	}
+
+	scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height,
+					       pScrn->depth, 0,
+					       pScrn->bitsPerPixel, &pitch);
+	if (!scanout->bo) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "Failed to allocate rotation buffer memory\n");
+		return NULL;
+	}
+
+	bo_handle = gbm_bo_get_handle(scanout->bo->bo.gbm);
+	ret = drmModeAddFB(drmmode->fd, width, height, pScrn->depth,
+			   pScrn->bitsPerPixel, pitch,
+			   bo_handle.u32, &scanout->fb_id);
+	if (ret) {
+		ErrorF("failed to add rotate fb\n");
+	}
+
+	return scanout->bo;
+}
+
+static PixmapPtr
+drmmode_crtc_scanout_create(xf86CrtcPtr crtc,
+                            struct drmmode_scanout *scanout,
+                            void *data, int width, int height)
+{
+	ScrnInfoPtr pScrn = crtc->scrn;
+	unsigned long rotate_pitch;
+
+	if (!data)
+		data = drmmode_crtc_scanout_allocate(crtc, scanout, width, height);
+
+	rotate_pitch = gbm_bo_get_stride(scanout->bo->bo.gbm);
+
+	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
+						 width, height,
+						 pScrn->depth,
+						 pScrn->bitsPerPixel,
+						 rotate_pitch,
+						 scanout->bo);
+	if (scanout->pixmap == NULL) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		           "Couldn't allocate shadow pixmap for rotated CRTC\n");
+	}
+	return scanout->pixmap;
+
+}
+
+
 static Bool
 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		       Rotation rotation, int x, int y)
@@ -406,8 +493,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 			y = 0;
 		} else
 #endif
-		if (drmmode_crtc->rotate_fb_id) {
-			fb_id = drmmode_crtc->rotate_fb_id;
+		if (drmmode_crtc->rotate.fb_id) {
+			fb_id = drmmode_crtc->rotate.fb_id;
 			x = y = 0;
 		}
 		ret =
@@ -527,68 +614,19 @@ static void drmmode_show_cursor(xf86CrtcPtr crtc)
 static void *drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width,
 					  int height)
 {
-	ScrnInfoPtr pScrn = crtc->scrn;
-	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-	drmmode_ptr drmmode = drmmode_crtc->drmmode;
-	struct amdgpu_buffer *rotate_buffer = NULL;
-	int ret;
-	int pitch;
-	union gbm_bo_handle bo_handle;
-
-	/* rotation requires acceleration */
-	if (info->shadow_fb) {
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-			   "Rotation requires acceleration!\n");
-		return NULL;
-	}
 
-	rotate_buffer = amdgpu_alloc_pixmap_bo(pScrn, width, height,
-					       pScrn->depth, 0,
-					       pScrn->bitsPerPixel, &pitch);
-	if (!rotate_buffer) {
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-			   "Failed to allocate rotation buffer memory\n");
-		return NULL;
-	}
-
-	bo_handle = gbm_bo_get_handle(rotate_buffer->bo.gbm);
-	ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
-			   crtc->scrn->bitsPerPixel, pitch,
-			   bo_handle.u32, &drmmode_crtc->rotate_fb_id);
-	if (ret) {
-		ErrorF("failed to add rotate fb\n");
-	}
-
-	drmmode_crtc->rotate_buffer = rotate_buffer;
-	return rotate_buffer;
+	return drmmode_crtc_scanout_allocate(crtc, &drmmode_crtc->rotate,
+					     width, height);
 }
 
 static PixmapPtr
 drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
 {
-	ScrnInfoPtr pScrn = crtc->scrn;
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-	unsigned long rotate_pitch;
-	PixmapPtr rotate_pixmap;
-
-	if (!data)
-		data = drmmode_crtc_shadow_allocate(crtc, width, height);
-
-	rotate_pitch = gbm_bo_get_stride(drmmode_crtc->rotate_buffer->bo.gbm);
-
-	rotate_pixmap = drmmode_create_bo_pixmap(pScrn,
-						 width, height,
-						 pScrn->depth,
-						 pScrn->bitsPerPixel,
-						 rotate_pitch,
-						 drmmode_crtc->rotate_buffer);
-	if (rotate_pixmap == NULL) {
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-			   "Couldn't allocate shadow pixmap for rotated CRTC\n");
-	}
-	return rotate_pixmap;
 
+	return drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, data,
+					   width, height);
 }
 
 static void
@@ -598,16 +636,7 @@ drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap,
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
 
-	if (rotate_pixmap)
-		drmmode_destroy_bo_pixmap(rotate_pixmap);
-
-	if (data) {
-		drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
-		drmmode_crtc->rotate_fb_id = 0;
-		amdgpu_bo_unref(&drmmode_crtc->rotate_buffer);
-		drmmode_crtc->rotate_buffer = NULL;
-	}
-
+	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
 }
 
 static void
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index df46099..77d9c03 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -70,13 +70,18 @@ typedef struct {
 	amdgpu_drm_abort_proc abort;
 } drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr;
 
+struct drmmode_scanout {
+	struct amdgpu_buffer *bo;
+	PixmapPtr pixmap;
+	unsigned fb_id;
+};
+
 typedef struct {
 	drmmode_ptr drmmode;
 	drmModeCrtcPtr mode_crtc;
 	int hw_id;
 	struct amdgpu_buffer *cursor_buffer;
-	struct amdgpu_buffer *rotate_buffer;
-	unsigned rotate_fb_id;
+	struct drmmode_scanout rotate;
 	int dpms_mode;
 	CARD64 dpms_last_ust;
 	uint32_t dpms_last_seq;
commit e4e4f7b83e7d7e43993fa0793d666d6dec2980f8
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri May 29 18:53:21 2015 +0900

    Rename scanout_pixmap_x field to prime_pixmap_x
    
    To avoid confusion with upcoming changes.
    
    (cherry picked from radeon commit c32b0530302739f6512755bccf281c2300617376)
    
    Signed-off-by: Darren Powell <darren.powell at amd.com>
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 870ced6..c391ab2 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -402,7 +402,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		fb_id = drmmode->fb_id;
 #ifdef AMDGPU_PIXMAP_SHARING
 		if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
-			x = drmmode_crtc->scanout_pixmap_x;
+			x = drmmode_crtc->prime_pixmap_x;
 			y = 0;
 		} else
 #endif
@@ -635,7 +635,7 @@ static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
 			PixmapStopDirtyTracking(crtc->
 						randr_crtc->scanout_pixmap,
 						screenpix);
-		drmmode_crtc->scanout_pixmap_x = 0;
+		drmmode_crtc->prime_pixmap_x = 0;
 		return TRUE;
 	}
 
@@ -677,7 +677,7 @@ static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
 		screen->width = screenpix->drawable.width = total_width;
 		screen->height = screenpix->drawable.height = max_height;
 	}
-	drmmode_crtc->scanout_pixmap_x = this_x;
+	drmmode_crtc->prime_pixmap_x = this_x;
 #ifdef HAS_DIRTYTRACKING2
 	PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0);
 #else
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 90ab537..df46099 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -83,7 +83,7 @@ typedef struct {
 	int dpms_last_fps;
 	uint32_t interpolated_vblanks;
 	uint16_t lut_r[256], lut_g[256], lut_b[256];
-	int scanout_pixmap_x;
+	int prime_pixmap_x;
 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
 
 typedef struct {


More information about the xorg-commit mailing list