[PATCH weston 1/2 v4] compositor-drm: Add support for DRM lease

Marius Vlad marius-cristian.vlad at nxp.com
Wed Mar 21 19:02:22 UTC 2018


Signed-off-by: Marius Vlad <marius-cristian.vlad at nxp.com>
---
 Makefile.am                |   4 +
 compositor/main.c          |  11 ++
 configure.ac               |   4 +
 libweston/compositor-drm.c | 272 +++++++++++++++++++++++++++++++++++++++++++++
 libweston/compositor.c     |   1 +
 libweston/compositor.h     |   2 +
 6 files changed, 294 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 69ca6cb..9c53a6b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -163,6 +163,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		\
@@ -888,6 +890,8 @@ BUILT_SOURCES +=					\
 	protocol/ivi-application-client-protocol.h	\
 	protocol/linux-dmabuf-unstable-v1-protocol.c	\
 	protocol/linux-dmabuf-unstable-v1-client-protocol.h		\
+	protocol/drm-lease-unstable-v1-protocol.c			\
+	protocol/drm-lease-unstable-v1-client-protocol.h		\
 	protocol/input-timestamps-unstable-v1-protocol.c		\
 	protocol/input-timestamps-unstable-v1-client-protocol.h
 
diff --git a/compositor/main.c b/compositor/main.c
index 1e82788..5ea15fc 100644
--- a/compositor/main.c
+++ b/compositor/main.c
@@ -1093,6 +1093,17 @@ drm_backend_output_configure(struct wl_listener *listener, void *data)
 	api->set_seat(output, seat);
 	free(seat);
 
+	char *lease;
+	weston_config_section_get_string(section, "lease", &lease, "off");
+	if (!strncmp(lease, "on", 2)) {
+		output->leasable = true;
+#ifdef DEBUG
+		weston_log("Enabling lease on output %s\n", output->name);
+#endif
+	}
+	free(lease);
+
+
 	weston_output_enable(output);
 }
 
