xserver: Branch 'master' - 4 commits

Keith Packard keithp at kemper.freedesktop.org
Tue Mar 31 09:13:04 PDT 2015


 hw/xfree86/modes/xf86Crtc.c |   53 +++
 hw/xfree86/modes/xf86Crtc.h |   26 +
 include/protocol-versions.h |    2 
 randr/Makefile.am           |    1 
 randr/randr.c               |    4 
 randr/randrstr.h            |   44 ++
 randr/rrdispatch.c          |    3 
 randr/rrmonitor.c           |  748 ++++++++++++++++++++++++++++++++++++++++++++
 randr/rrsdispatch.c         |   38 ++
 randr/rrxinerama.c          |  118 +-----
 10 files changed, 936 insertions(+), 101 deletions(-)

New commits:
commit e608f3521eaaab972a3eea62aa04a65958351c1c
Merge: d3b9c47 5de1383
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Mar 31 09:06:08 2015 -0700

    Merge remote-tracking branch 'airlied/for-keithp'

commit 5de13830709a7f2d4d112d71e062f710ef466ab6
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Dec 16 09:56:50 2014 -0800

    randr: Use Monitor list for Xinerama
    
    This replaces the CRTC-based Xinerama implementation with one which
    uses Monitors instead, allowing clients to manipulate the Xinerama
    configuration through the RandR Monitor list.
    
    Reviewed-by: Dave Airlie <airlied at redhat.com>
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/randr/rrxinerama.c b/randr/rrxinerama.c
index 36632c7..b6e9586 100644
--- a/randr/rrxinerama.c
+++ b/randr/rrxinerama.c
@@ -149,35 +149,10 @@ ProcRRXineramaGetState(ClientPtr client)
     return Success;
 }
 
-static Bool
-RRXineramaCrtcActive(RRCrtcPtr crtc)
-{
-    return crtc->mode != NULL && crtc->numOutputs > 0;
-}
-
 static int
 RRXineramaScreenCount(ScreenPtr pScreen)
 {
-    int i, n;
-    ScreenPtr slave;
-
-    n = 0;
-    if (rrGetScrPriv(pScreen)) {
-        rrScrPriv(pScreen);
-        for (i = 0; i < pScrPriv->numCrtcs; i++)
-            if (RRXineramaCrtcActive(pScrPriv->crtcs[i]))
-                n++;
-    }
-
-    xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
-        rrScrPrivPtr pSlavePriv;
-        pSlavePriv = rrGetScrPriv(slave);
-        for (i = 0; i < pSlavePriv->numCrtcs; i++)
-            if (RRXineramaCrtcActive(pSlavePriv->crtcs[i]))
-                n++;
-    }
-
-    return n;
+    return RRMonitorCountList(pScreen);
 }
 
 static Bool
@@ -276,42 +251,16 @@ ProcRRXineramaIsActive(ClientPtr client)
 }
 
 static void
-RRXineramaWriteCrtc(ClientPtr client, RRCrtcPtr crtc)
+RRXineramaWriteMonitor(ClientPtr client, RRMonitorPtr monitor)
 {
     xXineramaScreenInfo scratch;
 
-    if (RRXineramaCrtcActive(crtc)) {
-        ScreenPtr pScreen = crtc->pScreen;
-        rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen);
-        BoxRec panned_area;
-
-        /* Check to see if crtc is panned and return the full area when applicable. */
-        if (pScrPriv && pScrPriv->rrGetPanning &&
-            pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
-            (panned_area.x2 > panned_area.x1) &&
-            (panned_area.y2 > panned_area.y1)) {
-            scratch.x_org = panned_area.x1;
-            scratch.y_org = panned_area.y1;
-            scratch.width = panned_area.x2 - panned_area.x1;
-            scratch.height = panned_area.y2 - panned_area.y1;
-        }
-        else {
-            int width, height;
-
-            RRCrtcGetScanoutSize(crtc, &width, &height);
-            scratch.x_org = crtc->x;
-            scratch.y_org = crtc->y;
-            scratch.width = width;
-            scratch.height = height;
-        }
-        if (client->swapped) {
-            swaps(&scratch.x_org);
-            swaps(&scratch.y_org);
-            swaps(&scratch.width);
-            swaps(&scratch.height);
-        }
-        WriteToClient(client, sz_XineramaScreenInfo, &scratch);
-    }
+    scratch.x_org = monitor->geometry.box.x1;
+    scratch.y_org = monitor->geometry.box.y1;
+    scratch.width = monitor->geometry.box.x2 - monitor->geometry.box.x1;
+    scratch.height = monitor->geometry.box.y2 - monitor->geometry.box.y1;
+
+    WriteToClient(client, sz_XineramaScreenInfo, &scratch);
 }
 
 int
