xserver: Branch 'master' - 30 commits

Keith Packard keithp at kemper.freedesktop.org
Mon Jul 9 09:27:34 PDT 2012


 configure.ac                        |    4 
 dix/dispatch.c                      |   57 ++
 dix/pixmap.c                        |  135 ++++++
 exa/exa.c                           |    7 
 exa/exa.h                           |    6 
 exa/exa_mixed.c                     |   33 +
 exa/exa_priv.h                      |    7 
 glx/glxdri2.c                       |    2 
 hw/xfree86/common/xf86DGA.c         |   15 
 hw/xfree86/common/xf86Init.c        |    3 
 hw/xfree86/common/xf86platformBus.c |    9 
 hw/xfree86/common/xf86str.h         |    1 
 hw/xfree86/dixmods/extmod/dgaproc.h |    1 
 hw/xfree86/dri2/dri2.c              |  292 +++++++++++++-
 hw/xfree86/dri2/dri2.h              |   25 +
 hw/xfree86/dri2/dri2ext.c           |    4 
 hw/xfree86/modes/xf86Crtc.c         |   54 ++
 hw/xfree86/modes/xf86Crtc.h         |   48 ++
 hw/xfree86/modes/xf86DiDGA.c        |    2 
 hw/xfree86/modes/xf86RandR12.c      |  122 ++++++
 hw/xfree86/modes/xf86Rotate.c       |    6 
 hw/xfree86/ramdac/xf86Cursor.c      |    2 
 hw/xfree86/vgahw/vgaCmap.c          |    2 
 include/pixmap.h                    |   19 
 include/pixmapstr.h                 |   30 +
 include/screenint.h                 |   17 
 include/scrnintstr.h                |   34 +
 randr/Makefile.am                   |    2 
 randr/randr.c                       |   85 +++-
 randr/randrstr.h                    |  131 ++++++
 randr/rrcrtc.c                      |  298 ++++++++++++++
 randr/rrdispatch.c                  |   14 
 randr/rrprovider.c                  |  411 ++++++++++++++++++++
 randr/rrproviderproperty.c          |  716 ++++++++++++++++++++++++++++++++++++
 randr/rrscreen.c                    |  169 ++++++++
 35 files changed, 2698 insertions(+), 65 deletions(-)

New commits:
commit 329db3292223cccd4887062956622285c45a1523
Author: Dave Airlie <airlied at redhat.com>
Date:   Sat Jul 7 10:10:08 2012 +0100

    dri2/prime: allocate prime id at screen allocation time
    
    Add a static mask of prime id and allocate them at screen time,
    if the driver supports the prime interfaces and is a gpu screen.
    
    This is instead of them changing due to user controlled randr commands,
    as suggested by Keith.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index 87158ff..887ce46 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -51,6 +51,8 @@
 CARD8 dri2_major;               /* version of DRI2 supported by DDX */
 CARD8 dri2_minor;
 
+uint32_t prime_id_allocate_bitmask;
+
 static DevPrivateKeyRec dri2ScreenPrivateKeyRec;
 
 #define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec)
@@ -111,6 +113,7 @@ typedef struct _DRI2Screen {
     const char *deviceName;
     int fd;
     unsigned int lastSequence;
+    int prime_id;
 
     DRI2CreateBufferProcPtr CreateBuffer;
     DRI2DestroyBufferProcPtr DestroyBuffer;
@@ -145,16 +148,15 @@ static ScreenPtr
 GetScreenPrime(ScreenPtr master, int prime_id)
 {
     ScreenPtr slave;
-    int i;
-
     if (prime_id == 0 || xorg_list_is_empty(&master->offload_slave_list)) {
         return master;
     }
-    i = 0;
     xorg_list_for_each_entry(slave, &master->offload_slave_list, offload_head) {
-        if (i == (prime_id - 1))
+        DRI2ScreenPtr ds;
+
+        ds = DRI2GetScreen(slave);
+        if (ds->prime_id == prime_id)
             break;
-        i++;
     }
     if (!slave)
         return master;
@@ -1372,6 +1374,22 @@ DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw,
     return Success;
 }
 
+#define MAX_PRIME DRI2DriverPrimeMask
+static int
+get_prime_id(void)
+{
+    int i;
+    /* start at 1, prime id 0 is just normal driver */
+    for (i = 1; i < MAX_PRIME; i++) {
+         if (prime_id_allocate_bitmask & (1 << i))
+             continue;
+
+         prime_id_allocate_bitmask |= (1 << i);
+         return i;
+    }
+    return -1;
+}
+
 Bool
 DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
 {
@@ -1447,6 +1465,13 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
 
     if (info->version >= 9) {
         ds->CreateBuffer2 = info->CreateBuffer2;
+        if (info->CreateBuffer2 && pScreen->isGPU) {
+            ds->prime_id = get_prime_id();
+            if (ds->prime_id == -1) {
+                free(ds);
+                return FALSE;
+            }
+        }
         ds->DestroyBuffer2 = info->DestroyBuffer2;
         ds->CopyRegion2 = info->CopyRegion2;
     }
@@ -1520,6 +1545,8 @@ DRI2CloseScreen(ScreenPtr pScreen)
 
     pScreen->ConfigNotify = ds->ConfigNotify;
 
+    if (ds->prime_id)
+        prime_id_allocate_bitmask &= ~(1 << ds->prime_id);
     free(ds->driverNames);
     free(ds);
     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL);
commit 30298012162de7f76e8a4c7b0362e98703f80011
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Jun 26 10:20:52 2012 +0100

    dri2: add initial prime support. (v1.2)
    
    This adds the initial prime support for dri2 offload. The main thing is
    when we get a connection from a prime client, we stored the information
    and mark all drawables from that client as prime. We then create all
    buffers for that drawable on the prime device dri2screen.
    
    Then DRI2UpdatePrime is provided which drivers can call to get a shared
    pixmap which they can use as the front buffer. The driver is then
    responsible for doing the back->front copy to the shared buffer.
    
    prime requires a compositing manager be run, but it handles the case where
    a window get un-redirected by allocating a new pixmap and pointing the crtc
    at it while the client is in that state.
    
    Currently prime can't handle pageflipping, so always does straight copy swap,
    
    v1.1: renumber on top of master.
    v1.2: fix auth on top of master.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/glx/glxdri2.c b/glx/glxdri2.c
index 1e99179..e0f4cf7 100644
--- a/glx/glxdri2.c
+++ b/glx/glxdri2.c
@@ -929,7 +929,7 @@ __glXDRIscreenProbe(ScreenPtr pScreen)
         return NULL;
 
     if (!xf86LoaderCheckSymbol("DRI2Connect") ||
-        !DRI2Connect(pScreen, DRI2DriverDRI,
+        !DRI2Connect(serverClient, pScreen, DRI2DriverDRI,
                      &screen->fd, &driverName, &deviceName)) {
         LogMessage(X_INFO,
                    "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum);
diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index d3b3c73..87158ff 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -45,7 +45,7 @@
 #include "dixstruct.h"
 #include "dri2.h"
 #include "xf86VGAarbiter.h"
-
+#include "damage.h"
 #include "xf86.h"
 
 CARD8 dri2_major;               /* version of DRI2 supported by DDX */
@@ -63,6 +63,17 @@ static DevPrivateKeyRec dri2PixmapPrivateKeyRec;
 
 #define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec)
 
+static DevPrivateKeyRec dri2ClientPrivateKeyRec;
+
+#define dri2ClientPrivateKey (&dri2ClientPrivateKeyRec)
+
+#define dri2ClientPrivate(_pClient) (dixLookupPrivate(&(_pClient)->devPrivates, \
+                                                      dri2ClientPrivateKey))
+
+typedef struct _DRI2Client {
+    int prime_id;
+} DRI2ClientRec, *DRI2ClientPtr;
+
 static RESTYPE dri2DrawableRes;
 
 typedef struct _DRI2Screen *DRI2ScreenPtr;
@@ -87,6 +98,9 @@ typedef struct _DRI2Drawable {
     int swap_limit;             /* for N-buffering */
     unsigned long serialNumber;
     Bool needInvalidate;
+    int prime_id;
+    PixmapPtr prime_slave_pixmap;
+    PixmapPtr redirectpixmap;
 } DRI2DrawableRec, *DRI2DrawablePtr;
 
 typedef struct _DRI2Screen {
@@ -113,14 +127,47 @@ typedef struct _DRI2Screen {
     HandleExposuresProcPtr HandleExposures;
 
     ConfigNotifyProcPtr ConfigNotify;
+    DRI2CreateBuffer2ProcPtr CreateBuffer2;
+    DRI2DestroyBuffer2ProcPtr DestroyBuffer2;
+    DRI2CopyRegion2ProcPtr CopyRegion2;
 } DRI2ScreenRec;
 
+static void
+destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id);
+
 static DRI2ScreenPtr
 DRI2GetScreen(ScreenPtr pScreen)
 {
     return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey);
 }
 
+static ScreenPtr
+GetScreenPrime(ScreenPtr master, int prime_id)
+{
+    ScreenPtr slave;
+    int i;
+
+    if (prime_id == 0 || xorg_list_is_empty(&master->offload_slave_list)) {
+        return master;
+    }
+    i = 0;
+    xorg_list_for_each_entry(slave, &master->offload_slave_list, offload_head) {
+        if (i == (prime_id - 1))
+            break;
+        i++;
+    }
+    if (!slave)
+        return master;
+    return slave;
+}
+
+static DRI2ScreenPtr
+DRI2GetScreenPrime(ScreenPtr master, int prime_id)
+{
+    ScreenPtr slave = GetScreenPrime(master, prime_id);
+    return DRI2GetScreen(slave);
+}
+
 static DRI2DrawablePtr
 DRI2GetDrawable(DrawablePtr pDraw)
 {
@@ -187,7 +234,8 @@ DRI2AllocateDrawable(DrawablePtr pDraw)
     xorg_list_init(&pPriv->reference_list);
     pPriv->serialNumber = DRI2DrawableSerial(pDraw);
     pPriv->needInvalidate = FALSE;
-
+    pPriv->redirectpixmap = NULL;
+    pPriv->prime_slave_pixmap = NULL;
     if (pDraw->type == DRAWABLE_WINDOW) {
         pWin = (WindowPtr) pDraw;
         dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv);
@@ -286,6 +334,7 @@ DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
                    DRI2InvalidateProcPtr invalidate, void *priv)
 {
     DRI2DrawablePtr pPriv;
+    DRI2ClientPtr dri2_client = dri2ClientPrivate(client);
     XID dri2_id;
     int rc;
 
@@ -295,6 +344,8 @@ DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
     if (pPriv == NULL)
         return BadAlloc;
 
+    pPriv->prime_id = dri2_client->prime_id;
+
     dri2_id = FakeClientID(client->index);
     rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv);
     if (rc != Success)
@@ -307,7 +358,6 @@ static int
 DRI2DrawableGone(pointer p, XID id)
 {
     DRI2DrawablePtr pPriv = p;
-    DRI2ScreenPtr ds = pPriv->dri2_screen;
     DRI2DrawableRefPtr ref, next;
     WindowPtr pWin;
     PixmapPtr pPixmap;
@@ -347,16 +397,52 @@ DRI2DrawableGone(pointer p, XID id)
 
     if (pPriv->buffers != NULL) {
         for (i = 0; i < pPriv->bufferCount; i++)
-            (*ds->DestroyBuffer) (pDraw, pPriv->buffers[i]);
+            destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
 
         free(pPriv->buffers);
     }
 
+    if (pPriv->redirectpixmap) {
+        (*pDraw->pScreen->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
+        (*pDraw->pScreen->DestroyPixmap)(pPriv->redirectpixmap);
+    }
+
     free(pPriv);
 
     return Success;
 }
 
+static DRI2BufferPtr
+create_buffer(DrawablePtr pDraw,
+              unsigned int attachment, unsigned int format)
+{
+    ScreenPtr primeScreen;
+    DRI2DrawablePtr pPriv;
+    DRI2ScreenPtr ds;
+    DRI2BufferPtr buffer;
+    pPriv = DRI2GetDrawable(pDraw);
+    primeScreen = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
+    ds = DRI2GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
+    if (ds->CreateBuffer2)
+        buffer = (*ds->CreateBuffer2)(primeScreen, pDraw, attachment, format);
+    else
+        buffer = (*ds->CreateBuffer)(pDraw, attachment, format);
+    return buffer;
+}
+
+static void
+destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id)
+{
+    ScreenPtr primeScreen;
+    DRI2ScreenPtr ds;
+    primeScreen = GetScreenPrime(pDraw->pScreen, prime_id);
+    ds = DRI2GetScreen(primeScreen);
+    if (ds->DestroyBuffer2)
+        (*ds->DestroyBuffer2)(primeScreen, pDraw, buffer);
+    else
+        (*ds->DestroyBuffer)(pDraw, buffer);
+}
+
 static int
 find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
 {
@@ -387,7 +473,7 @@ allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
     if ((old_buf < 0)
         || attachment == DRI2BufferFrontLeft
         || !dimensions_match || (pPriv->buffers[old_buf]->format != format)) {
-        *buffer = (*ds->CreateBuffer) (pDraw, attachment, format);
+        *buffer = create_buffer (pDraw, attachment, format);
         pPriv->serialNumber = DRI2DrawableSerial(pDraw);
         return TRUE;
 
@@ -408,13 +494,12 @@ update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
                              DRI2BufferPtr * buffers, int out_count, int *width,
                              int *height)
 {
-    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
     int i;
 
     if (pPriv->buffers != NULL) {
         for (i = 0; i < pPriv->bufferCount; i++) {
             if (pPriv->buffers[i] != NULL) {
-                (*ds->DestroyBuffer) (pDraw, pPriv->buffers[i]);
+                destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
             }
         }
 
@@ -434,8 +519,8 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height,
                unsigned int *attachments, int count, int *out_count,
                int has_format)
 {
-    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
+    DRI2ScreenPtr ds;
     DRI2BufferPtr *buffers;
     int need_real_front = 0;
     int need_fake_front = 0;
@@ -452,6 +537,8 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height,
         return NULL;
     }
 
+    ds = DRI2GetScreen(pDraw->pScreen);
+
     dimensions_match = (pDraw->width == pPriv->width)
         && (pDraw->height == pPriv->height)
         && (pPriv->serialNumber == DRI2DrawableSerial(pDraw));
@@ -556,7 +643,7 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height,
     if (buffers) {
         for (i = 0; i < count; i++) {
             if (buffers[i] != NULL)
-                (*ds->DestroyBuffer) (pDraw, buffers[i]);
+                destroy_buffer(pDraw, buffers[i], 0);
         }
 
         free(buffers);
@@ -650,11 +737,118 @@ DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
     pPriv->blockedOnMsc = TRUE;
 }
 
+static inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable)
+{
+    if (drawable->type == DRAWABLE_PIXMAP)
+        return (PixmapPtr)drawable;
+    else {
+        struct _Window *pWin = (struct _Window *)drawable;
+        return drawable->pScreen->GetWindowPixmap(pWin);
+    }
+}
+
+DrawablePtr DRI2UpdatePrime(DrawablePtr pDraw, DRI2BufferPtr pDest)
+{
+    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
+    PixmapPtr spix;
+    PixmapPtr mpix = GetDrawablePixmap(pDraw);
+    ScreenPtr master, slave;
+    Bool ret;
+
+    master = mpix->drawable.pScreen;
+
+    if (pDraw->type == DRAWABLE_WINDOW) {
+        WindowPtr pWin = (WindowPtr)pDraw;
+        PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin);
+
+        if (pDraw->pScreen->GetScreenPixmap(pDraw->pScreen) == pPixmap) {
+            if (pPriv->redirectpixmap &&
+                pPriv->redirectpixmap->drawable.width == pDraw->width &&
+                pPriv->redirectpixmap->drawable.height == pDraw->height &&
+                pPriv->redirectpixmap->drawable.depth == pDraw->depth) {
+                mpix = pPriv->redirectpixmap;
+            } else {
+                if (master->ReplaceScanoutPixmap) {
+                    mpix = (*master->CreatePixmap)(master, pDraw->width, pDraw->height,
+                                                   pDraw->depth, CREATE_PIXMAP_USAGE_SHARED);
+                    if (!mpix)
+                        return NULL;
+
+                    ret = (*master->ReplaceScanoutPixmap)(pDraw, mpix, TRUE);
+                    if (ret == FALSE) {
+                        (*master->DestroyPixmap)(mpix);
+                        return NULL;
+                    }
+                    pPriv->redirectpixmap = mpix;
+                } else
+                    return NULL;
+            }
+        } else if (pPriv->redirectpixmap) {
+            (*master->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
+            (*master->DestroyPixmap)(pPriv->redirectpixmap);
+            pPriv->redirectpixmap = NULL;
+        }
+    }
+
+    slave = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
+
+    /* check if the pixmap is still fine */
+    if (pPriv->prime_slave_pixmap) {
+        if (pPriv->prime_slave_pixmap->master_pixmap == mpix)
+            return &pPriv->prime_slave_pixmap->drawable;
+        else {
+            (*master->DestroyPixmap)(pPriv->prime_slave_pixmap->master_pixmap);
+            (*slave->DestroyPixmap)(pPriv->prime_slave_pixmap);
+        }
+    }
+
+    spix = PixmapShareToSlave(mpix, slave);
+    if (!spix)
+        return NULL;
+
+    pPriv->prime_slave_pixmap = spix;
+#ifdef COMPOSITE
+    spix->screen_x = mpix->screen_x;
+    spix->screen_y = mpix->screen_y;
+#endif
+    return &spix->drawable;
+}
+
+static void dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
+                             DRI2BufferPtr pDest, DRI2BufferPtr pSrc)
+{
+    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
+    DRI2ScreenPtr ds;
+    ScreenPtr primeScreen;
+
+    primeScreen = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
+    ds = DRI2GetScreen(primeScreen);
+
+    if (ds->CopyRegion2)
+        (*ds->CopyRegion2)(primeScreen, pDraw, pRegion, pDest, pSrc);
+    else
+        (*ds->CopyRegion) (pDraw, pRegion, pDest, pSrc);
+
+    /* cause damage to the box */
+    if (pPriv->prime_id) {
+       BoxRec box;
+       RegionRec region;
+       box.x1 = 0;
+       box.x2 = box.x1 + pDraw->width;
+       box.y1 = 0;
+       box.y2 = box.y1 + pDraw->height;
+       RegionInit(&region, &box, 1);
+       RegionTranslate(&region, pDraw->x, pDraw->y);
+       DamageRegionAppend(pDraw, &region);
+       DamageRegionProcessPending(pDraw);
+       RegionUninit(&region);
+    }
+}
+
 int
 DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
                unsigned int dest, unsigned int src)
 {
-    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
     DRI2DrawablePtr pPriv;
     DRI2BufferPtr pDestBuffer, pSrcBuffer;
     int i;
@@ -674,7 +868,7 @@ DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
     if (pSrcBuffer == NULL || pDestBuffer == NULL)
         return BadValue;
 
-    (*ds->CopyRegion) (pDraw, pRegion, pDestBuffer, pSrcBuffer);
+    dri2_copy_region(pDraw, pRegion, pDestBuffer, pSrcBuffer);
 
     return Success;
 }
@@ -879,7 +1073,7 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
     }
 
     /* Old DDX or no swap interval, just blit */
-    if (!ds->ScheduleSwap || !pPriv->swap_interval) {
+    if (!ds->ScheduleSwap || !pPriv->swap_interval || pPriv->prime_id) {
         BoxRec box;
         RegionRec region;
 
@@ -891,7 +1085,7 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
 
         pPriv->swapsPending++;
 
-        (*ds->CopyRegion) (pDraw, &region, pDestBuffer, pSrcBuffer);
+        dri2_copy_region(pDraw, &region, pDestBuffer, pSrcBuffer);
         DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
                          func, data);
         return Success;
@@ -1091,22 +1285,34 @@ DRI2HasSwapControl(ScreenPtr pScreen)
 }
 
 Bool
-DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd,
+DRI2Connect(ClientPtr client, ScreenPtr pScreen,
+            unsigned int driverType, int *fd,
             const char **driverName, const char **deviceName)
 {
     DRI2ScreenPtr ds;
+    uint32_t prime_id = DRI2DriverPrimeId(driverType);
+    uint32_t driver_id = driverType & 0xffff;
 
     if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
         return FALSE;
 
-    ds = DRI2GetScreen(pScreen);
-    if (ds == NULL || driverType >= ds->numDrivers ||
-        !ds->driverNames[driverType])
+    ds = DRI2GetScreenPrime(pScreen, prime_id);
+    if (ds == NULL)
         return FALSE;
 
-    *fd = ds->fd;
-    *driverName = ds->driverNames[driverType];
+    if (driver_id >= ds->numDrivers ||
+        !ds->driverNames[driver_id])
+        return FALSE;
+
+    *driverName = ds->driverNames[driver_id];
     *deviceName = ds->deviceName;
+    *fd = ds->fd;
+
+    if (client) {
+        DRI2ClientPtr dri2_client;
+        dri2_client = dri2ClientPrivate(client);
+        dri2_client->prime_id = prime_id;
+    }
 
     return TRUE;
 }
@@ -1122,13 +1328,19 @@ DRI2AuthMagic (ScreenPtr pScreen, uint32_t magic)
 }
 
 Bool
-DRI2Authenticate(ScreenPtr pScreen, uint32_t magic)
+DRI2Authenticate(ClientPtr client, ScreenPtr pScreen, uint32_t magic)
 {
-    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
+    DRI2ScreenPtr ds;
+    DRI2ClientPtr dri2_client = dri2ClientPrivate(client);
+    ScreenPtr primescreen;
 
-    if (ds == NULL || (*ds->AuthMagic) (pScreen, magic))
+    ds = DRI2GetScreenPrime(pScreen, dri2_client->prime_id);
+    if (ds == NULL)
         return FALSE;
 
+    primescreen = GetScreenPrime(pScreen, dri2_client->prime_id);
+    if ((*ds->AuthMagic)(primescreen, magic))
+        return FALSE;
     return TRUE;
 }
 
@@ -1190,6 +1402,9 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
     if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
         return FALSE;
 
+    if (!dixRegisterPrivateKey(&dri2ClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DRI2ClientRec)))
+        return FALSE;
+
     ds = calloc(1, sizeof *ds);
     if (!ds)
         return FALSE;
@@ -1230,6 +1445,12 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
         cur_minor = 4;
     }
 
+    if (info->version >= 9) {
+        ds->CreateBuffer2 = info->CreateBuffer2;
+        ds->DestroyBuffer2 = info->DestroyBuffer2;
+        ds->CopyRegion2 = info->CopyRegion2;
+    }
+
     /*
      * if the driver doesn't provide an AuthMagic function or the info struct
      * version is too low, call through LegacyAuthMagic
diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h
index 4fd0fbc..a59e680 100644
--- a/hw/xfree86/dri2/dri2.h
+++ b/hw/xfree86/dri2/dri2.h
@@ -176,6 +176,18 @@ typedef void (*DRI2InvalidateProcPtr) (DrawablePtr pDraw, void *data, XID id);
 typedef Bool (*DRI2SwapLimitValidateProcPtr) (DrawablePtr pDraw,
                                               int swap_limit);
 
+typedef DRI2BufferPtr(*DRI2CreateBuffer2ProcPtr) (ScreenPtr pScreen,
+                                                  DrawablePtr pDraw,
+                                                  unsigned int attachment,
+                                                  unsigned int format);
+typedef void (*DRI2DestroyBuffer2ProcPtr) (ScreenPtr pScreen, DrawablePtr pDraw,
+                                          DRI2BufferPtr buffer);
+
+typedef void (*DRI2CopyRegion2ProcPtr) (ScreenPtr pScreen, DrawablePtr pDraw,
+                                        RegionPtr pRegion,
+                                        DRI2BufferPtr pDestBuffer,
+                                        DRI2BufferPtr pSrcBuffer);
+
 /**
  * \brief Get the value of a parameter.
  *
@@ -193,7 +205,7 @@ typedef int (*DRI2GetParamProcPtr) (ClientPtr client,
 /**
  * Version of the DRI2InfoRec structure defined in this header
  */
