diff --git a/package/weston/0008-weston-support-hotplug.patch b/package/weston/0008-weston-support-hotplug.patch new file mode 100644 index 00000000..1a03a50e --- /dev/null +++ b/package/weston/0008-weston-support-hotplug.patch @@ -0,0 +1,457 @@ +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);