From 7347bc7a3b2ee0bf8226ba2f15ae4c6a02110bdd Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Thu, 12 Nov 2020 16:59:50 +0800 Subject: [PATCH 28/74] backend-drm: Add dummy output when no screens connected Some clients are not expecting no screens, add a dummy output for them. Signed-off-by: Jeffy Chen --- compositor/main.c | 3 + desktop-shell/shell.c | 7 +- libweston/backend-drm/drm-internal.h | 3 + libweston/backend-drm/drm.c | 203 ++++++++++++++++++++++++++- libweston/backend-drm/kms.c | 3 + libweston/compositor.c | 3 + 6 files changed, 216 insertions(+), 6 deletions(-) diff --git a/compositor/main.c b/compositor/main.c index 128016b..3824404 100644 --- a/compositor/main.c +++ b/compositor/main.c @@ -2337,6 +2337,9 @@ drm_heads_changed(struct wl_listener *listener, void *arg) * output. */ while ((head = weston_compositor_iterate_heads(compositor, head))) { + if (!strcasecmp(weston_head_get_name(head), "dummy")) + continue; + drm_head_update_output_section(head); connected = weston_head_is_connected(head); diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index aedb1e9..c57e7ef 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -4820,10 +4820,6 @@ shell_reposition_view_on_output_change(struct weston_view *view) shsurf = get_shell_surface(view->surface); if (!shsurf) return; - - shsurf->saved_position_valid = false; - set_maximized(shsurf, false); - set_fullscreen(shsurf, false, NULL); } void @@ -4955,6 +4951,9 @@ handle_output_resized(struct wl_listener *listener, void *data) struct weston_output *output = (struct weston_output *)data; struct shell_output *sh_output = find_shell_output_from_weston_output(shell, output); + if (!sh_output) + return; + if (shell->lock_surface) shell->lock_surface->committed(shell->lock_surface, 0, 0); diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 9d24017..67e6dd2 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -354,6 +354,9 @@ struct drm_backend { struct wl_event_source *config_timer; struct stat config_stat; + + struct weston_output *dummy_output; + struct drm_head *dummy_head; }; struct drm_mode { diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 53a3d49..e829d77 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -210,8 +210,14 @@ drm_backend_update_outputs(struct drm_backend *b) { struct weston_output *base, *primary; - if (!b->primary_head) + if (!b->primary_head) { + if (!b->dummy_output->enabled) + weston_output_enable(b->dummy_output); return; + } else { + if (b->dummy_output->enabled) + weston_output_disable(b->dummy_output); + } primary = b->primary_head->base.output; @@ -1245,7 +1251,7 @@ drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output, num_primary - 1 != output->crtc->pipe) continue; - if (plane->type != type) + if (!plane->plane_id || plane->type != type) continue; if (!drm_plane_is_available(plane, output)) continue; @@ -2591,11 +2597,15 @@ drm_head_destroy(struct drm_head *head) { weston_head_release(&head->base); + if (!head->connector.connector_id) + goto out; + drm_connector_fini(&head->connector); if (head->backlight) backlight_destroy(head->backlight); +out: free(head); } @@ -2827,6 +2837,9 @@ drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_dev wl_list_for_each_safe(base, base_next, &b->compositor->head_list, compositor_link) { head = to_drm_head(base); + if (!head->connector.connector_id) + continue; + connector_id = head->connector.connector_id; if (resources_has_connector(resources, connector_id)) @@ -2871,6 +2884,9 @@ drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_dev continue; head = to_drm_head(base); + if (!head->connector.connector_id) + continue; + conn = head->connector.conn; if (conn->connection != DRM_MODE_CONNECTED || @@ -2900,6 +2916,8 @@ drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_dev } match_done: + weston_head_set_connection_status(&b->dummy_head->base, + !b->primary_head); drm_backend_update_outputs(b); weston_compositor_read_presentation_clock(b->compositor, &now); @@ -3072,6 +3090,8 @@ drm_destroy(struct weston_compositor *ec) struct drm_crtc *crtc, *crtc_tmp; struct drm_writeback *writeback, *writeback_tmp; + weston_output_destroy(b->dummy_output); + udev_input_destroy(&b->input); wl_event_source_remove(b->config_timer); @@ -3776,6 +3796,180 @@ config_timer_handler(void *data) return 0; } +static int +drm_dummy_output_start_repaint_loop(struct weston_output *output_base) +{ + weston_output_finish_frame(output_base, NULL, + WP_PRESENTATION_FEEDBACK_INVALID); + + return 0; +} + +static int +drm_dummy_output_repaint(struct weston_output *output_base, + pixman_region32_t *damage, + void *repaint_data) +{ + struct drm_backend *b = to_drm_backend(output_base->compositor); + + wl_signal_emit(&output_base->frame_signal, damage); + + if (b->use_pixman) + return -1; + + /* Switch GL output context to avoid corruption */ + output_base->compositor->renderer->repaint_output(output_base, damage); + return -1; +} + +static int +drm_dummy_output_enable(struct weston_output *output_base) +{ + struct drm_backend *b = to_drm_backend(output_base->compositor); + struct drm_output *output = to_drm_output(output_base); + + if (b->use_pixman) + return 0; + + return drm_output_init_egl(output, b); +} + +static int +drm_dummy_output_disable(struct weston_output *output_base) +{ + struct drm_backend *b = to_drm_backend(output_base->compositor); + struct drm_output *output = to_drm_output(output_base); + + if (!b->use_pixman) + drm_output_fini_egl(output); + + return 0; +} + +static void +drm_dummy_output_destroy(struct weston_output *output_base) +{ + struct drm_output *output = to_drm_output(output_base); + struct drm_plane *plane = output->scanout_plane; + struct weston_mode *mode, *next; + + if (output->base.enabled) + drm_dummy_output_disable(&output->base); + + wl_list_for_each_safe(mode, next, &output_base->mode_list, link) { + wl_list_remove(&mode->link); + free(mode); + } + + drm_plane_state_free(plane->state_cur, true); + weston_plane_release(&plane->base); + wl_list_remove(&plane->link); + weston_drm_format_array_fini(&plane->formats); + free(plane); + + weston_output_release(output_base); + free(output); +} + +static struct weston_output * +drm_dummy_output_create(struct drm_backend *b) +{ + struct drm_output *output; + struct drm_plane *plane; + struct weston_drm_format *fmt; + + output = zalloc(sizeof *output); + if (!output) + return NULL; + + weston_output_init(&output->base, b->compositor, "DUMMY"); + + output->base.enable = drm_dummy_output_enable; + output->base.destroy = drm_dummy_output_destroy; + output->base.disable = drm_dummy_output_disable; + + output->base.start_repaint_loop = drm_dummy_output_start_repaint_loop; + output->base.repaint = drm_dummy_output_repaint; + output->base.set_dpms = NULL; + output->base.switch_mode = NULL; + output->base.gamma_size = 0; + output->base.set_gamma = NULL; + output->base.unavailable = true; + + weston_compositor_add_pending_output(&output->base, b->compositor); + +#ifdef BUILD_DRM_GBM + output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING; + output->gbm_format = DRM_FORMAT_XRGB8888; +#endif + + plane = zalloc(sizeof(*plane)); + if (!plane) { + weston_output_release(&output->base); + free(output); + return NULL; + } + + plane->type = WDRM_PLANE_TYPE_PRIMARY; + plane->backend = b; + plane->state_cur = drm_plane_state_alloc(NULL, plane); + plane->state_cur->complete = true; + + weston_drm_format_array_init(&plane->formats); + fmt = weston_drm_format_array_add_format(&plane->formats, + output->gbm_format); + weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_LINEAR); + + weston_plane_init(&plane->base, b->compositor, 0, 0); + wl_list_insert(&b->plane_list, &plane->link); + + output->scanout_plane = plane; + + return &output->base; +} + +static int drm_backend_init_dummy(struct drm_backend *b) +{ + struct weston_mode *mode; + + b->dummy_output = drm_dummy_output_create(b); + if (!b->dummy_output) + return -1; + + mode = zalloc(sizeof *mode); + if (!mode) + goto err; + + mode->flags = WL_OUTPUT_MODE_CURRENT; + mode->width = 1920; + mode->height = 1080; + mode->refresh = 60 * 1000LL; + + wl_list_insert(b->dummy_output->mode_list.prev, &mode->link); + + b->dummy_output->current_mode = mode; + + weston_output_set_scale(b->dummy_output, 1); + weston_output_set_transform(b->dummy_output, + WL_OUTPUT_TRANSFORM_NORMAL); + + b->dummy_head = zalloc(sizeof *b->dummy_head); + if (!b->dummy_head) + goto err; + + weston_head_init(&b->dummy_head->base, "DUMMY"); + weston_head_set_monitor_strings(&b->dummy_head->base, + "DUMMY", "DUMMY", "DUMMY"); + weston_compositor_add_head(b->compositor, &b->dummy_head->base); + weston_output_attach_head(b->dummy_output, &b->dummy_head->base); + + return 0; +err: + drm_dummy_output_destroy(b->dummy_output); + b->dummy_output = NULL; + return -1; +} + enum drm_head_mode { DRM_HEAD_MODE_DEFAULT, DRM_HEAD_MODE_PRIMARY, @@ -4007,6 +4201,11 @@ drm_backend_create(struct weston_compositor *compositor, goto err_sprite; } + if (drm_backend_init_dummy(b) < 0) { + weston_log("Failed to init dummy output\n"); + goto err_udev_input; + } + wl_list_init(&b->writeback_connector_list); if (drm_backend_update_connectors(b, drm_device) < 0) { weston_log("Failed to create heads for %s\n", b->drm.filename); diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index 4b5ba42..a3c55bd 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -1170,6 +1170,9 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state, continue; head = to_drm_head(head_base); + if (head == b->dummy_head) + continue; + connector_id = head->connector.connector_id; drm_debug(b, "\t\t[atomic] disabling inactive head %s\n", diff --git a/libweston/compositor.c b/libweston/compositor.c index 121871c..67766df 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -6436,6 +6436,9 @@ weston_output_set_color_transforms(struct weston_output *output) struct weston_color_transform *sRGB_to_blend = NULL; bool ok; + if (!cm) + return false; + ok = cm->get_output_color_transform(cm, output, &blend_to_output); ok = ok && cm->get_sRGB_to_output_color_transform(cm, output, &sRGB_to_output); -- 2.20.1