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

Changes since v2:
- accommodate changes due to protocol changes
- use enable/disabled for the output instead of destroy/update_outputs (Daniel 
Stone)
- split into a series, added a client example
- forcing a repaint when giving the lease and not doing a modeset if the output
has been leased avoids blank switching between the lesor and lessee

Signed-off-by: Marius Vlad <marius-cristian.v...@nxp.com>
---
 Makefile.am                |   2 +
 compositor/main.c          |   9 ++
 configure.ac               |   4 +
 libweston/compositor-drm.c | 244 +++++++++++++++++++++++++++++++++++++++++++++
 libweston/compositor.c     |   1 +
 libweston/compositor.h     |   2 +
 6 files changed, 262 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index e224d60..4580d24 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..779a4dd 100644
--- a/compositor/main.c
+++ b/compositor/main.c
@@ -1209,6 +1209,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;
+               weston_log("Enabling lease on output %s\n", output->name);
+       }
+       free(lease);
+
+
        weston_output_enable(output);
 }
 
diff --git a/configure.ac b/configure.ac
index 6f295dc..e1aa0cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -209,6 +209,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 fe59bf5..253d0f7 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
@@ -202,6 +203,21 @@ struct drm_backend {
        uint32_t pageflip_timeout;
 
        bool shutting_down;
+       struct wl_list leases;
+};
+
+struct lease {
+       int leased_fd;
+       uint32_t leased_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 {
@@ -380,6 +396,9 @@ struct drm_output {
        struct wl_listener recorder_frame_listener;
 
        struct wl_event_source *pageflip_timer;
+
+       /** this output has been leased */
+       int leased;
 };
 
 static struct gl_renderer_interface *gl_renderer;
@@ -4837,6 +4856,225 @@ 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_clear_objects(struct lease *lease)
+{
+       memset(lease->objects, 0, sizeof(uint32_t) * lease->tnobjects);
+       lease->tnobjects = 0;
+}
+
+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);
+       int drm_fd = lease->drm_backend->drm.fd;
+       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;
+       }
+
+       lease->leased_fd = drmModeCreateLease(drm_fd, lease->objects,
+                                             lease->tnobjects, 0,
+                                             &lease->leased_id);
+       if (lease->leased_fd < 0) {
+               drm_lease_clear_objects(lease);
+               zwp_kms_lease_request_v1_send_failed(resource);
+               return;
+       }
+
+       lease->leased_output = leased_output;
+       lease->leased_output->leased = true;
+       wl_list_insert(&lease->drm_backend->leases, &lease->link);
+
+       weston_output_disable(&lease->leased_output->base);
+
+       zwp_kms_lease_request_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)
+{
+       (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->leased_id == id) {
+                       struct weston_output *wet_output = 
&old->leased_output->base;
+                       if (drmModeRevokeLease(drm_fd, id) < 0) {
+                               goto out_err;
+                       }
+
+                       old->leased_output->leased = false;
+                       /*
+                        * 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)
@@ -4945,6 +5183,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 dffcba8..900b67d 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;
 };
 
 enum weston_pointer_motion_mask {
-- 
2.9.3

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to