diff --git a/configure.ac b/configure.ac index eb5b3a224..4d7c24fa9 100644 --- a/configure.ac +++ b/configure.ac @@ -759,7 +759,7 @@ dnl List of libraries that require a specific version LIBAPPLEWM="applewm >= 1.4" LIBDMX="dmx >= 1.0.99.1" LIBDRI="dri >= 7.8.0" -LIBDRM="libdrm >= 2.3.1" +LIBDRM="libdrm >= 2.4.89" LIBEGL="egl" LIBGBM="gbm >= 10.2.0" LIBGL="gl >= 7.1.0" diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 7dce56ed4..ec2aa9a27 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -1804,6 +1804,9 @@ CloseScreen(ScreenPtr pScreen) free(ms->drmmode.shadow_fb2); ms->drmmode.shadow_fb2 = NULL; } + + drmmode_terminate_leases(pScrn, &ms->drmmode); + drmmode_uevent_fini(pScrn, &ms->drmmode); drmmode_free_bos(pScrn, &ms->drmmode); diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 1db514fc6..bfc8c50db 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2085,8 +2085,152 @@ 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; + + /* We can't talk to the kernel about leases when VT switched */ + if (!scrn->vtSema) + return; + + 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 nobjects; + int c, o; + int i; + int lease_fd; + uint32_t *objects; + drmmode_lease_private_ptr lease_private; + + nobjects = ncrtc + noutput; + + 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 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; + } + + /* 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; + + xf86CrtcLeaseStarted(lease); + + *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); + } +} + +void +drmmode_terminate_leases(ScrnInfoPtr pScrn, drmmode_ptr drmmode) +{ + ScreenPtr screen = xf86ScrnToScreen(pScrn); + rrScrPrivPtr scr_priv = rrGetScrPriv(screen); + RRLeasePtr lease, next; + + xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { + drmmode_lease_private_ptr lease_private = lease->devPrivate; + drmModeRevokeLease(drmmode->fd, lease_private->lessee_id); + free(lease_private); + lease->devPrivate = NULL; + RRLeaseTerminated(lease); + RRLeaseFree(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 @@ -2222,6 +2366,10 @@ drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw) return FALSE; } } + + /* Validate leases on VT re-entry */ + drmmode_validate_leases(pScrn); + return TRUE; } @@ -2427,6 +2575,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 65e127c52..267040918 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -143,6 +143,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 */ @@ -191,6 +195,8 @@ extern Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn); extern void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode); extern void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode); +extern void drmmode_terminate_leases(ScrnInfoPtr scrn, drmmode_ptr drmmode); + Bool drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode); void *drmmode_map_front_bo(drmmode_ptr drmmode); Bool drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode); diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c index 3ed7347df..4aa77a244 100644 --- a/hw/xfree86/modes/xf86Crtc.c +++ b/hw/xfree86/modes/xf86Crtc.c @@ -254,7 +254,7 @@ xf86CrtcSetModeTransform(xf86CrtcPtr crtc, DisplayModePtr mode, RRTransformRec saved_transform; Bool saved_transform_present; - crtc->enabled = xf86CrtcInUse(crtc); + crtc->enabled = xf86CrtcInUse(crtc) && !RRCrtcIsLeased(crtc->randr_crtc);; /* We only hit this if someone explicitly sends a "disabled" modeset. */ if (!crtc->enabled) { @@ -411,6 +411,10 @@ xf86CrtcSetOrigin(xf86CrtcPtr crtc, int x, int y) crtc->x = x; crtc->y = y; + + if (RRCrtcIsLeased(crtc->randr_crtc)) + return; + if (crtc->funcs->set_origin) { if (!xf86CrtcRotate(crtc)) return; @@ -2652,6 +2656,9 @@ xf86InitialConfiguration(ScrnInfoPtr scrn, Bool canGrow) static void xf86DisableCrtc(xf86CrtcPtr crtc) { + if (RRCrtcIsLeased(crtc->randr_crtc)) + return; + crtc->funcs->dpms(crtc, DPMSModeOff); xf86_crtc_hide_cursor(crtc); } @@ -2670,6 +2677,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 || @@ -2687,12 +2697,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) @@ -2713,6 +2726,9 @@ xf86PrepareCrtcs(ScrnInfoPtr scrn) if (desired_outputs != current_outputs || !desired_outputs) xf86DisableCrtc(crtc); #else + if (RRCrtcIsLeased(crtc->randr_crtc)) + continue; + xf86DisableCrtc(crtc); #endif } @@ -2948,7 +2964,7 @@ xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) for (i = 0; i < config->num_output; i++) { xf86OutputPtr output = config->output[i]; - if (output->crtc != NULL) + if (!RROutputIsLeased(output->randr_output) && output->crtc != NULL) (*output->funcs->dpms) (output, mode); } } @@ -2964,7 +2980,7 @@ xf86DPMSSet(ScrnInfoPtr scrn, int mode, int flags) for (i = 0; i < config->num_output; i++) { xf86OutputPtr output = config->output[i]; - if (output->crtc != NULL) + if (!RROutputIsLeased(output->randr_output) && output->crtc != NULL) (*output->funcs->dpms) (output, mode); } } diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h index ae81417f6..1d1124a1b 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 { @@ -677,6 +678,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. @@ -692,8 +741,29 @@ 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); + +extern _X_EXPORT void +xf86CrtcLeaseStarted(RRLeasePtr lease); + typedef void (*xf86_crtc_notify_proc_ptr) (ScreenPtr pScreen); typedef struct _xf86CrtcConfig { @@ -1009,6 +1079,12 @@ extern _X_EXPORT Bool extern _X_EXPORT void xf86_crtc_hide_cursor(xf86CrtcPtr crtc); +/** + * Called by the driver to turn a single crtc's cursor on + */ +extern _X_EXPORT Bool +xf86_crtc_show_cursor(xf86CrtcPtr crtc); + /** * Called by the driver to turn cursors off */ diff --git a/hw/xfree86/modes/xf86Cursors.c b/hw/xfree86/modes/xf86Cursors.c index ae2137d80..dba5f8877 100644 --- a/hw/xfree86/modes/xf86Cursors.c +++ b/hw/xfree86/modes/xf86Cursors.c @@ -344,11 +344,13 @@ xf86_hide_cursors(ScrnInfoPtr scrn) } } -static Bool +Bool xf86_crtc_show_cursor(xf86CrtcPtr crtc) { - if (!crtc->cursor_in_range) + if (!crtc->cursor_in_range) { + crtc->funcs->hide_cursor(crtc); return TRUE; + } if (!crtc->cursor_shown) crtc->cursor_shown = xf86_driver_show_cursor(crtc); diff --git a/hw/xfree86/modes/xf86RandR12.c b/hw/xfree86/modes/xf86RandR12.c index 818048335..b49d4c789 100644 --- a/hw/xfree86/modes/xf86RandR12.c +++ b/hw/xfree86/modes/xf86RandR12.c @@ -2205,6 +2205,131 @@ xf86RandR14ProviderDestroy(ScreenPtr screen, RRProviderPtr provider) config->randr_provider = NULL; } +static void +xf86CrtcCheckReset(xf86CrtcPtr crtc) { + if (xf86CrtcInUse(crtc)) { + RRTransformPtr transform; + + if (crtc->desiredTransformPresent) + transform = &crtc->desiredTransform; + else + transform = NULL; + xf86CrtcSetModeTransform(crtc, &crtc->desiredMode, + crtc->desiredRotation, transform, + crtc->desiredX, crtc->desiredY); + xf86_crtc_show_cursor(crtc); + } +} + +void +xf86CrtcLeaseTerminated(RRLeasePtr lease) +{ + int c; + int o; + + RRLeaseTerminated(lease); + /* + * 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; + + xf86CrtcCheckReset(crtc); + } + + /* Check to see if any leased output is using a crtc which + * was not reset in the above loop + */ + for (o = 0; o < lease->numOutputs; o++) { + RROutputPtr randr_output = lease->outputs[o]; + xf86OutputPtr output = randr_output->devPrivate; + xf86CrtcPtr crtc = output->crtc; + + if (crtc) { + for (c = 0; c < lease->numCrtcs; c++) + if (lease->crtcs[c] == crtc->randr_crtc) + break; + if (c != lease->numCrtcs) + continue; + xf86CrtcCheckReset(crtc); + } + } + RRLeaseFree(lease); +} + +static Bool +xf86CrtcSoleOutput(xf86CrtcPtr crtc, xf86OutputPtr output) +{ + ScrnInfoPtr scrn = crtc->scrn; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int o; + + for (o = 0; o < config->num_output; o++) { + xf86OutputPtr other = config->output[o]; + + if (other != output && other->crtc == crtc) + return FALSE; + } + return TRUE; +} + +void +xf86CrtcLeaseStarted(RRLeasePtr lease) +{ + int c; + int o; + + for (c = 0; c < lease->numCrtcs; c++) { + RRCrtcPtr randr_crtc = lease->crtcs[c]; + xf86CrtcPtr crtc = randr_crtc->devPrivate; + + if (crtc->enabled) { + /* + * Leave the primary plane enabled so we can + * flip without blanking the screen. Hide + * the cursor so it doesn't remain on the screen + * while the lease is active + */ + xf86_crtc_hide_cursor(crtc); + crtc->enabled = FALSE; + } + } + for (o = 0; o < lease->numOutputs; o++) { + RROutputPtr randr_output = lease->outputs[o]; + xf86OutputPtr output = randr_output->devPrivate; + xf86CrtcPtr crtc = output->crtc; + + if (crtc) + if (xf86CrtcSoleOutput(crtc, output)) + crtc->enabled = FALSE; + } +} + +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) { @@ -2234,6 +2359,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/meson.build b/meson.build index c6a391c73..77d3c9def 100644 --- a/meson.build +++ b/meson.build @@ -154,7 +154,7 @@ if (host_machine.system() != 'darwin' and xwayland_dep = [ dependency('wayland-client', version: '>= 1.3.0', required: xwayland_required), dependency('wayland-protocols', version: '>= 1.10', required: xwayland_required), - dependency('libdrm', version: '>= 2.3.1', required: xwayland_required), + dependency('libdrm', version: '>= 2.4.89', required: xwayland_required), dependency('epoxy', required: xwayland_required), ] 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/meson.build b/randr/meson.build index 69fab24e2..cc0e8efe9 100644 --- a/randr/meson.build +++ b/randr/meson.build @@ -3,6 +3,7 @@ srcs_randr = [ '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 @@ -222,6 +223,19 @@ SRRResourceChangeNotifyEvent(xRRResourceChangeNotifyEvent * from, cpswapl(from->window, to->window); } +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) { @@ -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 b4fe833d9..f94174b54 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; @@ -188,6 +190,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, @@ -255,6 +271,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 { @@ -327,6 +352,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 */ @@ -338,6 +367,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; @@ -377,6 +407,7 @@ typedef struct _rrScrPriv { int numMonitors; RRMonitorPtr *monitors; + struct xorg_list leases; } rrScrPrivRec, *rrScrPrivPtr; extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec; @@ -420,7 +451,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)\ {\ @@ -462,6 +493,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) @@ -772,6 +813,25 @@ void extern _X_EXPORT Bool RRClientKnowsRates(ClientPtr pClient); +/* rrlease.c */ +void +RRDeliverLeaseEvent(ClientPtr client, WindowPtr window); + +extern _X_EXPORT void +RRLeaseTerminated(RRLeasePtr lease); + +extern _X_EXPORT void +RRLeaseFree(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 @@ -1062,6 +1122,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 39af679b2..338064f9f 100644 --- a/randr/rrcrtc.c +++ b/randr/rrcrtc.c @@ -1075,7 +1075,7 @@ ProcRRGetCrtcInfo(ClientPtr client) REQUEST(xRRGetCrtcInfoReq); xRRGetCrtcInfoReply rep; RRCrtcPtr crtc; - CARD8 *extra; + CARD8 *extra = NULL; unsigned long extraLen; ScreenPtr pScreen; rrScrPrivPtr pScrPriv; @@ -1085,10 +1085,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 */ @@ -1104,61 +1107,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 = RR_Rotate_0; + rep.rotations = RR_Rotate_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); @@ -1205,6 +1224,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) @@ -1231,6 +1253,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) @@ -1474,6 +1502,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 */ @@ -1614,6 +1645,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; @@ -1647,6 +1681,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/rrlease.c b/randr/rrlease.c new file mode 100644 index 000000000..b4a8827cc --- /dev/null +++ b/randr/rrlease.c @@ -0,0 +1,351 @@ +/* + * 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 + * 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" +#include + +RESTYPE RRLeaseType; + +/* + * Notify of some lease change + */ +void +RRDeliverLeaseEvent(ClientPtr client, WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + rrScrPrivPtr scr_priv = rrGetScrPriv(screen); + RRLeasePtr lease; + + UpdateCurrentTimeIf(); + xorg_list_for_each_entry(lease, &scr_priv->leases, list) { + if (lease->id != None && (lease->state == RRLeaseCreating || + lease->state == RRLeaseTerminating)) + { + xRRLeaseNotifyEvent le = (xRRLeaseNotifyEvent) { + .type = RRNotify + RREventBase, + .subCode = RRNotify_Lease, + .timestamp = currentTime.milliseconds, + .window = window->drawable.id, + .lease = lease->id, + .created = lease->state == RRLeaseCreating, + }; + WriteEventsToClient(client, 1, (xEvent *) &le); + } + } +} + +/* + * Change the state of a lease and let anyone watching leases know + */ +static void +RRLeaseChangeState(RRLeasePtr lease, RRLeaseState old, RRLeaseState new) +{ + ScreenPtr screen = lease->screen; + rrScrPrivPtr scr_priv = rrGetScrPriv(screen); + + lease->state = old; + scr_priv->leasesChanged = TRUE; + RRSetChanged(lease->screen); + RRTellChanged(lease->screen); + scr_priv->leasesChanged = FALSE; + lease->state = new; +} + +/* + * Allocate and initialize a lease + */ +static RRLeasePtr +RRLeaseAlloc(ScreenPtr screen, RRLease lid, int numCrtcs, int numOutputs) +{ + RRLeasePtr lease; + lease = calloc(1, + sizeof(RRLeaseRec) + + numCrtcs * sizeof (RRCrtcPtr) + + numOutputs * sizeof(RROutputPtr)); + if (!lease) + return NULL; + lease->screen = screen; + xorg_list_init(&lease->list); + lease->id = lid; + lease->state = RRLeaseCreating; + lease->numCrtcs = numCrtcs; + lease->numOutputs = numOutputs; + lease->crtcs = (RRCrtcPtr *) (lease + 1); + lease->outputs = (RROutputPtr *) (lease->crtcs + numCrtcs); + return lease; +} + +/* + * Check if a crtc is leased + */ +Bool +RRCrtcIsLeased(RRCrtcPtr crtc) +{ + ScreenPtr screen = crtc->pScreen; + rrScrPrivPtr scr_priv = rrGetScrPriv(screen); + RRLeasePtr lease; + int c; + + xorg_list_for_each_entry(lease, &scr_priv->leases, list) { + for (c = 0; c < lease->numCrtcs; c++) + if (lease->crtcs[c] == crtc) + return TRUE; + } + return FALSE; +} + +/* + * Check if an output is leased + */ +Bool +RROutputIsLeased(RROutputPtr output) +{ + ScreenPtr screen = output->pScreen; + rrScrPrivPtr scr_priv = rrGetScrPriv(screen); + RRLeasePtr lease; + int o; + + xorg_list_for_each_entry(lease, &scr_priv->leases, list) { + for (o = 0; o < lease->numOutputs; o++) + if (lease->outputs[o] == output) + return TRUE; + } + return FALSE; +} + +/* + * A lease has been terminated. + * The driver is responsible for noticing and + * calling this function when that happens + */ + +void +RRLeaseTerminated(RRLeasePtr lease) +{ + /* Notify clients with events, but only if this isn't during lease creation */ + if (lease->state == RRLeaseRunning) + RRLeaseChangeState(lease, RRLeaseTerminating, RRLeaseTerminating); + + if (lease->id != None) + FreeResource(lease->id, RT_NONE); + + xorg_list_del(&lease->list); +} + +/* + * A lease is completely shut down and is + * ready to be deallocated + */ + +void +RRLeaseFree(RRLeasePtr lease) +{ + free(lease); +} + +/* + * Ask the driver to terminate a lease. The + * driver will call RRLeaseTerminated when that has + * finished, which may be some time after this function returns + * if the driver operation is asynchronous + */ +static void +RRTerminateLease(RRLeasePtr lease) +{ + ScreenPtr screen = lease->screen; + rrScrPrivPtr scr_priv = rrGetScrPriv(screen); + + scr_priv->rrTerminateLease(screen, lease); +} + +/* + * Destroy a lease resource ID. All this + * does is note that the lease no longer has an ID, and + * so doesn't appear over the protocol anymore. + */ +static int +RRLeaseDestroyResource(void *value, XID pid) +{ + RRLeasePtr lease = value; + + lease->id = None; + return 1; +} + +/* + * Create the lease resource type during server initialization + */ +Bool +RRLeaseInit(void) +{ + RRLeaseType = CreateNewResourceType(RRLeaseDestroyResource, "LEASE"); + if (!RRLeaseType) + return FALSE; + return TRUE; +} + +int +ProcRRCreateLease(ClientPtr client) +{ + REQUEST(xRRCreateLeaseReq); + xRRCreateLeaseReply rep; + WindowPtr window; + ScreenPtr screen; + rrScrPrivPtr scr_priv; + RRLeasePtr lease; + RRCrtc *crtcIds; + RROutput *outputIds; + int fd; + int rc; + unsigned long len; + int c, o; + + REQUEST_AT_LEAST_SIZE(xRRCreateLeaseReq); + + LEGAL_NEW_RESOURCE(stuff->lid, client); + + rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + len = client->req_len - bytes_to_int32(sizeof(xRRCreateLeaseReq)); + + if (len != stuff->nCrtcs + stuff->nOutputs) + return BadLength; + + screen = window->drawable.pScreen; + scr_priv = rrGetScrPriv(screen); + + if (!scr_priv) + return BadMatch; + + if (!scr_priv->rrCreateLease) + return BadMatch; + + /* Allocate a structure to hold all of the lease information */ + + lease = RRLeaseAlloc(screen, stuff->lid, stuff->nCrtcs, stuff->nOutputs); + if (!lease) + return BadAlloc; + + /* Look up all of the crtcs */ + crtcIds = (RRCrtc *) (stuff + 1); + for (c = 0; c < stuff->nCrtcs; c++) { + RRCrtcPtr crtc; + + rc = dixLookupResourceByType((void **)&crtc, crtcIds[c], + RRCrtcType, client, DixSetAttrAccess); + + if (rc != Success) { + client->errorValue = crtcIds[c]; + goto bail_lease; + } + + if (RRCrtcIsLeased(crtc)) { + client->errorValue = crtcIds[c]; + rc = BadAccess; + goto bail_lease; + } + + lease->crtcs[c] = crtc; + } + + /* Look up all of the outputs */ + outputIds = (RROutput *) (crtcIds + stuff->nCrtcs); + for (o = 0; o < stuff->nOutputs; o++) { + RROutputPtr output; + + rc = dixLookupResourceByType((void **)&output, outputIds[o], + RROutputType, client, DixSetAttrAccess); + if (rc != Success) { + client->errorValue = outputIds[o]; + goto bail_lease; + } + + if (RROutputIsLeased(output)) { + client->errorValue = outputIds[o]; + rc = BadAccess; + goto bail_lease; + } + + lease->outputs[o] = output; + } + + rc = scr_priv->rrCreateLease(screen, lease, &fd); + if (rc != Success) + goto bail_lease; + + xorg_list_add(&scr_priv->leases, &lease->list); + + if (!AddResource(stuff->lid, RRLeaseType, lease)) { + close(fd); + return BadAlloc; + } + + if (WriteFdToClient(client, fd, TRUE) < 0) { + RRTerminateLease(lease); + close(fd); + return BadAlloc; + } + + RRLeaseChangeState(lease, RRLeaseCreating, RRLeaseRunning); + + rep = (xRRCreateLeaseReply) { + .type = X_Reply, + .nfd = 1, + .sequenceNumber = client->sequence, + .length = 0, + }; + + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + } + + WriteToClient(client, sizeof (rep), &rep); + + return Success; + +bail_lease: + free(lease); + return rc; +} + +int +ProcRRFreeLease(ClientPtr client) +{ + REQUEST(xRRFreeLeaseReq); + RRLeasePtr lease; + + REQUEST_SIZE_MATCH(xRRFreeLeaseReq); + + VERIFY_RR_LEASE(stuff->lid, lease, DixDestroyAccess); + + if (stuff->terminate) + RRTerminateLease(lease); + else + /* Get rid of the resource database entry */ + FreeResource(stuff->lid, RT_NONE); + + return Success; +} 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 d5c30aded..b0ffedea8 100644 --- a/randr/rroutput.c +++ b/randr/rroutput.c @@ -449,66 +449,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->nonDesktop ? RR_Disconnected : output->connection, - .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 = calloc(1, 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); - - 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; + 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 = RR_Disconnected, + .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 = calloc(1, extraLen); + if (!extra) + return BadAlloc; + } 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]); + 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->nonDesktop ? RR_Disconnected : 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 = calloc(1, 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); + + 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) { @@ -575,6 +608,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 6598f6259..c2fb9585c 100644 --- a/randr/rrproperty.c +++ b/randr/rrproperty.c @@ -512,6 +512,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, @@ -582,6 +585,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/rrscreen.c b/randr/rrscreen.c index d059ce74a..58fd47be0 100644 --- a/randr/rrscreen.c +++ b/randr/rrscreen.c @@ -267,7 +267,7 @@ ProcRRSetScreenSize(ClientPtr client) RRCrtcPtr crtc = pScrPriv->crtcs[i]; RRModePtr mode = crtc->mode; - if (mode) { + if (!RRCrtcIsLeased(crtc) && mode) { int source_width = mode->mode.width; int source_height = mode->mode.height; Rotation rotation = crtc->rotation; 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 */ };