[PATCH] Initial SI support. (v2)

alexdeucher at gmail.com alexdeucher at gmail.com
Tue Jul 10 07:07:53 PDT 2012


From: Michel Dänzer <michel.daenzer at amd.com>

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

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
 man/radeon.man                    |    6 +
 src/Makefile.am                   |    2 +
 src/ati_pciids_gen.h              |   39 +
 src/pcidb/ati_pciids.csv          |   39 +
 src/radeon_chipinfo_gen.h         |   39 +
 src/radeon_chipset_gen.h          |   39 +
 src/radeon_dri2.c                 |    4 +-
 src/radeon_glamor.c               |   88 ++-
 src/radeon_glamor.h               |    5 +
 src/radeon_glamor_wrappers.c      | 1870 +++++++++++++++++++++++++++++++++++++
 src/radeon_glamor_wrappers.h      |  179 ++++
 src/radeon_kms.c                  |    5 +-
 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 +
 16 files changed, 2390 insertions(+), 7 deletions(-)
 create mode 100644 src/radeon_glamor_wrappers.c
 create mode 100644 src/radeon_glamor_wrappers.h

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
-- 
1.7.7.5



More information about the xorg-driver-ati mailing list