60d89ef1d9304427a1289174d9a311ab06e39b44 — Drew DeVault 4 months ago 7f065bc
Replace XCB DRM leasing with Wayland DRM leasing
M Makefile.am => Makefile.am +5 -4
@@ 23,10 23,10 @@
 
 bin_PROGRAMS = kmscube
 
-CFLAGS=-O0 -g
+CFLAGS=-O0 -g -Wno-unused-parameter
 
 kmscube_LDADD = \
-	$(XCB_LIBS) \
+	$(WAYLAND_LIBS) \
 	$(DRM_LIBS) \
 	$(GBM_LIBS) \
 	$(EGL_LIBS) \


@@ 37,7 37,7 @@
 kmscube_CFLAGS = \
 	-O0 -g \
 	-Wall -Wextra \
-	$(XCB_CFLAGS) \
+	$(WAYLAND_CFLAGS) \
 	$(DRM_CFLAGS) \
 	$(GBM_CFLAGS) \
 	$(EGL_CFLAGS) \


@@ 56,4 56,5 @@
 	esUtil.h \
 	frame-512x512-NV12.c \
 	frame-512x512-RGBA.c \
-	kmscube.c
+	kmscube.c \
+	drm-lease-protocol.c

M configure.ac => configure.ac +1 -1
@@ 39,7 39,7 @@
 PKG_CHECK_MODULES(GBM, gbm)
 PKG_CHECK_MODULES(EGL, egl)
 PKG_CHECK_MODULES(GLES2, glesv2)
-PKG_CHECK_MODULES(XCB, xcb-randr xcb)
+PKG_CHECK_MODULES(WAYLAND, wayland-client)
 
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT

M drm-common.c => drm-common.c +65 -36
@@ 93,22 93,22 @@
 
 static int leased(int fd, int nfd, int id)
 {
-        if (fd != nfd && nfd != -1) {
-                drmModeObjectListPtr    lease = drmModeGetLease(nfd);
-                int ret = 0;
-
-                if (lease) {
-                        uint32_t        u;
-                        for (u = 0; u < lease->count; u++)
-                                if (lease->objects[u] == (uint32_t) id) {
-                                        ret = 1;
-                                        break;
-                                }
-                        free(lease);
-                        return ret;
-                }
-        }
-        return 0;
+	if (fd != nfd && nfd != -1) {
+		drmModeObjectListPtr    lease = drmModeGetLease(nfd);
+		int ret = 0;
+
+		if (lease) {
+			uint32_t	u;
+			for (u = 0; u < lease->count; u++)
+				if (lease->objects[u] == (uint32_t) id) {
+					ret = 1;
+					break;
+				}
+			free(lease);
+			return ret;
+		}
+	}
+	return 0;
 }
 
 static uint32_t find_crtc_for_connector(int fd, int nfd, const struct drm *drm, const drmModeRes *resources,


@@ 138,7 138,7 @@
 	drmModeRes *resources;
 	drmModeConnector *connector = NULL;
 	drmModeEncoder *encoder = NULL;
-	int i;
+	int i, crtc_i = -1;
 
 	resources = drmModeGetResources(fd);
 	if (!resources) {


@@ 150,9 150,9 @@
 	for (i = 0; i < resources->count_connectors; i++) {
 		connector = drmModeGetConnector(fd, resources->connectors[i]);
 		if (connector->connection == DRM_MODE_CONNECTED && !leased(fd, nfd, connector->connector_id)) {
-                        printf("connector id %u\n", connector->connector_id);
+			printf("connector id %u\n", connector->connector_id);
 			/* it's connected, let's use this! */
-                        drm_resources->connector = connector->connector_id;
+			drm_resources->connector = connector->connector_id;
 			break;
 		}
 		drmModeFreeConnector(connector);


@@ 177,31 177,60 @@
 	}
 
 	if (encoder) {
-                drm_resources->encoder = encoder->encoder_id;
-                drm_resources->crtc = encoder->crtc_id;
+		drm_resources->encoder = encoder->encoder_id;
+		drm_resources->crtc = encoder->crtc_id;
 	} else {
-                uint32_t crtc_id;
-                for (i = 0; i < connector->count_encoders; i++) {
-                        const uint32_t encoder_id = connector->encoders[i];
-                        drmModeEncoder *encoder = drmModeGetEncoder(fd, encoder_id);
-
-                        if (encoder && !leased(fd, nfd, encoder->encoder_id)) {
-                                crtc_id = find_crtc_for_encoder(resources, encoder);
-
-                                if (crtc_id != 0)
-                                        break;
-                                drmModeFreeEncoder(encoder);
-                        }
-                }
+		uint32_t crtc_id;
+		for (i = 0; i < connector->count_encoders; i++) {
+			const uint32_t encoder_id = connector->encoders[i];
+			drmModeEncoder *encoder = drmModeGetEncoder(fd, encoder_id);
+
+			if (encoder && !leased(fd, nfd, encoder->encoder_id)) {
+				crtc_id = find_crtc_for_encoder(resources, encoder);
+
+				if (crtc_id != 0) {
+					break;
+				}
+				drmModeFreeEncoder(encoder);
+			}
+		}
 
 		if (crtc_id == 0) {
 			printf("no crtc found!\n");
 			return -1;
 		}
 
-                drm_resources->crtc = crtc_id;
+		drm_resources->crtc = crtc_id;
+	}
+	for (i = 0; i < resources->count_crtcs; i++) {
+		if (resources->crtcs[i] == drm_resources->crtc) {
+			crtc_i = i;
+			break;
+		}
+	}
+
+	drmModePlaneRes *plane_res = drmModeGetPlaneResources(fd);
+	if (!plane_res) {
+		printf("no planes!\n");
+		return -1;
+	}
+
+	for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
+		uint32_t id = plane_res->planes[i];
+		drmModePlane *plane = drmModeGetPlane(fd, id);
+		printf("plane %d possible CRTCs: %x (need %d)\n",
+				id, plane->possible_crtcs, crtc_i);
+		if (((1 << crtc_i) & plane->possible_crtcs)) {
+			printf("plane %d is compatible with crtc %d\n",
+					id, drm_resources->crtc);
+			drm_resources->plane = id;
+			break;
+		}
+		drmModeFreePlane(plane);
 	}
 
+	drmModeFreePlaneResources(plane_res);
+
 	drmModeFreeResources(resources);
 
 	return 0;


@@ 226,7 255,7 @@
 	for (i = 0; i < resources->count_connectors; i++) {
 		connector = drmModeGetConnector(drm->fd, resources->connectors[i]);
 		if (!leased(fd, nfd, connector->connector_id) && connector->connection == DRM_MODE_CONNECTED) {
-                        printf("connector id %u\n", connector->connector_id);
+			printf("connector id %u\n", connector->connector_id);
 			/* it's connected, let's use this! */
 			break;
 		}

M drm-common.h => drm-common.h +1 -0
@@ 81,6 81,7 @@
     uint32_t    encoder;
     uint32_t    connector;
     uint32_t    crtc;
+    uint32_t    plane;
 };
 
 int find_drm(struct drm_resources *drm_resources, int fd, int nfd);

A drm-lease-protocol.c => drm-lease-protocol.c +112 -0
@@ 0,0 1,112 @@
+/* Generated by wayland-scanner 1.17.0 */
+
+/*
+ * Copyright © 2018 NXP
+ * Copyright © 2019 Status Research & Development GmbH.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0  /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface zwp_drm_lease_connector_v1_interface;
+extern const struct wl_interface zwp_drm_lease_request_v1_interface;
+extern const struct wl_interface zwp_drm_lease_v1_interface;
+
+static const struct wl_interface *types[] = {
+	NULL,
+	&zwp_drm_lease_request_v1_interface,
+	&zwp_drm_lease_connector_v1_interface,
+	&zwp_drm_lease_connector_v1_interface,
+	&zwp_drm_lease_v1_interface,
+};
+
+static const struct wl_message zwp_drm_lease_manager_v1_requests[] = {
+	{ "create_lease_request", "n", types + 1 },
+	{ "stop", "", types + 0 },
+};
+
+static const struct wl_message zwp_drm_lease_manager_v1_events[] = {
+	{ "connector", "n", types + 2 },
+	{ "finished", "", types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_drm_lease_manager_v1_interface = {
+	"zwp_drm_lease_manager_v1", 1,
+	2, zwp_drm_lease_manager_v1_requests,
+	2, zwp_drm_lease_manager_v1_events,
+};
+
+static const struct wl_message zwp_drm_lease_connector_v1_requests[] = {
+	{ "destroy", "", types + 0 },
+};
+
+static const struct wl_message zwp_drm_lease_connector_v1_events[] = {
+	{ "name", "s", types + 0 },
+	{ "description", "s", types + 0 },
+	{ "edid", "a", types + 0 },
+	{ "withdrawn", "", types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_drm_lease_connector_v1_interface = {
+	"zwp_drm_lease_connector_v1", 1,
+	1, zwp_drm_lease_connector_v1_requests,
+	4, zwp_drm_lease_connector_v1_events,
+};
+
+static const struct wl_message zwp_drm_lease_request_v1_requests[] = {
+	{ "destroy", "", types + 0 },
+	{ "request_connector", "o", types + 3 },
+	{ "submit", "n", types + 4 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_drm_lease_request_v1_interface = {
+	"zwp_drm_lease_request_v1", 1,
+	3, zwp_drm_lease_request_v1_requests,
+	0, NULL,
+};
+
+static const struct wl_message zwp_drm_lease_v1_requests[] = {
+	{ "destroy", "", types + 0 },
+};
+
+static const struct wl_message zwp_drm_lease_v1_events[] = {
+	{ "lease_fd", "h", types + 0 },
+	{ "finished", "", types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwp_drm_lease_v1_interface = {
+	"zwp_drm_lease_v1", 1,
+	1, zwp_drm_lease_v1_requests,
+	2, zwp_drm_lease_v1_events,
+};
+

A drm-lease-protocol.h => drm-lease-protocol.h +618 -0
@@ 0,0 1,618 @@
+/* Generated by wayland-scanner 1.17.0 */
+
+#ifndef DRM_LEASE_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define DRM_LEASE_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_drm_lease_unstable_v1 The drm_lease_unstable_v1 protocol
+ * @section page_ifaces_drm_lease_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_drm_lease_manager_v1 - lease manager
+ * - @subpage page_iface_zwp_drm_lease_connector_v1 - a leasable DRM connector
+ * - @subpage page_iface_zwp_drm_lease_request_v1 - DRM lease request
+ * - @subpage page_iface_zwp_drm_lease_v1 - a DRM lease
+ * @section page_copyright_drm_lease_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2018 NXP
+ * Copyright © 2019 Status Research & Development GmbH.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct zwp_drm_lease_connector_v1;
+struct zwp_drm_lease_manager_v1;
+struct zwp_drm_lease_request_v1;
+struct zwp_drm_lease_v1;
+
+/**
+ * @page page_iface_zwp_drm_lease_manager_v1 zwp_drm_lease_manager_v1
+ * @section page_iface_zwp_drm_lease_manager_v1_desc Description
+ *
+ * This protocol is used by Wayland compositors which act as Direct
+ * Renderering Manager (DRM) masters to lease DRM resources to Wayland
+ * clients. Once leased, the compositor will not use the leased resources
+ * until the lease is revoked or the client closes the file descriptor.
+ *
+ * The lease manager is used to advertise connectors which are available for
+ * leasing, and by the client to negotiate a lease request.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ * @section page_iface_zwp_drm_lease_manager_v1_api API
+ * See @ref iface_zwp_drm_lease_manager_v1.
+ */
+/**
+ * @defgroup iface_zwp_drm_lease_manager_v1 The zwp_drm_lease_manager_v1 interface
+ *
+ * This protocol is used by Wayland compositors which act as Direct
+ * Renderering Manager (DRM) masters to lease DRM resources to Wayland
+ * clients. Once leased, the compositor will not use the leased resources
+ * until the lease is revoked or the client closes the file descriptor.
+ *
+ * The lease manager is used to advertise connectors which are available for
+ * leasing, and by the client to negotiate a lease request.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible changes
+ * may be added together with the corresponding interface version bump.
+ * Backward incompatible changes are done by bumping the version number in
+ * the protocol and interface names and resetting the interface version.
+ * Once the protocol is to be declared stable, the 'z' prefix and the
+ * version number in the protocol and interface names are removed and the
+ * interface version number is reset.
+ */
+extern const struct wl_interface zwp_drm_lease_manager_v1_interface;
+/**
+ * @page page_iface_zwp_drm_lease_connector_v1 zwp_drm_lease_connector_v1
+ * @section page_iface_zwp_drm_lease_connector_v1_desc Description
+ *
+ * Represents a DRM connector which is available for lease. These objects are
+ * created via zwp_drm_lease_manager_v1.connector, and should be passed into
+ * lease requests via zwp_drm_lease_request_v1.add_connector.
+ * @section page_iface_zwp_drm_lease_connector_v1_api API
+ * See @ref iface_zwp_drm_lease_connector_v1.
+ */
+/**
+ * @defgroup iface_zwp_drm_lease_connector_v1 The zwp_drm_lease_connector_v1 interface
+ *
+ * Represents a DRM connector which is available for lease. These objects are
+ * created via zwp_drm_lease_manager_v1.connector, and should be passed into
+ * lease requests via zwp_drm_lease_request_v1.add_connector.
+ */
+extern const struct wl_interface zwp_drm_lease_connector_v1_interface;
+/**
+ * @page page_iface_zwp_drm_lease_request_v1 zwp_drm_lease_request_v1
+ * @section page_iface_zwp_drm_lease_request_v1_desc Description
+ *
+ * A client that wishes to lease DRM resources will attach the list of
+ * connectors advertised with zwp_drm_lease_manager_v1.connector that they
+ * wish to lease, then use zwp_drm_lease_request_v1.submit to submit the
+ * request.
+ * @section page_iface_zwp_drm_lease_request_v1_api API
+ * See @ref iface_zwp_drm_lease_request_v1.
+ */
+/**
+ * @defgroup iface_zwp_drm_lease_request_v1 The zwp_drm_lease_request_v1 interface
+ *
+ * A client that wishes to lease DRM resources will attach the list of
+ * connectors advertised with zwp_drm_lease_manager_v1.connector that they
+ * wish to lease, then use zwp_drm_lease_request_v1.submit to submit the
+ * request.
+ */
+extern const struct wl_interface zwp_drm_lease_request_v1_interface;
+/**
+ * @page page_iface_zwp_drm_lease_v1 zwp_drm_lease_v1
+ * @section page_iface_zwp_drm_lease_v1_desc Description
+ *
+ * A DRM lease object is used to transfer the DRM file descriptor to the
+ * client and manage the lifetime of the lease.
+ * @section page_iface_zwp_drm_lease_v1_api API
+ * See @ref iface_zwp_drm_lease_v1.
+ */
+/**
+ * @defgroup iface_zwp_drm_lease_v1 The zwp_drm_lease_v1 interface
+ *
+ * A DRM lease object is used to transfer the DRM file descriptor to the
+ * client and manage the lifetime of the lease.
+ */
+extern const struct wl_interface zwp_drm_lease_v1_interface;
+
+/**
+ * @ingroup iface_zwp_drm_lease_manager_v1
+ * @struct zwp_drm_lease_manager_v1_listener
+ */
+struct zwp_drm_lease_manager_v1_listener {
+	/**
+	 * advertise connectors available for leases
+	 *
+	 * The compositor may choose to advertise 0 or more connectors
+	 * which may be leased to clients, and will use this event to do
+	 * so. This object may be passed into a lease request to lease that
+	 * connector. See zwp_drm_lease_request_v1.add_connector for
+	 * details.
+	 *
+	 * When this global is bound, the compositor will send all
+	 * connectors available for lease, but may send additional
+	 * connectors at any time.
+	 */
+	void (*connector)(void *data,
+			  struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1,
+			  struct zwp_drm_lease_connector_v1 *id);
+	/**
+	 * the compositor has finished using the manager
+	 *
+	 * This event indicates that the compositor is done sending
+	 * connector events. The compositor will destroy this object
+	 * immediately after sending this event, and it will become
+	 * invalid. The client should release any resources associated with
+	 * this manager after receiving this event.
+	 */
+	void (*finished)(void *data,
+			 struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1);
+};
+
+/**
+ * @ingroup iface_zwp_drm_lease_manager_v1
+ */
+static inline int
+zwp_drm_lease_manager_v1_add_listener(struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1,
+				      const struct zwp_drm_lease_manager_v1_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) zwp_drm_lease_manager_v1,
+				     (void (**)(void)) listener, data);
+}
+
+#define ZWP_DRM_LEASE_MANAGER_V1_CREATE_LEASE_REQUEST 0
+#define ZWP_DRM_LEASE_MANAGER_V1_STOP 1
+
+/**
+ * @ingroup iface_zwp_drm_lease_manager_v1
+ */
+#define ZWP_DRM_LEASE_MANAGER_V1_CONNECTOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_drm_lease_manager_v1
+ */
+#define ZWP_DRM_LEASE_MANAGER_V1_FINISHED_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_drm_lease_manager_v1
+ */
+#define ZWP_DRM_LEASE_MANAGER_V1_CREATE_LEASE_REQUEST_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_drm_lease_manager_v1
+ */
+#define ZWP_DRM_LEASE_MANAGER_V1_STOP_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_drm_lease_manager_v1 */
+static inline void
+zwp_drm_lease_manager_v1_set_user_data(struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) zwp_drm_lease_manager_v1, user_data);
+}
+
+/** @ingroup iface_zwp_drm_lease_manager_v1 */
+static inline void *
+zwp_drm_lease_manager_v1_get_user_data(struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) zwp_drm_lease_manager_v1);
+}
+
+static inline uint32_t
+zwp_drm_lease_manager_v1_get_version(struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zwp_drm_lease_manager_v1);
+}
+
+/** @ingroup iface_zwp_drm_lease_manager_v1 */
+static inline void
+zwp_drm_lease_manager_v1_destroy(struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1)
+{
+	wl_proxy_destroy((struct wl_proxy *) zwp_drm_lease_manager_v1);
+}
+
+/**
+ * @ingroup iface_zwp_drm_lease_manager_v1
+ *
+ * Creates a lease request object.
+ *
+ * See the documentation for zwp_drm_lease_request_v1 for details.
+ */
+static inline struct zwp_drm_lease_request_v1 *
+zwp_drm_lease_manager_v1_create_lease_request(struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_drm_lease_manager_v1,
+			 ZWP_DRM_LEASE_MANAGER_V1_CREATE_LEASE_REQUEST, &zwp_drm_lease_request_v1_interface, NULL);
+
+	return (struct zwp_drm_lease_request_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zwp_drm_lease_manager_v1
+ *
+ * Indicates the client no longer wishes to receive connector events. The
+ * compositor may still send connector events until it sends the finish
+ * event, however.
+ *
+ * The client must not send any requests after this one.
+ */
+static inline void
+zwp_drm_lease_manager_v1_stop(struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1)
+{
+	wl_proxy_marshal((struct wl_proxy *) zwp_drm_lease_manager_v1,
+			 ZWP_DRM_LEASE_MANAGER_V1_STOP);
+}
+
+/**
+ * @ingroup iface_zwp_drm_lease_connector_v1
+ * @struct zwp_drm_lease_connector_v1_listener
+ */
+struct zwp_drm_lease_connector_v1_listener {
+	/**
+	 * name
+	 *
+	 * The compositor sends this event once the connector is created
+	 * to indicate the name of this connector. This will not change for
+	 * the duration of the Wayland session, but is not guaranteed to be
+	 * consistent between sessions.
+	 *
+	 * If the compositor also supports zxdg_output_manager_v1 and this
+	 * connector corresponds to a zxdg_output_v1, this name will match
+	 * the name of this zxdg_output_v1 object.
+	 * @param name connector name
+	 */
+	void (*name)(void *data,
+		     struct zwp_drm_lease_connector_v1 *zwp_drm_lease_connector_v1,
+		     const char *name);
+	/**
+	 * description
+	 *
+	 * The compositor sends this event once the connector is created
+	 * to provide a human-readable description for this connector,
+	 * which may be presented to the user. This will not change for the
+	 * duration of the Wayland session, but is not guaranteed to be
+	 * consistent between sessions.
+	 *
+	 * If the compositor also supports zxdg_output_manager_v1 and this
+	 * connector corresponds to a zxdg_output_v1, this description will
+	 * match the description of this zxdg_output_v1 object.
+	 * @param name connector name
+	 */
+	void (*description)(void *data,
+			    struct zwp_drm_lease_connector_v1 *zwp_drm_lease_connector_v1,
+			    const char *name);
+	/**
+	 * edid
+	 *
+	 * The compositor sends this event once the connector is created
+	 * to inform the client of this connector's EDID, to assist in
+	 * selecting the correct connectors for lease. The EDID is supplied
+	 * as an array of unsigned 8-bit integers.
+	 * @param edid EDID for this connector
+	 */
+	void (*edid)(void *data,
+		     struct zwp_drm_lease_connector_v1 *zwp_drm_lease_connector_v1,
+		     struct wl_array *edid);
+	/**
+	 * lease offer withdrawn
+	 *
+	 * Sent to indicate that the compositor will no longer honor
+	 * requests for DRM leases which include this connector. The client
+	 * may still issue a lease request including this connector, but
+	 * the compositor will send zwp_drm_lease_v1.finished without
+	 * issuing a lease fd.
+	 */
+	void (*withdrawn)(void *data,
+			  struct zwp_drm_lease_connector_v1 *zwp_drm_lease_connector_v1);
+};
+
+/**
+ * @ingroup iface_zwp_drm_lease_connector_v1
+ */
+static inline int
+zwp_drm_lease_connector_v1_add_listener(struct zwp_drm_lease_connector_v1 *zwp_drm_lease_connector_v1,
+					const struct zwp_drm_lease_connector_v1_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) zwp_drm_lease_connector_v1,
+				     (void (**)(void)) listener, data);
+}
+
+#define ZWP_DRM_LEASE_CONNECTOR_V1_DESTROY 0
+
+/**
+ * @ingroup iface_zwp_drm_lease_connector_v1
+ */
+#define ZWP_DRM_LEASE_CONNECTOR_V1_NAME_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_drm_lease_connector_v1
+ */
+#define ZWP_DRM_LEASE_CONNECTOR_V1_DESCRIPTION_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_drm_lease_connector_v1
+ */
+#define ZWP_DRM_LEASE_CONNECTOR_V1_EDID_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_drm_lease_connector_v1
+ */
+#define ZWP_DRM_LEASE_CONNECTOR_V1_WITHDRAWN_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_drm_lease_connector_v1
+ */
+#define ZWP_DRM_LEASE_CONNECTOR_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_drm_lease_connector_v1 */
+static inline void
+zwp_drm_lease_connector_v1_set_user_data(struct zwp_drm_lease_connector_v1 *zwp_drm_lease_connector_v1, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) zwp_drm_lease_connector_v1, user_data);
+}
+
+/** @ingroup iface_zwp_drm_lease_connector_v1 */
+static inline void *
+zwp_drm_lease_connector_v1_get_user_data(struct zwp_drm_lease_connector_v1 *zwp_drm_lease_connector_v1)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) zwp_drm_lease_connector_v1);
+}
+
+static inline uint32_t
+zwp_drm_lease_connector_v1_get_version(struct zwp_drm_lease_connector_v1 *zwp_drm_lease_connector_v1)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zwp_drm_lease_connector_v1);
+}
+
+/**
+ * @ingroup iface_zwp_drm_lease_connector_v1
+ *
+ * The client may send this request to indicate that it will not issue a
+ * lease request for this connector. Clients are encouraged to send this
+ * after receiving the "withdrawn" request so that the server can release
+ * the resources associated with this connector offer.
+ */
+static inline void
+zwp_drm_lease_connector_v1_destroy(struct zwp_drm_lease_connector_v1 *zwp_drm_lease_connector_v1)
+{
+	wl_proxy_marshal((struct wl_proxy *) zwp_drm_lease_connector_v1,
+			 ZWP_DRM_LEASE_CONNECTOR_V1_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) zwp_drm_lease_connector_v1);
+}
+
+#ifndef ZWP_DRM_LEASE_REQUEST_V1_ERROR_ENUM
+#define ZWP_DRM_LEASE_REQUEST_V1_ERROR_ENUM
+enum zwp_drm_lease_request_v1_error {
+	/**
+	 * request submitted with zero connectors
+	 */
+	ZWP_DRM_LEASE_REQUEST_V1_ERROR_NO_CONNECTORS = 0,
+	/**
+	 * attempted to reuse a submitted lease
+	 */
+	ZWP_DRM_LEASE_REQUEST_V1_ERROR_SUBMITTED_LEASE = 1,
+};
+#endif /* ZWP_DRM_LEASE_REQUEST_V1_ERROR_ENUM */
+
+#define ZWP_DRM_LEASE_REQUEST_V1_DESTROY 0
+#define ZWP_DRM_LEASE_REQUEST_V1_REQUEST_CONNECTOR 1
+#define ZWP_DRM_LEASE_REQUEST_V1_SUBMIT 2
+
+
+/**
+ * @ingroup iface_zwp_drm_lease_request_v1
+ */
+#define ZWP_DRM_LEASE_REQUEST_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_drm_lease_request_v1
+ */
+#define ZWP_DRM_LEASE_REQUEST_V1_REQUEST_CONNECTOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_drm_lease_request_v1
+ */
+#define ZWP_DRM_LEASE_REQUEST_V1_SUBMIT_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_drm_lease_request_v1 */
+static inline void
+zwp_drm_lease_request_v1_set_user_data(struct zwp_drm_lease_request_v1 *zwp_drm_lease_request_v1, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) zwp_drm_lease_request_v1, user_data);
+}
+
+/** @ingroup iface_zwp_drm_lease_request_v1 */
+static inline void *
+zwp_drm_lease_request_v1_get_user_data(struct zwp_drm_lease_request_v1 *zwp_drm_lease_request_v1)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) zwp_drm_lease_request_v1);
+}
+
+static inline uint32_t
+zwp_drm_lease_request_v1_get_version(struct zwp_drm_lease_request_v1 *zwp_drm_lease_request_v1)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zwp_drm_lease_request_v1);
+}
+
+/**
+ * @ingroup iface_zwp_drm_lease_request_v1
+ *
+ * Indicates that the client will no longer use this lease request.
+ */
+static inline void
+zwp_drm_lease_request_v1_destroy(struct zwp_drm_lease_request_v1 *zwp_drm_lease_request_v1)
+{
+	wl_proxy_marshal((struct wl_proxy *) zwp_drm_lease_request_v1,
+			 ZWP_DRM_LEASE_REQUEST_V1_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) zwp_drm_lease_request_v1);
+}
+
+/**
+ * @ingroup iface_zwp_drm_lease_request_v1
+ *
+ * Indicates that the client would like to lease the given connector.
+ * This is only used as a suggestion, the compositor may choose to
+ * include any resources in the lease it issues, or change the set of
+ * leased resources at any time.
+ */
+static inline void
+zwp_drm_lease_request_v1_request_connector(struct zwp_drm_lease_request_v1 *zwp_drm_lease_request_v1, struct zwp_drm_lease_connector_v1 *connector)
+{
+	wl_proxy_marshal((struct wl_proxy *) zwp_drm_lease_request_v1,
+			 ZWP_DRM_LEASE_REQUEST_V1_REQUEST_CONNECTOR, connector);
+}
+
+/**
+ * @ingroup iface_zwp_drm_lease_request_v1
+ *
+ * Submits the lease request and creates a new zwp_drm_lease_v1 object.
+ * After calling submit, issuing any other request than destroy is a
+ * protocol error. Submitting a lease request with no connectors is a
+ * protocol error.
+ */
+static inline struct zwp_drm_lease_v1 *
+zwp_drm_lease_request_v1_submit(struct zwp_drm_lease_request_v1 *zwp_drm_lease_request_v1)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_drm_lease_request_v1,
+			 ZWP_DRM_LEASE_REQUEST_V1_SUBMIT, &zwp_drm_lease_v1_interface, NULL);
+
+	return (struct zwp_drm_lease_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zwp_drm_lease_v1
+ * @struct zwp_drm_lease_v1_listener
+ */
+struct zwp_drm_lease_v1_listener {
+	/**
+	 * shares the DRM file descriptor
+	 *
+	 * This event returns a file descriptor suitable for use with
+	 * DRM-related ioctls. The client should use drmModeGetLease to
+	 * enumerate the DRM objects which have been leased to them, which
+	 * may not be the objects they requested. The lease may have zero
+	 * DRM objects.
+	 *
+	 * The compositor may also issue and immediately revoke the lease
+	 * if no connectors are leasable, in which case this event is not
+	 * sent.
+	 *
+	 * It is a protocol error for the compositor to send this event
+	 * more than once for a given lease.
+	 * @param leased_fd leased DRM file descriptor
+	 */
+	void (*lease_fd)(void *data,
+			 struct zwp_drm_lease_v1 *zwp_drm_lease_v1,
+			 int32_t leased_fd);
+	/**
+	 * sent when the lease has been revoked
+	 *
+	 * When the compositor revokes the lease, it will issue this
+	 * event to notify clients of the change. If the client requires a
+	 * new lease, they should destroy this object and submit a new
+	 * lease request. The compositor will send no further events for
+	 * this object after sending the finish event.
+	 */
+	void (*finished)(void *data,
+			 struct zwp_drm_lease_v1 *zwp_drm_lease_v1);
+};
+
+/**
+ * @ingroup iface_zwp_drm_lease_v1
+ */
+static inline int
+zwp_drm_lease_v1_add_listener(struct zwp_drm_lease_v1 *zwp_drm_lease_v1,
+			      const struct zwp_drm_lease_v1_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) zwp_drm_lease_v1,
+				     (void (**)(void)) listener, data);
+}
+
+#define ZWP_DRM_LEASE_V1_DESTROY 0
+
+/**
+ * @ingroup iface_zwp_drm_lease_v1
+ */
+#define ZWP_DRM_LEASE_V1_LEASE_FD_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_drm_lease_v1
+ */
+#define ZWP_DRM_LEASE_V1_FINISHED_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_drm_lease_v1
+ */
+#define ZWP_DRM_LEASE_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_drm_lease_v1 */
+static inline void
+zwp_drm_lease_v1_set_user_data(struct zwp_drm_lease_v1 *zwp_drm_lease_v1, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) zwp_drm_lease_v1, user_data);
+}
+
+/** @ingroup iface_zwp_drm_lease_v1 */
+static inline void *
+zwp_drm_lease_v1_get_user_data(struct zwp_drm_lease_v1 *zwp_drm_lease_v1)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) zwp_drm_lease_v1);
+}
+
+static inline uint32_t
+zwp_drm_lease_v1_get_version(struct zwp_drm_lease_v1 *zwp_drm_lease_v1)
+{
+	return wl_proxy_get_version((struct wl_proxy *) zwp_drm_lease_v1);
+}
+
+/**
+ * @ingroup iface_zwp_drm_lease_v1
+ *
+ * The client should send this to indicate that it no longer wishes to use
+ * this lease. The compositor should use drmModeRevokeLease on the
+ * appropriate file descriptor, if necessary, then release this object.
+ */
+static inline void
+zwp_drm_lease_v1_destroy(struct zwp_drm_lease_v1 *zwp_drm_lease_v1)
+{
+	wl_proxy_marshal((struct wl_proxy *) zwp_drm_lease_v1,
+			 ZWP_DRM_LEASE_V1_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) zwp_drm_lease_v1);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif

A drm-lease-unstable-v1.xml => drm-lease-unstable-v1.xml +237 -0
@@ 0,0 1,237 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="drm_lease_unstable_v1">
+  <copyright>
+    Copyright © 2018 NXP
+    Copyright © 2019 Status Research &amp; Development GmbH.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zwp_drm_lease_manager_v1" version="1">
+    <description summary="lease manager">
+      This protocol is used by Wayland compositors which act as Direct
+      Renderering Manager (DRM) masters to lease DRM resources to Wayland
+      clients. Once leased, the compositor will not use the leased resources
+      until the lease is revoked or the client closes the file descriptor.
+
+      The lease manager is used to advertise connectors which are available for
+      leasing, and by the client to negotiate a lease request.
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="create_lease_request">
+      <description summary="create a lease request object">
+        Creates a lease request object.
+
+        See the documentation for zwp_drm_lease_request_v1 for details.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_drm_lease_request_v1" />
+    </request>
+
+    <request name="stop">
+      <description summary="stop sending events">
+        Indicates the client no longer wishes to receive connector events. The
+        compositor may still send connector events until it sends the finish
+        event, however.
+
+        The client must not send any requests after this one.
+      </description>
+    </request>
+
+    <event name="connector">
+      <description summary="advertise connectors available for leases">
+        The compositor may choose to advertise 0 or more connectors which may be
+        leased to clients, and will use this event to do so. This object may be
+        passed into a lease request to lease that connector. See
+        zwp_drm_lease_request_v1.add_connector for details.
+
+        When this global is bound, the compositor will send all connectors
+        available for lease, but may send additional connectors at any time.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_drm_lease_connector_v1" />
+    </event>
+
+    <event name="finished">
+      <description summary="the compositor has finished using the manager">
+        This event indicates that the compositor is done sending connector
+        events. The compositor will destroy this object immediately after
+        sending this event, and it will become invalid. The client should
+        release any resources associated with this manager after receiving this
+        event.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="zwp_drm_lease_connector_v1" version="1">
+    <description summary="a leasable DRM connector">
+      Represents a DRM connector which is available for lease. These objects are
+      created via zwp_drm_lease_manager_v1.connector, and should be passed into
+      lease requests via zwp_drm_lease_request_v1.add_connector.
+    </description>
+
+    <event name="name">
+      <description summary="name">
+        The compositor sends this event once the connector is created to
+        indicate the name of this connector. This will not change for the
+        duration of the Wayland session, but is not guaranteed to be consistent
+        between sessions.
+
+        If the compositor also supports zxdg_output_manager_v1 and this
+        connector corresponds to a zxdg_output_v1, this name will match the
+        name of this zxdg_output_v1 object.
+      </description>
+      <arg name="name" type="string" summary="connector name" />
+    </event>
+
+    <event name="description">
+      <description summary="description">
+        The compositor sends this event once the connector is created to provide
+        a human-readable description for this connector, which may be presented
+        to the user. This will not change for the duration of the Wayland
+        session, but is not guaranteed to be consistent between sessions.
+
+        If the compositor also supports zxdg_output_manager_v1 and this
+        connector corresponds to a zxdg_output_v1, this description will match
+        the description of this zxdg_output_v1 object.
+      </description>
+      <arg name="name" type="string" summary="connector name" />
+    </event>
+
+    <event name="edid">
+      <description summary="edid">
+        The compositor sends this event once the connector is created to
+        inform the client of this connector's EDID, to assist in selecting the
+        correct connectors for lease. The EDID is supplied as an array of
+        unsigned 8-bit integers.
+      </description>
+      <arg name="edid" type="array" summary="EDID for this connector" />
+    </event>
+
+    <event name="withdrawn">
+      <description summary="lease offer withdrawn">
+        Sent to indicate that the compositor will no longer honor requests for
+        DRM leases which include this connector. The client may still issue a
+        lease request including this connector, but the compositor will send
+        zwp_drm_lease_v1.finished without issuing a lease fd.
+      </description>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy connector">
+        The client may send this request to indicate that it will not issue a
+        lease request for this connector. Clients are encouraged to send this
+        after receiving the "withdrawn" request so that the server can release
+        the resources associated with this connector offer.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="zwp_drm_lease_request_v1" version="1">
+    <description summary="DRM lease request">
+      A client that wishes to lease DRM resources will attach the list of
+      connectors advertised with zwp_drm_lease_manager_v1.connector that they
+      wish to lease, then use zwp_drm_lease_request_v1.submit to submit the
+      request.
+    </description>
+
+    <enum name="error">
+      <entry name="no_connectors" value="0"
+        summary="request submitted with zero connectors"/>
+      <entry name="submitted_lease" value="1"
+        summary="attempted to reuse a submitted lease"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroys the lease request object">
+        Indicates that the client will no longer use this lease request.
+      </description>
+    </request>
+
+    <request name="request_connector">
+       <description summary="request a connector for this lease">
+         Indicates that the client would like to lease the given connector.
+         This is only used as a suggestion, the compositor may choose to
+         include any resources in the lease it issues, or change the set of
+         leased resources at any time.
+       </description>
+       <arg name="connector" type="object"
+         interface="zwp_drm_lease_connector_v1" />
+    </request>
+
+    <request name="submit">
+       <description summary="submit the lease request">
+         Submits the lease request and creates a new zwp_drm_lease_v1 object.
+         After calling submit, issuing any other request than destroy is a
+         protocol error. Submitting a lease request with no connectors is a
+         protocol error.
+       </description>
+       <arg name="id" type="new_id" interface="zwp_drm_lease_v1" />
+    </request>
+  </interface>
+
+  <interface name="zwp_drm_lease_v1" version="1">
+    <description summary="a DRM lease">
+      A DRM lease object is used to transfer the DRM file descriptor to the
+      client and manage the lifetime of the lease.
+    </description>
+
+    <event name="lease_fd">
+      <description summary="shares the DRM file descriptor">
+        This event returns a file descriptor suitable for use with DRM-related
+        ioctls. The client should use drmModeGetLease to enumerate the DRM
+        objects which have been leased to them, which may not be the objects
+        they requested. The lease may have zero DRM objects.
+
+        The compositor may also issue and immediately revoke the lease if no
+        connectors are leasable, in which case this event is not sent.
+
+        It is a protocol error for the compositor to send this event more than
+        once for a given lease.
+      </description>
+      <arg name="leased_fd" type="fd" summary="leased DRM file descriptor" />
+    </event>
+
+    <event name="finished">
+      <description summary="sent when the lease has been revoked">
+        When the compositor revokes the lease, it will issue this event to
+        notify clients of the change. If the client requires a new lease, they
+        should destroy this object and submit a new lease request. The
+        compositor will send no further events for this object after sending
+        the finish event.
+      </description>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroys the lease object">
+        The client should send this to indicate that it no longer wishes to use
+        this lease. The compositor should use drmModeRevokeLease on the
+        appropriate file descriptor, if necessary, then release this object.
+      </description>
+    </request>
+  </interface>
+</protocol>

M kmscube.c => kmscube.c +199 -212
@@ 30,11 30,11 @@
 #include <stdio.h>
 #include <getopt.h>
 #include <pthread.h>
-#include <xcb/xcb.h>
-#include <xcb/randr.h>
+#include <wayland-client.h>
 
 #include "common.h"
 #include "drm-common.h"
+#include "drm-lease-protocol.h"
 
 
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))


@@ 48,62 48,67 @@
 	{"atomic", no_argument,       0, 'A'},
 	{"device", required_argument, 0, 'D'},
 	{"mode",   required_argument, 0, 'M'},
-        {"thread", no_argument,       0, 't'},
-        {"lease", no_argument,        0, 'l'},
+	{"thread", no_argument,       0, 't'},
+	{"lease", no_argument,	0, 'l'},
 	{0, 0, 0, 0}
 };
 
+struct wayland_state {
+	struct zwp_drm_lease_manager_v1 *lease_manager;
+	struct zwp_drm_lease_connector_v1 *lease_connector;
+};
+
 static void usage(const char *name)
 {
 	printf("Usage: %s [-ADM]\n"
 			"\n"
 			"options:\n"
-			"    -A, --atomic             use atomic modesetting and fencing\n"
+			"    -A, --atomic	     use atomic modesetting and fencing\n"
 			"    -D, --device=DEVICE      use the given device\n"
-               		"    -t, --thread             two threads and cubes on two monitors\n"
-                        "    -l, --lease              lease output from the X server\n"
-			"    -M, --mode=MODE          specify mode, one of:\n"
-			"        smooth    -  smooth shaded cube (default)\n"
-			"        rgba      -  rgba textured cube\n"
-			"        nv12-2img -  yuv textured (color conversion in shader)\n"
-			"        nv12-1img -  yuv textured (single nv12 texture)\n",
+			"    -t, --thread	     two threads and cubes on two monitors\n"
+			"    -l, --lease	      lease output from the X server\n"
+			"    -M, --mode=MODE	  specify mode, one of:\n"
+			"	smooth    -  smooth shaded cube (default)\n"
+			"	rgba      -  rgba textured cube\n"
+			"	nv12-2img -  yuv textured (color conversion in shader)\n"
+			"	nv12-1img -  yuv textured (single nv12 texture)\n",
 			name);
 }
 
 static void dump_lessees(char *head, drmModeLesseeListPtr lessees) {
-        uint32_t i;
-        printf("%s lessees:", head);
-        if (!lessees) {
-            printf("null\n");
-            return;
-        }
-        for (i = 0; i < lessees->count; i++)
-                printf(" %u", lessees->lessees[i]);
-        printf("\n");
+	uint32_t i;
+	printf("%s lessees:", head);
+	if (!lessees) {
+	    printf("null\n");
+	    return;
+	}
+	for (i = 0; i < lessees->count; i++)
+		printf(" %u", lessees->lessees[i]);
+	printf("\n");
 }
 
 static void dump_objects(char *head, drmModeObjectListPtr objects) {
-        uint32_t i;
-        printf("%s objects:", head);
-        if (!objects) {
-            printf("null\n");
-            return;
-        }
-        for (i = 0; i < objects->count; i++)
-                printf(" %u", objects->objects[i]);
-        printf("\n");
+	uint32_t i;
+	printf("%s objects:", head);
+	if (!objects) {
+	    printf("null\n");
+	    return;
+	}
+	for (i = 0; i < objects->count; i++)
+		printf(" %u", objects->objects[i]);
+	printf("\n");
 }
 
 int run(int fd, int nfd) {
-        struct egl *egl;
-        struct gbm *gbm;
-        struct drm *drm;
-        int ret;
+	struct egl *egl;
+	struct gbm *gbm;
+	struct drm *drm;
+	int ret;
 
 	if (atomic)
-                drm = init_drm_atomic(fd, nfd);
+		drm = init_drm_atomic(fd, nfd);
 	else
-                drm = init_drm_legacy(fd, nfd);
+		drm = init_drm_legacy(fd, nfd);
 	if (!drm) {
 		printf("failed to initialize %s DRM\n", atomic ? "atomic" : "legacy");
 		return -1;


@@ 131,8 136,8 @@
 	glClear(GL_COLOR_BUFFER_BIT);
 
 	ret = drm->run(drm, gbm, egl);
-        printf ("drm->run returns %d\n", ret);
-        return ret;
+	printf ("drm->run returns %d\n", ret);
+	return ret;
 }
 
 static void *thread_run(void *arg)


@@ 145,14 150,64 @@
     return 0;
 }
 
