xf86-video-ati: Branch 'master' - 7 commits

Michel Dänzer daenzer at kemper.freedesktop.org
Thu Apr 16 02:43:57 PDT 2015


 configure.ac                 |   10 
 man/radeon.man               |   16 
 src/Makefile.am              |    1 
 src/drmmode_display.c        |  271 ++++++++---
 src/drmmode_display.h        |   17 
 src/radeon.h                 |   33 +
 src/radeon_bo_helper.c       |    7 
 src/radeon_dri3.c            |   15 
 src/radeon_glamor.c          |   80 ++-
 src/radeon_glamor.h          |   21 
 src/radeon_glamor_wrappers.c |  985 +++++++++++++++++++++++++++++++++++++++++++
 src/radeon_kms.c             |  180 +++++++
 src/radeon_present.c         |    2 
 13 files changed, 1515 insertions(+), 123 deletions(-)

New commits:
commit ae92d1765fa370a8d94c2856ad6c45d273ec3c69
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Mar 18 16:23:24 2015 +0900

    glamor: Add Option "ShadowPrimary" v2
    
    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.
    
    v2:
    * Set region data pointer to NULL for keeping only the extents
    * Move pRegion and pBox local variable declarations closer to their uses
      in drmmode_set_mode_major()

diff --git a/configure.ac b/configure.ac
index 57b4c1c..4ca5352 100644
--- a/configure.ac
+++ b/configure.ac
@@ -125,6 +125,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/radeon.man b/man/radeon.man
index 6e46f89..2703773 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -290,6 +290,22 @@ as of TAHITI, otherwise
 The following driver
 .B Options
 are 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.
+
+.PP
+The following driver
+.B Options
+are supported for
 .B EXA
 :
 .TP
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index d8d3ca3..1f22869 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -33,6 +33,7 @@
 #include <sys/ioctl.h>
 #include <time.h>
 #include "cursorstr.h"
+#include "damagestr.h"
 #include "micmap.h"
 #include "xf86cmap.h"
 #include "radeon.h"
@@ -489,6 +490,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,
@@ -510,6 +531,13 @@ drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
 		return NULL;
 	}
 
+	if (scanout->bo) {
+		if (scanout->width == width && scanout->height == height)
+			return scanout->bo->ptr;
+
+		drmmode_crtc_scanout_destroy(drmmode, scanout);
+	}
+
 	rotate_pitch =
 		RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0))
 		* drmmode->cpp;
@@ -531,6 +559,8 @@ drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
 	if (ret)
 		ErrorF("failed to add scanout fb\n");
 
+	scanout->width = width;
+	scanout->height = height;
 	return scanout->bo->ptr;
 }
 
@@ -543,6 +573,13 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
 	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);
 
@@ -562,6 +599,14 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
 	return scanout->pixmap;
 }
 
+static void
+radeon_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,
 		     Rotation rotation, int x, int y)
@@ -631,6 +676,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;
@@ -656,11 +703,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(radeon_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, drmmode_crtc->mode_crtc->crtc_id,
 				     fb_id, x, y, output_ids, output_count, &kmode);
@@ -1689,7 +1771,7 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 	if (front_bo)
 		radeon_bo_wait(front_bo);
 
