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

Michel Dänzer daenzer at kemper.freedesktop.org
Wed Jul 11 04:45:37 PDT 2012


 configure.ac                      |   14 
 man/radeon.man                    |   45 
 src/Makefile.am                   |   14 
 src/ati_pciids_gen.h              |   39 
 src/drmmode_display.c             |    8 
 src/pcidb/ati_pciids.csv          |   39 
 src/radeon.h                      |  125 ++
 src/radeon_accel.c                |    7 
 src/radeon_bo_helper.c            |  177 +++
 src/radeon_bo_helper.h            |   31 
 src/radeon_chipinfo_gen.h         |   39 
 src/radeon_chipset_gen.h          |   39 
 src/radeon_dri2.c                 |  244 +++-
 src/radeon_exa.c                  |  192 ---
 src/radeon_glamor.c               |  347 +++++++
 src/radeon_glamor.h               |   98 +
 src/radeon_glamor_wrappers.c      | 1870 ++++++++++++++++++++++++++++++++++++++
 src/radeon_glamor_wrappers.h      |  179 +++
 src/radeon_kms.c                  |   44 
 src/radeon_pci_chipset_gen.h      |   39 
 src/radeon_pci_device_match_gen.h |   39 
 src/radeon_probe.h                |    3 
 src/radeon_version.h              |    1 
 23 files changed, 3333 insertions(+), 300 deletions(-)

New commits:
commit ef8a404391036d8aa814dbda2407c789b8a64b92
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Jul 5 20:14:48 2012 +0200

    Initial SI support.
    
    Defaults to shadowfb. 3D acceleration is available with glamor. 2D
    acceleration is disabled until the radeonsi driver can handle glamor's
    shaders.
    
    v2: add chip flags (Alex Deucher)
    
    Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
    Signed-off-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/man/radeon.man b/man/radeon.man
index be50314..de1f6ec 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -180,6 +180,12 @@ Radeon HD 6430/6450/6470/6490
 Radeon HD 6950/6970/6990
 .TP 12
 .B ARUBA
+.TP 12
+.B TAHITI
+.TP 12
+.B PITCAIRN
+.TP 12
+.B VERDE
 .PD
 .SH CONFIGURATION DETAILS
 Please refer to __xconfigfile__(__filemansuffix__) for general configuration
diff --git a/src/Makefile.am b/src/Makefile.am
index da94927..3ee292a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -68,6 +68,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
 
@@ -96,6 +97,7 @@ EXTRA_DIST = \
 	radeon_exa_funcs.c \
 	radeon_exa_shared.h \
 	radeon_glamor.h \
+	radeon_glamor_wrappers.h \
 	radeon.h \
 	radeon_probe.h \
 	radeon_reg.h \
diff --git a/src/ati_pciids_gen.h b/src/ati_pciids_gen.h
index b08ad88..5509120 100644
--- a/src/ati_pciids_gen.h
+++ b/src/ati_pciids_gen.h
@@ -617,3 +617,42 @@
 #define PCI_CHIP_ARUBA_99A0 0x99A0
 #define PCI_CHIP_ARUBA_99A2 0x99A2
 #define PCI_CHIP_ARUBA_99A4 0x99A4
+#define PCI_CHIP_TAHITI_6780 0x6780
+#define PCI_CHIP_TAHITI_6784 0x6784
+#define PCI_CHIP_TAHITI_6788 0x6788
+#define PCI_CHIP_TAHITI_678A 0x678A
+#define PCI_CHIP_TAHITI_6790 0x6790
+#define PCI_CHIP_TAHITI_6798 0x6798
+#define PCI_CHIP_TAHITI_6799 0x6799
+#define PCI_CHIP_TAHITI_679A 0x679A
+#define PCI_CHIP_TAHITI_679E 0x679E
+#define PCI_CHIP_TAHITI_679F 0x679F
+#define PCI_CHIP_PITCAIRN_6800 0x6800
+#define PCI_CHIP_PITCAIRN_6801 0x6801
+#define PCI_CHIP_PITCAIRN_6802 0x6802
+#define PCI_CHIP_PITCAIRN_6808 0x6808
+#define PCI_CHIP_PITCAIRN_6809 0x6809
+#define PCI_CHIP_PITCAIRN_6810 0x6810
+#define PCI_CHIP_PITCAIRN_6818 0x6818
+#define PCI_CHIP_PITCAIRN_6819 0x6819
+#define PCI_CHIP_PITCAIRN_684C 0x684C
+#define PCI_CHIP_VERDE_6820 0x6820
+#define PCI_CHIP_VERDE_6821 0x6821
+#define PCI_CHIP_VERDE_6823 0x6823
+#define PCI_CHIP_VERDE_6824 0x6824
+#define PCI_CHIP_VERDE_6825 0x6825
+#define PCI_CHIP_VERDE_6826 0x6826
+#define PCI_CHIP_VERDE_6827 0x6827
+#define PCI_CHIP_VERDE_6828 0x6828
+#define PCI_CHIP_VERDE_6829 0x6829
+#define PCI_CHIP_VERDE_682B 0x682B
+#define PCI_CHIP_VERDE_682D 0x682D
+#define PCI_CHIP_VERDE_682F 0x682F
+#define PCI_CHIP_VERDE_6830 0x6830
+#define PCI_CHIP_VERDE_6831 0x6831
+#define PCI_CHIP_VERDE_6837 0x6837
+#define PCI_CHIP_VERDE_6838 0x6838
+#define PCI_CHIP_VERDE_6839 0x6839
+#define PCI_CHIP_VERDE_683B 0x683B
+#define PCI_CHIP_VERDE_683D 0x683D
+#define PCI_CHIP_VERDE_683F 0x683F
diff --git a/src/pcidb/ati_pciids.csv b/src/pcidb/ati_pciids.csv
index 501a0f6..29ff26b 100644
--- a/src/pcidb/ati_pciids.csv
+++ b/src/pcidb/ati_pciids.csv
@@ -618,3 +618,42 @@
 "0x99A0","ARUBA_99A0","ARUBA",1,,,,,"ARUBA"
 "0x99A2","ARUBA_99A2","ARUBA",1,,,,,"ARUBA"
 "0x99A4","ARUBA_99A4","ARUBA",,,,,,"ARUBA"
+"0x6780","TAHITI_6780","TAHITI",,,,,,"TAHITI"
+"0x6784","TAHITI_6784","TAHITI",,,,,,"TAHITI"
+"0x6788","TAHITI_6788","TAHITI",,,,,,"TAHITI"
+"0x678A","TAHITI_678A","TAHITI",,,,,,"TAHITI"
+"0x6790","TAHITI_6790","TAHITI",,,,,,"TAHITI"
+"0x6798","TAHITI_6798","TAHITI",,,,,,"TAHITI"
+"0x6799","TAHITI_6799","TAHITI",,,,,,"TAHITI"
+"0x679A","TAHITI_679A","TAHITI",,,,,,"TAHITI"
+"0x679E","TAHITI_679E","TAHITI",,,,,,"TAHITI"
+"0x679F","TAHITI_679F","TAHITI",,,,,,"TAHITI"
+"0x6800","PITCAIRN_6800","PITCAIRN",1,,,,,"PITCAIRN"
+"0x6801","PITCAIRN_6801","PITCAIRN",1,,,,,"PITCAIRN"
+"0x6802","PITCAIRN_6802","PITCAIRN",1,,,,,"PITCAIRN"
+"0x6808","PITCAIRN_6808","PITCAIRN",,,,,,"PITCAIRN"
+"0x6809","PITCAIRN_6809","PITCAIRN",,,,,,"PITCAIRN"
+"0x6810","PITCAIRN_6810","PITCAIRN",,,,,,"PITCAIRN"
+"0x6818","PITCAIRN_6818","PITCAIRN",,,,,,"PITCAIRN"
+"0x6819","PITCAIRN_6819","PITCAIRN",,,,,,"PITCAIRN"
+"0x684C","PITCAIRN_684C","PITCAIRN",,,,,,"PITCAIRN"
+"0x6820","VERDE_6820","VERDE",1,,,,,"VERDE"
+"0x6821","VERDE_6821","VERDE",1,,,,,"VERDE"
+"0x6823","VERDE_6823","VERDE",1,,,,,"VERDE"
+"0x6824","VERDE_6824","VERDE",1,,,,,"VERDE"
+"0x6825","VERDE_6825","VERDE",1,,,,,"VERDE"
+"0x6826","VERDE_6826","VERDE",1,,,,,"VERDE"
+"0x6827","VERDE_6827","VERDE",1,,,,,"VERDE"
+"0x6828","VERDE_6828","VERDE",,,,,,"VERDE"
+"0x6829","VERDE_6829","VERDE",,,,,,"VERDE"
+"0x682B","VERDE_682B","VERDE",1,,,,,"VERDE"
+"0x682D","VERDE_682D","VERDE",1,,,,,"VERDE"
+"0x682F","VERDE_682F","VERDE",1,,,,,"VERDE"
+"0x6830","VERDE_6830","VERDE",1,,,,,"VERDE"
+"0x6831","VERDE_6831","VERDE",1,,,,,"VERDE"
+"0x6837","VERDE_6837","VERDE",,,,,,"VERDE"
+"0x6838","VERDE_6838","VERDE",,,,,,"VERDE"
+"0x6839","VERDE_6839","VERDE",,,,,,"VERDE"
+"0x683B","VERDE_683B","VERDE",,,,,,"VERDE"
+"0x683D","VERDE_683D","VERDE",,,,,,"VERDE"
+"0x683F","VERDE_683F","VERDE",,,,,,"VERDE"
diff --git a/src/radeon_chipinfo_gen.h b/src/radeon_chipinfo_gen.h
index c64c921..295a824 100644
--- a/src/radeon_chipinfo_gen.h
+++ b/src/radeon_chipinfo_gen.h
@@ -537,4 +537,43 @@ static RADEONCardInfo RADEONCards[] = {
  { 0x99A0, CHIP_FAMILY_ARUBA, 1, 0, 0, 0, 0 },
  { 0x99A2, CHIP_FAMILY_ARUBA, 1, 0, 0, 0, 0 },
  { 0x99A4, CHIP_FAMILY_ARUBA, 0, 0, 0, 0, 0 },
+ { 0x6780, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x6784, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x6788, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x678A, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x6790, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x6798, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x6799, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x679A, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x679E, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x679F, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 },
+ { 0x6800, CHIP_FAMILY_PITCAIRN, 1, 0, 0, 0, 0 },
+ { 0x6801, CHIP_FAMILY_PITCAIRN, 1, 0, 0, 0, 0 },
+ { 0x6802, CHIP_FAMILY_PITCAIRN, 1, 0, 0, 0, 0 },
+ { 0x6808, CHIP_FAMILY_PITCAIRN, 0, 0, 0, 0, 0 },
+ { 0x6809, CHIP_FAMILY_PITCAIRN, 0, 0, 0, 0, 0 },
+ { 0x6810, CHIP_FAMILY_PITCAIRN, 0, 0, 0, 0, 0 },
+ { 0x6818, CHIP_FAMILY_PITCAIRN, 0, 0, 0, 0, 0 },
+ { 0x6819, CHIP_FAMILY_PITCAIRN, 0, 0, 0, 0, 0 },
+ { 0x684C, CHIP_FAMILY_PITCAIRN, 0, 0, 0, 0, 0 },
+ { 0x6820, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6821, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6823, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6824, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6825, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6826, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6827, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6828, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 },
+ { 0x6829, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 },
+ { 0x682B, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x682D, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x682F, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6830, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6831, CHIP_FAMILY_VERDE, 1, 0, 0, 0, 0 },
+ { 0x6837, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 },
+ { 0x6838, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 },
+ { 0x6839, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 },
+ { 0x683B, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 },
+ { 0x683D, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 },
+ { 0x683F, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 },
 };
diff --git a/src/radeon_chipset_gen.h b/src/radeon_chipset_gen.h
index 31b31ab..8e887ac 100644
--- a/src/radeon_chipset_gen.h
+++ b/src/radeon_chipset_gen.h
@@ -537,5 +537,44 @@ SymTabRec RADEONChipsets[] = {
   { PCI_CHIP_ARUBA_99A0, "ARUBA" },
   { PCI_CHIP_ARUBA_99A2, "ARUBA" },
   { PCI_CHIP_ARUBA_99A4, "ARUBA" },
+  { PCI_CHIP_TAHITI_6780, "TAHITI" },
+  { PCI_CHIP_TAHITI_6784, "TAHITI" },
+  { PCI_CHIP_TAHITI_6788, "TAHITI" },
+  { PCI_CHIP_TAHITI_678A, "TAHITI" },
+  { PCI_CHIP_TAHITI_6790, "TAHITI" },
+  { PCI_CHIP_TAHITI_6798, "TAHITI" },
+  { PCI_CHIP_TAHITI_6799, "TAHITI" },
+  { PCI_CHIP_TAHITI_679A, "TAHITI" },
+  { PCI_CHIP_TAHITI_679E, "TAHITI" },
+  { PCI_CHIP_TAHITI_679F, "TAHITI" },
+  { PCI_CHIP_PITCAIRN_6800, "PITCAIRN" },
+  { PCI_CHIP_PITCAIRN_6801, "PITCAIRN" },
+  { PCI_CHIP_PITCAIRN_6802, "PITCAIRN" },
+  { PCI_CHIP_PITCAIRN_6808, "PITCAIRN" },
+  { PCI_CHIP_PITCAIRN_6809, "PITCAIRN" },
+  { PCI_CHIP_PITCAIRN_6810, "PITCAIRN" },
+  { PCI_CHIP_PITCAIRN_6818, "PITCAIRN" },
+  { PCI_CHIP_PITCAIRN_6819, "PITCAIRN" },
+  { PCI_CHIP_PITCAIRN_684C, "PITCAIRN" },
+  { PCI_CHIP_VERDE_6820, "VERDE" },
+  { PCI_CHIP_VERDE_6821, "VERDE" },
+  { PCI_CHIP_VERDE_6823, "VERDE" },
+  { PCI_CHIP_VERDE_6824, "VERDE" },
+  { PCI_CHIP_VERDE_6825, "VERDE" },
+  { PCI_CHIP_VERDE_6826, "VERDE" },
+  { PCI_CHIP_VERDE_6827, "VERDE" },
+  { PCI_CHIP_VERDE_6828, "VERDE" },
+  { PCI_CHIP_VERDE_6829, "VERDE" },
+  { PCI_CHIP_VERDE_682B, "VERDE" },
+  { PCI_CHIP_VERDE_682D, "VERDE" },
+  { PCI_CHIP_VERDE_682F, "VERDE" },
+  { PCI_CHIP_VERDE_6830, "VERDE" },
+  { PCI_CHIP_VERDE_6831, "VERDE" },
+  { PCI_CHIP_VERDE_6837, "VERDE" },
+  { PCI_CHIP_VERDE_6838, "VERDE" },
+  { PCI_CHIP_VERDE_6839, "VERDE" },
+  { PCI_CHIP_VERDE_683B, "VERDE" },
+  { PCI_CHIP_VERDE_683D, "VERDE" },
+  { PCI_CHIP_VERDE_683F, "VERDE" },
   { -1,                 NULL }
 };
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index 12b198c..e16d551 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -1400,7 +1400,9 @@ radeon_dri2_screen_init(ScreenPtr pScreen)
 
     info->dri2.device_name = drmGetDeviceNameFromFd(info->dri2.drm_fd);
 
-    if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) {
+    if ( (info->ChipFamily >= CHIP_FAMILY_TAHITI) ) {
+        dri2_info.driverName = SI_DRIVER_NAME;
+    } else if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) {
         dri2_info.driverName = R600_DRIVER_NAME;
     } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) {
         dri2_info.driverName = R300_DRIVER_NAME;
diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c
index 232332e..714dde9 100644
--- a/src/radeon_glamor.c
+++ b/src/radeon_glamor.c
@@ -135,18 +135,85 @@ 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;
+}
+
+Bool radeon_glamor_prepare_access(PixmapPtr pixmap, glamor_access_t access)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
+	RADEONInfoPtr info = RADEONPTR(scrn);
+	struct radeon_bo *bo;
+	int ret;
+
+	if (access == GLAMOR_GPU_ACCESS_RW || access == GLAMOR_GPU_ACCESS_RO)
+		return info->ChipFamily < CHIP_FAMILY_TAHITI;
+
+	bo = radeon_get_pixmap_bo(pixmap);
+	if (bo) {
+		/* When falling back to swrast, flush all pending operations */
+		if (info->ChipFamily < CHIP_FAMILY_TAHITI)
+			radeon_glamor_flush(scrn);
+
+		ret = radeon_bo_map(bo, 1);
+		if (ret) {
+			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+				   "%s: bo map (tiling_flags %d, access %d) failed: %s\n",
+				   __FUNCTION__,
+				   radeon_get_pixmap_private(pixmap)->tiling_flags,
+				   access,
+				   strerror(-ret));
+			return FALSE;
+		}
+
+		pixmap->devPrivate.ptr = bo->ptr;
+	}
+
+	return TRUE;
+}
+
+void
+radeon_glamor_finish_access(PixmapPtr pixmap, glamor_access_t access)
+{
+	struct radeon_bo *bo;
+
+	switch(access) {
+	case GLAMOR_GPU_ACCESS_RW:
+	case GLAMOR_GPU_ACCESS_RO:
+		break;
+	case GLAMOR_CPU_ACCESS_RO:
+	case GLAMOR_CPU_ACCESS_RW:
+		bo = radeon_get_pixmap_bo(pixmap);
+		if (bo) {
+			radeon_bo_unmap(bo);
+			pixmap->devPrivate.ptr = NULL;
+		}
+		break;
+	default:
+		ErrorF("Invalid access mode %d\n", access);
+	}
+
+	return;
+}
+
 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 (!(usage & RADEON_CREATE_PIXMAP_DRI2)) {
-		pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
-		if (pixmap)
-			return pixmap;
+		if (info->ChipFamily < CHIP_FAMILY_TAHITI) {
+			pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
+			if (pixmap)
+				return pixmap;
+		} else
+			return fbCreatePixmap(screen, w, h, depth, usage);
 	}
 
 	if (w > 32767 || h > 32767)
