frame-clock: Ensure we're always monotonic

A call to frame gdk_frame_clock_get_frame_time() outside of the paint
cycle could report an un-error-corrected frame time, and later a
corrected value could be earlier than the previously reported value.

We now always store the latest reported time so we can ensure
monotonicity.

(cherry picked from commit a27fed47e0)
This commit is contained in:
Alexander Larsson
2020-05-28 17:44:51 +02:00
parent 687b49c18a
commit 1a598c32d9

View File

@@ -38,10 +38,11 @@
struct _GdkFrameClockIdlePrivate
{
gint64 frame_time; /* The exact time we last ran the clock cycle, or 0 if never */
gint64 smoothed_frame_time_base; /* A grid-aligned version of frame_time (grid size == refresh period), never more than half a grid from frame_time */
gint64 smoothed_frame_time_period; /* The grid size that smoothed_frame_time_base is aligned to */
gint64 min_next_frame_time; /* We're not synced to vblank, so wait at least until this before next cycle to avoid busy looping */
gint64 frame_time; /* The exact time we last ran the clock cycle, or 0 if never */
gint64 smoothed_frame_time_base; /* A grid-aligned version of frame_time (grid size == refresh period), never more than half a grid from frame_time */
gint64 smoothed_frame_time_period; /* The grid size that smoothed_frame_time_base is aligned to */
gint64 smoothed_frame_time_reported; /* Ensures we are always monotonic */
gint64 min_next_frame_time; /* We're not synced to vblank, so wait at least until this before next cycle to avoid busy looping */
gint64 sleep_serial;
#ifdef G_ENABLE_DEBUG
gint64 freeze_time;
@@ -220,9 +221,9 @@ compute_smooth_frame_time (GdkFrameClock *clock,
new_smoothed_time += correction_magnitude;
}
/* Ensure we're always strictly increasing (avoid division by zero when using time deltas) */
if (new_smoothed_time <= priv->smoothed_frame_time_base)
new_smoothed_time = priv->smoothed_frame_time_base + 1;
/* Ensure we're always monotonic */
if (new_smoothed_time <= priv->smoothed_frame_time_reported)
new_smoothed_time = priv->smoothed_frame_time_reported;
return new_smoothed_time;
}
@@ -232,6 +233,7 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
{
GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
gint64 now;
gint64 new_smoothed_time;
/* can't change frame time during a paint */
if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE &&
@@ -243,13 +245,19 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
/* First time frame, just return something */
if (priv->smoothed_frame_time_base == 0)
return now;
{
priv->smoothed_frame_time_reported = now;
return now;
}
/* Since time is monotonic this is <= what we will pick for the next cycle, but
more likely than not it will be equal if we're doing a constant animation. */
return compute_smooth_frame_time (clock, now, FALSE,
priv->smoothed_frame_time_base,
priv->smoothed_frame_time_period);
new_smoothed_time = compute_smooth_frame_time (clock, now, FALSE,
priv->smoothed_frame_time_base,
priv->smoothed_frame_time_period);
priv->smoothed_frame_time_reported = new_smoothed_time;
return new_smoothed_time;
}
#define RUN_FLUSH_IDLE(priv) \
@@ -424,6 +432,7 @@ gdk_frame_clock_paint_idle (void *data)
priv->smoothed_frame_time_period);
priv->smoothed_frame_time_period = frame_interval;
}
priv->smoothed_frame_time_reported = priv->smoothed_frame_time_base;
_gdk_frame_clock_begin_frame (clock);
/* Note "current" is different now so timings != prev_timings */