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.
Signed-off-by: Daniel Stone <dani...@collabora.com> Reviewed-by: Pekka Paalanen <pekka.paala...@collabora.co.uk> --- libweston/compositor-drm.c | 60 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c index d2ed8343..530b0fd5 100644 --- a/libweston/compositor-drm.c +++ b/libweston/compositor-drm.c @@ -185,6 +185,7 @@ struct drm_backend { void *repaint_data; + bool state_invalid; struct wl_array unused_connectors; struct wl_array unused_crtcs; @@ -345,8 +346,6 @@ struct drm_output { enum dpms_enum dpms; struct backlight *backlight; - bool state_invalid; - int vblank_pending; int page_flip_pending; int destroy_pending; @@ -384,6 +383,26 @@ static struct gl_renderer_interface *gl_renderer; static const char default_seat[] = "seat0"; +static void +wl_array_remove_uint32(struct wl_array *array, uint32_t elm) +{ + uint32_t *pos, *end; + + end = (uint32_t *) ((char *) array->data + array->size); + + wl_array_for_each(pos, array) { + if (*pos != elm) + continue; + + array->size -= sizeof(*pos); + if (pos + 1 == end) + break; + + memmove(pos, pos + 1, (char *) end - (char *) (pos + 1)); + break; + } +} + static inline struct drm_output * to_drm_output(struct weston_output *base) { @@ -1694,7 +1713,7 @@ drm_output_repaint(struct weston_output *output_base, assert(scanout_state->dest_h == scanout_state->src_h >> 16); mode = container_of(output->base.current_mode, struct drm_mode, base); - 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, @@ -1706,9 +1725,7 @@ 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, scanout_state->fb->fb_id, @@ -1815,7 +1832,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); @@ -1984,6 +2001,18 @@ 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) { @@ -1991,6 +2020,8 @@ drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data) DRM_OUTPUT_STATE_UPDATE_ASYNCHRONOUS); } + b->state_invalid = false; + drm_pending_state_free(pending_state); b->repaint_data = NULL; } @@ -3914,7 +3945,8 @@ drm_output_enable(struct weston_output *base) output->connector->count_modes == 0 ? ", built-in" : ""); - output->state_invalid = true; + wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id); + wl_array_remove_uint32(&b->unused_connectors, output->connector_id); return 0; @@ -3993,6 +4025,7 @@ drm_output_disable(struct weston_output *base) { struct drm_output *output = to_drm_output(base); struct drm_backend *b = to_drm_backend(base->compositor); + uint32_t *unused; if (output->page_flip_pending || output->vblank_pending) { output->disable_pending = 1; @@ -4011,6 +4044,11 @@ drm_output_disable(struct weston_output *base) drm_output_state_free(output->state_cur); output->state_cur = drm_output_state_alloc(output, NULL); + unused = wl_array_add(&b->unused_connectors, sizeof(*unused)); + *unused = output->connector_id; + unused = wl_array_add(&b->unused_crtcs, sizeof(*unused)); + *unused = output->crtc_id; + return 0; } @@ -4377,10 +4415,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"); @@ -4768,6 +4803,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); -- 2.14.1 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel