From b8deb4caa0fcaffdfed2636d2164050b8121a35b Mon Sep 17 00:00:00 2001 From: Dor Askayo Date: Fri, 26 Jan 2024 17:08:27 +0000 Subject: [PATCH] wayland: Emit frame callbacks when the frame is pending presentation When Wayland clients send commits without a buffer attached ("empty" commits), they may lead to stage updates that do not result in any frame being submitted for presentation ("empty" updates). Due to how frame scheduling is handled, there can be many such "empty" updates in a single refresh cycle. If frame callbacks were emitted after each of these "empty" updates, and if the client sending "empty" commits was using frame callbacks to throttle the same logic that results in these "empty" commits being sent, it would result in a feedback loop between Mutter and the client where the client would send "empty" commits and Mutter would reply almost immediately with a frame callback causing the client to send "empty" commits continuously. As such, when an "empty" update is detected, frame callbacks are scheduled to be emitted only once in every refresh cycle, avoiding the feedback loop. When a "non-empty" update is detected, frame callbacks are instead emitted immediately to allow clients to draw their next frame as soon as possible. It is safe to emit frame callbacks in this case because the frame for the current refresh cycle is already "finalized" and that any commit sent by the client at that point would only be handled in a future refresh cycle. To implement this, the previous logic had used meta_frame_native_had_kms_update() to detect "non-empty" updates, assuming that those would always result in a KMS presentation with the native backend. However, this approach misses the fact that virtual monitors do not use KMS, and as such do not result in KMS presentation even for "non-empty" updates. As a result, frame callbacks would not be emitted immediately, resulting in unintended throttling of client rendering. Instead, assume that it is safe to emit frame callbacks immediately whenever an update results in the frame clock waiting to be notified of presentation, since this is also when commits sent by clients are scheduled to be handled in a future refresh cycle. This issue was mostly hidden because frame callbacks would be sent immediately when the target presentation time for the frame had changed compared to the previous frame. However, this behavior was removed in 26d8b9c69 ("wayland: Remove unnecessary dispatch of frame callback source"), exposing the issue. Fixes: a7a7933e0 ("wayland: Emit frame events in GSource after "empty" updates") Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3263 Part-of: --- src/wayland/meta-wayland.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 9b292ff66..24840263b 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -293,7 +293,6 @@ on_after_update (ClutterStage *stage, #if defined(HAVE_NATIVE_BACKEND) MetaContext *context = meta_wayland_compositor_get_context (compositor); MetaBackend *backend = meta_context_get_backend (context); - MetaFrameNative *frame_native; GSource *source; int64_t frame_deadline_us; @@ -303,11 +302,10 @@ on_after_update (ClutterStage *stage, return; } - frame_native = meta_frame_native_from_frame (frame); - source = ensure_source_for_stage_view (compositor, stage_view); - if (meta_frame_native_had_kms_update (frame_native) || + if (clutter_frame_get_result (frame) == + CLUTTER_FRAME_RESULT_PENDING_PRESENTED || !clutter_frame_get_frame_deadline (frame, &frame_deadline_us)) {