@@ -230,9 +297,13 @@ Bool
 radeon_glamor_init(ScreenPtr screen)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	RADEONInfoPtr info = RADEONPTR(scrn);
+	unsigned int glamor_init_flags = GLAMOR_INVERTED_Y_AXIS | GLAMOR_USE_EGL_SCREEN;
 
-	if (!glamor_init(screen, GLAMOR_INVERTED_Y_AXIS | GLAMOR_USE_EGL_SCREEN |
-			 GLAMOR_USE_SCREEN | GLAMOR_USE_PICTURE_SCREEN)) {
+	if (info->ChipFamily < CHIP_FAMILY_TAHITI)
+		glamor_init_flags |= GLAMOR_USE_SCREEN | GLAMOR_USE_PICTURE_SCREEN;
+
+	if (!glamor_init(screen, glamor_init_flags)) {
 		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
 			   "Failed to initialize glamor.\n");
 		return FALSE;
@@ -251,6 +322,13 @@ radeon_glamor_init(ScreenPtr screen)
 #endif
 		return FALSE;
 
+	if (!(glamor_init_flags & GLAMOR_USE_SCREEN) &&
+	    !glamor_screen_init(screen)) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "GLAMOR initialization failed\n");
+		return FALSE;
+	}
+
 	screen->CreatePixmap = radeon_glamor_create_pixmap;
 	screen->DestroyPixmap = radeon_glamor_destroy_pixmap;
 
diff --git a/src/radeon_glamor.h b/src/radeon_glamor.h
index 40c9092..f814e46 100644
--- a/src/radeon_glamor.h
+++ b/src/radeon_glamor.h
@@ -29,6 +29,7 @@
 
 #ifdef USE_GLAMOR
 
+#include "radeon_glamor_wrappers.h"
 #include "radeon_surface.h"
 
 Bool radeon_glamor_pre_init(ScrnInfoPtr scrn);
