From 6020f478c7738548c815ab0fd1e673c47a537321 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Mon, 5 Feb 2018 15:46:20 +0000 Subject: [PATCH] compositor-drm: Disable unused CRTCs/connectors If we have an unused CRTC or connector, explicitly disable it during the end of the repaint cycle, or when we get VT-switched back in. This commit moves state_invalid from an output property to a backend property, as the unused CRTCs or connectors are likely not tracked by drm_outputs. This matches the mechanics of later commits, where we move to a global repaint-flush hook, applying the state for all outputs in one go. The output state_invalid flag originally provoked full changes on output creation (via setting the flag at output enable time) and session enter. For the new-output case, we will not have any FB in output->state_cur, so we still take the same path in repaint as if state_invalid were set. At session enter, we preserve the existing behaviour: as start_repaint_loop will fail when state_invalid is set, all outputs will be scheduled for repaint together, and state_invalid will not be cleared until after all outputs have been repainted, inside repaint_flush. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen --- libweston/compositor-drm.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c index f2d99b97..22bf75ae 100644 --- a/libweston/compositor-drm.c +++ b/libweston/compositor-drm.c @@ -188,6 +188,8 @@ struct drm_backend { void *repaint_data; + bool state_invalid; + /* Connector and CRTC IDs not used by any enabled output. */ struct wl_array unused_connectors; struct wl_array unused_crtcs; @@ -351,8 +353,6 @@ struct drm_output { enum dpms_enum dpms; struct backlight *backlight; - bool state_invalid; - int vblank_pending; int page_flip_pending; int destroy_pending; @@ -1751,7 +1751,7 @@ drm_output_repaint(struct weston_output *output_base, assert(scanout_state->dest_h == scanout_state->src_h >> 16); mode = to_drm_mode(output->base.current_mode); - if (output->state_invalid || !scanout_plane->state_cur->fb || + if (backend->state_invalid || !scanout_plane->state_cur->fb || scanout_plane->state_cur->fb->stride != scanout_state->fb->stride) { ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, scanout_state->fb->fb_id, @@ -1763,8 +1763,6 @@ drm_output_repaint(struct weston_output *output_base, goto err; } output_base->set_dpms(output_base, WESTON_DPMS_ON); - - output->state_invalid = false; } if (drmModePageFlip(backend->drm.fd, output->crtc_id, @@ -1872,7 +1870,7 @@ drm_output_start_repaint_loop(struct weston_output *output_base) /* Need to smash all state in from scratch; current timings might not * be what we want, page flip might not work, etc. */ - if (output->state_invalid) + if (backend->state_invalid) goto finish_frame; assert(scanout_plane->state_cur->output == output); @@ -2036,12 +2034,26 @@ drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data) struct drm_backend *b = to_drm_backend(compositor); struct drm_pending_state *pending_state = repaint_data; 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) { drm_output_assign_state(output_state, DRM_STATE_APPLY_ASYNC); } + b->state_invalid = false; + drm_pending_state_free(pending_state); b->repaint_data = NULL; } @@ -2662,7 +2674,7 @@ drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mo * sledgehammer modeswitch first, and only later showing new * content. */ - output->state_invalid = true; + b->state_invalid = true; if (b->use_pixman) { drm_output_fini_pixman(output); @@ -4003,8 +4015,6 @@ drm_output_enable(struct weston_output *base) output->connector->count_modes == 0 ? ", built-in" : ""); - output->state_invalid = true; - return 0; err: @@ -4523,10 +4533,7 @@ session_notify(struct wl_listener *listener, void *data) weston_log("activating session\n"); weston_compositor_wake(compositor); weston_compositor_damage_all(compositor); - - wl_list_for_each(output, &compositor->output_list, base.link) - output->state_invalid = true; - + b->state_invalid = true; udev_input_enable(&b->input); } else { weston_log("deactivating session\n"); @@ -4938,6 +4945,7 @@ drm_backend_create(struct weston_compositor *compositor, if (b == NULL) return NULL; + b->state_invalid = true; b->drm.fd = -1; wl_array_init(&b->unused_crtcs); wl_array_init(&b->unused_connectors);