-#define DRI2INFOREC_VERSION 8
+#define DRI2INFOREC_VERSION 9
 
 typedef struct {
     unsigned int version;       /**< Version of this struct */
@@ -228,7 +240,6 @@ typedef struct {
     DRI2SwapLimitValidateProcPtr SwapLimitValidate;
 
     /* added in version 7 */
-
     DRI2GetParamProcPtr GetParam;
 
     /* added in version 8 */
@@ -236,6 +247,11 @@ typedef struct {
     /* If this is NULL the AuthMagic callback is used */
     /* If this is non-NULL the AuthMagic callback is ignored */
     DRI2AuthMagic2ProcPtr AuthMagic2;
+
+    /* added in version 9 */
+    DRI2CreateBuffer2ProcPtr CreateBuffer2;
+    DRI2DestroyBuffer2ProcPtr DestroyBuffer2;
+    DRI2CopyRegion2ProcPtr CopyRegion2;
 } DRI2InfoRec, *DRI2InfoPtr;
 
 extern _X_EXPORT int DRI2EventBase;
@@ -246,13 +262,13 @@ extern _X_EXPORT void DRI2CloseScreen(ScreenPtr pScreen);
 
 extern _X_EXPORT Bool DRI2HasSwapControl(ScreenPtr pScreen);
 
-extern _X_EXPORT Bool DRI2Connect(ScreenPtr pScreen,
+extern _X_EXPORT Bool DRI2Connect(ClientPtr client, ScreenPtr pScreen,
                                   unsigned int driverType,
                                   int *fd,
                                   const char **driverName,
                                   const char **deviceName);
 
-extern _X_EXPORT Bool DRI2Authenticate(ScreenPtr pScreen, uint32_t magic);
+extern _X_EXPORT Bool DRI2Authenticate(ClientPtr client, ScreenPtr pScreen, uint32_t magic);
 
 extern _X_EXPORT int DRI2CreateDrawable(ClientPtr client,
                                         DrawablePtr pDraw,
@@ -339,4 +355,5 @@ extern _X_EXPORT int DRI2GetParam(ClientPtr client,
                                   BOOL *is_param_recognized,
                                   CARD64 *value);
 
+extern _X_EXPORT DrawablePtr DRI2UpdatePrime(DrawablePtr pDraw, DRI2BufferPtr pDest);
 #endif
diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c
index c6f5b4e..3bc3ea7 100644
--- a/hw/xfree86/dri2/dri2ext.c
+++ b/hw/xfree86/dri2/dri2ext.c
@@ -116,7 +116,7 @@ ProcDRI2Connect(ClientPtr client)
     rep.driverNameLength = 0;
     rep.deviceNameLength = 0;
 
-    if (!DRI2Connect(pDraw->pScreen,
+    if (!DRI2Connect(client, pDraw->pScreen,
                      stuff->driverType, &fd, &driverName, &deviceName))
         goto fail;
 
@@ -149,7 +149,7 @@ ProcDRI2Authenticate(ClientPtr client)
     rep.type = X_Reply;
     rep.sequenceNumber = client->sequence;
     rep.length = 0;
-    rep.authenticated = DRI2Authenticate(pDraw->pScreen, stuff->magic);
+    rep.authenticated = DRI2Authenticate(client, pDraw->pScreen, stuff->magic);
     WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep);
 
     return Success;
commit 234022cfb3ad2a1b16ab7981ce69f9cd5ba0fbeb
Author: Dave Airlie <airlied at redhat.com>
Date:   Sat Jul 7 10:20:58 2012 +0100

    configure: bump dri2proto to 2.8
    
    This is required for the prime macros.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/configure.ac b/configure.ac
index 2442bac..74e7e9a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -775,7 +775,7 @@ RECORDPROTO="recordproto >= 1.13.99.1"
 SCRNSAVERPROTO="scrnsaverproto >= 1.1"
 RESOURCEPROTO="resourceproto >= 1.2.0"
 DRIPROTO="xf86driproto >= 2.1.0"
-DRI2PROTO="dri2proto >= 2.7"
+DRI2PROTO="dri2proto >= 2.8"
 XINERAMAPROTO="xineramaproto"
 BIGFONTPROTO="xf86bigfontproto >= 1.2.0"
 DGAPROTO="xf86dgaproto >= 2.0.99.1"
commit c41922940adbc8891575b3321fadf01ff4cb5854
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Jun 26 10:00:21 2012 +0100

    dix/randr: add a hook into screen to replace scanout pixmap
    
    For DRI2 in some offload cases we need to set a new pixmap on the crtc,
    this hook allows dri2 to call into randr to do the necessary work to set
    a pixmap as the scanout pixmap for the crtc the drawable is currently on.
    
    This is really only to be used for unredirected full screen apps in composited
    environments.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index 80601b9..df74073 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -351,6 +351,8 @@ typedef Bool (*StartPixmapTrackingProcPtr)(PixmapPtr, PixmapPtr,
 
 typedef Bool (*StopPixmapTrackingProcPtr)(PixmapPtr, PixmapPtr);
 
+typedef Bool (*ReplaceScanoutPixmapProcPtr)(DrawablePtr, PixmapPtr, Bool);
+
 typedef struct _Screen {
     int myNum;                  /* index of this instance in Screens[] */
     ATOM id;
@@ -510,6 +512,7 @@ typedef struct _Screen {
     struct xorg_list offload_slave_list;
     struct xorg_list offload_head;
 
+    ReplaceScanoutPixmapProcPtr ReplaceScanoutPixmap;
 } ScreenRec;
 
 static inline RegionPtr
diff --git a/randr/randr.c b/randr/randr.c
index ae81166..3050c54 100644
--- a/randr/randr.c
+++ b/randr/randr.c
@@ -324,7 +324,7 @@ RRScreenInit(ScreenPtr pScreen)
     wrap(pScrPriv, pScreen, CloseScreen, RRCloseScreen);
 
     pScreen->ConstrainCursorHarder = RRConstrainCursorHarder;
-
+    pScreen->ReplaceScanoutPixmap = RRReplaceScanoutPixmap;
     pScrPriv->numOutputs = 0;
     pScrPriv->outputs = NULL;
     pScrPriv->numCrtcs = 0;
diff --git a/randr/randrstr.h b/randr/randrstr.h
index 16e7d01..62b9050 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -673,6 +673,9 @@ extern _X_EXPORT void
 extern _X_EXPORT void
  RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc);
 
+extern _X_EXPORT Bool
+ RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable);
+
 /*
  * Crtc dispatch
  */
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index 949ae60..1a6e593 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -1641,3 +1641,61 @@ RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
             return;
     }
 }
+
+Bool
+RRReplaceScanoutPixmap(DrawablePtr pDrawable, PixmapPtr pPixmap, Bool enable)
+{
+    rrScrPriv(pDrawable->pScreen);
+    int i;
+    Bool size_fits = FALSE;
+    Bool changed = FALSE;
+    Bool ret = TRUE;
+
+    for (i = 0; i < pScrPriv->numCrtcs; i++) {
+        RRCrtcPtr crtc = pScrPriv->crtcs[i];
+
+        if (!crtc->mode && enable)
+            continue;
+
+        changed = FALSE;
+        if (crtc->mode && crtc->x == pDrawable->x &&
+            crtc->y == pDrawable->y &&
+            crtc->mode->mode.width == pDrawable->width &&
+            crtc->mode->mode.height == pDrawable->height)
+            size_fits = TRUE;
+
+        /* is the pixmap already set? */
+        if (crtc->scanout_pixmap == pPixmap) {
+            /* if its a disable then don't care about size */
+            if (enable == FALSE) {
+                /* set scanout to NULL */
+                crtc->scanout_pixmap = NULL;
+                changed = TRUE;
+            } else {
+                /* if the size fits then we are already setup */
+                if (size_fits)
+                    return TRUE;
+                /* if the size no longer fits then drop off */
+                crtc->scanout_pixmap = NULL;
+                changed = TRUE;
+                ret = FALSE;
+            }
+        } else {
+            if (!size_fits)
+                return FALSE;
+            if (enable) {
+                crtc->scanout_pixmap = pPixmap;
+                pScrPriv->rrCrtcSetScanoutPixmap(crtc, pPixmap);
+                changed = TRUE;
+            }
+        }
+
+        if (changed && pScrPriv->rrCrtcSet) {
+            pScrPriv->rrCrtcSetScanoutPixmap(crtc, crtc->scanout_pixmap);
+
+            (*pScrPriv->rrCrtcSet) (pDrawable->pScreen, crtc, crtc->mode, crtc->x, crtc->y,
+                                    crtc->rotation, crtc->numOutputs, crtc->outputs);
+        }
+    }
+    return ret;
+}
commit e2fd447e76c4a1233374c9d8fa9cae54a55dad50
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu Jul 5 15:50:56 2012 +0100

    xf86: add callback for offloak sink setting support.
    
    This adds support for setting the offload sink to the xf86 ddx.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index c5c7cb7..d20152c 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -741,7 +741,11 @@ xf86CrtcCloseScreen(ScreenPtr screen)
     }
     /* detach any providers */
     if (config->randr_provider) {
-        if (config->randr_provider->output_source) {
+        if (config->randr_provider->offload_sink) {
+            DetachOffloadGPU(screen);
+            config->randr_provider->offload_sink = NULL;
+        }
+        else if (config->randr_provider->output_source) {
             DetachOutputGPU(screen);
             config->randr_provider->output_source = NULL;
         }
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index 9548333..b4ed46a 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1789,6 +1789,32 @@ xf86RandR14ProviderSetOutputSource(ScreenPtr pScreen,
 }
 
 static Bool
+xf86RandR14ProviderSetOffloadSink(ScreenPtr pScreen,
+                                  RRProviderPtr provider,
+                                  RRProviderPtr sink_provider)
+{
+    if (!sink_provider) {
+        if (provider->offload_sink) {
+            ScreenPtr cmScreen = pScreen->current_master;
+            DetachOutputGPU(pScreen);
+            AttachUnboundGPU(cmScreen, pScreen);
+        }
+
+        provider->offload_sink = NULL;
+        return TRUE;
+    }
+
+    if (provider->offload_sink == sink_provider)
+        return TRUE;
+
+    DetachUnboundGPU(pScreen);
+    AttachOffloadGPU(sink_provider->pScreen, pScreen);
+
+    provider->offload_sink = sink_provider;
+    return TRUE;
+}
+
+static Bool
 xf86RandR14ProviderSetProperty(ScreenPtr pScreen,
                              RRProviderPtr randr_provider,
                              Atom property, RRPropertyValuePtr value)
@@ -1857,6 +1883,7 @@ xf86RandR12Init12(ScreenPtr pScreen)
     rp->rrSetConfig = NULL;
 
     rp->rrProviderSetOutputSource = xf86RandR14ProviderSetOutputSource;
+    rp->rrProviderSetOffloadSink = xf86RandR14ProviderSetOffloadSink;
 
     rp->rrProviderSetProperty = xf86RandR14ProviderSetProperty;
     rp->rrProviderGetProperty = xf86RandR14ProviderGetProperty;
commit 22f02120eb4092e1c283f81c8040f178693ff0a4
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Jun 26 09:53:54 2012 +0100

    xf86: store scanout pixmap in the xf86 struct as well.
    
    This is so we can tell the scanout pixmap has changed between calls
    to the crtc set function.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
index 38b9ea5..802303f 100644
--- a/hw/xfree86/modes/xf86Crtc.h
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -225,7 +225,7 @@ typedef struct _xf86CrtcFuncs {
 
 } xf86CrtcFuncsRec, *xf86CrtcFuncsPtr;
 
-#define XF86_CRTC_VERSION 4
+#define XF86_CRTC_VERSION 5
 
 struct _xf86Crtc {
     /**
@@ -376,6 +376,10 @@ struct _xf86Crtc {
      * Added in ABI version 4
      */
     Bool driverIsPerformingTransform;
+
+    /* Added in ABI version 5
+     */
+    PixmapPtr current_scanout;
 };
 
 typedef struct _xf86OutputFuncs {
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index 5fc33ca..9548333 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1157,6 +1157,9 @@ xf86RandR12CrtcSet(ScreenPtr pScreen,
     if (rotation != crtc->rotation)
         changed = TRUE;
 
+    if (crtc->current_scanout != randr_crtc->scanout_pixmap)
+        changed = TRUE;
+
     transform = RRCrtcGetTransform(randr_crtc);
     if ((transform != NULL) != crtc->transformPresent)
         changed = TRUE;
@@ -1218,6 +1221,7 @@ xf86RandR12CrtcSet(ScreenPtr pScreen,
              */
             crtc->desiredMode = mode;
             crtc->desiredRotation = rotation;
+            crtc->current_scanout = randr_crtc->scanout_pixmap;
             if (transform) {
                 crtc->desiredTransform = *transform;
                 crtc->desiredTransformPresent = TRUE;
commit 426bc0a28edbe0e9153f692a02dd25f744ffa034
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu Jul 5 15:41:38 2012 +0100

    randr: add hooks for offload sink provider protocol
    
    This adds the protocol handler and associated providers handling
    for the offload slaves, it allows two providers to be connected as
    offload sink/source.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/randr/randrstr.h b/randr/randrstr.h
index 5ca8830..16e7d01 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -164,6 +164,7 @@ struct _rrProvider {
     int nameLength;
     RRPropertyPtr properties;
     Bool pendingProperties;
+    struct _rrProvider *offload_sink;
     struct _rrProvider *output_source;
 };
 
@@ -226,6 +227,11 @@ typedef Bool (*RRProviderSetOutputSourceProcPtr)(ScreenPtr pScreen,
                                           RRProviderPtr provider,
                                           RRProviderPtr output_source);
 
+typedef Bool (*RRProviderSetOffloadSinkProcPtr)(ScreenPtr pScreen,
+                                         RRProviderPtr provider,
+                                         RRProviderPtr offload_sink);
+
+
 /* These are for 1.0 compatibility */
 
 typedef struct _rrRefresh {
@@ -278,6 +284,7 @@ typedef struct _rrScrPriv {
     RRCrtcSetScanoutPixmapProcPtr rrCrtcSetScanoutPixmap;
 
     RRProviderSetOutputSourceProcPtr rrProviderSetOutputSource;
+    RRProviderSetOffloadSinkProcPtr rrProviderSetOffloadSink;
     RRProviderGetPropertyProcPtr rrProviderGetProperty;
     RRProviderSetPropertyProcPtr rrProviderSetProperty;
     /*
@@ -888,6 +895,9 @@ ProcRRGetProviderInfo(ClientPtr client);
 extern _X_EXPORT int
 ProcRRSetProviderOutputSource(ClientPtr client);
 
+extern _X_EXPORT int
+ProcRRSetProviderOffloadSink(ClientPtr client);
+
 extern _X_EXPORT Bool
 RRProviderInit(void);
 
diff --git a/randr/rrdispatch.c b/randr/rrdispatch.c
index 6fe51c7..1942d74 100644
--- a/randr/rrdispatch.c
+++ b/randr/rrdispatch.c
@@ -245,7 +245,7 @@ int (*ProcRandrVector[RRNumberRequests]) (ClientPtr) = {
 /* V1.4 additions */
         ProcRRGetProviders,     /* 32 */
         ProcRRGetProviderInfo,  /* 33 */
-        NULL, /* 34 */
+        ProcRRSetProviderOffloadSink, /* 34 */
         ProcRRSetProviderOutputSource, /* 35 */
         ProcRRListProviderProperties,    /* 36 */
         ProcRRQueryProviderProperty,     /* 37 */
diff --git a/randr/rrprovider.c b/randr/rrprovider.c
index 8385d3f..c4fe369 100644
--- a/randr/rrprovider.c
+++ b/randr/rrprovider.c
@@ -175,10 +175,15 @@ ProcRRGetProviderInfo (ClientPtr client)
 
     /* count associated providers */
     rep.nAssociatedProviders = 0;
+    if (provider->offload_sink)
+        rep.nAssociatedProviders++;
     if (provider->output_source)
         rep.nAssociatedProviders++;
     xorg_list_for_each_entry(provscreen, &pScreen->output_slave_list, output_head)
         rep.nAssociatedProviders++;
+    xorg_list_for_each_entry(provscreen, &pScreen->offload_slave_list, offload_head)
+        rep.nAssociatedProviders++;
+
     rep.length = (pScrPriv->numCrtcs + pScrPriv->numOutputs +
                   (rep.nAssociatedProviders * 2) + bytes_to_int32(rep.nameLength));
 
@@ -210,6 +215,15 @@ ProcRRGetProviderInfo (ClientPtr client)
     }
 
     i = 0;
+    if (provider->offload_sink) {
+        providers[i] = provider->offload_sink->id;
+        if (client->swapped)
+            swapl(&providers[i]);
+        prov_cap[i] = RR_Capability_SinkOffload;
+        if (client->swapped)
+            swapl(&prov_cap[i]);
+        i++;
+    }
     if (provider->output_source) {
         providers[i] = provider->output_source->id;
         if (client->swapped)
@@ -228,6 +242,17 @@ ProcRRGetProviderInfo (ClientPtr client)
             swapl(&prov_cap[i]);
         i++;
     }
+    xorg_list_for_each_entry(provscreen, &pScreen->offload_slave_list, offload_head) {
+        pScrProvPriv = rrGetScrPriv(provscreen);
+        providers[i] = pScrProvPriv->provider->id;
+        if (client->swapped)
+            swapl(&providers[i]);
+        prov_cap[i] = RR_Capability_SourceOffload;
+        if (client->swapped)
+            swapl(&prov_cap[i]);
+        i++;
+    }
+
 
     memcpy(name, provider->name, rep.nameLength);
     if (client->swapped) {
@@ -279,6 +304,35 @@ ProcRRSetProviderOutputSource(ClientPtr client)
     return Success;
 }
 
+int
+ProcRRSetProviderOffloadSink(ClientPtr client)
+{
+    REQUEST(xRRSetProviderOffloadSinkReq);
+    rrScrPrivPtr pScrPriv;
+    RRProviderPtr provider, sink_provider = NULL;
+    ScreenPtr pScreen;
+
+    REQUEST_AT_LEAST_SIZE(xRRSetProviderOffloadSinkReq);
+
+    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
+    if (!(provider->capabilities & RR_Capability_SourceOffload))
+        return BadValue;
+
+    if (stuff->sink_provider) {
+        VERIFY_RR_PROVIDER(stuff->sink_provider, sink_provider, DixReadAccess);
+        if (!(sink_provider->capabilities & RR_Capability_SinkOffload))
+            return BadValue;
+    }
+    pScreen = provider->pScreen;
+    pScrPriv = rrGetScrPriv(pScreen);
+
+    pScrPriv->rrProviderSetOffloadSink(pScreen, provider, sink_provider);
+
+    RRTellChanged (pScreen);
+
+    return Success;
+}
+
 RRProviderPtr
 RRProviderCreate(ScreenPtr pScreen, const char *name,
                  int nameLength)
commit 12905dfaf01088a00f4a0a78cffba03329e7b724
Author: Dave Airlie <airlied at redhat.com>
Date:   Sat May 26 13:11:01 2012 +0100

    dix/xf86: initial offload slave tracking (v1.1)
    
    add the linked list and provider hooks.
    
    v1.1: add another assert in the add path.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index bc803d7..bcce22f 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -3745,6 +3745,7 @@ static int init_screen(ScreenPtr pScreen, int i, Bool gpu)
     xorg_list_init(&pScreen->pixmap_dirty_list);
     xorg_list_init(&pScreen->unattached_list);
     xorg_list_init(&pScreen->output_slave_list);
+    xorg_list_init(&pScreen->offload_slave_list);
 
     /*
      * This loop gets run once for every Screen that gets added,
@@ -3927,3 +3928,21 @@ DetachOutputGPU(ScreenPtr slave)
     xorg_list_del(&slave->output_head);
     slave->current_master = NULL;
 }
+
+void
+AttachOffloadGPU(ScreenPtr pScreen, ScreenPtr new)
+{
+    assert(new->isGPU);
+    assert(!new->current_master);
+    xorg_list_add(&new->offload_head, &pScreen->offload_slave_list);
+    new->current_master = pScreen;
+}
+
+void
+DetachOffloadGPU(ScreenPtr slave)
+{
+    assert(slave->isGPU);
+    xorg_list_del(&slave->offload_head);
+    slave->current_master = NULL;
+}
+
diff --git a/include/screenint.h b/include/screenint.h
index b992cc2..e36b4d8 100644
--- a/include/screenint.h
+++ b/include/screenint.h
@@ -82,6 +82,12 @@ AttachOutputGPU(ScreenPtr pScreen, ScreenPtr new);
 extern _X_EXPORT void
 DetachOutputGPU(ScreenPtr output);
 
+extern _X_EXPORT void
+AttachOffloadGPU(ScreenPtr pScreen, ScreenPtr new);
+
+extern _X_EXPORT void
+DetachOffloadGPU(ScreenPtr slave);
+
 typedef struct _ColormapRec *ColormapPtr;
 
 #endif                          /* SCREENINT_H */
diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index 5ef37ed..80601b9 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -507,6 +507,9 @@ typedef struct _Screen {
     StopPixmapTrackingProcPtr StopPixmapTracking;
 
     struct xorg_list pixmap_dirty_list;
+    struct xorg_list offload_slave_list;
+    struct xorg_list offload_head;
+
 } ScreenRec;
 
 static inline RegionPtr
diff --git a/randr/rrprovider.c b/randr/rrprovider.c
index f35ca6a..8385d3f 100644
--- a/randr/rrprovider.c
+++ b/randr/rrprovider.c
@@ -76,6 +76,10 @@ ProcRRGetProviders (ClientPtr client)
         pScrPriv = rrGetScrPriv(iter);
         total_providers += pScrPriv->provider ? 1 : 0;
     }
+    xorg_list_for_each_entry(iter, &pScreen->offload_slave_list, offload_head) {
+        pScrPriv = rrGetScrPriv(iter);
+        total_providers += pScrPriv->provider ? 1 : 0;
+    }
     xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) {
         pScrPriv = rrGetScrPriv(iter);
         total_providers += pScrPriv->provider ? 1 : 0;
@@ -112,6 +116,9 @@ ProcRRGetProviders (ClientPtr client)
         xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) {
             ADD_PROVIDER(iter);
         }
+        xorg_list_for_each_entry(iter, &pScreen->offload_slave_list, offload_head) {
+            ADD_PROVIDER(iter);
+        }
         xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) {
             ADD_PROVIDER(iter);
         }
commit a7c01da54ab43f9d29333ccbd79dfc001f9dc5e3
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu Jul 5 20:34:54 2012 +0100

    xf86: make sure rotate calcs are done on the right screen boundaries
    
    This fixes a segfault where this code believes we are outside the screen
    boundaries on a slave device, but we aren't.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/modes/xf86Rotate.c b/hw/xfree86/modes/xf86Rotate.c
index 31e0372..a393747 100644
--- a/hw/xfree86/modes/xf86Rotate.c
+++ b/hw/xfree86/modes/xf86Rotate.c
@@ -322,6 +322,12 @@ xf86CrtcFitsScreen(xf86CrtcPtr crtc, struct pict_f_transform *crtc_to_fb)
     /* When called before PreInit, the driver is
      * presumably doing load detect
      */
+    if (pScrn->is_gpu) {
+	ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
+	if (pScreen->current_master)
+	    pScrn = xf86ScreenToScrn(pScreen->current_master);
+    }
+
     if (pScrn->virtualX == 0 || pScrn->virtualY == 0)
         return TRUE;
 
commit cc02f4ef3e407be794132d004c947c9a4e14f4c2
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Jun 19 16:01:16 2012 +0100

    xf86/cursor: fallback to sw cursor if we have slaves present.
    
    Current USB devices have no hw rendered cursors, so we need the
    master GPU to render the cursor, so whenever we plug in a
    slave device, fallback to sw rendered cursors.
    
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/ramdac/xf86Cursor.c b/hw/xfree86/ramdac/xf86Cursor.c
index 8b91e05..8d48a75 100644
--- a/hw/xfree86/ramdac/xf86Cursor.c
+++ b/hw/xfree86/ramdac/xf86Cursor.c
@@ -336,7 +336,7 @@ xf86CursorSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs,
         if (!infoPtr->pScrn->vtSema)
             ScreenPriv->SavedCursor = pCurs;
 
-        if (infoPtr->pScrn->vtSema &&
+        if (infoPtr->pScrn->vtSema && xorg_list_is_empty(&pScreen->pixmap_dirty_list) &&
             (ScreenPriv->ForceHWCursorCount ||
              ((
 #ifdef ARGB_CURSOR
commit 98686512cbe1affb75222a63136854af79f1411b
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu Jul 5 15:50:24 2012 +0100

    xf86: add output source setting callback (v2)
    
    This adds support for the randr callback for setting the output source
    for a device.
    
    v2: drop root clip change on detach
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 6a005cd..c5c7cb7 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -741,7 +741,11 @@ xf86CrtcCloseScreen(ScreenPtr screen)
     }
     /* detach any providers */
     if (config->randr_provider) {
-        if (screen->current_master)
+        if (config->randr_provider->output_source) {
+            DetachOutputGPU(screen);
+            config->randr_provider->output_source = NULL;
+        }
+        else if (screen->current_master)
             DetachUnboundGPU(screen);
     }
     xf86RandR12CloseScreen(screen);
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index ebea4d5..5fc33ca 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1754,6 +1754,37 @@ xf86RandR12EnterVT(ScrnInfoPtr pScrn)
 }
 
 static Bool
+xf86RandR14ProviderSetOutputSource(ScreenPtr pScreen,
+                                   RRProviderPtr provider,
+                                   RRProviderPtr source_provider)
+{
+
+
+    if (!source_provider) {
+        if (provider->output_source) {
+            ScreenPtr cmScreen = pScreen->current_master;
+
+            DetachOutputGPU(pScreen);
+            AttachUnboundGPU(cmScreen, pScreen);
+        }
+        provider->output_source = NULL;
+        return TRUE;
+    }
+
+    if (provider->output_source == source_provider)
+        return TRUE;
+
+    SetRootClip(source_provider->pScreen, FALSE);
+
+    DetachUnboundGPU(pScreen);
+    AttachOutputGPU(source_provider->pScreen, pScreen);
+
+    provider->output_source = source_provider;
+    SetRootClip(source_provider->pScreen, TRUE);
+    return TRUE;
+}
+
+static Bool
 xf86RandR14ProviderSetProperty(ScreenPtr pScreen,
                              RRProviderPtr randr_provider,
                              Atom property, RRPropertyValuePtr value)
@@ -1821,6 +1852,8 @@ xf86RandR12Init12(ScreenPtr pScreen)
     rp->rrModeDestroy = xf86RandR12ModeDestroy;
     rp->rrSetConfig = NULL;
 
+    rp->rrProviderSetOutputSource = xf86RandR14ProviderSetOutputSource;
+
     rp->rrProviderSetProperty = xf86RandR14ProviderSetProperty;
     rp->rrProviderGetProperty = xf86RandR14ProviderGetProperty;
     rp->rrCrtcSetScanoutPixmap = xf86CrtcSetScanoutPixmap;
commit 4c92eb00f97f7b8258de8e366226880382cc9ce9
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu Jul 5 15:41:22 2012 +0100

    randr: add output source setup
    
    This adds the output sources to the associated list and adds the protocol
    handler for the randr SetProviderOutputSource.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/randr/randrstr.h b/randr/randrstr.h
index ac93414..5ca8830 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -164,6 +164,7 @@ struct _rrProvider {
     int nameLength;
     RRPropertyPtr properties;
     Bool pendingProperties;
+    struct _rrProvider *output_source;
 };
 
 #if RANDR_12_INTERFACE
@@ -221,6 +222,10 @@ typedef Bool (*RRProviderSetPropertyProcPtr) (ScreenPtr pScreen,
 typedef Bool (*RRGetInfoProcPtr) (ScreenPtr pScreen, Rotation * rotations);
 typedef Bool (*RRCloseScreenProcPtr) (ScreenPtr pscreen);
 
+typedef Bool (*RRProviderSetOutputSourceProcPtr)(ScreenPtr pScreen,
+                                          RRProviderPtr provider,
+                                          RRProviderPtr output_source);
+
 /* These are for 1.0 compatibility */
 
 typedef struct _rrRefresh {
@@ -272,6 +277,7 @@ typedef struct _rrScrPriv {
     /* TODO #if RANDR_15_INTERFACE */
     RRCrtcSetScanoutPixmapProcPtr rrCrtcSetScanoutPixmap;
 
+    RRProviderSetOutputSourceProcPtr rrProviderSetOutputSource;
     RRProviderGetPropertyProcPtr rrProviderGetProperty;
     RRProviderSetPropertyProcPtr rrProviderSetProperty;
     /*
@@ -879,6 +885,8 @@ ProcRRGetProviders(ClientPtr client);
 extern _X_EXPORT int
 ProcRRGetProviderInfo(ClientPtr client);
 
+extern _X_EXPORT int
+ProcRRSetProviderOutputSource(ClientPtr client);
 
 extern _X_EXPORT Bool
 RRProviderInit(void);
diff --git a/randr/rrdispatch.c b/randr/rrdispatch.c
index 054e47a..6fe51c7 100644
--- a/randr/rrdispatch.c
+++ b/randr/rrdispatch.c
@@ -246,7 +246,7 @@ int (*ProcRandrVector[RRNumberRequests]) (ClientPtr) = {
         ProcRRGetProviders,     /* 32 */
         ProcRRGetProviderInfo,  /* 33 */
         NULL, /* 34 */
-        NULL, /* 35 */
+        ProcRRSetProviderOutputSource, /* 35 */
         ProcRRListProviderProperties,    /* 36 */
         ProcRRQueryProviderProperty,     /* 37 */
         ProcRRConfigureProviderProperty, /* 38 */
diff --git a/randr/rrprovider.c b/randr/rrprovider.c
index 3773200..f35ca6a 100644
--- a/randr/rrprovider.c
+++ b/randr/rrprovider.c
@@ -137,7 +137,7 @@ ProcRRGetProviderInfo (ClientPtr client)
 {
     REQUEST(xRRGetProviderInfoReq);
     xRRGetProviderInfoReply rep;
-    rrScrPrivPtr pScrPriv;
+    rrScrPrivPtr pScrPriv, pScrProvPriv;
     RRProviderPtr provider;
     ScreenPtr pScreen;
     CARD8 *extra;
@@ -168,6 +168,10 @@ ProcRRGetProviderInfo (ClientPtr client)
 
     /* count associated providers */
     rep.nAssociatedProviders = 0;
+    if (provider->output_source)
+        rep.nAssociatedProviders++;
+    xorg_list_for_each_entry(provscreen, &pScreen->output_slave_list, output_head)
+        rep.nAssociatedProviders++;
     rep.length = (pScrPriv->numCrtcs + pScrPriv->numOutputs +
                   (rep.nAssociatedProviders * 2) + bytes_to_int32(rep.nameLength));
 
@@ -198,6 +202,26 @@ ProcRRGetProviderInfo (ClientPtr client)
             swapl(&outputs[i]);
     }
 
+    i = 0;
+    if (provider->output_source) {
+        providers[i] = provider->output_source->id;
+        if (client->swapped)
+            swapl(&providers[i]);
+        prov_cap[i] = RR_Capability_SourceOutput;
+            swapl(&prov_cap[i]);
+        i++;
+    }
+    xorg_list_for_each_entry(provscreen, &pScreen->output_slave_list, output_head) {
+        pScrProvPriv = rrGetScrPriv(provscreen);
+        providers[i] = pScrProvPriv->provider->id;
+        if (client->swapped)
+            swapl(&providers[i]);
+        prov_cap[i] = RR_Capability_SinkOutput;
+        if (client->swapped)
+            swapl(&prov_cap[i]);
+        i++;
+    }
+
     memcpy(name, provider->name, rep.nameLength);
     if (client->swapped) {
               swaps(&rep.sequenceNumber);
@@ -216,6 +240,38 @@ ProcRRGetProviderInfo (ClientPtr client)
     return Success;
 }
 
+int
+ProcRRSetProviderOutputSource(ClientPtr client)
+{
+    REQUEST(xRRSetProviderOutputSourceReq);
+    rrScrPrivPtr pScrPriv;
+    RRProviderPtr provider, source_provider = NULL;
+    ScreenPtr pScreen;
+
+    REQUEST_AT_LEAST_SIZE(xRRSetProviderOutputSourceReq);
+
+    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
+
+    if (!(provider->capabilities & RR_Capability_SinkOutput))
+        return BadValue;
+
+    if (stuff->source_provider) {
+        VERIFY_RR_PROVIDER(stuff->source_provider, source_provider, DixReadAccess);
+
+        if (!(source_provider->capabilities & RR_Capability_SourceOutput))
+            return BadValue;
+    }
+
+    pScreen = provider->pScreen;
+    pScrPriv = rrGetScrPriv(pScreen);
+
+    pScrPriv->rrProviderSetOutputSource(pScreen, provider, source_provider);
+
+    RRTellChanged (pScreen);
+
+    return Success;
+}
+
 RRProviderPtr
 RRProviderCreate(ScreenPtr pScreen, const char *name,
                  int nameLength)
commit bec4cb72c55bb6dee09c65c0844af201067a090f
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu May 24 15:47:22 2012 +0100

    randr: hook up output slave to screen resources return
    
    When the client asks for the screen resources list, it will now
    get a list of crtc/outputs for the master + all attached slaves,
    this will let randr configure all attached slave devices properly.
    
    Keith asked I merge the two functions, but not just yet, the current
    multi screen code doesn't handle primary yet properly, will fix it up later.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/randr/rrscreen.c b/randr/rrscreen.c
index c564d1f..9bf9316 100644
--- a/randr/rrscreen.c
+++ b/randr/rrscreen.c
@@ -292,6 +292,172 @@ ProcRRSetScreenSize(ClientPtr client)
     return Success;
 }
 
+
+#define update_totals(gpuscreen, pScrPriv) do {       \
+    total_crtcs += pScrPriv->numCrtcs;                \
+    total_outputs += pScrPriv->numOutputs;            \
+    modes = RRModesForScreen(gpuscreen, &num_modes);  \
+    if (!modes)                                       \
+        return BadAlloc;                              \
+    for (j = 0; j < num_modes; j++)                   \
+        total_name_len += modes[j]->mode.nameLength;  \
+    total_modes += num_modes;                         \
+    free(modes);                                      \
+} while(0)
+
+static inline void swap_modeinfos(xRRModeInfo *modeinfos, int i)
+{
+    swapl(&modeinfos[i].id);
+    swaps(&modeinfos[i].width);
+    swaps(&modeinfos[i].height);
+    swapl(&modeinfos[i].dotClock);
+    swaps(&modeinfos[i].hSyncStart);
+    swaps(&modeinfos[i].hSyncEnd);
+    swaps(&modeinfos[i].hTotal);
+    swaps(&modeinfos[i].hSkew);
+    swaps(&modeinfos[i].vSyncStart);
+    swaps(&modeinfos[i].vSyncEnd);
+    swaps(&modeinfos[i].vTotal);
+    swaps(&modeinfos[i].nameLength);
+    swapl(&modeinfos[i].modeFlags);
+}
+
+#define update_arrays(gpuscreen, pScrPriv) do {            \
+    for (j = 0; j < pScrPriv->numCrtcs; j++) {             \
+        crtcs[crtc_count] = pScrPriv->crtcs[j]->id;        \
+        if (client->swapped)                               \
+            swapl(&crtcs[crtc_count]);                     \
+        crtc_count++;                                      \
+    }                                                      \
+    for (j = 0; j < pScrPriv->numOutputs; j++) {           \
+        outputs[output_count] = pScrPriv->outputs[j]->id;  \
+        if (client->swapped)                               \
+            swapl(&outputs[output_count]);                 \
+        output_count++;                                    \
+    }                                                      \
+    {                                                      \
+        RRModePtr mode;                                    \
+        modes = RRModesForScreen(gpuscreen, &num_modes);   \
+        for (j = 0; j < num_modes; j++) {                  \
+            mode = modes[j];                               \
+            modeinfos[mode_count] = mode->mode;            \
+            if (client->swapped) {                         \
+                swap_modeinfos(modeinfos, mode_count);     \
+            }                                              \
+            memcpy(names, mode->name, mode->mode.nameLength); \
+            names += mode->mode.nameLength;                \
+            mode_count++;                                  \
+        }                                                  \
+        free(modes);                                       \
+    }                                                      \
+    } while (0)
+
+static int
+rrGetMultiScreenResources(ClientPtr client, Bool query, ScreenPtr pScreen)
+{
+    int j;
+    int total_crtcs, total_outputs, total_modes, total_name_len;
+    int crtc_count, output_count, mode_count;
+    ScreenPtr iter;
+    rrScrPrivPtr pScrPriv;
+    int num_modes;
+    RRModePtr *modes;
+    xRRGetScreenResourcesReply rep;
+    unsigned long extraLen;
+    CARD8 *extra;
+    RRCrtc *crtcs;
+    RROutput *outputs;
+    xRRModeInfo *modeinfos;
+    CARD8 *names;
+
+    /* we need to iterate all the GPU masters and all their output slaves */
+    total_crtcs = 0;
+    total_outputs = 0;
+    total_modes = 0;
+    total_name_len = 0;
+
+    pScrPriv = rrGetScrPriv(pScreen);
+
+    if (query && pScrPriv)
+        if (!RRGetInfo(pScreen, query))
+            return BadAlloc;
+
+    update_totals(pScreen, pScrPriv);
+
+    xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) {
+        pScrPriv = rrGetScrPriv(iter);
+
+        if (query)
+          if (!RRGetInfo(iter, query))
+            return BadAlloc;
+        update_totals(iter, pScrPriv);
+    }
+
+    ErrorF("reporting %d %d %d %d\n", total_crtcs, total_outputs, total_modes, total_name_len);
+
+    pScrPriv = rrGetScrPriv(pScreen);
+    rep.pad = 0;
+    rep.type = X_Reply;
+    rep.sequenceNumber = client->sequence;
+    rep.length = 0;
+    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
+    rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
+    rep.nCrtcs = total_crtcs;
+    rep.nOutputs = total_outputs;
+    rep.nModes = total_modes;
+    rep.nbytesNames = total_name_len;
+
+    rep.length = (total_crtcs + total_outputs + total_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
+                  bytes_to_int32(rep.nbytesNames));
+
+    extraLen = rep.length << 2;
+    if (extraLen) {
+        extra = malloc(extraLen);
+        if (!extra) {
+            return BadAlloc;
+        }
+    }
+    else
+        extra = NULL;
+
+    crtcs = (RRCrtc *)extra;
+    outputs = (RROutput *)(crtcs + total_crtcs);
+    modeinfos = (xRRModeInfo *)(outputs + total_outputs);
+    names = (CARD8 *)(modeinfos + total_modes);
+
+    /* TODO primary */
+    crtc_count = 0;
+    output_count = 0;
+    mode_count = 0;
+
+    pScrPriv = rrGetScrPriv(pScreen);
+    update_arrays(pScreen, pScrPriv);
+
+    xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) {
+        pScrPriv = rrGetScrPriv(iter);
+
+        update_arrays(iter, pScrPriv);
+    }
+
+    assert(bytes_to_int32((char *) names - (char *) extra) == rep.length);
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swapl(&rep.timestamp);
+        swapl(&rep.configTimestamp);
+        swaps(&rep.nCrtcs);
+        swaps(&rep.nOutputs);
+        swaps(&rep.nModes);
+        swaps(&rep.nbytesNames);
+    }
+    WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *) &rep);
+    if (extraLen) {
+        WriteToClient(client, extraLen, (char *) extra);
+        free(extra);
+    }
+    return Success;
+}
+
 static int
 rrGetScreenResources(ClientPtr client, Bool query)
 {
@@ -321,6 +487,9 @@ rrGetScreenResources(ClientPtr client, Bool query)
         if (!RRGetInfo(pScreen, query))
             return BadAlloc;
 
+    if (!xorg_list_is_empty(&pScreen->output_slave_list))
+        return rrGetMultiScreenResources(client, query, pScreen);
+
     if (!pScrPriv) {
         rep.type = X_Reply;
         rep.sequenceNumber = client->sequence;
commit 88bc02bfaae2c15a30c606d34cf7940e6ad5ea14
Author: Dave Airlie <airlied at redhat.com>
Date:   Mon Jun 18 14:11:24 2012 +0100

    xf86/crtc: add new interface to detach slave crtcs
    
    This will detach any scanout pixmaps attached to slave crtcs.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 31efd83..6a005cd 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -3228,3 +3228,23 @@ xf86ProviderSetup(ScrnInfoPtr scrn,
 #endif
 }
 
+void
+xf86DetachAllCrtc(ScrnInfoPtr scrn)
+{
+        xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+        int i;
+
+        for (i = 0; i < xf86_config->num_crtc; i++) {
+            xf86CrtcPtr crtc = xf86_config->crtc[i];
+
+            if (crtc->randr_crtc)
+                RRCrtcDetachScanoutPixmap(crtc->randr_crtc);
+
+            /* dpms off */
+            (*crtc->funcs->dpms) (crtc, DPMSModeOff);
+            /* force a reset the next time its used */
+            crtc->randr_crtc->mode = NULL;
+            crtc->mode.HDisplay = 0;
+            crtc->x = crtc->y = 0;
+        }
+}
diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
index 25fb34d..38b9ea5 100644
--- a/hw/xfree86/modes/xf86Crtc.h
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -1014,4 +1014,7 @@ extern _X_EXPORT void
 xf86ProviderSetup(ScrnInfoPtr scrn,
                   const xf86ProviderFuncsRec * funcs, const char *name);
 
+extern _X_EXPORT void
+xf86DetachAllCrtc(ScrnInfoPtr scrn);
+
 #endif                          /* _XF86CRTC_H_ */
commit 9b8217f9ef6279fff6628631d18497bed0343ef9
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu Jun 14 15:24:46 2012 +0100

    dix/pixmap: track dirty pixmaps in server. (v4)
    
    This adds two functions for drivers to use directly to keep a
    linked list of slave pixmaps to do damage tracking on and keep
    updated. It also adds a helper function that drivers may optionally
    call to do a simple copy area damage update.
    
    v2: use damage.h not damagestr.h, fixes ephyr build.
    
    v3: address ajax review: use slave_dst, drop unused dst member.
    
    v4: check DamageCreate return, add SourceValidate comment,
    add a comment addressing possible optimisation possibility
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 29ac5a4..bc803d7 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -3742,6 +3742,7 @@ static int init_screen(ScreenPtr pScreen, int i, Bool gpu)
     pScreen->ClipNotify = 0;    /* for R4 ddx compatibility */
     pScreen->CreateScreenResources = 0;
 
+    xorg_list_init(&pScreen->pixmap_dirty_list);
     xorg_list_init(&pScreen->unattached_list);
     xorg_list_init(&pScreen->output_slave_list);
 
diff --git a/dix/pixmap.c b/dix/pixmap.c
index 11b1b04..9163e99 100644
--- a/dix/pixmap.c
+++ b/dix/pixmap.c
@@ -158,3 +158,109 @@ PixmapPtr PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave)
 
     return spix;
 }
+
+Bool
+PixmapStartDirtyTracking(PixmapPtr src,
+                         PixmapPtr slave_dst,
+                         int x, int y)
+{
+    ScreenPtr screen = src->drawable.pScreen;
+    PixmapDirtyUpdatePtr dirty_update;
+
+    dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec));
+    if (!dirty_update)
+        return FALSE;
+
+    dirty_update->src = src;
+    dirty_update->slave_dst = slave_dst;
+    dirty_update->x = x;
+    dirty_update->y = y;
+
+    dirty_update->damage = DamageCreate(NULL, NULL,
+                                        DamageReportNone,
+                                        TRUE, src->drawable.pScreen,
+                                        src->drawable.pScreen);
+    if (!dirty_update->damage) {
+        free(dirty_update);
+        return FALSE;
+    }
+
+    DamageRegister(&src->drawable, dirty_update->damage);
+    xorg_list_add(&dirty_update->ent, &screen->pixmap_dirty_list);
+    return TRUE;
+}
+
+Bool
+PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst)
+{
+    ScreenPtr screen = src->drawable.pScreen;
+    PixmapDirtyUpdatePtr ent, safe;
+
+    xorg_list_for_each_entry_safe(ent, safe, &screen->pixmap_dirty_list, ent) {
+        if (ent->src == src && ent->slave_dst == slave_dst) {
+            DamageUnregister(&src->drawable, ent->damage);
+            DamageDestroy(ent->damage);
+            xorg_list_del(&ent->ent);
+            free(ent);
+        }
+    }
+    return TRUE;
+}
+
+/*
+ * this function can possibly be improved and optimised, by clipping
+ * instead of iterating
+ */
+Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty, RegionPtr dirty_region)
+{
+    ScreenPtr pScreen = dirty->src->drawable.pScreen;
+    int n;
+    BoxPtr b;
+    RegionPtr region = DamageRegion(dirty->damage);
+    GCPtr pGC;
+    PixmapPtr dst;
+    SourceValidateProcPtr SourceValidate;
+
+    /*
+     * SourceValidate is used by the software cursor code
+     * to pull the cursor off of the screen when reading
+     * bits from the frame buffer. Bypassing this function
+     * leaves the software cursor in place
+     */
+    SourceValidate = pScreen->SourceValidate;
+    pScreen->SourceValidate = NULL;
+
+    RegionTranslate(dirty_region, dirty->x, dirty->y);
+    RegionIntersect(dirty_region, dirty_region, region);
+
+    if (RegionNil(dirty_region)) {
+        RegionUninit(dirty_region);
+        return FALSE;
+    }
+
+    dst = dirty->slave_dst->master_pixmap;
+
+    RegionTranslate(dirty_region, -dirty->x, -dirty->y);
+    n = RegionNumRects(dirty_region);
+    b = RegionRects(dirty_region);
+
+    pGC = GetScratchGC(dirty->src->drawable.depth, pScreen);
+    ValidateGC(&dst->drawable, pGC);
+
+    while (n--) {
+        BoxRec dst_box;
+        int w, h;
+
+        dst_box = *b;
+        w = dst_box.x2 - dst_box.x1;
+        h = dst_box.y2 - dst_box.y1;
+
+        pGC->ops->CopyArea(&dirty->src->drawable, &dst->drawable, pGC,
+                           dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h, dst_box.x1, dst_box.y1);
+        b++;
+    }
+    FreeScratchGC(pGC);
+
+    pScreen->SourceValidate = SourceValidate;
+    return TRUE;
+}
diff --git a/include/pixmap.h b/include/pixmap.h
index 8c523bd..921a94d 100644
--- a/include/pixmap.h
+++ b/include/pixmap.h
@@ -49,6 +49,7 @@ SOFTWARE.
 
 #include "misc.h"
 #include "screenint.h"