@@ -42,6 +43,8 @@ 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);
+Bool radeon_glamor_prepare_access(PixmapPtr pixmap, glamor_access_t access);
+void radeon_glamor_finish_access(PixmapPtr pixmap, glamor_access_t access);
 
 struct radeon_pixmap {
 	struct radeon_surface surface;
@@ -85,6 +88,8 @@ 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 Bool radeon_glamor_prepare_access(PixmapPtr pixmap, int access) { return FALSE; }
+static inline void radeon_glamor_finish_access(PixmapPtr pixmap, int access) {}
 
 static inline struct radeon_pixmap *radeon_get_pixmap_private(PixmapPtr pixmap) { return NULL; }
 
diff --git a/src/radeon_glamor_wrappers.c b/src/radeon_glamor_wrappers.c
new file mode 100644
index 0000000..d0eb383
--- /dev/null
+++ b/src/radeon_glamor_wrappers.c
@@ -0,0 +1,1870 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *             2010 Intel Corporation
+ *             2012 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_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "radeon_glamor_wrappers.h"
+#include "mipict.h"
+
+
+#if HAS_DEVPRIVATEKEYREC
+DevPrivateKeyRec glamor_screen_index;
+#else
+int glamor_screen_index;
+#endif
+
+/**
+ * glamor_get_drawable_pixmap() returns a 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.  Note that
+ * coordinate translation is needed when drawing to the backing pixmap of a
+ * redirected window, and the translation coordinates are provided by calling
+ * glamor_get_drawable_pixmap() on the drawable.
+ */
+static PixmapPtr glamor_get_drawable_pixmap(DrawablePtr pDrawable)
+{
+	if (pDrawable->type == DRAWABLE_WINDOW)
+		return pDrawable->pScreen->
+		    GetWindowPixmap((WindowPtr) pDrawable);
+	else
+		return (PixmapPtr) pDrawable;
+}
+
+/**
+ * Sets the offsets to add to coordinates to make them address the same bits in
+ * the backing drawable. These coordinates are nonzero only for redirected
+ * windows.
+ */
+static void
+glamor_get_drawable_deltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
+			int *xp, int *yp)
+{
+#ifdef COMPOSITE
+	if (pDrawable->type == DRAWABLE_WINDOW) {
+		*xp = -pPixmap->screen_x;
+		*yp = -pPixmap->screen_y;
+		return;
+	}
+#endif
+
+	*xp = 0;
+	*yp = 0;
+}
+
+/**
+ * glamor_drawable_is_offscreen() is a convenience wrapper for
+ * radeon_glamor_pixmap_is_offscreen().
+ */
+static Bool glamor_drawable_is_offscreen(DrawablePtr pDrawable)
+{
+	return radeon_glamor_pixmap_is_offscreen(glamor_get_drawable_pixmap(pDrawable));
+}
+
+/**
+ * glamor_prepare_access() is GLAMOR's wrapper for the driver's PrepareAccess() handler.
+ *
+ * It deals with waiting for synchronization with the card, determining if
+ * PrepareAccess() is necessary, and working around PrepareAccess() failure.
+ */
+static Bool glamor_prepare_access(DrawablePtr pDrawable, glamor_access_t access)
+{
+	PixmapPtr pPixmap = glamor_get_drawable_pixmap(pDrawable);
+
+	return radeon_glamor_prepare_access(pPixmap, access);
+}
+
+/**
+ * glamor_finish_access() is GLAMOR's wrapper for the driver's finish_access() handler.
+ *
+ * It deals with calling the driver's finish_access() only if necessary.
+ */
+static void glamor_finish_access(DrawablePtr pDrawable, glamor_access_t access)
+{
+	PixmapPtr pPixmap = glamor_get_drawable_pixmap(pDrawable);
+
+	radeon_glamor_finish_access(pPixmap, access);
+}
+
+static Bool glamor_prepare_access_window(WindowPtr pWin)
+{
+	if (pWin->backgroundState == BackgroundPixmap) {
+		if (!glamor_prepare_access
+		    (&pWin->background.pixmap->drawable, GLAMOR_CPU_ACCESS_RO))
+			return FALSE;
+	}
+
+	if (pWin->borderIsPixel == FALSE) {
+		if (!glamor_prepare_access
+		    (&pWin->border.pixmap->drawable, GLAMOR_CPU_ACCESS_RO)) {
+			if (pWin->backgroundState == BackgroundPixmap)
+				glamor_finish_access(&pWin->background.pixmap->
+						  drawable, GLAMOR_CPU_ACCESS_RO);
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+static void glamor_finish_access_window(WindowPtr pWin)
+{
+	if (pWin->backgroundState == BackgroundPixmap)
+		glamor_finish_access(&pWin->background.pixmap->drawable, GLAMOR_CPU_ACCESS_RO);
+
+	if (pWin->borderIsPixel == FALSE)
+		glamor_finish_access(&pWin->border.pixmap->drawable, GLAMOR_CPU_ACCESS_RO);
+}
+
+static Bool glamor_change_window_attributes(WindowPtr pWin, unsigned long mask)
+{
+	Bool ret;
+
+	if (!glamor_prepare_access_window(pWin))
+		return FALSE;
+	ret = fbChangeWindowAttributes(pWin, mask);
+	glamor_finish_access_window(pWin);
+	return ret;
+}
+
+static RegionPtr glamor_bitmap_to_region(PixmapPtr pPix)
+{
+	RegionPtr ret;
+	if (!glamor_prepare_access(&pPix->drawable, GLAMOR_CPU_ACCESS_RO))
+		return NULL;
+	ret = fbPixmapToRegion(pPix);
+	glamor_finish_access(&pPix->drawable, GLAMOR_CPU_ACCESS_RO);
+	return ret;
+}
+
+void glamor_set_fallback_debug(ScreenPtr screen, Bool enable)
+{
+	glamor_screen_t *glamor_screen = glamor_get_screen(screen);
+
+	glamor_screen->fallback_debug = enable;
+}
+
+
+/*
+ * These functions wrap the low-level fb rendering functions and
+ * synchronize framebuffer/accelerated drawing by stalling until
+ * the accelerator is idle
+ */
+
+/**
+ * Calls glamor_prepare_access with GLAMOR_PREPARE_SRC for the tile, if that is the
+ * current fill style.
+ *
+ * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
+ * 1bpp and never in fb, so we don't worry about them.
+ * We should worry about them for completeness sake and going forward.
+ */
+static Bool glamor_prepare_access_gc(GCPtr pGC)
+{
+	if (pGC->stipple)
+		if (!glamor_prepare_access(&pGC->stipple->drawable, GLAMOR_CPU_ACCESS_RO))
+			return FALSE;
+	if (pGC->fillStyle == FillTiled)
+		if (!glamor_prepare_access
+		    (&pGC->tile.pixmap->drawable, GLAMOR_CPU_ACCESS_RO)) {
+			if (pGC->stipple)
+				glamor_finish_access(&pGC->stipple->drawable, GLAMOR_CPU_ACCESS_RO);
+			return FALSE;
+		}
+	return TRUE;
+}
+
+/**
+ * Finishes access to the tile in the GC, if used.
+ */
+static void glamor_finish_access_gc(GCPtr pGC)
+{
+	if (pGC->fillStyle == FillTiled)
+		glamor_finish_access(&pGC->tile.pixmap->drawable, GLAMOR_CPU_ACCESS_RO);
+	if (pGC->stipple)
+		glamor_finish_access(&pGC->stipple->drawable, GLAMOR_CPU_ACCESS_RO);
+}
+
+static Bool glamor_picture_prepare_access(PicturePtr picture, int mode)
+{
+	if (picture->pDrawable == NULL)
+		return TRUE;
+
+	if (!glamor_prepare_access(picture->pDrawable, mode))
+		return FALSE;
+
+	if (picture->alphaMap &&
+	    !glamor_prepare_access(picture->alphaMap->pDrawable, mode)) {
+		glamor_finish_access(picture->pDrawable, mode);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void glamor_picture_finish_access(PicturePtr picture, int mode)
+{
+	if (picture->pDrawable == NULL)
+		return;
+
+	glamor_finish_access(picture->pDrawable, mode);
+	if (picture->alphaMap)
+		glamor_finish_access(picture->alphaMap->pDrawable, mode);
+}
+
+
+static char glamor_drawable_location(DrawablePtr pDrawable)
+{
+	return glamor_drawable_is_offscreen(pDrawable) ? 's' : 'm';
+}
+
+static void
+glamor_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
+		     DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable,
+		      glamor_drawable_location(pDrawable)));
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+		if (glamor_prepare_access_gc(pGC)) {
+			fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth,
+				    fSorted);
+			glamor_finish_access_gc(pGC);
+		}
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static void
+glamor_check_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+		    DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable,
+		      glamor_drawable_location(pDrawable)));
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+		fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static void
+glamor_check_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
+		    int x, int y, int w, int h, int leftPad, int format,
+		    char *bits)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable,
+		      glamor_drawable_location(pDrawable)));
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+		fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+			   bits);
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static RegionPtr
+glamor_check_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+		     int srcx, int srcy, int w, int h, int dstx, int dsty,
+		     unsigned long bitPlane)
+{
+	ScreenPtr screen = pSrc->pScreen;
+	RegionPtr ret = NULL;
+
+	GLAMOR_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+		      glamor_drawable_location(pSrc),
+		      glamor_drawable_location(pDst)));
+	if (glamor_prepare_access(pDst, GLAMOR_CPU_ACCESS_RW)) {
+		if (glamor_prepare_access(pSrc, GLAMOR_CPU_ACCESS_RO)) {
+			ret =
+			    fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
+					dsty, bitPlane);
+			glamor_finish_access(pSrc, GLAMOR_CPU_ACCESS_RO);
+		}
+		glamor_finish_access(pDst, GLAMOR_CPU_ACCESS_RW);
+	}
+	return ret;
+}
+
+static void
+glamor_check_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+		     DDXPointPtr pptInit)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable,
+		      glamor_drawable_location(pDrawable)));
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+		fbPolyPoint(pDrawable, pGC, mode, npt, pptInit);
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static void
+glamor_check_poly_lines(DrawablePtr pDrawable, GCPtr pGC,
+		     int mode, int npt, DDXPointPtr ppt)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
+		      pDrawable, glamor_drawable_location(pDrawable),
+		      pGC->lineWidth, mode, npt));
+
+	if (pGC->lineWidth == 0) {
+		if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+			if (glamor_prepare_access_gc(pGC)) {
+				fbPolyLine(pDrawable, pGC, mode, npt, ppt);
+				glamor_finish_access_gc(pGC);
+			}
+			glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+		}
+		return;
+	}
+	/* fb calls mi functions in the lineWidth != 0 case. */
+	fbPolyLine(pDrawable, pGC, mode, npt, ppt);
+}
+
+static void
+glamor_check_poly_segment(DrawablePtr pDrawable, GCPtr pGC,
+		       int nsegInit, xSegment * pSegInit)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
+		      glamor_drawable_location(pDrawable), pGC->lineWidth,
+		      nsegInit));
+	if (pGC->lineWidth == 0) {
+		if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+			if (glamor_prepare_access_gc(pGC)) {
+				fbPolySegment(pDrawable, pGC, nsegInit,
+					      pSegInit);
+				glamor_finish_access_gc(pGC);
+			}
+			glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+		}
+		return;
+	}
+	/* fb calls mi functions in the lineWidth != 0 case. */
+	fbPolySegment(pDrawable, pGC, nsegInit, pSegInit);
+}
+
+static void
+glamor_check_poly_arc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable,
+		      glamor_drawable_location(pDrawable)));
+
+	/* Disable this as fbPolyArc can call miZeroPolyArc which in turn
+	 * can call accelerated functions, that as yet, haven't been notified
+	 * with glamor_finish_access().
+	 */
+#if 0
+	if (pGC->lineWidth == 0) {
+		if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+			if (glamor_prepare_access_gc(pGC)) {
+				fbPolyArc(pDrawable, pGC, narcs, pArcs);
+				glamor_finish_access_gc(pGC);
+			}
+			glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+		}
+		return;
+	}
+#endif
+	miPolyArc(pDrawable, pGC, narcs, pArcs);
+}
+
+static void
+glamor_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
+			 int nrect, xRectangle * prect)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable,
+		      glamor_drawable_location(pDrawable)));
+
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+		if (glamor_prepare_access_gc(pGC)) {
+			fbPolyFillRect(pDrawable, pGC, nrect, prect);
+			glamor_finish_access_gc(pGC);
+		}
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static void
+glamor_check_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+			  int x, int y, unsigned int nglyph,
+			  CharInfoPtr * ppci, pointer pglyphBase)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable,
+		      glamor_drawable_location(pDrawable)));
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+		if (glamor_prepare_access_gc(pGC)) {
+			fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
+					pglyphBase);
+			glamor_finish_access_gc(pGC);
+		}
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static void
+glamor_check_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+			 int x, int y, unsigned int nglyph,
+			 CharInfoPtr * ppci, pointer pglyphBase)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
+		      glamor_drawable_location(pDrawable), pGC->fillStyle,
+		      pGC->alu));
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+		if (glamor_prepare_access_gc(pGC)) {
+			fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
+				       pglyphBase);
+			glamor_finish_access_gc(pGC);
+		}
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static void
+glamor_check_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
+		      DrawablePtr pDrawable, int w, int h, int x, int y)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
+		      glamor_drawable_location(&pBitmap->drawable),
+		      glamor_drawable_location(pDrawable)));
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) {
+		if (glamor_prepare_access(&pBitmap->drawable, GLAMOR_CPU_ACCESS_RO)) {
+			if (glamor_prepare_access_gc(pGC)) {
+				fbPushPixels(pGC, pBitmap, pDrawable, w, h, x,
+					     y);
+				glamor_finish_access_gc(pGC);
+			}
+			glamor_finish_access(&pBitmap->drawable, GLAMOR_CPU_ACCESS_RO);
+		}
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static void
+glamor_check_get_spans(DrawablePtr pDrawable,
+		    int wMax,
+		    DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("from %p (%c)\n", pDrawable,
+		      glamor_drawable_location(pDrawable)));
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RO)) {
+		fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RO);
+	}
+}
+
+static void
+glamor_check_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)
+{
+	ScreenPtr screen = pDst->pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst));
+
+	if (glamor_picture_prepare_access(pDst, GLAMOR_CPU_ACCESS_RW)) {
+		if (glamor_picture_prepare_access(pSrc, GLAMOR_CPU_ACCESS_RO)) {
+			if (!pMask || glamor_picture_prepare_access(pMask, GLAMOR_CPU_ACCESS_RO)) {
+				fbComposite(op, pSrc, pMask, pDst,
+					    xSrc, ySrc,
+					    xMask, yMask,
+					    xDst, yDst,
+					    width, height);
+				if (pMask)
+					glamor_picture_finish_access(pMask, GLAMOR_CPU_ACCESS_RO);
+			}
+			glamor_picture_finish_access(pSrc, GLAMOR_CPU_ACCESS_RO);
+		}
+		glamor_picture_finish_access(pDst, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static void
+glamor_check_add_traps(PicturePtr pPicture,
+		    INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
+{
+	ScreenPtr screen = pPicture->pDrawable->pScreen;
+
+	GLAMOR_FALLBACK(("to pict %p (%c)\n", pPicture,
+		      glamor_drawable_location(pPicture->pDrawable)));
+	if (glamor_picture_prepare_access(pPicture, GLAMOR_CPU_ACCESS_RW)) {
+		fbAddTraps(pPicture, x_off, y_off, ntrap, traps);
+		glamor_picture_finish_access(pPicture, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+
+static void
+glamor_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n,
+	       DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+	int ok;
+
+	ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	if (ok) {
+		ok = glamor_fill_spans_nf(pDrawable,
+					  pGC, n, ppt, pwidth, fSorted);
+		glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	}
+
+	if (!ok)
+		glamor_check_fill_spans(pDrawable, pGC, n, ppt, pwidth, fSorted);
+}
+
+static void
+glamor_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
+	      int w, int h, int leftPad, int format, char *bits)
+{
+	int ok;
+
+	ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	if (ok) {
+		ok = glamor_put_image_nf(pDrawable,
+					 pGC, depth, x, y, w, h,
+					 leftPad, format, bits);
+		glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	}
+
+	if (!ok)
+		glamor_check_put_image(pDrawable, pGC, depth, x, y, w, h, leftPad,
+				       format, bits);
+}
+
+static void
+glamor_copy_n_to_n(DrawablePtr pSrcDrawable,
+		DrawablePtr pDstDrawable,
+		GCPtr pGC,
+		BoxPtr pbox,
+		int nbox,
+		int dx,
+		int dy,
+		Bool reverse, Bool upsidedown, Pixel bitplane, void *closure)
+{
+	ScreenPtr screen = pDstDrawable->pScreen;
+	int ok;
+
+	if (!glamor_prepare_access(pSrcDrawable, GLAMOR_GPU_ACCESS_RO))
+		goto fallback;
+	ok = glamor_prepare_access(pDstDrawable, GLAMOR_GPU_ACCESS_RW);
+	if (!ok)
+		goto finish_src;
+	ok = glamor_copy_n_to_n_nf(pSrcDrawable, pDstDrawable,
+				   pGC, pbox, nbox, dx, dy,
+				   reverse, upsidedown, bitplane,
+				   closure);
+	glamor_finish_access(pDstDrawable, GLAMOR_GPU_ACCESS_RW);
+finish_src:
+	glamor_finish_access(pSrcDrawable, GLAMOR_GPU_ACCESS_RO);
+
+	if (ok)
+		return;
+
+fallback:
+	GLAMOR_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
+		      glamor_drawable_location(pSrcDrawable),
+		      glamor_drawable_location(pDstDrawable)));
+	if (glamor_prepare_access(pDstDrawable, GLAMOR_CPU_ACCESS_RW)) {
+		if (pSrcDrawable == pDstDrawable ||
+		    glamor_prepare_access(pSrcDrawable, GLAMOR_CPU_ACCESS_RO)) {
+			fbCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
+				   dx, dy, reverse, upsidedown, bitplane,
+				   closure);
+			if (pSrcDrawable != pDstDrawable)
+				glamor_finish_access(pSrcDrawable, GLAMOR_CPU_ACCESS_RO);
+		}
+		glamor_finish_access(pDstDrawable, GLAMOR_CPU_ACCESS_RW);
+	}
+}
+
+static RegionPtr
+glamor_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+	      int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+	return miDoCopy(pSrcDrawable, pDstDrawable, pGC,
+			srcx, srcy, width, height,
+			dstx, dsty, glamor_copy_n_to_n, 0, NULL);
+}
+
+static void
+glamor_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+	       DDXPointPtr ppt)
+{
+	int i;
+	xRectangle *prect;
+	int ok;
+
+	ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	if (ok) {
+		ok = glamor_poly_point_nf(pDrawable, pGC, mode, npt, ppt);
+		glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	}
+
+	if (ok)
+		return;
+
+	/* If we can't reuse the current GC as is, don't bother accelerating the
+	 * points.
+	 */
+	if (pGC->fillStyle != FillSolid) {
+		glamor_check_poly_point(pDrawable, pGC, mode, npt, ppt);
+		return;
+	}
+
+	prect = malloc(sizeof(xRectangle) * npt);
+	if (!prect)
+		return;
+	for (i = 0; i < npt; i++) {
+		prect[i].x = ppt[i].x;
+		prect[i].y = ppt[i].y;
+		if (i > 0 && mode == CoordModePrevious) {
+			prect[i].x += prect[i - 1].x;
+			prect[i].y += prect[i - 1].y;
+		}
+		prect[i].width = 1;
+		prect[i].height = 1;
+	}
+	pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
+	free(prect);
+}
+
+/**
+ * glamor_poly_lines() checks if it can accelerate the lines as a group of
+ * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ * acceleration if so.
+ */
+static void
+glamor_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+	       DDXPointPtr ppt)
+{
+	xRectangle *prect;
+	int x1, x2, y1, y2;
+	int i;
+	int ok;
+
+	if (!glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW))
+		goto fallback;
+	ok = glamor_poly_lines_nf(pDrawable, pGC, mode, npt, ppt);
+	glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+
+	if (ok)
+		return;
+
+fallback:
+	/* Don't try to do wide lines or non-solid fill style. */
+	if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
+	    pGC->fillStyle != FillSolid) {
+		glamor_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
+		return;
+	}
+
+	prect = malloc(sizeof(xRectangle) * (npt - 1));
+	if (!prect)
+		return;
+	x1 = ppt[0].x;
+	y1 = ppt[0].y;
+	/* If we have any non-horizontal/vertical, fall back. */
+	for (i = 0; i < npt - 1; i++) {
+		if (mode == CoordModePrevious) {
+			x2 = x1 + ppt[i + 1].x;
+			y2 = y1 + ppt[i + 1].y;
+		} else {
+			x2 = ppt[i + 1].x;
+			y2 = ppt[i + 1].y;
+		}
+
+		if (x1 != x2 && y1 != y2) {
+			free(prect);
+			glamor_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
+			return;
+		}
+
+		if (x1 < x2) {
+			prect[i].x = x1;
+			prect[i].width = x2 - x1 + 1;
+		} else {
+			prect[i].x = x2;
+			prect[i].width = x1 - x2 + 1;
+		}
+		if (y1 < y2) {
+			prect[i].y = y1;
+			prect[i].height = y2 - y1 + 1;
+		} else {
+			prect[i].y = y2;
+			prect[i].height = y1 - y2 + 1;
+		}
+
+		x1 = x2;
+		y1 = y2;
+	}
+	pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
+	free(prect);
+}
+
+/**
+ * glamor_poly_segment() checks if it can accelerate the lines as a group of
+ * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ * acceleration if so.
+ */
+static void
+glamor_poly_segment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg)
+{
+	xRectangle *prect;
+	int i;
+	int ok;
+
+	if (!glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW))
+		goto fallback;
+	ok = glamor_poly_segment_nf(pDrawable, pGC, nseg, pSeg);
+	glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+
+	if (ok)
+		return;
+
+fallback:
+	/* Don't try to do wide lines or non-solid fill style. */
+	if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
+	    pGC->fillStyle != FillSolid) {
+		glamor_check_poly_segment(pDrawable, pGC, nseg, pSeg);
+		return;
+	}
+
+	/* If we have any non-horizontal/vertical, fall back. */
+	for (i = 0; i < nseg; i++) {
+		if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
+			glamor_check_poly_segment(pDrawable, pGC, nseg, pSeg);
+			return;
+		}
+	}
+
+	prect = malloc(sizeof(xRectangle) * nseg);
+	if (!prect)
+		return;
+	for (i = 0; i < nseg; i++) {
+		if (pSeg[i].x1 < pSeg[i].x2) {
+			prect[i].x = pSeg[i].x1;
+			prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
+		} else {
+			prect[i].x = pSeg[i].x2;
+			prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
+		}
+		if (pSeg[i].y1 < pSeg[i].y2) {
+			prect[i].y = pSeg[i].y1;
+			prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
+		} else {
+			prect[i].y = pSeg[i].y2;
+			prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
+		}
+
+		/* don't paint last pixel */
+		if (pGC->capStyle == CapNotLast) {
+			if (prect[i].width == 1)
+				prect[i].height--;
+			else
+				prect[i].width--;
+		}
+	}
+	pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
+	free(prect);
+}
+
+static void
+glamor_poly_fill_rect(DrawablePtr pDrawable,
+		   GCPtr pGC, int nrect, xRectangle * prect)
+{
+	int ok;
+
+	ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	if (ok) {
+		ok = glamor_poly_fill_rect_nf(pDrawable, pGC, nrect, prect);
+		glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	}
+
+	if (!ok)
+		glamor_check_poly_fill_rect(pDrawable, pGC, nrect, prect);
+}
+
+static void
+glamor_get_spans(DrawablePtr pDrawable,
+	      int wMax,
+	      DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
+{
+	int ok;
+
+	ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	if (ok) {
+		ok = glamor_get_spans_nf(pDrawable, wMax, ppt,
+					 pwidth, nspans, pdstStart);
+		glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	}
+
+	if (!ok)
+		glamor_check_get_spans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+}
+
+static void
+glamor_set_spans(DrawablePtr pDrawable, GCPtr gc, char *src,
+                 DDXPointPtr points, int *widths, int n, int sorted)
+{
+	int ok;
+
+	ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	if (ok) {
+		ok = glamor_set_spans_nf(pDrawable, gc, src,
+					 points, widths, n, sorted);
+		glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	}
+
+	if (!ok)
+		glamor_check_set_spans(pDrawable, gc, src, points, widths, n, sorted);
+}
+
+static RegionPtr
+glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+	       int srcx, int srcy, int w, int h, int dstx, int dsty,
+	       unsigned long bitPlane)
+{
+	int ok;
+	RegionPtr region;
+
+	if (!glamor_prepare_access(pDst, GLAMOR_GPU_ACCESS_RW))
+		goto fallback;
+	ok = glamor_prepare_access(pSrc, GLAMOR_GPU_ACCESS_RO);
+	if (!ok)
+		goto finish_dst;
+	ok = glamor_copy_plane_nf(pSrc, pDst, pGC, srcx, srcy, w, h,
+				  dstx, dsty, bitPlane, &region);
+	glamor_finish_access(pSrc, GLAMOR_GPU_ACCESS_RO);
+finish_dst:
+	glamor_finish_access(pDst, GLAMOR_GPU_ACCESS_RW);
+
+	if (ok)
+		return region;
+
+fallback:
+	return glamor_check_copy_plane(pSrc, pDst, pGC, srcx, srcy, w, h,
+				    dstx, dsty, bitPlane);
+}
+
+static void
+glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+		    int x, int y, unsigned int nglyph,
+		    CharInfoPtr * ppci, pointer pglyphBase)
+{
+	int ok;
+
+	ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	if (ok) {
+		ok = glamor_image_glyph_blt_nf(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+		glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	}
+
+	if (!ok)
+		glamor_check_image_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+}
+
+static void
+glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+		   int x, int y, unsigned int nglyph,
+		   CharInfoPtr * ppci, pointer pglyphBase)
+{
+	int ok;
+
+	ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	if (ok) {
+		ok = glamor_poly_glyph_blt_nf(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+		glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+	}
+
+	if (!ok)
+		glamor_check_poly_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+}
+
+static void
+glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
+		DrawablePtr pDrawable, int w, int h, int x, int y)
+{
+	int ok;
+
+	if (!glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW))
+		goto fallback;
+	ok = glamor_prepare_access(&pBitmap->drawable, GLAMOR_GPU_ACCESS_RO);
+	if (!ok)
+		goto finish_drawable;
+	ok = glamor_push_pixels_nf(pGC, pBitmap, pDrawable, w, h, x, y);
+	glamor_finish_access(&pBitmap->drawable, GLAMOR_GPU_ACCESS_RO);
+finish_drawable:
+	glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+
+	if (ok)
+	  return;
+
+fallback:
+	glamor_check_push_pixels(pGC, pBitmap, pDrawable, w, h, x, y);
+}
+
+const GCOps glamor_ops = {
+	glamor_fill_spans,
+	glamor_set_spans,
+	glamor_put_image,
+	glamor_copy_area,
+	glamor_copy_plane,
+	glamor_poly_point,
+	glamor_poly_lines,
+	glamor_poly_segment,
+	miPolyRectangle,
+	glamor_check_poly_arc,
+	miFillPolygon,
+	glamor_poly_fill_rect,
+	miPolyFillArc,
+	miPolyText8,
+	miPolyText16,
+	miImageText8,
+	miImageText16,
+	glamor_image_glyph_blt,
+	glamor_poly_glyph_blt,
+	glamor_push_pixels,
+};
+
+/**
+ * glamor_validate_gc() sets the ops to GLAMOR's 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)
+{
+	glamor_validate_gc(pGC, changes, pDrawable);
+	pGC->ops = (GCOps *) & glamor_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)
+{
+	if (!fbCreateGC(pGC))
+		return FALSE;
+
+	pGC->funcs = &glamorGCFuncs;
+
+	return TRUE;
+}
+
+static void glamor_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+	RegionRec rgnDst;
+	int dx, dy;
+	PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
+
+	dx = ptOldOrg.x - pWin->drawable.x;
+	dy = ptOldOrg.y - pWin->drawable.y;
+	REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
+
+	REGION_INIT(pWin->drawable.pScreen, &rgnDst, NullBox, 0);
+
+	REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip,
+			 prgnSrc);
+#ifdef COMPOSITE
+	if (pPixmap->screen_x || pPixmap->screen_y)
+		REGION_TRANSLATE(pWin->drawable.pScreen, &rgnDst,
+				 -pPixmap->screen_x, -pPixmap->screen_y);
+#endif
+
+	miCopyRegion(&pPixmap->drawable, &pPixmap->drawable,
+		     NULL, &rgnDst, dx, dy, glamor_copy_n_to_n, 0, NULL);
+
+	REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
+}
+
+/**
+ * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
+ *
+ * This is probably the only case we actually care about.  The rest fall through
+ * to migration and fbGetImage, which hopefully will result in migration pushing
+ * the pixmap out of framebuffer.
+ */
+void
+static glamor_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
+	      unsigned int format, unsigned long planeMask, char *d)
+{
+	ScreenPtr screen = pDrawable->pScreen;
+	BoxRec Box;
+	PixmapPtr pPix = glamor_get_drawable_pixmap(pDrawable);
+	int xoff, yoff;
+	Bool ok;
+
+	if (!glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW))
+		goto fallback;
+
+	glamor_get_drawable_deltas(pDrawable, pPix, &xoff, &yoff);
+
+	Box.x1 = pDrawable->y + x + xoff;
+	Box.y1 = pDrawable->y + y + yoff;
+	Box.x2 = Box.x1 + w;
+	Box.y2 = Box.y1 + h;
+
+	ok = glamor_get_image_nf(pDrawable, x, y, w, h,
+				 format, planeMask, d);
+	glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW);
+
+	if (ok)
+		return;
+
+fallback:
+	GLAMOR_FALLBACK(("from %p (%c)\n", pDrawable,
+		      glamor_drawable_location(pDrawable)));
+
+	if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RO)) {
+		fbGetImage(pDrawable, x, y, w, h, format, planeMask, d);
+		glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RO);
+	}
+
+	return;
+}
+
+
+/* Cut and paste from render/glyph.c - probably should export it instead */
+static void
+glamor_glyph_extents(int nlist,
+		  GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
+{
+	int x1, x2, y1, y2;
+	int x, y, n;
+
+	x1 = y1 = MAXSHORT;
+	x2 = y2 = MINSHORT;
+	x = y = 0;
+	while (nlist--) {
+		x += list->xOff;
+		y += list->yOff;
+		n = list->len;
+		list++;
+		while (n--) {
+			GlyphPtr glyph = *glyphs++;
+			int v;
+
+			v = x - glyph->info.x;
+			if (v < x1)
+			    x1 = v;
+			v += glyph->info.width;
+			if (v > x2)
+			    x2 = v;
+
+			v = y - glyph->info.y;
+			if (v < y1)
+			    y1 = v;
+			v += glyph->info.height;
+			if (v > y2)
+			    y2 = v;
+
+			x += glyph->info.xOff;
+			y += glyph->info.yOff;
+		}
+	}
+
+	extents->x1 = x1 < MINSHORT ? MINSHORT : x1;
+	extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2;
+	extents->y1 = y1 < MINSHORT ? MINSHORT : y1;
+	extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2;
+}
+
+#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
+
+static void
+glamor_check_glyphs(CARD8 op,
+		 PicturePtr src,
+		 PicturePtr dst,
+		 PictFormatPtr maskFormat,
+		 INT16 xSrc,
+		 INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
+{
+	pixman_image_t *image;
+	PixmapPtr scratch;
+	PicturePtr mask;
+	int width = 0, height = 0;
+	int x, y, n;
+	int xDst = list->xOff, yDst = list->yOff;
+	BoxRec extents = { 0, 0, 0, 0 };
+
+	if (maskFormat) {
+		pixman_format_code_t format;
+		CARD32 component_alpha;
+		int error;
+
+		glamor_glyph_extents(nlist, list, glyphs, &extents);
+		if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
+			return;
+
+		width = extents.x2 - extents.x1;
+		height = extents.y2 - extents.y1;
+
+		format = maskFormat->format |
+			(BitsPerPixel(maskFormat->depth) << 24);
+		image =
+			pixman_image_create_bits(format, width, height, NULL, 0);
+		if (!image)
+			return;
+
+		scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height,
+						 PIXMAN_FORMAT_DEPTH(format),
+						 PIXMAN_FORMAT_BPP(format),
+						 pixman_image_get_stride(image),
+						 pixman_image_get_data(image));
+
+		if (!scratch) {
+			pixman_image_unref(image);
+			return;
+		}
+
+		component_alpha = NeedsComponent(maskFormat->format);
+		mask = CreatePicture(0, &scratch->drawable,
+				     maskFormat, CPComponentAlpha,
+				     &component_alpha, serverClient, &error);
+		if (!mask) {
+			FreeScratchPixmapHeader(scratch);
+			pixman_image_unref(image);
+			return;
+		}
+		ValidatePicture(mask);
+
+		x = -extents.x1;
+		y = -extents.y1;
+	} else {
+		mask = dst;
+		x = 0;
+		y = 0;
+	}
+
+	while (nlist--) {
+		x += list->xOff;
+		y += list->yOff;
+		n = list->len;
+		while (n--) {
+			GlyphPtr glyph = *glyphs++;
+			PicturePtr g = GetGlyphPicture(glyph, dst->pDrawable->pScreen);
+			if (g) {
+				if (maskFormat) {
+					CompositePicture(PictOpAdd, g, NULL, mask,
+							 0, 0,
+							 0, 0,
+							 x - glyph->info.x,
+							 y - glyph->info.y,
+							 glyph->info.width,
+							 glyph->info.height);
+				} else {
+					CompositePicture(op, src, g, dst,
+							 xSrc + (x - glyph->info.x) - xDst,
+							 ySrc + (y - glyph->info.y) - yDst,
+							 0, 0,
+							 x - glyph->info.x,
+							 y - glyph->info.y,
+							 glyph->info.width,
+							 glyph->info.height);
+				}
+			}
+
+			x += glyph->info.xOff;
+			y += glyph->info.yOff;
+		}
+		list++;
+	}
+
+	if (maskFormat) {
+		x = extents.x1;
+		y = extents.y1;
+		CompositePicture(op, src, mask, dst,
+				 xSrc + x - xDst,
+				 ySrc + y - yDst,
+				 0, 0,
+				 x, y,
+				 width, height);
+		FreePicture(mask, 0);
+		FreeScratchPixmapHeader(scratch);
+		pixman_image_unref(image);
+	}
+}
+
+void
+glamor_glyphs(CARD8 op,
+	   PicturePtr pSrc,
+	   PicturePtr pDst,
+	   PictFormatPtr maskFormat,
+	   INT16 xSrc, INT16 ySrc,
+	   int nlist, GlyphListPtr list, GlyphPtr * glyphs)
+{
+	int ok;
+
+	if (!glamor_picture_prepare_access(pDst, GLAMOR_GPU_ACCESS_RW))
+		goto fallback;
+	ok = glamor_picture_prepare_access(pSrc, GLAMOR_GPU_ACCESS_RO);
+	if (!ok)
+		goto finish_dst;
+	ok = glamor_glyphs_nf(op,
+			      pSrc, pDst, maskFormat,
+			      xSrc, ySrc, nlist, list, glyphs);
+	glamor_picture_finish_access(pSrc, GLAMOR_GPU_ACCESS_RO);
+finish_dst:
+	glamor_picture_finish_access(pDst, GLAMOR_GPU_ACCESS_RW);
+
+	if (ok)
+		return;
+
+fallback:
+	glamor_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
+}
+
+
+#ifdef RENDER
+
+/* Note: when using glamor we can not fail through to the ordinary GLAMOR
+ * code paths, as glamor keeps an internal texture which will become
+ * inconsistent with the original bo. (The texture is replaced whenever
+ * the format changes, e.g. switching between xRGB and ARGB, for which mesa
+ * will allocate its own bo.)
+ *
+ * Ergo it is unsafe to fall through to the original backend operations if
+ * glamor is enabled.
+ *
+ * XXX This has some serious implications for mixing Render, DRI, scanout...
+ */
+
+static void glamor_composite_fallback_pict_desc(PicturePtr pict, char *string,
+					     int n)
+{
+	char format[20];
+	char size[20];
+	char loc;
+
+	if (!pict) {
+		snprintf(string, n, "None");
+		return;
+	}
+
+	if (pict->pDrawable == NULL) {
+		snprintf(string, n, "source-only");
+		return;
+	}
+
+	switch (pict->format) {
+	case PICT_a8r8g8b8:
+		snprintf(format, 20, "ARGB8888");
+		break;
+	case PICT_x8r8g8b8:
+		snprintf(format, 20, "XRGB8888");
+		break;
+	case PICT_r5g6b5:
+		snprintf(format, 20, "RGB565  ");
+		break;
+	case PICT_x1r5g5b5:
+		snprintf(format, 20, "RGB555  ");
+		break;
+	case PICT_a8:
+		snprintf(format, 20, "A8      ");
+		break;
+	case PICT_a1:
+		snprintf(format, 20, "A1      ");
+		break;
+	default:
+		snprintf(format, 20, "0x%x", (int)pict->format);
+		break;
+	}
+
+	loc = glamor_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm';
+
+	snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
+		 pict->pDrawable->height, pict->repeat ? " R" : "");
+
+	snprintf(string, n, "%p:%c fmt %s (%s)%s",
+		 pict->pDrawable, loc, format, size,
+		 pict->alphaMap ? " with alpha map" :"");
+}
+
+static const char *
+op_to_string(CARD8 op)
+{
+    switch (op) {
+#define C(x) case PictOp##x: return #x
+	C(Clear);
+	C(Src);
+	C(Dst);
+	C(Over);
+	C(OverReverse);
+	C(In);
+	C(InReverse);
+	C(Out);
+	C(OutReverse);
+	C(Atop);
+	C(AtopReverse);
+	C(Xor);
+	C(Add);
+	C(Saturate);
+
+	/*
+	 * Operators only available in version 0.2
+	 */
+#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 2
+	C(DisjointClear);
+	C(DisjointSrc);
+	C(DisjointDst);
+	C(DisjointOver);
+	C(DisjointOverReverse);
+	C(DisjointIn);
+	C(DisjointInReverse);
+	C(DisjointOut);
+	C(DisjointOutReverse);
+	C(DisjointAtop);
+	C(DisjointAtopReverse);
+	C(DisjointXor);
+
+	C(ConjointClear);
+	C(ConjointSrc);
+	C(ConjointDst);
+	C(ConjointOver);
+	C(ConjointOverReverse);
+	C(ConjointIn);
+	C(ConjointInReverse);
+	C(ConjointOut);
+	C(ConjointOutReverse);
+	C(ConjointAtop);
+	C(ConjointAtopReverse);
+	C(ConjointXor);
+#endif
+
+	/*
+	 * Operators only available in version 0.11
+	 */
+#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 11
+	C(Multiply);
+	C(Screen);
+	C(Overlay);
+	C(Darken);
+	C(Lighten);
+	C(ColorDodge);
+	C(ColorBurn);
+	C(HardLight);
+	C(SoftLight);
+	C(Difference);
+	C(Exclusion);
+	C(HSLHue);
+	C(HSLSaturation);
+	C(HSLColor);
+	C(HSLLuminosity);
+#endif
+    default: return "garbage";
+#undef C
+    }
+}
+
+static void
+glamor_print_composite_fallback(const char *func, CARD8 op,
+			     PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
+{
+	glamor_screen_t *glamor_screen = glamor_get_screen(pDst->pDrawable->pScreen);
+	char srcdesc[40], maskdesc[40], dstdesc[40];
+
+	if (! glamor_screen->fallback_debug)
+		return;
+
+	glamor_composite_fallback_pict_desc(pSrc, srcdesc, 40);
+	glamor_composite_fallback_pict_desc(pMask, maskdesc, 40);
+	glamor_composite_fallback_pict_desc(pDst, dstdesc, 40);
+
+	ErrorF("Composite fallback at %s:\n"
+	       "  op   %s, \n"
+	       "  src  %s, \n"
+	       "  mask %s, \n"
+	       "  dst  %s, \n",
+	       func, op_to_string (op), srcdesc, maskdesc, dstdesc);
+}
+
+
+static void
+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)
+{
+	int ok;
+
+	if (!glamor_picture_prepare_access(pDst, GLAMOR_GPU_ACCESS_RW))
+		goto fallback;
+	ok = glamor_picture_prepare_access(pSrc, GLAMOR_GPU_ACCESS_RO);
+	if (!ok)
+		goto finish_dst;
+	if (pMask) {
+		ok = glamor_picture_prepare_access(pMask, GLAMOR_GPU_ACCESS_RO);
+		if (!ok)
+			goto finish_src;
+	}
+
+	ok = glamor_composite_nf(op,
+				 pSrc, pMask, pDst, xSrc, ySrc,
+				 xMask, yMask, xDst, yDst,
+				 width, height);
+
+	if (pMask)
+		glamor_picture_finish_access(pMask, GLAMOR_GPU_ACCESS_RO);
+finish_src:
+	glamor_picture_finish_access(pSrc, GLAMOR_GPU_ACCESS_RO);
+finish_dst:
+	glamor_picture_finish_access(pDst, GLAMOR_GPU_ACCESS_RW);
+
+	if (ok)
+		return;
+
+fallback:
+	glamor_print_composite_fallback("glamor_composite",
+				     op, pSrc, pMask, pDst);
+
+	glamor_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
+			    xMask, yMask, xDst, yDst, width, height);
+}
+
+
+static void
+glamor_check_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
+		     PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+		     int ntrap, xTrapezoid * traps)
+{
+	ScreenPtr screen = dst->pDrawable->pScreen;
+
+	if (maskFormat) {
+		PixmapPtr scratch = NULL;
+		PicturePtr mask;
+		INT16 xDst, yDst;
+		INT16 xRel, yRel;
+		BoxRec bounds;
+		int width, height;
+		pixman_image_t *image;
+		pixman_format_code_t format;
+		int error;
+
+		xDst = traps[0].left.p1.x >> 16;
+		yDst = traps[0].left.p1.y >> 16;
+
+		miTrapezoidBounds (ntrap, traps, &bounds);
+		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+			return;
+
+		width  = bounds.x2 - bounds.x1;
+		height = bounds.y2 - bounds.y1;
+
+		format = maskFormat->format |
+			(BitsPerPixel(maskFormat->depth) << 24);
+		image =
+		    pixman_image_create_bits(format, width, height, NULL, 0);
+		if (!image)
+			return;
+
+		for (; ntrap; ntrap--, traps++)
+			pixman_rasterize_trapezoid(image,
+						   (pixman_trapezoid_t *) traps,
+						   -bounds.x1, -bounds.y1);
+
+
+		scratch = GetScratchPixmapHeader(screen, width, height,
+						 PIXMAN_FORMAT_DEPTH(format),
+						 PIXMAN_FORMAT_BPP(format),
+						 pixman_image_get_stride(image),
+						 pixman_image_get_data(image));
+		if (!scratch) {
+			pixman_image_unref(image);
+			return;
+		}
+
+		mask = CreatePicture(0, &scratch->drawable,
+				     PictureMatchFormat(screen,
+							PIXMAN_FORMAT_DEPTH(format),
+							format),
+				     0, 0, serverClient, &error);
+		if (!mask) {
+			FreeScratchPixmapHeader(scratch);
+			pixman_image_unref(image);
+			return;
+		}
+
+		xRel = bounds.x1 + xSrc - xDst;
+		yRel = bounds.y1 + ySrc - yDst;
+		CompositePicture(op, src, mask, dst,
+				 xRel, yRel,
+				 0, 0,
+				 bounds.x1, bounds.y1,
+				 width, height);
+		FreePicture(mask, 0);
+
+		FreeScratchPixmapHeader(scratch);
+		pixman_image_unref(image);
+	} else {
+		if (dst->polyEdge == PolyEdgeSharp)
+			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
+		else
+			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
+
+		for (; ntrap; ntrap--, traps++)
+			glamor_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1, traps);
+	}
+}
+
+/**
+ * glamor_trapezoids is essentially a copy of miTrapezoids that uses
+ * glamor_create_alpha_picture instead of miCreateAlphaPicture.
+ *
+ * The problem with miCreateAlphaPicture is that it calls PolyFillRect
+ * to initialize the contents after creating the pixmap, which
+ * causes the pixmap to be moved in for acceleration. The subsequent
+ * call to RasterizeTrapezoid won't be accelerated however, which
+ * forces the pixmap to be moved out again.
+ *
+ * glamor_create_alpha_picture avoids this roundtrip by using
+ * glamor_check_poly_fill_rect to initialize the contents.
+ */
+static void
+glamor_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
+		  PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+		  int ntrap, xTrapezoid * traps)
+{
+	int ok;
+
+	if (!glamor_picture_prepare_access(dst, GLAMOR_GPU_ACCESS_RW))
+		goto fallback;
+	ok = glamor_picture_prepare_access(src, GLAMOR_GPU_ACCESS_RO);
+	if (!ok)
+		goto finish_dst;
+	ok = glamor_trapezoids_nf(op,
+				  src, dst, maskFormat, xSrc,
+				  ySrc, ntrap, traps);
+	glamor_picture_finish_access(src, GLAMOR_GPU_ACCESS_RO);
+finish_dst:
+	glamor_picture_finish_access(dst, GLAMOR_GPU_ACCESS_RW);
+
+	if (ok)
+		return;
+
+fallback:
+	glamor_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, ntrap, traps);
+}
+
+static void
+glamor_check_triangles(CARD8 op, PicturePtr src, PicturePtr dst,
+		    PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+		    int ntri, xTriangle *tri)
+{
+	ScreenPtr screen = dst->pDrawable->pScreen;
+
+	if (maskFormat) {
+		PixmapPtr scratch = NULL;
+		PicturePtr mask;
+		INT16 xDst, yDst;
+		INT16 xRel, yRel;
+		BoxRec bounds;
+		int width, height;
+		pixman_image_t *image;
+		pixman_format_code_t format;
+		int error;
+
+		xDst = pixman_fixed_to_int(tri[0].p1.x);
+		yDst = pixman_fixed_to_int(tri[0].p1.y);
+
+		miTriangleBounds (ntri, tri, &bounds);
+		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+			return;
+
+		width  = bounds.x2 - bounds.x1;
+		height = bounds.y2 - bounds.y1;
+
+		format = maskFormat->format |
+			(BitsPerPixel(maskFormat->depth) << 24);
+		image =
+		    pixman_image_create_bits(format, width, height, NULL, 0);
+		if (!image)
+			return;
+
+		pixman_add_triangles(image,
+				     -bounds.x1, -bounds.y1,
+				     ntri, (pixman_triangle_t *)tri);
+
+		scratch = GetScratchPixmapHeader(screen, width, height,
+						 PIXMAN_FORMAT_DEPTH(format),
+						 PIXMAN_FORMAT_BPP(format),
+						 pixman_image_get_stride(image),
+						 pixman_image_get_data(image));
+		if (!scratch) {
+			pixman_image_unref(image);
+			return;
+		}
+
+		mask = CreatePicture(0, &scratch->drawable,
+				     PictureMatchFormat(screen,
+							PIXMAN_FORMAT_DEPTH(format),
+							format),
+				     0, 0, serverClient, &error);
+		if (!mask) {
+			FreeScratchPixmapHeader(scratch);
+			pixman_image_unref(image);
+			return;
+		}
+
+		xRel = bounds.x1 + xSrc - xDst;
+		yRel = bounds.y1 + ySrc - yDst;
+		CompositePicture(op, src, mask, dst,
+				 xRel, yRel,
+				 0, 0,
+				 bounds.x1, bounds.y1,
+				 width, height);
+		FreePicture(mask, 0);
+
+		FreeScratchPixmapHeader(scratch);
+		pixman_image_unref(image);
+	} else {
+		if (dst->polyEdge == PolyEdgeSharp)
+			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
+		else
+			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
+
+		for (; ntri; ntri--, tri++)
+			glamor_check_triangles(op, src, dst, maskFormat, xSrc, ySrc, 1, tri);
+	}
+}
+
+/**
+ * glamor_triangles is essentially a copy of miTriangles that uses
+ * glamor_create_alpha_picture instead of miCreateAlphaPicture.
+ *
+ * The problem with miCreateAlphaPicture is that it calls PolyFillRect
+ * to initialize the contents after creating the pixmap, which
+ * causes the pixmap to be moved in for acceleration. The subsequent
+ * call to AddTriangles won't be accelerated however, which forces the pixmap
+ * to be moved out again.
+ *
+ * glamor_create_alpha_picture avoids this roundtrip by using
+ * glamor_check_poly_fill_rect to initialize the contents.
+ */
+static void
+glamor_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+	      PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+	      int ntri, xTriangle * tris)
+{
+	int ok;
+
+	if (!glamor_picture_prepare_access(pDst, GLAMOR_GPU_ACCESS_RW))
+		goto fallback;
+	ok = glamor_picture_prepare_access(pSrc, GLAMOR_GPU_ACCESS_RO);
+	if (!ok)
+		goto finish_dst;
+	ok = glamor_triangles_nf(op,
+				 pSrc, pDst, maskFormat, xSrc,
+				 ySrc, ntri, tris);
+	glamor_picture_finish_access(pSrc, GLAMOR_GPU_ACCESS_RO);
+finish_dst:
+	glamor_picture_finish_access(pDst, GLAMOR_GPU_ACCESS_RW);
+
+	if (ok)
+		return;
+
+fallback:
+	glamor_check_triangles(op, pSrc, pDst, maskFormat,
+			       xSrc, ySrc, ntri, tris);
+}
+
+void
+glamor_add_traps(PicturePtr pPicture,
+		 INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
+{
+	int ok;
+
+	ok = glamor_picture_prepare_access(pPicture, GLAMOR_GPU_ACCESS_RW);
+	if (ok) {
+		ok = glamor_add_traps_nf(pPicture,
+					 x_off, y_off, ntrap, traps);
+		glamor_picture_finish_access(pPicture, GLAMOR_GPU_ACCESS_RW);
+	}
+
+	if (!ok)
+		glamor_check_add_traps(pPicture, x_off, y_off, ntrap, traps);
+}
+
+#endif /* RENDER */
+
+
+/**
+ * radeon_glamor_close_screen() unwraps its wrapped screen functions and tears down GLAMOR's
+ * screen private, before calling down to the next CloseSccreen.
+ */
+static Bool radeon_glamor_close_screen(CLOSE_SCREEN_ARGS_DECL)
+{
+	glamor_screen_t *glamor_screen = glamor_get_screen(pScreen);
+#ifdef RENDER
+	PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+
+	pScreen->CreateGC = glamor_screen->SavedCreateGC;
+	pScreen->CloseScreen = glamor_screen->SavedCloseScreen;
+	pScreen->GetImage = glamor_screen->SavedGetImage;
+	pScreen->GetSpans = glamor_screen->SavedGetSpans;
+	pScreen->CreatePixmap = glamor_screen->SavedCreatePixmap;
+	pScreen->DestroyPixmap = glamor_screen->SavedDestroyPixmap;
+	pScreen->CopyWindow = glamor_screen->SavedCopyWindow;
+	pScreen->ChangeWindowAttributes =
+	    glamor_screen->SavedChangeWindowAttributes;
+	pScreen->BitmapToRegion = glamor_screen->SavedBitmapToRegion;
+#ifdef RENDER
+	if (ps) {
+		ps->Composite = glamor_screen->SavedComposite;
+		ps->Glyphs = glamor_screen->SavedGlyphs;
+		ps->Trapezoids = glamor_screen->SavedTrapezoids;
+		ps->AddTraps = glamor_screen->SavedAddTraps;
+		ps->Triangles = glamor_screen->SavedTriangles;
+
+		ps->UnrealizeGlyph = glamor_screen->SavedUnrealizeGlyph;
+	}
+#endif
+
+	free(glamor_screen);
+
+	return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS);
+}
+
+/**
+ * @param screen screen being initialized
+ */
+Bool glamor_screen_init(ScreenPtr screen)
+{
+	glamor_screen_t *glamor_screen;
+
+#if HAS_DIXREGISTERPRIVATEKEY
+	if (!dixRegisterPrivateKey(&glamor_screen_index, PRIVATE_SCREEN, 0))
+	    return FALSE;
+#endif
+	glamor_screen = calloc(sizeof(glamor_screen_t), 1);
+
+	if (!glamor_screen) {
+		LogMessage(X_WARNING,
+			   "GLAMOR(%d): Failed to allocate screen private\n",
+			   screen->myNum);
+		return FALSE;
+	}
+
+	dixSetPrivate(&screen->devPrivates, &glamor_screen_index, glamor_screen);
+
+	/*
+	 * Replace various fb screen functions
+	 */
+	glamor_screen->SavedCloseScreen = screen->CloseScreen;
+	screen->CloseScreen = radeon_glamor_close_screen;
+
+	glamor_screen->SavedCreateGC = screen->CreateGC;
+	screen->CreateGC = radeon_glamor_create_gc;
+
+	glamor_screen->SavedGetImage = screen->GetImage;
+	screen->GetImage = glamor_get_image;
+
+	glamor_screen->SavedGetSpans = screen->GetSpans;
+	screen->GetSpans = glamor_get_spans;
+
+	glamor_screen->SavedCreatePixmap = screen->CreatePixmap;
+	glamor_screen->SavedDestroyPixmap = screen->DestroyPixmap;
+
+	glamor_screen->SavedCopyWindow = screen->CopyWindow;
+	screen->CopyWindow = glamor_copy_window;
+
+	glamor_screen->SavedChangeWindowAttributes =
+	    screen->ChangeWindowAttributes;
+	screen->ChangeWindowAttributes = glamor_change_window_attributes;
+
+	glamor_screen->SavedBitmapToRegion = screen->BitmapToRegion;
+	screen->BitmapToRegion = glamor_bitmap_to_region;
+
+#ifdef RENDER
+	{
+		PictureScreenPtr ps = GetPictureScreenIfSet(screen);
+		if (ps) {
+			glamor_screen->SavedComposite = ps->Composite;
+			ps->Composite = glamor_composite;
+
+			glamor_screen->SavedGlyphs = ps->Glyphs;
+			ps->Glyphs = glamor_glyphs;
+
+			glamor_screen->SavedTriangles = ps->Triangles;
+			ps->Triangles = glamor_triangles;
+
+			glamor_screen->SavedTrapezoids = ps->Trapezoids;
+			ps->Trapezoids = glamor_trapezoids;
+
+			glamor_screen->SavedAddTraps = ps->AddTraps;
+			ps->AddTraps = glamor_add_traps;
+		}
+	}
+#endif
+
+	return TRUE;
+}
diff --git a/src/radeon_glamor_wrappers.h b/src/radeon_glamor_wrappers.h
new file mode 100644
index 0000000..9abbd22
--- /dev/null
+++ b/src/radeon_glamor_wrappers.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright © 2000,2008 Keith Packard
+ *             2004 Eric Anholt
+ *             2005 Zack Rusin, Trolltech
+ *             2012 Advanced Micro Devices, 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 copyright 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.
+ */
+
+#ifndef RADEON_GLAMOR_WRAPPERS_H
+#define RADEON_GLAMOR_WRAPPERS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+#include <xorg-server.h>
+#include "xf86.h"
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "servermd.h"
+#include "mibstore.h"
+#include "colormapst.h"
+#include "gcstruct.h"
+#include "input.h"
+#include "mipointer.h"
+#include "mi.h"
+#include "dix.h"
+#include "fb.h"
+#include "fboverlay.h"
+#ifdef RENDER
+//#include "fbpict.h"
+#include "glyphstr.h"
+#include "picturestr.h"
+#endif
+#include "damage.h"
+
+#include "../src/compat-api.h"
+
+/* Provide substitutes for gcc's __FUNCTION__ on other compilers */
+#if !defined(__GNUC__) && !defined(__FUNCTION__)
+# if defined(__STDC__) && (__STDC_VERSION__>=199901L)	/* C99 */
+#  define __FUNCTION__ __func__
+# else
+#  define __FUNCTION__ ""
+# endif
+#endif
+
+/* 1.6 and earlier server compat */
+#ifndef miGetCompositeClip
+#define miCopyRegion fbCopyRegion
+#define miDoCopy fbDoCopy
+#endif
+
+typedef enum {
+	GLAMOR_CPU_ACCESS_RO,
+	GLAMOR_CPU_ACCESS_RW,
+	GLAMOR_GPU_ACCESS_RO,
+	GLAMOR_GPU_ACCESS_RW
+} glamor_access_t;
+
+#include "radeon.h"
+#include "glamor.h"
+
+
+Bool glamor_screen_init(ScreenPtr screen);
+
+void glamor_set_fallback_debug(ScreenPtr screen, Bool enable);
+
+#define DEBUG_MIGRATE		0
+#define DEBUG_PIXMAP		0
+#define DEBUG_OFFSCREEN		0
+#define DEBUG_GLYPH_CACHE	0
+
+#define GLAMOR_FALLBACK(x)     					\
+if (glamor_get_screen(screen)->fallback_debug) {			\
+	ErrorF("GLAMOR fallback at %s: ", __FUNCTION__);		\
+	ErrorF x;						\
+}
+
+#if DEBUG_PIXMAP
+#define DBG_PIXMAP(a) ErrorF a
+#else
+#define DBG_PIXMAP(a)
+#endif
+
+typedef void (*EnableDisableFBAccessProcPtr) (int, Bool);
+typedef struct {
+	CreateGCProcPtr SavedCreateGC;
+	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
+
+	Bool fallback_debug;
+} glamor_screen_t;
+
+/*
+ * This is the only completely portable way to
+ * compute this info.
+ */
+#ifndef BitsPerPixel
+#define BitsPerPixel(d) (\
+    PixmapWidthPaddingInfo[d].notPower2 ? \
+    (PixmapWidthPaddingInfo[d].bytesPerPixel * 8) : \
+    ((1 << PixmapWidthPaddingInfo[d].padBytesLog2) * 8 / \
+    (PixmapWidthPaddingInfo[d].padRoundUp+1)))
+#endif
+
+#if HAS_DEVPRIVATEKEYREC
+extern DevPrivateKeyRec glamor_screen_index;
+#else
+extern int glamor_screen_index;
+#endif
+
+static inline glamor_screen_t *glamor_get_screen(ScreenPtr screen)
+{
+#if HAS_DEVPRIVATEKEYREC
+	return dixGetPrivate(&screen->devPrivates, &glamor_screen_index);
+#else
+	return dixLookupPrivate(&screen->devPrivates, &glamor_screen_index);
+#endif
+}
+
+#ifdef RENDER
+
+/* XXX these are in fbpict.h, which is not installed */
+void
+fbComposite(CARD8 op,
+	    PicturePtr pSrc,
+	    PicturePtr pMask,
+	    PicturePtr pDst,
+	    INT16 xSrc,
+	    INT16 ySrc,
+	    INT16 xMask,
+	    INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
+
+void
+fbAddTraps(PicturePtr pPicture,
+	   INT16 xOff, INT16 yOff, int ntrap, xTrap * traps);
+
+#endif
+
+#endif /* RADEON_GLAMOR_WRAPPERS_H */
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 5d9ccff..5cc362f 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -418,6 +418,7 @@ static Bool RADEONPreInitAccel_KMS(ScrnInfoPtr pScrn)
 	(!RADEONIsAccelWorking(pScrn))) {
 	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		   "GPU accel disabled or not working, using shadowfb for KMS\n");
