[PATCH xserver 3/3] Add RandR leases with modesetting driver support [v2]

Keith Packard keithp at keithp.com
Wed Aug 2 10:42:13 UTC 2017


This adds support for RandR CRTC/Output leases through the modesetting
driver, creating a lease using new kernel infrastructure and returning
that to a client through an fd which will have access to only those
resources.

v2:
	When a lease terminates for a crtc we have saved data for, go
	ahead and restore the saved mode.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 configure.ac                                     |   2 +-
 hw/xfree86/drivers/modesetting/drmmode_display.c | 138 ++++++++++++++++++++-
 hw/xfree86/drivers/modesetting/drmmode_display.h |   4 +
 hw/xfree86/modes/xf86Crtc.c                      |  11 +-
 hw/xfree86/modes/xf86Crtc.h                      |  67 +++++++++++
 hw/xfree86/modes/xf86RandR12.c                   |  54 +++++++++
 include/protocol-versions.h                      |   2 +-
 randr/Makefile.am                                |   1 +
 randr/randr.c                                    |  29 +++++
 randr/randrstr.h                                 |  65 +++++++++-
 randr/rrcrtc.c                                   | 147 ++++++++++++++---------
 randr/rrdispatch.c                               |   4 +
 randr/rrmode.c                                   |   6 +
 randr/rroutput.c                                 | 137 +++++++++++++--------
 randr/rrproperty.c                               |   6 +
 randr/rrsdispatch.c                              |  27 +++++
 16 files changed, 589 insertions(+), 111 deletions(-)

diff --git a/configure.ac b/configure.ac
index 8d3c3b55b..ac9fbc87f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -744,7 +744,7 @@ LIBXSHMFENCE="xshmfence >= 1.1"
 
 dnl Required modules
 XPROTO="xproto >= 7.0.31"
-RANDRPROTO="randrproto >= 1.5.0"
+RANDRPROTO="randrproto >= 1.6.0"
 RENDERPROTO="renderproto >= 0.11"
 XEXTPROTO="xextproto >= 7.2.99.901"
 INPUTPROTO="inputproto >= 2.3"
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 837421efe..70bc68354 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -54,7 +54,6 @@ static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
 static PixmapPtr drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
                                               int depth, int bitsPerPixel, int devKind,
                                               void *pPixData);
-
 static Bool drmmode_set_cursor(xf86CrtcPtr crtc);
 
 static void drmmode_hide_cursor(xf86CrtcPtr crtc);
@@ -2057,8 +2056,140 @@ drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
     return FALSE;
 }
 
+static void
+drmmode_validate_leases(ScrnInfoPtr scrn)
+{
+    ScreenPtr screen = scrn->pScreen;
+    rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
+    modesettingPtr ms = modesettingPTR(scrn);
+    drmmode_ptr drmmode = &ms->drmmode;
+    drmModeLesseeListPtr lessees;
+    RRLeasePtr lease, next;
+    int l;
+
+    lessees = drmModeListLessees(drmmode->fd);
+    if (!lessees)
+        return;
+
+    xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
+        drmmode_lease_private_ptr lease_private = lease->devPrivate;
+
+        for (l = 0; l < lessees->count; l++) {
+            if (lessees->lessees[l] == lease_private->lessee_id)
+                break;
+        }
+
+        /* check to see if the lease has gone away */
+        if (l == lessees->count) {
+            free(lease_private);
+            lease->devPrivate = NULL;
+            xf86CrtcLeaseTerminated(lease);
+        }
+    }
+
+    free(lessees);
+}
+
+static int
+drmmode_create_lease(RRLeasePtr lease, int *fd)
+{
+    ScreenPtr screen = lease->screen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    modesettingPtr ms = modesettingPTR(scrn);
+    drmmode_ptr drmmode = &ms->drmmode;
+    int ncrtc = lease->numCrtcs;
+    int noutput = lease->numOutputs;
+    int nencoder = 0;
+    int nobjects;
+    int c, o, e;
+    int i;
+    int lease_fd;
+    uint32_t *objects;
+    drmmode_lease_private_ptr   lease_private;
+
+    /* Find encoders for each output */
+    for (o = 0; o < noutput; o++) {
+        xf86OutputPtr   output = lease->outputs[o]->devPrivate;
+        drmmode_output_private_ptr drmmode_output = output->driver_private;
+
+        nencoder += drmmode_output->mode_output->count_encoders;
+    }
+
+    nobjects = ncrtc + noutput + nencoder;
+
+    if (nobjects == 0)
+        return BadValue;
+
+    lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
+    if (!lease_private)
+        return BadAlloc;
+
+    objects = xallocarray(nobjects, sizeof (uint32_t));
+
+    if (!objects) {
+        free(lease_private);
+        return BadAlloc;
+    }
+
+    i = 0;
+
+    /* Add CRTC ids */
+    for (c = 0; c < ncrtc; c++) {
+        xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
+        drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+        objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
+    }
+
+    /* Add connector and encoder ids */
+
+    for (o = 0; o < noutput; o++) {
+        xf86OutputPtr   output = lease->outputs[o]->devPrivate;
+        drmmode_output_private_ptr drmmode_output = output->driver_private;
+
+        objects[i++] = drmmode_output->mode_output->connector_id;
+        for (e = 0; e < drmmode_output->mode_output->count_encoders; e++)
+            objects[i++] = drmmode_output->mode_encoders[e]->encoder_id;
+    }
+
+    /* call kernel to create lease */
+    assert (i == nobjects);
+
+    lease_fd = drmModeCreateLease(drmmode->fd, objects, nobjects, 0, &lease_private->lessee_id);
+
+    free(objects);
+
+    if (lease_fd < 0) {
+        free(lease_private);
+        return BadMatch;
+    }
+
+    lease->devPrivate = lease_private;
+
+    *fd = lease_fd;
+    return Success;
+}
+
+static void
+drmmode_terminate_lease(RRLeasePtr lease)
+{
+    ScreenPtr screen = lease->screen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    modesettingPtr ms = modesettingPTR(scrn);
+    drmmode_ptr drmmode = &ms->drmmode;
+    drmmode_lease_private_ptr lease_private = lease->devPrivate;
+
+    if (drmModeRevokeLease(drmmode->fd, lease_private->lessee_id) == 0) {
+        free(lease_private);
+        lease->devPrivate = NULL;
+        xf86CrtcLeaseTerminated(lease);
+    }
+}
+
 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