-	if (info->allowColorTiling) {
+	if (info->allowColorTiling && !info->shadow_primary) {
 		if (info->ChipFamily >= CHIP_FAMILY_R600) {
 			if (info->allowColorTiling2D) {
 				tiling_flags |= RADEON_TILING_MACRO;
@@ -1770,7 +1852,10 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 	scrn->virtualY = height;
 	scrn->displayWidth = pitch / cpp;
 
-	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align, RADEON_GEM_DOMAIN_VRAM, 0);
+	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align,
+					info->shadow_primary ?
+					RADEON_GEM_DOMAIN_GTT :
+					RADEON_GEM_DOMAIN_VRAM, 0);
 	if (!info->front_bo)
 		goto fail;
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 6607896..43a3a4a 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -76,6 +76,7 @@ struct drmmode_scanout {
     struct radeon_bo *bo;
     PixmapPtr pixmap;
     unsigned fb_id;
+    int width, height;
 };
 
 typedef struct {
@@ -84,6 +85,9 @@ typedef struct {
     int hw_id;
     struct radeon_bo *cursor_bo;
     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;
@@ -125,6 +129,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);
 
diff --git a/src/radeon.h b/src/radeon.h
index 80adc5d..afb66b2 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -151,6 +151,7 @@ typedef enum {
     OPTION_SWAPBUFFERS_WAIT,
     OPTION_DELETE_DP12,
     OPTION_DRI3,
+    OPTION_SHADOW_PRIMARY,
 } RADEONOpts;
 
 
@@ -476,6 +477,7 @@ typedef struct {
     struct radeon_accel_state *accel_state;
     Bool              accelOn;
     Bool              use_glamor;
+    Bool              shadow_primary;
     Bool	      exa_pixmaps;
     Bool              exa_force_create;
     XF86ModReqInfo    exaReq;
diff --git a/src/radeon_bo_helper.c b/src/radeon_bo_helper.c
index fdff032..ebbb192 100644
--- a/src/radeon_bo_helper.c
+++ b/src/radeon_bo_helper.c
@@ -88,12 +88,15 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth,
 	if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH)
 		tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO;
 
+	if ((usage_hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP &&
+	     info->shadow_primary)
 #ifdef CREATE_PIXMAP_USAGE_SHARED
-	if ((usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED) {
+	    || (usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED
+#endif
+	    ) {
 		tiling = 0;
 		domain = RADEON_GEM_DOMAIN_GTT;
 	}
-#endif
     }
 
     /* Small pixmaps must not be macrotiled on R300, hw cannot sample them
diff --git a/src/radeon_dri3.c b/src/radeon_dri3.c
index 3a7322e..1415a0d 100644
--- a/src/radeon_dri3.c
+++ b/src/radeon_dri3.c
@@ -101,8 +101,17 @@ static PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen,
 	if (RADEONPTR(xf86ScreenToScrn(screen))->use_glamor) {
 		pixmap = glamor_pixmap_from_fd(screen, fd, width, height,
 					       stride, depth, bpp);
-		if (pixmap)
-			return pixmap;
+		if (pixmap) {
+			struct radeon_pixmap *priv =
+				calloc(1, sizeof(struct radeon_pixmap));
+
+			if (priv) {
+				radeon_set_pixmap_private(pixmap, priv);
+				return pixmap;
+			}
+
+			screen->DestroyPixmap(pixmap);
+		}
 	}
 #endif
 
@@ -118,7 +127,7 @@ static PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen,
 		return NULL;
 	}
 
-	pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
+	pixmap = screen->CreatePixmap(screen, 0, 0, depth, RADEON_CREATE_PIXMAP_DRI2);
 	if (!pixmap)
 		return NULL;
 
diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c
index 74d9584..eccb8f7 100644
--- a/src/radeon_glamor.c
+++ b/src/radeon_glamor.c
@@ -166,26 +166,24 @@ radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_pixmap *pri
 						 priv->stride);
 }
 
-#ifndef CREATE_PIXMAP_USAGE_SHARED
-#define CREATE_PIXMAP_USAGE_SHARED RADEON_CREATE_PIXMAP_DRI2
-#endif
-
-#define RADEON_CREATE_PIXMAP_SHARED(usage) \
-	(((usage) & ~RADEON_CREATE_PIXMAP_TILING_FLAGS) == RADEON_CREATE_PIXMAP_DRI2 || \
-	 (usage) == CREATE_PIXMAP_USAGE_SHARED)
-
 static PixmapPtr
 radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 			unsigned usage)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	RADEONInfoPtr info = RADEONPTR(scrn);
 	struct radeon_pixmap *priv;
 	PixmapPtr pixmap, new_pixmap = NULL;
 
 	if (!RADEON_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);
+		} else {
+			pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
+			if (pixmap)
+			    return pixmap;
+		}
 	}
 
 	if (w > 32767 || h > 32767)
@@ -220,6 +218,8 @@ radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 
 		if (!radeon_glamor_create_textured_pixmap(pixmap, priv))
 			goto fallback_glamor;
+
+		pixmap->devPrivate.ptr = NULL;
 	}
 
 	return pixmap;
@@ -258,6 +258,13 @@ fallback_pixmap:
 static Bool radeon_glamor_destroy_pixmap(PixmapPtr pixmap)
 {
 	if (pixmap->refcnt == 1) {
+		if (pixmap->devPrivate.ptr) {
+			struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap);
+
+			if (bo)
+				radeon_bo_unmap(bo);
+		}
+
 		glamor_egl_destroy_textured_pixmap(pixmap);
 		radeon_set_pixmap_bo(pixmap, NULL);
 	}
@@ -316,6 +323,26 @@ Bool
 radeon_glamor_init(ScreenPtr screen)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	RADEONInfoPtr info = RADEONPTR(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 |
@@ -338,6 +365,17 @@ radeon_glamor_init(ScreenPtr screen)
 #endif
 		return FALSE;
 
+	if (info->shadow_primary)
+		radeon_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 = radeon_glamor_create_pixmap;
 	screen->DestroyPixmap = radeon_glamor_destroy_pixmap;
 #ifdef RADEON_PIXMAP_SHARING
diff --git a/src/radeon_glamor.h b/src/radeon_glamor.h
index ea385c7..1ba7049 100644
--- a/src/radeon_glamor.h
+++ b/src/radeon_glamor.h
@@ -35,6 +35,16 @@
 
 #include "radeon_surface.h"
 
+#ifndef CREATE_PIXMAP_USAGE_SHARED
+#define CREATE_PIXMAP_USAGE_SHARED RADEON_CREATE_PIXMAP_DRI2
+#endif
+
+#define RADEON_CREATE_PIXMAP_SHARED(usage) \
+	(((usage) & ~RADEON_CREATE_PIXMAP_TILING_FLAGS) == RADEON_CREATE_PIXMAP_DRI2 || \
+	 (usage) == CREATE_PIXMAP_USAGE_SHARED)
+
+struct radeon_pixmap;
+
 #ifndef GLAMOR_NO_DRI3
 #define GLAMOR_NO_DRI3 0
 #define glamor_fd_from_pixmap glamor_dri3_fd_from_pixmap
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 3f723d5..64593ab 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -70,6 +70,7 @@ const OptionInfoRec RADEONOptions_KMS[] = {
     { OPTION_SUBPIXEL_ORDER, "SubPixelOrder",    OPTV_ANYSTR,  {0}, FALSE },
 #ifdef USE_GLAMOR
     { OPTION_ACCELMETHOD,    "AccelMethod",      OPTV_STRING,  {0}, FALSE },
+    { OPTION_SHADOW_PRIMARY, "ShadowPrimary",    OPTV_BOOLEAN, {0}, FALSE },
 #endif
     { OPTION_EXA_VSYNC,      "EXAVSync",         OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_EXA_PIXMAPS,    "EXAPixmaps",	 OPTV_BOOLEAN,   {0}, FALSE },
@@ -308,6 +309,142 @@ radeon_dirty_update(ScreenPtr screen)
 }
 #endif
 
+static Bool
+radeon_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
+radeon_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
+radeon_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;
+    RADEONInfoPtr info;
+    Bool force;
+
+    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 (!radeon_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);
+    info = RADEONPTR(scrn);
+    force = info->accel_state->force;
+    info->accel_state->force = TRUE;
+
+    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);
+
+    info->accel_state->force = force;
+
+    radeon_cs_flush_indirect(scrn);
+
+clear_damage:
+    RegionEmpty(pRegion);
+
+out:
+    drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+radeon_scanout_update(xf86CrtcPtr xf86_crtc)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+    struct radeon_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 (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
+					  pDraw->width, pDraw->height))
+	return;
+
+    scrn = xf86_crtc->scrn;
+    drm_queue_entry = radeon_drm_queue_alloc(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT,
+					     RADEON_DRM_QUEUE_ID_DEFAULT,
+					     xf86_crtc,
+					     radeon_scanout_update_handler,
+					     radeon_scanout_update_abort);
+    if (!drm_queue_entry) {
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		   "radeon_drm_queue_alloc failed for scanout update\n");
+	return;
+    }
+
+    vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
+    vbl.request.type |= radeon_populate_vbl_request_type(xf86_crtc);
+    vbl.request.sequence = 1;
+    vbl.request.signal = (unsigned long)drm_queue_entry;
+    if (drmWaitVBlank(RADEONPTR(scrn)->dri2.drm_fd, &vbl)) {
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		   "drmWaitVBlank failed for scanout update: %s\n",
+		   strerror(errno));
+	radeon_drm_abort_entry(drm_queue_entry);
+	return;
+    }
+
+    drmmode_crtc->scanout_update_pending = TRUE;
+}
+
 static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 {
     SCREEN_PTR(arg);
@@ -318,7 +455,16 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
     (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
     pScreen->BlockHandler = RADEONBlockHandler_KMS;
 
+    if (info->shadow_primary) {
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+	int c;
+
+	for (c = 0; c < xf86_config->num_crtc; c++)
+	    radeon_scanout_update(xf86_config->crtc[c]);
+    }
+
     radeon_cs_flush_indirect(pScrn);
+
 #ifdef RADEON_PIXMAP_SHARING
     radeon_dirty_update(pScreen);
 #endif
@@ -936,11 +1082,32 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 	 "KMS Color Tiling 2D: %sabled\n", info->allowColorTiling2D ? "en" : "dis");
 
+#if USE_GLAMOR
+    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");
+    }
+#endif
+
     if (info->dri2.pKernelDRMVersion->version_minor >= 8) {
 	info->allowPageFlip = xf86ReturnOptValBool(info->Options,
 						   OPTION_PAGE_FLIP, TRUE);
-	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-		   "KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis");
+#if USE_GLAMOR
+	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
+#endif
+	{
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis");
+	}
     }
 
     info->swapBuffersWait = xf86ReturnOptValBool(info->Options,
@@ -1506,6 +1673,7 @@ void RADEONLeaveVT_KMS(VT_FUNC_ARGS_DECL)
     radeon_drop_drm_master(pScrn);
 
     xf86RotateFreeShadow(pScrn);
+    drmmode_scanout_free(pScrn);
 
     xf86_hide_cursors (pScrn);
     info->accel_state->XInited3D = FALSE;
@@ -1556,7 +1724,7 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
 	}
     }
 
-    if (info->allowColorTiling) {
+    if (info->allowColorTiling && !info->shadow_primary) {
 	if (info->ChipFamily >= CHIP_FAMILY_R600) {
 		if (info->allowColorTiling2D) {
 			tiling_flags |= RADEON_TILING_MACRO;
@@ -1659,7 +1827,10 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
 
     if (info->front_bo == NULL) {
         info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size,
-                                        base_align, RADEON_GEM_DOMAIN_VRAM, 0);
+                                        base_align,
+                                        info->shadow_primary ?
+                                        RADEON_GEM_DOMAIN_GTT :
+                                        RADEON_GEM_DOMAIN_VRAM, 0);
         if (info->r600_shadow_fb == TRUE) {
             if (radeon_bo_map(info->front_bo, 1)) {
                 ErrorF("Failed to map cursor buffer memory\n");
commit eea79472a84672ee4dc7adc4487cec6a4037048a
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Apr 1 15:51:52 2015 +0900

    glamor: Add wrappers for the X server rendering hooks
    
    They can choose between using the GPU or CPU for the operation.

diff --git a/src/Makefile.am b/src/Makefile.am
index 697c08c..a5c4bc2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -65,6 +65,7 @@ if GLAMOR
 AM_CFLAGS += @LIBGLAMOR_CFLAGS@
 radeon_drv_la_LIBADD += @LIBGLAMOR_LIBS@
 radeon_drv_la_SOURCES += \
+	 radeon_glamor_wrappers.c \
 	 radeon_glamor.c
 endif
 
diff --git a/src/radeon.h b/src/radeon.h
index 83b462b..80adc5d 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -248,6 +248,10 @@ typedef enum {
 
 struct radeon_pixmap {
 	struct radeon_surface surface;
+
+	uint_fast32_t gpu_read;
+	uint_fast32_t gpu_write;
+
 	struct radeon_bo *bo;
 
 	uint32_t tiling_flags;
@@ -467,6 +471,8 @@ typedef struct {
     Bool              RenderAccel; /* Render */
     Bool              allowColorTiling;
     Bool              allowColorTiling2D;
+    uint_fast32_t     gpu_flushed;
+    uint_fast32_t     gpu_synced;
     struct radeon_accel_state *accel_state;
     Bool              accelOn;
     Bool              use_glamor;
@@ -525,6 +531,30 @@ typedef struct {
     /* cursor size */
     int cursor_w;
     int cursor_h;
+
+#ifdef USE_GLAMOR
+    struct {
+	CreateGCProcPtr SavedCreateGC;
+	RegionPtr (*SavedCopyArea)(DrawablePtr, DrawablePtr, GCPtr, int, int,
+				   int, int, int, int);
+	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;
+#endif /* USE_GLAMOR */
 } RADEONInfoRec, *RADEONInfoPtr;
 
 /* radeon_accel.c */
diff --git a/src/radeon_glamor.h b/src/radeon_glamor.h
index 8010b4a..ea385c7 100644
--- a/src/radeon_glamor.h
+++ b/src/radeon_glamor.h
@@ -55,6 +55,7 @@ struct radeon_pixmap;
 
 Bool radeon_glamor_pre_init(ScrnInfoPtr scrn);
 Bool radeon_glamor_init(ScreenPtr screen);
+void radeon_glamor_screen_init(ScreenPtr screen);
 Bool radeon_glamor_create_screen_resources(ScreenPtr screen);
 void radeon_glamor_free_screen(int scrnIndex, int flags);
 
diff --git a/src/radeon_glamor_wrappers.c b/src/radeon_glamor_wrappers.c
new file mode 100644
index 0000000..db2e85f
--- /dev/null
+++ b/src/radeon_glamor_wrappers.c
@@ -0,0 +1,985 @@
+/*
+ * 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 "radeon.h"
+#include "radeon_glamor.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
+radeon_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
+radeon_glamor_prepare_access_cpu(ScrnInfoPtr scrn, RADEONInfoPtr info,
+				 PixmapPtr pixmap, struct radeon_pixmap *priv,
+				 Bool need_sync)
+{
+	struct radeon_bo *bo = priv->bo;
+	int ret;
+
+	/* When falling back to swrast, flush all pending operations */
+	if (need_sync) {
+		glamor_block_handler(scrn->pScreen);
+		info->gpu_flushed++;
+	}
+
+	if (!pixmap->devPrivate.ptr) {
+		ret = radeon_bo_map(bo, 1);
+		if (ret) {
+			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+				   "%s: bo map (tiling_flags %d) failed: %s\n",
+				   __FUNCTION__,
+				   priv->tiling_flags,
+				   strerror(-ret));
+			return FALSE;
+		}
+
+		pixmap->devPrivate.ptr = bo->ptr;
+		info->gpu_synced = info->gpu_flushed;
+	} else if (need_sync) {
+		radeon_bo_wait(bo);
+		info->gpu_synced = info->gpu_flushed;
+	}
+
+	return TRUE;
+}
+
+static Bool
+radeon_glamor_prepare_access_cpu_ro(ScrnInfoPtr scrn, PixmapPtr pixmap,
+				    struct radeon_pixmap *priv)
+{
+	RADEONInfoPtr info;
+	Bool need_sync;
+
+	if (!priv)
+		return TRUE;
+
+	info = RADEONPTR(scrn);
+	need_sync = radeon_glamor_gpu_pending(info->gpu_synced, priv->gpu_read);
+	return radeon_glamor_prepare_access_cpu(scrn, RADEONPTR(scrn), pixmap,
+						priv, need_sync);
+}
+
+static Bool
+radeon_glamor_prepare_access_cpu_rw(ScrnInfoPtr scrn, PixmapPtr pixmap,
+				    struct radeon_pixmap *priv)
+{
+	RADEONInfoPtr info;
+	uint_fast32_t gpu_synced;
+	Bool need_sync;
+
+	if (!priv)
+		return TRUE;
+
+	info = RADEONPTR(scrn);
+	gpu_synced = info->gpu_synced;
+	need_sync = radeon_glamor_gpu_pending(gpu_synced, priv->gpu_write) |
+		radeon_glamor_gpu_pending(gpu_synced, priv->gpu_read);
+	return radeon_glamor_prepare_access_cpu(scrn, info, pixmap, priv,
+						need_sync);
+}
+
+static void
+radeon_glamor_finish_access_cpu(PixmapPtr pixmap)
+{
+	/* Nothing to do */
+}
+
+/*
+ * Pixmap GPU access wrappers
+ */
+
+static Bool
+radeon_glamor_prepare_access_gpu(struct radeon_pixmap *priv)
+{
+	return priv != NULL;
+}
+
+static void
+radeon_glamor_finish_access_gpu_ro(RADEONInfoPtr info,
+				   struct radeon_pixmap *priv)
+{
+	priv->gpu_read = info->gpu_flushed + 1;
+}
+
+static void
+radeon_glamor_finish_access_gpu_rw(RADEONInfoPtr info,
+				   struct radeon_pixmap *priv)
+{
+	priv->gpu_write = priv->gpu_read = info->gpu_flushed + 1;
+}
+
+/*
+ * GC CPU access wrappers
+ */
+
+static Bool
+radeon_glamor_prepare_access_gc(ScrnInfoPtr scrn, GCPtr pGC)
+{
+	struct radeon_pixmap *priv;
+
+	if (pGC->stipple) {
+		priv = radeon_get_pixmap_private(pGC->stipple);
+		if (!radeon_glamor_prepare_access_cpu_ro(scrn, pGC->stipple, priv))
+			return FALSE;
+	}
+	if (pGC->fillStyle == FillTiled) {
+		priv = radeon_get_pixmap_private(pGC->tile.pixmap);
+		if (!radeon_glamor_prepare_access_cpu_ro(scrn, pGC->tile.pixmap,
+						      priv)) {
+			if (pGC->stipple)
+				radeon_glamor_finish_access_cpu(pGC->stipple);
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+static void
+radeon_glamor_finish_access_gc(GCPtr pGC)
+{
+	if (pGC->fillStyle == FillTiled)
+		radeon_glamor_finish_access_cpu(pGC->tile.pixmap);
+	if (pGC->stipple)
+		radeon_glamor_finish_access_cpu(pGC->stipple);
+}
+
+/*
+ * Picture CPU access wrappers
+ */
+
+static void
+radeon_glamor_picture_finish_access_cpu(PicturePtr picture)
+{
+	/* Nothing to do */
+}
+
+static Bool
+radeon_glamor_picture_prepare_access_cpu_ro(ScrnInfoPtr scrn,
+					    PicturePtr picture)
+{
+	PixmapPtr pixmap;
+	struct radeon_pixmap *priv;
+
+	if (picture->pDrawable == NULL)
+		return TRUE;
+
+	pixmap = get_drawable_pixmap(picture->pDrawable);
+	priv = radeon_get_pixmap_private(pixmap);
+	if (!radeon_glamor_prepare_access_cpu_ro(scrn, pixmap, priv))
+		return FALSE;
+
+	if (picture->alphaMap) {
+		pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable);
+		priv = radeon_get_pixmap_private(pixmap);
+		if (!radeon_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) {
+			radeon_glamor_picture_finish_access_cpu(picture);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static Bool
+radeon_glamor_picture_prepare_access_cpu_rw(ScrnInfoPtr scrn,
+					    PicturePtr picture)
+{
+	PixmapPtr pixmap;
+	struct radeon_pixmap *priv;
+
+	pixmap = get_drawable_pixmap(picture->pDrawable);
+	priv = radeon_get_pixmap_private(pixmap);
+	if (!radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv))
+		return FALSE;
+
+	if (picture->alphaMap) {
+		pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable);
+		priv = radeon_get_pixmap_private(pixmap);
+		if (!radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+			radeon_glamor_picture_finish_access_cpu(picture);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+/*
+ * GC rendering wrappers
+ */
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		if (radeon_glamor_prepare_access_gc(scrn, pGC)) {
+			fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth,
+				    fSorted);
+			radeon_glamor_finish_access_gc(pGC);
+		}
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+			   bits);
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static RegionPtr
+radeon_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 radeon_pixmap *dst_priv = radeon_get_pixmap_private(dst_pix);
+	RegionPtr ret = NULL;
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, dst_pix, dst_priv)) {
+		PixmapPtr src_pix = get_drawable_pixmap(pSrc);
+		struct radeon_pixmap *src_priv = radeon_get_pixmap_private(src_pix);
+		if (radeon_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) {
+			ret =
+			    fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
+					dsty, bitPlane);
+			radeon_glamor_finish_access_cpu(src_pix);
+		}
+		radeon_glamor_finish_access_cpu(dst_pix);
+	}
+	return ret;
+}
+
+static RegionPtr
+radeon_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 radeon_pixmap *src_priv = radeon_get_pixmap_private(src_pix);
+	RegionPtr ret = NULL;
+
+	if (radeon_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) {
+		ret = fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h,
+				  dstx,	dsty, bitPlane);
+		radeon_glamor_finish_access_cpu(src_pix);
+	}
+	return ret;
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		fbPolyPoint(pDrawable, pGC, mode, npt, pptInit);
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+		if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+			if (radeon_glamor_prepare_access_gc(scrn, pGC)) {
+				fbPolyLine(pDrawable, pGC, mode, npt, ppt);
+				radeon_glamor_finish_access_gc(pGC);
+			}
+			radeon_glamor_finish_access_cpu(pixmap);
+		}
+		return;
+	}
+	/* fb calls mi functions in the lineWidth != 0 case. */
+	fbPolyLine(pDrawable, pGC, mode, npt, ppt);
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+		if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+			if (radeon_glamor_prepare_access_gc(scrn, pGC)) {
+				fbPolySegment(pDrawable, pGC, nsegInit,
+					      pSegInit);
+				radeon_glamor_finish_access_gc(pGC);
+			}
+			radeon_glamor_finish_access_cpu(pixmap);
+		}
+		return;
+	}
+	/* fb calls mi functions in the lineWidth != 0 case. */
+	fbPolySegment(pDrawable, pGC, nsegInit, pSegInit);
+}
+
+static void
+radeon_glamor_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
+			     int nrect, xRectangle *prect)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(pDrawable);
+	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		if (radeon_glamor_prepare_access_gc(scrn, pGC)) {
+			fbPolyFillRect(pDrawable, pGC, nrect, prect);
+			radeon_glamor_finish_access_gc(pGC);
+		}
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		if (radeon_glamor_prepare_access_gc(scrn, pGC)) {
+			fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
+					pglyphBase);
+			radeon_glamor_finish_access_gc(pGC);
+		}
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		if (radeon_glamor_prepare_access_gc(scrn, pGC)) {
+			fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
+				       pglyphBase);
+			radeon_glamor_finish_access_gc(pGC);
+		}
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		priv = radeon_get_pixmap_private(pBitmap);
+		if (radeon_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) {
+			if (radeon_glamor_prepare_access_gc(scrn, pGC)) {
+				fbPushPixels(pGC, pBitmap, pDrawable, w, h, x,
+					     y);
+				radeon_glamor_finish_access_gc(pGC);
+			}
+			radeon_glamor_finish_access_cpu(pBitmap);
+		}
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+radeon_glamor_push_pixels_nodstbo(GCPtr pGC, PixmapPtr pBitmap,
+				  DrawablePtr pDrawable, int w, int h,
+				  int x, int y)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen);
+	struct radeon_pixmap *priv = radeon_get_pixmap_private(pBitmap);
+
+	if (radeon_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) {
+		fbPushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
+		radeon_glamor_finish_access_cpu(pBitmap);
+	}
+}
+
+static RegionPtr
+radeon_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);
+	RADEONInfoPtr info = RADEONPTR(scrn);
+	PixmapPtr src_pixmap = get_drawable_pixmap(pSrcDrawable);
+	PixmapPtr dst_pixmap = get_drawable_pixmap(pDstDrawable);
+	struct radeon_pixmap *src_priv = radeon_get_pixmap_private(src_pixmap);
+	struct radeon_pixmap *dst_priv = radeon_get_pixmap_private(dst_pixmap);
+	RegionPtr ret = NULL;
+
+	if (info->accel_state->force || (src_priv && !src_priv->bo) ||
+	    (dst_priv && !dst_priv->bo)) {
+		if (!radeon_glamor_prepare_access_gpu(dst_priv))
+			goto fallback;
+		if (src_priv != dst_priv &&
+		    !radeon_glamor_prepare_access_gpu(src_priv))
+			goto fallback;
+
+		ret = info->glamor.SavedCopyArea(pSrcDrawable, pDstDrawable,
+						 pGC, srcx, srcy,
+						 width, height, dstx, dsty);
+		radeon_glamor_finish_access_gpu_rw(info, dst_priv);
+		if (src_priv != dst_priv)
+			radeon_glamor_finish_access_gpu_ro(info, src_priv);
+
+		return ret;
+	}
+
+fallback:
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, dst_pixmap, dst_priv)) {
+		if (pSrcDrawable == pDstDrawable ||
+			radeon_glamor_prepare_access_cpu_ro(scrn, src_pixmap,
+							    src_priv)) {
+			ret = fbCopyArea(pSrcDrawable, pDstDrawable, pGC,
+					 srcx, srcy, width, height, dstx, dsty);
+			if (pSrcDrawable != pDstDrawable)
+				radeon_glamor_finish_access_cpu(src_pixmap);
+		}
+		radeon_glamor_finish_access_cpu(dst_pixmap);
+	}
+
+	return ret;
+}
+
+static RegionPtr
+radeon_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 radeon_pixmap *src_priv;
+	RegionPtr ret = NULL;
+
+	if (src_pixmap != dst_pixmap) {
+		src_priv = radeon_get_pixmap_private(src_pixmap);
+
+		if (!radeon_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)
+		radeon_glamor_finish_access_cpu(src_pixmap);
+
+	return ret;
+}
+
+static const GCOps radeon_glamor_ops = {
+	radeon_glamor_fill_spans,
+	radeon_glamor_set_spans,
+	radeon_glamor_put_image,
+	radeon_glamor_copy_area,
+	radeon_glamor_copy_plane,
+	radeon_glamor_poly_point,
+	radeon_glamor_poly_lines,
+	radeon_glamor_poly_segment,
+	miPolyRectangle,
+	miPolyArc,
+	miFillPolygon,
+	radeon_glamor_poly_fill_rect,
+	miPolyFillArc,
+	miPolyText8,
+	miPolyText16,
+	miImageText8,
+	miImageText16,
+	radeon_glamor_image_glyph_blt,
+	radeon_glamor_poly_glyph_blt,
+	radeon_glamor_push_pixels,
+};
+
+static GCOps radeon_glamor_nodstbo_ops;
+
+/**
+ * radeon_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
+radeon_glamor_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pGC->pScreen);
+	RADEONInfoPtr info = RADEONPTR(scrn);
+
+	glamor_validate_gc(pGC, changes, pDrawable);
+	info->glamor.SavedCopyArea = pGC->ops->CopyArea;
+
+	if (radeon_get_pixmap_private(get_drawable_pixmap(pDrawable)) ||
+	    (pGC->stipple && radeon_get_pixmap_private(pGC->stipple)) ||
+	    (pGC->fillStyle == FillTiled &&
+	     radeon_get_pixmap_private(pGC->tile.pixmap)))
+		pGC->ops = (GCOps *)&radeon_glamor_ops;
+	else
+		pGC->ops = &radeon_glamor_nodstbo_ops;
+}
+
+static GCFuncs glamorGCFuncs = {
+	radeon_glamor_validate_gc,
+	miChangeGC,
+	miCopyGC,
+	miDestroyGC,
+	miChangeClip,
+	miDestroyClip,
+	miCopyClip
+};
+
+/**
+ * radeon_glamor_create_gc makes a new GC and hooks up its funcs handler, so that
+ * radeon_glamor_validate_gc() will get called.
+ */
+static int
+radeon_glamor_create_gc(GCPtr pGC)
+{
+	static Bool nodstbo_ops_initialized;
+
+	if (!fbCreateGC(pGC))
+		return FALSE;
+
+	if (!nodstbo_ops_initialized) {
+		radeon_glamor_nodstbo_ops = radeon_glamor_ops;
+
+		radeon_glamor_nodstbo_ops.FillSpans = pGC->ops->FillSpans;
+		radeon_glamor_nodstbo_ops.SetSpans = pGC->ops->SetSpans;
+		radeon_glamor_nodstbo_ops.PutImage = pGC->ops->PutImage;
+		radeon_glamor_nodstbo_ops.CopyArea = radeon_glamor_copy_area_nodstbo;
+		radeon_glamor_nodstbo_ops.CopyPlane = radeon_glamor_copy_plane_nodstbo;
+		radeon_glamor_nodstbo_ops.PolyPoint = pGC->ops->PolyPoint;
+		radeon_glamor_nodstbo_ops.Polylines = pGC->ops->Polylines;
+		radeon_glamor_nodstbo_ops.PolySegment = pGC->ops->PolySegment;
+		radeon_glamor_nodstbo_ops.PolyFillRect = pGC->ops->PolyFillRect;
+		radeon_glamor_nodstbo_ops.ImageGlyphBlt = pGC->ops->ImageGlyphBlt;
+		radeon_glamor_nodstbo_ops.PolyGlyphBlt = pGC->ops->PolyGlyphBlt;
+		radeon_glamor_nodstbo_ops.PushPixels = radeon_glamor_push_pixels_nodstbo;
+
+		nodstbo_ops_initialized = TRUE;
+	}
+
+	pGC->funcs = &glamorGCFuncs;
+
+	return TRUE;
+}
+
+/*
+ * Screen rendering wrappers
+ */
+
+static RegionPtr
+radeon_glamor_bitmap_to_region(PixmapPtr pPix)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pPix->drawable.pScreen);
+	struct radeon_pixmap *priv = radeon_get_pixmap_private(pPix);
+	RegionPtr ret;
+
+	if (!radeon_glamor_prepare_access_cpu_ro(scrn, pPix, priv))
+		return NULL;
+	ret = fbPixmapToRegion(pPix);
+	radeon_glamor_finish_access_cpu(pPix);
+	return ret;
+}
+
+static void
+radeon_glamor_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg,
+			  RegionPtr prgnSrc)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pWin->drawable.pScreen);
+	PixmapPtr pixmap = get_drawable_pixmap(&pWin->drawable);
+	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) {
+		fbCopyWindow(pWin, ptOldOrg, prgnSrc);
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) {
+		fbGetImage(pDrawable, x, y, w, h, format, planeMask, d);
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+static void
+radeon_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 radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+
+	if (radeon_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) {
+		fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+		radeon_glamor_finish_access_cpu(pixmap);
+	}
+}
+
+/*
+ * Picture screen rendering wrappers
+ */
+
+#ifdef RENDER
+
+static void
+radeon_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);
+	RADEONInfoPtr info;
+	PixmapPtr pixmap;
+	struct radeon_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 != RADEON_CREATE_PIXMAP_SCANOUT)
+		goto fallback;
+
+	dst_priv = radeon_get_pixmap_private(pixmap);
+	if (!radeon_glamor_prepare_access_gpu(dst_priv))
+		goto fallback;
+
+	info = RADEONPTR(scrn);
+	if (!pSrc->pDrawable ||
+	    ((pixmap = get_drawable_pixmap(pSrc->pDrawable)) &&
+	     (src_priv = radeon_get_pixmap_private(pixmap)) &&
+	     radeon_glamor_prepare_access_gpu(src_priv))) {
+		if (!pMask || !pMask->pDrawable ||
+		    ((pixmap = get_drawable_pixmap(pMask->pDrawable)) &&
+		     (mask_priv = radeon_get_pixmap_private(pixmap)) &&
+		     radeon_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)
+				radeon_glamor_finish_access_gpu_ro(info, mask_priv);
+		}
+
+		if (src_priv)
+			radeon_glamor_finish_access_gpu_ro(info, src_priv);
+	}
+	radeon_glamor_finish_access_gpu_rw(info, dst_priv);
+
+	if (gpu_done)
+		return;
+
+fallback:
+	if (radeon_glamor_picture_prepare_access_cpu_rw(scrn, pDst)) {
+		if (radeon_glamor_picture_prepare_access_cpu_ro(scrn, pSrc)) {
+			if (!pMask ||
+			    radeon_glamor_picture_prepare_access_cpu_ro(scrn, pMask)) {
+				fbComposite(op, pSrc, pMask, pDst,
+					    xSrc, ySrc,
+					    xMask, yMask,
+					    xDst, yDst,
+					    width, height);
+				if (pMask)
+					radeon_glamor_picture_finish_access_cpu(pMask);
+			}
+			radeon_glamor_picture_finish_access_cpu(pSrc);
+		}
+		radeon_glamor_picture_finish_access_cpu(pDst);
+	}
+}
+
+static void
+radeon_glamor_add_traps(PicturePtr pPicture,
+		    INT16 x_off, INT16 y_off, int ntrap, xTrap *traps)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pPicture->pDrawable->pScreen);
+
+	if (radeon_glamor_picture_prepare_access_cpu_rw(scrn, pPicture)) {
+		fbAddTraps(pPicture, x_off, y_off, ntrap, traps);
+		radeon_glamor_picture_finish_access_cpu(pPicture);
+	}
+}
+
+static void
+radeon_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 (radeon_glamor_picture_prepare_access_cpu_rw(scrn, dst)) {
+		if (radeon_glamor_picture_prepare_access_cpu_ro(scrn, src)) {
+			RADEONInfoPtr info = RADEONPTR(scrn);
+
+			info->glamor.SavedGlyphs(op, src, dst, maskFormat, xSrc,
+						 ySrc, nlist, list, glyphs);
+			radeon_glamor_picture_finish_access_cpu(src);
+		}
+		radeon_glamor_picture_finish_access_cpu(dst);
+	}
+}
+
+static void
+radeon_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 (radeon_glamor_picture_prepare_access_cpu_rw(scrn, dst)) {
+		if (radeon_glamor_picture_prepare_access_cpu_ro(scrn, src)) {
+			RADEONInfoPtr info = RADEONPTR(scrn);
+
+			info->glamor.SavedTrapezoids(op, src, dst, maskFormat,
+						     xSrc, ySrc, ntrap, traps);
+			radeon_glamor_picture_finish_access_cpu(src);
+		}
+		radeon_glamor_picture_finish_access_cpu(dst);
+	}
+}
+
+static void
+radeon_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 (radeon_glamor_picture_prepare_access_cpu_rw(scrn, dst)) {
+		if (radeon_glamor_picture_prepare_access_cpu_ro(scrn, src)) {
+			RADEONInfoPtr info = RADEONPTR(scrn);
+
+			info->glamor.SavedTriangles(op, src, dst, maskFormat,
+						    xSrc, ySrc, ntri, tri);
+			radeon_glamor_picture_finish_access_cpu(src);
+		}
+		radeon_glamor_picture_finish_access_cpu(dst);
+	}
+}
+
+#endif /* RENDER */
+
+
+/**
+ * radeon_glamor_close_screen() unwraps its wrapped screen functions and tears
+ * down our screen private, before calling down to the next CloseScreen.
+ */
+static Bool
+radeon_glamor_close_screen(CLOSE_SCREEN_ARGS_DECL)
+{
+	RADEONInfoPtr info = RADEONPTR(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
+radeon_glamor_screen_init(ScreenPtr screen)
+{
+	RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen));
+
+	/*
+	 * Replace various fb screen functions
+	 */
+	info->glamor.SavedCloseScreen = screen->CloseScreen;
+	screen->CloseScreen = radeon_glamor_close_screen;
+
+	info->glamor.SavedCreateGC = screen->CreateGC;
+	screen->CreateGC = radeon_glamor_create_gc;
+
+	info->glamor.SavedGetImage = screen->GetImage;
+	screen->GetImage = radeon_glamor_get_image;
+
+	info->glamor.SavedGetSpans = screen->GetSpans;
+	screen->GetSpans = radeon_glamor_get_spans;
+
+	info->glamor.SavedCreatePixmap = screen->CreatePixmap;
+	info->glamor.SavedDestroyPixmap = screen->DestroyPixmap;
+
+	info->glamor.SavedCopyWindow = screen->CopyWindow;
+	screen->CopyWindow = radeon_glamor_copy_window;
+
+	info->glamor.SavedBitmapToRegion = screen->BitmapToRegion;
+	screen->BitmapToRegion = radeon_glamor_bitmap_to_region;
+
+#ifdef RENDER
+	{
+		PictureScreenPtr ps = GetPictureScreenIfSet(screen);
+		if (ps) {
+			info->glamor.SavedComposite = ps->Composite;
+			ps->Composite = radeon_glamor_composite;
+
+			info->glamor.SavedUnrealizeGlyph = ps->UnrealizeGlyph;
+
+			ps->Glyphs = radeon_glamor_glyphs;
+			ps->Triangles = radeon_glamor_triangles;
+			ps->Trapezoids = radeon_glamor_trapezoids;
+
+			info->glamor.SavedAddTraps = ps->AddTraps;
+			ps->AddTraps = radeon_glamor_add_traps;
+		}
+	}
+#endif
+}
+
+#endif /* USE_GLAMOR */
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 0722f0d..3f723d5 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -91,6 +91,7 @@ void radeon_cs_flush_indirect(ScrnInfoPtr pScrn)
 #ifdef USE_GLAMOR
     if (info->use_glamor) {
 	glamor_block_handler(pScrn->pScreen);
+	info->gpu_flushed++;
 	return;
     }
 #endif
