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

Philipp Zabel p.zabel at pengutronix.de
Wed Feb 21 16:16:07 UTC 2018


Hi Marius,

On Wed, 2018-02-21 at 16:49 +0200, Marius Vlad wrote:
> Signed-off-by: Marius Vlad <marius-cristian.vlad at nxp.com>
> ---
>  Makefile.am                |   2 +
>  compositor/main.c          |   9 ++
>  configure.ac               |   4 +
>  libweston/compositor-drm.c | 272 +++++++++++++++++++++++++++++++++++++++++++++
>  libweston/compositor.c     |   1 +
>  libweston/compositor.h     |   2 +
>  6 files changed, 290 insertions(+)
> 
> diff --git a/Makefile.am b/Makefile.am
> index b5c29c0..439fa73 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		\
> diff --git a/compositor/main.c b/compositor/main.c
> index 18810f2..020553f 100644
> --- a/compositor/main.c
> +++ b/compositor/main.c
> @@ -1092,6 +1092,15 @@ 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->lease = true;

Should this be enabled by default for non-desktop outputs?

I suppose this is out of scope for this patchset, but I'd be curious
if adding a non_desktop property to struct weston_output would be
appropriate.

> +		weston_log("Enabling lease on output %s\n", output->name);
> +	}
> +	free(lease);
> +
> +

Spurious empty line.

>  	weston_output_enable(output);
>  }
>  
> diff --git a/configure.ac b/configure.ac
> index e607cd0..97e3661 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 321ee19..a0d195d 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
> @@ -270,6 +271,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 {
> @@ -423,6 +439,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;
> @@ -450,6 +467,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;
> @@ -1402,6 +1421,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
> @@ -1435,6 +1484,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);
> @@ -4979,6 +5034,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;
> @@ -5642,6 +5698,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->lease) {
> +			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)
> @@ -5752,6 +6018,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 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 ca1acc6..685ffab 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 lease;

Maybe call this "leasable" to avoid confusion with "lease" variables of
type struct lease?

regards
Philipp


More information about the wayland-devel mailing list