-    drmmode_xf86crtc_resize
+    .resize = drmmode_xf86crtc_resize,
+    .create_lease = drmmode_create_lease,
+    .terminate_lease = drmmode_terminate_lease
 };
 
 Bool
@@ -2399,6 +2530,9 @@ drmmode_handle_uevents(int fd, void *closure)
         drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
     }
 
+    /* Check to see if a lessee has disappeared */
+    drmmode_validate_leases(scrn);
+
     if (changed) {
         RRSetChanged(xf86ScrnToScreen(scrn));
         RRTellChanged(xf86ScrnToScreen(scrn));
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index f774250ef..e99d32a86 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -140,6 +140,10 @@ typedef struct {
     int enc_clone_mask;
 } drmmode_output_private_rec, *drmmode_output_private_ptr;
 
+typedef struct {
+    uint32_t    lessee_id;
+} drmmode_lease_private_rec, *drmmode_lease_private_ptr;
+
 typedef struct _msPixmapPriv {
     uint32_t fb_id;
     struct dumb_bo *backing_bo; /* if this pixmap is backed by a dumb bo */
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index fa404d9d4..7cfbd6bc7 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -2665,6 +2665,9 @@ xf86PrepareOutputs(ScrnInfoPtr scrn)
     for (o = 0; o < config->num_output; o++) {
         xf86OutputPtr output = config->output[o];
 
+        if (RROutputIsLeased(output->randr_output))
+            continue;
+
 #if RANDR_GET_CRTC_INTERFACE
         /* Disable outputs that are unused or will be re-routed */
         if (!output->funcs->get_crtc ||
@@ -2682,12 +2685,15 @@ xf86PrepareCrtcs(ScrnInfoPtr scrn)
     int c;
 
     for (c = 0; c < config->num_crtc; c++) {
-#if RANDR_GET_CRTC_INTERFACE
         xf86CrtcPtr crtc = config->crtc[c];
+#if RANDR_GET_CRTC_INTERFACE
         xf86OutputPtr output = NULL;
         uint32_t desired_outputs = 0, current_outputs = 0;
         int o;
 
+        if (RRCrtcIsLeased(crtc->randr_crtc))
+            continue;
+
         for (o = 0; o < config->num_output; o++) {
             output = config->output[o];
             if (output->crtc == crtc)
@@ -2708,6 +2714,9 @@ xf86PrepareCrtcs(ScrnInfoPtr scrn)
         if (desired_outputs != current_outputs || !desired_outputs)
             (*crtc->funcs->dpms) (crtc, DPMSModeOff);
 #else
+        if (RRCrtcIsLeased(crtc->randr_crtc))
+            continue;
+
         (*crtc->funcs->dpms) (crtc, DPMSModeOff);
 #endif
     }
diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h
index 215eb2a04..840bf99b5 100644
--- a/hw/xfree86/modes/xf86Crtc.h
+++ b/hw/xfree86/modes/xf86Crtc.h
@@ -47,6 +47,7 @@
 
 typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr;
 typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr;
+typedef struct _xf86Lease xf86LeaseRec, *xf86LeasePtr;
 
 /* define a standard for connector types */
 typedef enum _xf86ConnectorType {
@@ -672,6 +673,54 @@ typedef struct _xf86ProviderFuncs {
 
 } xf86ProviderFuncsRec, *xf86ProviderFuncsPtr;
 
+#define XF86_LEASE_VERSION      1
+
+struct _xf86Lease {
+    /**
+     * ABI versioning
+     */
+    int version;
+
+    /**
+     * Associated ScrnInfo
+     */
+    ScrnInfoPtr scrn;
+
+    /**
+     * Driver private
+     */
+    void *driver_private;
+
+    /**
+     * RandR lease
+     */
+    RRLeasePtr randr_lease;
+
+    /*
+     * Contents of the lease
+     */
+
+    /**
+     * Number of leased CRTCs
+     */
+    int num_crtc;
+
+    /**
+     * Number of leased outputs
+     */
+    int num_output;
+
+    /**
+     * Array of pointers to leased CRTCs
+     */
+    RRCrtcPtr *crtcs;
+
+    /**
+     * Array of pointers to leased outputs
+     */
+    RROutputPtr *outputs;
+};
+
 typedef struct _xf86CrtcConfigFuncs {
     /**
      * Requests that the driver resize the screen.
@@ -687,8 +736,26 @@ typedef struct _xf86CrtcConfigFuncs {
      */
     Bool
      (*resize) (ScrnInfoPtr scrn, int width, int height);
+
+    /**
+     * Requests that the driver create a lease
+     */
+    int (*create_lease)(RRLeasePtr lease, int *fd);
+
+    /**
+     * Ask the driver to terminate a lease, freeing all
+     * driver resources
+     */
+    void (*terminate_lease)(RRLeasePtr lease);
 } xf86CrtcConfigFuncsRec, *xf86CrtcConfigFuncsPtr;
 
+/*
+ * The driver calls this when it detects that a lease
+ * has been terminated
+ */
+extern _X_EXPORT void
+xf86CrtcLeaseTerminated(RRLeasePtr lease);
+
 typedef void (*xf86_crtc_notify_proc_ptr) (ScreenPtr pScreen);
 
 typedef struct _xf86CrtcConfig {
diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c
index fe8770d61..c55ab7c90 100644
--- a/hw/xfree86/modes/xf86RandR12.c
+++ b/hw/xfree86/modes/xf86RandR12.c
@@ -2163,6 +2163,57 @@ xf86RandR14ProviderDestroy(ScreenPtr screen, RRProviderPtr provider)
     config->randr_provider = NULL;
 }
 
+void
+xf86CrtcLeaseTerminated(RRLeasePtr lease)
+{
+    int c;
+
+    /*
+     * Force a full mode set on any crtc in the expiring lease which
+     * was running before the lease started
+     */
+    for (c = 0; c < lease->numCrtcs; c++) {
+        RRCrtcPtr randr_crtc = lease->crtcs[c];
+        xf86CrtcPtr crtc = randr_crtc->devPrivate;
+
+        if (crtc->enabled) {
+            RRTransformPtr transform;
+
+            if (crtc->desiredTransformPresent)
+                transform = &crtc->desiredTransform;
+            else
+                transform = NULL;
+            xf86CrtcSetModeTransform(crtc, &crtc->desiredMode,
+                                     crtc->desiredRotation, transform,
+                                     crtc->desiredX, crtc->desiredY);
+        }
+    }
+    RRLeaseTerminated(lease);
+}
+
+static int
+xf86RandR16CreateLease(ScreenPtr screen, RRLeasePtr randr_lease, int *fd)
+{
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+
+    if (config->funcs->create_lease)
+        return config->funcs->create_lease(randr_lease, fd);
+    else
+        return BadMatch;
+}
+
+
+static void
+xf86RandR16TerminateLease(ScreenPtr screen, RRLeasePtr randr_lease)
+{
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+
+    if (config->funcs->terminate_lease)
+        config->funcs->terminate_lease(randr_lease);
+}
+
 static Bool
 xf86RandR12Init12(ScreenPtr pScreen)
 {
@@ -2192,6 +2243,9 @@ xf86RandR12Init12(ScreenPtr pScreen)
     rp->rrCrtcSetScanoutPixmap = xf86CrtcSetScanoutPixmap;
     rp->rrProviderDestroy = xf86RandR14ProviderDestroy;
 
+    rp->rrCreateLease = xf86RandR16CreateLease;
+    rp->rrTerminateLease = xf86RandR16TerminateLease;
+
     pScrn->PointerMoved = xf86RandR12PointerMoved;
     pScrn->ChangeGamma = xf86RandR12ChangeGamma;
 
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index b4498927b..938b9caa4 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		5
+#define SERVER_RANDR_MINOR_VERSION		6
 
 /* Record */
 #define SERVER_RECORD_MAJOR_VERSION		1
diff --git a/randr/Makefile.am b/randr/Makefile.am
index 90dc9ec9a..f9cefd18a 100644
--- a/randr/Makefile.am
+++ b/randr/Makefile.am
@@ -14,6 +14,7 @@ librandr_la_SOURCES =	\
 	rrcrtc.c	\
 	rrdispatch.c	\
 	rrinfo.c	\
+	rrlease.c	\
 	rrmode.c	\
 	rrmonitor.c	\
 	rroutput.c	\
diff --git a/randr/randr.c b/randr/randr.c
index 507158eb6..339ad3ece 100644
--- a/randr/randr.c
+++ b/randr/randr.c
@@ -2,6 +2,7 @@
  * Copyright © 2000 Compaq Computer Corporation
  * Copyright © 2002 Hewlett-Packard Company
  * Copyright © 2006 Intel Corporation
+ * Copyright © 2017 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
@@ -223,6 +224,19 @@ SRRResourceChangeNotifyEvent(xRRResourceChangeNotifyEvent * from,
 }
 
 static void _X_COLD
+SRRLeaseNotifyEvent(xRRLeaseNotifyEvent * from,
+                    xRRLeaseNotifyEvent * 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->lease, to->lease);
+    to->created = from->created;
+}
+
+static void _X_COLD
 SRRNotifyEvent(xEvent *from, xEvent *to)
 {
     switch (from->u.u.detail) {
@@ -249,6 +263,11 @@ SRRNotifyEvent(xEvent *from, xEvent *to)
     case RRNotify_ResourceChange:
         SRRResourceChangeNotifyEvent((xRRResourceChangeNotifyEvent *) from,
                                    (xRRResourceChangeNotifyEvent *) to);
+        break;
+    case RRNotify_Lease:
+        SRRLeaseNotifyEvent((xRRLeaseNotifyEvent *) from,
+                            (xRRLeaseNotifyEvent *) to);
+        break;
     default:
         break;
     }
@@ -268,6 +287,8 @@ RRInit(void)
             return FALSE;
         if (!RRProviderInit())
             return FALSE;
+        if (!RRLeaseInit())
+            return FALSE;
         RRGeneration = serverGeneration;
     }
     if (!dixRegisterPrivateKey(&rrPrivKeyRec, PRIVATE_SCREEN, 0))
@@ -335,6 +356,8 @@ RRScreenInit(ScreenPtr pScreen)
     pScrPriv->numCrtcs = 0;
     pScrPriv->crtcs = NULL;
 
+    xorg_list_init(&pScrPriv->leases);
+
     RRMonitorInit(pScreen);
 
     RRNScreens += 1;            /* keep count of screens that implement randr */
@@ -532,6 +555,12 @@ TellChanged(WindowPtr pWin, void *value)
                 RRDeliverResourceEvent(client, pWin);
             }
         }
+
+        if (pRREvent->mask & RRLeaseNotifyMask) {
+            if (pScrPriv->leasesChanged) {
+                RRDeliverLeaseEvent(client, pWin);
+            }
+        }
     }
     return WT_WALKCHILDREN;
 }
diff --git a/randr/randrstr.h b/randr/randrstr.h
index 706e9a7b0..924c0e837 100644
--- a/randr/randrstr.h
+++ b/randr/randrstr.h
@@ -63,6 +63,7 @@ typedef XID RRMode;
 typedef XID RROutput;
 typedef XID RRCrtc;
 typedef XID RRProvider;
+typedef XID RRLease;
 
 extern int RREventBase, RRErrorBase;
 
@@ -81,6 +82,7 @@ typedef struct _rrCrtc RRCrtcRec, *RRCrtcPtr;
 typedef struct _rrOutput RROutputRec, *RROutputPtr;
 typedef struct _rrProvider RRProviderRec, *RRProviderPtr;
 typedef struct _rrMonitor RRMonitorRec, *RRMonitorPtr;
+typedef struct _rrLease RRLeaseRec, *RRLeasePtr;
 
 struct _rrMode {
     int refcnt;
@@ -187,6 +189,20 @@ struct _rrMonitor {
     RRMonitorGeometryRec geometry;
 };
 
+typedef enum _rrLeaseState { RRLeaseCreating, RRLeaseRunning, RRLeaseTerminating } RRLeaseState;
+
+struct _rrLease {
+    struct xorg_list list;
+    ScreenPtr screen;
+    RRLease id;
+    RRLeaseState state;
+    void *devPrivate;
+    int numCrtcs;
+    RRCrtcPtr *crtcs;
+    int numOutputs;
+    RROutputPtr *outputs;
+};
+
 #if RANDR_12_INTERFACE
 typedef Bool (*RRScreenSetSizeProcPtr) (ScreenPtr pScreen,
                                         CARD16 width,
@@ -254,6 +270,15 @@ typedef Bool (*RRProviderSetOffloadSinkProcPtr)(ScreenPtr pScreen,
 typedef void (*RRProviderDestroyProcPtr)(ScreenPtr pScreen,
                                          RRProviderPtr provider);
 
+/* Additions for 1.6 */
+
+typedef int (*RRCreateLeaseProcPtr)(ScreenPtr screen,
+                                    RRLeasePtr lease,
+                                    int *fd);
+
+typedef void (*RRTerminateLeaseProcPtr)(ScreenPtr screen,
+                                        RRLeasePtr lease);
+
 /* These are for 1.0 compatibility */
 
 typedef struct _rrRefresh {
@@ -326,6 +351,10 @@ typedef struct _rrScrPriv {
     RRProviderSetOffloadSinkProcPtr rrProviderSetOffloadSink;
     RRProviderGetPropertyProcPtr rrProviderGetProperty;
     RRProviderSetPropertyProcPtr rrProviderSetProperty;
+
+    RRCreateLeaseProcPtr rrCreateLease;
+    RRTerminateLeaseProcPtr rrTerminateLease;
+
     /*
      * Private part of the structure; not considered part of the ABI
      */
@@ -337,6 +366,7 @@ typedef struct _rrScrPriv {
     Bool configChanged;         /* configuration changed */
     Bool layoutChanged;         /* screen layout changed */
     Bool resourcesChanged;      /* screen resources change */
+    Bool leasesChanged;         /* leases change */
 
     CARD16 minWidth, minHeight;
     CARD16 maxWidth, maxHeight;
@@ -376,6 +406,7 @@ typedef struct _rrScrPriv {
     int numMonitors;
     RRMonitorPtr *monitors;
 
+    struct xorg_list leases;
 } rrScrPrivRec, *rrScrPrivPtr;
 
 extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec;
@@ -419,7 +450,7 @@ extern RESTYPE RRClientType, RREventType;     /* resource types for event masks
 extern DevPrivateKeyRec RRClientPrivateKeyRec;
 
 #define RRClientPrivateKey (&RRClientPrivateKeyRec)
-extern _X_EXPORT RESTYPE RRCrtcType, RRModeType, RROutputType, RRProviderType;
+extern _X_EXPORT RESTYPE RRCrtcType, RRModeType, RROutputType, RRProviderType, RRLeaseType;
 
 #define VERIFY_RR_OUTPUT(id, ptr, a)\
     {\
@@ -461,6 +492,16 @@ extern _X_EXPORT RESTYPE RRCrtcType, RRModeType, RROutputType, RRProviderType;
         }\
     }
 
+#define VERIFY_RR_LEASE(id, ptr, a)\
+    {\
+        int rc = dixLookupResourceByType((void **)&(ptr), id,\
+                                         RRLeaseType, 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)
 
@@ -769,6 +810,22 @@ void
 extern _X_EXPORT Bool
  RRClientKnowsRates(ClientPtr pClient);
 
+/* rrlease.c */
+void
+RRDeliverLeaseEvent(ClientPtr client, WindowPtr window);
+
+void
+RRLeaseTerminated(RRLeasePtr lease);
+
+extern _X_EXPORT Bool
+RRCrtcIsLeased(RRCrtcPtr crtc);
+
+extern _X_EXPORT Bool
+RROutputIsLeased(RROutputPtr output);
+
+Bool
+RRLeaseInit(void);
+
 /* rrmode.c */
 /*
  * Find, and if necessary, create a mode
@@ -1059,6 +1116,12 @@ ProcRRSetMonitor(ClientPtr client);
 int
 ProcRRDeleteMonitor(ClientPtr client);
 
+int
+ProcRRCreateLease(ClientPtr client);
+
+int
+ProcRRFreeLease(ClientPtr client);
+
 #endif                          /* _RANDRSTR_H_ */
 
 /*
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index 401a1c178..f310cd00f 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -1079,7 +1079,7 @@ ProcRRGetCrtcInfo(ClientPtr client)
     REQUEST(xRRGetCrtcInfoReq);
     xRRGetCrtcInfoReply rep;
     RRCrtcPtr crtc;
-    CARD8 *extra;
+    CARD8 *extra = NULL;
     unsigned long extraLen;
     ScreenPtr pScreen;
     rrScrPrivPtr pScrPriv;
@@ -1089,10 +1089,13 @@ ProcRRGetCrtcInfo(ClientPtr client)
     int i, j, k;
     int width, height;
     BoxRec panned_area;
+    Bool leased;
 
     REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
 
+    leased = RRCrtcIsLeased(crtc);
+
     /* All crtcs must be associated with screens before client
      * requests are processed
      */
@@ -1108,61 +1111,77 @@ ProcRRGetCrtcInfo(ClientPtr client)
         .length = 0,
         .timestamp = pScrPriv->lastSetTime.milliseconds
     };
-    if (pScrPriv->rrGetPanning &&
-        pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
-        (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
-    {
-        rep.x = panned_area.x1;
-        rep.y = panned_area.y1;
-        rep.width = panned_area.x2 - panned_area.x1;
-        rep.height = panned_area.y2 - panned_area.y1;
-    }
-    else {
-        RRCrtcGetScanoutSize(crtc, &width, &height);
-        rep.x = crtc->x;
-        rep.y = crtc->y;
-        rep.width = width;
-        rep.height = height;
-    }
-    rep.mode = mode ? mode->mode.id : 0;
-    rep.rotation = crtc->rotation;
-    rep.rotations = crtc->rotations;
-    rep.nOutput = crtc->numOutputs;
-    k = 0;
-    for (i = 0; i < pScrPriv->numOutputs; i++)
-        for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
-            if (pScrPriv->outputs[i]->crtcs[j] == crtc)
-                k++;
-    rep.nPossibleOutput = k;
-
-    rep.length = rep.nOutput + rep.nPossibleOutput;
-
-    extraLen = rep.length << 2;
-    if (extraLen) {
-        extra = malloc(extraLen);
-        if (!extra)
-            return BadAlloc;
-    }
-    else
-        extra = NULL;
-
-    outputs = (RROutput *) extra;
-    possible = (RROutput *) (outputs + rep.nOutput);
-
-    for (i = 0; i < crtc->numOutputs; i++) {
-        outputs[i] = crtc->outputs[i]->id;
-        if (client->swapped)
-            swapl(&outputs[i]);
-    }
-    k = 0;
-    for (i = 0; i < pScrPriv->numOutputs; i++)
-        for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
-            if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
-                possible[k] = pScrPriv->outputs[i]->id;
-                if (client->swapped)
-                    swapl(&possible[k]);
-                k++;
+    if (leased) {
+        rep.x = rep.y = rep.width = rep.height = 0;
+        rep.mode = 0;
+        rep.rotation = 0;
+        rep.rotations = 0;
+        rep.nOutput = 0;
+        rep.nPossibleOutput = 0;
+        rep.length = 0;
+        extraLen = 0;
+    } else {
+        if (pScrPriv->rrGetPanning &&
+            pScrPriv->rrGetPanning(pScreen, crtc, &panned_area, NULL, NULL) &&
+            (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1))
+        {
+            rep.x = panned_area.x1;
+            rep.y = panned_area.y1;
+            rep.width = panned_area.x2 - panned_area.x1;
+            rep.height = panned_area.y2 - panned_area.y1;
+        }
+        else {
+            RRCrtcGetScanoutSize(crtc, &width, &height);
+            rep.x = crtc->x;
+            rep.y = crtc->y;
+            rep.width = width;
+            rep.height = height;
+        }
+        rep.mode = mode ? mode->mode.id : 0;
+        rep.rotation = crtc->rotation;
+        rep.rotations = crtc->rotations;
+        rep.nOutput = crtc->numOutputs;
+        k = 0;
+        for (i = 0; i < pScrPriv->numOutputs; i++) {
+            if (!RROutputIsLeased(pScrPriv->outputs[i])) {
+                for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
+                    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
+                        k++;
+            }
+        }
+
+        rep.nPossibleOutput = k;
+
+        rep.length = rep.nOutput + rep.nPossibleOutput;
+
+        extraLen = rep.length << 2;
+        if (extraLen) {
+            extra = malloc(extraLen);
+            if (!extra)
+                return BadAlloc;
+        }
+
+        outputs = (RROutput *) extra;
+        possible = (RROutput *) (outputs + rep.nOutput);
+
+        for (i = 0; i < crtc->numOutputs; i++) {
+            outputs[i] = crtc->outputs[i]->id;
+            if (client->swapped)
+                swapl(&outputs[i]);
+        }
+        k = 0;
+        for (i = 0; i < pScrPriv->numOutputs; i++) {
+            if (!RROutputIsLeased(pScrPriv->outputs[i])) {
+                for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
+                    if (pScrPriv->outputs[i]->crtcs[j] == crtc) {
+                        possible[k] = pScrPriv->outputs[i]->id;
+                        if (client->swapped)
+                            swapl(&possible[k]);
+                        k++;
+                    }
             }
+        }
+    }
 
     if (client->swapped) {
         swaps(&rep.sequenceNumber);
@@ -1209,6 +1228,9 @@ ProcRRSetCrtcConfig(ClientPtr client)
 
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixSetAttrAccess);
 
+    if (RRCrtcIsLeased(crtc))
+        return BadAccess;
+
     if (stuff->mode == None) {
         mode = NULL;
         if (numOutputs > 0)
@@ -1235,6 +1257,12 @@ ProcRRSetCrtcConfig(ClientPtr client)
             free(outputs);
             return ret;
         }
+
+        if (RROutputIsLeased(outputs[i])) {
+            free(outputs);
+            return BadAccess;
+        }
+
         /* validate crtc for this output */
         for (j = 0; j < outputs[i]->numCrtcs; j++)
             if (outputs[i]->crtcs[j] == crtc)
@@ -1478,6 +1506,9 @@ ProcRRSetPanning(ClientPtr client)
     REQUEST_SIZE_MATCH(xRRSetPanningReq);
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
 
+    if (RRCrtcIsLeased(crtc))
+        return BadAccess;
+
     /* All crtcs must be associated with screens before client
      * requests are processed
      */
@@ -1618,6 +1649,9 @@ ProcRRSetCrtcGamma(ClientPtr client)
     REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
 
+    if (RRCrtcIsLeased(crtc))
+        return BadAccess;
+
     len = client->req_len - bytes_to_int32(sizeof(xRRSetCrtcGammaReq));
     if (len < (stuff->size * 3 + 1) >> 1)
         return BadLength;
@@ -1651,6 +1685,9 @@ ProcRRSetCrtcTransform(ClientPtr client)
     REQUEST_AT_LEAST_SIZE(xRRSetCrtcTransformReq);
     VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
 
+    if (RRCrtcIsLeased(crtc))
+        return BadAccess;
+
     PictTransform_from_xRenderTransform(&transform, &stuff->transform);
     pixman_f_transform_from_pixman_transform(&f_transform, &transform);
     if (!pixman_f_transform_invert(&f_inverse, &f_transform))
diff --git a/randr/rrdispatch.c b/randr/rrdispatch.c
index 314e4ea52..a5b390914 100644
--- a/randr/rrdispatch.c
+++ b/randr/rrdispatch.c
@@ -256,7 +256,11 @@ int (*ProcRandrVector[RRNumberRequests]) (ClientPtr) = {
         ProcRRChangeProviderProperty, /* 39 */
         ProcRRDeleteProviderProperty, /* 40 */
         ProcRRGetProviderProperty,    /* 41 */
+/* V1.5 additions */
         ProcRRGetMonitors,            /* 42 */
         ProcRRSetMonitor,             /* 43 */
         ProcRRDeleteMonitor,          /* 44 */
+/* V1.6 additions */
+        ProcRRCreateLease,            /* 45 */
+        ProcRRFreeLease,              /* 46 */
 };
diff --git a/randr/rrmode.c b/randr/rrmode.c
index a7aa43320..d34025bd0 100644
--- a/randr/rrmode.c
+++ b/randr/rrmode.c
@@ -357,6 +357,9 @@ ProcRRAddOutputMode(ClientPtr client)
     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
     VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess);
 
+    if (RROutputIsLeased(output))
+        return BadAccess;
+
     return RROutputAddUserMode(output, mode);
 }
 
@@ -371,5 +374,8 @@ ProcRRDeleteOutputMode(ClientPtr client)
     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
     VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess);
 
+    if (RROutputIsLeased(output))
+        return BadAccess;
+
     return RROutputDeleteUserMode(output, mode);
 }
diff --git a/randr/rroutput.c b/randr/rroutput.c
index a8efec409..ce2e6216b 100644
--- a/randr/rroutput.c
+++ b/randr/rroutput.c
@@ -429,65 +429,99 @@ ProcRRGetOutputInfo(ClientPtr client)
     RROutput *clones;
     char *name;
     int i;
+    Bool leased;
 
     REQUEST_SIZE_MATCH(xRRGetOutputInfoReq);
     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
 
+    leased = RROutputIsLeased(output);
+
     pScreen = output->pScreen;
     pScrPriv = rrGetScrPriv(pScreen);
 
-    rep = (xRRGetOutputInfoReply) {
-        .type = X_Reply,
-        .status = RRSetConfigSuccess,
-        .sequenceNumber = client->sequence,
-        .length = bytes_to_int32(OutputInfoExtra),
-        .timestamp = pScrPriv->lastSetTime.milliseconds,
-        .crtc = output->crtc ? output->crtc->id : None,
-        .mmWidth = output->mmWidth,
-        .mmHeight = output->mmHeight,
-        .connection = output->connection,
-        .subpixelOrder = output->subpixelOrder,
-        .nCrtcs = output->numCrtcs,
-        .nModes = output->numModes + output->numUserModes,
-        .nPreferred = output->numPreferred,
-        .nClones = output->numClones,
-        .nameLength = output->nameLength
-    };
-    extraLen = ((output->numCrtcs +
-                 output->numModes + output->numUserModes +
-                 output->numClones + bytes_to_int32(rep.nameLength)) << 2);
-
-    if (extraLen) {
-        rep.length += bytes_to_int32(extraLen);
-        extra = malloc(extraLen);
-        if (!extra)
-            return BadAlloc;
-    }
-    else
-        extra = NULL;
+    if (leased) {
+        rep = (xRRGetOutputInfoReply) {
+            .type = X_Reply,
+            .status = RRSetConfigSuccess,
+            .sequenceNumber = client->sequence,
+            .length = bytes_to_int32(OutputInfoExtra),
+            .timestamp = pScrPriv->lastSetTime.milliseconds,
+            .crtc = None,
+            .mmWidth = 0,
+            .mmHeight = 0,
+            .connection = 0,
+            .subpixelOrder = SubPixelUnknown,
+            .nCrtcs = 0,
+            .nModes = 0,
+            .nPreferred = 0,
+            .nClones = 0,
+            .nameLength = output->nameLength
+        };
+        extraLen = bytes_to_int32(rep.nameLength) << 2;
+        if (extraLen) {
+            rep.length += bytes_to_int32(extraLen);
+            extra = malloc(extraLen);
+            if (!extra)
+                return BadAlloc;
+        }
+        else
+            extra = NULL;
+
+        name = (char *) extra;
+    } else {
+        rep = (xRRGetOutputInfoReply) {
+            .type = X_Reply,
+            .status = RRSetConfigSuccess,
+            .sequenceNumber = client->sequence,
+            .length = bytes_to_int32(OutputInfoExtra),
+            .timestamp = pScrPriv->lastSetTime.milliseconds,
+            .crtc = output->crtc ? output->crtc->id : None,
+            .mmWidth = output->mmWidth,
+            .mmHeight = output->mmHeight,
+            .connection = output->connection,
+            .subpixelOrder = output->subpixelOrder,
+            .nCrtcs = output->numCrtcs,
+            .nModes = output->numModes + output->numUserModes,
+            .nPreferred = output->numPreferred,
+            .nClones = output->numClones,
+            .nameLength = output->nameLength
+        };
+        extraLen = ((output->numCrtcs +
+                     output->numModes + output->numUserModes +
+                     output->numClones + bytes_to_int32(rep.nameLength)) << 2);
+
+        if (extraLen) {
+            rep.length += bytes_to_int32(extraLen);
+            extra = malloc(extraLen);
+            if (!extra)
+                return BadAlloc;
+        }
+        else
+            extra = NULL;
 
-    crtcs = (RRCrtc *) extra;
-    modes = (RRMode *) (crtcs + output->numCrtcs);
-    clones = (RROutput *) (modes + output->numModes + output->numUserModes);
-    name = (char *) (clones + output->numClones);
+        crtcs = (RRCrtc *) extra;
+        modes = (RRMode *) (crtcs + output->numCrtcs);
+        clones = (RROutput *) (modes + output->numModes + output->numUserModes);
+        name = (char *) (clones + output->numClones);
 
-    for (i = 0; i < output->numCrtcs; i++) {
-        crtcs[i] = output->crtcs[i]->id;
-        if (client->swapped)
-            swapl(&crtcs[i]);
-    }
-    for (i = 0; i < output->numModes + output->numUserModes; i++) {
-        if (i < output->numModes)
-            modes[i] = output->modes[i]->mode.id;
-        else
-            modes[i] = output->userModes[i - output->numModes]->mode.id;
-        if (client->swapped)
-            swapl(&modes[i]);
-    }
-    for (i = 0; i < output->numClones; i++) {
-        clones[i] = output->clones[i]->id;
-        if (client->swapped)
-            swapl(&clones[i]);
+        for (i = 0; i < output->numCrtcs; i++) {
+            crtcs[i] = output->crtcs[i]->id;
+            if (client->swapped)
+                swapl(&crtcs[i]);
+        }
+        for (i = 0; i < output->numModes + output->numUserModes; i++) {
+            if (i < output->numModes)
+                modes[i] = output->modes[i]->mode.id;
+            else
+                modes[i] = output->userModes[i - output->numModes]->mode.id;
+            if (client->swapped)
+                swapl(&modes[i]);
+        }
+        for (i = 0; i < output->numClones; i++) {
+            clones[i] = output->clones[i]->id;
+            if (client->swapped)
+                swapl(&clones[i]);
+        }
     }
     memcpy(name, output->name, output->nameLength);
     if (client->swapped) {
@@ -554,6 +588,9 @@ ProcRRSetOutputPrimary(ClientPtr client)
     if (stuff->output) {
         VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
 
+        if (RROutputIsLeased(output))
+            return BadAccess;
+
         if (!output->pScreen->isGPU && output->pScreen != pWin->drawable.pScreen) {
             client->errorValue = stuff->window;
             return BadMatch;
diff --git a/randr/rrproperty.c b/randr/rrproperty.c
index e56626cd2..b5a591de5 100644
--- a/randr/rrproperty.c
+++ b/randr/rrproperty.c
@@ -485,6 +485,9 @@ ProcRRConfigureOutputProperty(ClientPtr client)
 
     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
 
+    if (RROutputIsLeased(output))
+        return BadAccess;
+
     num_valid =
         stuff->length - bytes_to_int32(sizeof(xRRConfigureOutputPropertyReq));
     return RRConfigureOutputProperty(output, stuff->property, stuff->pending,
@@ -555,6 +558,9 @@ ProcRRDeleteOutputProperty(ClientPtr client)
     UpdateCurrentTime();
     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
 
+    if (RROutputIsLeased(output))
+        return BadAccess;
+
     if (!ValidAtom(stuff->property)) {
         client->errorValue = stuff->property;
         return BadAtom;
diff --git a/randr/rrsdispatch.c b/randr/rrsdispatch.c
index e0ffaa4d5..7d7b5a884 100644
--- a/randr/rrsdispatch.c
+++ b/randr/rrsdispatch.c
@@ -613,6 +613,29 @@ SProcRRDeleteMonitor(ClientPtr client) {
     return ProcRandrVector[stuff->randrReqType] (client);
 }
 
+static int _X_COLD
+SProcRRCreateLease(ClientPtr client) {
+    REQUEST(xRRCreateLeaseReq);
+
+    REQUEST_AT_LEAST_SIZE(xRRCreateLeaseReq);
+    swaps(&stuff->length);
+    swapl(&stuff->window);
+    swaps(&stuff->nCrtcs);
+    swaps(&stuff->nOutputs);
+    SwapRestL(stuff);
+    return ProcRandrVector[stuff->randrReqType] (client);
+}
+
+static int _X_COLD
+SProcRRFreeLease(ClientPtr client) {
+    REQUEST(xRRFreeLeaseReq);
+
+    REQUEST_SIZE_MATCH(xRRFreeLeaseReq);
+    swaps(&stuff->length);
+    swapl(&stuff->lid);
+    return ProcRandrVector[stuff->randrReqType] (client);
+}
+
 int (*SProcRandrVector[RRNumberRequests]) (ClientPtr) = {
     SProcRRQueryVersion,        /* 0 */
 /* we skip 1 to make old clients fail pretty immediately */
@@ -662,7 +685,11 @@ int (*SProcRandrVector[RRNumberRequests]) (ClientPtr) = {
         SProcRRChangeProviderProperty,  /* 39 */
         SProcRRDeleteProviderProperty,  /* 40 */
         SProcRRGetProviderProperty,     /* 41 */
+/* V1.5 additions */
         SProcRRGetMonitors,            /* 42 */
         SProcRRSetMonitor,             /* 43 */
         SProcRRDeleteMonitor,          /* 44 */
+/* V1.6 additions */
+        SProcRRCreateLease,            /* 45 */
+        SProcRRFreeLease,              /* 46 */
 };
-- 
2.11.0



More information about the xorg-devel mailing list