wayland: Use per-view & per-frame list of pending presentation feedbacks

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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4306>
This commit is contained in:
Michel Dänzer 2025-03-04 18:49:57 +01:00 committed by Michel Dänzer
parent 34b203ed99
commit 903f6281f9
7 changed files with 109 additions and 60 deletions

View File

@ -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

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -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