+#include "regionstr.h"
 
 /* types for Drawable */
 #define DRAWABLE_WINDOW 0
@@ -73,6 +74,8 @@ SOFTWARE.
 typedef struct _Drawable *DrawablePtr;
 typedef struct _Pixmap *PixmapPtr;
 
+typedef struct _PixmapDirtyUpdate *PixmapDirtyUpdatePtr;
+
 typedef union _PixUnion {
     PixmapPtr pixmap;
     unsigned long pixel;
@@ -112,4 +115,17 @@ extern _X_EXPORT void FreePixmap(PixmapPtr /*pPixmap */ );
 extern _X_EXPORT PixmapPtr
 PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave);
 
+extern _X_EXPORT Bool
+PixmapStartDirtyTracking(PixmapPtr src,
+                         PixmapPtr slave_dst,
+                         int x, int y);
+
+extern _X_EXPORT Bool
+PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst);
+
+/* helper function, drivers can do this themselves if they can do it more
+   efficently */
+extern _X_EXPORT Bool
+PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty, RegionPtr dirty_region);
+
 #endif                          /* PIXMAP_H */
diff --git a/include/pixmapstr.h b/include/pixmapstr.h
index 40af5c4..2a1ef9b 100644
--- a/include/pixmapstr.h
+++ b/include/pixmapstr.h
@@ -50,6 +50,7 @@ SOFTWARE.
 #include "screenint.h"
 #include "regionstr.h"
 #include "privates.h"