+void lease_handle_lease_fd(void *data,
+		struct zwp_drm_lease_v1 *zwp_drm_lease_v1, int32_t leased_fd) {
+	int *fd = data;
+	*fd = leased_fd;
+}
+
+void lease_handle_finished(void *data,
+		struct zwp_drm_lease_v1 *zwp_drm_lease_v1) {
+	// Who cares
+}
+
+static const struct zwp_drm_lease_v1_listener lease_listener = {
+	.lease_fd = lease_handle_lease_fd,
+	.finished = lease_handle_finished,
+};
+
+static void drm_lease_manager_connector(void *data,
+		struct zwp_drm_lease_manager_v1 *zwp_drm_lease_manager_v1,
+		struct zwp_drm_lease_connector_v1 *conn) {
+	struct wayland_state *state = data;
+	if (!state->lease_connector) {
+		state->lease_connector = conn;
+	}
+}
+
+static const struct zwp_drm_lease_manager_v1_listener lease_manager_listener = {
+	.connector = drm_lease_manager_connector,
+};
+
+static void registry_global(void *data, struct wl_registry *wl_registry,
+		uint32_t name, const char *interface, uint32_t version) {
+	struct wayland_state *state = data;
+	if (strcmp(interface, zwp_drm_lease_manager_v1_interface.name) == 0) {
+		state->lease_manager = wl_registry_bind(wl_registry, name,
+				&zwp_drm_lease_manager_v1_interface, 1);
+		zwp_drm_lease_manager_v1_add_listener(state->lease_manager,
+				&lease_manager_listener, state);
+	}
+}
+
+static void registry_global_remove(
+		void *data, struct wl_registry *wl_registry, uint32_t name) {
+	// who cares
+}
+
+static const struct wl_registry_listener registry_listener = {
+	.global = registry_global,
+	.global_remove = registry_global_remove,
+};
+
 int main(int argc, char *argv[])
 {
 	const char *device = "/dev/dri/card0";
-        int do_thread = 0;
-        int do_lease = 0;
+	int do_thread = 0;
+	int do_lease = 0;
 	int opt;
-        int fd;
-        int nfd = -1;
+	int fd;
+	int nfd = -1;
 
 	while ((opt = getopt_long_only(argc, argv, shortopts, longopts, NULL)) != -1) {
 		switch (opt) {


@@ 177,204 232,136 @@
 				return -1;
 			}
 			break;
-                case 't':
-                        do_thread = 1;
-                        break;
-                case 'l':
-                        do_lease = 1;
-                        break;
+		case 't':
+			do_thread = 1;
+			break;
+		case 'l':
+			do_lease = 1;
+			break;
 		default:
 			usage(argv[0]);
 			return -1;
 		}
 	}
 
