diff options
author | Drew DeVault <sir@cmpwn.com> | 2019-07-25 15:51:33 -0400 |
---|---|---|
committer | Olivier Fourdan <fourdan@gmail.com> | 2021-12-07 10:02:29 +0000 |
commit | 089e7f98f86836fdd09fd231bff8004c0fc45381 (patch) | |
tree | 87b1ffd0f67550eb8da73dc6392eeeceb314a497 | |
parent | 7759743c6387f72faa9eb8602ea3f2777c0e0d17 (diff) |
Xwayland: implement drm-lease-v1
This commit allows X11 clients running through Xwayland to lease
non-desktop connectors from the Wayland compositor by implementing
support for drm-lease-v1.
In order to not deadlock with the Wayland compositor if its response
to a lease request is delayed, the new interface in _rrScrPriv
introduced in the last commit is used, which makes it possible to
block the X11 client while a response is pending.
Leasing normal outputs is not yet supported, all connectors offered
for lease will be advertised as non-desktop.
Co-authored-by: Xaver Hugl <xaver.hugl@gmail.com>
Reviewed-by: Simon Ser <contact@emersion.fr>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Acked-by: Michel Dänzer <mdaenzer@redhat.com>
-rw-r--r-- | hw/xwayland/meson.build | 9 | ||||
-rw-r--r-- | hw/xwayland/xwayland-drm-lease.c | 439 | ||||
-rw-r--r-- | hw/xwayland/xwayland-drm-lease.h | 67 | ||||
-rw-r--r-- | hw/xwayland/xwayland-output.c | 32 | ||||
-rw-r--r-- | hw/xwayland/xwayland-output.h | 23 | ||||
-rw-r--r-- | hw/xwayland/xwayland-screen.c | 46 | ||||
-rw-r--r-- | hw/xwayland/xwayland-screen.h | 4 | ||||
-rw-r--r-- | hw/xwayland/xwayland-types.h | 1 |
8 files changed, 608 insertions, 13 deletions
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index 093d7552b..37c39497c 100644 --- a/hw/xwayland/meson.build +++ b/hw/xwayland/meson.build @@ -4,6 +4,8 @@ srcs = [ 'xwayland-input.h', 'xwayland-cursor.c', 'xwayland-cursor.h', + 'xwayland-drm-lease.h', + 'xwayland-drm-lease.c', 'xwayland-glamor.h', 'xwayland-glx.h', 'xwayland-pixmap.c', @@ -43,6 +45,7 @@ xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unst dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml') viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml') xdg_shell_xml = join_paths(protodir, 'stable', 'xdg-shell', 'xdg-shell.xml') +drm_lease_xml = join_paths(protodir, 'staging', 'drm-lease', 'drm-lease-v1.xml') client_header = generator(scanner, output : '@BASENAME@-client-protocol.h', @@ -68,6 +71,7 @@ srcs += client_header.process(xdg_output_xml) srcs += client_header.process(dmabuf_xml) srcs += client_header.process(viewporter_xml) srcs += client_header.process(xdg_shell_xml) +srcs += client_header.process(drm_lease_xml) srcs += code.process(relative_xml) srcs += code.process(pointer_xml) srcs += code.process(gestures_xml) @@ -77,6 +81,7 @@ srcs += code.process(xdg_output_xml) srcs += code.process(dmabuf_xml) srcs += code.process(viewporter_xml) srcs += code.process(xdg_shell_xml) +srcs += code.process(drm_lease_xml) xwayland_glamor = [] eglstream_srcs = [] @@ -116,6 +121,10 @@ if build_glx wayland_inc += glx_inc endif +if libdrm_dep.found() + xwayland_dep += libdrm_dep +endif + xwayland_server = executable( 'Xwayland', srcs, diff --git a/hw/xwayland/xwayland-drm-lease.c b/hw/xwayland/xwayland-drm-lease.c new file mode 100644 index 000000000..656e6a62d --- /dev/null +++ b/hw/xwayland/xwayland-drm-lease.c @@ -0,0 +1,439 @@ +/* + * Copyright © 2020 Drew Devault + * Copyright © 2021 Xaver Hugl + * + * 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 <xwayland-config.h> + +#ifdef WITH_LIBDRM +#include <xf86drm.h> +#include <xf86drmMode.h> +#endif + +#include "xwayland-drm-lease.h" +#include "xwayland-screen.h" +#include "xwayland-output.h" + +static void +drm_lease_handle_lease_fd(void *data, + struct wp_drm_lease_v1 *wp_drm_lease_v1, + int32_t lease_fd) +{ + struct xwl_drm_lease *lease = (struct xwl_drm_lease *)data; + + lease->fd = lease_fd; + AttendClient(lease->client); +} + +static void +drm_lease_handle_finished(void *data, + struct wp_drm_lease_v1 *wp_drm_lease_v1) +{ + struct xwl_drm_lease *lease = (struct xwl_drm_lease *)data; + struct xwl_output *output; + int i; + + if (lease->fd >= 0) { + RRTerminateLease(lease->rrLease); + } else { + AttendClient(lease->client); + for (i = 0; i < lease->rrLease->numOutputs; ++i) { + output = lease->rrLease->outputs[i]->devPrivate; + output->lease = NULL; + } + } +} + +static struct wp_drm_lease_v1_listener drm_lease_listener = { + .lease_fd = drm_lease_handle_lease_fd, + .finished = drm_lease_handle_finished, +}; + +void +xwl_randr_get_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr *rrLease, int *fd) +{ + struct xwl_screen *xwl_screen; + struct xwl_drm_lease *lease; + xwl_screen = xwl_screen_get(screen); + + xorg_list_for_each_entry(lease, &xwl_screen->drm_leases, link) { + if (lease->client == client) { + *rrLease = lease->rrLease; + *fd = lease->fd; + if (lease->fd < 0) + xorg_list_del(&lease->link); + return; + } + } + *rrLease = NULL; + *fd = -1; +} + +int +xwl_randr_request_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr rrLease) +{ + struct xwl_screen *xwl_screen; + struct wp_drm_lease_request_v1 *req; + struct xwl_drm_lease *lease_private; + struct xwl_drm_lease_device *lease_device = NULL; + struct xwl_drm_lease_device *device_data; + struct xwl_output *output; + int i; + + xwl_screen = xwl_screen_get(screen); + + if (xorg_list_is_empty(&xwl_screen->drm_lease_devices)) { + ErrorF("Attempted to create DRM lease without wp_drm_lease_device_v1\n"); + return BadMatch; + } + + xorg_list_for_each_entry(device_data, &xwl_screen->drm_lease_devices, link) { + Bool connectors_of_device = FALSE; + for (i = 0; i < rrLease->numOutputs; ++i) { + output = rrLease->outputs[i]->devPrivate; + if (output->lease_device == device_data) { + connectors_of_device = TRUE; + break; + } + } + if (connectors_of_device) { + if (lease_device != NULL) { + ErrorF("Attempted to create DRM lease from multiple devices\n"); + return BadValue; + } + lease_device = device_data; + } + } + + for (i = 0; i < rrLease->numOutputs; ++i) { + output = rrLease->outputs[i]->devPrivate; + if (!output || !output->lease_connector || output->lease) { + return BadValue; + } + } + + req = wp_drm_lease_device_v1_create_lease_request( + lease_device->drm_lease_device); + lease_private = calloc(1, sizeof(struct xwl_drm_lease)); + for (i = 0; i < rrLease->numOutputs; ++i) { + output = rrLease->outputs[i]->devPrivate; + output->lease = lease_private; + wp_drm_lease_request_v1_request_connector(req, output->lease_connector); + } + lease_private->fd = -1; + lease_private->lease = wp_drm_lease_request_v1_submit(req); + lease_private->rrLease = rrLease; + lease_private->client = client; + rrLease->devPrivate = lease_private; + + wp_drm_lease_v1_add_listener(lease_private->lease, + &drm_lease_listener, lease_private); + xorg_list_add(&lease_private->link, &xwl_screen->drm_leases); + + ResetCurrentRequest(client); + client->sequence--; + IgnoreClient(client); + + return Success; +} + +void +xwl_randr_terminate_lease(ScreenPtr screen, RRLeasePtr lease) +{ + struct xwl_drm_lease *lease_private = lease->devPrivate; + + if (lease_private) { + xorg_list_del(&lease_private->link); + if (lease_private->fd >= 0) + close(lease_private->fd); + wp_drm_lease_v1_destroy(lease_private->lease); + free(lease_private); + lease->devPrivate = NULL; + } + + RRLeaseTerminated(lease); +} + +static void +lease_connector_handle_name(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, + const char *name) +{ + /* This space is deliberately left blank */ +} + +static void +lease_connector_handle_description(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, + const char *description) +{ + /* This space is deliberately left blank */ +} + +static RRModePtr * +xwl_get_rrmodes_from_connector_id(int drm, int32_t connector_id, int *nmode, int *npref) +{ +#ifdef WITH_LIBDRM + drmModeConnectorPtr conn; + drmModeModeInfoPtr kmode; + RRModePtr *rrmodes; + int pref, i; + + *nmode = *npref = 0; + + conn = drmModeGetConnectorCurrent(drm, connector_id); + if (!conn) { + ErrorF("drmModeGetConnector for connector %d failed\n", connector_id); + return NULL; + } + rrmodes = xallocarray(conn->count_modes, sizeof(RRModePtr)); + if (!rrmodes) { + ErrorF("Failed to allocate connector modes\n"); + drmModeFreeConnector(conn); + return NULL; + } + + /* This spaghetti brought to you courtesey of xf86RandrR12.c + * It adds preferred modes first, then non-preferred modes */ + for (pref = 1; pref >= 0; pref--) { + for (i = 0; i < conn->count_modes; ++i) { + kmode = &conn->modes[i]; + if ((pref != 0) == ((kmode->type & DRM_MODE_TYPE_PREFERRED) != 0)) { + xRRModeInfo modeInfo; + RRModePtr rrmode; + + modeInfo.nameLength = strlen(kmode->name); + + modeInfo.width = kmode->hdisplay; + modeInfo.dotClock = kmode->clock * 1000; + modeInfo.hSyncStart = kmode->hsync_start; + modeInfo.hSyncEnd = kmode->hsync_end; + modeInfo.hTotal = kmode->htotal; + modeInfo.hSkew = kmode->hskew; + + modeInfo.height = kmode->vdisplay; + modeInfo.vSyncStart = kmode->vsync_start; + modeInfo.vSyncEnd = kmode->vsync_end; + modeInfo.vTotal = kmode->vtotal; + modeInfo.modeFlags = kmode->flags; + + rrmode = RRModeGet(&modeInfo, kmode->name); + if (rrmode) { + rrmodes[*nmode] = rrmode; + *nmode = *nmode + 1; + *npref = *npref + pref; + } + } + } + } + /* workaround: there could be no preferred mode that got added */ + if (*nmode > 0 && *npref == 0) + *npref = 1; + + drmModeFreeConnector(conn); + return rrmodes; +#else + *nmode = *npref = 0; + return NULL; +#endif +} + +static void +lease_connector_handle_connector_id(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, + uint32_t connector_id) +{ + struct xwl_output *output; + Atom name; + INT32 value; + int err; + int nmode, npref; + RRModePtr *rrmodes; + + value = connector_id; + output = (struct xwl_output *)data; + name = MakeAtom("CONNECTOR_ID", 12, TRUE); + + if (name != BAD_RESOURCE) { + err = RRConfigureOutputProperty(output->randr_output, name, + FALSE, FALSE, TRUE, + 1, &value); + if (err != 0) { + ErrorF("RRConfigureOutputProperty error, %d\n", err); + return; + } + err = RRChangeOutputProperty(output->randr_output, name, + XA_INTEGER, 32, PropModeReplace, 1, + &value, FALSE, FALSE); + if (err != 0) { + ErrorF("RRChangeOutputProperty error, %d\n", err); + return; + } + } + rrmodes = xwl_get_rrmodes_from_connector_id(output->lease_device->drm_read_only_fd, + connector_id, &nmode, &npref); + + if (rrmodes != NULL) + RROutputSetModes(output->randr_output, rrmodes, nmode, npref); + + free(rrmodes); +} + +static void +lease_connector_handle_done(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) +{ + /* This space is deliberately left blank */ +} + +static void +lease_connector_handle_withdrawn(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) +{ + xwl_output_remove(data); +} + +static const struct wp_drm_lease_connector_v1_listener lease_connector_listener = { + .name = lease_connector_handle_name, + .description = lease_connector_handle_description, + .connector_id = lease_connector_handle_connector_id, + .withdrawn = lease_connector_handle_withdrawn, + .done = lease_connector_handle_done, +}; + +static void +drm_lease_device_handle_drm_fd(void *data, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, + int fd) +{ + ((struct xwl_drm_lease_device *)data)->drm_read_only_fd = fd; +} + +static void +drm_lease_device_handle_connector(void *data, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, + struct wp_drm_lease_connector_v1 *connector) +{ + struct xwl_drm_lease_device *lease_device = data; + struct xwl_output *xwl_output; + char name[256]; + + xwl_output = calloc(1, sizeof *xwl_output); + if (xwl_output == NULL) { + ErrorF("%s ENOMEM\n", __func__); + return; + } + + snprintf(name, sizeof name, "XWAYLAND%d", xwl_get_next_output_serial()); + + xwl_output->lease_device = lease_device; + xwl_output->xwl_screen = lease_device->xwl_screen; + xwl_output->lease_connector = connector; + xwl_output->randr_crtc = RRCrtcCreate(lease_device->xwl_screen->screen, xwl_output); + if (!xwl_output->randr_crtc) { + ErrorF("Failed creating RandR CRTC\n"); + goto err; + } + RRCrtcSetRotations(xwl_output->randr_crtc, ALL_ROTATIONS); + xwl_output->randr_output = RROutputCreate(lease_device->xwl_screen->screen, + name, strlen(name), xwl_output); + if (!xwl_output->randr_output) { + ErrorF("Failed creating RandR Output\n"); + goto err; + } + + RRCrtcGammaSetSize(xwl_output->randr_crtc, 256); + RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1); + RROutputSetConnection(xwl_output->randr_output, RR_Connected); + RROutputSetNonDesktop(xwl_output->randr_output, TRUE); + xwl_output->randr_output->devPrivate = xwl_output; + + wp_drm_lease_connector_v1_add_listener(connector, + &lease_connector_listener, + xwl_output); + + xorg_list_append(&xwl_output->link, &lease_device->xwl_screen->output_list); + return; + +err: + if (xwl_output->randr_crtc) + RRCrtcDestroy(xwl_output->randr_crtc); + free(xwl_output); +} + +static void +drm_lease_device_handle_released(void *data, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + xwl_screen_destroy_drm_lease_device(data, wp_drm_lease_device_v1); +} + +static void +drm_lease_device_handle_done(void *data, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + /* This space is deliberately left blank */ +} + +static const struct wp_drm_lease_device_v1_listener drm_lease_device_listener = { + .drm_fd = drm_lease_device_handle_drm_fd, + .connector = drm_lease_device_handle_connector, + .released = drm_lease_device_handle_released, + .done = drm_lease_device_handle_done, +}; + +void +xwl_screen_add_drm_lease_device(struct xwl_screen *xwl_screen, uint32_t id) +{ + struct wp_drm_lease_device_v1 *lease_device = wl_registry_bind( + xwl_screen->registry, id, &wp_drm_lease_device_v1_interface, 1); + struct xwl_drm_lease_device *device_data = malloc(sizeof(struct xwl_drm_lease_device)); + + device_data->drm_lease_device = lease_device; + device_data->xwl_screen = xwl_screen; + device_data->drm_read_only_fd = -1; + device_data->id = id; + xorg_list_add(&device_data->link, &xwl_screen->drm_lease_devices); + wp_drm_lease_device_v1_add_listener(lease_device, + &drm_lease_device_listener, + device_data); +} + +void +xwl_screen_destroy_drm_lease_device(struct xwl_screen *xwl_screen, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + struct xwl_drm_lease_device *device_data; + + xorg_list_for_each_entry(device_data, &xwl_screen->drm_lease_devices, link) { + if (device_data->drm_lease_device == wp_drm_lease_device_v1) { + wp_drm_lease_device_v1_destroy(wp_drm_lease_device_v1); + xorg_list_del(&device_data->link); + if (device_data->drm_read_only_fd >= 0) + close(device_data->drm_read_only_fd); + free(device_data); + return; + } + } +} diff --git a/hw/xwayland/xwayland-drm-lease.h b/hw/xwayland/xwayland-drm-lease.h new file mode 100644 index 000000000..aa5aed63c --- /dev/null +++ b/hw/xwayland/xwayland-drm-lease.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2020 Drew Devault + * Copyright © 2021 Xaver Hugl + * + * 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. + */ + +#ifndef XWAYLAND_DRM_LEASE_H +#define XWAYLAND_DRM_LEASE_H + +#include <X11/Xatom.h> +#include <randrstr.h> + +#include "xwayland-types.h" +#include "list.h" + +#include "drm-lease-v1-client-protocol.h" + +struct xwl_drm_lease_device { + struct xorg_list link; + struct wp_drm_lease_device_v1 *drm_lease_device; + int drm_read_only_fd; + struct xwl_screen *xwl_screen; + uint32_t id; +}; + +struct xwl_queued_drm_lease_device { + struct xorg_list link; + uint32_t id; +}; + +struct xwl_drm_lease { + struct xorg_list link; + struct wp_drm_lease_v1 *lease; + RRLeasePtr rrLease; + ClientPtr client; + int fd; +}; + +int xwl_randr_request_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr rrLease); +void xwl_randr_get_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr *rrLease, int *fd); +void xwl_randr_terminate_lease(ScreenPtr screen, RRLeasePtr lease); + +void xwl_screen_add_drm_lease_device(struct xwl_screen *xwl_screen, uint32_t id); +void xwl_screen_destroy_drm_lease_device(struct xwl_screen *xwl_screen, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1); + +#endif /* XWAYLAND_DRM_LEASE_H */ diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 1f22c4cf6..d2fa4e0bb 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -35,13 +35,6 @@ #include "xdg-output-unstable-v1-client-protocol.h" -#define ALL_ROTATIONS (RR_Rotate_0 | \ - RR_Rotate_90 | \ - RR_Rotate_180 | \ - RR_Rotate_270 | \ - RR_Reflect_X | \ - RR_Reflect_Y) - static void xwl_output_get_xdg_output(struct xwl_output *xwl_output); static Rotation @@ -731,7 +724,6 @@ struct xwl_output * xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id) { struct xwl_output *xwl_output; - static int serial; char name[256]; xwl_output = calloc(1, sizeof *xwl_output); @@ -750,7 +742,7 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id) xwl_output->server_output_id = id; wl_output_add_listener(xwl_output->output, &output_listener, xwl_output); - snprintf(name, sizeof name, "XWAYLAND%d", serial++); + snprintf(name, sizeof name, "XWAYLAND%d", xwl_get_next_output_serial()); xwl_output->xwl_screen = xwl_screen; xwl_output->randr_crtc = RRCrtcCreate(xwl_screen->screen, xwl_output); @@ -795,9 +787,12 @@ err: void xwl_output_destroy(struct xwl_output *xwl_output) { + if (xwl_output->lease_connector) + wp_drm_lease_connector_v1_destroy(xwl_output->lease_connector); if (xwl_output->xdg_output) zxdg_output_v1_destroy(xwl_output->xdg_output); - wl_output_destroy(xwl_output->output); + if (xwl_output->output) + wl_output_destroy(xwl_output->output); free(xwl_output); } @@ -946,6 +941,10 @@ xwl_screen_init_output(struct xwl_screen *xwl_screen) rp->rrModeDestroy = xwl_randr_mode_destroy; #endif + rp->rrRequestLease = xwl_randr_request_lease; + rp->rrGetLease = xwl_randr_get_lease; + rp->rrTerminateLease = xwl_randr_terminate_lease; + return TRUE; } @@ -954,6 +953,12 @@ xwl_output_get_xdg_output(struct xwl_output *xwl_output) { struct xwl_screen *xwl_screen = xwl_output->xwl_screen; + if (!xwl_output->output) { + /* This can happen when an output is created from a leasable DRM + * connector */ + return; + } + xwl_output->xdg_output = zxdg_output_manager_v1_get_xdg_output (xwl_screen->xdg_output_manager, xwl_output->output); @@ -973,3 +978,10 @@ xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen) xorg_list_for_each_entry(it, &xwl_screen->output_list, link) xwl_output_get_xdg_output(it); } + +int +xwl_get_next_output_serial(void) +{ + static int output_name_serial = 0; + return output_name_serial++; +} diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h index 02b983108..74a46994f 100644 --- a/hw/xwayland/xwayland-output.h +++ b/hw/xwayland/xwayland-output.h @@ -34,19 +34,34 @@ #include <randrstr.h> #include "xwayland-types.h" +#include "xwayland-drm-lease.h" + +#define ALL_ROTATIONS (RR_Rotate_0 | \ + RR_Rotate_90 | \ + RR_Rotate_180 | \ + RR_Rotate_270 | \ + RR_Reflect_X | \ + RR_Reflect_Y) struct xwl_output { struct xorg_list link; - struct wl_output *output; - struct zxdg_output_v1 *xdg_output; - uint32_t server_output_id; struct xwl_screen *xwl_screen; RROutputPtr randr_output; RRCrtcPtr randr_crtc; + + /* only for regular outputs */ + struct wl_output *output; + struct zxdg_output_v1 *xdg_output; + uint32_t server_output_id; int32_t x, y, width, height, refresh; Rotation rotation; Bool wl_output_done; Bool xdg_output_done; + + /* only for lease-able DRM connectors */ + struct wp_drm_lease_connector_v1 *lease_connector; + struct xwl_drm_lease *lease; + struct xwl_drm_lease_device *lease_device; }; /* Per client per output emulated randr/vidmode resolution info. */ @@ -79,4 +94,6 @@ void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen, void xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen); +int xwl_get_next_output_serial(void); + #endif /* XWAYLAND_OUTPUT_H */ diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c index b39a3d2fd..b249dbb08 100644 --- a/hw/xwayland/xwayland-screen.c +++ b/hw/xwayland/xwayland-screen.c @@ -149,6 +149,24 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure, xwl_window_update_property(xwl_window, rec); } +static void +xwl_root_window_finalized_callback(CallbackListPtr *pcbl, + void *closure, + void *calldata) +{ + ScreenPtr screen = closure; + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + struct xwl_queued_drm_lease_device *queued_device, *next; + + xorg_list_for_each_entry_safe(queued_device, next, + &xwl_screen->queued_drm_lease_devices, link) { + xwl_screen_add_drm_lease_device(xwl_screen, queued_device->id); + xorg_list_del(&queued_device->link); + free(queued_device); + } + DeleteCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, screen); +} + Bool xwl_close_screen(ScreenPtr screen) { @@ -168,6 +186,12 @@ xwl_close_screen(ScreenPtr screen) xwl_screen_release_tablet_manager(xwl_screen); + struct xwl_drm_lease_device *device_data, *next; + xorg_list_for_each_entry_safe(device_data, next, + &xwl_screen->drm_lease_devices, link) + xwl_screen_destroy_drm_lease_device(xwl_screen, + device_data->drm_lease_device); + RemoveNotifyFd(xwl_screen->wayland_fd); wl_display_disconnect(xwl_screen->display); @@ -392,6 +416,15 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, version); xwl_screen_init_xdg_output(xwl_screen); } + else if (strcmp(interface, "wp_drm_lease_device_v1") == 0) { + if (xwl_screen->screen->root == NULL) { + struct xwl_queued_drm_lease_device *queued = malloc(sizeof(struct xwl_queued_drm_lease_device)); + queued->id = id; + xorg_list_append(&queued->link, &xwl_screen->queued_drm_lease_devices); + } else { + xwl_screen_add_drm_lease_device(xwl_screen, id); + } + } else if (strcmp(interface, "wp_viewporter") == 0) { xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1); } @@ -408,6 +441,7 @@ global_remove(void *data, struct wl_registry *registry, uint32_t name) { struct xwl_screen *xwl_screen = data; struct xwl_output *xwl_output, *tmp_xwl_output; + struct xwl_drm_lease_device *lease_device, *tmp_lease_device; xorg_list_for_each_entry_safe(xwl_output, tmp_xwl_output, &xwl_screen->output_list, link) { @@ -416,6 +450,14 @@ global_remove(void *data, struct wl_registry *registry, uint32_t name) break; } } + + xorg_list_for_each_entry_safe(lease_device, tmp_lease_device, + &xwl_screen->drm_lease_devices, link) { + if (lease_device->id == name) { + wp_drm_lease_device_v1_release(lease_device->drm_lease_device); + break; + } + } } static const struct wl_registry_listener registry_listener = { @@ -619,6 +661,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) xorg_list_init(&xwl_screen->seat_list); xorg_list_init(&xwl_screen->damage_window_list); xorg_list_init(&xwl_screen->window_list); + xorg_list_init(&xwl_screen->drm_lease_devices); + xorg_list_init(&xwl_screen->queued_drm_lease_devices); + xorg_list_init(&xwl_screen->drm_leases); xwl_screen->depth = 24; if (!monitorResolution) @@ -744,6 +789,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) return FALSE; AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen); + AddCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, pScreen); xwl_screen_roundtrip(xwl_screen); diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h index 137e94b55..f04d431c7 100644 --- a/hw/xwayland/xwayland-screen.h +++ b/hw/xwayland/xwayland-screen.h @@ -36,6 +36,7 @@ #include "xwayland-types.h" #include "xwayland-output.h" #include "xwayland-glamor.h" +#include "xwayland-drm-lease.h" struct xwl_format { uint32_t format; @@ -87,6 +88,9 @@ struct xwl_screen { struct zwp_linux_dmabuf_v1 *dmabuf; struct zxdg_output_manager_v1 *xdg_output_manager; struct wp_viewporter *viewporter; + struct xorg_list drm_lease_devices; + struct xorg_list queued_drm_lease_devices; + struct xorg_list drm_leases; uint32_t serial; #define XWL_FORMAT_ARGB8888 (1 << 0) diff --git a/hw/xwayland/xwayland-types.h b/hw/xwayland/xwayland-types.h index da80ff98e..e70e56320 100644 --- a/hw/xwayland/xwayland-types.h +++ b/hw/xwayland/xwayland-types.h @@ -30,5 +30,6 @@ struct xwl_pixmap; struct xwl_window; struct xwl_screen; struct xwl_egl_backend; +struct xwl_drm_lease; #endif /* XWAYLAND_TYPES_H */ |