commit 051d46382656ffc3e6cac1aab3aee7efdf5b623a
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Mar 19 17:34:27 2015 +0900

    glamor: Add radeon_pixmap parameter to radeon_glamor_create_textured_pixmap

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index e68f17e..d8d3ca3 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -149,7 +149,8 @@ static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
 		}
 	}
 
-	if (!radeon_glamor_create_textured_pixmap(pixmap)) {
+	if (!radeon_glamor_create_textured_pixmap(pixmap,
+						  radeon_get_pixmap_private(pixmap))) {
 		pScreen->DestroyPixmap(pixmap);
 	  	return NULL;
 	}
diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c
index 46148ad..74d9584 100644
--- a/src/radeon_glamor.c
+++ b/src/radeon_glamor.c
@@ -151,23 +151,19 @@ radeon_glamor_pre_init(ScrnInfoPtr scrn)
 }
 
 Bool
-radeon_glamor_create_textured_pixmap(PixmapPtr pixmap)
+radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_pixmap *priv)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
 	RADEONInfoPtr info = RADEONPTR(scrn);
-	struct radeon_pixmap *priv;
 
 	if ((info->use_glamor) == 0)
 		return TRUE;
 
-	priv = radeon_get_pixmap_private(pixmap);
 	if (!priv->stride)
 		priv->stride = pixmap->devKind;
