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.
Differential Revision: https://phabricator.freedesktop.org/D1507 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> --- libweston/compositor-drm.c | 208 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 203 insertions(+), 5 deletions(-) diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c index b33d519..2f9415c 100644 --- a/libweston/compositor-drm.c +++ b/libweston/compositor-drm.c @@ -349,6 +349,7 @@ struct drm_output { int vblank_pending; int page_flip_pending; + int atomic_complete_pending; int destroy_pending; int disable_pending; int dpms_off_pending; @@ -1376,6 +1377,7 @@ drm_output_assign_state(struct drm_output_state *state, enum drm_output_state_update_mode mode) { struct drm_output *output = state->output; + struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_plane_state *plane_state; assert(!output->state_last); @@ -1388,6 +1390,9 @@ drm_output_assign_state(struct drm_output_state *state, output->state_cur = state; output->state_pending = NULL; + if (b->atomic_modeset && mode == DRM_OUTPUT_STATE_UPDATE_ASYNCHRONOUS) + output->atomic_complete_pending = 1; + /* Replace state_cur on each affected plane with the new state, being * careful to dispose of orphaned (but only orphaned) previous state. * If the previous state is not orphaned (still has an output_state @@ -1399,7 +1404,8 @@ drm_output_assign_state(struct drm_output_state *state, drm_plane_state_free(plane->state_cur, true); plane->state_cur = plane_state; - if (mode != DRM_OUTPUT_STATE_UPDATE_ASYNCHRONOUS) + if (mode != DRM_OUTPUT_STATE_UPDATE_ASYNCHRONOUS || + b->atomic_modeset) continue; if (plane->type == WDRM_PLANE_TYPE_OVERLAY) @@ -1686,7 +1692,7 @@ drm_waitvblank_pipe(struct drm_output *output) } static int -drm_output_apply_state(struct drm_output_state *state) +drm_output_apply_state_legacy(struct drm_output_state *state) { struct drm_output *output = state->output; struct drm_backend *backend = to_drm_backend(output->base.compositor); @@ -1844,6 +1850,168 @@ err: return -1; } +#ifdef HAVE_DRM_ATOMIC +static int +crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output, + enum wdrm_crtc_property prop, uint64_t val) +{ + struct property_item *item = &output->props_crtc.item[prop]; + int ret; + + if (!item) + return -1; + + ret = drmModeAtomicAddProperty(req, output->crtc_id, + item->drm_prop->prop_id, val); + return (ret <= 0) ? -1 : 0; +} + +static int +connector_add_prop(drmModeAtomicReq *req, struct drm_output *output, + enum wdrm_connector_property prop, uint64_t val) +{ + struct property_item *item = &output->props_conn.item[prop]; + int ret; + + if (!item) + return -1; + + ret = drmModeAtomicAddProperty(req, output->connector_id, + item->drm_prop->prop_id, val); + return (ret <= 0) ? -1 : 0; +} + +static int +plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane, + enum wdrm_plane_property prop, uint64_t val) +{ + struct property_item *item = &plane->props.item[prop]; + int ret; + + if (!item) + return -1; + + ret = drmModeAtomicAddProperty(req, plane->plane_id, + item->drm_prop->prop_id, val); + return (ret <= 0) ? -1 : 0; +} + +static int +drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode) +{ + int ret; + + if (mode->blob_id) + return 0; + + ret = drmModeCreatePropertyBlob(backend->drm.fd, + &mode->mode_info, + sizeof(mode->mode_info), + &mode->blob_id); + if (ret != 0) + weston_log("failed to create mode property blob: %m\n"); + + return ret; +} + +static int +drm_output_apply_state_atomic(struct drm_output_state *state) +{ + struct drm_output *output = state->output; + struct drm_backend *backend = to_drm_backend(output->base.compositor); + struct drm_plane_state *plane_state; + drmModeAtomicReq *req = drmModeAtomicAlloc(); + struct drm_mode *current_mode = to_drm_mode(output->base.current_mode); + uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK; + int ret = 0; + + if (!req) + return -1; + + 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; + } + } + + if (drmModeAtomicCommit(backend->drm.fd, req, flags, output) != 0) { + weston_log("couldn't commit new state: %m\n"); + goto err; + } + + drm_output_assign_state(state, DRM_OUTPUT_STATE_UPDATE_ASYNCHRONOUS); + + return 0; + +err: + drm_output_state_free(state); + output->state_pending = NULL; + return -1; +} +#endif + +static int +drm_output_apply_state(struct drm_output_state *state) +{ +#ifdef HAVE_DRM_ATOMIC + struct drm_backend *b = to_drm_backend(state->output->base.compositor); + + if (b->atomic_modeset) + return drm_output_apply_state_atomic(state); + else +#endif + return drm_output_apply_state_legacy(state); +} + static int drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) @@ -1977,9 +2145,12 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, struct drm_plane_state *ps = (struct drm_plane_state *) data; struct drm_output_state *os = ps->output_state; struct drm_output *output = os->output; + struct drm_backend *b = to_drm_backend(output->base.compositor); uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION | WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; + assert(!b->atomic_modeset); + drm_output_update_msc(output, frame); output->vblank_pending--; assert(output->vblank_pending >= 0); @@ -1997,12 +2168,14 @@ page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { struct drm_output *output = data; + struct drm_backend *b = to_drm_backend(output->base.compositor); uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC | WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION | WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; drm_output_update_msc(output, frame); + assert(!b->atomic_modeset); assert(output->page_flip_pending); output->page_flip_pending = 0; @@ -2012,6 +2185,25 @@ page_flip_handler(int fd, unsigned int frame, drm_output_update_complete(output, flags, sec, usec); } +static void +atomic_flip_handler(int fd, unsigned int frame, + unsigned int sec, unsigned int usec, void *data) +{ + struct drm_output *output = data; + struct drm_backend *b = to_drm_backend(output->base.compositor); + uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC | + WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION | + WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; + + drm_output_update_msc(output, frame); + + assert(b->atomic_modeset); + assert(output->atomic_complete_pending); + output->atomic_complete_pending = 0; + + drm_output_update_complete(output, flags, sec, usec); +} + static uint32_t drm_output_check_plane_format(struct drm_plane *p, struct weston_view *ev, struct gbm_bo *bo) @@ -2633,11 +2825,15 @@ 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) { + struct drm_backend *b = data; drmEventContext evctx; memset(&evctx, 0, sizeof evctx); evctx.version = DRM_EVENT_CONTEXT_VERSION; - evctx.page_flip_handler = page_flip_handler; + if (b->atomic_modeset) + evctx.page_flip_handler = atomic_flip_handler; + else + evctx.page_flip_handler = page_flip_handler; evctx.vblank_handler = vblank_handler; drmHandleEvent(fd, &evctx); @@ -3956,7 +4152,8 @@ drm_output_destroy(struct weston_output *base) struct drm_output *output = to_drm_output(base); struct drm_backend *b = to_drm_backend(base->compositor); - if (output->page_flip_pending || output->vblank_pending) { + if (output->page_flip_pending || output->vblank_pending || + output->atomic_complete_pending) { output->destroy_pending = 1; weston_log("destroy output while page flip pending\n"); return; @@ -3989,7 +4186,8 @@ drm_output_disable(struct weston_output *base) struct drm_output *output = to_drm_output(base); int ret; - if (output->page_flip_pending || output->vblank_pending) { + if (output->page_flip_pending || output->vblank_pending || + output->atomic_complete_pending) { output->disable_pending = 1; return -1; } -- 2.9.3 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel