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 <[email protected]> --- 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_@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 _______________________________________________ wayland-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/wayland-devel
