diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 1ee1974c..d2cc7a5b 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -519,6 +519,9 @@ struct drm_head { drmModeModeInfo inherited_mode; /**< Original mode on the connector */ uint32_t inherited_max_bpc; /**< Original max_bpc on the connector */ uint32_t inherited_crtc_id; /**< Original CRTC assignment */ + + /* drm_output::disable_head */ + struct wl_list disable_head_link; }; struct drm_crtc { @@ -541,6 +544,9 @@ struct drm_output { struct drm_device *device; struct drm_crtc *crtc; + /* drm_head::disable_head_link */ + struct wl_list disable_head; + bool page_flip_pending; bool atomic_complete_pending; bool destroy_pending; diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 7d607ca6..52996d50 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -1299,10 +1299,14 @@ drm_output_attach_head(struct weston_output *output_base, { struct drm_backend *b = to_drm_backend(output_base->compositor); struct drm_device *device = b->drm; + struct drm_head *head = to_drm_head(head_base); if (wl_list_length(&output_base->head_list) >= MAX_CLONED_CONNECTORS) return -1; + wl_list_remove(&head->disable_head_link); + wl_list_init(&head->disable_head_link); + if (!output_base->enabled) return 0; @@ -1326,18 +1330,14 @@ static void drm_output_detach_head(struct weston_output *output_base, struct weston_head *head_base) { - struct drm_backend *b = to_drm_backend(output_base->compositor); - struct drm_device *device = b->drm; + struct drm_output *output = to_drm_output(output_base); + struct drm_head *head = to_drm_head(head_base); if (!output_base->enabled) return; - /* Need to go through modeset to drop connectors that should no longer - * be driven. */ - /* XXX: Ideally we'd do this per-output, not globally. */ - device->state_invalid = true; - - weston_output_schedule_repaint(output_base); + /* Drop connectors that should no longer be driven on next repaint. */ + wl_list_insert(&output->disable_head, &head->disable_head_link); } int @@ -2249,6 +2249,8 @@ drm_head_create(struct drm_device *device, drmModeConnector *conn, head->base.backend_id = drm_head_destroy; + wl_list_init(&head->disable_head_link); + ret = drm_head_update_info(head, conn); if (ret < 0) goto err_update; @@ -2322,6 +2324,8 @@ drm_output_create(struct weston_compositor *compositor, const char *name) output->device = device; output->crtc = NULL; + wl_list_init(&output->disable_head); + output->max_bpc = 16; output->gbm_format = DRM_FORMAT_INVALID; #ifdef BUILD_DRM_GBM diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index 0118efa1..b6c7fe5f 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -951,6 +951,7 @@ drm_output_apply_state_atomic(struct drm_output_state *state, struct drm_plane_state *plane_state; struct drm_mode *current_mode = to_drm_mode(output->base.current_mode); struct drm_head *head; + struct drm_head *tmp; int ret = 0; drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n", @@ -987,6 +988,14 @@ drm_output_apply_state_atomic(struct drm_output_state *state, wl_list_for_each(head, &output->base.head_list, base.output_link) ret |= connector_add_prop(req, &head->connector, WDRM_CONNECTOR_CRTC_ID, 0); + + wl_list_for_each_safe(head, tmp, &output->disable_head, + disable_head_link) { + ret |= connector_add_prop(req, &head->connector, + WDRM_CONNECTOR_CRTC_ID, 0); + wl_list_remove(&head->disable_head_link); + wl_list_init(&head->disable_head_link); + } } wl_list_for_each(head, &output->base.head_list, base.output_link) {