+#include "damage.h"
 
 typedef struct _Drawable {
     unsigned char type;         /* DRAWABLE_<type> */
@@ -84,6 +85,13 @@ typedef struct _Pixmap {
     PixmapPtr master_pixmap;    /* pointer to master copy of pixmap for pixmap sharing */
 } PixmapRec;
 
+typedef struct _PixmapDirtyUpdate {
+    PixmapPtr src, slave_dst;
+    int x, y;
+    DamagePtr damage;
+    struct xorg_list ent;
+} PixmapDirtyUpdateRec;
+
 static inline void
 PixmapBox(BoxPtr box, PixmapPtr pixmap)
 {
diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index 3a738d3..5ef37ed 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -505,6 +505,8 @@ typedef struct _Screen {
 
     StartPixmapTrackingProcPtr StartPixmapTracking;
     StopPixmapTrackingProcPtr StopPixmapTracking;
+
+    struct xorg_list pixmap_dirty_list;
 } ScreenRec;
 
 static inline RegionPtr
commit c5cc2a8243c5e6bf454af989b7512ec7e20fc3f2
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue May 29 14:41:39 2012 +0100

    randr: check the screen size bounds against the master
    
    The master contains the complete screen size bounds, so check
    the width/height against it.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index e5fe059..949ae60 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -1125,6 +1125,16 @@ ProcRRSetCrtcConfig(ClientPtr client)
             int source_height;
             PictTransform transform;
             struct pixman_f_transform f_transform, f_inverse;
+            int width, height;
+
+            if (pScreen->isGPU) {
+                width = pScreen->current_master->width;
+                height = pScreen->current_master->height;
+            }
+            else {
+                width = pScreen->width;
+                height = pScreen->height;
+            }
 
             RRTransformCompute(stuff->x, stuff->y,
                                mode->mode.width, mode->mode.height,
@@ -1134,13 +1144,13 @@ ProcRRSetCrtcConfig(ClientPtr client)
 
             RRModeGetScanoutSize(mode, &transform, &source_width,
                                  &source_height);
-            if (stuff->x + source_width > pScreen->width) {
+            if (stuff->x + source_width > width) {
                 client->errorValue = stuff->x;
                 free(outputs);
                 return BadValue;
             }
 
-            if (stuff->y + source_height > pScreen->height) {
+            if (stuff->y + source_height > height) {
                 client->errorValue = stuff->y;
                 free(outputs);
                 return BadValue;
commit 26d848cb916c8a85f2c69d2aeb004665ba07bf00
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue May 29 14:35:24 2012 +0100

    randr: fix tellchanged to work with slave scanouts
    
    Tell changed need to tell only for the master pixmap,
    however it gets called from various places for slave screens,
    so convert to telling clients about changes on the master screen.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/randr/randr.c b/randr/randr.c
index 103c31e..ae81166 100644
--- a/randr/randr.c
+++ b/randr/randr.c
@@ -467,25 +467,37 @@ TellChanged(WindowPtr pWin, pointer value)
 void
 RRTellChanged(ScreenPtr pScreen)
 {
+    ScreenPtr master;
     rrScrPriv(pScreen);
+    rrScrPrivPtr mastersp;
     int i;
 
+    if (pScreen->isGPU) {
+        master = pScreen->current_master;
+        mastersp = rrGetScrPriv(master);
+    }
+    else {
+        master = pScreen;
+        mastersp = pScrPriv;
+    }
+
     if (pScrPriv->changed) {
         UpdateCurrentTimeIf();
-        if (pScrPriv->configChanged) {
-            pScrPriv->lastConfigTime = currentTime;
-            pScrPriv->configChanged = FALSE;
+        if (mastersp->configChanged) {
+            mastersp->lastConfigTime = currentTime;
+            mastersp->configChanged = FALSE;
         }
         pScrPriv->changed = FALSE;
-        WalkTree(pScreen, TellChanged, (pointer) pScreen);
+        mastersp->changed = FALSE;
+        WalkTree(master, TellChanged, (pointer) master);
         for (i = 0; i < pScrPriv->numOutputs; i++)
             pScrPriv->outputs[i]->changed = FALSE;
         for (i = 0; i < pScrPriv->numCrtcs; i++)
             pScrPriv->crtcs[i]->changed = FALSE;
-        if (pScrPriv->layoutChanged) {
+        if (mastersp->layoutChanged) {
             pScrPriv->layoutChanged = FALSE;
-            RRPointerScreenConfigured(pScreen);
-            RRSendConfigNotify(pScreen);
+            RRPointerScreenConfigured(master);
+            RRSendConfigNotify(master);
         }
     }
 }
commit 4bf0192d810e01c89a1903cc4bc5e639fc13a547
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue May 29 14:37:11 2012 +0100

    randr: fixup constrain to work with slave screens.
    
    Current code constrains the cursor to the crtcs on the master
    device, for slave outputs to work we have to include their crtcs
    in the constrain calculations.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index 29b02a9..e5fe059 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -1544,18 +1544,10 @@ ProcRRGetCrtcTransform(ClientPtr client)
     return Success;
 }
 
-void
-RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
-                        int *y)
+static Bool check_all_screen_crtcs(ScreenPtr pScreen, int *x, int *y)
 {
     rrScrPriv(pScreen);
     int i;
-
-    /* intentional dead space -> let it float */
-    if (pScrPriv->discontiguous)
-        return;
-
-    /* if we're moving inside a crtc, we're fine */
     for (i = 0; i < pScrPriv->numCrtcs; i++) {
         RRCrtcPtr crtc = pScrPriv->crtcs[i];
 
@@ -1567,8 +1559,15 @@ RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
         crtc_bounds(crtc, &left, &right, &top, &bottom);
 
         if ((*x >= left) && (*x < right) && (*y >= top) && (*y < bottom))
-            return;
+            return TRUE;
     }
+    return FALSE;
+}
+
+static Bool constrain_all_screen_crtcs(DeviceIntPtr pDev, ScreenPtr pScreen, int *x, int *y)
+{
+    rrScrPriv(pScreen);
+    int i;
 
     /* if we're trying to escape, clamp to the CRTC we're coming from */
     for (i = 0; i < pScrPriv->numCrtcs; i++) {
@@ -1592,7 +1591,43 @@ RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
             if (*y >= bottom)
                 *y = bottom - 1;
 
-            return;
+            return TRUE;
         }
     }
+    return FALSE;
+}
+
+void
+RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x,
+                        int *y)
+{
+    rrScrPriv(pScreen);
+    Bool ret;
+    ScreenPtr slave;
+
+    /* intentional dead space -> let it float */
+    if (pScrPriv->discontiguous)
+        return;
+
+    /* if we're moving inside a crtc, we're fine */
+    ret = check_all_screen_crtcs(pScreen, x, y);
+    if (ret == TRUE)
+        return;
+
+    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
+        ret = check_all_screen_crtcs(slave, x, y);
+        if (ret == TRUE)
+            return;
+    }
+
+    /* if we're trying to escape, clamp to the CRTC we're coming from */
+    ret = constrain_all_screen_crtcs(pDev, pScreen, x, y);
+    if (ret == TRUE)
+        return;
+
+    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
+        ret = constrain_all_screen_crtcs(pDev, slave, x, y);
+        if (ret == TRUE)
+            return;
+    }
 }
commit 2ed3f64d9d453628ab5c03b8aee006093019c933
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Jun 20 12:37:26 2012 +0100

    xf86: add initial scanout pixmap support (v2)
    
    Add the simple passthrough interface for drivers to use,
    so they can set scanout pixmaps.
    
    v2: detach scanout pixmap properly.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 0bf14eb..31efd83 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -734,6 +734,9 @@ xf86CrtcCloseScreen(ScreenPtr screen)
     for (c = 0; c < config->num_crtc; c++) {
         xf86CrtcPtr crtc = config->crtc[c];
 
+        if (crtc->randr_crtc->scanout_pixmap)
+            RRCrtcDetachScanoutPixmap(crtc->randr_crtc);
+
         crtc->randr_crtc = NULL;
     }
     /* detach any providers */
diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
index 58d8cec..25fb34d 100644
--- a/hw/xfree86/modes/xf86Crtc.h
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -218,6 +218,11 @@ typedef struct _xf86CrtcFuncs {
     void
      (*set_origin) (xf86CrtcPtr crtc, int x, int y);
 
+    /**
+     */
+    Bool
+    (*set_scanout_pixmap)(xf86CrtcPtr crtc, PixmapPtr pixmap);
+
 } xf86CrtcFuncsRec, *xf86CrtcFuncsPtr;
 
 #define XF86_CRTC_VERSION 4
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index 41c0b11..ebea4d5 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1790,6 +1790,15 @@ xf86RandR14ProviderGetProperty(ScreenPtr pScreen,
 }
 
 static Bool
+xf86CrtcSetScanoutPixmap(RRCrtcPtr randr_crtc, PixmapPtr pixmap)
+{
+    xf86CrtcPtr crtc = randr_crtc->devPrivate;
+    if (!crtc->funcs->set_scanout_pixmap)
+        return FALSE;
+    return crtc->funcs->set_scanout_pixmap(crtc, pixmap);
+}
+
+static Bool
 xf86RandR12Init12(ScreenPtr pScreen)
 {
     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
@@ -1814,6 +1823,7 @@ xf86RandR12Init12(ScreenPtr pScreen)
 
     rp->rrProviderSetProperty = xf86RandR14ProviderSetProperty;
     rp->rrProviderGetProperty = xf86RandR14ProviderGetProperty;
+    rp->rrCrtcSetScanoutPixmap = xf86CrtcSetScanoutPixmap;
 
     pScrn->PointerMoved = xf86RandR12PointerMoved;
     pScrn->ChangeGamma = xf86RandR12ChangeGamma;
commit f2da2c12042d3447b1c954e7301632d174a08b4f
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Jun 20 12:37:12 2012 +0100

    randr: add initial scanout pixmap support (v3)
    
    When randr notices a crtc configuration request for a slave device,
    it checks if the slave allocated pixmap exists and is suitable,
    if not it allocates a new shared pixmap from the master, shares
    it to the slave, and starts the master tracking damage to it,
    to keep it updated from the current front pixmap.
    
    If the resize means the crtc is no longer used it will destroy
    the slave pixmap.
    
    This adds the concept of a scanout_pixmap to the randr_crtc object,
    and also adds a master pixmap pointer to the pixmap object, along
    with defining some pixmap helper functions for getting pixmap box/regions.
    
    v2: split out pixmap sharing to a separate function.
    
    v3: update for void *
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/dix/pixmap.c b/dix/pixmap.c
index 0c85c3f..11b1b04 100644
--- a/dix/pixmap.c
+++ b/dix/pixmap.c
@@ -129,3 +129,32 @@ FreePixmap(PixmapPtr pPixmap)
     dixFiniPrivates(pPixmap, PRIVATE_PIXMAP);
     free(pPixmap);
 }
+
+PixmapPtr PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave)
+{
+    PixmapPtr spix;
+    int ret;
+    void *handle;
+    ScreenPtr master = pixmap->drawable.pScreen;
+    int depth = pixmap->drawable.depth;
+
+    ret = master->SharePixmapBacking(pixmap, slave, &handle);
+    if (ret == FALSE)
+        return NULL;
+
+    spix = slave->CreatePixmap(slave, 0, 0, depth,
+                               CREATE_PIXMAP_USAGE_SHARED);
+    slave->ModifyPixmapHeader(spix, pixmap->drawable.width,
+                              pixmap->drawable.height, depth, 0,
+                              pixmap->devKind, NULL);
+
+    spix->master_pixmap = pixmap;
+
+    ret = slave->SetSharedPixmapBacking(spix, handle);
+    if (ret == FALSE) {
+        slave->DestroyPixmap(spix);
+        return NULL;
+    }
+
+    return spix;
+}
diff --git a/include/pixmap.h b/include/pixmap.h
index 9bb5bb7..8c523bd 100644
--- a/include/pixmap.h
+++ b/include/pixmap.h
@@ -109,4 +109,7 @@ extern _X_EXPORT PixmapPtr AllocatePixmap(ScreenPtr /*pScreen */ ,
 
 extern _X_EXPORT void FreePixmap(PixmapPtr /*pPixmap */ );
 
+extern _X_EXPORT PixmapPtr
+PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave);
+
 #endif                          /* PIXMAP_H */
diff --git a/include/pixmapstr.h b/include/pixmapstr.h
index 0800c62..40af5c4 100644
--- a/include/pixmapstr.h
+++ b/include/pixmapstr.h
@@ -80,6 +80,28 @@ typedef struct _Pixmap {
     short screen_y;
 #endif
     unsigned usage_hint;        /* see CREATE_PIXMAP_USAGE_* */
+
+    PixmapPtr master_pixmap;    /* pointer to master copy of pixmap for pixmap sharing */
 } PixmapRec;
 
+static inline void
+PixmapBox(BoxPtr box, PixmapPtr pixmap)
+{
+    box->x1 = 0;
+    box->x2 = pixmap->drawable.width;
+
+    box->y1 = 0;
+    box->y2 = pixmap->drawable.height;
+}
+
+
+static inline void
+PixmapRegionInit(RegionPtr region, PixmapPtr pixmap)
+{
+    BoxRec box;
+
+    PixmapBox(&box, pixmap);
+    RegionInit(region, &box, 1);
+}
+
 #endif                          /* PIXMAPSTRUCT_H */
diff --git a/randr/randrstr.h b/randr/randrstr.h
index 3dac633..ac93414 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -127,6 +127,8 @@ struct _rrCrtc {
     PictTransform transform;
     struct pict_f_transform f_transform;
     struct pict_f_transform f_inverse;
+
+    PixmapPtr scanout_pixmap;
 };
 
 struct _rrOutput {
@@ -242,6 +244,8 @@ typedef Bool (*RRSetConfigProcPtr) (ScreenPtr pScreen,
 
 #endif
 
+typedef Bool (*RRCrtcSetScanoutPixmapProcPtr)(RRCrtcPtr crtc, PixmapPtr pixmap);
+
 typedef struct _rrScrPriv {
     /*
      * 'public' part of the structure; DDXen fill this in
@@ -265,6 +269,8 @@ typedef struct _rrScrPriv {
     RRGetPanningProcPtr rrGetPanning;
     RRSetPanningProcPtr rrSetPanning;
 #endif
+    /* TODO #if RANDR_15_INTERFACE */
+    RRCrtcSetScanoutPixmapProcPtr rrCrtcSetScanoutPixmap;
 
     RRProviderGetPropertyProcPtr rrProviderGetProperty;
     RRProviderSetPropertyProcPtr rrProviderSetProperty;
@@ -649,6 +655,12 @@ extern _X_EXPORT void
  RRCrtcInitErrorValue(void);
 
 /*
+ * Detach and free a scanout pixmap
+ */
+extern _X_EXPORT void
+ RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc);
+
+/*
  * Crtc dispatch
  */
 
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index 0c596dd..29b02a9 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -367,6 +367,154 @@ RRComputeContiguity(ScreenPtr pScreen)
     pScrPriv->discontiguous = discontiguous;
 }
 
+void
+RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)
+{
+    ScreenPtr master = crtc->pScreen->current_master;
+    int ret;
+    PixmapPtr mscreenpix;
+    rrScrPriv(crtc->pScreen);
+
+    mscreenpix = master->GetScreenPixmap(master);
+
+    ret = pScrPriv->rrCrtcSetScanoutPixmap(crtc, NULL);
+    if (crtc->scanout_pixmap) {
+        master->StopPixmapTracking(mscreenpix, crtc->scanout_pixmap);
+        master->DestroyPixmap(crtc->scanout_pixmap->master_pixmap);
+        crtc->pScreen->DestroyPixmap(crtc->scanout_pixmap);
+    }
+    crtc->scanout_pixmap = NULL;
+    RRCrtcChanged(crtc, TRUE);
+}
+
+static Bool
+rrCreateSharedPixmap(RRCrtcPtr crtc, int width, int height,
+                     int x, int y)
+{
+    PixmapPtr mpix, spix;
+    ScreenPtr master = crtc->pScreen->current_master;
+    Bool ret;
+    int depth;
+    PixmapPtr mscreenpix;
+    PixmapPtr protopix = crtc->pScreen->current_master->GetScreenPixmap(crtc->pScreen->current_master);
+    rrScrPriv(crtc->pScreen);
+
+    /* create a pixmap on the master screen,
+       then get a shared handle for it
+       create a shared pixmap on the slave screen using the handle
+       set the master screen to do dirty updates to the shared pixmap
+       from the screen pixmap.
+       set slave screen to scanout shared linear pixmap
+    */
+
+    mscreenpix = master->GetScreenPixmap(master);
+    depth = protopix->drawable.depth;
+
+    if (crtc->scanout_pixmap)
+        RRCrtcDetachScanoutPixmap(crtc);
+
+    if (width == 0 && height == 0) {
+        return TRUE;
+    }
+
+    mpix = master->CreatePixmap(master, width, height, depth,
+                                CREATE_PIXMAP_USAGE_SHARED);
+    if (!mpix)
+        return FALSE;
+
+    spix = PixmapShareToSlave(mpix, crtc->pScreen);
+    if (spix == NULL) {
+        master->DestroyPixmap(mpix);
+        return FALSE;
+    }
+
+    ret = pScrPriv->rrCrtcSetScanoutPixmap(crtc, spix);
+    if (ret == FALSE) {
+        ErrorF("failed to set shadow slave pixmap\n");
+        return FALSE;
+    }
+
+    crtc->scanout_pixmap = spix;
+
+    master->StartPixmapTracking(mscreenpix, spix, x, y);
+    return TRUE;
+}
+
+static Bool
+rrCheckPixmapBounding(ScreenPtr pScreen,
+                      RRCrtcPtr rr_crtc, int x, int y, int w, int h)
+{
+    RegionRec root_pixmap_region, total_region, new_crtc_region;
+    int i, c;
+    BoxRec newbox;
+    BoxPtr newsize;
+    ScreenPtr slave;
+    int new_width, new_height;
+    PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
+    rrScrPriv(pScreen);
+
+    PixmapRegionInit(&root_pixmap_region, screen_pixmap);
+    RegionInit(&total_region, NULL, 0);
+
+    /* have to iterate all the crtcs of the attached gpu masters
+       and all their output slaves */
+    for (c = 0; c < pScrPriv->numCrtcs; c++) {
+        if (pScrPriv->crtcs[c] == rr_crtc) {
+            newbox.x1 = x;
+            newbox.x2 = x + w;
+            newbox.y1 = y;
+            newbox.y2 = y + h;
+        } else {
+            if (!pScrPriv->crtcs[c]->mode)
+                continue;
+            newbox.x1 = pScrPriv->crtcs[c]->x;
+            newbox.x2 = pScrPriv->crtcs[c]->x + pScrPriv->crtcs[c]->mode->mode.width;
+            newbox.y1 = pScrPriv->crtcs[c]->y;
+            newbox.y2 = pScrPriv->crtcs[c]->y + pScrPriv->crtcs[c]->mode->mode.height;
+        }
+        RegionInit(&new_crtc_region, &newbox, 1);
+        RegionUnion(&total_region, &total_region, &new_crtc_region);
+    }
+
+    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
+        rrScrPriv(slave);
+        for (c = 0; c < pScrPriv->numCrtcs; c++)
+            if (pScrPriv->crtcs[c] == rr_crtc) {
+                newbox.x1 = x;
+                newbox.x2 = x + w;
+                newbox.y1 = y;
+                newbox.y2 = y + h;
+            }
+            else {
+                if (!pScrPriv->crtcs[c]->mode)
+                    continue;
+                newbox.x1 = pScrPriv->crtcs[c]->x;
+                newbox.x2 = pScrPriv->crtcs[c]->x + pScrPriv->crtcs[c]->mode->mode.width;
+                newbox.y1 = pScrPriv->crtcs[c]->y;
+                newbox.y2 = pScrPriv->crtcs[c]->y + pScrPriv->crtcs[c]->mode->mode.height;
+            }
+        RegionInit(&new_crtc_region, &newbox, 1);
+        RegionUnion(&total_region, &total_region, &new_crtc_region);
+    }
+
+    newsize = RegionExtents(&total_region);
+    new_width = newsize->x2 - newsize->x1;
+    new_height = newsize->y2 - newsize->y1;
+
+    if (new_width == screen_pixmap->drawable.width &&
+        new_height == screen_pixmap->drawable.height) {
+        ErrorF("adjust shatters %d %d\n", newsize->x1, newsize->x2);
+    } else {
+        int ret;
+        rrScrPriv(pScreen);
+        ret = pScrPriv->rrScreenSetSize(pScreen,
+                                           new_width, new_height, 0, 0);
+    }
+
+    /* set shatters TODO */
+    return TRUE;
+}
+
 /*
  * Request that the Crtc be reconfigured
  */
@@ -394,6 +542,26 @@ RRCrtcSet(RRCrtcPtr crtc,
         ret = TRUE;
     }
     else {
+        if (pScreen->isGPU) {
+            ScreenPtr master = pScreen->current_master;
+            int width = 0, height = 0;
+
+            if (mode) {
+                width = mode->mode.width;
+                height = mode->mode.height;
+            }
+            ErrorF("have a master to look out for\n");
+            ret = rrCheckPixmapBounding(master, crtc,
+                                        x, y, width, height);
+            if (!ret)
+                return FALSE;
+
+            if (pScreen->current_master) {
+                ret = rrCreateSharedPixmap(crtc, width, height, x, y);
+                ErrorF("need to create shared pixmap %d", ret);
+
+            }
+        }
 #if RANDR_12_INTERFACE
         if (pScrPriv->rrCrtcSet) {
             ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
@@ -508,6 +676,9 @@ RRCrtcDestroyResource(pointer value, XID pid)
             }
         }
     }
+
+    if (crtc->scanout_pixmap)
+        RRCrtcDetachScanoutPixmap(crtc);
     free(crtc->gammaRed);
     if (crtc->mode)
         RRModeDestroy(crtc->mode);
commit 0b0e7148925e1f835d4f4f06e402a97023531828
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu May 24 16:03:31 2012 +0100

    exa: pixmap sharing infrastructure (v3)
    
    This just adds exa interfaces for mixed exa so drivers can
    share and set shared pixmaps up correctly.
    
    v2: update for passing slave screen.
    v3: update for void *
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/exa/exa.c b/exa/exa.c
index 623ece0..d12344f 100644
--- a/exa/exa.c
+++ b/exa/exa.c
@@ -782,6 +782,10 @@ exaCloseScreen(ScreenPtr pScreen)
     unwrap(pExaScr, pScreen, ChangeWindowAttributes);
     unwrap(pExaScr, pScreen, BitmapToRegion);
     unwrap(pExaScr, pScreen, CreateScreenResources);
+    if (pExaScr->SavedSharePixmapBacking)
+        unwrap(pExaScr, pScreen, SharePixmapBacking);
+    if (pExaScr->SavedSetSharedPixmapBacking)
+        unwrap(pExaScr, pScreen, SetSharedPixmapBacking);
     unwrap(pExaScr, ps, Composite);
     if (pExaScr->SavedGlyphs)
         unwrap(pExaScr, ps, Glyphs);
@@ -976,6 +980,9 @@ exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo)
                 wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_mixed);
                 wrap(pExaScr, pScreen, ModifyPixmapHeader,
                      exaModifyPixmapHeader_mixed);
+                wrap(pExaScr, pScreen, SharePixmapBacking, exaSharePixmapBacking_mixed);
+                wrap(pExaScr, pScreen, SetSharedPixmapBacking, exaSetSharedPixmapBacking_mixed);
+
                 pExaScr->do_migration = exaDoMigration_mixed;
                 pExaScr->pixmap_has_gpu_copy = exaPixmapHasGpuCopy_mixed;
                 pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed;
diff --git a/exa/exa.h b/exa/exa.h
index 8a6539f..be022b2 100644
--- a/exa/exa.h
+++ b/exa/exa.h
@@ -39,7 +39,7 @@
 #include "fb.h"
 
 #define EXA_VERSION_MAJOR   2
-#define EXA_VERSION_MINOR   5
+#define EXA_VERSION_MINOR   6
 #define EXA_VERSION_RELEASE 0
 
 typedef struct _ExaOffscreenArea ExaOffscreenArea;
@@ -694,6 +694,10 @@ typedef struct _ExaDriver {
                             int depth, int usage_hint, int bitsPerPixel,
                             int *new_fb_pitch);
     /** @} */
+    Bool (*SharePixmapBacking)(PixmapPtr pPixmap, ScreenPtr slave, void **handle_p);
+
+    Bool (*SetSharedPixmapBacking)(PixmapPtr pPixmap, void *handle);
+
 } ExaDriverRec, *ExaDriverPtr;
 
 /** @name EXA driver flags
diff --git a/exa/exa_mixed.c b/exa/exa_mixed.c
index 0681731..0fb4091 100644
--- a/exa/exa_mixed.c
+++ b/exa/exa_mixed.c
@@ -294,3 +294,36 @@ exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap)
 
     return ret;
 }
+
+Bool
+exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr slave, void **handle_p)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    Bool ret = FALSE;
+
+    exaMoveInPixmap(pPixmap);
+    /* get the driver to give us a handle */
+    if (pExaScr->info->SharePixmapBacking)
+        ret = pExaScr->info->SharePixmapBacking(pPixmap, slave, handle_p);
+
+    return ret;
+}
+
+Bool
+exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    ExaScreenPriv(pScreen);
+    Bool ret = FALSE;
+
+    if (pExaScr->info->SetSharedPixmapBacking)
+        ret = pExaScr->info->SetSharedPixmapBacking(pPixmap, handle);
+
+    if (ret == TRUE)
+        exaMoveInPixmap(pPixmap);
+
+    return ret;
+}
+
+
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 68eadc5..ea7e7fa 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -163,6 +163,8 @@ typedef struct {
     BitmapToRegionProcPtr SavedBitmapToRegion;
     CreateScreenResourcesProcPtr SavedCreateScreenResources;
     ModifyPixmapHeaderProcPtr SavedModifyPixmapHeader;
+    SharePixmapBackingProcPtr SavedSharePixmapBacking;
+    SetSharedPixmapBackingProcPtr SavedSetSharedPixmapBacking;
     SourceValidateProcPtr SavedSourceValidate;
     CompositeProcPtr SavedComposite;
     TrianglesProcPtr SavedTriangles;
@@ -658,6 +660,11 @@ void
 void
  exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg);
 
+Bool
+exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle);
+Bool
+exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr slave, void **handle_p);
+
 /* exa_render.c */
 Bool
  exaOpReadsDestination(CARD8 op);
commit fd6c1bf0a3efced3ad4623dbd4716230a5f2419e
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu May 24 16:03:19 2012 +0100

    dix: pixmap sharing infrastructure (v3)
    
    This is a hooks for pixmap sharing and tracking.
    
    The pixmap sharing ones get an integer handle for the pixmap
    and use a handle to be the backing for a pixmap.
    
    The tracker interface is to be used when a GPU needs to
    track pixmaps to be updated for another GPU.
    
    v2: pass slave to sharing so it can use it to work out driver.
    
    v3: use void * as per keithp's suggestion.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index 7efc5c3..3a738d3 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -179,6 +179,8 @@ typedef void (*ClipNotifyProcPtr) (WindowPtr /*pWindow */ ,
 #define CREATE_PIXMAP_USAGE_BACKING_PIXMAP              2
 /* pixmap will contain a glyph */
 #define CREATE_PIXMAP_USAGE_GLYPH_PICTURE               3
