[PATCH weston] RFC: libweston/compositor-drm: Add support for drm-lease.
Daniel Stone
daniel at fooishbar.org
Wed Jan 24 22:07:03 UTC 2018
Hi Marius,
The protocol changes I suggested would require a fair bit of work
here, but I've enclosed a few comments on the implementation.
Also, do you have a client you're using for this somewhere, that we
could use to test?
On 24 January 2018 at 19:11, Marius Vlad <marius-cristian.vlad at nxp.com> wrote:
> @@ -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
Hm, doing this in generic code seems a bit odd.
> +#ifdef HAVE_DRM_LEASE
> +/* hold current leases given */
> +static struct wl_list leases;
This should be under drm_backend.
> +struct drm_display {
> + uint32_t connector_id;
> + uint32_t crtc_id;
> + uint32_t plane_id;
> +};
This seems to get stored but not used after that?
> +struct drm_lease {
> + int leased_fd;
> + uint32_t leased_id;
> + struct wl_list list;
> +};
The convention for embedded struct wl_list which is an element of a
list, rather than a list head, is to call it 'link'.
> +struct drm_lease_data {
> + struct drm_backend *drm_backend;
> + struct udev_device *drm_device;
> +};
This is a bit odd as we only have one udev device in the backend. Like
the lease list though, any data for leases should just live directly
in the drm_backend.
> +#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
If individual leases were a separate object, you could have
drmModeRevokeLease inside the resource destruction handler; this would
then get called when either the client or the compositor was
destroyed.
> +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);
> +}
Rather than destroying the output, I'd be much more comfortable
marking it as disabled or so. There is also a race here: in the DRM
backend, output destruction can be deferred, when a pageflip has not
yet completed.
> +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);
As above, with separate resources, this would just be part of the
resource destruction handler.
> + /* re-initialize outputs */
> + update_outputs(user_data->drm_backend, user_data->drm_device);
Does this mean if update_outputs is called when a lease is active
(e.g. because another output was hotplugged), the backend will try to
take it over again? For me, this points towards needing a field in the
drm_output which indicates that it is currently reserved by a lease.
> + wl_signal_emit(&compositor->wake_signal, compositor);
> + wl_event_source_timer_update(compositor->idle_source,
> + compositor->idle_time * 1000);
I assume this is just to force a repaint. If the existing compositor
API doesn't quite work for this, we should create API which does, or
make sure enabling the output does the right thing. Are you using
desktop-shell, or ... ?
> +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))
Again, this should just be part of drm_backend. No need to hide your
code away! :)
Cheers,
Daniel
More information about the wayland-devel
mailing list