@@ -319,21 +268,23 @@ ProcRRXineramaQueryScreens(ClientPtr client)
 {
     xXineramaQueryScreensReply rep;
     ScreenPtr pScreen = screenInfo.screens[RR_XINERAMA_SCREEN];
-    int n = 0;
-    int i;
+    int m;
+    RRMonitorPtr monitors = NULL;
+    int nmonitors = 0;
 
     REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
 
     if (RRXineramaScreenActive(pScreen)) {
         RRGetInfo(pScreen, FALSE);
-        n = RRXineramaScreenCount(pScreen);
+        if (!RRMonitorMakeList(pScreen, TRUE, &monitors, &nmonitors))
+            return BadAlloc;
     }
 
     rep = (xXineramaQueryScreensReply) {
         .type = X_Reply,
         .sequenceNumber = client->sequence,
-        .length = bytes_to_int32(n * sz_XineramaScreenInfo),
-        .number = n
+        .length = bytes_to_int32(nmonitors * sz_XineramaScreenInfo),
+        .number = nmonitors
     };
     if (client->swapped) {
         swaps(&rep.sequenceNumber);
@@ -342,40 +293,11 @@ ProcRRXineramaQueryScreens(ClientPtr client)
     }
     WriteToClient(client, sizeof(xXineramaQueryScreensReply), &rep);
 
-    if (n) {
-        ScreenPtr slave;
-        rrScrPriv(pScreen);
-        int has_primary = 0;
-        RRCrtcPtr primary_crtc = NULL;
-
-        if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
-            has_primary = 1;
-            primary_crtc = pScrPriv->primaryOutput->crtc;
-            RRXineramaWriteCrtc(client, pScrPriv->primaryOutput->crtc);
-        }
-
-        for (i = 0; i < pScrPriv->numCrtcs; i++) {
-            if (has_primary &&
-                primary_crtc == pScrPriv->crtcs[i]) {
-                has_primary = 0;
-                continue;
-            }
-            RRXineramaWriteCrtc(client, pScrPriv->crtcs[i]);
-        }
-
-        xorg_list_for_each_entry(slave, &pScreen->output_slave_list, output_head) {
-            rrScrPrivPtr pSlavePriv;
-            pSlavePriv = rrGetScrPriv(slave);
-            for (i = 0; i < pSlavePriv->numCrtcs; i++) {
-                if (has_primary &&
-                    primary_crtc == pSlavePriv->crtcs[i]) {
-                    has_primary = 0;
-                    continue;
-                }
-                RRXineramaWriteCrtc(client, pSlavePriv->crtcs[i]);
-            }
-        }
-    }
+    for (m = 0; m < nmonitors; m++)
+        RRXineramaWriteMonitor(client, &monitors[m]);
+
+    if (monitors)
+        RRMonitorFreeList(monitors, nmonitors);
 
     return Success;
 }
commit 7e1f86d42b54fb7f6492875e47a718eaeca3069b
Author: Keith Packard <keithp at keithp.com>
Date:   Tue Dec 16 01:59:03 2014 -0800

    randr: Add Monitor support (v1.1)
    
    Store the user-defined monitors in the RandR screen private.
    
    Generate a list of monitors from both the user-defined ones and from
    any outputs not mentioned in one of the user-defined monitors. This list
    covers both the outputs in the main screen as well as any slaves.
    
    v1.1: airlied: fix up primary skipping bug,
    fix wrong height initialiser
    add get_active flag from updated protocol.
    
    Reviewed-by: Dave Airlie <airlied at redhat.com>
    Signed-off-by: Keith Packard <keithp at keithp.com>

diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index fc428c8..be532ff 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -73,7 +73,7 @@
 
 /* RandR */
 #define SERVER_RANDR_MAJOR_VERSION		1
-#define SERVER_RANDR_MINOR_VERSION		4
+#define SERVER_RANDR_MINOR_VERSION		5
 
 /* Record */
 #define SERVER_RECORD_MAJOR_VERSION		1
diff --git a/randr/Makefile.am b/randr/Makefile.am
index ccaff3f..90dc9ec 100644
--- a/randr/Makefile.am
+++ b/randr/Makefile.am
@@ -15,6 +15,7 @@ librandr_la_SOURCES =	\
 	rrdispatch.c	\
 	rrinfo.c	\
 	rrmode.c	\
+	rrmonitor.c	\
 	rroutput.c	\
 	rrpointer.c	\
 	rrproperty.c	\
diff --git a/randr/randr.c b/randr/randr.c
index 6e3f14b..ad1dda2 100644
--- a/randr/randr.c
+++ b/randr/randr.c
@@ -98,6 +98,8 @@ RRCloseScreen(ScreenPtr pScreen)
     if (pScrPriv->provider)
         RRProviderDestroy(pScrPriv->provider);
 
+    RRMonitorClose(pScreen);
+
     free(pScrPriv->crtcs);
     free(pScrPriv->outputs);
     free(pScrPriv);
@@ -333,6 +335,8 @@ RRScreenInit(ScreenPtr pScreen)
     pScrPriv->numCrtcs = 0;
     pScrPriv->crtcs = NULL;
 
+    RRMonitorInit(pScreen);
+
     RRNScreens += 1;            /* keep count of screens that implement randr */
     return TRUE;
 }
diff --git a/randr/randrstr.h b/randr/randrstr.h
index 13e6a85..438a52a 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -80,6 +80,7 @@ typedef struct _rrProperty RRPropertyRec, *RRPropertyPtr;
 typedef struct _rrCrtc RRCrtcRec, *RRCrtcPtr;
 typedef struct _rrOutput RROutputRec, *RROutputPtr;
 typedef struct _rrProvider RRProviderRec, *RRProviderPtr;