diff --git a/configure.ac b/configure.ac
index 1609ace..738f4a4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -212,6 +212,10 @@ 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
 
 
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 81ca67d..dc2d37f 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
@@ -269,6 +270,21 @@ struct drm_backend {
 	uint32_t pageflip_timeout;
 
 	bool shutting_down;
+	struct wl_list leases;
+};
+
+struct lease {
+	int leased_fd;
+	uint32_t lessee_id;
+
+	int nobjects;
+	int tnobjects;
+	uint32_t *objects;
+
+	struct drm_output *leased_output;
+	struct wl_resource *lease_resource;
+	struct drm_backend *drm_backend;
+	struct wl_list link;
 };
 
 struct drm_mode {
@@ -422,6 +438,7 @@ struct drm_output {
 	int destroy_pending;
 	int disable_pending;
 	int dpms_off_pending;
+	int lease_pending;
 
 	struct drm_fb *gbm_cursor_fb[2];
 	struct drm_plane *cursor_plane;
@@ -449,6 +466,8 @@ struct drm_output {
 	struct wl_listener recorder_frame_listener;
 
 	struct wl_event_source *pageflip_timer;
+
+	struct lease *lease;
 };
 
 static struct gl_renderer_interface *gl_renderer;
@@ -1383,6 +1402,36 @@ drm_pending_state_get_output(struct drm_pending_state *pending_state,
 
 static int drm_pending_state_apply_sync(struct drm_pending_state *state);
 
+#ifdef HAVE_DRM_LEASE
+static void
+drm_lease_clear_objects(struct lease *lease)
+{
+	memset(lease->objects, 0, sizeof(uint32_t) * lease->tnobjects);
+	lease->tnobjects = 0;
+}
+
+static void
+drm_output_send_lease(struct drm_output *output)
+{
+	struct lease *lease = output->lease;
+	struct wl_resource *resource = lease->lease_resource;
+	int drm_fd = lease->drm_backend->drm.fd;
+
+	lease->leased_fd = drmModeCreateLease(drm_fd, lease->objects,
+					      lease->tnobjects, 0,
+					      &lease->lessee_id);
+	if (lease->leased_fd < 0) {
+		drm_lease_clear_objects(lease);
+		zwp_kms_lease_request_v1_send_failed(resource);
+		return;
+	}
+
+	wl_list_insert(&lease->drm_backend->leases, &lease->link);
+	zwp_kms_lease_request_v1_send_created(resource,
+			lease->leased_fd, lease->lessee_id);
+}
+#endif
+
 /**
  * Mark a drm_output_state (the output's last state) as complete. This handles
  * any post-completion actions such as updating the repaint timer, disabling the
@@ -1416,6 +1465,12 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags,
 		output->disable_pending = 0;
 		output->dpms_off_pending = 0;
 		weston_output_disable(&output->base);
+#ifdef HAVE_DRM_LEASE
+		if (output->lease_pending) {
+			output->lease_pending = 0;
+			drm_output_send_lease(output);
+		}
+#endif
 		return;
 	} else if (output->dpms_off_pending) {
 		struct drm_pending_state *pending = drm_pending_state_alloc(b);
@@ -4963,6 +5018,7 @@ create_output_for_connector(struct drm_backend *b,
 
 	output->destroy_pending = 0;
 	output->disable_pending = 0;
+	output->lease_pending = 0;
 
 	if (drm_output_init_crtc(output, resources, connector) < 0)
 		goto err_output;
@@ -5626,6 +5682,216 @@ static const struct weston_drm_output_api api = {
 	drm_output_set_seat,
 };
 
+#ifdef HAVE_DRM_LEASE
+static void
+destroy_lease_req(struct wl_resource *params_resource)
+{
+	struct lease *lease = wl_resource_get_user_data(params_resource);
+	free(lease->objects);
+	free(lease);
+}
+
+static void
+drm_lease_add_objects(struct lease *lease, uint32_t id)
+{
+	if (lease->tnobjects > lease->nobjects) {
+		lease->nobjects *= 2;
+		lease->objects = realloc(lease->objects,
+					 lease->nobjects * sizeof(uint32_t));
+	}
+
+	lease->objects[lease->tnobjects++] = id;
+}
+
+static void
+drm_lease_add_connector(struct wl_client *client, struct wl_resource *resource,
+			uint32_t id)
+{
+	(void) client;
+
+	struct lease *lease = wl_resource_get_user_data(resource);
+	drm_lease_add_objects(lease, id);
+}
+
+static void
+drm_lease_add_crtc(struct wl_client *client, struct wl_resource *resource,
+		   uint32_t id)
+{
+	(void) client;
+	struct lease *lease = wl_resource_get_user_data(resource);
+	drm_lease_add_objects(lease, id);
+}
+
+static void
+drm_lease_add_plane(struct wl_client *client, struct wl_resource *resource,
+		    uint32_t id)
+{
+	(void) client;
+	struct lease *lease = wl_resource_get_user_data(resource);
+	drm_lease_add_objects(lease, id);
+}
+
+static void
+drm_lease_create(struct wl_client *client, struct wl_resource *resource)
+{
+	(void) client;
+	struct lease *lease = wl_resource_get_user_data(resource);
+	struct weston_compositor *compositor = lease->drm_backend->compositor;
+	struct drm_output *output, *leased_output = NULL;
+
+	wl_list_for_each(output, &compositor->output_list, base.link) {
+		struct weston_output *wet_output = &output->base;
+
+		/* verify if this output is allow to be leased */
+		if (wet_output->leasable) {
+			int conn_found = 0;
+
+			/* determine which connector to disable */
+			for (int i = 0; i < lease->tnobjects; i++) {
+				if (lease->objects[i] == output->connector_id) {
+					conn_found = 1;
+					break;
+				}
+			}
+
+			if (!conn_found) {
+				break;
+			}
+
+			leased_output = output;
+			break;
+		}
+	}
+
+	if (!leased_output) {
+		zwp_kms_lease_request_v1_send_failed(resource);
+		drm_lease_clear_objects(lease);
+		return;
+	}
+
+	leased_output->lease = lease;
+	lease->leased_output = leased_output;
+
+	/*
+	 * If we are just in the middle of a flip disabling the output will be
+	 * deferred so we rely on drm_output_update_complete() to disable it and
+	 * send the event back to the client. Otherwise we disable and send the
+	 * event directly.
+	 */
+	if (leased_output->page_flip_pending || output->vblank_pending ||
+	    leased_output->atomic_complete_pending) {
+		leased_output->lease_pending = 1;
+		leased_output->disable_pending = 1;
+	} else {
+		weston_output_disable(&leased_output->base);
+		drm_output_send_lease(leased_output);
+	}
+}
+
+
+static void
+drm_lease_revoke(struct wl_client *client,
+		 struct wl_resource *resource, uint32_t id)
+{
+	(void) client;
+	struct lease *lease = wl_resource_get_user_data(resource);
+	int drm_fd = lease->drm_backend->drm.fd;
+	struct lease *old, *tmp;
+
+	wl_list_for_each_safe(old, tmp, &lease->drm_backend->leases, link) {
+		if (old->lessee_id == id) {
+			struct weston_output *wet_output = &old->leased_output->base;
+			if (drmModeRevokeLease(drm_fd, id) < 0) {
+				goto out_err;
+			}
+
+			/*
+			 * calling directly weston_output_schedule_repaint()
+			 * would not help. Also, weston_output_enable() will
+			 * eventuall schedule a repaint but without the
+			 * REPAINT_SCHEDULED repaint status set we will continue
+			 * to see the last fb frame of the leased app on the
+			 * screen, hence forcibly the repaint status solves this
+			 * issue.
+			 */
+			wet_output->repaint_status = REPAINT_SCHEDULED;
+			weston_output_enable(wet_output);
+
+			wl_list_remove(&old->link);
+			zwp_kms_lease_request_v1_send_revoked(resource);
+			return;
+		}
+	}
+out_err:
+	zwp_kms_lease_request_v1_send_failed(resource);
+}
+
+static const struct zwp_kms_lease_request_v1_interface
+zwp_kms_lease_request_v1_implementation = {
+	drm_lease_add_connector,
+	drm_lease_add_crtc,
+	drm_lease_add_plane,
+	drm_lease_create,
+	drm_lease_revoke,
+};
+
+static void drm_lease_manager_create_lease_req(struct wl_client *client,
+					       struct wl_resource *resource,
+					       uint32_t params_id)
+{
+	struct lease *lease = zalloc(sizeof(*lease));
+	uint32_t version = wl_resource_get_version(resource);
+
+	/*
+	 * Not arbitrary, normal we should lease  connector/crtc/plane. User
+	 * might be want to share additional overlay plane(s)
+	 */
+	lease->nobjects = 3;
+	lease->objects = calloc(lease->nobjects, sizeof(uint32_t));
+
+	lease->lease_resource = wl_resource_create(client,
+						   &zwp_kms_lease_request_v1_interface,
+						   version, params_id);
+	if (!lease->lease_resource) {
+		free(lease);
+		free(lease->objects);
+		return;
+	}
+
+	lease->drm_backend = wl_resource_get_user_data(resource);
+	wl_resource_set_implementation(lease->lease_resource,
+				       &zwp_kms_lease_request_v1_implementation,
+				       lease, destroy_lease_req);
+}
+
+static void drm_lease_manager_destroy(struct wl_client *client,
+				      struct wl_resource *resource)
+{
+	(void) client;
+	(void) resource;
+}
+
+static const struct zwp_kms_lease_manager_v1_interface drm_lease_manager_interface = {
+	drm_lease_manager_destroy,
+	drm_lease_manager_create_lease_req,
+};
+
+static void
+drm_lease_setup(struct wl_client *client, void *data, uint32_t ver, uint32_t id)
+{
+	struct drm_backend *drm_backend = (struct drm_backend *) data;
+	struct wl_resource *resource;
+
+	resource = wl_resource_create(client, &zwp_kms_lease_manager_v1_interface, ver, id);
+	if (resource == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	wl_resource_set_implementation(resource, &drm_lease_manager_interface, drm_backend, NULL);
+}
+#endif
+
 static struct drm_backend *
 drm_backend_create(struct weston_compositor *compositor,
 		   struct weston_drm_backend_config *config)
@@ -5736,6 +6002,12 @@ 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
+	wl_list_init(&b->leases);
+	wl_global_create(compositor->wl_display,
+			 &zwp_kms_lease_manager_v1_interface, 1, b,
+			 drm_lease_setup);
+#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 67b5d28..1ee5a2c 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -4771,6 +4771,7 @@ weston_output_init(struct weston_output *output,
 	output->name = strdup(name);
 	wl_list_init(&output->link);
 	output->enabled = false;
+	output->leasable = 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 010f1fa..1f2727f 100644
--- a/libweston/compositor.h
+++ b/libweston/compositor.h
@@ -239,6 +239,8 @@ struct weston_output {
 
 	int (*enable)(struct weston_output *output);
 	int (*disable)(struct weston_output *output);
+	/**< this output can be leased */
+	bool leasable;
 };
 
 enum weston_pointer_motion_mask {
-- 
2.9.3



More information about the wayland-devel mailing list