-        if (do_lease) {
-                xcb_connection_t        *connection;
-                int                     screen;
-
-                connection = xcb_connect(NULL, &screen);
-                if (!connection) {
-                        printf("Connection to X server failed\n");
-                        exit(1);
-                }
-                xcb_randr_query_version_cookie_t rqv_c = xcb_randr_query_version(connection,
-                                                                                 XCB_RANDR_MAJOR_VERSION,
-                                                                                 XCB_RANDR_MINOR_VERSION);
-                xcb_randr_query_version_reply_t *rqv_r = xcb_randr_query_version_reply(connection, rqv_c, NULL);
-
-                if (!rqv_r || rqv_r->minor_version < 6) {
-                        printf("No new-enough RandR version\n");
-                        exit(1);
-                }
-
-                xcb_screen_iterator_t s_i;
-
-                int i_s = 0;
-
-                for (s_i = xcb_setup_roots_iterator(xcb_get_setup(connection));
-                     s_i.rem;
-                     xcb_screen_next(&s_i), i_s++) {
-                        printf ("index %d screen %d\n", s_i.index, screen);
-                        if (i_s == screen)
-                                break;
-                }
-
-                xcb_window_t root = s_i.data->root;
-
-                printf("root %x\n", root);
-
-                xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(connection, root);
-
-                xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
-
-                if (!gsr_r) {
-                        printf("get_screen_resources failed\n");
-                        exit(1);
-                }
-
-                xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
-                int o, c;
-
-                xcb_randr_output_t output = 0;
-
-                /* Find a connected but idle output */
-                for (o = 0; output == 0 && o < gsr_r->num_outputs; o++) {
-                        xcb_randr_get_output_info_cookie_t goi_c = xcb_randr_get_output_info(connection, ro[o], gsr_r->config_timestamp);
-
-                        xcb_randr_get_output_info_reply_t *goi_r = xcb_randr_get_output_info_reply(connection, goi_c, NULL);
-
-                        /* Find the first connected but unused output */
-                        if (goi_r->connection == XCB_RANDR_CONNECTION_CONNECTED &&
-                            goi_r->crtc == 0) {
-                                output = ro[o];
-                        }
-
-                        free(goi_r);
-                }
-
-                xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
-
-                xcb_randr_crtc_t crtc = 0;
-
-                /* Find an idle crtc */
-                for (c = 0; crtc == 0 && c < gsr_r->num_crtcs; c++) {
-                        xcb_randr_get_crtc_info_cookie_t gci_c = xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
-
-                        xcb_randr_get_crtc_info_reply_t *gci_r = xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
-
-                        /* Find the first connected but unused crtc */
-                        if (gci_r->mode == 0)
-                                crtc = rc[c];
-
-                        free(gci_r);
-                }
-
-                free(gsr_r);
-
-                printf("output %x crtc %x\n", output, crtc);
-
-                xcb_randr_lease_t lease = xcb_generate_id(connection);
-
-                xcb_randr_create_lease_cookie_t rcl_c = xcb_randr_create_lease(connection,
-                                                                               root,
-                                                                               lease,
-                                                                               1,
-                                                                               1,
-                                                                               &crtc,
-                                                                               &output);
-                xcb_randr_create_lease_reply_t *rcl_r = xcb_randr_create_lease_reply(connection, rcl_c, NULL);
-
-                if (!rcl_r) {
-                        printf("create_lease failed\n");
-                        exit(1);
-                }
-
-                int *rcl_f = xcb_randr_create_lease_reply_fds(connection, rcl_r);
-
-                fd = rcl_f[0];
-
-                printf("fd %d\n", fd);
-
-        } else {
-                fd = open(device, O_RDWR);
-                if (fd < 0) {
-                        printf("could not open drm device\n");
-                        return -1;
-                }
-        }
-        if (do_thread) {
-                struct drm_resources resources;
-                uint32_t objects[3];
-                int nobjects;
-                uint32_t lessee;
-                pthread_t thread;
-
-                drmModeLesseeListPtr l_list;
-                drmModeObjectListPtr o_list;
+	if (do_lease) {
+		struct wayland_state state = { 0 };
+		struct wl_display *display = wl_display_connect(NULL);
+		if (!display) {
+			fprintf(stderr, "Failed to establish Wayland connection\n");
+			return -1;
+		}
+		struct wl_registry *registry = wl_display_get_registry(display);
+		wl_registry_add_listener(registry, &registry_listener, &state);
+		wl_display_dispatch(display);
+		wl_display_roundtrip(display);
+		if (!state.lease_manager) {
+			fprintf(stderr, "zwp_lease_manager_v1 global not available\n");
+			return -1;
+		}
+		if (!state.lease_connector) {
+			fprintf(stderr, "no connectors offered for lease\n");
+			return -1;
+		}
+		struct zwp_drm_lease_request_v1 *req =
+			zwp_drm_lease_manager_v1_create_lease_request(state.lease_manager);
+		zwp_drm_lease_request_v1_request_connector(req, state.lease_connector);
+		struct zwp_drm_lease_v1 *lease = zwp_drm_lease_request_v1_submit(req);
+		zwp_drm_lease_v1_add_listener(lease, &lease_listener, &fd);
+		wl_display_dispatch(display);
+		wl_display_roundtrip(display);
+		if (fd < 0) {
+			fprintf(stderr, "Failed to acquire lease\n");
+			return -1;
+		}
+	} else {
+		fd = open(device, O_RDWR);
+		if (fd < 0) {
+			printf("could not open drm device\n");
+			return -1;
+		}
+	}
+	if (do_thread) {
+		struct drm_resources resources;
+		uint32_t objects[3];
+		int nobjects;
+		uint32_t lessee;
+		pthread_t thread;
+
+		drmModeLesseeListPtr l_list;
+		drmModeObjectListPtr o_list;
+
+		if (find_drm(&resources, fd, -1) != 0) {
+			printf("Could not get DRM resources for fork\n");
+			return -1;
+		}
 
-                if (find_drm(&resources, fd, -1) != 0) {
-                        printf("Could not get DRM resources for fork\n");
-                        return -1;
-                }
+		printf("connector %d crtc %d plane %d\n",
+						resources.connector, resources.crtc, resources.plane);
 
-                printf("connector %d encoder %d crtc %d\n", resources.connector, resources.encoder, resources.crtc);
+		nobjects = 0;
+		if (resources.connector)
+			objects[nobjects++] = resources.connector;
+		if (resources.crtc)
+			objects[nobjects++] = resources.crtc;
+		if (resources.plane)
+			objects[nobjects++] = resources.plane;
 
-                nobjects = 0;
-                if (resources.connector)
-                        objects[nobjects++] = resources.connector;
-                if (resources.encoder)
-                        objects[nobjects++] = resources.encoder;
-                if (resources.crtc)
-                        objects[nobjects++] = resources.crtc;
+		printf("objects to lease: %d\n", nobjects);
+		for (int i = 0; i < nobjects; ++i) {
+			printf("%d\n", objects[i]);
+		}
 
-                o_list = drmModeGetLease(fd);
+		o_list = drmModeGetLease(fd);
 
-                dump_objects("owner before lease", o_list);
-                free(o_list);
+		dump_objects("owner before lease", o_list);
+		free(o_list);
 
-                l_list = drmModeListLessees(fd);
+		l_list = drmModeListLessees(fd);
 
-                dump_lessees("owner before lease", l_list);
+		dump_lessees("owner before lease", l_list);
 
-                free(l_list);
+		free(l_list);
 
-                nfd = drmModeCreateLease(fd, objects, nobjects, 0, &lessee);
+		nfd = drmModeCreateLease(fd, objects, nobjects, 0, &lessee);
+		if (nfd < 0) {
+			fprintf(stderr, "drmModeCreateLease: %s\n", strerror(errno));
+		}
 
-                o_list = drmModeGetLease(fd);
+		o_list = drmModeGetLease(fd);
 
-                dump_objects("owner after lease", o_list);
-                free(o_list);
+		dump_objects("owner after lease", o_list);
+		free(o_list);
 
-                l_list = drmModeListLessees(fd);
+		l_list = drmModeListLessees(fd);
 
-                dump_lessees("owner after lease", l_list);
+		dump_lessees("owner after lease", l_list);
 
-                free(l_list);
+		free(l_list);
 
-                o_list = drmModeGetLease(nfd);
+		o_list = drmModeGetLease(nfd);
 
-                dump_objects("lessee after lease", o_list);
-                free(o_list);
+		dump_objects("lessee after lease", o_list);
+		free(o_list);
 
-                l_list = drmModeListLessees(nfd);
+		l_list = drmModeListLessees(nfd);
 
-                dump_lessees("lessee after lease", l_list);
+		dump_lessees("lessee after lease", l_list);
 
-                free(l_list);
+		free(l_list);
 
 #if 0
-                printf("closing lease\n");
-                close(nfd);
-                printf("closing owner\n");
-                close(fd);
-                exit(0);
+		printf("closing lease\n");
+		close(nfd);
+		printf("closing owner\n");
+		close(fd);
+		exit(0);
 #endif
 
-                pthread_create(&thread, NULL, thread_run, (void *) (intptr_t) nfd);
-                printf("parent running on owner %d\n", fd);
-                printf("parent running now...\n");
-        }
+		pthread_create(&thread, NULL, thread_run, (void *) (intptr_t) nfd);
+		printf("parent running on owner %d\n", fd);
+		printf("parent running now...\n");
+	}
 
-        return run(fd, nfd);
+	return run(fd, nfd);
 }