diff options
author | Daniel Stone <daniels@collabora.com> | 2016-11-08 17:46:10 +0000 |
---|---|---|
committer | Daniel Stone <daniels@collabora.com> | 2017-02-07 19:16:32 +0000 |
commit | 8f949cd240d059c94819a48cde1c2f68112ecead (patch) | |
tree | 3d2317945fd9b028ece149b9b187c81a2bdc4bf0 | |
parent | 43483a004375104a330f62aec62c49195d15c985 (diff) |
compositor-drm: Move DPMS into output state
Extend drm_output_state to also cover DPMS, so we can use it to enable
and disable outputs, and always keep a coherent state.
Differential Revision: https://phabricator.freedesktop.org/D1501
Signed-off-by: Daniel Stone <daniels@collabora.com>
-rw-r--r-- | libweston/compositor-drm.c | 139 |
1 files changed, 114 insertions, 25 deletions
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c index 172bea29..a2f3e9c5 100644 --- a/libweston/compositor-drm.c +++ b/libweston/compositor-drm.c @@ -230,6 +230,7 @@ struct drm_edid { struct drm_output_state { struct drm_output *output; + enum dpms_enum dpms; struct wl_list plane_list; }; @@ -300,12 +301,11 @@ struct drm_output { drmModePropertyPtr dpms_prop; uint32_t gbm_format; - enum dpms_enum dpms; - int vblank_pending; int page_flip_pending; int destroy_pending; int disable_pending; + int dpms_off_pending; struct gbm_surface *gbm_surface; struct drm_fb *gbm_cursor_fb[2]; @@ -1106,6 +1106,7 @@ drm_output_state_alloc(struct drm_output *output) struct drm_output_state *state = calloc(1, sizeof(*state)); state->output = output; + state->dpms = WESTON_DPMS_OFF; wl_list_init(&state->plane_list); return state; @@ -1162,6 +1163,23 @@ drm_output_state_free(struct drm_output_state *state) free(state); } +static struct drm_output_state * +drm_output_get_disable_state(struct drm_output *output) +{ + struct drm_output_state *state; + + if (!output->state_cur) + state = drm_output_state_alloc(output); + else + state = drm_output_state_duplicate(output->state_cur, + DRM_OUTPUT_STATE_CLEAR_PLANES); + state->dpms = WESTON_DPMS_OFF; + + return state; +} + +static int drm_output_apply_state(struct drm_output_state *state); + /** * Mark a drm_output_state (the output's last state) as complete. This handles * any post-completion actions such as updating the repaint timer, disabling the @@ -1172,6 +1190,7 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags, unsigned int sec, unsigned int usec) { struct drm_plane_state *ps; + struct drm_output_state *os; struct timespec ts; wl_list_for_each(ps, &output->state_cur->plane_list, link) @@ -1186,6 +1205,9 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags, } else if (output->disable_pending) { weston_output_disable(&output->base); goto out; + } else if (output->dpms_off_pending) { + os = drm_output_get_disable_state(output); + drm_output_apply_state(os); } ts.tv_sec = sec; @@ -1200,6 +1222,7 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags, out: output->destroy_pending = 0; output->disable_pending = 0; + output->dpms_off_pending = 0; } /** @@ -1246,7 +1269,6 @@ drm_output_assign_state(struct drm_output_state *state, } } - static int drm_view_transform_supported(struct weston_view *ev) { @@ -1537,7 +1559,41 @@ drm_output_apply_state(struct drm_output_state *state) struct drm_mode *mode; int ret = 0; - scanout_state = drm_output_state_get_plane(state, scanout_plane); + if (state->dpms != WESTON_DPMS_ON) { + wl_list_for_each(ps, &state->plane_list, link) { + p = ps->plane; + assert(ps->fb == NULL); + assert(ps->output == NULL); + + if (p->type != WDRM_PLANE_TYPE_OVERLAY) + continue; + + ret = drmModeSetPlane(backend->drm.fd, p->plane_id, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + if (ret) + weston_log("drmModeSetPlane failed disable: %m\n"); + } + + if (output->cursor_plane) { + ret = drmModeSetCursor(backend->drm.fd, output->crtc_id, + 0, 0, 0); + if (ret) + weston_log("drmModeSetCursor failed disable: %m\n"); + } + + ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0, + &output->connector_id, 0, NULL); + if (ret) + weston_log("drmModeSetCrtc failed disabling: %m\n"); + + drm_output_assign_state(state, + DRM_OUTPUT_STATE_UPDATE_SYNCHRONOUS); + + return 0; + } + + scanout_state = + drm_output_state_get_existing_plane(state, scanout_plane); /* The legacy SetCrtc API doesn't allow us to do scaling, and the * legacy PageFlip API doesn't allow us to do clipping either. */ @@ -1564,7 +1620,6 @@ drm_output_apply_state(struct drm_output_state *state) weston_log("set mode failed: %m\n"); goto err; } - output->base.set_dpms(&output->base, WESTON_DPMS_ON); } if (drmModePageFlip(backend->drm.fd, output->crtc_id, @@ -1626,6 +1681,18 @@ drm_output_apply_state(struct drm_output_state *state) } } + if (output->dpms_prop && + output->state_cur->dpms != output->state_pending->dpms) { + ret = drmModeConnectorSetProperty(backend->drm.fd, + output->connector_id, + output->dpms_prop->prop_id, + output->state_pending->dpms); + if (ret) { + weston_log("DRM: DPMS: failed property set for %s\n", + output->base.name); + } + } + drm_output_assign_state(output->state_pending, DRM_OUTPUT_STATE_UPDATE_ASYNCHRONOUS); @@ -1655,6 +1722,7 @@ drm_output_repaint(struct weston_output *output_base, output->state_pending = drm_output_state_duplicate(output->state_cur, DRM_OUTPUT_STATE_CLEAR_PLANES); + output->state_pending->dpms = WESTON_DPMS_ON; drm_output_render(output, damage); scanout_state = drm_output_state_get_plane(output->state_pending, @@ -1781,6 +1849,9 @@ drm_output_update_msc(struct drm_output *output, unsigned int seq) } static void +drm_output_destroy(struct weston_output *base); + +static void vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { @@ -1803,9 +1874,6 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, } static void -drm_output_destroy(struct weston_output *base); - -static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { @@ -2749,8 +2817,6 @@ drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output, static void drm_plane_destroy(struct drm_plane *plane) { - drmModeSetPlane(plane->backend->drm.fd, plane->plane_id, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0); drm_plane_state_free(plane->state_cur, true); weston_plane_release(&plane->base); wl_list_remove(&plane->link); @@ -2944,22 +3010,42 @@ static void drm_set_dpms(struct weston_output *output_base, enum dpms_enum level) { struct drm_output *output = to_drm_output(output_base); - struct weston_compositor *ec = output_base->compositor; - struct drm_backend *b = to_drm_backend(ec); int ret; - if (!output->dpms_prop) + + /* As we throw everything away when disabling, just send us back through + * a repaint cycle. */ + if (level == WESTON_DPMS_ON) { + if (output->dpms_off_pending) { + output->dpms_off_pending = 0; + assert(!output->state_cur || + output->state_cur->dpms != level); + } + + if (output->state_cur && output->state_cur->dpms == level) + return; + + weston_log("asked for DPMS on; scheduling repaint\n"); + weston_output_schedule_repaint(output_base); return; + } - ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id, - output->dpms_prop->prop_id, level); - if (ret) { - weston_log("DRM: DPMS: failed property set for %s\n", - output->base.name); + if (!output->state_cur || output->state_cur->dpms == WESTON_DPMS_OFF) + return; + + /* If we've already got a request in the pipeline (common when we've + * just finished a repaint cycle, and it's the animation destroy + * callback which is asking us to disable), then we need to park our + * DPMS request until that request has quiesced. */ + if (output->state_last) { + output->dpms_off_pending = 1; return; } - output->dpms = level; + output->state_pending = drm_output_get_disable_state(output); + ret = drm_output_apply_state(output->state_pending); + if (ret != 0) + weston_log("drm_set_dpms: couldn't disable output?\n"); } static const char * const connector_type_names[] = { @@ -3773,7 +3859,7 @@ static int drm_output_disable(struct weston_output *base) { struct drm_output *output = to_drm_output(base); - struct drm_backend *b = to_drm_backend(base->compositor); + int ret; if (output->page_flip_pending || output->vblank_pending) { output->disable_pending = 1; @@ -3785,11 +3871,12 @@ drm_output_disable(struct weston_output *base) output->disable_pending = 0; - weston_log("Disabling output %s\n", output->base.name); - drmModeSetCrtc(b->drm.fd, output->crtc_id, - 0, 0, 0, 0, 0, NULL); - drm_output_state_free(output->state_cur); - output->state_cur = NULL; + output->state_pending = drm_output_get_disable_state(output); + ret = drm_output_apply_state(output->state_pending); + if (ret) { + weston_log("Couldn't disable output output %s\n", + output->base.name); + } return 0; } @@ -4094,6 +4181,8 @@ session_notify(struct wl_listener *listener, void *data) output->crtc_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } + + /* XXX: invalidate state_cur everywhere */ } } |