-	if (glamor_egl_create_textured_pixmap(pixmap, priv->bo->handle,
-					      priv->stride))
-		return TRUE;
-	else
-		return FALSE;
+
+	return glamor_egl_create_textured_pixmap(pixmap, priv->bo->handle,
+						 priv->stride);
 }
 
 #ifndef CREATE_PIXMAP_USAGE_SHARED
@@ -222,7 +218,7 @@ radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
 
 		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, priv->stride, NULL);
 
-		if (!radeon_glamor_create_textured_pixmap(pixmap))
+		if (!radeon_glamor_create_textured_pixmap(pixmap, priv))
 			goto fallback_glamor;
 	}
 
@@ -298,7 +294,7 @@ radeon_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle)
 	priv->stride = pixmap->devKind;
 	priv->surface = surface;
 
-	if (!radeon_glamor_create_textured_pixmap(pixmap)) {
+	if (!radeon_glamor_create_textured_pixmap(pixmap, priv)) {
 		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
 			   "Failed to get PRIME drawable for glamor pixmap.\n");
 		return FALSE;
diff --git a/src/radeon_glamor.h b/src/radeon_glamor.h
index e766bcc..8010b4a 100644
--- a/src/radeon_glamor.h
+++ b/src/radeon_glamor.h
@@ -51,12 +51,14 @@
 #define GLAMOR_USE_PICTURE_SCREEN 0
 #endif
 
+struct radeon_pixmap;
+
 Bool radeon_glamor_pre_init(ScrnInfoPtr scrn);
 Bool radeon_glamor_init(ScreenPtr screen);
 Bool radeon_glamor_create_screen_resources(ScreenPtr screen);
 void radeon_glamor_free_screen(int scrnIndex, int flags);
 
-Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap);
+Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_pixmap *priv);
 void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst);
 
 XF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt);
