diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index a944eb5b..6af4bc8a 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -623,6 +623,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 { @@ -646,6 +649,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 5b6ade46..f2a3755d 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -1527,10 +1527,14 @@ drm_output_attach_head(struct weston_output *output_base, struct drm_output *output = to_drm_output(output_base); struct drm_backend *b = output->backend; 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; @@ -1555,18 +1559,13 @@ drm_output_detach_head(struct weston_output *output_base, struct weston_head *head_base) { struct drm_output *output = to_drm_output(output_base); - struct drm_backend *b = output->backend; - struct drm_device *device = b->drm; + 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 @@ -2497,6 +2496,8 @@ drm_head_create(struct drm_device *device, drmModeConnector *conn, head->base.backend = &backend->base; + wl_list_init(&head->disable_head_link); + ret = drm_head_update_info(head, conn); if (ret < 0) goto err_update; @@ -2594,6 +2595,8 @@ drm_output_create(struct weston_backend *backend, const char *name) output->device = device; output->crtc = NULL; + wl_list_init(&output->disable_head); + output->max_bpc = 16; #ifdef BUILD_DRM_GBM output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index ea1d8090..d12fa57e 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -1163,6 +1163,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; struct drm_writeback_state *wb_state = output->wb_state; enum writeback_screenshot_state wb_screenshot_state = drm_output_get_writeback_state(output); @@ -1235,6 +1236,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) {