On Wed, 20 Dec 2017 12:26:34 +0000
Daniel Stone <dani...@collabora.com> wrote:

> Add support for using the atomic-modesetting API to apply output state.
> Unlike previous series, this commit does not unflip sprites_are_broken,
> until further work has been done with assign_planes to make it reliable.
> 
> Signed-off-by: Daniel Stone <dani...@collabora.com>
> Co-authored-by: Pekka Paalanen <pekka.paala...@collabora.co.uk>
> Co-authored-by: Louis-Francis Ratté-Boulianne 
> <louis-francis.ratte-boulia...@collabora.com>
> Co-authored-by: Derek Foreman <derek.fore...@collabora.co.uk>
> ---
>  configure.ac               |   2 +-
>  libweston/compositor-drm.c | 504 
> ++++++++++++++++++++++++++++++++++++++-------
>  2 files changed, 431 insertions(+), 75 deletions(-)

> diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
> index cb8f00e95..d5955c9ca 100644
> --- a/libweston/compositor-drm.c
> +++ b/libweston/compositor-drm.c

> +static int
> +drm_output_apply_state_atomic(struct drm_output_state *state,
> +                           drmModeAtomicReq *req,
> +                           uint32_t *flags)
> +{
> +     struct drm_output *output = state->output;
> +     struct drm_backend *backend = to_drm_backend(output->base.compositor);
> +     struct drm_plane_state *plane_state;
> +     struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
> +     int ret = 0;
> +
> +     if (state->dpms != output->state_cur->dpms)
> +             *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
> +
> +     if (state->dpms == WESTON_DPMS_ON) {
> +             ret = drm_mode_ensure_blob(backend, current_mode);
> +             if (ret != 0)
> +                     goto err;
> +
> +             ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
> +                                  current_mode->blob_id);
> +             ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
> +             ret |= connector_add_prop(req, output, WDRM_CONNECTOR_CRTC_ID,
> +                                       output->crtc_id);
> +     } else {
> +             ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
> +             ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
> +             ret |= connector_add_prop(req, output, WDRM_CONNECTOR_CRTC_ID,
> +                                       0);
> +     }
> +
> +     if (ret != 0) {
> +             weston_log("couldn't set atomic CRTC/connector state\n");
> +             goto err;
> +     }
> +
> +     wl_list_for_each(plane_state, &state->plane_list, link) {
> +             struct drm_plane *plane = plane_state->plane;
> +
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
> +                                   plane_state->fb ? plane_state->fb->fb_id 
> : 0);
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
> +                                   plane_state->fb ? output->crtc_id : 0);
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
> +                                   plane_state->src_x);
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
> +                                   plane_state->src_y);
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
> +                                   plane_state->src_w);
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
> +                                   plane_state->src_h);
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
> +                                   plane_state->dest_x);
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
> +                                   plane_state->dest_y);
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
> +                                   plane_state->dest_w);
> +             ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
> +                                   plane_state->dest_h);
> +
> +             if (ret != 0) {
> +                     weston_log("couldn't set plane state\n");
> +                     goto err;
> +             }
> +     }
> +
> +     return 0;
> +
> +err:
> +     drm_output_state_free(state);
> +     return -1;
> +}
> +
> +static int
> +drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
> +                            enum drm_state_apply_mode mode)
> +{
> +     struct drm_backend *b = pending_state->backend;
> +     struct drm_output_state *output_state, *tmp;
> +     struct drm_plane *plane;
> +     drmModeAtomicReq *req = drmModeAtomicAlloc();
> +     uint32_t flags = 0;
> +     int ret = 0;
> +
> +     if (!req)
> +             return -1;
> +
> +     if (b->state_invalid) {
> +             uint32_t *unused;
> +             int err;
> +
> +             /* If we need to reset all our state (e.g. because we've
> +              * just started, or just been VT-switched in), explicitly
> +              * disable all the CRTCs and connectors we aren't using. */
> +             wl_array_for_each(unused, &b->unused_connectors) {

> +             }
> +
> +             wl_array_for_each(unused, &b->unused_crtcs) {

> +             }
> +
> +             /* Disable all the planes; planes which are being used will
> +              * override this state in the output-state application. */
> +             wl_list_for_each(plane, &b->plane_list, link) {
> +                     plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
> +                     plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
> +             }
> +
> +             flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
> +     }
> +
> +     wl_list_for_each(output_state, &pending_state->output_list, link) {

Hi,

this should probably be wl_list_for_each_safe(), because the error path
of drm_output_apply_state_atomic() will drm_output_state_free().


> +             if (mode == DRM_STATE_APPLY_SYNC)
> +                     assert(output_state->dpms == WESTON_DPMS_OFF);
> +             ret |= drm_output_apply_state_atomic(output_state, req, &flags);
> +     }
> +
> +     if (ret != 0) {
> +             weston_log("atomic: couldn't compile atomic state\n");
> +             goto out;
> +     }


>  
> +#ifdef HAVE_DRM_ATOMIC
> +static void
> +atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
> +                 unsigned int usec, unsigned int crtc_id, void *data)
> +{
> +     struct drm_backend *b = data;
> +     struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
> +     uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
> +                      WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
> +                      WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
> +
> +     /* During the initial modeset, we can disable CRTCs which we don't
> +      * actually handle during normal operation; this will give us events
> +      * for unknown outputs. Ignore them. */
> +     if (!output)
> +             return;

Did you consider that drm_output_find_by_crtc() will search also the
pending_output_list? Which means outputs we don't drive.

Maybe the check should be (!output || !output->base.enabled)?

> +
> +     drm_output_update_msc(output, frame);
> +
> +     assert(b->atomic_modeset);
> +     assert(output->atomic_complete_pending);

I think the above would explode here at least, and maybe confuse also
elsewhere.

> +     output->atomic_complete_pending = 0;
> +
> +     drm_output_update_complete(output, flags, sec, usec);
> +}
> +#endif
> +
>  static uint32_t
>  drm_output_check_plane_format(struct drm_plane *p,
>                              struct weston_view *ev, struct gbm_bo *bo)
> @@ -2868,11 +3250,19 @@ drm_output_switch_mode(struct weston_output 
> *output_base, struct weston_mode *mo
>  static int
>  on_drm_input(int fd, uint32_t mask, void *data)
>  {
> +#ifdef HAVE_DRM_ATOMIC
> +     struct drm_backend *b = data;
> +#endif
>       drmEventContext evctx;
>  
>       memset(&evctx, 0, sizeof evctx);
> -     evctx.version = 2;
> -     evctx.page_flip_handler = page_flip_handler;
> +     evctx.version = 3;

I believe this is effectively missing something like:

#ifdef HAVE_DRM_ATOMIC
        evctx.version = 3;
#else
        evctx.version = 2;
#endif

Otherwise, if Weston is built against libdrm without HAVE_DRM_ATOMIC,
then drmEventContext may not contain the field page_flip_handler2. If
libdrm is then upgraded without recompiling Weston, evctx.version=3
means libdrm will try to inspect page_flip_handler2 which has no memory
allocated and will get arbitrary stack data instead.


> +#ifdef HAVE_DRM_ATOMIC
> +     if (b->atomic_modeset)
> +             evctx.page_flip_handler2 = atomic_flip_handler;
> +     else
> +#endif
> +             evctx.page_flip_handler = page_flip_handler;
>       evctx.vblank_handler = vblank_handler;
>       drmHandleEvent(fd, &evctx);
>  

Aside from the above and Philipp's comments, the patch looks ok.


Thanks,
pq

Attachment: pgpnb3nD9_c_e.pgp
Description: OpenPGP digital signature

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

Reply via email to