+typedef struct _rrMonitor RRMonitorRec, *RRMonitorPtr;
 
 struct _rrMode {
     int refcnt;
@@ -169,6 +170,22 @@ struct _rrProvider {
     struct _rrProvider *output_source;
 };
 
+typedef struct _rrMonitorGeometry {
+    BoxRec box;
+    CARD32 mmWidth;
+    CARD32 mmHeight;
+} RRMonitorGeometryRec, *RRMonitorGeometryPtr;
+
+struct _rrMonitor {
+    Atom name;
+    ScreenPtr pScreen;
+    int numOutputs;
+    RROutput *outputs;
+    Bool primary;
+    Bool automatic;
+    RRMonitorGeometryRec geometry;
+};
+
 #if RANDR_12_INTERFACE
 typedef Bool (*RRScreenSetSizeProcPtr) (ScreenPtr pScreen,
                                         CARD16 width,
@@ -338,6 +355,9 @@ typedef struct _rrScrPriv {
 
     RRProviderDestroyProcPtr rrProviderDestroy;
 
+    int numMonitors;
+    RRMonitorPtr *monitors;
+
 } rrScrPrivRec, *rrScrPrivPtr;
 
 extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec;
@@ -981,6 +1001,30 @@ extern _X_EXPORT void
  RRXineramaExtensionInit(void);
 #endif
 
+void
+RRMonitorInit(ScreenPtr screen);
+
+Bool
+RRMonitorMakeList(ScreenPtr screen, Bool get_active, RRMonitorPtr *monitors_ret, int *nmon_ret);
+
+int
+RRMonitorCountList(ScreenPtr screen);
+
+void
+RRMonitorFreeList(RRMonitorPtr monitors, int nmon);
+
+void
+RRMonitorClose(ScreenPtr screen);
+
+int
+ProcRRGetMonitors(ClientPtr client);
+
+int
+ProcRRSetMonitor(ClientPtr client);
+
+int
+ProcRRDeleteMonitor(ClientPtr client);
+
 #endif                          /* _RANDRSTR_H_ */
 
 /*
diff --git a/randr/rrdispatch.c b/randr/rrdispatch.c
index b9346d3..13ac6b1 100644
--- a/randr/rrdispatch.c
+++ b/randr/rrdispatch.c
@@ -254,4 +254,7 @@ int (*ProcRandrVector[RRNumberRequests]) (ClientPtr) = {
         ProcRRChangeProviderProperty, /* 39 */
         ProcRRDeleteProviderProperty, /* 40 */
         ProcRRGetProviderProperty,    /* 41 */
+        ProcRRGetMonitors,            /* 42 */
+        ProcRRSetMonitor,             /* 43 */
+        ProcRRDeleteMonitor,          /* 44 */
 };
diff --git a/randr/rrmonitor.c b/randr/rrmonitor.c
new file mode 100644
index 0000000..fbdd352
--- /dev/null
+++ b/randr/rrmonitor.c
@@ -0,0 +1,748 @@
+/*
+ * Copyright © 2014 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 "swaprep.h"
+
+static Atom
+RRMonitorCrtcName(RRCrtcPtr crtc)
+{
+    char        name[20];
+
+    if (crtc->numOutputs) {
+        RROutputPtr     output = crtc->outputs[0];
+        return MakeAtom(output->name, output->nameLength, TRUE);
+    }
+    sprintf(name, "Monitor-%08x", crtc->id);
+    return MakeAtom(name, strlen(name), TRUE);
+}
+
+static Bool
+RRMonitorCrtcPrimary(RRCrtcPtr crtc)
+{
+    ScreenPtr screen = crtc->pScreen;
+    rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+    int o;
+
+    for (o = 0; o < crtc->numOutputs; o++)
+        if (crtc->outputs[o] == pScrPriv->primaryOutput)
+            return TRUE;
+    return FALSE;
+}
+
+#define DEFAULT_PIXELS_PER_MM   (96.0 / 25.4)
+
+static void
+RRMonitorGetCrtcGeometry(RRCrtcPtr crtc, RRMonitorGeometryPtr geometry)
+{
+    ScreenPtr screen = crtc->pScreen;
+    rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+    BoxRec      panned_area;
+
+    /* Check to see if crtc is panned and return the full area when applicable. */
+    if (pScrPriv && pScrPriv->rrGetPanning &&
+        pScrPriv->rrGetPanning(screen, crtc, &panned_area, NULL, NULL) &&
+        (panned_area.x2 > panned_area.x1) &&
+        (panned_area.y2 > panned_area.y1)) {
+        geometry->box = panned_area;
+    }
+    else {
+        int width, height;
+
+        RRCrtcGetScanoutSize(crtc, &width, &height);
+        geometry->box.x1 = crtc->x;
+        geometry->box.y1 = crtc->y;
+        geometry->box.x2 = geometry->box.x1 + width;
+        geometry->box.y2 = geometry->box.y1 + height;
+    }
+    if (crtc->numOutputs && crtc->outputs[0]->mmWidth && crtc->outputs[0]->mmHeight) {
+        RROutputPtr output = crtc->outputs[0];
+        geometry->mmWidth = output->mmWidth;
+        geometry->mmHeight = output->mmHeight;
+    } else {
+        geometry->mmWidth = floor ((geometry->box.x2 - geometry->box.x1) / DEFAULT_PIXELS_PER_MM + 0.5);
+        geometry->mmHeight = floor ((geometry->box.y2 - geometry->box.y1) / DEFAULT_PIXELS_PER_MM + 0.5);
+    }
+}
+
+static Bool
+RRMonitorSetFromServer(RRCrtcPtr crtc, RRMonitorPtr monitor)
+{
+    int o;
+
+    monitor->name = RRMonitorCrtcName(crtc);
+    monitor->pScreen = crtc->pScreen;
+    monitor->numOutputs = crtc->numOutputs;
+    monitor->outputs = calloc(crtc->numOutputs, sizeof(RRCrtc));
+    if (!monitor->outputs)
+        return FALSE;
+    for (o = 0; o < crtc->numOutputs; o++)
+        monitor->outputs[o] = crtc->outputs[o]->id;
+    monitor->primary = RRMonitorCrtcPrimary(crtc);
+    monitor->automatic = TRUE;
+    RRMonitorGetCrtcGeometry(crtc, &monitor->geometry);
+    return TRUE;
+}
+
+static Bool
+RRMonitorAutomaticGeometry(RRMonitorPtr monitor)
+{
+    return (monitor->geometry.box.x1 == 0 &&
+            monitor->geometry.box.y1 == 0 &&
+            monitor->geometry.box.x2 == 0 &&
+            monitor->geometry.box.y2 == 0);
+}
+
+static void
+RRMonitorGetGeometry(RRMonitorPtr monitor, RRMonitorGeometryPtr geometry)
+{
+    if (RRMonitorAutomaticGeometry(monitor) && monitor->numOutputs > 0) {
+        ScreenPtr               screen = monitor->pScreen;
+        rrScrPrivPtr            pScrPriv = rrGetScrPriv(screen);
+        RRMonitorGeometryRec    first = { .box = { 0, 0, 0, 0 }, .mmWidth = 0, .mmHeight = 0 };
+        RRMonitorGeometryRec    this;
+        int                     c, o, co;
+        int                     active_crtcs = 0;
+
+        *geometry = first;
+        for (o = 0; o < monitor->numOutputs; o++) {
+            RRCrtcPtr   crtc = NULL;
+            Bool        in_use = FALSE;
+
+            for (c = 0; !in_use && c < pScrPriv->numCrtcs; c++) {
+                crtc = pScrPriv->crtcs[c];
+                if (!crtc->mode)
+                    continue;
+                for (co = 0; !in_use && co < crtc->numOutputs; co++)
+                    if (monitor->outputs[o] == crtc->outputs[co]->id)
+                        in_use = TRUE;
+            }
+
+            if (!in_use)
+                continue;
+
+            RRMonitorGetCrtcGeometry(crtc, &this);
+
+            if (active_crtcs == 0) {
+                first = this;
+                *geometry = this;
+            } else {
+                geometry->box.x1 = min(this.box.x1, geometry->box.x1);
+                geometry->box.x2 = max(this.box.x2, geometry->box.x2);
+                geometry->box.y1 = min(this.box.y1, geometry->box.y1);
+                geometry->box.y2 = max(this.box.y2, geometry->box.y2);
+            }
+            active_crtcs++;
+        }
+
+        /* Adjust physical sizes to account for total area */
+        if (active_crtcs > 1 && first.box.x2 != first.box.x1 && first.box.y2 != first.box.y1) {
+            geometry->mmWidth = (this.box.x2 - this.box.x1) / (first.box.x2 - first.box.x1) * first.mmWidth;
+            geometry->mmHeight = (this.box.y2 - this.box.y1) / (first.box.y2 - first.box.y1) * first.mmHeight;
+        }
+    } else {
+        *geometry = monitor->geometry;
+    }
+}
+
+static Bool
+RRMonitorSetFromClient(RRMonitorPtr client_monitor, RRMonitorPtr monitor)
+{
+    monitor->name = client_monitor->name;
+    monitor->pScreen = client_monitor->pScreen;
+    monitor->numOutputs = client_monitor->numOutputs;
+    monitor->outputs = calloc(client_monitor->numOutputs, sizeof (RROutput));
+    if (!monitor->outputs && client_monitor->numOutputs)
+        return FALSE;
+    memcpy(monitor->outputs, client_monitor->outputs, client_monitor->numOutputs * sizeof (RROutput));
+    monitor->primary = client_monitor->primary;
+    monitor->automatic = client_monitor->automatic;
+    RRMonitorGetGeometry(client_monitor, &monitor->geometry);
+    return TRUE;
+}
+
+typedef struct _rrMonitorList {
+    int         num_client;
+    int         num_server;
+    RRCrtcPtr   *server_crtc;
+    int         num_crtcs;
+    int         client_primary;
+    int         server_primary;
+} RRMonitorListRec, *RRMonitorListPtr;
+
+static Bool
+RRMonitorInitList(ScreenPtr screen, RRMonitorListPtr mon_list, Bool get_active)
+{
+    rrScrPrivPtr        pScrPriv = rrGetScrPriv(screen);
+    int                 m, o, c, sc;
+    int                 numCrtcs;
+    ScreenPtr           slave;
+
+    if (!RRGetInfo(screen, FALSE))
+        return FALSE;
+
+    /* Count the number of crtcs in this and any slave screens */
+    numCrtcs = pScrPriv->numCrtcs;
+    xorg_list_for_each_entry(slave, &screen->output_slave_list, output_head) {
+        rrScrPrivPtr pSlavePriv;
+        pSlavePriv = rrGetScrPriv(slave);
+        numCrtcs += pSlavePriv->numCrtcs;
+    }
+    mon_list->num_crtcs = numCrtcs;
+
+    mon_list->server_crtc = calloc(numCrtcs * 2, sizeof (RRCrtcPtr));
+    if (!mon_list->server_crtc)
+        return FALSE;
+
+    /* Collect pointers to all of the active crtcs */
+    c = 0;
+    for (sc = 0; sc < pScrPriv->numCrtcs; sc++, c++) {
+        if (pScrPriv->crtcs[sc]->mode != NULL)
+            mon_list->server_crtc[c] = pScrPriv->crtcs[sc];
+    }
+
+    xorg_list_for_each_entry(slave, &screen->output_slave_list, output_head) {
+        rrScrPrivPtr pSlavePriv;
+        pSlavePriv = rrGetScrPriv(slave);
+        for (sc = 0; sc < pSlavePriv->numCrtcs; sc++, c++) {
+            if (pSlavePriv->crtcs[sc]->mode != NULL)
+                mon_list->server_crtc[c] = pSlavePriv->crtcs[sc];
+        }
+    }
+
+    /* Walk the list of client-defined monitors, clearing the covered
+     * CRTCs from the full list and finding whether one of the
+     * monitors is primary
+     */
+    mon_list->num_client = pScrPriv->numMonitors;
+    mon_list->client_primary = -1;
+
+    for (m = 0; m < pScrPriv->numMonitors; m++) {
+        RRMonitorPtr monitor = pScrPriv->monitors[m];
+        if (get_active) {
+            RRMonitorGeometryRec geom;
+
+            RRMonitorGetGeometry(monitor, &geom);
+            if (geom.box.x2 - geom.box.x1 == 0 ||
+                geom.box.y2 - geom.box.y1 == 0) {
+                mon_list->num_client--;
+                continue;
+            }
+        }
+        if (monitor->primary && mon_list->client_primary == -1)
+            mon_list->client_primary = m;
+        for (o = 0; o < monitor->numOutputs; o++) {
+            for (c = 0; c < numCrtcs; c++) {
+                RRCrtcPtr       crtc = mon_list->server_crtc[c];
+                if (crtc) {
+                    int             co;
+                    for (co = 0; co < crtc->numOutputs; co++)
+                        if (crtc->outputs[co]->id == monitor->outputs[o]) {
+                            mon_list->server_crtc[c] = NULL;
+                            break;
+                        }
+                }
+            }
+        }
+    }
+
+    /* Now look at the active CRTCs, and count
+     * those not covered by a client monitor, as well
+     * as finding whether one of them is marked primary
+     */
+    mon_list->num_server = 0;
+    mon_list->server_primary = -1;
+
+    for (c = 0; c < mon_list->num_crtcs; c++) {
+        RRCrtcPtr       crtc = mon_list->server_crtc[c];
+
+        if (!crtc)
+            continue;
+
+        mon_list->num_server++;
+
+        if (RRMonitorCrtcPrimary(crtc) && mon_list->server_primary == -1)
+            mon_list->server_primary = c;
+    }
+    return TRUE;
+}
+
+static void
+RRMonitorFiniList(RRMonitorListPtr list)
+{
+    free(list->server_crtc);
+}
+
+/* Construct a complete list of protocol-visible monitors, including
+ * the manually generated ones as well as those generated
+ * automatically from the remaining CRCTs
+ */
+
+Bool
+RRMonitorMakeList(ScreenPtr screen, Bool get_active, RRMonitorPtr *monitors_ret, int *nmon_ret)
+{
+    rrScrPrivPtr        pScrPriv = rrGetScrPriv(screen);
+    RRMonitorListRec    list;
+    int                 m, c;
+    RRMonitorPtr        mon, monitors;
+    Bool                has_primary = FALSE;
+
+    if (!pScrPriv)
+        return FALSE;
+
+    if (!RRMonitorInitList(screen, &list, get_active))
+        return FALSE;
+
+    monitors = calloc(list.num_client + list.num_server, sizeof (RRMonitorRec));
+    if (!monitors) {
+        RRMonitorFiniList(&list);
+        return FALSE;
+    }
+
+    mon = monitors;
+
+    /* Fill in the primary monitor data first
+     */
+    if (list.client_primary >= 0) {
+        RRMonitorSetFromClient(pScrPriv->monitors[list.client_primary], mon);
+        mon++;
+    } else if (list.server_primary >= 0) {
+        RRMonitorSetFromServer(pScrPriv->crtcs[list.server_primary], mon);
+        mon++;
+    }
+
+    /* Fill in the client-defined monitors next
+     */
+    for (m = 0; m < pScrPriv->numMonitors; m++) {
+        if (m == list.client_primary)
+            continue;
+        if (get_active) {
+            RRMonitorGeometryRec geom;
+
+            RRMonitorGetGeometry(pScrPriv->monitors[m], &geom);
+            if (geom.box.x2 - geom.box.x1 == 0 ||
+                geom.box.y2 - geom.box.y1 == 0) {
+                continue;
+            }
+        }
+        RRMonitorSetFromClient(pScrPriv->monitors[m], mon);
+        if (has_primary)
+            mon->primary = FALSE;
+        else if (mon->primary)
+            has_primary = TRUE;
+        mon++;
+    }
+
+    /* And finish with the list of crtc-inspired monitors
+     */
+    for (c = 0; c < pScrPriv->numCrtcs; c++) {
+        RRCrtcPtr crtc = pScrPriv->crtcs[c];
+        if (c == list.server_primary && list.client_primary < 0)
+            continue;
+
+        if (!list.server_crtc[c])
+            continue;
+
+        RRMonitorSetFromServer(crtc, mon);
+        if (has_primary)
+            mon->primary = FALSE;
+        else if (mon->primary)
+            has_primary = TRUE;
+        mon++;
+    }
+
+    RRMonitorFiniList(&list);
+    *nmon_ret = list.num_client + list.num_server;
+    *monitors_ret = monitors;
+    return TRUE;
+}
+
+int
+RRMonitorCountList(ScreenPtr screen)
+{
+    RRMonitorListRec    list;
+    int                 nmon;
+
+    if (!RRMonitorInitList(screen, &list, FALSE))
+        return -1;
+    nmon = list.num_client + list.num_server;
+    RRMonitorFiniList(&list);
+    return nmon;
+}
+
+static void
+RRMonitorFree(RRMonitorPtr monitor)
+{
+    free(monitor);
+}
+
+static RRMonitorPtr
+RRMonitorAlloc(int noutput)
+{
+    RRMonitorPtr        monitor;
+
+    monitor = calloc(1, sizeof (RRMonitorRec) + noutput * sizeof (RROutput));
+    if (!monitor)
+        return NULL;
+    monitor->numOutputs = noutput;
+    monitor->outputs = (RROutput *) (monitor + 1);
+    return monitor;
+}
+
+static int
+RRMonitorDelete(ClientPtr client, ScreenPtr screen, Atom name)
+{
+    rrScrPrivPtr        pScrPriv = rrGetScrPriv(screen);
+    int                 m;
+
+    if (!pScrPriv) {
+        client->errorValue = name;
+        return BadAtom;
+    }
+
+    for (m = 0; m < pScrPriv->numMonitors; m++) {
+        RRMonitorPtr    monitor = pScrPriv->monitors[m];
+        if (monitor->name == name) {
+            memmove(pScrPriv->monitors + m, pScrPriv->monitors + m + 1,
+                    (pScrPriv->numMonitors - (m + 1)) * sizeof (RRMonitorPtr));
+            --pScrPriv->numMonitors;
+            RRMonitorFree(monitor);
+            return Success;
+        }
+    }
+
+    client->errorValue = name;
+    return BadValue;
+}
+
+static Bool
+RRMonitorMatchesOutputName(ScreenPtr screen, Atom name)
+{
+    rrScrPrivPtr        pScrPriv = rrGetScrPriv(screen);
+    int                 o;
+    const char          *str = NameForAtom(name);
+    int                 len = strlen(str);
+
+    for (o = 0; o < pScrPriv->numOutputs; o++) {
+        RROutputPtr     output = pScrPriv->outputs[o];
+
+        if (output->nameLength == len && !memcmp(output->name, str, len))
+            return TRUE;
+    }
+    return FALSE;
+}
+
+static int
+RRMonitorAdd(ClientPtr client, ScreenPtr screen, RRMonitorPtr monitor)
+{
+    rrScrPrivPtr        pScrPriv = rrGetScrPriv(screen);
+    int                 m;
+    ScreenPtr           slave;
+    RRMonitorPtr        *monitors;
+
+    if (!pScrPriv)
+        return BadAlloc;
+
+    /* 	'name' must not match the name of any Output on the screen, or
+     *	a Value error results.
+     */
+
+    if (RRMonitorMatchesOutputName(screen, monitor->name)) {
+        client->errorValue = monitor->name;
+        return BadValue;
+    }
+
+    xorg_list_for_each_entry(slave, &screen->output_slave_list, output_head) {
+        if (RRMonitorMatchesOutputName(slave, monitor->name)) {
+            client->errorValue = monitor->name;
+            return BadValue;
+        }
+    }
+
+    /* 'name' must not match the name of any Monitor on the screen, or
+     * a Value error results.
+     */
+
+    for (m = 0; m < pScrPriv->numMonitors; m++) {
+        if (pScrPriv->monitors[m]->name == monitor->name) {
+            client->errorValue = monitor->name;
+            return BadValue;
+        }
+    }
+
+    /* Allocate space for the new pointer. This is done before
+     * removing matching monitors as it may fail, and the request
+     * needs to not have any side-effects on failure
+     */
+    if (pScrPriv->numMonitors)
+        monitors = realloc(pScrPriv->monitors,
+                           (pScrPriv->numMonitors + 1) * sizeof (RRMonitorPtr));
+    else
+        monitors = malloc(sizeof (RRMonitorPtr));
+
+    if (!monitors)
+        return BadAlloc;
+
+    pScrPriv->monitors = monitors;
+
+    for (m = 0; m < pScrPriv->numMonitors; m++) {
+        RRMonitorPtr    existing = pScrPriv->monitors[m];
+        int             o, eo;
+
+	/* If 'name' matches an existing Monitor on the screen, the
+         * existing one will be deleted as if RRDeleteMonitor were called.
+         */
+        if (existing->name == monitor->name) {
+            (void) RRMonitorDelete(client, screen, existing->name);
+            continue;
+        }
+
+        /* For each output in 'info.outputs', each one is removed from all
+         * pre-existing Monitors. If removing the output causes the list
+         * of outputs for that Monitor to become empty, then that
+         * Monitor will be deleted as if RRDeleteMonitor were called.
+         */
+
+        for (eo = 0; eo < existing->numOutputs; eo++) {
+            for (o = 0; o < monitor->numOutputs; o++) {
+                if (monitor->outputs[o] == existing->outputs[eo]) {
+                    memmove(existing->outputs + eo, existing->outputs + eo + 1,
+                            (existing->numOutputs - (eo + 1)) * sizeof (RROutput));
+                    --existing->numOutputs;
+                    --eo;
+                    break;
+                }
+            }
+            if (existing->numOutputs == 0) {
+                (void) RRMonitorDelete(client, screen, existing->name);
+                break;
+            }
+        }
+        if (monitor->primary)
+            existing->primary = FALSE;
+    }
+
+    /* Add the new one to the list
+     */
+    pScrPriv->monitors[pScrPriv->numMonitors++] = monitor;
+
+    return Success;
+}
+
+void
+RRMonitorFreeList(RRMonitorPtr monitors, int nmon)
+{
+    int m;
+
+    for (m = 0; m < nmon; m++)
+        free(monitors[m].outputs);
+    free(monitors);
+}
+
+void
+RRMonitorInit(ScreenPtr screen)
+{
+    rrScrPrivPtr pScrPriv = rrGetScrPriv(screen);
+
+    if (!pScrPriv)
+        return;
+
+    pScrPriv->numMonitors = 0;
+    pScrPriv->monitors = NULL;
+}
+
+void
+RRMonitorClose(ScreenPtr screen)
+{
+    rrScrPrivPtr        pScrPriv = rrGetScrPriv(screen);
+    int                 m;
+
+    if (!pScrPriv)
+        return;
+
+    for (m = 0; m < pScrPriv->numMonitors; m++)
+        RRMonitorFree(pScrPriv->monitors[m]);
+    free(pScrPriv->monitors);
+    pScrPriv->monitors = NULL;
+    pScrPriv->numMonitors = 0;
+}
+
+static CARD32
+RRMonitorTimestamp(ScreenPtr screen)
+{
+    rrScrPrivPtr        pScrPriv = rrGetScrPriv(screen);
+
+    /* XXX should take client monitor changes into account */
+    return pScrPriv->lastConfigTime.milliseconds;
+}
+
+int
+ProcRRGetMonitors(ClientPtr client)
+{
+    REQUEST(xRRGetMonitorsReq);
+    xRRGetMonitorsReply rep = {
+        .type = X_Reply,
+        .sequenceNumber = client->sequence,
+        .length = 0,
+    };
+    WindowPtr           window;
+    ScreenPtr           screen;
+    int                 r;
+    RRMonitorPtr        monitors;
+    int                 nmonitors;
+    int                 noutputs;
+    int                 m;
+    Bool                get_active;
+    REQUEST_SIZE_MATCH(xRRGetMonitorsReq);
+    r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
+    if (r != Success)
+        return r;
+    screen = window->drawable.pScreen;
+
+    get_active = stuff->get_active;
+    if (!RRMonitorMakeList(screen, get_active, &monitors, &nmonitors))
+        return BadAlloc;
+
+    rep.timestamp = RRMonitorTimestamp(screen);
+
+    noutputs = 0;
+    for (m = 0; m < nmonitors; m++) {
+        rep.length += SIZEOF(xRRMonitorInfo) >> 2;
+        rep.length += monitors[m].numOutputs;
+        noutputs += monitors[m].numOutputs;
+    }
+
+    rep.nmonitors = nmonitors;
+    rep.noutputs = noutputs;
+
+    if (client->swapped) {
+        swaps(&rep.sequenceNumber);
+        swapl(&rep.length);
+        swapl(&rep.timestamp);
+        swapl(&rep.nmonitors);
+        swapl(&rep.noutputs);
+    }
+    WriteToClient(client, sizeof(xRRGetMonitorsReply), &rep);
+
+    client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
+
+    for (m = 0; m < nmonitors; m++) {
+        RRMonitorPtr    monitor = &monitors[m];
+        xRRMonitorInfo  info = {
+            .name = monitor->name,
+            .primary = monitor->primary,
+            .automatic = monitor->automatic,
+            .noutput = monitor->numOutputs,
+            .x = monitor->geometry.box.x1,
+            .y = monitor->geometry.box.y1,
+            .width = monitor->geometry.box.x2 - monitor->geometry.box.x1,
+            .height = monitor->geometry.box.y2 - monitor->geometry.box.y1,
+            .widthInMillimeters = monitor->geometry.mmWidth,
+            .heightInMillimeters = monitor->geometry.mmHeight,
+        };
+        if (client->swapped) {
+            swapl(&info.name);
+            swaps(&info.noutput);
+            swaps(&info.x);
+            swaps(&info.y);
+            swaps(&info.width);
+            swaps(&info.height);
+            swapl(&info.widthInMillimeters);
+            swapl(&info.heightInMillimeters);
+        }
+
+        WriteToClient(client, sizeof(xRRMonitorInfo), &info);
+        WriteSwappedDataToClient(client, monitor->numOutputs * sizeof (RROutput), monitor->outputs);
+    }
+
+    RRMonitorFreeList(monitors, nmonitors);
+
+    return Success;
+}
+
+int
+ProcRRSetMonitor(ClientPtr client)
+{
+    REQUEST(xRRSetMonitorReq);
+    WindowPtr           window;
+    ScreenPtr           screen;
+    RRMonitorPtr        monitor;
+    int                 r;
+
+    REQUEST_AT_LEAST_SIZE(xRRSetMonitorReq);
+
+    if (stuff->monitor.noutput != stuff->length - (SIZEOF(xRRSetMonitorReq) >> 2))
+        return BadLength;
+
+    r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
+    if (r != Success)
+        return r;
+    screen = window->drawable.pScreen;
+
+    if (!ValidAtom(stuff->monitor.name))
+        return BadAtom;
+
+    /* Allocate the new monitor */
+    monitor = RRMonitorAlloc(stuff->monitor.noutput);
+    if (!monitor)
+        return BadAlloc;
+
+    /* Fill in the bits from the request */
+    monitor->pScreen = screen;
+    monitor->name = stuff->monitor.name;
+    monitor->primary = stuff->monitor.primary;
+    monitor->automatic = FALSE;
+    memcpy(monitor->outputs, stuff + 1, stuff->monitor.noutput * sizeof (RROutput));
+    monitor->geometry.box.x1 = stuff->monitor.x;
+    monitor->geometry.box.y1 = stuff->monitor.y;
+    monitor->geometry.box.x2 = stuff->monitor.x + stuff->monitor.width;
+    monitor->geometry.box.y2 = stuff->monitor.y + stuff->monitor.height;
+    monitor->geometry.mmWidth = stuff->monitor.widthInMillimeters;
+    monitor->geometry.mmHeight = stuff->monitor.heightInMillimeters;
+
+    r = RRMonitorAdd(client, screen, monitor);
+    if (r != Success)
+        RRMonitorFree(monitor);
+    return r;
+}
+
+int
+ProcRRDeleteMonitor(ClientPtr client)
+{
+    REQUEST(xRRDeleteMonitorReq);
+    WindowPtr           window;
+    ScreenPtr           screen;
+    int                 r;
+
+    REQUEST_SIZE_MATCH(xRRDeleteMonitorReq);
+    r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
+    if (r != Success)
+        return r;
+    screen = window->drawable.pScreen;
+
+    if (!ValidAtom(stuff->name)) {
+        client->errorValue = stuff->name;
+        return BadAtom;
+    }
+
+    return RRMonitorDelete(client, screen, stuff->name);
+}
diff --git a/randr/rrsdispatch.c b/randr/rrsdispatch.c
index 47558cf..cf2a3b0 100644
--- a/randr/rrsdispatch.c
+++ b/randr/rrsdispatch.c
@@ -565,6 +565,41 @@ static int SProcRRGetProviderProperty(ClientPtr client)
     return ProcRandrVector[stuff->randrReqType] (client);
 }
 
+static int SProcRRGetMonitors(ClientPtr client) {
+    REQUEST(xRRGetMonitorsReq);
+
+    REQUEST_SIZE_MATCH(xRRGetMonitorsReq);
+    swaps(&stuff->length);
+    swapl(&stuff->window);
+    return ProcRandrVector[stuff->randrReqType] (client);
+}
+
+static int SProcRRSetMonitor(ClientPtr client) {
+    REQUEST(xRRSetMonitorReq);
+
+    REQUEST_AT_LEAST_SIZE(xRRGetMonitorsReq);
+    swaps(&stuff->length);
+    swapl(&stuff->window);
+    swapl(&stuff->monitor.name);
+    swaps(&stuff->monitor.noutput);
+    swaps(&stuff->monitor.x);
+    swaps(&stuff->monitor.y);
+    swaps(&stuff->monitor.width);
+    swaps(&stuff->monitor.height);
+    SwapRestL(stuff);
+    return ProcRandrVector[stuff->randrReqType] (client);
+}
+
+static int SProcRRDeleteMonitor(ClientPtr client) {
+    REQUEST(xRRDeleteMonitorReq);
+
+    REQUEST_SIZE_MATCH(xRRDeleteMonitorReq);
+    swaps(&stuff->length);
+    swapl(&stuff->window);
+    swapl(&stuff->name);
+    return ProcRandrVector[stuff->randrReqType] (client);
+}
+
 int (*SProcRandrVector[RRNumberRequests]) (ClientPtr) = {
     SProcRRQueryVersion,        /* 0 */
 /* we skip 1 to make old clients fail pretty immediately */
@@ -614,4 +649,7 @@ int (*SProcRandrVector[RRNumberRequests]) (ClientPtr) = {
         SProcRRChangeProviderProperty,  /* 39 */
         SProcRRDeleteProviderProperty,  /* 40 */
         SProcRRGetProviderProperty,     /* 41 */
+        SProcRRGetMonitors,            /* 42 */
+        SProcRRSetMonitor,             /* 43 */
+        SProcRRDeleteMonitor,          /* 44 */
 };
commit 9c2b4f8e0e2b5d4b5e1102d6eea7bdb4211baa68
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Mar 31 11:18:44 2015 +1000

    xf86Crtc: add tile prop setting
    
    Add support for drivers to set the tiling
    property. This is used by clients to
    work out the monitor tiles for DisplayID
    monitors.
    
    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 9d592a7..a194724 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -3026,6 +3026,27 @@ xf86OutputSetEDIDProperty(xf86OutputPtr output, void *data, int data_len)
     }
 }
 