+/* pixmap will be shared */
+#define CREATE_PIXMAP_USAGE_SHARED                      4
 
 typedef PixmapPtr (*CreatePixmapProcPtr) (ScreenPtr /*pScreen */ ,
                                           int /*width */ ,
@@ -339,6 +341,16 @@ typedef void (*DeviceCursorCleanupProcPtr) (DeviceIntPtr /* pDev */ ,
 typedef void (*ConstrainCursorHarderProcPtr) (DeviceIntPtr, ScreenPtr, int,
                                               int *, int *);
 
+
+typedef Bool (*SharePixmapBackingProcPtr)(PixmapPtr, ScreenPtr, void **);
+
+typedef Bool (*SetSharedPixmapBackingProcPtr)(PixmapPtr, void *);
+
+typedef Bool (*StartPixmapTrackingProcPtr)(PixmapPtr, PixmapPtr,
+                                           int x, int y);
+
+typedef Bool (*StopPixmapTrackingProcPtr)(PixmapPtr, PixmapPtr);
+
 typedef struct _Screen {
     int myNum;                  /* index of this instance in Screens[] */
     ATOM id;
@@ -488,6 +500,11 @@ typedef struct _Screen {
     struct xorg_list output_slave_list;
     struct xorg_list output_head;
 
+    SharePixmapBackingProcPtr SharePixmapBacking;
+    SetSharedPixmapBackingProcPtr SetSharedPixmapBacking;
+
+    StartPixmapTrackingProcPtr StartPixmapTracking;
+    StopPixmapTrackingProcPtr StopPixmapTracking;
 } ScreenRec;
 
 static inline RegionPtr
commit 382dd45bb88fa92764bf0ecd655cb9890eb84960
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu May 24 15:39:05 2012 +0100

    dix: add ability to link output slave gpus to the current gpu (v1.1)
    
    Just add the interfaces to attach/detach output slaves, and
    a linked list to keep track of them. Hook up the randr providers
    list to include these slaves.
    
    v1.1: add another assert to the add path.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index 9e84621..29ac5a4 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -3743,6 +3743,7 @@ static int init_screen(ScreenPtr pScreen, int i, Bool gpu)
     pScreen->CreateScreenResources = 0;
 
     xorg_list_init(&pScreen->unattached_list);
+    xorg_list_init(&pScreen->output_slave_list);
 
     /*
      * This loop gets run once for every Screen that gets added,
@@ -3909,3 +3910,19 @@ DetachUnboundGPU(ScreenPtr slave)
     slave->current_master = NULL;
 }
 
+void
+AttachOutputGPU(ScreenPtr pScreen, ScreenPtr new)
+{
+    assert(new->isGPU);
+    assert(!new->current_master);
+    xorg_list_add(&new->output_head, &pScreen->output_slave_list);
+    new->current_master = pScreen;
+}
+
+void
+DetachOutputGPU(ScreenPtr slave)
+{
+    assert(slave->isGPU);
+    xorg_list_del(&slave->output_head);
+    slave->current_master = NULL;
+}
diff --git a/include/screenint.h b/include/screenint.h
index c0c60ef..b992cc2 100644
--- a/include/screenint.h
+++ b/include/screenint.h
@@ -76,6 +76,12 @@ AttachUnboundGPU(ScreenPtr pScreen, ScreenPtr new);
 extern _X_EXPORT void
 DetachUnboundGPU(ScreenPtr unbound);
 
+extern _X_EXPORT void
+AttachOutputGPU(ScreenPtr pScreen, ScreenPtr new);
+
+extern _X_EXPORT void
+DetachOutputGPU(ScreenPtr output);
+
 typedef struct _ColormapRec *ColormapPtr;
 
 #endif                          /* SCREENINT_H */
diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index 6b738de..7efc5c3 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -485,6 +485,9 @@ typedef struct _Screen {
 
     ScreenPtr current_master;
 
+    struct xorg_list output_slave_list;
+    struct xorg_list output_head;
+
 } ScreenRec;
 
 static inline RegionPtr
diff --git a/randr/rrprovider.c b/randr/rrprovider.c
index aae3095..3773200 100644
--- a/randr/rrprovider.c
+++ b/randr/rrprovider.c
@@ -72,6 +72,10 @@ ProcRRGetProviders (ClientPtr client)
 
     if (pScrPriv->provider)
         total_providers++;
+    xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) {
+        pScrPriv = rrGetScrPriv(iter);
+        total_providers += pScrPriv->provider ? 1 : 0;
+    }
     xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) {
         pScrPriv = rrGetScrPriv(iter);
         total_providers += pScrPriv->provider ? 1 : 0;
@@ -105,6 +109,9 @@ ProcRRGetProviders (ClientPtr client)
 
         providers = (RRProvider *)extra;
         ADD_PROVIDER(pScreen);
+        xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) {
+            ADD_PROVIDER(iter);
+        }
         xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) {
             ADD_PROVIDER(iter);
         }
commit 05d2472cd242293a5fa205efff5734a3380072b4
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu Jun 14 15:03:02 2012 +0100

    xf86dga: handle DGAAvailable for gpu screens. (v2)
    
    v2: Split out DGAAvailable into two interfaces, one for calls from protocol
    decoding and one for internal usage, after discussion with ajax and keithp.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/common/xf86DGA.c b/hw/xfree86/common/xf86DGA.c
index 6416372..61612c3 100644
--- a/hw/xfree86/common/xf86DGA.c
+++ b/hw/xfree86/common/xf86DGA.c
@@ -521,18 +521,27 @@ DGAChangePixmapMode(int index, int *x, int *y, int mode)
 }
 
 Bool
-DGAAvailable(int index)
+DGAScreenAvailable(ScreenPtr pScreen)
 {
     if (!DGAScreenKeyRegistered)
         return FALSE;
 
-    if (DGA_GET_SCREEN_PRIV(screenInfo.screens[index]))
+    if (DGA_GET_SCREEN_PRIV(pScreen))
         return TRUE;
-
     return FALSE;
 }
 
 Bool
+DGAAvailable(int index)
+{
+    ScreenPtr pScreen;
+
+    assert(index < MAXSCREENS);
+    pScreen = screenInfo.screens[index];
+    return DGAScreenAvailable(pScreen);
+}
+
+Bool
 DGAActive(int index)
 {
     DGAScreenPtr pScreenPriv;
diff --git a/hw/xfree86/dixmods/extmod/dgaproc.h b/hw/xfree86/dixmods/extmod/dgaproc.h
index b4e0ddf..2c2fae0 100644
--- a/hw/xfree86/dixmods/extmod/dgaproc.h
+++ b/hw/xfree86/dixmods/extmod/dgaproc.h
@@ -64,6 +64,7 @@ extern _X_EXPORT void
  DGASelectInput(int Index, ClientPtr client, long mask);
 
 extern _X_EXPORT Bool DGAAvailable(int Index);
+extern _X_EXPORT Bool DGAScreenAvailable(ScreenPtr pScreen);
 extern _X_EXPORT Bool DGAActive(int Index);
 extern _X_EXPORT void DGAShutdown(void);
 extern _X_EXPORT void DGAInstallCmap(ColormapPtr cmap);
diff --git a/hw/xfree86/modes/xf86DiDGA.c b/hw/xfree86/modes/xf86DiDGA.c
index bb954ac..3f1a330 100644
--- a/hw/xfree86/modes/xf86DiDGA.c
+++ b/hw/xfree86/modes/xf86DiDGA.c
@@ -178,7 +178,7 @@ _xf86_di_dga_reinit_internal(ScreenPtr pScreen)
     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
 
-    if (!DGAAvailable(pScreen->myNum))
+    if (!DGAScreenAvailable(pScreen))
         return TRUE;
 
     if (!xf86_dga_get_modes(pScreen))
diff --git a/hw/xfree86/vgahw/vgaCmap.c b/hw/xfree86/vgahw/vgaCmap.c
index a1aa405..e7a0d02 100644
--- a/hw/xfree86/vgahw/vgaCmap.c
+++ b/hw/xfree86/vgahw/vgaCmap.c
@@ -97,7 +97,7 @@ xColorItem *pdefs;
     }
 
     writeColormap = scrninfp->vtSema;
-    if (DGAAvailable(scrnIndex)) {
+    if (DGAScreenAvailable(pmap->pScreen)) {
         writeColormap = writeColormap ||
             (DGAGetDirectMode(scrnIndex) &&
              !(DGAGetFlags(scrnIndex) & XF86DGADirectColormap)) ||
commit 3cbc4c10b52896324fe14d2ab56bd54577c9294c
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Jun 13 14:35:49 2012 +0100

    randr: expose unattached providers to the clients.
    
    This provides the unattached provider list to the clients.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/randr/rrprovider.c b/randr/rrprovider.c
index db7074c..aae3095 100644
--- a/randr/rrprovider.c
+++ b/randr/rrprovider.c
@@ -59,6 +59,7 @@ ProcRRGetProviders (ClientPtr client)
     unsigned int extraLen;
     RRProvider *providers;
     int total_providers = 0, count_providers = 0;
+    ScreenPtr iter;
 
     REQUEST_SIZE_MATCH(xRRGetProvidersReq);
     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
@@ -71,6 +72,10 @@ ProcRRGetProviders (ClientPtr client)
 
     if (pScrPriv->provider)
         total_providers++;
+    xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) {
+        pScrPriv = rrGetScrPriv(iter);
+        total_providers += pScrPriv->provider ? 1 : 0;
+    }
 
     pScrPriv = rrGetScrPriv(pScreen);
     rep.pad = 0;
@@ -100,6 +105,9 @@ ProcRRGetProviders (ClientPtr client)
 
         providers = (RRProvider *)extra;
         ADD_PROVIDER(pScreen);
+        xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) {
+            ADD_PROVIDER(iter);
+        }
     }
 
     if (client->swapped) {
commit d0e138c3f3e58ef127dad6c6aef48b1713b5ce58
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Jun 13 14:32:05 2012 +0100

    dix: attach unbound screens to protocol screen 0 (v2)
    
    This is the default attachment, unbound gpu screens get
    attached to the 0 protocol screen.
    
    detach on hotunplug.
    
    v2: detach after tearing down crtc/outputs.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c
index aa17a58..058d09f 100644
--- a/hw/xfree86/common/xf86Init.c
+++ b/hw/xfree86/common/xf86Init.c
@@ -920,6 +920,9 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
 #endif
     }
 
+    for (i = 0; i < xf86NumGPUScreens; i++)
+        AttachUnboundGPU(xf86Screens[0]->pScreen, xf86GPUScreens[i]->pScreen);
+
     xf86VGAarbiterWrapFunctions();
     OsReleaseSIGIO();
 
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index a2cd856..0bf14eb 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -736,6 +736,11 @@ xf86CrtcCloseScreen(ScreenPtr screen)
 
         crtc->randr_crtc = NULL;
     }
+    /* detach any providers */
+    if (config->randr_provider) {
+        if (screen->current_master)
+            DetachUnboundGPU(screen);
+    }
     xf86RandR12CloseScreen(screen);
 
     free(config->name);
commit 4caad34c932115dc0a9fd9c2995ebb2d38b9359c
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Jun 13 14:27:42 2012 +0100

    dix: add unattached list for attaching screens to initially. (v1.1)
    
    This list is meant for attaching unbound gpu screens to initially,
    before the client side rebinds them.
    
    v1.1: add another assert in the add path.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/dix/dispatch.c b/dix/dispatch.c
index fa39728..9e84621 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -3742,6 +3742,8 @@ static int init_screen(ScreenPtr pScreen, int i, Bool gpu)
     pScreen->ClipNotify = 0;    /* for R4 ddx compatibility */
     pScreen->CreateScreenResources = 0;
 
+    xorg_list_init(&pScreen->unattached_list);
+
     /*
      * This loop gets run once for every Screen that gets added,
      * but thats ok.  If the ddx layer initializes the formats
@@ -3889,3 +3891,21 @@ RemoveGPUScreen(ScreenPtr pScreen)
     free(pScreen);
 
 }
+
+void
+AttachUnboundGPU(ScreenPtr pScreen, ScreenPtr new)
+{
+    assert(new->isGPU);
+    assert(!new->current_master);
+    xorg_list_add(&new->unattached_head, &pScreen->unattached_list);
+    new->current_master = pScreen;
+}
+
+void
+DetachUnboundGPU(ScreenPtr slave)
+{
+    assert(slave->isGPU);
+    xorg_list_del(&slave->unattached_head);
+    slave->current_master = NULL;
+}
+
diff --git a/include/screenint.h b/include/screenint.h
index 8205f63..c0c60ef 100644
--- a/include/screenint.h
+++ b/include/screenint.h
@@ -71,6 +71,11 @@ extern _X_EXPORT int AddGPUScreen(Bool (*pfnInit) (ScreenPtr /*pScreen */ ,
 
 extern _X_EXPORT void RemoveGPUScreen(ScreenPtr pScreen);
 
+extern _X_EXPORT void
+AttachUnboundGPU(ScreenPtr pScreen, ScreenPtr new);
+extern _X_EXPORT void
+DetachUnboundGPU(ScreenPtr unbound);
+
 typedef struct _ColormapRec *ColormapPtr;
 
 #endif                          /* SCREENINT_H */
diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index bcac475..6b738de 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -479,6 +479,12 @@ typedef struct _Screen {
     Bool canDoBGNoneRoot;
 
     Bool isGPU;
+
+    struct xorg_list unattached_list;
+    struct xorg_list unattached_head;
+
+    ScreenPtr current_master;
+
 } ScreenRec;
 
 static inline RegionPtr
commit 9b5cf2ed76b00937af12304e0e8dbd60df62067e
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Jun 13 14:17:06 2012 +0100

    xfree86: add framework for provider support in ddx. (v4)
    
    This adds the framework for DDX provider support.
    
    v2: as per keithp's suggestion remove the xf86 provider object
    and just store it in the toplevel object.
    
    v3: update for new protocol
    
    v4: drop devPrivate, free name
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/common/xf86str.h b/hw/xfree86/common/xf86str.h
index 6bd6a62..0590262 100644
--- a/hw/xfree86/common/xf86str.h
+++ b/hw/xfree86/common/xf86str.h
@@ -814,6 +814,7 @@ typedef struct _ScrnInfoRec {
     funcPointer reservedFuncs[NUM_RESERVED_FUNCS];
 
     Bool is_gpu;
+    uint32_t capabilities;
 } ScrnInfoRec;
 
 typedef struct {
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 2c8878f..a2cd856 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -738,6 +738,7 @@ xf86CrtcCloseScreen(ScreenPtr screen)
     }
     xf86RandR12CloseScreen(screen);
 
+    free(config->name);
     return screen->CloseScreen(screen);
 }
 
@@ -3202,3 +3203,20 @@ xf86_crtc_supports_gamma(ScrnInfoPtr pScrn)
 
     return FALSE;
 }
+
+void
+xf86ProviderSetup(ScrnInfoPtr scrn,
+                  const xf86ProviderFuncsRec *funcs, const char *name)
+{
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+
+    assert(!xf86_config->name);
+    assert(name);
+
+    xf86_config->name = strdup(name);
+    xf86_config->provider_funcs = funcs;
+#ifdef RANDR_12_INTERFACE
+    xf86_config->randr_provider = NULL;
+#endif
+}
+
diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
index a6a3c2e..58d8cec 100644
--- a/hw/xfree86/modes/xf86Crtc.h
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -607,6 +607,29 @@ struct _xf86Output {
     INT16 initialBorder[4];
 };
 
+typedef struct _xf86ProviderFuncs {
+    /**
+     * Called to allow the provider a chance to create properties after the
+     * RandR objects have been created.
+     */
+    void
+    (*create_resources) (ScrnInfoPtr scrn);
+
+    /**
+     * Callback when an provider's property has changed.
+     */
+    Bool
+    (*set_property) (ScrnInfoPtr scrn,
+                     Atom property, RRPropertyValuePtr value);
+
+    /**
+     * Callback to get an updated property value
+     */
+    Bool
+    (*get_property) (ScrnInfoPtr provider, Atom property);
+
+} xf86ProviderFuncsRec, *xf86ProviderFuncsPtr;
+
 typedef struct _xf86CrtcConfigFuncs {
     /**
      * Requests that the driver resize the screen.
@@ -681,6 +704,13 @@ typedef struct _xf86CrtcConfig {
     /* callback when crtc configuration changes */
     xf86_crtc_notify_proc_ptr xf86_crtc_notify;
 
+    char *name;
+    const xf86ProviderFuncsRec *provider_funcs;
+#ifdef RANDR_12_INTERFACE
+    RRProviderPtr randr_provider;
+#else
+    void *randr_provider;
+#endif
 } xf86CrtcConfigRec, *xf86CrtcConfigPtr;
 
 extern _X_EXPORT int xf86CrtcConfigPrivateIndex;
@@ -975,4 +1005,8 @@ extern _X_EXPORT void
 extern _X_EXPORT Bool
  xf86_crtc_supports_gamma(ScrnInfoPtr pScrn);
 
+extern _X_EXPORT void
+xf86ProviderSetup(ScrnInfoPtr scrn,
+                  const xf86ProviderFuncsRec * funcs, const char *name);
+
 #endif                          /* _XF86CRTC_H_ */
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index 59b6f82..41c0b11 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -1552,6 +1552,14 @@ xf86RandR12CreateObjects12(ScreenPtr pScreen)
             output->funcs->create_resources(output);
         RRPostPendingProperties(output->randr_output);
     }
+
+    if (config->name) {
+        config->randr_provider = RRProviderCreate(pScreen, config->name,
+                                                  strlen(config->name));
+
+        RRProviderSetCapabilities(config->randr_provider, pScrn->capabilities);
+    }
+
     return TRUE;
 }
 
@@ -1746,6 +1754,42 @@ xf86RandR12EnterVT(ScrnInfoPtr pScrn)
 }
 
 static Bool
+xf86RandR14ProviderSetProperty(ScreenPtr pScreen,
+                             RRProviderPtr randr_provider,
+                             Atom property, RRPropertyValuePtr value)
+{
+    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+
+    /* If we don't have any property handler, then we don't care what the
+     * user is setting properties to.
+     */
+    if (config->provider_funcs->set_property == NULL)
+        return TRUE;
+
+    /*
+     * This function gets called even when vtSema is FALSE, as
+     * drivers will need to remember the correct value to apply
+     * when the VT switch occurs
+     */
+    return config->provider_funcs->set_property(pScrn, property, value);
+}
+
+static Bool
+xf86RandR14ProviderGetProperty(ScreenPtr pScreen,
+                               RRProviderPtr randr_provider, Atom property)
+{
+    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+
+    if (config->provider_funcs->get_property == NULL)
+        return TRUE;
+
+    /* Should be safe even w/o vtSema */
+    return config->provider_funcs->get_property(pScrn, property);
+}
+
+static Bool
 xf86RandR12Init12(ScreenPtr pScreen)
 {
     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
@@ -1767,6 +1811,10 @@ xf86RandR12Init12(ScreenPtr pScreen)
 #endif
     rp->rrModeDestroy = xf86RandR12ModeDestroy;
     rp->rrSetConfig = NULL;
+
+    rp->rrProviderSetProperty = xf86RandR14ProviderSetProperty;
+    rp->rrProviderGetProperty = xf86RandR14ProviderGetProperty;
+
     pScrn->PointerMoved = xf86RandR12PointerMoved;
     pScrn->ChangeGamma = xf86RandR12ChangeGamma;
 
commit 66d92afeaeed9f4a19267d95a1f81b9bf27162a5
Author: Dave Airlie <airlied at redhat.com>
Date:   Wed Jun 13 14:03:04 2012 +0100

    randr: add provider object and provider property support (v6)
    
    This adds the initial provider object and provider property
    support to the randr dix code.
    
    v2: destroy provider in screen close
    v2.1: fix whitespace
    
    v3: update for latest rev of protocol + renumber after 1.4 tearout.
    
    v4: fix logic issue, thanks Samsagax on irc
    
    v5: keithp's review: fix current_role, fix copyrights, fix master
    reporting crtc/outputs.
    
    v6: port to new randr interface, drop all set role bits for now
    
    v7: drop devPrivate in provider, not needed, add BadMatch returns
    for NULL SetProviderOffloadSink and SetProviderOutputSource, drop
    the old typedef.
    
    Reviewed-by: Keith Packard <keithp at keithp.com>
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c
index 3bfb22e..24b9473 100644
--- a/hw/xfree86/common/xf86platformBus.c
+++ b/hw/xfree86/common/xf86platformBus.c
@@ -432,14 +432,17 @@ xf86platformAddDevice(int index)
         xf86DeleteScreen(xf86GPUScreens[i]);
         return -1;
     }
-        
+
    scr_index = AddGPUScreen(xf86GPUScreens[i]->ScreenInit, 0, NULL);
-   
+
    dixSetPrivate(&xf86GPUScreens[i]->pScreen->devPrivates,
                  xf86ScreenKey, xf86GPUScreens[i]);
 
    CreateScratchPixmapsForScreen(xf86GPUScreens[i]->pScreen);
-  
+
+   /* attach unbound to 0 protocol screen */
+   AttachUnboundGPU(xf86Screens[0]->pScreen, xf86GPUScreens[i]->pScreen);
+
    return 0;
 }
 
diff --git a/randr/Makefile.am b/randr/Makefile.am
index de338b9..ccaff3f 100644
--- a/randr/Makefile.am
+++ b/randr/Makefile.am
@@ -18,6 +18,8 @@ librandr_la_SOURCES =	\
 	rroutput.c	\
 	rrpointer.c	\
 	rrproperty.c	\
+	rrprovider.c    \
+	rrproviderproperty.c    \
 	rrscreen.c	\
 	rrsdispatch.c	\
 	rrtransform.h	\
diff --git a/randr/randr.c b/randr/randr.c
index 103da48..103c31e 100644
--- a/randr/randr.c
+++ b/randr/randr.c
@@ -94,6 +94,9 @@ RRCloseScreen(ScreenPtr pScreen)
     for (j = pScrPriv->numOutputs - 1; j >= 0; j--)
         RROutputDestroy(pScrPriv->outputs[j]);
 
+    if (pScrPriv->provider)
+        RRProviderDestroy(pScrPriv->provider);
+
     free(pScrPriv->crtcs);
     free(pScrPriv->outputs);
     free(pScrPriv);
@@ -176,6 +179,47 @@ SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent * from,
 }
 
 static void
