[PATCH weston] RFC: libweston/compositor-drm: Add support for drm-lease.

Marius Vlad marius-cristian.vlad at nxp.com
Wed Jan 24 19:11:39 UTC 2018


DRM leases is a method developed by Keith Packard to allow other application
manage the output of a display/VR, while a DRM master is already owning the
outputs resources. A more thorough explanation and terminology can be found at
[1].

This patch adds support for DRM lease. libdrm is lease-aware in 2.4.89,
while the kernel support has landed in Linus's master tree (4.15).

The easiest way to choose which output to lease is to have a 'lease' entry for
the output in the config file. My assumption is based on the fact that one would
not want to destroy/close the application running on a particular output. Upon
leasing an output to a client that output will no longer be managed by weston.
When the application is done with the lease it will send a revoke request,
moment in which weston will reclaim the output.

For instance the following configuration file can lease HDMI-A-1 output to other
application.

[output]
name=HDMI-A-1
lease=on

The patch relies on previous drm-lease-unstable-v1 extension protocol
posted previously [4].

[1] https://keithp.com/blogs/DRM-lease/
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v4.15-rc9&id=62884cd386b876638720ef88374b31a84ca7ee5f
[3] https://cgit.freedesktop.org/mesa/drm/commit/?id=c4171535389d72e9135c9615cecd07b346fd6d7e
[4] https://lists.freedesktop.org/archives/wayland-devel/2018-January/036652.html

Signed-off-by: Marius Vlad <marius-cristian.vlad at nxp.com>
---
 Makefile.am                |   2 +
 compositor/main.c          |  10 +++
 configure.ac               |   4 +-
 libweston/compositor-drm.c | 204 ++++++++++++++++++++++++++++++++++++++++++++-
 libweston/compositor.c     |   1 +
 libweston/compositor.h     |   3 +
 man/weston.ini.man         |   8 ++
 7 files changed, 230 insertions(+), 2 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index e224d60..9a5fcb9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -178,6 +178,8 @@ nodist_libweston_ at LIBWESTON_MAJOR@_la_SOURCES =				\
 	protocol/viewporter-server-protocol.h		\
 	protocol/linux-dmabuf-unstable-v1-protocol.c	\
 	protocol/linux-dmabuf-unstable-v1-server-protocol.h		\
+	protocol/drm-lease-unstable-v1-protocol.c	\
+	protocol/drm-lease-unstable-v1-server-protocol.h	\
 	protocol/relative-pointer-unstable-v1-protocol.c		\
 	protocol/relative-pointer-unstable-v1-server-protocol.h		\
 	protocol/pointer-constraints-unstable-v1-protocol.c		\
diff --git a/compositor/main.c b/compositor/main.c
index 7feb4cb..bf1712c 100644
--- a/compositor/main.c
+++ b/compositor/main.c
@@ -1186,6 +1186,7 @@ drm_backend_output_configure(struct wl_listener *listener, void *data)
 		modeline = s;
 		s = NULL;
 	}
+
 	free(s);
 
 	if (api->set_mode(output, mode, modeline) < 0) {
@@ -1208,6 +1209,15 @@ drm_backend_output_configure(struct wl_listener *listener, void *data)
 
 	api->set_seat(output, seat);
 	free(seat);
+#ifdef HAVE_DRM_LEASE
+	char *lease;
+	weston_config_section_get_string(section, "lease", &lease, "off");
+	if (!strncmp(lease, "on", 2)) {
+		output->lease = true;
+		weston_log("Enabling lease on output %s\n", output->name);
+	}
+	free(lease);
+#endif
 
 	weston_output_enable(output);
 }
diff --git a/configure.ac b/configure.ac
index 6f295dc..444666b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -209,9 +209,11 @@ if test x$enable_drm_compositor = xyes; then
   PKG_CHECK_MODULES(DRM_COMPOSITOR_GBM, [gbm >= 10.2],
 		    [AC_DEFINE([HAVE_GBM_FD_IMPORT], 1, [gbm supports dmabuf import])],
 		    [AC_MSG_WARN([gbm does not support dmabuf import, will omit that capability])])