+#define TILE_ATOM_NAME		"TILE"
+/* changing this in the future could be tricky as people may hardcode 8 */
+#define TILE_PROP_NUM_ITEMS		8
+static void
+xf86OutputSetTileProperty(xf86OutputPtr output)
+{
+    Atom tile_atom = MakeAtom(TILE_ATOM_NAME, sizeof(TILE_ATOM_NAME) - 1, TRUE);
+
+    /* This may get called before the RandR resources have been created */
+    if (output->randr_output == NULL)
+        return;
+
+    if (output->tile_info.group_id != 0) {
+        RRChangeOutputProperty(output->randr_output, tile_atom, XA_INTEGER, 32,
+                               PropModeReplace, TILE_PROP_NUM_ITEMS, (uint32_t *)&output->tile_info, FALSE, TRUE);
+    }
+    else {
+        RRDeleteOutputProperty(output->randr_output, tile_atom);
+    }
+}
+
 #endif
 
 /* Pull out a phyiscal size from a detailed timing if available. */
@@ -3071,6 +3092,38 @@ handle_detailed_physical_size(struct detailed_monitor_section
     }
 }
 
+Bool
+xf86OutputParseKMSTile(const char *tile_data, int tile_length,
+                       struct xf86CrtcTileInfo *tile_info)
+{
+    int ret;
+
+    ret = sscanf(tile_data, "%d:%d:%d:%d:%d:%d:%d:%d",
+                 &tile_info->group_id,
+                 &tile_info->flags,
+                 &tile_info->num_h_tile,
+                 &tile_info->num_v_tile,
+                 &tile_info->tile_h_loc,
+                 &tile_info->tile_v_loc,
+                 &tile_info->tile_h_size,
+                 &tile_info->tile_v_size);
+    if (ret != 8)
+        return FALSE;
+    return TRUE;
+}
+
+void
+xf86OutputSetTile(xf86OutputPtr output, struct xf86CrtcTileInfo *tile_info)
+{
+    if (tile_info)
+        output->tile_info = *tile_info;
+    else
+        memset(&output->tile_info, 0, sizeof(output->tile_info));
+#ifdef RANDR_12_INTERFACE
+    xf86OutputSetTileProperty(output);
+#endif
+}
+
 /**
  * Set the EDID information for the specified output
  */
diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
index 692bf40..3c5bbcf 100644
--- a/hw/xfree86/modes/xf86Crtc.h
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -70,6 +70,17 @@ typedef enum _xf86OutputStatus {
     XF86OutputStatusUnknown
 } xf86OutputStatus;
 
+struct xf86CrtcTileInfo {
+    uint32_t group_id;
+    uint32_t flags;
+    uint32_t num_h_tile;
+    uint32_t num_v_tile;
+    uint32_t tile_h_loc;
+    uint32_t tile_v_loc;
+    uint32_t tile_h_size;
+    uint32_t tile_v_size;
+};
+
 typedef struct _xf86CrtcFuncs {
    /**
     * Turns the crtc on/off, or sets intermediate power levels if available.
@@ -226,7 +237,7 @@ typedef struct _xf86CrtcFuncs {
 
 } xf86CrtcFuncsRec, *xf86CrtcFuncsPtr;
 
-#define XF86_CRTC_VERSION 5
+#define XF86_CRTC_VERSION 6
 
 struct _xf86Crtc {
     /**
@@ -500,7 +511,7 @@ typedef struct _xf86OutputFuncs {
      (*destroy) (xf86OutputPtr output);
 } xf86OutputFuncsRec, *xf86OutputFuncsPtr;
 
-#define XF86_OUTPUT_VERSION 2
+#define XF86_OUTPUT_VERSION 3
 
 struct _xf86Output {
     /**
@@ -615,6 +626,8 @@ struct _xf86Output {
     BoxRec initialTotalArea;
     BoxRec initialTrackingArea;
     INT16 initialBorder[4];
+
+    struct xf86CrtcTileInfo tile_info;
 };
 
 typedef struct _xf86ProviderFuncs {
@@ -881,6 +894,15 @@ extern _X_EXPORT void
  xf86OutputSetEDID(xf86OutputPtr output, xf86MonPtr edid_mon);
 
 /**
+ * Set the TILE information for the specified output
+ */
+extern _X_EXPORT void
+xf86OutputSetTile(xf86OutputPtr output, struct xf86CrtcTileInfo *tile_info);
+
+extern _X_EXPORT Bool
+xf86OutputParseKMSTile(const char *tile_data, int tile_length, struct xf86CrtcTileInfo *tile_info);
+
+/**
  * Return the list of modes supported by the EDID information
  * stored in 'output'
  */


More information about the xorg-commit mailing list