summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYariv Barkan <21448-yarivb@users.noreply.gitlab.gnome.org>2020-06-10 10:54:07 +0300
committerAlexander Larsson <alexl@redhat.com>2020-06-15 08:53:23 +0200
commitcf91cf4825754b2412a44365ad1e033d661d92e9 (patch)
tree421df38e8737e17e53da7271bca6d3606551eedc
parentb80bc06b993f69f9c5686844b8d50242853257de (diff)
downloadgtk+-cf91cf4825754b2412a44365ad1e033d661d92e9.tar.gz
frame clock: fix scheduling
Fix scheduling of the frame clock when we don't receive "frame drawn" messages from the compositor. If we received "frame drawn" events recently, then the "smooth frame time" would be in sync with the vsync time. When we don't receive frame drawn events, the "smooth frame time" is simply incremented by constant multiples of the refresh interval. In both cases we can use this smooth time as the basis for scheduling the next clock cycle. By only using the "smooth frame time" as a basis we also benefit from more consistent scheduling cadence. If, for example, we got "frame drawn" events, then didn't receive them for a few frames, we would still be in sync when we start receiving these events again.
-rw-r--r--gdk/gdkframeclockidle.c34
1 files changed, 14 insertions, 20 deletions
diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c
index bbedd606f5..89f5823a72 100644
--- a/gdk/gdkframeclockidle.c
+++ b/gdk/gdkframeclockidle.c
@@ -141,6 +141,7 @@ gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
gdk_frame_clock_idle_get_instance_private (frame_clock_idle);
priv->freeze_count = 0;
+ priv->smoothed_frame_time_period = FRAME_INTERVAL;
}
static void
@@ -347,23 +348,6 @@ maybe_stop_idle (GdkFrameClockIdle *clock_idle)
}
}
-static gint64
-compute_min_next_frame_time (GdkFrameClockIdle *clock_idle,
- gint64 last_frame_time)
-{
- gint64 presentation_time;
- gint64 refresh_interval;
-
- gdk_frame_clock_get_refresh_info (GDK_FRAME_CLOCK (clock_idle),
- last_frame_time,
- &refresh_interval, &presentation_time);
-
- if (presentation_time == 0)
- return last_frame_time + refresh_interval;
- else
- return presentation_time + refresh_interval / 2;
-}
-
static gboolean
gdk_frame_clock_flush_idle (void *data)
{
@@ -659,9 +643,19 @@ gdk_frame_clock_paint_idle (void *data)
*/
if (priv->freeze_count == 0)
{
- priv->min_next_frame_time = compute_min_next_frame_time (clock_idle,
- priv->smoothed_frame_time_base -
- priv->smoothed_frame_time_phase);
+ /*
+ * If we don't receive "frame drawn" events, smooth_cycle_start will simply be advanced in constant increments of
+ * the refresh interval. That way we get absolute target times for the next cycles, which should prevent skewing
+ * in the scheduling of the frame clock.
+ *
+ * Once we do receive "frame drawn" events, smooth_cycle_start will track the vsync, and do so in a more stable
+ * way compared to frame_time. If we then no longer receive "frame drawn" events, smooth_cycle_start will again be
+ * simply advanced in increments of the refresh interval, but this time we are in sync with the vsync. If we start
+ * receiving "frame drawn" events shortly after loosing them, then we should still be in sync.
+ */
+ gint64 smooth_cycle_start = priv->smoothed_frame_time_base - priv->smoothed_frame_time_phase;
+ priv->min_next_frame_time = smooth_cycle_start + priv->smoothed_frame_time_period;
+
maybe_start_idle (clock_idle, FALSE);
}