+SRRProviderChangeNotifyEvent(xRRProviderChangeNotifyEvent * from,
+                         xRRProviderChangeNotifyEvent * to)
+{
+    to->type = from->type;
+    to->subCode = from->subCode;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->timestamp, to->timestamp);
+    cpswapl(from->window, to->window);
+    cpswapl(from->provider, to->provider);
+}
+
+static void
+SRRProviderPropertyNotifyEvent(xRRProviderPropertyNotifyEvent * from,
+                               xRRProviderPropertyNotifyEvent * to)
+{
+    to->type = from->type;
+    to->subCode = from->subCode;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->window, to->window);
+    cpswapl(from->provider, to->provider);
+    cpswapl(from->atom, to->atom);
+    cpswapl(from->timestamp, to->timestamp);
+    to->state = from->state;
+    /* pad1 */
+    /* pad2 */
+    /* pad3 */
+    /* pad4 */
+}
+
+static void
+SRRResourceChangeNotifyEvent(xRRResourceChangeNotifyEvent * from,
+                             xRRResourceChangeNotifyEvent * to)
+{
+    to->type = from->type;
+    to->subCode = from->subCode;
+    cpswaps(from->sequenceNumber, to->sequenceNumber);
+    cpswapl(from->timestamp, to->timestamp);
+    cpswapl(from->window, to->window);
+}
+
+static void
 SRRNotifyEvent(xEvent *from, xEvent *to)
 {
     switch (from->u.u.detail) {
@@ -191,6 +235,17 @@ SRRNotifyEvent(xEvent *from, xEvent *to)
         SRROutputPropertyNotifyEvent((xRROutputPropertyNotifyEvent *) from,
                                      (xRROutputPropertyNotifyEvent *) to);
         break;
+    case RRNotify_ProviderChange:
+        SRRProviderChangeNotifyEvent((xRRProviderChangeNotifyEvent *) from,
+                                   (xRRProviderChangeNotifyEvent *) to);
+        break;
+    case RRNotify_ProviderProperty:
+        SRRProviderPropertyNotifyEvent((xRRProviderPropertyNotifyEvent *) from,
+                                       (xRRProviderPropertyNotifyEvent *) to);
+        break;
+    case RRNotify_ResourceChange:
+        SRRResourceChangeNotifyEvent((xRRResourceChangeNotifyEvent *) from,
+                                   (xRRResourceChangeNotifyEvent *) to);
     default:
         break;
     }
@@ -356,7 +411,7 @@ RRExtensionInit(void)
     RRModeInitErrorValue();
     RRCrtcInitErrorValue();
     RROutputInitErrorValue();
-
+    RRProviderInitErrorValue();
 #ifdef PANORAMIX
     RRXineramaExtensionInit();
 #endif
diff --git a/randr/randrstr.h b/randr/randrstr.h
index 38fb107..3dac633 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -62,6 +62,7 @@
 typedef XID RRMode;
 typedef XID RROutput;
 typedef XID RRCrtc;
+typedef XID RRProvider;
 
 extern _X_EXPORT int RREventBase, RRErrorBase;
 
@@ -78,6 +79,7 @@ typedef struct _rrPropertyValue RRPropertyValueRec, *RRPropertyValuePtr;
 typedef struct _rrProperty RRPropertyRec, *RRPropertyPtr;
 typedef struct _rrCrtc RRCrtcRec, *RRCrtcPtr;
 typedef struct _rrOutput RROutputRec, *RROutputPtr;
+typedef struct _rrProvider RRProviderRec, *RRProviderPtr;
 
 struct _rrMode {
     int refcnt;
@@ -152,6 +154,16 @@ struct _rrOutput {
     void *devPrivate;
 };
 
+struct _rrProvider {
+    RRProvider id;
+    ScreenPtr pScreen;
+    uint32_t capabilities;
+    char *name;
+    int nameLength;
+    RRPropertyPtr properties;
+    Bool pendingProperties;
+};
+
 #if RANDR_12_INTERFACE
 typedef Bool (*RRScreenSetSizeProcPtr) (ScreenPtr pScreen,
                                         CARD16 width,
@@ -197,6 +209,13 @@ typedef Bool (*RRSetPanningProcPtr) (ScreenPtr pScrn,
 
 #endif                          /* RANDR_13_INTERFACE */
 
+typedef Bool (*RRProviderGetPropertyProcPtr) (ScreenPtr pScreen,
+                                            RRProviderPtr provider, Atom property);
+typedef Bool (*RRProviderSetPropertyProcPtr) (ScreenPtr pScreen,
+                                              RRProviderPtr provider,
+                                              Atom property,
+                                              RRPropertyValuePtr value);
+
 typedef Bool (*RRGetInfoProcPtr) (ScreenPtr pScreen, Rotation * rotations);
 typedef Bool (*RRCloseScreenProcPtr) (ScreenPtr pscreen);
 
@@ -247,6 +266,8 @@ typedef struct _rrScrPriv {
     RRSetPanningProcPtr rrSetPanning;
 #endif
 
+    RRProviderGetPropertyProcPtr rrProviderGetProperty;
+    RRProviderSetPropertyProcPtr rrProviderSetProperty;
     /*
      * Private part of the structure; not considered part of the ABI
      */
@@ -288,6 +309,8 @@ typedef struct _rrScrPriv {
     int size;
 #endif
     Bool discontiguous;
+
+    RRProviderPtr provider;
 } rrScrPrivRec, *rrScrPrivPtr;
 
 extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec;
@@ -331,7 +354,7 @@ extern _X_EXPORT RESTYPE RRClientType, RREventType;     /* resource types for ev
 extern _X_EXPORT DevPrivateKeyRec RRClientPrivateKeyRec;
 
 #define RRClientPrivateKey (&RRClientPrivateKeyRec)
-extern _X_EXPORT RESTYPE RRCrtcType, RRModeType, RROutputType;
+extern _X_EXPORT RESTYPE RRCrtcType, RRModeType, RROutputType, RRProviderType;
 
 #define VERIFY_RR_OUTPUT(id, ptr, a)\
     {\
@@ -363,6 +386,16 @@ extern _X_EXPORT RESTYPE RRCrtcType, RRModeType, RROutputType;
 	}\
     }
 
+#define VERIFY_RR_PROVIDER(id, ptr, a)\
+    {\
+        int rc = dixLookupResourceByType((pointer *)&(ptr), id,\
+                                         RRProviderType, client, a);\
+        if (rc != Success) {\
+            client->errorValue = id;\
+            return rc;\
+        }\
+    }
+
 #define GetRRClient(pClient)    ((RRClientPtr)dixLookupPrivate(&(pClient)->devPrivates, RRClientPrivateKey))
 #define rrClientPriv(pClient)	RRClientPtr pRRClient = GetRRClient(pClient)
 
@@ -824,6 +857,69 @@ extern _X_EXPORT int
 extern _X_EXPORT int
  ProcRRDeleteOutputProperty(ClientPtr client);
 
+/* rrprovider.c */
+extern _X_EXPORT void
+RRProviderInitErrorValue(void);
+
+extern _X_EXPORT int
+ProcRRGetProviders(ClientPtr client);
+
+extern _X_EXPORT int
+ProcRRGetProviderInfo(ClientPtr client);
+
+
+extern _X_EXPORT Bool
+RRProviderInit(void);
+
+extern _X_EXPORT RRProviderPtr
+RRProviderCreate(ScreenPtr pScreen, const char *name,
+                 int nameLength);
+
+extern _X_EXPORT void
+RRProviderDestroy (RRProviderPtr provider);
+
+extern _X_EXPORT void
+RRProviderSetCapabilities(RRProviderPtr provider, uint32_t capabilities);
+
+extern _X_EXPORT Bool
+RRProviderLookup(XID id, RRProviderPtr *provider_p);
+
+/* rrproviderproperty.c */
+
+extern _X_EXPORT void
+ RRDeleteAllProviderProperties(RRProviderPtr provider);
+
+extern _X_EXPORT RRPropertyValuePtr
+ RRGetProviderProperty(RRProviderPtr provider, Atom property, Bool pending);
+
+extern _X_EXPORT RRPropertyPtr
+ RRQueryProviderProperty(RRProviderPtr provider, Atom property);
+
+extern _X_EXPORT void
+ RRDeleteProviderProperty(RRProviderPtr provider, Atom property);
+
+extern _X_EXPORT int
+RRChangeProviderProperty(RRProviderPtr provider, Atom property, Atom type,
+                       int format, int mode, unsigned long len,
+                       pointer value, Bool sendevent, Bool pending);
+
+extern _X_EXPORT int
+ ProcRRGetProviderProperty(ClientPtr client);
+
+extern _X_EXPORT int
+ ProcRRListProviderProperties(ClientPtr client);
+
+extern _X_EXPORT int
+ ProcRRQueryProviderProperty(ClientPtr client);
+
+extern _X_EXPORT int
+ProcRRConfigureProviderProperty(ClientPtr client);
+
+extern _X_EXPORT int
+ProcRRChangeProviderProperty(ClientPtr client);
+
+extern _X_EXPORT int
+ ProcRRDeleteProviderProperty(ClientPtr client);
 /* rrxinerama.c */
 #ifdef XINERAMA
 extern _X_EXPORT void
diff --git a/randr/rrdispatch.c b/randr/rrdispatch.c
index 85cf037..054e47a 100644
--- a/randr/rrdispatch.c
+++ b/randr/rrdispatch.c
@@ -90,7 +90,8 @@ ProcRRSelectInput(ClientPtr client)
     if (stuff->enable & (RRScreenChangeNotifyMask |
                          RRCrtcChangeNotifyMask |
                          RROutputChangeNotifyMask |
-                         RROutputPropertyNotifyMask)) {
+                         RROutputPropertyNotifyMask |
+                         RRProviderPropertyNotifyMask)) {
         ScreenPtr pScreen = pWin->drawable.pScreen;
 
         rrScrPriv(pScreen);
@@ -241,4 +242,15 @@ int (*ProcRandrVector[RRNumberRequests]) (ClientPtr) = {
         ProcRRSetPanning,       /* 29 */
         ProcRRSetOutputPrimary, /* 30 */
         ProcRRGetOutputPrimary, /* 31 */
+/* V1.4 additions */
+        ProcRRGetProviders,     /* 32 */
+        ProcRRGetProviderInfo,  /* 33 */
+        NULL, /* 34 */
+        NULL, /* 35 */
+        ProcRRListProviderProperties,    /* 36 */
+        ProcRRQueryProviderProperty,     /* 37 */
+        ProcRRConfigureProviderProperty, /* 38 */
+        ProcRRChangeProviderProperty, /* 39 */
+        ProcRRDeleteProviderProperty, /* 40 */
+        ProcRRGetProviderProperty,    /* 41 */
 };
diff --git a/randr/rrprovider.c b/randr/rrprovider.c
new file mode 100644
index 0000000..db7074c
--- /dev/null
+++ b/randr/rrprovider.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright © 2012 Red Hat 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.
+ *
+ * Authors: Dave Airlie
+ */
+
+#include "randrstr.h"
+#include "swaprep.h"
+
+RESTYPE RRProviderType;
+
+/*
+ * Initialize provider type error value
+ */
+void
+RRProviderInitErrorValue(void)
+{
+    SetResourceTypeErrorValue(RRProviderType, RRErrorBase + BadRRProvider);
+}
+
+#define ADD_PROVIDER(_pScreen) do {                                 \
+    pScrPriv = rrGetScrPriv((_pScreen));                            \
+    if (pScrPriv->provider) {                                   \
+        providers[count_providers] = pScrPriv->provider->id;    \
+        if (client->swapped)                                    \
+            swapl(&providers[count_providers]);                 \
+        count_providers++;                                      \
+    }                                                           \
+    } while(0)
+
+int
+ProcRRGetProviders (ClientPtr client)
+{
+    REQUEST(xRRGetProvidersReq);
+    xRRGetProvidersReply rep;
+    WindowPtr pWin;
+    ScreenPtr pScreen;
+    rrScrPrivPtr pScrPriv;
+    int rc;
+    CARD8 *extra;
+    unsigned int extraLen;
+    RRProvider *providers;
+    int total_providers = 0, count_providers = 0;
+
+    REQUEST_SIZE_MATCH(xRRGetProvidersReq);
+    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
+    if (rc != Success)
+        return rc;
+
+    pScreen = pWin->drawable.pScreen;
+
+    pScrPriv = rrGetScrPriv(pScreen);
+
+    if (pScrPriv->provider)
+        total_providers++;
+
+    pScrPriv = rrGetScrPriv(pScreen);
+    rep.pad = 0;
+
+    if (!pScrPriv)
+    {
+        rep.type = X_Reply;
+        rep.sequenceNumber = client->sequence;
+        rep.length = 0;
+        rep.timestamp = currentTime.milliseconds;
+        rep.nProviders = 0;
+        extra = NULL;
+        extraLen = 0;
+    } else {
+        rep.type = X_Reply;
+        rep.sequenceNumber = client->sequence;
+        rep.timestamp = pScrPriv->lastSetTime.milliseconds;
+        rep.nProviders = total_providers;
+        rep.length = total_providers;
+        extraLen = rep.length << 2;
+        if (extraLen) {
+            extra = malloc(extraLen);
+            if (!extra)
+                return BadAlloc;
+        } else
+            extra = NULL;
+
+        providers = (RRProvider *)extra;
+        ADD_PROVIDER(pScreen);
+    }
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swapl(&rep.timestamp);
+        swaps(&rep.nProviders);
+    }
+    WriteToClient(client, sizeof(xRRGetProvidersReply), (char *)&rep);
+    if (extraLen)
+    {
+        WriteToClient (client, extraLen, (char *) extra);
+        free(extra);
+    }
+    return Success;
+}
+
+int
+ProcRRGetProviderInfo (ClientPtr client)
+{
+    REQUEST(xRRGetProviderInfoReq);
+    xRRGetProviderInfoReply rep;
+    rrScrPrivPtr pScrPriv;
+    RRProviderPtr provider;
+    ScreenPtr pScreen;
+    CARD8 *extra;
+    unsigned int extraLen = 0;
+    RRCrtc *crtcs;
+    RROutput *outputs;
+    int i;
+    char *name;
+    ScreenPtr provscreen;
+    RRProvider *providers;
+    uint32_t *prov_cap;
+ 
+    REQUEST_SIZE_MATCH(xRRGetProviderInfoReq);
+    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
+
+    pScreen = provider->pScreen;
+    pScrPriv = rrGetScrPriv(pScreen);
+
+    rep.type = X_Reply;
+    rep.status = RRSetConfigSuccess;
+    rep.sequenceNumber = client->sequence;
+    rep.length = 0;
+    rep.capabilities = provider->capabilities;
+    rep.nameLength = provider->nameLength;
+    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
+    rep.nCrtcs = pScrPriv->numCrtcs;
+    rep.nOutputs = pScrPriv->numOutputs;
+
+    /* count associated providers */
+    rep.nAssociatedProviders = 0;
+    rep.length = (pScrPriv->numCrtcs + pScrPriv->numOutputs +
+                  (rep.nAssociatedProviders * 2) + bytes_to_int32(rep.nameLength));
+
+    extraLen = rep.length << 2;
+    if (extraLen) {
+        extra = malloc(extraLen);
+        if (!extra)
+            return BadAlloc;
+    }
+    else
+        extra = NULL;
+
+    crtcs = (RRCrtc *)extra;
+    outputs = (RROutput *)(crtcs + rep.nCrtcs);
+    providers = (RRProvider *)(outputs + rep.nOutputs);
+    prov_cap = (unsigned int *)(providers + rep.nAssociatedProviders);
+    name = (char *)(prov_cap + rep.nAssociatedProviders);
+
+    for (i = 0; i < pScrPriv->numCrtcs; i++) {
+        crtcs[i] = pScrPriv->crtcs[i]->id;
+        if (client->swapped)
+            swapl(&crtcs[i]);
+    }
+
+    for (i = 0; i < pScrPriv->numOutputs; i++) {
+        outputs[i] = pScrPriv->outputs[i]->id;
+        if (client->swapped)
+            swapl(&outputs[i]);
+    }
+
+    memcpy(name, provider->name, rep.nameLength);
+    if (client->swapped) {
+              swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swapl(&rep.capabilities);
+        swaps(&rep.nCrtcs);
+        swaps(&rep.nOutputs);
+        swaps(&rep.nameLength);
+    }
+    WriteToClient(client, sizeof(xRRGetProviderInfoReply), (char *)&rep);
+    if (extraLen)
+    {
+        WriteToClient (client, extraLen, (char *) extra);
+        free(extra);
+    }
+    return Success;
+}
+
+RRProviderPtr
+RRProviderCreate(ScreenPtr pScreen, const char *name,
+                 int nameLength)
+{
+    RRProviderPtr provider;
+    rrScrPrivPtr pScrPriv;
+
+    pScrPriv = rrGetScrPriv(pScreen);
+
+    provider = calloc(1, sizeof(RRProviderRec) + nameLength + 1);
+    if (!provider)
+        return NULL;
+
+    provider->id = FakeClientID(0);
+    provider->pScreen = pScreen;
+    provider->name = (char *) (provider + 1);
+    provider->nameLength = nameLength;
+    memcpy(provider->name, name, nameLength);
+    provider->name[nameLength] = '\0';
+
+    if (!AddResource (provider->id, RRProviderType, (pointer) provider))
+        return NULL;
+    pScrPriv->provider = provider;
+    return provider;
+}
+
+/*
+ * Destroy a provider at shutdown
+ */
+void
+RRProviderDestroy (RRProviderPtr provider)
+{
+    FreeResource (provider->id, 0);
+}
+
+void
+RRProviderSetCapabilities(RRProviderPtr provider, uint32_t capabilities)
+{
+    provider->capabilities = capabilities;
+}
+
+static int
+RRProviderDestroyResource (pointer value, XID pid)
+{
+    RRProviderPtr provider = (RRProviderPtr)value;
+    ScreenPtr pScreen = provider->pScreen;
+
+    if (pScreen)
+    {
+        rrScrPriv(pScreen);
+
+        pScrPriv->provider = NULL;
+    }
+    free(provider);
+    return 1;
+}
+
+Bool
+RRProviderInit(void)
+{
+    RRProviderType = CreateNewResourceType(RRProviderDestroyResource, "Provider");
+    if (!RRProviderType)
+        return FALSE;
+
+    return TRUE;
+}
+
+extern _X_EXPORT Bool
+RRProviderLookup(XID id, RRProviderPtr *provider_p)
+{
+    int rc = dixLookupResourceByType((void **)provider_p, id,
+                                   RRProviderType, NullClient, DixReadAccess);
+    if (rc == Success)
+        return TRUE;
+    return FALSE;
+}
diff --git a/randr/rrproviderproperty.c b/randr/rrproviderproperty.c
new file mode 100644
index 0000000..5e04fab
--- /dev/null
+++ b/randr/rrproviderproperty.c
@@ -0,0 +1,716 @@
+/*
+ * Copyright © 2006 Keith Packard
+ *
+ * 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.
+ */
+
+#include "randrstr.h"
+#include "propertyst.h"
+#include "swaprep.h"
+
+static int
+DeliverPropertyEvent(WindowPtr pWin, void *value)
+{
+    xRRProviderPropertyNotifyEvent *event = value;
+    RREventPtr *pHead, pRREvent;
+
+    dixLookupResourceByType((pointer *) &pHead, pWin->drawable.id,
+                            RREventType, serverClient, DixReadAccess);
+    if (!pHead)
+        return WT_WALKCHILDREN;
+
+    for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
+        if (!(pRREvent->mask & RRProviderPropertyNotifyMask))
+            continue;
+
+        event->window = pRREvent->window->drawable.id;
+        WriteEventsToClient(pRREvent->client, 1, (xEvent *) event);
+    }
+
+    return WT_WALKCHILDREN;
+}
+
+static void
+RRDeliverPropertyEvent(ScreenPtr pScreen, xEvent *event)
+{
+    if (!(dispatchException & (DE_RESET | DE_TERMINATE)))
+        WalkTree(pScreen, DeliverPropertyEvent, event);
+}
+
+static void
+RRDestroyProviderProperty(RRPropertyPtr prop)
+{
+    free(prop->valid_values);
+    free(prop->current.data);
+    free(prop->pending.data);
+    free(prop);
+}
+
+static void
+RRDeleteProperty(RRProviderRec * provider, RRPropertyRec * prop)
+{
+    xRRProviderPropertyNotifyEvent event;
+
+    event.type = RREventBase + RRNotify;
+    event.subCode = RRNotify_ProviderProperty;
+    event.provider = provider->id;
+    event.state = PropertyDelete;
+    event.atom = prop->propertyName;
+    event.timestamp = currentTime.milliseconds;
+
+    RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event);
+
+    RRDestroyProviderProperty(prop);
+}
+
+void
+RRDeleteAllProviderProperties(RRProviderPtr provider)
+{
+    RRPropertyPtr prop, next;
+
+    for (prop = provider->properties; prop; prop = next) {
+        next = prop->next;
+        RRDeleteProperty(provider, prop);
+    }
+}
+
+static void
+RRInitProviderPropertyValue(RRPropertyValuePtr property_value)
+{
+    property_value->type = None;
+    property_value->format = 0;
+    property_value->size = 0;
+    property_value->data = NULL;
+}
+
+static RRPropertyPtr
+RRCreateProviderProperty(Atom property)
+{
+    RRPropertyPtr prop;
+
+    prop = (RRPropertyPtr) malloc(sizeof(RRPropertyRec));
+    if (!prop)
+        return NULL;
+    prop->next = NULL;
+    prop->propertyName = property;
+    prop->is_pending = FALSE;
+    prop->range = FALSE;
+    prop->immutable = FALSE;
+    prop->num_valid = 0;
+    prop->valid_values = NULL;
+    RRInitProviderPropertyValue(&prop->current);
+    RRInitProviderPropertyValue(&prop->pending);
+    return prop;
+}
+
+void
+RRDeleteProviderProperty(RRProviderPtr provider, Atom property)
+{
+    RRPropertyRec *prop, **prev;
+
+    for (prev = &provider->properties; (prop = *prev); prev = &(prop->next))
+        if (prop->propertyName == property) {
+            *prev = prop->next;
+            RRDeleteProperty(provider, prop);
+            return;
+        }
+}
+
+int
+RRChangeProviderProperty(RRProviderPtr provider, Atom property, Atom type,
+                       int format, int mode, unsigned long len,
+                       pointer value, Bool sendevent, Bool pending)
+{
+    RRPropertyPtr prop;
+    xRRProviderPropertyNotifyEvent event;
+    rrScrPrivPtr pScrPriv = rrGetScrPriv(provider->pScreen);
+    int size_in_bytes;
+    int total_size;
+    unsigned long total_len;
+    RRPropertyValuePtr prop_value;
+    RRPropertyValueRec new_value;
+    Bool add = FALSE;
+
+    size_in_bytes = format >> 3;
+
+    /* first see if property already exists */
+    prop = RRQueryProviderProperty(provider, property);
+    if (!prop) {                /* just add to list */
+        prop = RRCreateProviderProperty(property);
+        if (!prop)
+            return BadAlloc;
+        add = TRUE;
+        mode = PropModeReplace;
+    }
+    if (pending && prop->is_pending)
+        prop_value = &prop->pending;
+    else
+        prop_value = &prop->current;
+
+    /* To append or prepend to a property the request format and type
+       must match those of the already defined property.  The
+       existing format and type are irrelevant when using the mode
+       "PropModeReplace" since they will be written over. */
+
+    if ((format != prop_value->format) && (mode != PropModeReplace))
+        return BadMatch;
+    if ((prop_value->type != type) && (mode != PropModeReplace))
+        return BadMatch;
+    new_value = *prop_value;
+    if (mode == PropModeReplace)
+        total_len = len;
+    else
+        total_len = prop_value->size + len;
+
+    if (mode == PropModeReplace || len > 0) {
+        pointer new_data = NULL, old_data = NULL;
+
+        total_size = total_len * size_in_bytes;
+        new_value.data = (pointer) malloc(total_size);
+        if (!new_value.data && total_size) {
+            if (add)
+                RRDestroyProviderProperty(prop);
+            return BadAlloc;
+        }
+        new_value.size = len;
+        new_value.type = type;
+        new_value.format = format;
+
+        switch (mode) {
+        case PropModeReplace:
+            new_data = new_value.data;
+            old_data = NULL;
+            break;
+        case PropModeAppend:
+            new_data = (pointer) (((char *) new_value.data) +
+                                  (prop_value->size * size_in_bytes));
+            old_data = new_value.data;
+            break;
+        case PropModePrepend:
+            new_data = new_value.data;
+            old_data = (pointer) (((char *) new_value.data) +
+                                  (prop_value->size * size_in_bytes));
+            break;
+        }
+        if (new_data)
+            memcpy((char *) new_data, (char *) value, len * size_in_bytes);
+        if (old_data)
+            memcpy((char *) old_data, (char *) prop_value->data,
+                   prop_value->size * size_in_bytes);
+
+        if (pending && pScrPriv->rrProviderSetProperty &&
+            !pScrPriv->rrProviderSetProperty(provider->pScreen, provider,
+                                           prop->propertyName, &new_value)) {
+            free(new_value.data);
+            return BadValue;
+        }
+        free(prop_value->data);
+        *prop_value = new_value;
+    }
+
+    else if (len == 0) {
+        /* do nothing */
+    }
+
+    if (add) {
+        prop->next = provider->properties;
+        provider->properties = prop;
+    }
+
+    if (pending && prop->is_pending)
+        provider->pendingProperties = TRUE;
+
+    if (sendevent) {
+        event.type = RREventBase + RRNotify;
+        event.subCode = RRNotify_ProviderProperty;
+        event.provider = provider->id;
+        event.state = PropertyNewValue;
+        event.atom = prop->propertyName;
+        event.timestamp = currentTime.milliseconds;
+        RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event);
+    }
+    return Success;
+}
+
+Bool
+RRPostProviderPendingProperties(RRProviderPtr provider)
+{
+    RRPropertyValuePtr pending_value;
+    RRPropertyValuePtr current_value;
+    RRPropertyPtr property;
+    Bool ret = TRUE;
+
+    if (!provider->pendingProperties)
+        return TRUE;
+
+    provider->pendingProperties = FALSE;
+    for (property = provider->properties; property; property = property->next) {
+        /* Skip non-pending properties */
+        if (!property->is_pending)
+            continue;
+
+        pending_value = &property->pending;
+        current_value = &property->current;
+
+        /*
+         * If the pending and current values are equal, don't mark it
+         * as changed (which would deliver an event)
+         */
+        if (pending_value->type == current_value->type &&
+            pending_value->format == current_value->format &&
+            pending_value->size == current_value->size &&
+            !memcmp(pending_value->data, current_value->data,
+                    pending_value->size * (pending_value->format / 8)))
+            continue;
+
+        if (RRChangeProviderProperty(provider, property->propertyName,
+                                   pending_value->type, pending_value->format,
+                                   PropModeReplace, pending_value->size,
+                                   pending_value->data, TRUE, FALSE) != Success)
+            ret = FALSE;
+    }
+    return ret;
+}
+
+RRPropertyPtr
+RRQueryProviderProperty(RRProviderPtr provider, Atom property)
+{
+    RRPropertyPtr prop;
+
+    for (prop = provider->properties; prop; prop = prop->next)
+        if (prop->propertyName == property)
+            return prop;
+    return NULL;
+}
+
+RRPropertyValuePtr
+RRGetProviderProperty(RRProviderPtr provider, Atom property, Bool pending)
+{
+    RRPropertyPtr prop = RRQueryProviderProperty(provider, property);
+    rrScrPrivPtr pScrPriv = rrGetScrPriv(provider->pScreen);
+
+    if (!prop)
+        return NULL;
+    if (pending && prop->is_pending)
+        return &prop->pending;
+    else {
+#if RANDR_13_INTERFACE
+        /* If we can, try to update the property value first */
+        if (pScrPriv->rrProviderGetProperty)
+            pScrPriv->rrProviderGetProperty(provider->pScreen, provider,
+                                          prop->propertyName);
+#endif
+        return &prop->current;
+    }
+}
+
+int
+RRConfigureProviderProperty(RRProviderPtr provider, Atom property,
+                          Bool pending, Bool range, Bool immutable,
+                          int num_values, INT32 *values)
+{
+    RRPropertyPtr prop = RRQueryProviderProperty(provider, property);
+    Bool add = FALSE;
+    INT32 *new_values;
+
+    if (!prop) {
+        prop = RRCreateProviderProperty(property);
+        if (!prop)
+            return BadAlloc;
+        add = TRUE;
+    }
+    else if (prop->immutable && !immutable)
+        return BadAccess;
+
+    /*
+     * ranges must have even number of values
+     */
+    if (range && (num_values & 1))
+        return BadMatch;
+
+    new_values = malloc(num_values * sizeof(INT32));
+    if (!new_values && num_values)
+        return BadAlloc;
+    if (num_values)
+        memcpy(new_values, values, num_values * sizeof(INT32));
+
+    /*
+     * Property moving from pending to non-pending
+     * loses any pending values
+     */
+    if (prop->is_pending && !pending) {
+        free(prop->pending.data);
+        RRInitProviderPropertyValue(&prop->pending);
+    }
+
+    prop->is_pending = pending;
+    prop->range = range;
+    prop->immutable = immutable;
+    prop->num_valid = num_values;
+    free(prop->valid_values);
+    prop->valid_values = new_values;
+
+    if (add) {
+        prop->next = provider->properties;
+        provider->properties = prop;
+    }
+
+    return Success;
+}
+
+int
+ProcRRListProviderProperties(ClientPtr client)
+{
+    REQUEST(xRRListProviderPropertiesReq);
+    Atom *pAtoms = NULL, *temppAtoms;
+    xRRListProviderPropertiesReply rep;
+    int numProps = 0;
+    RRProviderPtr provider;
+    RRPropertyPtr prop;
+
+    REQUEST_SIZE_MATCH(xRRListProviderPropertiesReq);
+
+    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
+
+    for (prop = provider->properties; prop; prop = prop->next)
+        numProps++;
+    if (numProps)
+        if (!(pAtoms = (Atom *) malloc(numProps * sizeof(Atom))))
+            return BadAlloc;
+
+    rep.type = X_Reply;
+    rep.length = bytes_to_int32(numProps * sizeof(Atom));
+    rep.sequenceNumber = client->sequence;
+    rep.nAtoms = numProps;
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swaps(&rep.nAtoms);
+    }
+    temppAtoms = pAtoms;
+    for (prop = provider->properties; prop; prop = prop->next)
+        *temppAtoms++ = prop->propertyName;
+
+    WriteToClient(client, sizeof(xRRListProviderPropertiesReply), (char *) &rep);
+    if (numProps) {
+        client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+        WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
+        free(pAtoms);
+    }
+    return Success;
+}
+
+int
+ProcRRQueryProviderProperty(ClientPtr client)
+{
+    REQUEST(xRRQueryProviderPropertyReq);
+    xRRQueryProviderPropertyReply rep;
+    RRProviderPtr provider;
+    RRPropertyPtr prop;
+    char *extra = NULL;
+
+    REQUEST_SIZE_MATCH(xRRQueryProviderPropertyReq);
+
+    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
+
+    prop = RRQueryProviderProperty(provider, stuff->property);
+    if (!prop)
+        return BadName;
+
+    if (prop->num_valid) {
+        extra = malloc(prop->num_valid * sizeof(INT32));
+        if (!extra)
+            return BadAlloc;
+    }
+    rep.type = X_Reply;
+    rep.length = prop->num_valid;
+    rep.sequenceNumber = client->sequence;
+    rep.pending = prop->is_pending;
+    rep.range = prop->range;
+    rep.immutable = prop->immutable;
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+    }
+    WriteToClient(client, sizeof(xRRQueryProviderPropertyReply), (char *) &rep);
+    if (prop->num_valid) {
+        memcpy(extra, prop->valid_values, prop->num_valid * sizeof(INT32));
+        client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
+        WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32),
+                                 extra);
+        free(extra);
+    }
+    return Success;
+}
+
+int
+ProcRRConfigureProviderProperty(ClientPtr client)
+{
+    REQUEST(xRRConfigureProviderPropertyReq);
+    RRProviderPtr provider;
+    int num_valid;
+
+    REQUEST_AT_LEAST_SIZE(xRRConfigureProviderPropertyReq);
+
+    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
+
+    num_valid =
+        stuff->length - bytes_to_int32(sizeof(xRRConfigureProviderPropertyReq));
+    return RRConfigureProviderProperty(provider, stuff->property, stuff->pending,
+                                     stuff->range, FALSE, num_valid,
+                                     (INT32 *) (stuff + 1));
+}
+
+int
+ProcRRChangeProviderProperty(ClientPtr client)
+{
+    REQUEST(xRRChangeProviderPropertyReq);
+    RRProviderPtr provider;
+    char format, mode;
+    unsigned long len;
+    int sizeInBytes;
+    int totalSize;
+    int err;
+
+    REQUEST_AT_LEAST_SIZE(xRRChangeProviderPropertyReq);
+    UpdateCurrentTime();
+    format = stuff->format;
+    mode = stuff->mode;
+    if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
+        (mode != PropModePrepend)) {
+        client->errorValue = mode;
+        return BadValue;
+    }
+    if ((format != 8) && (format != 16) && (format != 32)) {
+        client->errorValue = format;
+        return BadValue;
+    }
+    len = stuff->nUnits;
+    if (len > bytes_to_int32((0xffffffff - sizeof(xChangePropertyReq))))
+        return BadLength;
+    sizeInBytes = format >> 3;
+    totalSize = len * sizeInBytes;
+    REQUEST_FIXED_SIZE(xRRChangeProviderPropertyReq, totalSize);
+
+    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
+
+    if (!ValidAtom(stuff->property)) {
+        client->errorValue = stuff->property;
+        return BadAtom;
+    }
+    if (!ValidAtom(stuff->type)) {
+        client->errorValue = stuff->type;
+        return BadAtom;
+    }
+
+    err = RRChangeProviderProperty(provider, stuff->property,
+                                 stuff->type, (int) format,
+                                 (int) mode, len, (pointer) &stuff[1], TRUE,
+                                 TRUE);
+    if (err != Success)
+        return err;
+    else
+        return Success;
+}
+
+int
+ProcRRDeleteProviderProperty(ClientPtr client)
+{
+    REQUEST(xRRDeleteProviderPropertyReq);
+    RRProviderPtr provider;
+    RRPropertyPtr prop;
+
+    REQUEST_SIZE_MATCH(xRRDeleteProviderPropertyReq);
+    UpdateCurrentTime();
+    VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
+
+    if (!ValidAtom(stuff->property)) {
+        client->errorValue = stuff->property;
+        return BadAtom;
+    }
+
+    prop = RRQueryProviderProperty(provider, stuff->property);
+    if (!prop) {
+        client->errorValue = stuff->property;
+        return BadName;
+    }
+
+    if (prop->immutable) {
+        client->errorValue = stuff->property;
+        return BadAccess;
+    }
+
+    RRDeleteProviderProperty(provider, stuff->property);
+    return Success;
+}
+
+int
+ProcRRGetProviderProperty(ClientPtr client)
+{
+    REQUEST(xRRGetProviderPropertyReq);
+    RRPropertyPtr prop, *prev;
+    RRPropertyValuePtr prop_value;
+    unsigned long n, len, ind;
+    RRProviderPtr provider;
+    xRRGetProviderPropertyReply reply;
+    char *extra = NULL;
+
+    REQUEST_SIZE_MATCH(xRRGetProviderPropertyReq);
+    if (stuff->delete)
+        UpdateCurrentTime();
+    VERIFY_RR_PROVIDER(stuff->provider, provider,
+                     stuff->delete ? DixWriteAccess : DixReadAccess);
+
+    if (!ValidAtom(stuff->property)) {
+        client->errorValue = stuff->property;
+        return BadAtom;
+    }
+    if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) {
+        client->errorValue = stuff->delete;
+        return BadValue;
+    }
+    if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) {
+        client->errorValue = stuff->type;
+        return BadAtom;
+    }
+
+    for (prev = &provider->properties; (prop = *prev); prev = &prop->next)
+        if (prop->propertyName == stuff->property)
+            break;
+
+    reply.type = X_Reply;
+    reply.sequenceNumber = client->sequence;
+    if (!prop) {
+        reply.nItems = 0;
+        reply.length = 0;
+        reply.bytesAfter = 0;
+        reply.propertyType = None;
+        reply.format = 0;
+        if (client->swapped) {
+            swaps(&reply.sequenceNumber);
+            swapl(&reply.length);
+            swapl(&reply.propertyType);
+            swapl(&reply.bytesAfter);
+            swapl(&reply.nItems);
+        }
+        WriteToClient(client, sizeof(xRRGetProviderPropertyReply), &reply);
+        return Success;
+    }
+
+    if (prop->immutable && stuff->delete)
+        return BadAccess;
+
+    prop_value = RRGetProviderProperty(provider, stuff->property, stuff->pending);
+    if (!prop_value)
+        return BadAtom;
+
+    /* If the request type and actual type don't match. Return the
+       property information, but not the data. */
+
+    if (((stuff->type != prop_value->type) && (stuff->type != AnyPropertyType))
+        ) {
+        reply.bytesAfter = prop_value->size;
+        reply.format = prop_value->format;
+        reply.length = 0;
+        reply.nItems = 0;
+        reply.propertyType = prop_value->type;
+        if (client->swapped) {
+            swaps(&reply.sequenceNumber);
+            swapl(&reply.length);
+            swapl(&reply.propertyType);
+            swapl(&reply.bytesAfter);
+            swapl(&reply.nItems);
+        }
+        WriteToClient(client, sizeof(xRRGetProviderPropertyReply), &reply);
+        return Success;
+    }
+
+/*
+ *  Return type, format, value to client
+ */
+    n = (prop_value->format / 8) * prop_value->size;    /* size (bytes) of prop */
+    ind = stuff->longOffset << 2;
+
+    /* If longOffset is invalid such that it causes "len" to
+       be negative, it's a value error. */
+
+    if (n < ind) {
+        client->errorValue = stuff->longOffset;
+        return BadValue;
+    }
+
+    len = min(n - ind, 4 * stuff->longLength);
+
+    if (len) {
+        extra = malloc(len);
+        if (!extra)
+            return BadAlloc;
+    }
+    reply.bytesAfter = n - (ind + len);
+    reply.format = prop_value->format;
+    reply.length = bytes_to_int32(len);
+    if (prop_value->format)
+        reply.nItems = len / (prop_value->format / 8);
+    else
+        reply.nItems = 0;
+    reply.propertyType = prop_value->type;
+
+    if (stuff->delete && (reply.bytesAfter == 0)) {
+        xRRProviderPropertyNotifyEvent event;
+
+        event.type = RREventBase + RRNotify;
+        event.subCode = RRNotify_ProviderProperty;
+        event.provider = provider->id;
+        event.state = PropertyDelete;
+        event.atom = prop->propertyName;
+        event.timestamp = currentTime.milliseconds;
+        RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event);
+    }
+
+    if (client->swapped) {
+        swaps(&reply.sequenceNumber);
+        swapl(&reply.length);
+        swapl(&reply.propertyType);
+        swapl(&reply.bytesAfter);
+        swapl(&reply.nItems);
+    }
+    WriteToClient(client, sizeof(xGenericReply), &reply);
+    if (len) {
+        memcpy(extra, (char *) prop_value->data + ind, len);
+        switch (reply.format) {
+        case 32:
+            client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
+            break;
+        case 16:
+            client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
+            break;
+        default:
+            client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient;
+            break;
+        }
+        WriteSwappedDataToClient(client, len, extra);
+        free(extra);
+    }
+
+    if (stuff->delete && (reply.bytesAfter == 0)) {     /* delete the Property */
+        *prev = prop->next;
+        RRDestroyProviderProperty(prop);
+    }
+    return Success;
+}
commit 44eae69f1df2d00e0c9f1ea8d3c4fae06bcacfbc
Author: Dave Airlie <airlied at redhat.com>
Date:   Thu Jul 5 21:11:16 2012 +0100

    configure: bump randrproto min requirements to 1.4.0
    
    Needed to build latest randr stuff.
    
    Reviewed-by: Adam Jackson <ajax at redhat.com>
    Signed-off-by: Dave Airlie <airlied at redhat.com>

diff --git a/configure.ac b/configure.ac
index d1358a2..2442bac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -787,7 +787,7 @@ APPLEWMPROTO="applewmproto >= 1.4"
 
 dnl Required modules
 XPROTO="xproto >= 7.0.22"
-RANDRPROTO="randrproto >= 1.2.99.3"
+RANDRPROTO="randrproto >= 1.4.0"
 RENDERPROTO="renderproto >= 0.11"
 XEXTPROTO="xextproto >= 7.1.99"
 INPUTPROTO="inputproto >= 2.1.99.6"


More information about the xorg-commit mailing list