+shadowfb:
 	info->r600_shadow_fb = TRUE;
 	if (!xf86LoadSubModule(pScrn, "shadow"))
 	    info->r600_shadow_fb = FALSE;
@@ -427,7 +428,9 @@ static Bool RADEONPreInitAccel_KMS(ScrnInfoPtr pScrn)
     if (radeon_glamor_pre_init(pScrn))
 	return TRUE;
 
-    if (info->ChipFamily == CHIP_FAMILY_PALM) {
+    if (info->ChipFamily >= CHIP_FAMILY_TAHITI) {
+	goto shadowfb;
+    } else if (info->ChipFamily == CHIP_FAMILY_PALM) {
 	info->accel_state->allowHWDFS = RADEONIsFusionGARTWorking(pScrn);
     } else
 	info->accel_state->allowHWDFS = TRUE;
diff --git a/src/radeon_pci_chipset_gen.h b/src/radeon_pci_chipset_gen.h
index c9f9656..02c0a7e 100644
--- a/src/radeon_pci_chipset_gen.h
+++ b/src/radeon_pci_chipset_gen.h
@@ -537,5 +537,44 @@ static PciChipsets RADEONPciChipsets[] = {
  { PCI_CHIP_ARUBA_99A0, PCI_CHIP_ARUBA_99A0, RES_SHARED_VGA },
  { PCI_CHIP_ARUBA_99A2, PCI_CHIP_ARUBA_99A2, RES_SHARED_VGA },
  { PCI_CHIP_ARUBA_99A4, PCI_CHIP_ARUBA_99A4, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_6780, PCI_CHIP_TAHITI_6780, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_6784, PCI_CHIP_TAHITI_6784, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_6788, PCI_CHIP_TAHITI_6788, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_678A, PCI_CHIP_TAHITI_678A, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_6790, PCI_CHIP_TAHITI_6790, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_6798, PCI_CHIP_TAHITI_6798, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_6799, PCI_CHIP_TAHITI_6799, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_679A, PCI_CHIP_TAHITI_679A, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_679E, PCI_CHIP_TAHITI_679E, RES_SHARED_VGA },
+ { PCI_CHIP_TAHITI_679F, PCI_CHIP_TAHITI_679F, RES_SHARED_VGA },
+ { PCI_CHIP_PITCAIRN_6800, PCI_CHIP_PITCAIRN_6800, RES_SHARED_VGA },
+ { PCI_CHIP_PITCAIRN_6801, PCI_CHIP_PITCAIRN_6801, RES_SHARED_VGA },
+ { PCI_CHIP_PITCAIRN_6802, PCI_CHIP_PITCAIRN_6802, RES_SHARED_VGA },
+ { PCI_CHIP_PITCAIRN_6808, PCI_CHIP_PITCAIRN_6808, RES_SHARED_VGA },
+ { PCI_CHIP_PITCAIRN_6809, PCI_CHIP_PITCAIRN_6809, RES_SHARED_VGA },
+ { PCI_CHIP_PITCAIRN_6810, PCI_CHIP_PITCAIRN_6810, RES_SHARED_VGA },
+ { PCI_CHIP_PITCAIRN_6818, PCI_CHIP_PITCAIRN_6818, RES_SHARED_VGA },
+ { PCI_CHIP_PITCAIRN_6819, PCI_CHIP_PITCAIRN_6819, RES_SHARED_VGA },
+ { PCI_CHIP_PITCAIRN_684C, PCI_CHIP_PITCAIRN_684C, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6820, PCI_CHIP_VERDE_6820, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6821, PCI_CHIP_VERDE_6821, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6823, PCI_CHIP_VERDE_6823, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6824, PCI_CHIP_VERDE_6824, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6825, PCI_CHIP_VERDE_6825, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6826, PCI_CHIP_VERDE_6826, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6827, PCI_CHIP_VERDE_6827, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6828, PCI_CHIP_VERDE_6828, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6829, PCI_CHIP_VERDE_6829, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_682B, PCI_CHIP_VERDE_682B, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_682D, PCI_CHIP_VERDE_682D, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_682F, PCI_CHIP_VERDE_682F, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6830, PCI_CHIP_VERDE_6830, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6831, PCI_CHIP_VERDE_6831, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6837, PCI_CHIP_VERDE_6837, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6838, PCI_CHIP_VERDE_6838, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_6839, PCI_CHIP_VERDE_6839, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_683B, PCI_CHIP_VERDE_683B, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_683D, PCI_CHIP_VERDE_683D, RES_SHARED_VGA },
+ { PCI_CHIP_VERDE_683F, PCI_CHIP_VERDE_683F, RES_SHARED_VGA },
  { -1,                 -1,                 RES_UNDEFINED }
 };
diff --git a/src/radeon_pci_device_match_gen.h b/src/radeon_pci_device_match_gen.h
index a6663e0..f729914 100644
--- a/src/radeon_pci_device_match_gen.h
+++ b/src/radeon_pci_device_match_gen.h
@@ -537,5 +537,44 @@ static const struct pci_id_match radeon_device_match[] = {
  ATI_DEVICE_MATCH( PCI_CHIP_ARUBA_99A0, 0 ),
  ATI_DEVICE_MATCH( PCI_CHIP_ARUBA_99A2, 0 ),
  ATI_DEVICE_MATCH( PCI_CHIP_ARUBA_99A4, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_6780, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_6784, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_6788, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_678A, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_6790, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_6798, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_6799, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_679A, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_679E, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_TAHITI_679F, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_PITCAIRN_6800, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_PITCAIRN_6801, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_PITCAIRN_6802, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_PITCAIRN_6808, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_PITCAIRN_6809, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_PITCAIRN_6810, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_PITCAIRN_6818, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_PITCAIRN_6819, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_PITCAIRN_684C, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6820, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6821, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6823, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6824, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6825, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6826, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6827, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6828, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6829, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_682B, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_682D, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_682F, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6830, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6831, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6837, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6838, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_6839, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_683B, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_683D, 0 ),
+ ATI_DEVICE_MATCH( PCI_CHIP_VERDE_683F, 0 ),
  { 0, 0, 0 }
 };
diff --git a/src/radeon_probe.h b/src/radeon_probe.h
index 576f722..07bc080 100644
--- a/src/radeon_probe.h
+++ b/src/radeon_probe.h
@@ -102,6 +102,9 @@ typedef enum {
     CHIP_FAMILY_CAICOS,
     CHIP_FAMILY_CAYMAN,
     CHIP_FAMILY_ARUBA,
+    CHIP_FAMILY_TAHITI,
+    CHIP_FAMILY_PITCAIRN,
+    CHIP_FAMILY_VERDE,
     CHIP_FAMILY_LAST
 } RADEONChipFamily;
 
diff --git a/src/radeon_version.h b/src/radeon_version.h
index 129046d..9a6fac1 100644
--- a/src/radeon_version.h
+++ b/src/radeon_version.h
@@ -39,6 +39,7 @@
 #define R200_DRIVER_NAME     "r200"
 #define R300_DRIVER_NAME     "r300"
 #define R600_DRIVER_NAME     "r600"
+#define SI_DRIVER_NAME       "radeonsi"
 
 #define RADEON_VERSION_MAJOR PACKAGE_VERSION_MAJOR
 #define RADEON_VERSION_MINOR PACKAGE_VERSION_MINOR
commit e9edd2f5002c642b59f028b3ec076d604ae8ce9d
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Jun 20 08:40:07 2012 +0200

    Initial glamor support.
    
    Enable at build time with --enable-glamor and runtime with
    
    	Option	"AccelMethod" "glamor"
    
    The most notable lack of functionality is XVideo. Use something like VDPAU for
    now.
    
    Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>

diff --git a/configure.ac b/configure.ac
index a73dd4e..86199f2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -91,6 +91,20 @@ AM_CONDITIONAL(LIBUDEV, test x$LIBUDEV = xyes)
 SAVE_CPPFLAGS="$CPPFLAGS"
 CPPFLAGS="$CPPFLAGS $XORG_CFLAGS"
 
+AC_MSG_CHECKING([whether to include GLAMOR support])
+AC_ARG_ENABLE(glamor,
+	      AS_HELP_STRING([--enable-glamor],
+			     [Enable glamor, a new GL-based acceleration [default=no]]),
+	      [GLAMOR="$enableval"],
+	      [GLAMOR=no])
+AC_MSG_RESULT([$GLAMOR])
+AM_CONDITIONAL(GLAMOR, test x$GLAMOR != xno)
+if test "x$GLAMOR" != "xno"; then
+	PKG_CHECK_MODULES(LIBGLAMOR, [glamor >= 0.3.1])
+	PKG_CHECK_MODULES(LIBGLAMOR_EGL, [glamor-egl])
+	AC_DEFINE(USE_GLAMOR, 1, [Enable glamor acceleration])
+fi
+
 AC_CHECK_DECL(xf86ModeBandwidth,
 	      [AC_DEFINE(HAVE_XF86MODEBANDWIDTH, 1, [Have xf86ModeBandwidth prototype])],
 	      [],
diff --git a/man/radeon.man b/man/radeon.man
index da0c1cc..be50314 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -211,13 +211,6 @@ For example:
 Option \*qZaphodHeads\*q \*qLVDS,VGA-0\*q
 will assign xrandr outputs LVDS and VGA-0 to this instance of the driver.
 .TP
-.BI "Option \*qEXAVSync\*q \*q" boolean \*q
-This option attempts to avoid tearing by stalling the engine until the display
-controller has passed the destination region.  It reduces tearing at the cost
-of performance and has been known to cause instability on some chips.
-The default is
-.B off.
-.TP
 .BI "Option \*qColorTiling\*q \*q" "boolean" \*q
 The framebuffer can be addressed either in linear or tiled mode. Tiled mode can provide
 significant performance benefits with 3D applications.  Tiling will be disabled if the drm
@@ -241,6 +234,33 @@ The default value is
 .B off
 for R/RV6XX, R/RV7XX, RS780, RS880, EVERGREEN, and CAYMAN.
 .TP
+.BI "Option \*qEnablePageFlip\*q \*q" boolean \*q
+Enable DRI2 page flipping.  The default is
+.B on.
+Pageflipping is supported on all radeon hardware.
+.TP
+.BI "Option \*qAccelMethod\*q \*q" "string" \*q
+Chooses between available acceleration architectures.  Valid values are
+.B EXA
+and
+.B glamor.
+The default is
+.B EXA.
+
+.PP
+The following driver
+.B Options
+are supported for
+.B EXA
+:
+.TP
+.BI "Option \*qEXAVSync\*q \*q" boolean \*q
+This option attempts to avoid tearing by stalling the engine until the display
+controller has passed the destination region.  It reduces tearing at the cost
+of performance and has been known to cause instability on some chips.
+The default is
+.B off.
+.TP
 .BI "Option \*qEXAPixmaps\*q \*q" boolean \*q
 Under KMS, to avoid thrashing pixmaps in/out of VRAM on low memory cards,
 we use a heuristic based on VRAM amount to determine whether to allow EXA
@@ -259,11 +279,6 @@ the framerate of applications that render frames at less than refresh rate.
 .IP
 The default value is
 .B on.
-.TP
-.BI "Option \*qEnablePageFlip\*q \*q" boolean \*q
-Enable DRI2 page flipping.  The default is
-.B on.
-Pageflipping is supported on all radeon hardware.
 
 .SH TEXTURED VIDEO ATTRIBUTES
 The driver supports the following X11 Xv attributes for Textured Video.
diff --git a/src/Makefile.am b/src/Makefile.am
index e857f21..da94927 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -64,6 +64,13 @@ radeon_drv_la_SOURCES = \
 	$(RADEON_EXA_SOURCES) \
 	$(RADEON_KMS_SRCS)
 
+if GLAMOR
+AM_CFLAGS += @LIBGLAMOR_CFLAGS@
+radeon_drv_la_LIBADD += @LIBGLAMOR_LIBS@
+radeon_drv_la_SOURCES += \
+	 radeon_glamor.c
+endif
+
 EXTRA_DIST = \
 	radeon_textured_videofuncs.c \
 	r600_reg.h \
@@ -88,6 +95,7 @@ EXTRA_DIST = \
 	radeon_exa_render.c \
 	radeon_exa_funcs.c \
 	radeon_exa_shared.h \
+	radeon_glamor.h \
 	radeon.h \
 	radeon_probe.h \
 	radeon_reg.h \
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 27569e5..6a35728 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -101,7 +101,8 @@ static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
 		return NULL;
 	}
 
-	exaMoveInPixmap(pixmap);
+	if (!info->use_glamor)
+		exaMoveInPixmap(pixmap);
 	radeon_set_pixmap_bo(pixmap, bo);
 	if (info->ChipFamily >= CHIP_FAMILY_R600) {
 		surface = radeon_get_pixmap_surface(pixmap);
@@ -278,7 +279,7 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
 	uint32_t tiling_flags = 0;
 	Bool ret;
 
-	if (info->accelOn == FALSE)
+	if (info->accelOn == FALSE || info->use_glamor)
 		goto fallback;
 
 	for (i = 0; i < xf86_config->num_crtc; i++) {
@@ -1442,6 +1443,9 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
 				       crtc->rotation, crtc->x, crtc->y);
 	}
 
+	if (info->use_glamor)
+		radeon_glamor_create_screen_resources(scrn->pScreen);
+
 	if (old_fb_id)
 		drmModeRmFB(drmmode->fd, old_fb_id);
 	if (old_front)
diff --git a/src/radeon.h b/src/radeon.h
index d357dc1..2f05249 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -51,6 +51,7 @@
 
 #include "exa.h"
 
+#include "radeon_glamor.h"
 
 				/* Exa and Cursor Support */
 #include "xf86Cursor.h"
@@ -429,6 +430,7 @@ typedef struct {
     Bool              allowColorTiling2D;
     struct radeon_accel_state *accel_state;
     Bool              accelOn;
+    Bool              use_glamor;
     Bool	      exa_pixmaps;
     Bool              exa_force_create;
     XF86ModReqInfo    exaReq;
@@ -522,11 +524,107 @@ extern void radeon_ddx_cs_start(ScrnInfoPtr pScrn,
 				int num, const char *file,
 				const char *func, int line);
 void radeon_kms_update_vram_limit(ScrnInfoPtr pScrn, int new_fb_size);
-struct radeon_surface *radeon_get_pixmap_surface(PixmapPtr pPix);
-struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix);
-void radeon_set_pixmap_bo(PixmapPtr pPix, struct radeon_bo *bo);
+
+static inline struct radeon_surface *radeon_get_pixmap_surface(PixmapPtr pPix)
+{
+#ifdef USE_GLAMOR
+    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pPix->drawable.pScreen));
+
+    if (info->use_glamor) {
+	struct radeon_pixmap *priv;
+	priv = radeon_get_pixmap_private(pPix);
+	return priv ? &priv->surface : NULL;
+    } else
+#endif
+    {
+	struct radeon_exa_pixmap_priv *driver_priv;
+	driver_priv = exaGetPixmapDriverPrivate(pPix);
+	return &driver_priv->surface;
+    }
+
+    return NULL;
+}
+
 uint32_t radeon_get_pixmap_tiling(PixmapPtr pPix);
 
