summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdk/gdkframeclock.c73
-rw-r--r--gdk/gdkframeclock.h11
-rw-r--r--gdk/gdkframeclockidle.c37
-rw-r--r--gdk/gdkframehistory.c3
-rw-r--r--gdk/gdkframetimings.c18
-rw-r--r--gdk/gdkframetimings.h4
-rw-r--r--gdk/x11/gdkdisplay-x11.c11
-rw-r--r--gdk/x11/gdkwindow-x11.c59
-rw-r--r--gdk/x11/gdkwindow-x11.h4
9 files changed, 201 insertions, 19 deletions
diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c
index ecb84bd8aa..fd41d94533 100644
--- a/gdk/gdkframeclock.c
+++ b/gdk/gdkframeclock.c
@@ -378,3 +378,76 @@ gdk_frame_clock_frame_requested (GdkFrameClock *clock)
g_signal_emit (G_OBJECT (clock),
signals[FRAME_REQUESTED], 0);
}
+
+GdkFrameTimings *
+gdk_frame_clock_get_current_frame_timings (GdkFrameClock *clock)
+{
+ GdkFrameHistory *history;
+ gint64 frame_counter;
+
+ g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), 0);
+
+ history = gdk_frame_clock_get_history (clock);
+ frame_counter = gdk_frame_history_get_frame_counter (history);
+ return gdk_frame_history_get_timings (history, frame_counter);
+}
+
+
+#define DEFAULT_REFRESH_INTERVAL 16667 /* 16.7ms (1/60th second) */
+#define MAX_HISTORY_AGE 150000 /* 150ms */
+
+void
+gdk_frame_clock_get_refresh_info (GdkFrameClock *clock,
+ gint64 base_time,
+ gint64 *refresh_interval_return,
+ gint64 *presentation_time_return)
+{
+ GdkFrameHistory *history;
+ gint64 frame_counter;
+
+ g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
+
+ history = gdk_frame_clock_get_history (clock);
+ frame_counter = gdk_frame_history_get_frame_counter (history);
+
+ if (presentation_time_return)
+ *presentation_time_return = 0;
+ if (refresh_interval_return)
+ *refresh_interval_return = DEFAULT_REFRESH_INTERVAL;
+
+ while (TRUE)
+ {
+ GdkFrameTimings *timings = gdk_frame_history_get_timings (history, frame_counter);
+ gint64 presentation_time;
+ gint64 refresh_interval;
+
+ if (timings == NULL)
+ return;
+
+ refresh_interval = gdk_frame_timings_get_refresh_interval (timings);
+ presentation_time = gdk_frame_timings_get_presentation_time (timings);
+
+ if (presentation_time != 0)
+ {
+ if (presentation_time > base_time - MAX_HISTORY_AGE &&
+ presentation_time_return)
+ {
+ if (refresh_interval == 0)
+ refresh_interval = DEFAULT_REFRESH_INTERVAL;
+
+ if (refresh_interval_return)
+ *refresh_interval_return = refresh_interval;
+
+ while (presentation_time < base_time)
+ presentation_time += refresh_interval;
+
+ if (presentation_time_return)
+ *presentation_time_return = presentation_time;
+ }
+
+ return;
+ }
+
+ frame_counter--;
+ }
+}
diff --git a/gdk/gdkframeclock.h b/gdk/gdkframeclock.h
index 03b04304cd..8d79f90a96 100644
--- a/gdk/gdkframeclock.h
+++ b/gdk/gdkframeclock.h
@@ -78,7 +78,7 @@ struct _GdkFrameClockInterface
{
GTypeInterface base_iface;
- guint64 (* get_frame_time) (GdkFrameClock *clock);
+ guint64 (* get_frame_time) (GdkFrameClock *clock);
void (* request_phase) (GdkFrameClock *clock,
GdkFrameClockPhase phase);
@@ -102,7 +102,7 @@ struct _GdkFrameClockInterface
GType gdk_frame_clock_get_type (void) G_GNUC_CONST;
-guint64 gdk_frame_clock_get_frame_time (GdkFrameClock *clock);
+guint64 gdk_frame_clock_get_frame_time (GdkFrameClock *clock);
void gdk_frame_clock_request_phase (GdkFrameClock *clock,
GdkFrameClockPhase phase);
@@ -117,6 +117,13 @@ GdkFrameHistory *gdk_frame_clock_get_history (GdkFrameClock *clock);
void gdk_frame_clock_get_frame_time_val (GdkFrameClock *clock,
GTimeVal *timeval);
+void gdk_frame_clock_get_refresh_info (GdkFrameClock *clock,
+ gint64 base_time,
+ gint64 *refresh_interval_return,
+ gint64 *presentation_time_return);
+
+GdkFrameTimings *gdk_frame_clock_get_current_frame_timings (GdkFrameClock *clock);
+
/* Signal emitters (used in frame clock implementations) */
void gdk_frame_clock_frame_requested (GdkFrameClock *clock);
diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c
index 09624c45b0..47103703cd 100644
--- a/gdk/gdkframeclockidle.c
+++ b/gdk/gdkframeclockidle.c
@@ -204,7 +204,7 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle)
{
GdkFrameClockIdlePrivate *priv = clock_idle->priv;
- if (priv->freeze_count == 0)
+ if (priv->freeze_count == 0 && priv->requested != 0)
{
guint min_interval = 0;
@@ -240,6 +240,23 @@ maybe_start_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)
{
@@ -277,6 +294,7 @@ gdk_frame_clock_paint_idle (void *data)
priv->paint_idle_id = 0;
priv->in_paint_idle = TRUE;
+ priv->min_next_frame_time = 0;
skip_to_resume_events =
(priv->requested & ~(GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS | GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS)) == 0;
@@ -403,19 +421,16 @@ gdk_frame_clock_paint_idle (void *data)
priv->in_paint_idle = FALSE;
- if (priv->freeze_count == 0 && priv->requested != 0)
+ /* If there is throttling in the backend layer, then we'll do another
+ * update as soon as the backend unthrottles (if there is work to do),
+ * otherwise we need to figure when the next frame should be.
+ */
+ if (priv->freeze_count == 0)
{
- /* We need to start over again immediately - this implies that there is no
- * throttling at the backend layer, so we need to back-off ourselves.
- */
- gdk_flush ();
- priv->min_next_frame_time = priv->frame_time + FRAME_INTERVAL;
+ priv->min_next_frame_time = compute_min_next_frame_time (clock_idle,
+ priv->frame_time);
maybe_start_idle (clock_idle);
}
- else
- {
- priv->min_next_frame_time = 0;
- }
if (priv->freeze_count == 0)
priv->sleep_serial = get_sleep_serial ();
diff --git a/gdk/gdkframehistory.c b/gdk/gdkframehistory.c
index 322467bc86..2f7147ef73 100644
--- a/gdk/gdkframehistory.c
+++ b/gdk/gdkframehistory.c
@@ -154,6 +154,7 @@ _gdk_frame_history_debug_print (GdkFrameHistory *history,
gint64 frame_end_time = _gdk_frame_timings_get_frame_end_time (timings);
gint64 frame_time = gdk_frame_timings_get_frame_time (timings);
gint64 presentation_time = gdk_frame_timings_get_presentation_time (timings);
+ gint64 predicted_presentation_time = gdk_frame_timings_get_predicted_presentation_time (timings);
gint64 refresh_interval = gdk_frame_timings_get_refresh_interval (timings);
gint64 previous_frame_time = 0;
gboolean slept_before = gdk_frame_timings_get_slept_before (timings);
@@ -177,6 +178,8 @@ _gdk_frame_history_debug_print (GdkFrameHistory *history,
g_print (" frame_end=%-4.1f", (frame_end_time - frame_time) / 1000.);
if (presentation_time != 0)
g_print (" present=%-4.1f", (presentation_time - frame_time) / 1000.);
+ if (predicted_presentation_time != 0)
+ g_print (" predicted=%-4.1f", (predicted_presentation_time - frame_time) / 1000.);
if (refresh_interval != 0)
g_print (" refresh_interval=%-4.1f", refresh_interval / 1000.);
g_print ("\n");
diff --git a/gdk/gdkframetimings.c b/gdk/gdkframetimings.c
index 08130015fd..ad9ec2e527 100644
--- a/gdk/gdkframetimings.c
+++ b/gdk/gdkframetimings.c
@@ -29,6 +29,7 @@ struct _GdkFrameTimings
gint64 drawn_time;
gint64 presentation_time;
gint64 refresh_interval;
+ gint64 predicted_presentation_time;
#ifdef G_ENABLE_DEBUG
gint64 layout_start_time;
@@ -188,6 +189,23 @@ gdk_frame_timings_set_presentation_time (GdkFrameTimings *timings,
}
gint64
+gdk_frame_timings_get_predicted_presentation_time (GdkFrameTimings *timings)
+{
+ g_return_val_if_fail (timings != NULL, 0);
+
+ return timings->predicted_presentation_time;
+}
+
+void
+gdk_frame_timings_set_predicted_presentation_time (GdkFrameTimings *timings,
+ gint64 predicted_presentation_time)
+{
+ g_return_if_fail (timings != NULL);
+
+ timings->predicted_presentation_time = predicted_presentation_time;
+}
+
+gint64
gdk_frame_timings_get_refresh_interval (GdkFrameTimings *timings)
{
g_return_val_if_fail (timings != NULL, 0);
diff --git a/gdk/gdkframetimings.h b/gdk/gdkframetimings.h
index 53dbffbd06..8e86c6e69f 100644
--- a/gdk/gdkframetimings.h
+++ b/gdk/gdkframetimings.h
@@ -62,6 +62,10 @@ gint64 gdk_frame_timings_get_refresh_interval (GdkFrameTimings *timin
void gdk_frame_timings_set_refresh_interval (GdkFrameTimings *timings,
gint64 refresh_interval);
+gint64 gdk_frame_timings_get_predicted_presentation_time (GdkFrameTimings *timings);
+void gdk_frame_timings_set_predicted_presentation_time (GdkFrameTimings *timings,
+ gint64 predicted_presentation_time);
+
G_END_DECLS
#endif /* __GDK_FRAME_TIMINGS_H__ */
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 888d87dd70..cf26b3016d 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -1108,18 +1108,27 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
guint32 d3 = xevent->xclient.data.l[3];
guint64 serial = ((guint64)d0 << 32) | d1;
+ gint64 frame_drawn_time = ((guint64)d2 << 32) | d3;
+ gint64 refresh_interval, presentation_time;
GdkFrameClock *clock = gdk_window_get_frame_clock (event->any.window);
GdkFrameTimings *timings = find_frame_timings (clock, serial);
if (timings)
- gdk_frame_timings_set_drawn_time (timings, ((guint64)d2 << 32) | d3);
+ gdk_frame_timings_set_drawn_time (timings, frame_drawn_time);
if (window_impl->toplevel->frame_pending)
{
window_impl->toplevel->frame_pending = FALSE;
gdk_frame_clock_thaw (clock);
}
+
+ gdk_frame_clock_get_refresh_info (clock,
+ frame_drawn_time,
+ &refresh_interval,
+ &presentation_time);
+ if (presentation_time != 0)
+ window_impl->toplevel->throttled_presentation_time = presentation_time + refresh_interval;
}
return GDK_FILTER_REMOVE;
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index ea74baa3f4..d3fac4df5f 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -278,6 +278,58 @@ unhook_surface_changed (GdkWindow *window)
}
static void
+gdk_x11_window_predict_presentation_time (GdkWindow *window)
+{
+ GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
+ GdkFrameClock *clock;
+ GdkFrameTimings *timings;
+ gint64 frame_time;
+ gint64 presentation_time;
+ gint64 refresh_interval;
+ gboolean slept_before;
+
+ if (!WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ clock = gdk_window_get_frame_clock (window);
+
+ timings = gdk_frame_clock_get_current_frame_timings (clock);
+ frame_time = gdk_frame_timings_get_frame_time (timings);
+ slept_before = gdk_frame_timings_get_slept_before (timings);
+
+ gdk_frame_clock_get_refresh_info (clock,
+ frame_time,
+ &refresh_interval, &presentation_time);
+
+ if (presentation_time != 0)
+ {
+ if (slept_before)
+ {
+ presentation_time += refresh_interval;
+ }
+ else
+ {
+ if (presentation_time < frame_time + refresh_interval / 2)
+ presentation_time += refresh_interval;
+ }
+ }
+ else
+ {
+ if (slept_before)
+ presentation_time = frame_time + refresh_interval + refresh_interval / 2;
+ else
+ presentation_time = frame_time + refresh_interval;
+ }
+
+ if (presentation_time < impl->toplevel->throttled_presentation_time)
+ presentation_time = impl->toplevel->throttled_presentation_time;
+
+ gdk_frame_timings_set_predicted_presentation_time (timings,
+ presentation_time);
+
+}
+
+static void
gdk_x11_window_begin_frame (GdkWindow *window)
{
GdkWindowImplX11 *impl;
@@ -299,8 +351,6 @@ static void
gdk_x11_window_end_frame (GdkWindow *window)
{
GdkFrameClock *clock;
- GdkFrameHistory *history;
- gint64 frame_counter;
GdkFrameTimings *timings;
GdkWindowImplX11 *impl;
@@ -314,9 +364,7 @@ gdk_x11_window_end_frame (GdkWindow *window)
return;
clock = gdk_window_get_frame_clock (window);
- history = gdk_frame_clock_get_history (clock);
- frame_counter = gdk_frame_history_get_frame_counter (history);
- timings = gdk_frame_history_get_timings (history, frame_counter);
+ timings = gdk_frame_clock_get_current_frame_timings (clock);
impl->toplevel->in_frame = FALSE;
@@ -880,6 +928,7 @@ static void
on_frame_clock_before_paint (GdkFrameClock *clock,
GdkWindow *window)
{
+ gdk_x11_window_predict_presentation_time (window);
gdk_x11_window_begin_frame (window);
}
diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h
index 8dde335011..7eb95a07f2 100644
--- a/gdk/x11/gdkwindow-x11.h
+++ b/gdk/x11/gdkwindow-x11.h
@@ -156,6 +156,10 @@ struct _GdkToplevelX11
* ConfigureNotify
*/
gint64 current_counter_value;
+
+ /* After a _NET_WM_FRAME_DRAWN message, this is the soonest that we think
+ * frame after will be presented */
+ gint64 throttled_presentation_time;
#endif
};