[PATCH v14 17/41] compositor-drm: Atomic modesetting support
Pekka Paalanen
ppaalanen at gmail.com
Tue Jan 23 12:28:38 UTC 2018
On Wed, 20 Dec 2017 12:26:34 +0000
Daniel Stone <daniels at 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 <daniels at collabora.com>
> Co-authored-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
> Co-authored-by: Louis-Francis Ratté-Boulianne <louis-francis.ratte-boulianne at collabora.com>
> Co-authored-by: Derek Foreman <derek.foreman at 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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://lists.freedesktop.org/archives/wayland-devel/attachments/20180123/747d354a/attachment.sig>
More information about the wayland-devel
mailing list