+static inline void radeon_set_pixmap_bo(PixmapPtr pPix, struct radeon_bo *bo)
+{
+#ifdef USE_GLAMOR
+    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pPix->drawable.pScreen));
+
+    if (info->use_glamor) {
+	struct radeon_pixmap *priv;
+
+	priv = radeon_get_pixmap_private(pPix);
+	if (priv == NULL && bo == NULL)
+	    return;
+
+	if (priv) {
+	    if (priv->bo == bo)
+		return;
+
+	    if (priv->bo)
+		radeon_bo_unref(priv->bo);
+
+	    free(priv);
+	    priv = NULL;
+	}
+
+	if (bo) {
+	    uint32_t pitch;
+
+	    priv = calloc(1, sizeof (struct radeon_pixmap));
+	    if (priv == NULL)
+		goto out;
+
+	    radeon_bo_ref(bo);
+	    priv->bo = bo;
+
+	    radeon_bo_get_tiling(bo, &priv->tiling_flags, &pitch);
+	}
+out:
+	radeon_set_pixmap_private(pPix, priv);
+    } else
+#endif /* USE_GLAMOR */
+    {
+	struct radeon_exa_pixmap_priv *driver_priv;
+
+	driver_priv = exaGetPixmapDriverPrivate(pPix);
+	if (driver_priv) {
+	    uint32_t pitch;
+
+	    if (driver_priv->bo)
+		radeon_bo_unref(driver_priv->bo);
+
+	    radeon_bo_ref(bo);
+	    driver_priv->bo = bo;
+
+	    radeon_bo_get_tiling(bo, &driver_priv->tiling_flags, &pitch);
+	}
+    }
+}
+
+static inline struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix)
+{
+#ifdef USE_GLAMOR
+    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pPix->drawable.pScreen));
+
+    if (info->use_glamor) {
+	struct radeon_pixmap *priv;
+	priv = radeon_get_pixmap_private(pPix);
+	return priv ? priv->bo : NULL;
+    } else
+#endif
+    {
+	struct radeon_exa_pixmap_priv *driver_priv;
+	driver_priv = exaGetPixmapDriverPrivate(pPix);
+	return driver_priv->bo;
+    }
+
+    return NULL;
+}
+
+
 #define CP_PACKET0(reg, n)						\
 	(RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
 #define CP_PACKET1(reg0, reg1)						\
@@ -659,6 +757,7 @@ static __inline__ void RADEON_SYNC(RADEONInfoPtr info, ScrnInfoPtr pScrn)
 }
 
 enum {
+    RADEON_CREATE_PIXMAP_DRI2 = 0x08000000,
     RADEON_CREATE_PIXMAP_TILING_MACRO = 0x10000000,
     RADEON_CREATE_PIXMAP_TILING_MICRO = 0x20000000,
     RADEON_CREATE_PIXMAP_DEPTH = 0x40000000, /* for r200 */
diff --git a/src/radeon_accel.c b/src/radeon_accel.c
index 15cf2bd..8eff5c5 100644
--- a/src/radeon_accel.c
+++ b/src/radeon_accel.c
@@ -182,7 +182,12 @@ Bool RADEONAccelInit(ScreenPtr pScreen)
     RADEONInfoPtr  info  = RADEONPTR(pScrn);
 
     if (info->directRenderingEnabled) {
-	if (info->ChipFamily >= CHIP_FAMILY_CEDAR) {
+	if (info->use_glamor) {
+	    if (!radeon_glamor_init(pScreen)) {
+		info->use_glamor = FALSE;
+		return FALSE;
+	    }
+	} else if (info->ChipFamily >= CHIP_FAMILY_CEDAR) {
 	    if (!EVERGREENDrawInit(pScreen))
 		return FALSE;
 	} else
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index 8c24de9..12b198c 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -73,6 +73,77 @@ struct dri2_buffer_priv {
 };
 
 
+static PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
+{
+    if (drawable->type == DRAWABLE_PIXMAP)
+	return (PixmapPtr)drawable;
+    else
+	return (*drawable->pScreen->GetWindowPixmap)((WindowPtr)drawable);
+}
+
+
+static PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap)
+{
+	PixmapPtr old = get_drawable_pixmap(drawable);
+#ifdef USE_GLAMOR
+	ScreenPtr screen = drawable->pScreen;
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
+	GCPtr gc;
+
+	/* With a glamor pixmap, 2D pixmaps are created in texture
+	 * and without a static BO attached to it. To support DRI,
+	 * we need to create a new textured-drm pixmap and
+	 * need to copy the original content to this new textured-drm
+	 * pixmap, and then convert the old pixmap to a coherent
+	 * textured-drm pixmap which has a valid BO attached to it
+	 * and also has a valid texture, thus both glamor and DRI2
+	 * can access it.
+	 *
+	 */
+
+	/* Copy the current contents of the pixmap to the bo. */
+	gc = GetScratchGC(drawable->depth, screen);
+	if (gc) {
+		ValidateGC(&pixmap->drawable, gc);
+		gc->ops->CopyArea(&old->drawable, &pixmap->drawable,
+				  gc,
+				  0, 0,
+				  old->drawable.width,
+				  old->drawable.height,
+				  0, 0);
+		FreeScratchGC(gc);
+	}
+
+	radeon_set_pixmap_private(pixmap, NULL);
+	screen->DestroyPixmap(pixmap);
+
+	/* And redirect the pixmap to the new bo (for 3D). */
+	radeon_set_pixmap_private(old, priv);
+	old->refcnt++;
+
+	/* This creating should not fail, as we already created its
+	 * successfully. But if it happens, we put a warning indicator
+	 * here, and the old pixmap will still be a glamor pixmap, and
+	 * latter the pixmap_flink will get a 0 name, then the X server
+	 * will pass a BadAlloc to the client.*/
+	if (!radeon_glamor_create_textured_pixmap(old))
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "Failed to get DRI drawable for glamor pixmap.\n");
+
+	screen->ModifyPixmapHeader(old,
+				   old->drawable.width,
+				   old->drawable.height,
+				   0, 0,
+				   priv->stride,
+				   NULL);
+
+#endif /* USE_GLAMOR*/
+
+	return old;
+}
+
+
 #ifndef USE_DRI2_1_1_0
 static BufferPtr
 radeon_dri2_create_buffers(DrawablePtr drawable,
@@ -85,13 +156,13 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
     BufferPtr buffers;
     struct dri2_buffer_priv *privates;
     PixmapPtr pixmap, depth_pixmap;
-    struct radeon_exa_pixmap_priv *driver_priv;
+    struct radeon_bo *bo;
     int i, r, need_enlarge = 0;
     int flags = 0;
     unsigned front_width;
     uint32_t tiling = 0;
 
-    pixmap = screen->GetScreenPixmap(screen);
+    pixmap = pScreen->GetScreenPixmap(pScreen);
     front_width = pixmap->drawable.width;
 
     buffers = calloc(count, sizeof *buffers);
@@ -106,17 +177,25 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
 
     depth_pixmap = NULL;
     for (i = 0; i < count; i++) {
+	Bool is_glamor_pixmap = FALSE;
+	unsigned aligned_width = drawable->width;
+	unsigned aligned_height = drawable->height;
+
         if (attachments[i] == DRI2BufferFrontLeft) {
-            if (drawable->type == DRAWABLE_PIXMAP) {
-                pixmap = (Pixmap*)drawable;
-            } else {
-                pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable);
-            }
-            pixmap->refcnt++;
+            pixmap = get_drawable_pixmap(drawable);
+	    if (info->use_glamor && !radeon_get_pixmap_bo(pixmap)) {
+		is_glamor_pixmap = TRUE;
+		aligned_width = pixmap->drawable.width;
+		aligned_height = pixmap->drawable.height;
+		pixmap = NULL;
+	    } else
+		pixmap->refcnt++;
         } else if (attachments[i] == DRI2BufferStencil && depth_pixmap) {
             pixmap = depth_pixmap;
             pixmap->refcnt++;
-        } else {
+        }
+
+	if (!pixmap) {
 	    /* tile the back buffer */
 	    switch(attachments[i]) {
 	    case DRI2BufferDepth:
@@ -145,6 +224,8 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
 		break;
 	    case DRI2BufferBackLeft:
 	    case DRI2BufferBackRight:
+	    case DRI2BufferFrontLeft:
+	    case DRI2BufferFrontRight:
 	    case DRI2BufferFakeFrontLeft:
 	    case DRI2BufferFakeFrontRight:
 		if (info->ChipFamily >= CHIP_FAMILY_R600)
@@ -164,14 +245,15 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
 	    if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO)
 		tiling |= RADEON_TILING_MACRO;
 
+	    if (aligned_width == front_width)
+		aligned_width = pScrn->virtualX;
+
 	    if (need_enlarge) {
 		/* evergreen uses separate allocations for depth and stencil
 		 * so we make an extra large depth buffer to cover stencil
 		 * as well.
 		 */
-		unsigned aligned_width = drawable->width;
 		unsigned width_align = drmmode_get_pitch_align(pScrn, drawable->depth / 8, tiling);
-		unsigned aligned_height;
 		unsigned height_align = drmmode_get_height_align(pScrn, tiling);
 		unsigned base_align = drmmode_get_base_align(pScrn, drawable->depth / 8, tiling);
 		unsigned pitch_bytes;
@@ -181,42 +263,33 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
 		    aligned_width = pScrn->virtualX;
 		aligned_width = RADEON_ALIGN(aligned_width, width_align);
 		pitch_bytes = aligned_width * (drawable->depth / 8);
-		aligned_height = RADEON_ALIGN(drawable->height, height_align);
+		aligned_height = RADEON_ALIGN(aligned_height, height_align);
 		size = pitch_bytes * aligned_height;
 		size = RADEON_ALIGN(size, base_align);
 		/* add additional size for stencil */
 		size += aligned_width * aligned_height;
 		aligned_height = RADEON_ALIGN(size / pitch_bytes, height_align);
-
-		pixmap = (*pScreen->CreatePixmap)(pScreen,
-						  aligned_width,
-						  aligned_height,
-						  drawable->depth,
-						  flags);
-
-	    } else {
-		unsigned aligned_width = drawable->width;
-
-		if (aligned_width == front_width)
-		    aligned_width = pScrn->virtualX;
-
-		pixmap = (*pScreen->CreatePixmap)(pScreen,
-						  aligned_width,
-						  drawable->height,
-						  drawable->depth,
-						  flags);
 	    }
+
+	    pixmap = (*pScreen->CreatePixmap)(pScreen,
+					      aligned_width,
+					      aligned_height,
+					      drawable->depth,
+					      flags | RADEON_CREATE_PIXMAP_DRI2);
         }
 
         if (attachments[i] == DRI2BufferDepth) {
             depth_pixmap = pixmap;
         }
-	info->exa_force_create = TRUE;
-	exaMoveInPixmap(pixmap);
-	info->exa_force_create = FALSE;
-        driver_priv = exaGetPixmapDriverPrivate(pixmap);
-	if (!driver_priv ||
-	    radeon_gem_get_kernel_name(driver_priv->bo, &buffers[i].name) != 0) {
+	if (!info->use_glamor) {
+	    info->exa_force_create = TRUE;
+	    exaMoveInPixmap(pixmap);
+	    info->exa_force_create = FALSE;
+	}
+	if (is_glamor_pixmap)
+	    pixmap = fixup_glamor(drawable, pixmap);
+	bo = radeon_get_pixmap_bo(pixmap);
+	if (!bo || radeon_gem_get_kernel_name(bo, &buffers[i].name) != 0) {
 	    int j;
 
 	    for (j = 0; j < i; j++)
@@ -249,11 +322,13 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
     BufferPtr buffers;
     struct dri2_buffer_priv *privates;
     PixmapPtr pixmap, depth_pixmap;
-    struct radeon_exa_pixmap_priv *driver_priv;
+    struct radeon_bo *bo;
     int flags;
     unsigned front_width;
     uint32_t tiling = 0;
     unsigned aligned_width = drawable->width;
+    unsigned height = drawable->height;
+    Bool is_glamor_pixmap = FALSE;
 
     pixmap = pScreen->GetScreenPixmap(pScreen);
     front_width = pixmap->drawable.width;
@@ -261,16 +336,20 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
     pixmap = depth_pixmap = NULL;
 
     if (attachment == DRI2BufferFrontLeft) {
-        if (drawable->type == DRAWABLE_PIXMAP) {
-            pixmap = (PixmapPtr)drawable;
-        } else {
-            pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable);
-        }
-        pixmap->refcnt++;
+        pixmap = get_drawable_pixmap(drawable);
+	if (info->use_glamor && !radeon_get_pixmap_bo(pixmap)) {
+	    is_glamor_pixmap = TRUE;
+	    aligned_width = pixmap->drawable.width;
+	    height = pixmap->drawable.height;
+	    pixmap = NULL;
+	} else
+	    pixmap->refcnt++;
     } else if (attachment == DRI2BufferStencil && depth_pixmap) {
         pixmap = depth_pixmap;
         pixmap->refcnt++;
-    } else {
+    }
+
+    if (!pixmap) {
 	/* tile the back buffer */
 	switch(attachment) {
 	case DRI2BufferDepth:
@@ -310,6 +389,8 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
 	    break;
 	case DRI2BufferBackLeft:
 	case DRI2BufferBackRight:
+	case DRI2BufferFrontLeft:
+	case DRI2BufferFrontRight:
 	case DRI2BufferFakeFrontLeft:
 	case DRI2BufferFakeFrontRight:
 	    if (info->ChipFamily >= CHIP_FAMILY_R600) {
@@ -336,9 +417,9 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
 
 	    pixmap = (*pScreen->CreatePixmap)(pScreen,
 					      aligned_width,
-					      drawable->height,
+					      height,
 					      (format != 0)?format:drawable->depth,
-					      flags);
+					      flags | RADEON_CREATE_PIXMAP_DRI2);
     }
 
     if (!pixmap)
@@ -351,12 +432,15 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
     if (attachment == DRI2BufferDepth) {
         depth_pixmap = pixmap;
     }
-    info->exa_force_create = TRUE;
-    exaMoveInPixmap(pixmap);
-    info->exa_force_create = FALSE;
-    driver_priv = exaGetPixmapDriverPrivate(pixmap);
-    if (!driver_priv ||
-	(radeon_gem_get_kernel_name(driver_priv->bo, &buffers->name) != 0))
+    if (!info->use_glamor) {
+	info->exa_force_create = TRUE;
+	exaMoveInPixmap(pixmap);
+	info->exa_force_create = FALSE;
+    }
+    if (is_glamor_pixmap)
+	pixmap = fixup_glamor(drawable, pixmap);
+    bo = radeon_get_pixmap_bo(pixmap);
+    if (!bo || radeon_gem_get_kernel_name(bo, &buffers->name) != 0)
         goto error;
 
     privates = calloc(1, sizeof(struct dri2_buffer_priv));
@@ -476,11 +560,10 @@ radeon_dri2_copy_region(DrawablePtr drawable,
 	    if (extents->x1 == 0 && extents->y1 == 0 &&
 		extents->x2 == drawable->width &&
 		extents->y2 == drawable->height) {
-		struct radeon_exa_pixmap_priv *exa_priv =
-		    exaGetPixmapDriverPrivate(dst_private->pixmap);
+		struct radeon_bo *bo = radeon_get_pixmap_bo(dst_private->pixmap);
 
-		if (exa_priv && exa_priv->bo)
-		    radeon_bo_wait(exa_priv->bo);
+		if (bo)
+		    radeon_bo_wait(bo);
 	    }
 	}
     }
@@ -643,7 +726,7 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
 			  void *data, unsigned int target_msc)
 {
     struct dri2_buffer_priv *back_priv;
-    struct radeon_exa_pixmap_priv *exa_priv;
+    struct radeon_bo *bo;
     DRI2FrameEventPtr flip_info;
 
     /* Main crtc for this drawable shall finally deliver pageflip event. */
@@ -665,9 +748,9 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
 
     /* Page flip the full screen buffer */
     back_priv = back->driverPrivate;
-    exa_priv = exaGetPixmapDriverPrivate(back_priv->pixmap);
+    bo = radeon_get_pixmap_bo(back_priv->pixmap);
 
-    return radeon_do_pageflip(scrn, exa_priv->bo, flip_info, ref_crtc_hw_id);
+    return radeon_do_pageflip(scrn, bo, flip_info, ref_crtc_hw_id);
 }
 
 static Bool
@@ -675,19 +758,17 @@ update_front(DrawablePtr draw, DRI2BufferPtr front)
 {
     int r;
     PixmapPtr pixmap;
+    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(draw->pScreen));
     struct dri2_buffer_priv *priv = front->driverPrivate;
-    struct radeon_exa_pixmap_priv *driver_priv;
-
-    if (draw->type == DRAWABLE_PIXMAP)
-	pixmap = (PixmapPtr)draw;
-    else
-	pixmap = (*draw->pScreen->GetWindowPixmap)((WindowPtr)draw);
+    struct radeon_bo *bo;
 
+    pixmap = get_drawable_pixmap(draw);
     pixmap->refcnt++;
 
-    exaMoveInPixmap(pixmap);
-    driver_priv = exaGetPixmapDriverPrivate(pixmap);
-    r = radeon_gem_get_kernel_name(driver_priv->bo, &front->name);
+    if (!info->use_glamor)
+	exaMoveInPixmap(pixmap);
+    bo = radeon_get_pixmap_bo(pixmap);
+    r = radeon_gem_get_kernel_name(bo, &front->name);
     if (r) {
 	(*draw->pScreen->DestroyPixmap)(pixmap);
 	return FALSE;
@@ -753,10 +834,9 @@ radeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPt
 {
     struct dri2_buffer_priv *front_priv = front->driverPrivate;
     struct dri2_buffer_priv *back_priv = back->driverPrivate;
-    struct radeon_exa_pixmap_priv *front_radeon, *back_radeon;
+    struct radeon_bo *front_bo, *back_bo;
     ScreenPtr screen;
     RADEONInfoPtr info;
-    struct radeon_bo *bo;
     int tmp;
 
     /* Swap BO names so DRI works */
@@ -765,22 +845,22 @@ radeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPt
     back->name = tmp;
 
     /* Swap pixmap bos */
-    front_radeon = exaGetPixmapDriverPrivate(front_priv->pixmap);
-    back_radeon = exaGetPixmapDriverPrivate(back_priv->pixmap);
-    bo = back_radeon->bo;
-    back_radeon->bo = front_radeon->bo;
-    front_radeon->bo = bo;
+    front_bo = radeon_get_pixmap_bo(front_priv->pixmap);
+    back_bo = radeon_get_pixmap_bo(back_priv->pixmap);
+    radeon_set_pixmap_bo(front_priv->pixmap, back_bo);
+    radeon_set_pixmap_bo(back_priv->pixmap, front_bo);
 
     /* Do we need to update the Screen? */
     screen = draw->pScreen;
     info = RADEONPTR(xf86ScreenToScrn(screen));
-    if (front_radeon->bo == info->front_bo) {
+    if (front_bo == info->front_bo) {
+	radeon_bo_ref(back_bo);
 	radeon_bo_unref(info->front_bo);
-	info->front_bo = back_radeon->bo;
-	radeon_bo_ref(info->front_bo);
-	front_radeon = exaGetPixmapDriverPrivate(screen->GetScreenPixmap(screen));
-        front_radeon->bo = bo;
+	info->front_bo = back_bo;
+	radeon_set_pixmap_bo(screen->GetScreenPixmap(screen), back_bo);
     }
+
+    radeon_glamor_exchange_buffers(front_priv->pixmap, back_priv->pixmap);
 }
 
 void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
diff --git a/src/radeon_exa.c b/src/radeon_exa.c
index d80c7e4..5c5d997 100644
--- a/src/radeon_exa.c
+++ b/src/radeon_exa.c
@@ -325,20 +325,6 @@ void RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv)
     free(driverPriv);
 }
 
-struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix)
-{
-    struct radeon_exa_pixmap_priv *driver_priv;
-    driver_priv = exaGetPixmapDriverPrivate(pPix);
-    return driver_priv->bo;
-}
-
-struct radeon_surface *radeon_get_pixmap_surface(PixmapPtr pPix)
-{
-    struct radeon_exa_pixmap_priv *driver_priv;
-    driver_priv = exaGetPixmapDriverPrivate(pPix);
-    return &driver_priv->surface;
-}
-
 uint32_t radeon_get_pixmap_tiling(PixmapPtr pPix)
 {
     struct radeon_exa_pixmap_priv *driver_priv;
@@ -346,24 +332,6 @@ uint32_t radeon_get_pixmap_tiling(PixmapPtr pPix)
     return driver_priv->tiling_flags;
 }
 
-void radeon_set_pixmap_bo(PixmapPtr pPix, struct radeon_bo *bo)
-{
-    struct radeon_exa_pixmap_priv *driver_priv;
-
-    driver_priv = exaGetPixmapDriverPrivate(pPix);
-    if (driver_priv) {
-	uint32_t pitch;
-
-	if (driver_priv->bo)
-	    radeon_bo_unref(driver_priv->bo);
-
-	radeon_bo_ref(bo);
-	driver_priv->bo = bo;
-
-	radeon_bo_get_tiling(bo, &driver_priv->tiling_flags, &pitch);
-    }
-}
-
 Bool RADEONEXAPixmapIsOffscreen(PixmapPtr pPix)
 {
     struct radeon_exa_pixmap_priv *driver_priv;
diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c
new file mode 100644
index 0000000..232332e
--- /dev/null
+++ b/src/radeon_glamor.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright © 2011 Intel Corporation.
+ *             2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including
+ * the next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xf86.h>
+#define GLAMOR_FOR_XORG  1
+#include <glamor.h>
+
+#include "radeon.h"
+#include "radeon_bo_helper.h"
+
+#if HAS_DEVPRIVATEKEYREC
+DevPrivateKeyRec glamor_pixmap_index;
+#else
+int glamor_pixmap_index;
+#endif
+
+void
+radeon_glamor_exchange_buffers(PixmapPtr src,
+			       PixmapPtr dst)
+{
+	RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(dst->drawable.pScreen));
+
+	if (!info->use_glamor)
+		return;
+	glamor_egl_exchange_buffers(src, dst);
+}
+
+Bool
+radeon_glamor_create_screen_resources(ScreenPtr screen)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	RADEONInfoPtr info = RADEONPTR(scrn);
+
+	if (!info->use_glamor)
+		return TRUE;
+
+	if (!glamor_glyphs_init(screen))
+		return FALSE;
+
+	if (!glamor_egl_create_textured_screen_ext(screen,
+						   info->front_bo->handle,
+						   scrn->displayWidth *
+						   info->pixel_bytes,
+						   NULL))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+Bool
+radeon_glamor_pre_init(ScrnInfoPtr scrn)
+{
+	RADEONInfoPtr info = RADEONPTR(scrn);
+	pointer glamor_module;
+	CARD32 version;
+	const char *s;
+
+	s = xf86GetOptValString(info->Options, OPTION_ACCELMETHOD);
+	if (s == NULL)
+		return FALSE;
+
+	if (strcasecmp(s, "glamor") != 0)
+		return FALSE;
+
+	/* Load glamor module */
+	if ((glamor_module = xf86LoadSubModule(scrn, GLAMOR_EGL_MODULE_NAME))) {
+		version = xf86GetModuleVersion(glamor_module);
+		if (version < MODULE_VERSION_NUMERIC(0,3,1)) {
+			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			"Incompatible glamor version, required >= 0.3.0.\n");
+			return FALSE;
+		} else {
+			if (glamor_egl_init(scrn, info->dri2.drm_fd)) {
+				xf86DrvMsg(scrn->scrnIndex, X_INFO,
+					   "glamor detected, initialising EGL layer.\n");
+			} else {
+				xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+					   "glamor detected, failed to initialize EGL.\n");
+				return FALSE;
+			}
+		}
+	} else {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR, "glamor not available\n");
+		return FALSE;
+	}
+
+	info->use_glamor = TRUE;
+
+	return TRUE;
+}
+
+Bool
+radeon_glamor_create_textured_pixmap(PixmapPtr pixmap)
+{
+	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 (glamor_egl_create_textured_pixmap(pixmap, priv->bo->handle,
+					      priv->stride))
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static PixmapPtr
+radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
+			unsigned usage)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	struct radeon_pixmap *priv;
+	PixmapPtr pixmap, new_pixmap = NULL;
+
+	if (!(usage & RADEON_CREATE_PIXMAP_DRI2)) {
+		pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
+		if (pixmap)
+			return pixmap;
+	}
+
+	if (w > 32767 || h > 32767)
+		return NullPixmap;
+
+	if (depth == 1)
+		return fbCreatePixmap(screen, w, h, depth, usage);
+
+	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32)
+		return fbCreatePixmap(screen, w, h, depth, usage);
+
+	pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
+	if (pixmap == NullPixmap)
+		return pixmap;
+
+	if (w && h) {
+		priv = calloc(1, sizeof (struct radeon_pixmap));
+		if (priv == NULL)
+			goto fallback_pixmap;
+
+		priv->bo = radeon_alloc_pixmap_bo(scrn, w, h, depth, usage,
+						  pixmap->drawable.bitsPerPixel,
+						  &priv->stride,
+						  &priv->surface,
+						  &priv->tiling_flags);
+		if (!priv->bo)
+			goto fallback_priv;
+
+		radeon_set_pixmap_private(pixmap, priv);
+
+		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, priv->stride, NULL);
+
+		if (!radeon_glamor_create_textured_pixmap(pixmap))
+			goto fallback_glamor;
+	}
+
+	return pixmap;
+
+fallback_glamor:
+	if (usage & RADEON_CREATE_PIXMAP_DRI2) {
+	/* XXX need further work to handle the DRI2 failure case.
+	 * Glamor don't know how to handle a BO only pixmap. Put
+	 * a warning indicator here.
+	 */
+		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+			   "Failed to create textured DRI2 pixmap.");
+		return pixmap;
+	}
+	/* Create textured pixmap failed means glamor failed to
+	 * create a texture from current BO for some reasons. We turn
+	 * to create a new glamor pixmap and clean up current one.
+	 * One thing need to be noted, this new pixmap doesn't
+	 * has a priv and bo attached to it. It's glamor's responsbility
+	 * to take care of it. Glamor will mark this new pixmap as a
+	 * texture only pixmap and will never fallback to DDX layer
+	 * afterwards.
+	 */
+	new_pixmap = glamor_create_pixmap(screen, w, h,	depth, usage);
+	radeon_bo_unref(priv->bo);
+fallback_priv:
+	free(priv);
+fallback_pixmap:
+	fbDestroyPixmap(pixmap);
+	if (new_pixmap)
+		return new_pixmap;
+	else
+		return fbCreatePixmap(screen, w, h, depth, usage);
+}
+
+static Bool radeon_glamor_destroy_pixmap(PixmapPtr pixmap)
+{
+	if (pixmap->refcnt == 1) {
+		glamor_egl_destroy_textured_pixmap(pixmap);
+		radeon_set_pixmap_bo(pixmap, NULL);
+	}
+	fbDestroyPixmap(pixmap);
+	return TRUE;
+}
+
+Bool
+radeon_glamor_init(ScreenPtr screen)
+{
+	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+
+	if (!glamor_init(screen, GLAMOR_INVERTED_Y_AXIS | GLAMOR_USE_EGL_SCREEN |
+			 GLAMOR_USE_SCREEN | GLAMOR_USE_PICTURE_SCREEN)) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "Failed to initialize glamor.\n");
+		return FALSE;
+	}
+
+	if (!glamor_egl_init_textured_pixmap(screen)) {
+		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+			   "Failed to initialize textured pixmap of screen for glamor.\n");
+		return FALSE;
+	}
+
+#if HAS_DIXREGISTERPRIVATEKEY
+	if (!dixRegisterPrivateKey(&glamor_pixmap_index, PRIVATE_PIXMAP, 0))
+#else
+	if (!dixRequestPrivate(&glamor_pixmap_index, 0))
+#endif
+		return FALSE;
+
+	screen->CreatePixmap = radeon_glamor_create_pixmap;
+	screen->DestroyPixmap = radeon_glamor_destroy_pixmap;
+
+	xf86DrvMsg(scrn->scrnIndex, X_INFO,
+		   "Use GLAMOR acceleration.\n");
+	return TRUE;
+}
+
+void
+radeon_glamor_flush(ScrnInfoPtr pScrn)
+{
+	RADEONInfoPtr info = RADEONPTR(pScrn);
+
+	if (info->use_glamor)
+		glamor_block_handler(pScrn->pScreen);
+}
diff --git a/src/radeon_glamor.h b/src/radeon_glamor.h
new file mode 100644
index 0000000..40c9092
--- /dev/null
+++ b/src/radeon_glamor.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright © 2011 Intel Corporation.
+ *             2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including
+ * the next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef RADEON_GLAMOR_H
+#define RADEON_GLAMOR_H
+
+#ifdef USE_GLAMOR
+
+#include "radeon_surface.h"
+
+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);
+
+void radeon_glamor_flush(ScrnInfoPtr pScrn);
+
+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);
+
+struct radeon_pixmap {
+	struct radeon_surface surface;
+	struct radeon_bo *bo;
+
+	uint32_t tiling_flags;
+	int stride;
+};
+
+#if HAS_DEVPRIVATEKEYREC
+extern DevPrivateKeyRec glamor_pixmap_index;
+#else
+extern int glamor_pixmap_index;
+#endif
+
+static inline struct radeon_pixmap *radeon_get_pixmap_private(PixmapPtr pixmap)
+{
+#if HAS_DEVPRIVATEKEYREC
+	return dixGetPrivate(&pixmap->devPrivates, &glamor_pixmap_index);
+#else
+	return dixLookupPrivate(&pixmap->devPrivates, &glamor_pixmap_index);
+#endif
+}
+
+static inline void radeon_set_pixmap_private(PixmapPtr pixmap, struct radeon_pixmap *priv)
+{
+	dixSetPrivate(&pixmap->devPrivates, &glamor_pixmap_index, priv);
+}
+
+#else
+
+static inline Bool radeon_glamor_pre_init(ScrnInfoPtr scrn) { return FALSE; }
+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 void radeon_glamor_flush(ScrnInfoPtr pScrn) { }
+
+static inline Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap) { return FALSE; }
+
+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; }
+
+#endif
+
+#endif /* RADEON_GLAMOR_H */
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 61d6419..5d9ccff 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -224,7 +224,7 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen)
 	    return FALSE;
     }
 
