From: Michel Dänzer <[email protected]>

They can choose between using the GPU or CPU for the operation.

(cherry picked from radeon commits eea79472a84672ee4dc7adc4487cec6a4037048a
and e58fc380ccf2a581d28f041fd74b963626ca5404)

Signed-off-by: Darren Powell <[email protected]>
Signed-off-by: Michel Dänzer <[email protected]>
---
 src/Makefile.am              |   1 +
 src/amdgpu_bo_helper.c       |   3 -
 src/amdgpu_drv.h             |  26 ++
 src/amdgpu_glamor.c          |   4 +-
 src/amdgpu_glamor_wrappers.c | 992 +++++++++++++++++++++++++++++++++++++++++++
 src/amdgpu_pixmap.h          |   3 +
 6 files changed, 1025 insertions(+), 4 deletions(-)
 create mode 100644 src/amdgpu_glamor_wrappers.c

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

_______________________________________________
xorg-driver-ati mailing list
[email protected]
http://lists.x.org/mailman/listinfo/xorg-driver-ati

Reply via email to