@@ -68,7 +70,7 @@ static inline Bool radeon_glamor_init(ScreenPtr screen) { return FALSE; }
 static inline Bool radeon_glamor_create_screen_resources(ScreenPtr screen) { return FALSE; }
 static inline void radeon_glamor_free_screen(int scrnIndex, int flags) { }
 
-static inline Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap) { return TRUE; }
+static inline Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_pixmap *priv) { return TRUE; }
 
 static inline void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst) {}
 
commit 2fa021f77372ca93375a3d13a0c43a9089674899
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Mar 19 17:38:47 2015 +0900

    glamor: Remove unused function radeon_glamor_pixmap_is_offscreen

diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c
index e3633ce..46148ad 100644
--- a/src/radeon_glamor.c
+++ b/src/radeon_glamor.c
@@ -170,12 +170,6 @@ radeon_glamor_create_textured_pixmap(PixmapPtr pixmap)
 		return FALSE;
 }
 
-Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap)
-{
-	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
-	return priv && priv->bo;
-}
-
 #ifndef CREATE_PIXMAP_USAGE_SHARED
 #define CREATE_PIXMAP_USAGE_SHARED RADEON_CREATE_PIXMAP_DRI2
 #endif
diff --git a/src/radeon_glamor.h b/src/radeon_glamor.h
index a504acb..e766bcc 100644
--- a/src/radeon_glamor.h
+++ b/src/radeon_glamor.h
@@ -59,8 +59,6 @@ void radeon_glamor_free_screen(int scrnIndex, int flags);
 Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap);
 void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst);
 
-Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap);
-
 XF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt);
 
 #else
@@ -74,8 +72,6 @@ static inline Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap) { retu
 
 static inline void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst) {}
 
-static inline Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap) { return FALSE; }
-
 static inline struct radeon_pixmap *radeon_get_pixmap_private(PixmapPtr pixmap) { return NULL; }
 
 static inline XF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt) { return NULL; }
commit e96349ba6281fd18b8bf9c76629128276b065e6c
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Apr 1 16:04:13 2015 +0900

    Add RADEON_CREATE_PIXMAP_SCANOUT flag
    
    It means that the pixmap is used for scanout exclusively.

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index e8ae58d..e68f17e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -98,7 +98,8 @@ static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
 	PixmapPtr pixmap;
 	struct radeon_surface *surface;
 
-	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
+	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
+					  RADEON_CREATE_PIXMAP_SCANOUT);
 	if (!pixmap)
 		return NULL;
 
diff --git a/src/radeon.h b/src/radeon.h
index 00d0495..83b462b 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -838,6 +838,7 @@ static __inline__ void RADEON_SYNC(RADEONInfoPtr info, ScrnInfoPtr pScrn)
 }
 
 enum {
+    RADEON_CREATE_PIXMAP_SCANOUT		= 0x02000000,
     RADEON_CREATE_PIXMAP_DRI2			= 0x04000000,
     RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE	= 0x08000000,
     RADEON_CREATE_PIXMAP_TILING_MACRO		= 0x10000000,
commit 9be7dd382e86d2b804de81d4e2af7431b2e16843
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Apr 1 12:40:16 2015 +0900

    Split out struct drmmode_scanout for rotation shadow buffer information
    
    Will be used for other kinds of dedicated scanout buffers as well.

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index db7ef95..e8ae58d 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -468,6 +468,98 @@ fallback:
 	radeon_bo_unmap(info->front_bo);
 }
 
+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;
+		radeon_bo_unmap(scanout->bo);
+		radeon_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;
+	RADEONInfoPtr info = RADEONPTR(pScrn);
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+	int size;
+	int ret;
+	unsigned long rotate_pitch;
+	int base_align;
+
+	/* rotation requires acceleration */
+	if (info->r600_shadow_fb) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "Rotation requires acceleration!\n");
+		return NULL;
+	}
+
+	rotate_pitch =
+		RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0))
+		* drmmode->cpp;
+	height = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, 0));
+	base_align = drmmode_get_base_align(pScrn, drmmode->cpp, 0);
+	size = RADEON_ALIGN(rotate_pitch * height, RADEON_GPU_PAGE_SIZE);
+
+	scanout->bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align,
+				     RADEON_GEM_DOMAIN_VRAM, 0);
+	if (scanout->bo == NULL)
+		return NULL;
+
+	radeon_bo_map(scanout->bo, 1);
+
+	ret = drmModeAddFB(drmmode->fd, width, height, pScrn->depth,
+			   pScrn->bitsPerPixel, rotate_pitch,
+			   scanout->bo->handle,
+			   &scanout->fb_id);
+	if (ret)
+		ErrorF("failed to add scanout fb\n");
+
+	return scanout->bo->ptr;
+}
+
+static PixmapPtr
+drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
+			    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 (!data)
+		data = drmmode_crtc_scanout_allocate(crtc, scanout, width, height);
+
+	rotate_pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0))
+		* drmmode->cpp;
+
+	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
+						 width, height,
+						 pScrn->depth,
+						 pScrn->bitsPerPixel,
+						 rotate_pitch,
+						 0, scanout->bo, NULL);
+	if (scanout->pixmap == NULL)
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "Couldn't allocate scanout pixmap for CRTC\n");
+
+	return scanout->pixmap;
+}
+
 static Bool
 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		     Rotation rotation, int x, int y)