-    if (info->dri2.enabled) {
+    if (info->dri2.enabled || info->use_glamor) {
 	if (info->front_bo) {
 	    PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen);
 	    radeon_set_pixmap_bo(pPix, info->front_bo);
@@ -234,6 +234,10 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen)
 	    }
 	}
     }
+
+    if (info->use_glamor)
+	radeon_glamor_create_screen_resources(pScreen);
+
     return TRUE;
 }
 
@@ -247,6 +251,9 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
     (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
     pScreen->BlockHandler = RADEONBlockHandler_KMS;
 
+    if (info->use_glamor)
+	radeon_glamor_flush(pScrn);
+
     radeon_cs_flush_indirect(pScrn);
 }
 
@@ -258,6 +265,7 @@ radeon_flush_callback(CallbackListPtr *list,
 
     if (pScrn->vtSema) {
         radeon_cs_flush_indirect(pScrn);
+	radeon_glamor_flush(pScrn);
     }
 }
 
@@ -416,6 +424,9 @@ static Bool RADEONPreInitAccel_KMS(ScrnInfoPtr pScrn)
 	return TRUE;
     }
 
+    if (radeon_glamor_pre_init(pScrn))
+	return TRUE;
+
     if (info->ChipFamily == CHIP_FAMILY_PALM) {
 	info->accel_state->allowHWDFS = RADEONIsFusionGARTWorking(pScrn);
     } else