+  PKG_CHECK_MODULES(DRM_LEASE, [libdrm >= 2.4.89],
+		    [AC_DEFINE([HAVE_DRM_LEASE], 1, [libdrm support lease capability])],
+		    [AC_MSG_WARN([libdrm doesn't have leases support, will omit that capability])])
 fi
 
-
 PKG_CHECK_MODULES(LIBINPUT_BACKEND, [libinput >= 0.8.0])
 PKG_CHECK_MODULES(COMPOSITOR, [$COMPOSITOR_MODULES])
 
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index fe59bf5..98c2e6b 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -62,6 +62,7 @@
 #include "presentation-time-server-protocol.h"
 #include "linux-dmabuf.h"
 #include "linux-dmabuf-unstable-v1-server-protocol.h"
+#include "drm-lease-unstable-v1-server-protocol.h"
 
 #ifndef DRM_CAP_TIMESTAMP_MONOTONIC
 #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
@@ -386,6 +387,30 @@ static struct gl_renderer_interface *gl_renderer;
 
 static const char default_seat[] = "seat0";
 
+#ifdef HAVE_DRM_LEASE
+/* hold current leases given */
+static struct wl_list leases;
+
+struct drm_display {
+       uint32_t connector_id;
+       uint32_t crtc_id;
+       uint32_t plane_id;
+};
+
+struct drm_lease {
+       int leased_fd;
+       uint32_t leased_id;
+       struct wl_list list;
+};
+
+struct drm_lease_data {
+       struct drm_backend *drm_backend;
+       struct udev_device *drm_device;
+};
+
+static struct drm_lease_data drm_lease_data;
+#endif
+
 static inline struct drm_output *
 to_drm_output(struct weston_output *base)
 {
@@ -4399,6 +4424,26 @@ drm_restore(struct weston_compositor *ec)
 	weston_launcher_restore(ec->launcher);
 }
 
+#ifdef HAVE_DRM_LEASE
+static void
+drm_lease_destroy(struct drm_backend *b)
+{
+	struct drm_lease *lease, *lease_iter;
+
+	wl_list_for_each_safe(lease, lease_iter, &leases, list) {
+		if (drmModeRevokeLease(b->drm.fd, lease->leased_id) < 0) {
+			weston_log("Failed to revoke lease id %u\n",
+				   lease->leased_id);
+			continue;
+		}
+
+		weston_log("Lease id %u revoked\n", lease->leased_id);
+		wl_list_remove(&lease->list);
+		free(lease);
+	}
+}
+#endif
+
 static void
 drm_destroy(struct weston_compositor *ec)
 {
@@ -4412,7 +4457,9 @@ drm_destroy(struct weston_compositor *ec)
 	b->shutting_down = true;
 
 	destroy_sprites(b);
-
+#ifdef HAVE_DRM_LEASE
+	drm_lease_destroy(b);
+#endif
 	weston_compositor_shutdown(ec);
 
 	if (b->gbm)
@@ -4837,6 +4884,158 @@ static const struct weston_drm_output_api api = {
 	drm_output_set_seat,
 };
 
+#ifdef HAVE_DRM_LEASE
+static void
+drm_lease_save_objects(const struct drm_display *drm,
+		       uint32_t *objects, uint32_t *nobjects)
+{
+	uint32_t i = 0;
+
+	if (drm->connector_id)
+		objects[i++] = drm->connector_id;
+
+	if (drm->crtc_id)
+		objects[i++] = drm->crtc_id;
+
+	/* if universal plane */
+	if (drm->plane_id)
+		objects[i++] = drm->plane_id;
+
+	*nobjects = i;
+}
+static void
+drm_lease_create(struct wl_client *client, struct wl_resource *resource)
+{
+	struct drm_lease_data *user_data = wl_resource_get_user_data(resource);
+	struct weston_compositor *compositor = user_data->drm_backend->compositor;
+	int drm_fd = user_data->drm_backend->drm.fd;
+
+	struct drm_output *output = NULL;
+	struct drm_output *choosen_output = NULL;
+
+	uint32_t objects[3];
+	uint32_t nobjects;
+
+	struct drm_lease *lease;
+	struct drm_display display = {};
+
+	wl_list_for_each(output, &compositor->output_list, base.link) {
+		struct weston_output *wet_output = &output->base;
+		if (wet_output->lease) {
+			display.crtc_id = output->crtc_id;
+			display.connector_id = output->connector_id;
+			display.plane_id = output->scanout_plane->plane_id;
+
+			choosen_output = output;
+			break;
+		}
+	}
+
+	if (!choosen_output) {
+		weston_log("No valid output found to lease!\n");
+		zwp_drm_lease_v1_send_failed(resource);
+		return;
+	}
+
+	drm_lease_save_objects(&display, objects, &nobjects);
+	lease = zalloc(sizeof(*lease));
+
+	/* create lease */
+	lease->leased_fd = drmModeCreateLease(drm_fd, objects, nobjects, 0,
+					      &lease->leased_id);
+	if (lease->leased_fd < 0) {
+		weston_log("Failed to create the lease!");
+		free(lease);
+		zwp_drm_lease_v1_send_failed(resource);
+		return;
+	}
+
+	weston_log("Lease leased_id = %u created, on output %s\n",
+		   lease->leased_id, choosen_output->base.name);
+
+	wl_list_insert(&leases, &lease->list);
+	drm_output_destroy(&choosen_output->base);
+
+	zwp_drm_lease_v1_send_created(resource, lease->leased_fd,
+				      lease->leased_id);
+}
+
+
+static void
+drm_lease_revoke(struct wl_client *client, struct wl_resource *resource, uint32_t id)
+{
+	struct drm_lease *lease, *lease_iter;
+	struct drm_lease_data *user_data = wl_resource_get_user_data(resource);
+	struct weston_compositor *compositor = user_data->drm_backend->compositor;
+	int drm_fd = user_data->drm_backend->drm.fd;
+
+	wl_list_for_each_safe(lease, lease_iter, &leases, list) {
+		if (lease->leased_id == id) {
+			if (drmModeRevokeLease(drm_fd, lease->leased_id) < 0) {
+				goto fail;
+			}
+
+			wl_list_remove(&lease->list);
+			zwp_drm_lease_v1_send_revoked(resource);
+
+			free(lease);
+
+			/* re-initialize outputs */
+			update_outputs(user_data->drm_backend, user_data->drm_device);
+
+			wl_signal_emit(&compositor->wake_signal, compositor);
+			wl_event_source_timer_update(compositor->idle_source,
+						     compositor->idle_time * 1000);
+			return;
+		}
+	}
+
+fail:
+	weston_log("No valid lease found to revoke for id %u\n", id);
+	zwp_drm_lease_v1_send_failed(resource);
+}
+
+static const struct zwp_drm_lease_v1_interface drm_lease_implementation = {
+	drm_lease_create,
+	drm_lease_revoke,
+};
+
+static void
+__drm_lease_init(struct wl_client *client, void *data, uint32_t ver, uint32_t id)
+{
+	struct drm_lease_data *lease_data = (struct drm_lease_data *) data;
+	struct wl_resource *resource;
+
+	resource = wl_resource_create(client, &zwp_drm_lease_v1_interface,
+				      ver, id);
+	if (resource == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	wl_resource_set_implementation(resource, &drm_lease_implementation,
+				       lease_data, NULL);
+}
+
+static int
+drm_lease_init(struct drm_backend *drm_backend, struct udev_device *drm_device)
+{
+	struct weston_compositor *compositor = drm_backend->compositor;
+
+	wl_list_init(&leases);
+
+	drm_lease_data.drm_backend = drm_backend;
+	drm_lease_data.drm_device = drm_device;
+
+	if (!wl_global_create(compositor->wl_display,
+			      &zwp_drm_lease_v1_interface, 1, &drm_lease_data,
+			      __drm_lease_init))
+		return -1;
+
+	return 0;
+}
+#endif
+
 static struct drm_backend *
 drm_backend_create(struct weston_compositor *compositor,
 		   struct weston_drm_backend_config *config)
@@ -4945,6 +5144,9 @@ drm_backend_create(struct weston_compositor *compositor,
 		weston_log("failed to create output for %s\n", b->drm.filename);
 		goto err_udev_input;
 	}
+#ifdef HAVE_DRM_LEASE
+	drm_lease_init(b, drm_device);
+#endif
 
 	/* A this point we have some idea of whether or not we have a working
 	 * cursor plane. */
diff --git a/libweston/compositor.c b/libweston/compositor.c
index aec937b..529a61c 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -4773,6 +4773,7 @@ weston_output_init(struct weston_output *output,
 	output->name = strdup(name);
 	wl_list_init(&output->link);
 	output->enabled = false;
+	output->lease = false;
 
 	/* Add some (in)sane defaults which can be used
 	 * for checking if an output was properly configured
diff --git a/libweston/compositor.h b/libweston/compositor.h
index dffcba8..da54180 100644
--- a/libweston/compositor.h
+++ b/libweston/compositor.h
@@ -239,6 +239,9 @@ struct weston_output {
 
 	int (*enable)(struct weston_output *output);
 	int (*disable)(struct weston_output *output);
+
+	/**< this output can be leased to other application */
+	bool lease;
 };
 
 enum weston_pointer_motion_mask {
diff --git a/man/weston.ini.man b/man/weston.ini.man
index f237fd6..a2f603c 100644
--- a/man/weston.ini.man
+++ b/man/weston.ini.man
@@ -436,6 +436,14 @@ multiheaded environment with a single compositor for multiple output and input
 configurations. The default seat is called "default" and will always be
 present. This seat can be constrained like any other.
 .RE
+.TP 7
+.BI "lease=" on/off
+Specifies that this output can leased to other applications. If an application
+requests a lease, this output will be destroyed and the application has full
+control over the output. Upon revoking the lease weston will take control of the
+output.
+.RE
+.TP 7
 .SH "INPUT-METHOD SECTION"
 .TP 7
 .BI "path=" "/usr/libexec/weston-keyboard"
-- 
2.9.3



More information about the wayland-devel mailing list