-----Original Message-----
From: Daniel Stone [mailto:[email protected]] 
Sent: Thursday, January 25, 2018 12:07 AM
To: Marius-cristian Vlad <[email protected]>
Cc: [email protected]; Pekka Paalanen 
<[email protected]>; Keith Packard <[email protected]>
Subject: Re: [PATCH weston] RFC: libweston/compositor-drm: Add support for 
drm-lease.

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.

[mvlad] No problem. Thanks for taking the time to review it. I'll adjust it 
accordingly. 

Also, do you have a client you're using for this somewhere, that we could use 
to test?

[mvlad] Indeed, would've make sense to add a test client for it. Will add it.  

On 24 January 2018 at 19:11, Marius Vlad <[email protected]> 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.

[mvlad] Not sure what you mean. Checking for "lease" in config file or the 
ifdefs? 

> +#ifdef HAVE_DRM_LEASE
> +/* hold current leases given */
> +static struct wl_list leases;

This should be under drm_backend.

[mvlad] Initially I wanted to have this isolated from the drm compositor, then 
I realized I needed some way
to disable/destroy the output. Having them inside drm_backend makes much more 
sense. 

> +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?

[mvlad] A helper struct to store the objects we want to pass. Easier to pass as 
a whole.  

> +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'.

[mvlad] OK, will fix that. 

> +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.

[mvlad] Understood.

> +#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.

[mvlad] This sounds nice. Will give it a try. 

> +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.

[mvlad] Assuming that you are referring to weston_output_disable, the backends 
output disable callback 
-- drm_output_disable will eventually disable the output. With the output 
disabled the client will no longer be able to use the connector. It could also 
be that my testing version of the client assumes that the output will not be 
disabled (hence forth 
it can question the leased fd for connector/crtc/plane). From my tests 
destroying the output seem to be the most reliable. 

> +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.

[mvlad] Right, will do. 

> +                       /* 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.

[mvlad] Oops, indeed it seems so. Yes, a field in drm_output seems the right 
way to do it. Thanks for spotting this.  


> +                       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 ... ?

[mvlad] Indeed. What I've observed is that it could be some time until the 
repaint fires and in that time the fb of the client can still be present on 
that output. Forcing a repaint seems to fix that. There's also a longer 
explanation: If the client destroyes the fb this would cause the connector to 
be disabled. If weston can reclaim the connector after it has been disabled 
there's no issue. I will need to check this once more, it might not be needed 
after all.  

> +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! 
:)

[mvlad] Right, will do.

Cheers,
Daniel
_______________________________________________
wayland-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to