@@ -838,16 +849,18 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
 	}
     }
 
-    info->exa_pixmaps = xf86ReturnOptValBool(info->Options,
-                                             OPTION_EXA_PIXMAPS, 
-					     ((info->vram_size > (32 * 1024 * 1024) &&
-					      info->RenderAccel)));
-    if (info->exa_pixmaps)
-    	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-		"EXA: Driver will allow EXA pixmaps in VRAM\n");
-    else
-    	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-		"EXA: Driver will not allow EXA pixmaps in VRAM\n");
+    if (!info->use_glamor) {
+	info->exa_pixmaps = xf86ReturnOptValBool(info->Options,
+						 OPTION_EXA_PIXMAPS,
+						 ((info->vram_size > (32 * 1024 * 1024) &&
+						 info->RenderAccel)));
+	if (info->exa_pixmaps)
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "EXA: Driver will allow EXA pixmaps in VRAM\n");
+	else
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "EXA: Driver will not allow EXA pixmaps in VRAM\n");
+    }
 
     /* no tiled scanout on r6xx+ yet */
     if (info->allowColorTiling) {
@@ -1186,7 +1199,7 @@ Bool RADEONScreenInit_KMS(SCREEN_INIT_ARGS_DECL)
      */
     /* xf86DiDGAInit(pScreen, info->LinearAddr + pScrn->fbOffset); */
 #endif
-    if (info->r600_shadow_fb == FALSE) {
+    if (!info->use_glamor && info->r600_shadow_fb == FALSE) {
         /* Init Xv */
         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
                        "Initializing Xv\n");
@@ -1322,7 +1335,7 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
 	xf86DrvMsg(pScreen->myNum, X_ERROR, "Memory map already initialized\n");
 	return FALSE;
     }
-    if (info->r600_shadow_fb == FALSE) {
+    if (!info->use_glamor && info->r600_shadow_fb == FALSE) {
         info->accel_state->exa = exaDriverAlloc();
         if (info->accel_state->exa == NULL) {
 	    xf86DrvMsg(pScreen->myNum, X_ERROR, "exaDriverAlloc failed\n");
commit 9eac8021f3d33a63156f9f5d43a220e88bb3f8db
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Wed Jun 27 14:48:47 2012 +0200

    EXA: Factor out pixmap BO allocation into a helper function.
    
    Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>

diff --git a/src/Makefile.am b/src/Makefile.am
index 5c09554..e857f21 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,7 +28,8 @@
 
 radeon_drv_la_LIBADD = $(LIBDRM_RADEON_LIBS)
 
-RADEON_KMS_SRCS=radeon_dri2.c radeon_kms.c drmmode_display.c radeon_vbo.c
+RADEON_KMS_SRCS=radeon_dri2.c radeon_kms.c drmmode_display.c radeon_vbo.c \
+	radeon_bo_helper.c
 
 RADEON_EXA_SOURCES = radeon_exa.c r600_exa.c r6xx_accel.c r600_textured_videofuncs.c r600_shader.c radeon_exa_shared.c \
 	evergreen_exa.c evergreen_accel.c evergreen_shader.c evergreen_textured_videofuncs.c cayman_accel.c cayman_shader.c
@@ -82,6 +83,7 @@ EXTRA_DIST = \
 	ati.h \
 	ativersion.h \
 	bicubic_table.h \
+	radeon_bo_helper.h \
 	radeon_drm.h \
 	radeon_exa_render.c \
 	radeon_exa_funcs.c \
diff --git a/src/radeon.h b/src/radeon.h
index 742a6f8..d357dc1 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -665,4 +665,24 @@ enum {
     RADEON_CREATE_PIXMAP_SZBUFFER = 0x80000000, /* for eg */
 };
 
+
+/* Compute log base 2 of val. */
+static __inline__ int
+RADEONLog2(int val)
+{
+	int bits;
+#if (defined __i386__ || defined __x86_64__) && (defined __GNUC__)
+	__asm volatile("bsrl	%1, %0"
+		: "=r" (bits)
+		: "c" (val)
+	);
+	return bits;
+#else
+	for (bits = 0; val != 0; val >>= 1, ++bits)
+		;
+	return bits - 1;
+#endif
+}
+
+
 #endif /* _RADEON_H_ */
diff --git a/src/radeon_bo_helper.c b/src/radeon_bo_helper.c
new file mode 100644
index 0000000..ccdf7eb
--- /dev/null
+++ b/src/radeon_bo_helper.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2012  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "radeon.h"
+
+
+static const unsigned MicroBlockTable[5][3][2] = {
+    /*linear  tiled   square-tiled */
+    {{32, 1}, {8, 4}, {0, 0}}, /*   8 bits per pixel */
+    {{16, 1}, {8, 2}, {4, 4}}, /*  16 bits per pixel */
+    {{ 8, 1}, {4, 2}, {0, 0}}, /*  32 bits per pixel */
+    {{ 4, 1}, {0, 0}, {2, 2}}, /*  64 bits per pixel */
+    {{ 2, 1}, {0, 0}, {0, 0}}  /* 128 bits per pixel */
+};
+
+/* Return true if macrotiling can be enabled */
+static Bool RADEONMacroSwitch(int width, int height, int bpp,
+                              uint32_t flags, Bool rv350_mode)
+{
+    unsigned tilew, tileh, microtiled, logbpp;
+
+    logbpp = RADEONLog2(bpp / 8);
+    if (logbpp > 4)
+        return 0;
+
+    microtiled = !!(flags & RADEON_TILING_MICRO);
+    tilew = MicroBlockTable[logbpp][microtiled][0] * 8;
+    tileh = MicroBlockTable[logbpp][microtiled][1] * 8;
+
+    /* See TX_FILTER1_n.MACRO_SWITCH. */
+    if (rv350_mode) {
+        return width >= tilew && height >= tileh;
+    } else {
+        return width > tilew && height > tileh;
+    }
+}
+
+/* Calculate appropriate tiling and pitch for a pixmap and allocate a BO that
+ * can hold it.
+ */
+struct radeon_bo*
+radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth,
+		       int usage_hint, int bitsPerPixel, int *new_pitch,
+		       struct radeon_surface *new_surface, uint32_t *new_tiling)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    int pitch, base_align;
+    uint32_t size, heighta;
+    int cpp = bitsPerPixel / 8;
+    uint32_t tiling = 0;
+    struct radeon_surface surface;
+    struct radeon_bo *bo;
+
+    if (usage_hint) {
+	if (info->allowColorTiling) {
+	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MACRO)
+		tiling |= RADEON_TILING_MACRO;
+	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MICRO)
+                tiling |= RADEON_TILING_MICRO;
+	}
+	if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH)
+		tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO;
+
+    }
+
+    /* Small pixmaps must not be macrotiled on R300, hw cannot sample them
+     * correctly because samplers automatically switch to macrolinear. */
+    if (info->ChipFamily >= CHIP_FAMILY_R300 &&
+        info->ChipFamily <= CHIP_FAMILY_RS740 &&
+        (tiling & RADEON_TILING_MACRO) &&
+        !RADEONMacroSwitch(width, height, bitsPerPixel, tiling,
+                           info->ChipFamily >= CHIP_FAMILY_RV350)) {
+        tiling &= ~RADEON_TILING_MACRO;
+    }
+
+    heighta = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, tiling));
+    pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp, tiling)) * cpp;
+    base_align = drmmode_get_base_align(pScrn, cpp, tiling);
+    size = RADEON_ALIGN(heighta * pitch, RADEON_GPU_PAGE_SIZE);
+    memset(&surface, 0, sizeof(struct radeon_surface));
+
+    if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
+		if (width) {
+			surface.npix_x = width;
+			/* need to align height to 8 for old kernel */
+			surface.npix_y = RADEON_ALIGN(height, 8);
+			surface.npix_z = 1;
+			surface.blk_w = 1;
+			surface.blk_h = 1;
+			surface.blk_d = 1;
+			surface.array_size = 1;
+			surface.last_level = 0;
+			surface.bpe = cpp;
+			surface.nsamples = 1;
+			if (height < 64) {
+				/* disable 2d tiling for small surface to work around
+				 * the fact that ddx align height to 8 pixel for old
+				 * obscure reason i can't remember
+				 */
+				tiling &= ~RADEON_TILING_MACRO;
+			}
+			surface.flags = RADEON_SURF_SCANOUT;
+			surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
+			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE);
+			if ((tiling & RADEON_TILING_MICRO)) {
+				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
+				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
+			}
+			if ((tiling & RADEON_TILING_MACRO)) {
+				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
+				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
+			}
+			if (usage_hint & RADEON_CREATE_PIXMAP_SZBUFFER) {
+				surface.flags |= RADEON_SURF_ZBUFFER;
+				surface.flags |= RADEON_SURF_SBUFFER;
+			}
+			if (radeon_surface_best(info->surf_man, &surface)) {
+				return NULL;
+			}
+			if (radeon_surface_init(info->surf_man, &surface)) {
+				return NULL;
+			}
+			size = surface.bo_size;
+			base_align = surface.bo_alignment;
+			pitch = surface.level[0].pitch_bytes;
+			tiling = 0;
+			switch (surface.level[0].mode) {
+			case RADEON_SURF_MODE_2D:
+				tiling |= RADEON_TILING_MACRO;
+				tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT;
+				tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT;
+				tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT;
+				tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT;
+				tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT;
+				break;
+			case RADEON_SURF_MODE_1D:
+				tiling |= RADEON_TILING_MICRO;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+    bo = radeon_bo_open(info->bufmgr, 0, size, base_align,
+			RADEON_GEM_DOMAIN_VRAM, 0);
+
+    if (bo && tiling && radeon_bo_set_tiling(bo, tiling, pitch) == 0)
+	*new_tiling = tiling;
+
+    *new_surface = surface;
+    *new_pitch = pitch;
+    return bo;
+}
diff --git a/src/radeon_bo_helper.h b/src/radeon_bo_helper.h
new file mode 100644
index 0000000..0f6fffb
--- /dev/null
+++ b/src/radeon_bo_helper.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012  Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef RADEON_BO_HELPER_H
+#define RADEON_BO_HELPER_H 1
+
+extern struct radeon_bo*
+radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth,
+		       int usage_hint, int bitsPerPixel, int *new_pitch,
+		       struct radeon_surface *new_surface, uint32_t *new_tiling);
+
+#endif /* RADEON_BO_HELPER_H */
diff --git a/src/radeon_exa.c b/src/radeon_exa.c
index 99dc453..d80c7e4 100644
--- a/src/radeon_exa.c
+++ b/src/radeon_exa.c
@@ -37,6 +37,7 @@
 #include "radeon_reg.h"
 #include "r600_reg.h"
 #include "radeon_drm.h"
