Weston support hotplug. Signed-off-by: Leo Lu diff -purN a/desktop-shell/shell.c b/desktop-shell/shell.c --- a/desktop-shell/shell.c 2023-07-04 09:48:32.408894461 +0800 +++ b/desktop-shell/shell.c 2023-07-04 09:48:50.988079473 +0800 @@ -3051,6 +3051,10 @@ panel_committed(struct weston_surface *e view = container_of(es->views.next, struct weston_view, surface_link); + /* The output might be unavaiable */ + if (!view->output) + return; + get_panel_size(shell, view, &width, &height); switch (shell->panel_position) { case WESTON_DESKTOP_SHELL_PANEL_POSITION_TOP: @@ -4306,6 +4310,7 @@ check_desktop_shell_crash_too_early(stru if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) return false; +#if 0 /* * If the shell helper client dies before the session has been * up for roughly 30 seconds, better just make Weston shut down, @@ -4321,7 +4326,7 @@ check_desktop_shell_crash_too_early(stru return true; } - +#endif return false; } diff -purN a/include/libweston/libweston.h b/include/libweston/libweston.h --- a/include/libweston/libweston.h 2023-07-04 09:48:32.436887036 +0800 +++ b/include/libweston/libweston.h 2023-07-04 09:48:50.992078460 +0800 @@ -2160,8 +2160,8 @@ weston_compositor_load_icc_file(struct w const char *path); void -weston_compositor_reflow_outputs(struct weston_compositor *compositor, - struct weston_output *resized_output, int delta_width); +weston_compositor_reflow_outputs(struct weston_compositor *compositor); + #ifdef __cplusplus } diff -purN a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c --- a/libweston/backend-drm/drm.c 2023-07-04 09:48:32.456881733 +0800 +++ b/libweston/backend-drm/drm.c 2023-07-04 09:48:50.992078460 +0800 @@ -67,6 +67,8 @@ #include "linux-explicit-synchronization.h" #include +static int + drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_device); static const char default_seat[] = "seat0"; static inline bool @@ -88,9 +90,7 @@ static void drm_backend_update_outputs(struct drm_backend *b) { struct weston_output *primary,*base; - struct weston_output *output; - int x, y, next_x, next_y; - next_x = next_y = 0; + if (!b->primary_head) return; @@ -122,15 +122,8 @@ drm_backend_update_outputs(struct drm_ba wl_list_remove(&primary->link); wl_list_insert(&b->compositor->output_list, &primary->link); - wl_list_for_each(output, &b->compositor->output_list, link) { - if (output->destroying) - continue; - - x = next_x; - y = next_y; - next_x += output->width; - weston_output_move(output, x, y); - } + /* Reflow outputs */ + weston_compositor_reflow_outputs(b->compositor); weston_compositor_damage_all(b->compositor); } @@ -349,8 +342,11 @@ drm_output_update_complete(struct drm_ou wl_list_for_each(ps, &output->state_cur->plane_list, link) ps->complete = true; - drm_output_state_free(output->state_last); - output->state_last = NULL; + if (output->state_last) { + drm_output_state_free(output->state_last); + output->state_last = NULL; + } + if (output->destroy_pending) { output->destroy_pending = false; @@ -684,7 +680,7 @@ drm_output_repaint(struct weston_output err: drm_output_state_free(state); - return -1; + return 0; } /* Determine the type of vblank synchronization to use for the output. @@ -846,7 +842,7 @@ drm_repaint_flush(struct weston_composit ret = drm_pending_state_apply(pending_state); if (ret != 0) - weston_log("repaint-flush failed: %s\n", strerror(errno)); + // weston_log("repaint-flush failed: %s\n", strerror(errno)); drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state); b->repaint_data = NULL; @@ -2553,6 +2549,49 @@ drm_head_is_available(struct weston_head return true; } +static void +udev_hotplug_event(struct drm_backend *b, struct udev_device *device) +{ + struct timespec now; + int64_t now_ms, next_ms; + + weston_compositor_read_presentation_clock(b->compositor, &now); + now_ms = timespec_to_msec(&now); + + /* Already have a pending request */ + if (b->pending_update) + return; + + next_ms = b->last_update_ms ; + + // Try to use different hotplug mode + if (!b->mirror_mode) { + /* Long enough to trigger a new request */ + drm_backend_update_connectors(b, device); + } else { + /* Too close to the last request, schedule a new one */ + b->pending_update = true; + wl_event_source_timer_update(b->hotplug_timer, + next_ms - now_ms); + } +} + +static int +hotplug_timer_handler(void *data) +{ + struct drm_backend *b = data; + struct udev_device *device; + struct udev *udev; + + udev = udev_monitor_get_udev(b->udev_monitor); + device = udev_device_new_from_syspath(udev, b->drm.syspath); + + drm_backend_update_connectors(b, device); + b->pending_update = false; + + udev_device_unref(device); + return 0; +} static int drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_device) @@ -2782,8 +2821,7 @@ udev_drm_event(int fd, uint32_t mask, vo if (udev_event_is_conn_prop_change(b, event, &conn_id, &prop_id)) drm_backend_update_conn_props(b, conn_id, prop_id); else - drm_backend_update_connectors(b, event); - + udev_hotplug_event(b, event); } udev_device_unref(event); @@ -2801,6 +2839,7 @@ drm_destroy(struct weston_compositor *ec udev_input_destroy(&b->input); + wl_event_source_remove(b->hotplug_timer); wl_event_source_remove(b->udev_drm_source); wl_event_source_remove(b->drm_source); @@ -3102,6 +3141,8 @@ planes_binding(struct weston_keyboard *k } } + + #ifdef BUILD_VAAPI_RECORDER static void recorder_destroy(struct drm_output *output) @@ -3222,6 +3263,7 @@ output_create_notify(struct wl_listener drm_backend_update_outputs(b); } + static const struct weston_drm_output_api api = { drm_output_set_mode, drm_output_set_gbm_format, @@ -3503,7 +3545,8 @@ drm_backend_create(struct weston_composi weston_log("Failed to register virtual output API.\n"); goto err_udev_monitor; } - + b->hotplug_timer = + wl_event_loop_add_timer(loop, hotplug_timer_handler, b); return b; err_udev_monitor: diff -purN a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h --- a/libweston/backend-drm/drm-internal.h 2023-07-04 09:48:32.456881733 +0800 +++ b/libweston/backend-drm/drm-internal.h 2023-07-04 09:48:50.992078460 +0800 @@ -268,6 +268,7 @@ struct drm_backend { int fd; char *filename; dev_t devnum; + char *syspath; } drm; struct gbm_device *gbm; struct wl_listener session_listener; @@ -316,6 +317,7 @@ struct drm_backend { struct weston_log_scope *debug; + struct wl_event_source *hotplug_timer; bool pending_update; int64_t last_update_ms; int64_t last_resize_ms; diff -purN a/libweston/backend-drm/fb.c b/libweston/backend-drm/fb.c --- a/libweston/backend-drm/fb.c 2023-07-04 09:48:32.456881733 +0800 +++ b/libweston/backend-drm/fb.c 2023-07-04 09:48:50.992078460 +0800 @@ -421,7 +421,6 @@ drm_fb_unref(struct drm_fb *fb) { if (!fb) return; - assert(fb->refcnt > 0); if (--fb->refcnt > 0) return; diff -purN a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c --- a/libweston/backend-drm/kms.c 2023-07-04 09:48:32.456881733 +0800 +++ b/libweston/backend-drm/kms.c 2023-07-04 09:48:50.992078460 +0800 @@ -702,6 +702,9 @@ drm_output_apply_state_legacy(struct drm scanout_state = drm_output_state_get_existing_plane(state, scanout_plane); + + if (!scanout_state || !scanout_state->fb) + return 0; /* The legacy SetCrtc API doesn't allow us to do scaling, and the * legacy PageFlip API doesn't allow us to do clipping either. */ @@ -719,7 +722,7 @@ drm_output_apply_state_legacy(struct drm assert(scanout_state->in_fence_fd == -1); mode = to_drm_mode(output->base.current_mode); - if (backend->state_invalid || + if (output->state_invalid || !scanout_plane->state_cur->fb || scanout_plane->state_cur->fb->strides[0] != scanout_state->fb->strides[0]) { @@ -733,6 +736,7 @@ drm_output_apply_state_legacy(struct drm weston_log("set mode failed: %s\n", strerror(errno)); goto err; } + output->state_invalid = false; } pinfo = scanout_state->fb->format; @@ -943,6 +947,10 @@ drm_output_apply_state_atomic(struct drm *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; } + if (output->state_invalid) { + drm_debug(b, "\t\t\t[atomic] output state invalid, modeset OK\n"); + *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; + } if (state->dpms == WESTON_DPMS_ON) { ret = drm_mode_ensure_blob(b, current_mode); if (ret != 0) @@ -1049,11 +1057,21 @@ drm_pending_state_apply_atomic(struct dr struct drm_plane *plane; drmModeAtomicReq *req = drmModeAtomicAlloc(); uint32_t flags; + struct timespec now; int ret = 0; if (!req) return -1; + wl_list_for_each(output_state, &pending_state->output_list, link) { + if (output_state->output->virtual) + continue; + if (output_state->dpms == WESTON_DPMS_OFF && + mode == DRM_STATE_APPLY_ASYNC) + mode = DRM_STATE_APPLY_SYNC; + } + + switch (mode) { case DRM_STATE_APPLY_SYNC: flags = 0; @@ -1152,8 +1170,6 @@ drm_pending_state_apply_atomic(struct dr wl_list_for_each(output_state, &pending_state->output_list, link) { if (output_state->output->virtual) continue; - if (mode == DRM_STATE_APPLY_SYNC) - assert(output_state->dpms == WESTON_DPMS_OFF); ret |= drm_output_apply_state_atomic(output_state, req, &flags); } @@ -1173,18 +1189,38 @@ drm_pending_state_apply_atomic(struct dr } if (ret != 0) { - weston_log("atomic: couldn't commit new state: %s\n", - strerror(errno)); + // weston_log("atomic: couldn't commit new state: %s\n", + // strerror(errno)); goto out; } + weston_compositor_read_presentation_clock(b->compositor, &now); wl_list_for_each_safe(output_state, tmp, &pending_state->output_list, - link) + link) { + struct drm_output *output = output_state->output; + struct drm_plane *scanout_plane = output->scanout_plane; + struct drm_plane_state *scanout_state = + drm_output_state_get_existing_plane(output_state, + scanout_plane); + + /* Don't have a new state to apply */ + if (output_state->dpms == WESTON_DPMS_ON && + (!scanout_state || !scanout_state->fb)) + continue; + drm_output_assign_state(output_state, mode); + output->state_invalid = false; + + /* Not gonna receive flip event when dpms off */ + if (output_state->dpms != WESTON_DPMS_ON) + drm_output_update_complete(output, + WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION, + now.tv_sec, + now.tv_nsec / 1000); + } b->state_invalid = false; - assert(wl_list_empty(&pending_state->output_list)); out: drmModeAtomicFree(req); @@ -1284,7 +1320,6 @@ drm_pending_state_apply(struct drm_pendi b->state_invalid = false; - assert(wl_list_empty(&pending_state->output_list)); drm_pending_state_free(pending_state); @@ -1337,7 +1372,6 @@ drm_pending_state_apply_sync(struct drm_ b->state_invalid = false; - assert(wl_list_empty(&pending_state->output_list)); drm_pending_state_free(pending_state); @@ -1400,7 +1434,6 @@ atomic_flip_handler(int fd, unsigned int drm_debug(b, "[atomic][CRTC:%u] flip processing started\n", crtc_id); assert(b->atomic_modeset); - assert(output->atomic_complete_pending); output->atomic_complete_pending = false; drm_output_update_complete(output, flags, sec, usec); diff -purN a/libweston/compositor.c b/libweston/compositor.c --- a/libweston/compositor.c 2023-07-04 09:48:32.464879611 +0800 +++ b/libweston/compositor.c 2023-07-04 09:48:50.996077446 +0800 @@ -308,8 +308,7 @@ weston_output_mode_set_native(struct wes weston_mode_switch_finish(output, mode_changed, scale_changed); if (mode_changed || scale_changed) { - weston_compositor_reflow_outputs(output->compositor, output, output->width - old_width); - + weston_compositor_reflow_outputs(output->compositor); wl_signal_emit(&output->compositor->output_resized_signal, output); } return 0; @@ -3189,7 +3188,6 @@ weston_output_finish_frame(struct weston struct timespec vblank_monotonic; int64_t msec_rel; - assert(output->repaint_status == REPAINT_AWAITING_COMPLETION); /* * If timestamp of latest vblank is given, it must always go forwards. @@ -6053,31 +6051,25 @@ weston_head_get_destroy_listener(struct /* Move other outputs when one is resized so the space remains contiguous. */ WL_EXPORT void -weston_compositor_reflow_outputs(struct weston_compositor *compositor, - struct weston_output *resized_output, int delta_width) +weston_compositor_reflow_outputs(struct weston_compositor *compositor) { struct weston_output *output; struct weston_head *head; - bool start_resizing = false; - - if (!delta_width) - return; + int x, y, next_x, next_y; + next_x = next_y = 0; wl_list_for_each(output, &compositor->output_list, link) { wl_list_for_each(head, &output->head_list, output_link) weston_head_update_global(head); if (!weston_output_valid(output)) continue; - if (output == resized_output) { - start_resizing = true; - continue; - } - if (start_resizing) { - weston_output_move(output, output->x + delta_width, output->y); - output->dirty = 1; - } + x = next_x; + y = next_y; + + next_x += output->width; + weston_output_move(output, x, y); } } @@ -6436,7 +6428,7 @@ weston_compositor_remove_output(struct w weston_presentation_feedback_discard_list(&output->feedback_list); - weston_compositor_reflow_outputs(compositor, output, -output->width); + weston_compositor_reflow_outputs(compositor); wl_list_remove(&output->link); wl_list_insert(compositor->pending_output_list.prev, &output->link);