1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2010. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 #include "gdkframeclockprivate.h"
30 #include "gdkinternals.h"
34 * @Short_description: Frame clock syncs painting to a window or display
37 * A #GdkFrameClock tells the application when to update and repaint a
38 * window. This may be synced to the vertical refresh rate of the
39 * monitor, for example. Even when the frame clock uses a simple timer
40 * rather than a hardware-based vertical sync, the frame clock helps
41 * because it ensures everything paints at the same time (reducing the
42 * total number of frames). The frame clock can also automatically
43 * stop painting when it knows the frames will not be visible, or
44 * scale back animation framerates.
46 * #GdkFrameClock is designed to be compatible with an OpenGL-based
47 * implementation or with mozRequestAnimationFrame in Firefox,
50 * A frame clock is idle until someone requests a frame with
51 * gdk_frame_clock_request_phase(). At some later point that makes
52 * sense for the synchronization being implemented, the clock will
53 * process a frame and emit signals for each phase that has been
54 * requested. (See the signals of the #GdkFrameClock class for
55 * documentation of the phases. GDK_FRAME_CLOCK_PHASE_UPDATE and the
56 * ::update signal are most interesting for application writers, and
57 * are used to update the animations, using the frame time given by
58 * gdk_frame_clock_get_frame_time().
60 * The frame time is reported in microseconds and generally in the same
61 * timescale as g_get_monotonic_time(), however, it is not the same
62 * as g_get_monotonic_time(). The frame time does not advance during
63 * the time a frame is being painted, and outside of a frame, an attempt
64 * is made so that all calls to gdk_frame_clock_get_frame_time() that
65 * are called at a "similar" time get the same value. This means that
66 * if different animations are timed by looking at the difference in
67 * time between an initial value from gdk_frame_clock_get_frame_time()
68 * and the value inside the ::update signal of the clock, they will
69 * stay exactly synchronized.
72 G_DEFINE_ABSTRACT_TYPE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
85 static guint signals[LAST_SIGNAL];
87 #define FRAME_HISTORY_MAX_LENGTH 16
89 struct _GdkFrameClockPrivate
94 GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
98 gdk_frame_clock_finalize (GObject *object)
100 GdkFrameClockPrivate *priv = GDK_FRAME_CLOCK (object)->priv;
103 for (i = 0; i < FRAME_HISTORY_MAX_LENGTH; i++)
104 if (priv->timings[i] != 0)
105 gdk_frame_timings_unref (priv->timings[i]);
107 G_OBJECT_CLASS (gdk_frame_clock_parent_class)->finalize (object);
111 gdk_frame_clock_class_init (GdkFrameClockClass *klass)
113 GObjectClass *gobject_class = (GObjectClass*) klass;
115 gobject_class->finalize = gdk_frame_clock_finalize;
118 * GdkFrameClock::flush-events:
119 * @clock: the frame clock emitting the signal
121 * This signal is used to flush pending motion events that
122 * are being batched up and compressed together. Applications
123 * should not handle this signal.
125 signals[FLUSH_EVENTS] =
126 g_signal_new (g_intern_static_string ("flush-events"),
127 GDK_TYPE_FRAME_CLOCK,
131 g_cclosure_marshal_VOID__VOID,
135 * GdkFrameClock::before-paint:
136 * @clock: the frame clock emitting the signal
138 * This signal begins processing of the frame. Applications
139 * should generally not handle this signal.
141 signals[BEFORE_PAINT] =
142 g_signal_new (g_intern_static_string ("before-paint"),
143 GDK_TYPE_FRAME_CLOCK,
147 g_cclosure_marshal_VOID__VOID,
151 * GdkFrameClock::update:
152 * @clock: the frame clock emitting the signal
154 * This signal is emitted as the first step of toolkit and
155 * application processing of the frame. Animations should
156 * be updated using gdk_frame_clock_get_frame_time().
157 * Applications can connect directly to this signal, or
158 * use gtk_widget_add_tick_callback() as a more convenient
162 g_signal_new (g_intern_static_string ("update"),
163 GDK_TYPE_FRAME_CLOCK,
167 g_cclosure_marshal_VOID__VOID,
171 * GdkFrameClock::layout:
172 * @clock: the frame clock emitting the signal
174 * This signal is emitted as the second step of toolkit and
175 * application processing of the frame. Any work to update
176 * sizes and positions of application elements should be
177 * performed. GTK normally handles this internally.
180 g_signal_new (g_intern_static_string ("layout"),
181 GDK_TYPE_FRAME_CLOCK,
185 g_cclosure_marshal_VOID__VOID,
189 * GdkFrameClock::layout:
190 * @clock: the frame clock emitting the signal
192 * This signal is emitted as the third step of toolkit and
193 * application processing of the frame. The frame is
194 * repainted. GDK normally handles this internally and
195 * produce expose events, which are turned into GTK
196 * GtkWidget::draw signals.
199 g_signal_new (g_intern_static_string ("paint"),
200 GDK_TYPE_FRAME_CLOCK,
204 g_cclosure_marshal_VOID__VOID,
208 * GdkFrameClock::after-paint:
209 * @clock: the frame clock emitting the signal
211 * This signal ends processing of the frame. Applications
212 * should generally not handle this signal.
214 signals[AFTER_PAINT] =
215 g_signal_new (g_intern_static_string ("after-paint"),
216 GDK_TYPE_FRAME_CLOCK,
220 g_cclosure_marshal_VOID__VOID,
224 * GdkFrameClock::resume-events:
225 * @clock: the frame clock emitting the signal
227 * This signal is emitted after processing of the frame is
228 * finished, and is handled internally by GTK+ to resume normal
229 * event processing. Applications should not handle this signal.
231 signals[RESUME_EVENTS] =
232 g_signal_new (g_intern_static_string ("resume-events"),
233 GDK_TYPE_FRAME_CLOCK,
237 g_cclosure_marshal_VOID__VOID,
240 g_type_class_add_private (klass, sizeof (GdkFrameClockPrivate));
244 gdk_frame_clock_init (GdkFrameClock *clock)
246 GdkFrameClockPrivate *priv;
248 clock->priv = G_TYPE_INSTANCE_GET_PRIVATE (clock,
249 GDK_TYPE_FRAME_CLOCK,
250 GdkFrameClockPrivate);
253 priv->frame_counter = -1;
254 priv->current = FRAME_HISTORY_MAX_LENGTH - 1;
258 * gdk_frame_clock_get_frame_time:
259 * @frame_clock: a #GdkFrameClock
261 * Gets the time that should currently be used for animations. Inside
262 * the processing of a frame, it's the time used to compute the
263 * animation position of everything in a frame. Outside of a frame, it's
264 * the time of the conceptual "previous frame," which may be either
265 * the actual previous frame time, or if that's too old, an updated
269 * Return value: a timestamp in microseconds, in the timescale of
270 * of g_get_monotonic_time().
273 gdk_frame_clock_get_frame_time (GdkFrameClock *frame_clock)
275 g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), 0);
277 return GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->get_frame_time (frame_clock);
281 * gdk_frame_clock_request_phase:
282 * @frame_clock: a #GdkFrameClock
284 * Asks the frame clock to run a particular phase. The signal
285 * corresponding the requested phase will be emitted the next
286 * time the frame clock processes. Multiple calls to
287 * gdk_frame_clock_request_phase() will be combined togethe
288 * and only one frame processed.
293 gdk_frame_clock_request_phase (GdkFrameClock *frame_clock,
294 GdkFrameClockPhase phase)
296 g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
298 GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->request_phase (frame_clock, phase);
303 _gdk_frame_clock_freeze (GdkFrameClock *clock)
305 g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
307 GDK_FRAME_CLOCK_GET_CLASS (clock)->freeze (clock);
312 _gdk_frame_clock_thaw (GdkFrameClock *clock)
314 g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
316 GDK_FRAME_CLOCK_GET_CLASS (clock)->thaw (clock);
320 * gdk_frame_clock_get_frame_counter:
321 * @frame_clock: a #GdkFrameClock
323 * A #GdkFrameClock maintains a 64-bit counter that increments for
326 * Returns: inside frame processing, the value of the frame counter
327 * for the current frame. Outside of frame processing, the frame
328 * counter for the last frame.
332 gdk_frame_clock_get_frame_counter (GdkFrameClock *frame_clock)
334 GdkFrameClockPrivate *priv;
336 g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), 0);
338 priv = frame_clock->priv;
340 return priv->frame_counter;
344 * gdk_frame_clock_get_history_start:
345 * @frame_clock: a #GdkFrameClock
347 * #GdkFrameClock internally keeps a history of #GdkFrameTiming
348 * objects for recent frames that can be retrieved with
349 * gdk_frame_clock_get_timings(). The set of stored frames
350 * is the set from the counter values given by
351 * gdk_frame_clock_get_history_start() and
352 * gdk_frame_clock_get_frame_counter(), inclusive.
354 * Return value: the frame counter value for the oldest frame
355 * that is available in the internal frame history of the
360 gdk_frame_clock_get_history_start (GdkFrameClock *frame_clock)
362 GdkFrameClockPrivate *priv;
364 g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), 0);
366 priv = frame_clock->priv;
368 return priv->frame_counter + 1 - priv->n_timings;
372 _gdk_frame_clock_begin_frame (GdkFrameClock *frame_clock)
374 GdkFrameClockPrivate *priv;
376 g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
378 priv = frame_clock->priv;
380 priv->frame_counter++;
381 priv->current = (priv->current + 1) % FRAME_HISTORY_MAX_LENGTH;
383 if (priv->n_timings < FRAME_HISTORY_MAX_LENGTH)
387 gdk_frame_timings_unref(priv->timings[priv->current]);
390 priv->timings[priv->current] = _gdk_frame_timings_new (priv->frame_counter);
394 * gdk_frame_clock_get_timings:
395 * @frame_clock: a #GdkFrameClock
396 * @frame_counter: the frame counter value identifying the frame to
399 * Retrieves a #GdkFrameTimings object holding timing information
400 * for the current frame or a recent frame. The #GdkFrameTimings
401 * object may not yet be complete: see gdk_frame_timings_get_complete().
403 * Return value: the #GdkFrameTimings object for the specified
404 * frame, or %NULL if it is not available. See
405 * gdk_frame_clock_get_history_start().
409 gdk_frame_clock_get_timings (GdkFrameClock *frame_clock,
410 gint64 frame_counter)
412 GdkFrameClockPrivate *priv;
415 g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), NULL);
417 priv = frame_clock->priv;
419 if (frame_counter > priv->frame_counter)
422 if (frame_counter <= priv->frame_counter - priv->n_timings)
425 pos = (priv->current - (priv->frame_counter - frame_counter) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
427 return priv->timings[pos];
431 * gdk_frame_clock_get_current_timings:
432 * @frame_clock: a #GdkFrameClock
434 * Gets the frame timings for the current frame.
436 * Returns: the #GdkFrameTimings for the frame currently being
437 * processed, or even no frame is being processed, for the
438 * previous frame. Before any frames have been procesed,
443 gdk_frame_clock_get_current_timings (GdkFrameClock *frame_clock)
445 GdkFrameClockPrivate *priv;
447 g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), 0);
449 priv = frame_clock->priv;
451 return gdk_frame_clock_get_timings (frame_clock, priv->frame_counter);
455 #ifdef G_ENABLE_DEBUG
457 _gdk_frame_clock_debug_print_timings (GdkFrameClock *clock,
458 GdkFrameTimings *timings)
460 gint64 previous_frame_time = 0;
461 GdkFrameTimings *previous_timings = gdk_frame_clock_get_timings (clock,
462 timings->frame_counter - 1);
464 if (previous_timings != NULL)
465 previous_frame_time = previous_timings->frame_time;
467 g_print ("%5" G_GINT64_FORMAT ":", timings->frame_counter);
468 if (previous_frame_time != 0)
470 g_print (" interval=%-4.1f", (timings->frame_time - previous_frame_time) / 1000.);
471 g_print (timings->slept_before ? " (sleep)" : " ");
473 if (timings->layout_start_time != 0)
474 g_print (" layout_start=%-4.1f", (timings->layout_start_time - timings->frame_time) / 1000.);
475 if (timings->paint_start_time != 0)
476 g_print (" paint_start=%-4.1f", (timings->paint_start_time - timings->frame_time) / 1000.);
477 if (timings->frame_end_time != 0)
478 g_print (" frame_end=%-4.1f", (timings->frame_end_time - timings->frame_time) / 1000.);
479 if (timings->presentation_time != 0)
480 g_print (" present=%-4.1f", (timings->presentation_time - timings->frame_time) / 1000.);
481 if (timings->predicted_presentation_time != 0)
482 g_print (" predicted=%-4.1f", (timings->predicted_presentation_time - timings->frame_time) / 1000.);
483 if (timings->refresh_interval != 0)
484 g_print (" refresh_interval=%-4.1f", timings->refresh_interval / 1000.);
487 #endif /* G_ENABLE_DEBUG */
489 #define DEFAULT_REFRESH_INTERVAL 16667 /* 16.7ms (1/60th second) */
490 #define MAX_HISTORY_AGE 150000 /* 150ms */
493 * gdk_frame_clock_get_refresh_info:
494 * @frame_clock: a #GdkFrameClock
495 * @base_time: base time for determining a presentaton time
496 * @refresh_interval_return: a location to store the determined refresh
497 * interval, or %NULL. A default refresh interval of 1/60th of
498 * a second will be stored if no history is present.
499 * @presentation_time_return: a location to store the next
500 * candidate presentation time after the given base time.
501 * 0 will be will be stored if no history is present.
503 * Using the frame history stored in the frame clock, finds the last
504 * known presentation time and refresh interval, and assuming that
505 * presentation times are separated by the refresh interval,
506 * predicts a presentation time that is a multiple of the refresh
507 * interval after the last presentation time, and later than @base_time.
512 gdk_frame_clock_get_refresh_info (GdkFrameClock *frame_clock,
514 gint64 *refresh_interval_return,
515 gint64 *presentation_time_return)
517 gint64 frame_counter;
519 g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
521 frame_counter = gdk_frame_clock_get_frame_counter (frame_clock);
523 if (presentation_time_return)
524 *presentation_time_return = 0;
525 if (refresh_interval_return)
526 *refresh_interval_return = DEFAULT_REFRESH_INTERVAL;
530 GdkFrameTimings *timings = gdk_frame_clock_get_timings (frame_clock, frame_counter);
531 gint64 presentation_time;
532 gint64 refresh_interval;
537 refresh_interval = timings->refresh_interval;
538 presentation_time = timings->presentation_time;
540 if (presentation_time != 0)
542 if (presentation_time > base_time - MAX_HISTORY_AGE &&
543 presentation_time_return)
545 if (refresh_interval == 0)
546 refresh_interval = DEFAULT_REFRESH_INTERVAL;
548 if (refresh_interval_return)
549 *refresh_interval_return = refresh_interval;
551 while (presentation_time < base_time)
552 presentation_time += refresh_interval;
554 if (presentation_time_return)
555 *presentation_time_return = presentation_time;