+#include "radeon_bo_helper.h"
 #include "radeon_probe.h"
 #include "radeon_version.h"
 #include "radeon_exa_shared.h"
@@ -70,24 +71,6 @@ static struct {
     { RADEON_ROP3_ONE,  RADEON_ROP3_ONE  }  /* GXset          */
 };
 
-/* Compute log base 2 of val. */
-static __inline__ int
-RADEONLog2(int val)
-{
-	int bits;
-#if (defined __i386__ || defined __x86_64__) && (defined __GNUC__)
-	__asm volatile("bsrl	%1, %0"
-		: "=r" (bits)
-		: "c" (val)
-	);
-	return bits;
-#else
-	for (bits = 0; val != 0; val >>= 1, ++bits)
-		;
-	return bits - 1;
-#endif
-}
-
 static __inline__ uint32_t F_TO_DW(float val)
 {
     union {
@@ -292,37 +275,6 @@ void *RADEONEXACreatePixmap(ScreenPtr pScreen, int size, int align)
 
 }
 
-static const unsigned MicroBlockTable[5][3][2] = {
-    /*linear  tiled   square-tiled */
-    {{32, 1}, {8, 4}, {0, 0}}, /*   8 bits per pixel */
-    {{16, 1}, {8, 2}, {4, 4}}, /*  16 bits per pixel */
-    {{ 8, 1}, {4, 2}, {0, 0}}, /*  32 bits per pixel */
-    {{ 4, 1}, {0, 0}, {2, 2}}, /*  64 bits per pixel */
-    {{ 2, 1}, {0, 0}, {0, 0}}  /* 128 bits per pixel */
-};
-
-/* Return true if macrotiling can be enabled */
-static Bool RADEONMacroSwitch(int width, int height, int bpp,
-                              uint32_t flags, Bool rv350_mode)
-{
-    unsigned tilew, tileh, microtiled, logbpp;
-
-    logbpp = RADEONLog2(bpp / 8);
-    if (logbpp > 4)
-        return 0;
-
-    microtiled = !!(flags & RADEON_TILING_MICRO);
-    tilew = MicroBlockTable[logbpp][microtiled][0] * 8;
-    tileh = MicroBlockTable[logbpp][microtiled][1] * 8;
-
-    /* See TX_FILTER1_n.MACRO_SWITCH. */
-    if (rv350_mode) {
-        return width >= tilew && height >= tileh;
-    } else {
-        return width > tilew && height > tileh;
-    }
-}
-
 void *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
 			     int depth, int usage_hint, int bitsPerPixel,
 			     int *new_pitch)
@@ -330,11 +282,6 @@ void *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
     RADEONInfoPtr info = RADEONPTR(pScrn);
     struct radeon_exa_pixmap_priv *new_priv;
-    int pitch, base_align;
-    uint32_t size, heighta;
-    uint32_t tiling = 0;
-    int cpp = bitsPerPixel / 8;
-    struct radeon_surface surface;
 
 #ifdef EXA_MIXED_PIXMAPS
     if (info->accel_state->exa->flags & EXA_MIXED_PIXMAPS) {
@@ -344,120 +291,25 @@ void *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
     }
 #endif
 
-    if (usage_hint) {
-	if (info->allowColorTiling) {
-    	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MACRO)
- 	   	tiling |= RADEON_TILING_MACRO;
-    	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MICRO)
-                tiling |= RADEON_TILING_MICRO;
-	}
-	if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH)
- 	   	tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO;
-		
-    }
-
-    /* Small pixmaps must not be macrotiled on R300, hw cannot sample them
-     * correctly because samplers automatically switch to macrolinear. */
-    if (info->ChipFamily >= CHIP_FAMILY_R300 &&
-        info->ChipFamily <= CHIP_FAMILY_RS740 &&
-        (tiling & RADEON_TILING_MACRO) &&
-        !RADEONMacroSwitch(width, height, bitsPerPixel, tiling,
-                           info->ChipFamily >= CHIP_FAMILY_RV350)) {
-        tiling &= ~RADEON_TILING_MACRO;
-    }
-
-    heighta = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, tiling));
-    pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp, tiling)) * cpp;
-    base_align = drmmode_get_base_align(pScrn, cpp, tiling);
-    size = RADEON_ALIGN(heighta * pitch, RADEON_GPU_PAGE_SIZE);
-    memset(&surface, 0, sizeof(struct radeon_surface));
-
-    if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
-		if (width) {
-			surface.npix_x = width;
-			/* need to align height to 8 for old kernel */
-			surface.npix_y = RADEON_ALIGN(height, 8);
-			surface.npix_z = 1;
-			surface.blk_w = 1;
-			surface.blk_h = 1;
-			surface.blk_d = 1;
-			surface.array_size = 1;
-			surface.last_level = 0;
-			surface.bpe = cpp;
-			surface.nsamples = 1;
-			if (height < 64) {
-				/* disable 2d tiling for small surface to work around
-				 * the fact that ddx align height to 8 pixel for old
-				 * obscure reason i can't remember
-				 */
-				tiling &= ~RADEON_TILING_MACRO;
-			}
-			surface.flags = RADEON_SURF_SCANOUT;
-			surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
-			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE);
-			if ((tiling & RADEON_TILING_MICRO)) {
-				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
-				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
-			}
-			if ((tiling & RADEON_TILING_MACRO)) {
-				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
-				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
-			}
-			if (usage_hint & RADEON_CREATE_PIXMAP_SZBUFFER) {
-				surface.flags |= RADEON_SURF_ZBUFFER;
-				surface.flags |= RADEON_SURF_SBUFFER;
-			}
-			if (radeon_surface_best(info->surf_man, &surface)) {
-				return NULL;
-			}
-			if (radeon_surface_init(info->surf_man, &surface)) {
-				return NULL;
-			}
-			size = surface.bo_size;
-			base_align = surface.bo_alignment;
-			pitch = surface.level[0].pitch_bytes;
-			tiling = 0;
-			switch (surface.level[0].mode) {
-			case RADEON_SURF_MODE_2D:
-				tiling |= RADEON_TILING_MACRO;
-				tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT;
-				tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT;
-				tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT;
-				tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT;
-				tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT;
-				break;
-			case RADEON_SURF_MODE_1D:
-				tiling |= RADEON_TILING_MICRO;
-				break;
-			default:
-				break;
-			}
-		}
-	}
-
     new_priv = calloc(1, sizeof(struct radeon_exa_pixmap_priv));
     if (!new_priv) {
 	return NULL;
     }
 
-    if (size == 0) {
+    if (width == 0 || height == 0) {
 	return new_priv;
     }
 
-    *new_pitch = pitch;
-
-    new_priv->bo = radeon_bo_open(info->bufmgr, 0, size, base_align,
-				  RADEON_GEM_DOMAIN_VRAM, 0);
+    new_priv->bo = radeon_alloc_pixmap_bo(pScrn, width, height, depth,
+					  usage_hint, bitsPerPixel, new_pitch,
+					  &new_priv->surface,
+					  &new_priv->tiling_flags);
     if (!new_priv->bo) {
 	free(new_priv);
 	ErrorF("Failed to alloc memory\n");
 	return NULL;
     }
 
-    if (tiling && !radeon_bo_set_tiling(new_priv->bo, tiling, *new_pitch))
-	new_priv->tiling_flags = tiling;
-
-    new_priv->surface = surface;
     return new_priv;
 }
 


More information about the xorg-commit mailing list