@@ -564,8 +656,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 = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
@@ -687,73 +779,19 @@ drmmode_show_cursor (xf86CrtcPtr crtc)
 static void *
 drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
 {
-	ScrnInfoPtr pScrn = crtc->scrn;
-	RADEONInfoPtr info = RADEONPTR(pScrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-	drmmode_ptr drmmode = drmmode_crtc->drmmode;
-	int size;
-	struct radeon_bo *rotate_bo;
-	int ret;
-	unsigned long rotate_pitch;
-	int base_align;
-
-	/* rotation requires acceleration */
-	if (info->r600_shadow_fb) {
-		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-			   "Rotation requires acceleration!\n");
-		return NULL;
-	}
-
-	rotate_pitch =
-		RADEON_ALIGN(width, drmmode_get_pitch_align(crtc->scrn, drmmode->cpp, 0)) * drmmode->cpp;
-	height = RADEON_ALIGN(height, drmmode_get_height_align(crtc->scrn, 0));
-	base_align = drmmode_get_base_align(crtc->scrn, drmmode->cpp, 0);
-	size = RADEON_ALIGN(rotate_pitch * height, RADEON_GPU_PAGE_SIZE);
-
-	rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_VRAM, 0);
-	if (rotate_bo == NULL)
-		return NULL;
-
-	radeon_bo_map(rotate_bo, 1);
-
-	ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
-			   crtc->scrn->bitsPerPixel, rotate_pitch,
-			   rotate_bo->handle,
-			   &drmmode_crtc->rotate_fb_id);
-	if (ret) {
-		ErrorF("failed to add rotate fb\n");
-	}
 
-	drmmode_crtc->rotate_bo = rotate_bo;
-	return drmmode_crtc->rotate_bo->ptr;
+	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;
-	drmmode_ptr drmmode = drmmode_crtc->drmmode;
-	unsigned long rotate_pitch;
-	PixmapPtr rotate_pixmap;
-
-	if (!data)
-		data = drmmode_crtc_shadow_allocate (crtc, width, height);
-
-	rotate_pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0)) * drmmode->cpp;
-
-	rotate_pixmap = drmmode_create_bo_pixmap(pScrn,
-						 width, height,
-						 pScrn->depth,
-						 pScrn->bitsPerPixel,
-						 rotate_pitch,
-						 0, drmmode_crtc->rotate_bo, NULL);
-	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
@@ -762,17 +800,7 @@ drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *dat
 	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;
-		radeon_bo_unmap(drmmode_crtc->rotate_bo);
-		radeon_bo_unref(drmmode_crtc->rotate_bo);
-		drmmode_crtc->rotate_bo = NULL;
-	}
-
+	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
 }
 
 static void
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 245588c..6607896 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -72,13 +72,18 @@ typedef struct {
   Bool dispatch_me;
 } drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr;
 
+struct drmmode_scanout {
+    struct radeon_bo *bo;
+    PixmapPtr pixmap;
+    unsigned fb_id;
+};
+
 typedef struct {
     drmmode_ptr drmmode;
     drmModeCrtcPtr mode_crtc;
     int hw_id;
     struct radeon_bo *cursor_bo;
-    struct radeon_bo *rotate_bo;
-    unsigned rotate_fb_id;
+    struct drmmode_scanout rotate;
     int dpms_mode;
     CARD64 dpms_last_ust;
     uint32_t dpms_last_seq;
diff --git a/src/radeon_present.c b/src/radeon_present.c
index 52ca03e..5b1d5ab 100644
--- a/src/radeon_present.c
+++ b/src/radeon_present.c
@@ -263,7 +263,7 @@ radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
 	drmmode_crtc_private_ptr drmmode_crtc = get_drmmode_crtc(scrn, crtc);
 
 	if (!drmmode_crtc ||
-	    drmmode_crtc->rotate_bo != NULL ||
+	    drmmode_crtc->rotate.bo != NULL ||
 	    drmmode_crtc->dpms_mode != DPMSModeOn)
 	    return FALSE;
     }
commit c32b0530302739f6512755bccf281c2300617376
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Mar 19 17:46:48 2015 +0900

    Rename scanout_pixmap_x field to prime_pixmap_x
    
    To avoid confusion with upcoming changes.

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index e81c6d4..db7ef95 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -560,7 +560,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		fb_id = drmmode->fb_id;
 #ifdef RADEON_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
@@ -799,7 +799,7 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
 	if (!ppix) {
 		if (crtc->randr_crtc->scanout_pixmap)
 			PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix);
-		drmmode_crtc->scanout_pixmap_x = 0;
+		drmmode_crtc->prime_pixmap_x = 0;
 		return TRUE;
 	}
 
@@ -838,7 +838,7 @@ 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 c6c076c..245588c 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -85,7 +85,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