From 903f6281f9964100ceb133beda2e262ba9edae9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 4 Mar 2025 18:49:57 +0100 Subject: [PATCH] wayland: Use per-view & per-frame list of pending presentation feedbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of a single hash table with a list of feedbacks per stage view, there's a nested hash table per stage view with a list of feedbacks per view frame counter. This ensures that presentation feedbacks don't get mixed up between different frames. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3937 v2: * Use ClutterFrame(Info)::frame_count. (Jonas Ã…dahl) Part-of: --- src/backends/meta-cursor-renderer.c | 14 ++- src/backends/meta-cursor-renderer.h | 3 +- .../native/meta-cursor-renderer-native.c | 3 +- src/wayland/meta-wayland-cursor-surface.c | 2 + .../meta-wayland-presentation-time-private.h | 6 +- src/wayland/meta-wayland-presentation-time.c | 101 +++++++++++++++--- src/wayland/meta-wayland.c | 40 +------ 7 files changed, 109 insertions(+), 60 deletions(-) diff --git a/src/backends/meta-cursor-renderer.c b/src/backends/meta-cursor-renderer.c index ff9da0402..0205b38de 100644 --- a/src/backends/meta-cursor-renderer.c +++ b/src/backends/meta-cursor-renderer.c @@ -97,9 +97,11 @@ meta_hw_cursor_inhibitor_default_init (MetaHwCursorInhibitorInterface *iface) void meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite, - ClutterStageView *stage_view) + ClutterStageView *stage_view, + int64_t view_frame_counter) { - g_signal_emit (renderer, signals[CURSOR_PAINTED], 0, cursor_sprite, stage_view); + g_signal_emit (renderer, signals[CURSOR_PAINTED], 0, cursor_sprite, + stage_view, view_frame_counter); } static void @@ -203,7 +205,8 @@ meta_cursor_renderer_after_paint (ClutterStage *stage, { meta_cursor_renderer_emit_painted (renderer, priv->displayed_cursor, - stage_view); + stage_view, + frame->frame_count); } } } @@ -331,9 +334,10 @@ meta_cursor_renderer_class_init (MetaCursorRendererClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, + G_TYPE_NONE, 3, G_TYPE_POINTER, - CLUTTER_TYPE_STAGE_VIEW); + CLUTTER_TYPE_STAGE_VIEW, + G_TYPE_INT64); } static void diff --git a/src/backends/meta-cursor-renderer.h b/src/backends/meta-cursor-renderer.h index b76f1b279..2e2ffec06 100644 --- a/src/backends/meta-cursor-renderer.h +++ b/src/backends/meta-cursor-renderer.h @@ -70,7 +70,8 @@ graphene_rect_t meta_cursor_renderer_calculate_rect (MetaCursorRenderer *rendere void meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite, - ClutterStageView *stage_view); + ClutterStageView *stage_view, + int64_t view_frame_counter); ClutterInputDevice * meta_cursor_renderer_get_input_device (MetaCursorRenderer *renderer); void meta_cursor_renderer_update_stage_overlay (MetaCursorRenderer *renderer, diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c index 50ed91880..c81fb496e 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -248,7 +248,8 @@ meta_cursor_renderer_native_prepare_frame (MetaCursorRendererNative *cursor_rend { meta_cursor_renderer_emit_painted (cursor_renderer, cursor_sprite, - CLUTTER_STAGE_VIEW (view)); + CLUTTER_STAGE_VIEW (view), + frame->frame_count); cursor_stage_view->needs_emit_painted = FALSE; } } diff --git a/src/wayland/meta-wayland-cursor-surface.c b/src/wayland/meta-wayland-cursor-surface.c index 0b7831b39..2aa9e7f66 100644 --- a/src/wayland/meta-wayland-cursor-surface.c +++ b/src/wayland/meta-wayland-cursor-surface.c @@ -491,6 +491,7 @@ static void on_cursor_painted (MetaCursorRenderer *renderer, MetaCursorSprite *displayed_sprite, ClutterStageView *stage_view, + int64_t view_frame_counter, MetaWaylandCursorSurface *cursor_surface) { MetaWaylandCursorSurfacePrivate *priv = @@ -519,6 +520,7 @@ on_cursor_painted (MetaCursorRenderer *renderer, meta_wayland_presentation_time_cursor_painted (&compositor->presentation_time, stage_view, + view_frame_counter, cursor_surface); } diff --git a/src/wayland/meta-wayland-presentation-time-private.h b/src/wayland/meta-wayland-presentation-time-private.h index 254ce08df..dc2db22a1 100644 --- a/src/wayland/meta-wayland-presentation-time-private.h +++ b/src/wayland/meta-wayland-presentation-time-private.h @@ -56,9 +56,11 @@ void meta_wayland_presentation_feedback_present (MetaWaylandPresentationFeedback ClutterFrameInfo *frame_info, MetaWaylandOutput *output); -struct wl_list * meta_wayland_presentation_time_ensure_feedbacks (MetaWaylandPresentationTime *presentation_time, - ClutterStageView *stage_view); +void meta_wayland_presentation_time_present_feedbacks (MetaWaylandCompositor *compositor, + ClutterStageView *stage_view, + ClutterFrameInfo *frame_info); void meta_wayland_presentation_time_cursor_painted (MetaWaylandPresentationTime *presentation_time, ClutterStageView *stage_view, + int64_t view_frame_counter, MetaWaylandCursorSurface *cursor_surface); diff --git a/src/wayland/meta-wayland-presentation-time.c b/src/wayland/meta-wayland-presentation-time.c index e09819df4..94abba8f2 100644 --- a/src/wayland/meta-wayland-presentation-time.c +++ b/src/wayland/meta-wayland-presentation-time.c @@ -111,6 +111,11 @@ wp_presentation_bind (struct wl_client *client, wp_presentation_send_clock_id (resource, CLOCK_MONOTONIC); } +static struct wl_list * +meta_wayland_presentation_time_ensure_feedbacks (MetaWaylandPresentationTime *presentation_time, + ClutterStageView *stage_view, + int64_t view_frame_counter); + static void discard_non_cursor_feedbacks (struct wl_list *feedbacks) { @@ -146,7 +151,7 @@ on_after_paint (ClutterStage *stage, */ feedbacks = meta_wayland_presentation_time_ensure_feedbacks (&compositor->presentation_time, - stage_view); + stage_view, frame->frame_count); discard_non_cursor_feedbacks (feedbacks); l = compositor->presentation_time.feedback_surfaces; @@ -229,7 +234,8 @@ meta_wayland_init_presentation_time (MetaWaylandCompositor *compositor) ClutterActor *stage = meta_backend_get_stage (backend); compositor->presentation_time.feedbacks = - g_hash_table_new_full (NULL, NULL, NULL, destroy_feedback_list); + g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) g_hash_table_destroy); g_signal_connect (monitor_manager, "monitors-changed-internal", G_CALLBACK (on_monitors_changed), compositor); @@ -390,27 +396,93 @@ meta_wayland_presentation_feedback_present (MetaWaylandPresentationFeedback *fee wl_resource_destroy (feedback->resource); } -struct wl_list * +static struct wl_list * meta_wayland_presentation_time_ensure_feedbacks (MetaWaylandPresentationTime *presentation_time, - ClutterStageView *stage_view) + ClutterStageView *stage_view, + int64_t view_frame_counter) { - if (!g_hash_table_contains (presentation_time->feedbacks, stage_view)) + GHashTable *hash_table; + struct wl_list *list; + + hash_table = g_hash_table_lookup (presentation_time->feedbacks, stage_view); + if (!hash_table) { - struct wl_list *list; - - list = g_new0 (struct wl_list, 1); - wl_list_init (list); - g_hash_table_insert (presentation_time->feedbacks, stage_view, list); - - return list; + hash_table = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, + destroy_feedback_list); + g_hash_table_insert (presentation_time->feedbacks, stage_view, hash_table); } - return g_hash_table_lookup (presentation_time->feedbacks, stage_view); + list = g_hash_table_lookup (hash_table, &view_frame_counter); + if (!list) + { + int64_t *key; + + key = g_new (int64_t, 1); + *key = view_frame_counter; + list = g_new0 (struct wl_list, 1); + wl_list_init (list); + g_hash_table_insert (hash_table, key, list); + } + + return list; +} + +static MetaWaylandOutput * +get_output_for_stage_view (MetaWaylandCompositor *compositor, + ClutterStageView *stage_view) +{ + MetaCrtc *crtc; + MetaOutput *output; + MetaMonitor *monitor; + + crtc = meta_renderer_view_get_crtc (META_RENDERER_VIEW (stage_view)); + + /* + * All outputs occupy the same region of the screen, as their contents are + * the same, so pick the first one. + */ + output = meta_crtc_get_outputs (crtc)->data; + + monitor = meta_output_get_monitor (output); + return g_hash_table_lookup (compositor->outputs, + meta_monitor_get_spec (monitor)); +} + +void +meta_wayland_presentation_time_present_feedbacks (MetaWaylandCompositor *compositor, + ClutterStageView *stage_view, + ClutterFrameInfo *frame_info) +{ + MetaWaylandPresentationFeedback *feedback, *next; + struct wl_list *feedbacks; + MetaWaylandOutput *output; + GHashTable *hash_table; + + hash_table = g_hash_table_lookup (compositor->presentation_time.feedbacks, + stage_view); + if (!hash_table) + return; + + feedbacks = g_hash_table_lookup (hash_table, &frame_info->view_frame_counter); + if (!feedbacks) + return; + + output = get_output_for_stage_view (compositor, stage_view); + + wl_list_for_each_safe (feedback, next, feedbacks, link) + { + meta_wayland_presentation_feedback_present (feedback, + frame_info, + output); + } + + g_hash_table_remove (hash_table, &frame_info->view_frame_counter); } void meta_wayland_presentation_time_cursor_painted (MetaWaylandPresentationTime *presentation_time, ClutterStageView *stage_view, + int64_t view_frame_counter, MetaWaylandCursorSurface *cursor_surface) { struct wl_list *feedbacks; @@ -420,7 +492,8 @@ meta_wayland_presentation_time_cursor_painted (MetaWaylandPresentationTime *pres feedbacks = meta_wayland_presentation_time_ensure_feedbacks (presentation_time, - stage_view); + stage_view, + view_frame_counter); /* Discard previous feedbacks for this cursor as now it has gone stale. */ wl_list_for_each_safe (feedback, next, feedbacks, link) diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 211eeb0c2..b2df0737b 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -538,49 +538,15 @@ meta_wayland_compositor_update (MetaWaylandCompositor *compositor, meta_wayland_seat_update (compositor->seat, event); } -static MetaWaylandOutput * -get_output_for_stage_view (MetaWaylandCompositor *compositor, - ClutterStageView *stage_view) -{ - MetaCrtc *crtc; - MetaOutput *output; - MetaMonitor *monitor; - - crtc = meta_renderer_view_get_crtc (META_RENDERER_VIEW (stage_view)); - - /* - * All outputs occupy the same region of the screen, as their contents are - * the same, so pick the first one. - */ - output = meta_crtc_get_outputs (crtc)->data; - - monitor = meta_output_get_monitor (output); - return g_hash_table_lookup (compositor->outputs, - meta_monitor_get_spec (monitor)); -} - static void on_presented (ClutterStage *stage, ClutterStageView *stage_view, ClutterFrameInfo *frame_info, MetaWaylandCompositor *compositor) { - MetaWaylandPresentationFeedback *feedback, *next; - struct wl_list *feedbacks; - MetaWaylandOutput *output; - - feedbacks = - meta_wayland_presentation_time_ensure_feedbacks (&compositor->presentation_time, - stage_view); - - output = get_output_for_stage_view (compositor, stage_view); - - wl_list_for_each_safe (feedback, next, feedbacks, link) - { - meta_wayland_presentation_feedback_present (feedback, - frame_info, - output); - } + meta_wayland_presentation_time_present_feedbacks (compositor, + stage_view, + frame_info); } static void