[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