[gtk+] Fix irregular gdk_frame_clock_get_frame_time
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Fix irregular gdk_frame_clock_get_frame_time
- Date: Sun, 10 Dec 2017 02:23:17 +0000 (UTC)
commit 3b2f9395905ec2d9696bcf51497781236c95ec63
Author: Daniel van Vugt <daniel van vugt canonical com>
Date: Fri Sep 15 17:49:12 2017 +0800
Fix irregular gdk_frame_clock_get_frame_time
This fixes stuttering in animations that rely on the regularity of
gdk_frame_clock_get_frame_time.
https://bugzilla.gnome.org/show_bug.cgi?id=787665
BEFORE
gdkgears:
58 FPS and visibly stuttering
gnome-maps on a 59.95Hz monitor:
"paint" g_get_monotonic_time +17278μs, gdk_frame_clock_get_frame_time +17278μs
"paint" g_get_monotonic_time +17449μs, gdk_frame_clock_get_frame_time +17426μs
"paint" g_get_monotonic_time +17620μs, gdk_frame_clock_get_frame_time +17600μs
AFTER
gdkgears:
60 FPS and smoother
gnome-maps on a 59.95Hz monitor:
"paint" g_get_monotonic_time +18228μs, gdk_frame_clock_get_frame_time +16680μs
"paint" g_get_monotonic_time +15010μs, gdk_frame_clock_get_frame_time +16680μs
"paint" g_get_monotonic_time +17134μs, gdk_frame_clock_get_frame_time +16680μs
gdk/gdkframeclockidle.c | 31 ++++++++++++++++++++++++++++++-
1 files changed, 30 insertions(+), 1 deletions(-)
---
diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c
index 0af296c..3714502 100644
--- a/gdk/gdkframeclockidle.c
+++ b/gdk/gdkframeclockidle.c
@@ -123,6 +123,7 @@ gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
frame_clock_idle->priv = priv =
gdk_frame_clock_idle_get_instance_private (frame_clock_idle);
+ priv->frame_time = g_get_monotonic_time (); /* more sane than zero */
priv->freeze_count = 0;
}
@@ -350,9 +351,37 @@ gdk_frame_clock_paint_idle (void *data)
case GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT:
if (priv->freeze_count == 0)
{
- priv->frame_time = compute_frame_time (clock_idle);
+ gint64 frame_interval = FRAME_INTERVAL;
+ gint64 reset_frame_time;
+ gint64 smoothest_frame_time;
+ gint64 frame_time_error;
+ GdkFrameTimings *prev_timings =
+ gdk_frame_clock_get_current_timings (clock);
+
+ if (prev_timings && prev_timings->refresh_interval)
+ frame_interval = prev_timings->refresh_interval;
+
+ /* We are likely not getting precisely even callbacks in real
+ * time, particularly if the event loop is busy.
+ * This is a documented limitation in the precision of
+ * gdk_threads_add_timeout_full and g_timeout_add_full.
+ *
+ * In order to avoid this imprecision from compounding between
+ * frames and affecting visual smoothness, we correct frame_time
+ * to more precisely match the even refresh interval of the
+ * physical display. This also means we proactively avoid (most)
+ * missed frames before they occur.
+ */
+ smoothest_frame_time = priv->frame_time + frame_interval;
+ reset_frame_time = compute_frame_time (clock_idle);
+ frame_time_error = ABS (reset_frame_time - smoothest_frame_time);
+ if (frame_time_error >= frame_interval)
+ priv->frame_time = reset_frame_time;
+ else
+ priv->frame_time = smoothest_frame_time;
_gdk_frame_clock_begin_frame (clock);
+ /* Note "current" is different now so timings != prev_timings */
timings = gdk_frame_clock_get_current_timings (clock);
timings->frame_time = priv->frame_time;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]