Hi Daniel,

On Tue, 2017-09-26 at 18:15 +0100, Daniel Stone wrote:
> Split repaint into two stages, as implied by the grouped-repaint
> interface: drm_output_repaint generates the repaint state only, and
> drm_repaint_flush applies it.
> 
> This also moves DPMS into output state. Previously, the usual way to
> DPMS off was that repaint would be called and apply its state, followed
> by set_dpms being called afterwards to push the DPMS state separately.
> As this happens before the repaint_flush hook, with no change to DPMS we
> would set DPMS off, then immediately re-enable the output by posting the
> repaint. Not ideal.
> 
> Moving DPMS application at the same time complicates this patch, but I
> couldn't find a way to split it; if we keep set_dpms before begin_flush
> then we break DPMS off, or if we try to move DPMS to output state before
> using the repaint flush, we get stuck as the repaint hook generates an
> asynchronous state update, followed immediately by set_dpms generating a
> synchronous state update.
> 
> > Signed-off-by: Daniel Stone <dani...@collabora.com>
> ---
>  libweston/compositor-drm.c | 313 
> ++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 240 insertions(+), 73 deletions(-)
> 
> diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
> index 530b0fd5..6c1c6881 100644
> --- a/libweston/compositor-drm.c
> +++ b/libweston/compositor-drm.c
[...]
> @@ -1360,7 +1397,6 @@ drm_output_assign_state(struct drm_output_state *state,
> >     }
>  }
>  
> -
>  static int
>  drm_view_transform_supported(struct weston_view *ev)
>  {
> @@ -1653,37 +1689,20 @@ drm_waitvblank_pipe(struct drm_output *output)
>  }
>  
>  static int
> -drm_output_repaint(struct weston_output *output_base,
> > -              pixman_region32_t *damage,
> > -              void *repaint_data)
> +drm_output_apply_state(struct drm_output_state *state)
>  {
> > -   struct drm_pending_state *pending_state = repaint_data;
> -     struct drm_output_state *state = NULL;

Here state was initialized ...

> > -   struct drm_output *output = to_drm_output(output_base);
> > -   struct drm_backend *backend =
> > -           to_drm_backend(output->base.compositor);
> > +   struct drm_output *output = state->output;
> > +   struct drm_backend *backend = to_drm_backend(output->base.compositor);
> >     struct drm_plane *scanout_plane = output->scanout_plane;
> > +   struct drm_property_info *dpms_prop =
> > +           &output->props_conn[WDRM_CONNECTOR_DPMS];
> >     struct drm_plane_state *scanout_state;
> >     struct drm_plane_state *ps;
> >     struct drm_plane *p;
> >     struct drm_mode *mode;
> > +   struct timespec now;
> >     int ret = 0;
>  
> > -   if (output->disable_pending || output->destroy_pending)
> -             goto err;

... so this may return ...

> -
> > -   assert(!output->state_last);
> -
> > -   /* If planes have been disabled in the core, we might not have
> > -    * hit assign_planes at all, so might not have valid output state
> > -    * here. */
> > -   state = drm_pending_state_get_output(pending_state, output);
> > -   if (!state)
> > -           state = drm_output_state_duplicate(output->state_cur,
> > -                                              pending_state,
> > -                                              
> > DRM_OUTPUT_STATE_CLEAR_PLANES);
> -
> -
> >     /* If disable_planes is set then assign_planes() wasn't
> >      * called for this render, so we could still have a stale
>        * cursor plane set up.
[...]
> @@ -1790,13 +1844,101 @@ drm_output_repaint(struct weston_output *output_base,
> >             }
> >     }
>  
> > +   if (dpms_prop->prop_id && state->dpms != output->state_cur->dpms) {
> > +           ret = drmModeConnectorSetProperty(backend->drm.fd,
> > +                                             output->connector_id,
> > +                                             dpms_prop->prop_id,
> > +                                             state->dpms);
> > +           if (ret) {
> > +                   weston_log("DRM: DPMS: failed property set for %s\n",
> > +                              output->base.name);
> > +           }
> > +   }
> +
> > +   drm_output_assign_state(state, DRM_OUTPUT_STATE_UPDATE_ASYNCHRONOUS);
> +
> >     return 0;
>  
>  err:
> >     output->cursor_view = NULL;
> -
>       drm_output_state_free(state);

... without causing issues here.

> > +   return -1;
> +}
> +
> +static int
> +drm_pending_state_apply(struct drm_pending_state *pending_state)
> +{
> > +   struct drm_backend *b = pending_state->backend;
> > +   struct drm_output_state *output_state, *tmp;
> > +   uint32_t *unused;
> +
> > +   if (b->state_invalid) {
> > +           /* 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 we aren't using. This also disables
> > +            * all connectors on these CRTCs, so we don't need to do that
> > +            * separately with the pre-atomic API. */
> > +           wl_array_for_each(unused, &b->unused_crtcs)
> > +                   drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
> > +                                  NULL);
> > +   }
> +
> > +   wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
> > +                         link) {
> > +           struct drm_output *output = output_state->output;
> > +           int ret;
> +
> > +           ret = drm_output_apply_state(output_state);
> > +           if (ret != 0) {
> > +                   weston_log("Couldn't apply state for output %s\n",
> > +                              output->base.name);
> > +           }
> > +   }
> +
> > +   b->state_invalid = false;
> +
> > +   assert(wl_list_empty(&pending_state->output_list));
>  
> > +   drm_pending_state_free(pending_state);
> +
> > +   return 0;
> +}
> +
> +static int
> +drm_output_repaint(struct weston_output *output_base,
> > +              pixman_region32_t *damage,
> > +              void *repaint_data)
> +{
> > +   struct drm_pending_state *pending_state = repaint_data;
> > +   struct drm_output *output = to_drm_output(output_base);
> +     struct drm_output_state *state;

Here state is not initialized anymore ...

> > +   struct drm_plane_state *scanout_state;
> +
> > +   if (output->disable_pending || output->destroy_pending)
> +             goto err;

... so this error path ...

> +
> > +   assert(!output->state_last);
> +
> > +   /* If planes have been disabled in the core, we might not have
> > +    * hit assign_planes at all, so might not have valid output state
> > +    * here. */
> > +   state = drm_pending_state_get_output(pending_state, output);
> > +   if (!state)
> > +           state = drm_output_state_duplicate(output->state_cur,
> > +                                              pending_state,
> > +                                              
> > DRM_OUTPUT_STATE_CLEAR_PLANES);
> > +   state->dpms = WESTON_DPMS_ON;
> +
> > +   drm_output_render(state, damage);
> > +   scanout_state = drm_output_state_get_plane(state,
> > +                                              output->scanout_plane);
> > +   if (!scanout_state || !scanout_state->fb)
> > +           goto err;
> +
> > +   return 0;
> +
> +err:
> +     drm_output_state_free(state);

... will cause drm_output_state_free to be called with uninitialized state.

> >     return -1;
>  }

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

Reply via email to