1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * Modified by the GTK+ Team and others 1997-2010.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23  */
24 
25 #include "config.h"
26 
27 #include "gdkinternals.h"
28 #include "gdkframeclockprivate.h"
29 #include "gdkframeclockidle.h"
30 #include "gdkprofilerprivate.h"
31 #include "gdk.h"
32 
33 #ifdef G_OS_WIN32
34 #include <windows.h>
35 #endif
36 
37 #define FRAME_INTERVAL 16667 /* microseconds */
38 
39 typedef enum {
40   SMOOTH_PHASE_STATE_VALID = 0,    /* explicit, since we count on zero-init */
41   SMOOTH_PHASE_STATE_AWAIT_FIRST,
42   SMOOTH_PHASE_STATE_AWAIT_DRAWN,
43 } SmoothDeltaState;
44 
45 struct _GdkFrameClockIdlePrivate
46 {
47   gint64 frame_time;                   /* The exact time we last ran the clock cycle, or 0 if never */
48   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 */
49   gint64 smoothed_frame_time_period;   /* The grid size that smoothed_frame_time_base is aligned to */
50   gint64 smoothed_frame_time_reported; /* Ensures we are always monotonic */
51   gint64 smoothed_frame_time_phase;    /* The offset of the first reported frame time, in the current animation sequence, from the preceding vsync */
52   gint64 min_next_frame_time;          /* We're not synced to vblank, so wait at least until this before next cycle to avoid busy looping */
53   SmoothDeltaState smooth_phase_state; /* The state of smoothed_frame_time_phase - is it valid, awaiting vsync etc. Thanks to zero-init, the initial value
54                                           of smoothed_frame_time_phase is `0`. This is valid, since we didn't get a "frame drawn" event yet. Accordingly,
55                                           the initial value of smooth_phase_state is SMOOTH_PHASE_STATE_VALID. See the comment in gdk_frame_clock_paint_idle()
56                                           for details. */
57 
58   gint64 sleep_serial;
59 #ifdef G_ENABLE_DEBUG
60   gint64 freeze_time;
61 #endif
62 
63   guint flush_idle_id;
64   guint paint_idle_id;
65   guint freeze_count;
66   guint updating_count;
67 
68   GdkFrameClockPhase requested;
69   GdkFrameClockPhase phase;
70 
71   guint in_paint_idle : 1;
72   guint paint_is_thaw : 1;
73 #ifdef G_OS_WIN32
74   guint begin_period : 1;
75 #endif
76 };
77 
78 static gboolean gdk_frame_clock_flush_idle (void *data);
79 static gboolean gdk_frame_clock_paint_idle (void *data);
80 
G_DEFINE_TYPE_WITH_PRIVATE(GdkFrameClockIdle,gdk_frame_clock_idle,GDK_TYPE_FRAME_CLOCK)81 G_DEFINE_TYPE_WITH_PRIVATE (GdkFrameClockIdle, gdk_frame_clock_idle, GDK_TYPE_FRAME_CLOCK)
82 
83 static gint64 sleep_serial;
84 static gint64 sleep_source_prepare_time;
85 static GSource *sleep_source;
86 
87 static gboolean
88 sleep_source_prepare (GSource *source,
89                       gint    *timeout)
90 {
91   sleep_source_prepare_time = g_source_get_time (source);
92   *timeout = -1;
93   return FALSE;
94 }
95 
96 static gboolean
sleep_source_check(GSource * source)97 sleep_source_check (GSource *source)
98 {
99   if (g_source_get_time (source) != sleep_source_prepare_time)
100     sleep_serial++;
101 
102   return FALSE;
103 }
104 
105 static gboolean
sleep_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)106 sleep_source_dispatch (GSource     *source,
107                        GSourceFunc  callback,
108                        gpointer     user_data)
109 {
110   return TRUE;
111 }
112 
113 static GSourceFuncs sleep_source_funcs = {
114   sleep_source_prepare,
115   sleep_source_check,
116   sleep_source_dispatch,
117   NULL /* finalize */
118 };
119 
120 static gint64
get_sleep_serial(void)121 get_sleep_serial (void)
122 {
123   if (sleep_source == NULL)
124     {
125       sleep_source = g_source_new (&sleep_source_funcs, sizeof (GSource));
126 
127       g_source_set_priority (sleep_source, G_PRIORITY_HIGH);
128       g_source_attach (sleep_source, NULL);
129       g_source_unref (sleep_source);
130     }
131 
132   return sleep_serial;
133 }
134 
135 static void
gdk_frame_clock_idle_init(GdkFrameClockIdle * frame_clock_idle)136 gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
137 {
138   GdkFrameClockIdlePrivate *priv;
139 
140   frame_clock_idle->priv = priv =
141     gdk_frame_clock_idle_get_instance_private (frame_clock_idle);
142 
143   priv->freeze_count = 0;
144   priv->smoothed_frame_time_period = FRAME_INTERVAL;
145 }
146 
147 static void
gdk_frame_clock_idle_dispose(GObject * object)148 gdk_frame_clock_idle_dispose (GObject *object)
149 {
150   GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (object)->priv;
151 
152   if (priv->flush_idle_id != 0)
153     {
154       g_source_remove (priv->flush_idle_id);
155       priv->flush_idle_id = 0;
156     }
157 
158   if (priv->paint_idle_id != 0)
159     {
160       g_source_remove (priv->paint_idle_id);
161       priv->paint_idle_id = 0;
162     }
163 
164 #ifdef G_OS_WIN32
165   if (priv->begin_period)
166     {
167       timeEndPeriod(1);
168       priv->begin_period = FALSE;
169     }
170 #endif
171 
172   G_OBJECT_CLASS (gdk_frame_clock_idle_parent_class)->dispose (object);
173 }
174 
175 /* Note: This is never called on first frame, so
176  * smoothed_frame_time_base != 0 and we have a valid frame_interval. */
177 static gint64
compute_smooth_frame_time(GdkFrameClock * clock,gint64 new_frame_time,gboolean new_frame_time_is_vsync_related,gint64 smoothed_frame_time_base,gint64 frame_interval)178 compute_smooth_frame_time (GdkFrameClock *clock,
179                            gint64 new_frame_time,
180                            gboolean new_frame_time_is_vsync_related,
181                            gint64 smoothed_frame_time_base,
182                            gint64 frame_interval)
183 {
184   GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
185   int frames_passed;
186   gint64 new_smoothed_time;
187   gint64 current_error;
188   gint64 correction_magnitude;
189 
190   /* Consecutive frame, assume it is an integer number of frames later, so round to nearest such */
191   /* NOTE:  This is >= 0, because smoothed_frame_time_base is < frame_interval/2 from old_frame_time
192    *        and new_frame_time >= old_frame_time. */
193   frames_passed = (new_frame_time - smoothed_frame_time_base + frame_interval / 2) / frame_interval;
194 
195   /* We use an approximately whole number of frames in the future from
196    * last smoothed frame time. This way we avoid minor jitter in the
197    * frame times making the animation speed uneven, but still animate
198    * evenly in case of whole frame skips. */
199   new_smoothed_time = smoothed_frame_time_base + frames_passed * frame_interval;
200 
201   /* However, sometimes the smoothed time is too much off from the
202    * real time. For example, if the first frame clock cycle happened
203    * not due to a frame rendering but an input event, then
204    * new_frame_time could happen to be near the middle between two
205    * frames. If that happens and we then start regularly animating at
206    * the refresh_rate, then the jitter in the real time may cause us
207    * to randomly sometimes round up, and sometimes down.
208    *
209    * To combat this we converge the smooth time towards the real time
210    * in a way that is slow when they are near and fast when they are
211    * far from each other.
212    *
213    * This is done by using the square of the error as the correction
214    * magnitude. I.e. if the error is 0.5 frame, we correct by
215    * 0.5*0.5=0.25 frame, if the error is 0.25 we correct by 0.125, if
216    * the error is 0.1, frame we correct by 0.01 frame, etc.
217    *
218    * The actual computation is:
219    *   (current_error/frame_interval)*(current_error/frame_interval)*frame_interval
220    * But this can be simplified as below.
221    *
222    * Note: We only do this correction if the new frame is caused by a
223    * thaw of the frame clock, so that we know the time is actually
224    * related to the physical vblank. For frameclock cycles triggered
225    * by other events we always step up in whole frames from the last
226    * reported time.
227    */
228   if (new_frame_time_is_vsync_related)
229     {
230       current_error = new_smoothed_time - new_frame_time;
231       correction_magnitude = current_error * current_error / frame_interval; /* Note, this is always > 0 due to the square */
232       if (current_error > 0)
233         new_smoothed_time -= correction_magnitude;
234       else
235         new_smoothed_time += correction_magnitude;
236     }
237 
238   /* Ensure we're always monotonic  */
239   if (new_smoothed_time <= priv->smoothed_frame_time_reported)
240     new_smoothed_time = priv->smoothed_frame_time_reported;
241 
242   return new_smoothed_time;
243 }
244 
245 static gint64
gdk_frame_clock_idle_get_frame_time(GdkFrameClock * clock)246 gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
247 {
248   GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
249   gint64 now;
250   gint64 new_smoothed_time;
251 
252   /* can't change frame time during a paint */
253   if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE &&
254       priv->phase != GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS &&
255       (priv->phase != GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT || priv->in_paint_idle))
256     return priv->smoothed_frame_time_base;
257 
258   /* Outside a paint, pick something smoothed close to now */
259   now = g_get_monotonic_time ();
260 
261   /* First time frame, just return something */
262   if (priv->smoothed_frame_time_base == 0)
263     {
264       priv->smoothed_frame_time_reported = now;
265       return now;
266     }
267 
268   /* Since time is monotonic this is <= what we will pick for the next cycle, but
269      more likely than not it will be equal if we're doing a constant animation. */
270   new_smoothed_time = compute_smooth_frame_time (clock, now, FALSE,
271                                                  priv->smoothed_frame_time_base,
272                                                  priv->smoothed_frame_time_period);
273 
274   priv->smoothed_frame_time_reported = new_smoothed_time;
275   return new_smoothed_time;
276 }
277 
278 #define RUN_FLUSH_IDLE(priv)                                            \
279   ((priv)->freeze_count == 0 &&                                         \
280    ((priv)->requested & GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0)
281 
282 /* The reason why we track updating_count separately here and don't
283  * just add GDK_FRAME_CLOCK_PHASE_UPDATE into ->request on every frame
284  * is so that we can avoid doing one more frame when an animation
285  * is cancelled.
286  */
287 #define RUN_PAINT_IDLE(priv)                                            \
288   ((priv)->freeze_count == 0 &&                                         \
289    (((priv)->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0 ||   \
290     (priv)->updating_count > 0))
291 
292 static void
maybe_start_idle(GdkFrameClockIdle * clock_idle,gboolean caused_by_thaw)293 maybe_start_idle (GdkFrameClockIdle *clock_idle,
294                   gboolean caused_by_thaw)
295 {
296   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
297 
298   if (RUN_FLUSH_IDLE (priv) || RUN_PAINT_IDLE (priv))
299     {
300       guint min_interval = 0;
301 
302       if (priv->min_next_frame_time != 0)
303         {
304           gint64 now = g_get_monotonic_time ();
305           gint64 min_interval_us = MAX (priv->min_next_frame_time, now) - now;
306           min_interval = (min_interval_us + 500) / 1000;
307         }
308 
309       if (priv->flush_idle_id == 0 && RUN_FLUSH_IDLE (priv))
310         {
311           priv->flush_idle_id = gdk_threads_add_timeout_full (GDK_PRIORITY_EVENTS + 1,
312                                                               min_interval,
313                                                               gdk_frame_clock_flush_idle,
314                                                               g_object_ref (clock_idle),
315                                                               (GDestroyNotify) g_object_unref);
316           g_source_set_name_by_id (priv->flush_idle_id, "[gtk+] gdk_frame_clock_flush_idle");
317         }
318 
319       if (!priv->in_paint_idle &&
320 	  priv->paint_idle_id == 0 && RUN_PAINT_IDLE (priv))
321         {
322           priv->paint_is_thaw = caused_by_thaw;
323           priv->paint_idle_id = gdk_threads_add_timeout_full (GDK_PRIORITY_REDRAW,
324                                                               min_interval,
325                                                               gdk_frame_clock_paint_idle,
326                                                               g_object_ref (clock_idle),
327                                                               (GDestroyNotify) g_object_unref);
328           g_source_set_name_by_id (priv->paint_idle_id, "[gtk+] gdk_frame_clock_paint_idle");
329         }
330     }
331 }
332 
333 static void
maybe_stop_idle(GdkFrameClockIdle * clock_idle)334 maybe_stop_idle (GdkFrameClockIdle *clock_idle)
335 {
336   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
337 
338   if (priv->flush_idle_id != 0 && !RUN_FLUSH_IDLE (priv))
339     {
340       g_source_remove (priv->flush_idle_id);
341       priv->flush_idle_id = 0;
342     }
343 
344   if (priv->paint_idle_id != 0 && !RUN_PAINT_IDLE (priv))
345     {
346       g_source_remove (priv->paint_idle_id);
347       priv->paint_idle_id = 0;
348     }
349 }
350 
351 static gboolean
gdk_frame_clock_flush_idle(void * data)352 gdk_frame_clock_flush_idle (void *data)
353 {
354   GdkFrameClock *clock = GDK_FRAME_CLOCK (data);
355   GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
356   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
357 
358   priv->flush_idle_id = 0;
359 
360   if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE)
361     return FALSE;
362 
363   priv->phase = GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS;
364   priv->requested &= ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS;
365 
366   _gdk_frame_clock_emit_flush_events (clock);
367 
368   if ((priv->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0 ||
369       priv->updating_count > 0)
370     priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
371   else
372     priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
373 
374   return FALSE;
375 }
376 
377 /*
378  * Returns the positive remainder.
379  *
380  * As an example, lets consider (-5) % 16:
381  *
382  *   (-5) % 16 = (0 * 16) + (-5) = -5
383  *
384  * If we only want positive remainders, we can instead calculate
385  *
386  *   (-5) % 16 = (1 * 16) + (-5) = 11
387  *
388  * The built-in `%` operator returns the former, positive_modulo() returns the latter.
389  */
390 static int
positive_modulo(int i,int n)391 positive_modulo (int i, int n)
392 {
393   return (i % n + n) % n;
394 }
395 
396 static gboolean
gdk_frame_clock_paint_idle(void * data)397 gdk_frame_clock_paint_idle (void *data)
398 {
399   GdkFrameClock *clock = GDK_FRAME_CLOCK (data);
400   GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
401   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
402   gboolean skip_to_resume_events;
403   GdkFrameTimings *timings = NULL;
404 
405   priv->paint_idle_id = 0;
406   priv->in_paint_idle = TRUE;
407   priv->min_next_frame_time = 0;
408 
409   skip_to_resume_events =
410     (priv->requested & ~(GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS | GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS)) == 0 &&
411     priv->updating_count == 0;
412 
413   if (priv->phase > GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT)
414     {
415       timings = gdk_frame_clock_get_current_timings (clock);
416     }
417 
418   if (!skip_to_resume_events)
419     {
420       switch (priv->phase)
421         {
422         case GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS:
423           break;
424         case GDK_FRAME_CLOCK_PHASE_NONE:
425         case GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT:
426           if (priv->freeze_count == 0)
427             {
428               gint64 frame_interval = FRAME_INTERVAL;
429               GdkFrameTimings *prev_timings = gdk_frame_clock_get_current_timings (clock);
430 
431               if (prev_timings && prev_timings->refresh_interval)
432                 frame_interval = prev_timings->refresh_interval;
433 
434               priv->frame_time = g_get_monotonic_time ();
435 
436               /*
437                * The first clock cycle of an animation might have been triggered by some external event. An external
438                * event can be an input event, an expired timer, data arriving over the network etc. This can happen at
439                * any time, so the cycle could have been scheduled at some random time rather then immediately after a
440                * frame completion. The offset between the start of the first animation cycle and the preceding vsync is
441                * called the "phase" of the clock cycle start time (not to be confused with the phase of the frame
442                * clock).
443                *
444                * In this first clock cycle, the "smooth" frame time is simply the time when the cycle was started. This
445                * could be followed by several cycles which are not vsync-related. As long as we don't get a "frame
446                * drawn" signal from the compositor, the clock cycles will occur every about frame_interval. Once we do
447                * get a "frame drawn" signal, from this point on the frame clock cycles will start shortly after the
448                * corresponding vsync signals, again every about frame_interval. The first vsync-related clock cycle
449                * might occur less than a refresh interval away from the last non-vsync-related cycle. See the diagram
450                * below for details. So while the cadence stays the same - a frame clock cycle every about frame_interval
451                * - the phase of the cycles start time has changed.
452                *
453                * Since we might have already reported the frame time to the application in the previous clock cycles, we
454                * have to adjust future reported frame times. We want the first vsync-related smooth time to be separated
455                * by exactly 1 frame_interval from the previous one, in order to maintain the regularity of the reported
456                * frame times. To achieve that, from this point on we add the phase of the first clock cycle start time to
457                * the smooth time. In order to compute that phase, accounting for possible skipped frames (e.g. due to
458                * compositor stalls), we want the following to be true:
459                *
460                *   first_vsync_smooth_time = last_non_vsync_smooth_time + frame_interval * (1 + frames_skipped)
461                *
462                * We can assign the following known/desired values to the above equation:
463                *
464                *   last_non_vsync_smooth_time = smoothed_frame_time_base
465                *   first_vsync_smooth_time = frame_time + smoothed_frame_time_phase
466                *
467                * That leads us to the following, from which we can extract smoothed_frame_time_phase:
468                *
469                *   frame_time + smoothed_frame_time_phase = smoothed_frame_time_base +
470                *                                            frame_interval * (1 + frames_skipped)
471                *
472                * In the following diagram, '|' mark a vsync, '*' mark the start of a clock cycle, '+' is the adjusted
473                * frame time, '!' marks the reception of "frame drawn" events from the compositor. Note that the clock
474                * cycle cadence changed after the first vsync-related cycle. This cadence is kept even if we don't
475                * receive a 'frame drawn' signal in a subsequent frame, since then we schedule the clock at intervals of
476                * refresh_interval.
477                *
478                * vsync             |           |           |           |           |           |...
479                * frame drawn       |           |           |!          |!          |           |...
480                * cycle start       |       *   |       *   |*          |*          |*          |...
481                * adjusted times    |       *   |       *   |       +   |       +   |       +   |...
482                * phase                                      ^------^
483                */
484               if (priv->smooth_phase_state == SMOOTH_PHASE_STATE_AWAIT_FIRST)
485                 {
486                   /* First animation cycle - usually unrelated to vsync */
487                   priv->smoothed_frame_time_base = 0;
488                   priv->smoothed_frame_time_phase = 0;
489                   priv->smooth_phase_state = SMOOTH_PHASE_STATE_AWAIT_DRAWN;
490                 }
491               else if (priv->smooth_phase_state == SMOOTH_PHASE_STATE_AWAIT_DRAWN &&
492                        priv->paint_is_thaw)
493                 {
494                   /* First vsync-related animation cycle, we can now compute the phase. We want the phase to satisfy
495                      0 <= phase < frame_interval */
496                   priv->smoothed_frame_time_phase =
497                       positive_modulo (priv->smoothed_frame_time_base - priv->frame_time,
498                                        frame_interval);
499                   priv->smooth_phase_state = SMOOTH_PHASE_STATE_VALID;
500                 }
501 
502               if (priv->smoothed_frame_time_base == 0)
503                 {
504                   /* First frame ever, or first cycle in a new animation sequence. Ensure monotonicity */
505                   priv->smoothed_frame_time_base = MAX (priv->frame_time, priv->smoothed_frame_time_reported);
506                 }
507               else
508                 {
509                   /* compute_smooth_frame_time() ensures monotonicity */
510                   priv->smoothed_frame_time_base =
511                       compute_smooth_frame_time (clock, priv->frame_time + priv->smoothed_frame_time_phase,
512                                                  priv->paint_is_thaw,
513                                                  priv->smoothed_frame_time_base,
514                                                  priv->smoothed_frame_time_period);
515                 }
516 
517               priv->smoothed_frame_time_period = frame_interval;
518               priv->smoothed_frame_time_reported = priv->smoothed_frame_time_base;
519 
520               _gdk_frame_clock_begin_frame (clock);
521               /* Note "current" is different now so timings != prev_timings */
522               timings = gdk_frame_clock_get_current_timings (clock);
523 
524               timings->frame_time = priv->frame_time;
525               timings->smoothed_frame_time = priv->smoothed_frame_time_base;
526               timings->slept_before = priv->sleep_serial != get_sleep_serial ();
527 
528               priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
529 
530               /* We always emit ::before-paint and ::after-paint if
531                * any of the intermediate phases are requested and
532                * they don't get repeated if you freeze/thaw while
533                * in them.
534                */
535               priv->requested &= ~GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
536               _gdk_frame_clock_emit_before_paint (clock);
537               priv->phase = GDK_FRAME_CLOCK_PHASE_UPDATE;
538             }
539           /* fallthrough */
540         case GDK_FRAME_CLOCK_PHASE_UPDATE:
541           if (priv->freeze_count == 0)
542             {
543               if ((priv->requested & GDK_FRAME_CLOCK_PHASE_UPDATE) != 0 ||
544                   priv->updating_count > 0)
545                 {
546                   priv->requested &= ~GDK_FRAME_CLOCK_PHASE_UPDATE;
547                   _gdk_frame_clock_emit_update (clock);
548                 }
549             }
550           /* fallthrough */
551         case GDK_FRAME_CLOCK_PHASE_LAYOUT:
552           if (priv->freeze_count == 0)
553             {
554 	      int iter;
555 #ifdef G_ENABLE_DEBUG
556               if (GDK_DEBUG_CHECK (FRAMES) || gdk_profiler_is_running ())
557                 {
558                   if (priv->phase != GDK_FRAME_CLOCK_PHASE_LAYOUT &&
559                       (priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT))
560                     timings->layout_start_time = g_get_monotonic_time ();
561                 }
562 #endif /* G_ENABLE_DEBUG */
563 
564               priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
565 	      /* We loop in the layout phase, because we don't want to progress
566 	       * into the paint phase with invalid size allocations. This may
567 	       * happen in some situation like races between user window
568 	       * resizes and natural size changes.
569 	       */
570 	      iter = 0;
571               while ((priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT) &&
572 		     priv->freeze_count == 0 && iter++ < 4)
573                 {
574                   priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
575                   _gdk_frame_clock_emit_layout (clock);
576                 }
577 	      if (iter == 5)
578 		g_warning ("gdk-frame-clock: layout continuously requested, giving up after 4 tries");
579             }
580           /* fallthrough */
581         case GDK_FRAME_CLOCK_PHASE_PAINT:
582           if (priv->freeze_count == 0)
583             {
584 #ifdef G_ENABLE_DEBUG
585               if (GDK_DEBUG_CHECK (FRAMES) || gdk_profiler_is_running ())
586                 {
587                   if (priv->phase != GDK_FRAME_CLOCK_PHASE_PAINT &&
588                       (priv->requested & GDK_FRAME_CLOCK_PHASE_PAINT))
589                     timings->paint_start_time = g_get_monotonic_time ();
590                 }
591 #endif /* G_ENABLE_DEBUG */
592 
593               priv->phase = GDK_FRAME_CLOCK_PHASE_PAINT;
594               if (priv->requested & GDK_FRAME_CLOCK_PHASE_PAINT)
595                 {
596                   priv->requested &= ~GDK_FRAME_CLOCK_PHASE_PAINT;
597                   _gdk_frame_clock_emit_paint (clock);
598                 }
599             }
600           /* fallthrough */
601         case GDK_FRAME_CLOCK_PHASE_AFTER_PAINT:
602           if (priv->freeze_count == 0)
603             {
604               priv->requested &= ~GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
605               _gdk_frame_clock_emit_after_paint (clock);
606               /* the ::after-paint phase doesn't get repeated on freeze/thaw,
607                */
608               priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
609 
610 #ifdef G_ENABLE_DEBUG
611               if (GDK_DEBUG_CHECK (FRAMES) || gdk_profiler_is_running ())
612                 timings->frame_end_time = g_get_monotonic_time ();
613 #endif /* G_ENABLE_DEBUG */
614             }
615           /* fallthrough */
616         case GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS:
617           ;
618         }
619     }
620 
621 #ifdef G_ENABLE_DEBUG
622   if (GDK_DEBUG_CHECK (FRAMES))
623     {
624       if (timings && timings->complete)
625         _gdk_frame_clock_debug_print_timings (clock, timings);
626     }
627 #endif /* G_ENABLE_DEBUG */
628 
629   if (priv->requested & GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS)
630     {
631       priv->requested &= ~GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS;
632       _gdk_frame_clock_emit_resume_events (clock);
633     }
634 
635   if (priv->freeze_count == 0)
636     priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
637 
638   priv->in_paint_idle = FALSE;
639 
640   /* If there is throttling in the backend layer, then we'll do another
641    * update as soon as the backend unthrottles (if there is work to do),
642    * otherwise we need to figure when the next frame should be.
643    */
644   if (priv->freeze_count == 0)
645     {
646       /*
647        * If we don't receive "frame drawn" events, smooth_cycle_start will simply be advanced in constant increments of
648        * the refresh interval. That way we get absolute target times for the next cycles, which should prevent skewing
649        * in the scheduling of the frame clock.
650        *
651        * Once we do receive "frame drawn" events, smooth_cycle_start will track the vsync, and do so in a more stable
652        * way compared to frame_time. If we then no longer receive "frame drawn" events, smooth_cycle_start will again be
653        * simply advanced in increments of the refresh interval, but this time we are in sync with the vsync. If we start
654        * receiving "frame drawn" events shortly after loosing them, then we should still be in sync.
655        */
656       gint64 smooth_cycle_start = priv->smoothed_frame_time_base - priv->smoothed_frame_time_phase;
657       priv->min_next_frame_time = smooth_cycle_start + priv->smoothed_frame_time_period;
658 
659       maybe_start_idle (clock_idle, FALSE);
660     }
661 
662   if (priv->freeze_count == 0)
663     priv->sleep_serial = get_sleep_serial ();
664 
665   return FALSE;
666 }
667 
668 static void
gdk_frame_clock_idle_request_phase(GdkFrameClock * clock,GdkFrameClockPhase phase)669 gdk_frame_clock_idle_request_phase (GdkFrameClock      *clock,
670                                     GdkFrameClockPhase  phase)
671 {
672   GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
673   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
674 
675   priv->requested |= phase;
676   maybe_start_idle (clock_idle, FALSE);
677 }
678 
679 static void
gdk_frame_clock_idle_begin_updating(GdkFrameClock * clock)680 gdk_frame_clock_idle_begin_updating (GdkFrameClock *clock)
681 {
682   GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
683   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
684 
685 #ifdef G_OS_WIN32
686   /* We need a higher resolution timer while doing animations */
687   if (priv->updating_count == 0 && !priv->begin_period)
688     {
689       timeBeginPeriod(1);
690       priv->begin_period = TRUE;
691     }
692 #endif
693 
694   if (priv->updating_count == 0)
695     {
696       priv->smooth_phase_state = SMOOTH_PHASE_STATE_AWAIT_FIRST;
697     }
698 
699   priv->updating_count++;
700   maybe_start_idle (clock_idle, FALSE);
701 }
702 
703 static void
gdk_frame_clock_idle_end_updating(GdkFrameClock * clock)704 gdk_frame_clock_idle_end_updating (GdkFrameClock *clock)
705 {
706   GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
707   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
708 
709   g_return_if_fail (priv->updating_count > 0);
710 
711   priv->updating_count--;
712   maybe_stop_idle (clock_idle);
713 
714   if (priv->updating_count == 0)
715     {
716       priv->smooth_phase_state = SMOOTH_PHASE_STATE_VALID;
717     }
718 
719 #ifdef G_OS_WIN32
720   if (priv->updating_count == 0 && priv->begin_period)
721     {
722       timeEndPeriod(1);
723       priv->begin_period = FALSE;
724     }
725 #endif
726 }
727 
728 static void
gdk_frame_clock_idle_freeze(GdkFrameClock * clock)729 gdk_frame_clock_idle_freeze (GdkFrameClock *clock)
730 {
731   GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
732   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
733 
734 #ifdef G_ENABLE_DEBUG
735   if (priv->freeze_count == 0)
736     {
737       if (gdk_profiler_is_running ())
738         priv->freeze_time = g_get_monotonic_time ();
739     }
740 #endif
741 
742   priv->freeze_count++;
743   maybe_stop_idle (clock_idle);
744 }
745 
746 static void
gdk_frame_clock_idle_thaw(GdkFrameClock * clock)747 gdk_frame_clock_idle_thaw (GdkFrameClock *clock)
748 {
749   GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
750   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
751 
752   g_return_if_fail (priv->freeze_count > 0);
753 
754   priv->freeze_count--;
755   if (priv->freeze_count == 0)
756     {
757       maybe_start_idle (clock_idle, TRUE);
758       /* If nothing is requested so we didn't start an idle, we need
759        * to skip to the end of the state chain, since the idle won't
760        * run and do it for us.
761        */
762       if (priv->paint_idle_id == 0)
763         priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
764 
765       priv->sleep_serial = get_sleep_serial ();
766 
767 #ifdef G_ENABLE_DEBUG
768       if (gdk_profiler_is_running ())
769         {
770           if (priv->freeze_time != 0)
771             {
772               gint64 thaw_time = g_get_monotonic_time ();
773               gdk_profiler_add_mark (priv->freeze_time * 1000,
774                                      (thaw_time - priv->freeze_time) * 1000,
775                                      "freeze", "");
776               priv->freeze_time = 0;
777             }
778         }
779 #endif
780     }
781 }
782 
783 static void
gdk_frame_clock_idle_class_init(GdkFrameClockIdleClass * klass)784 gdk_frame_clock_idle_class_init (GdkFrameClockIdleClass *klass)
785 {
786   GObjectClass *gobject_class = (GObjectClass*) klass;
787   GdkFrameClockClass *frame_clock_class = (GdkFrameClockClass *)klass;
788 
789   gobject_class->dispose = gdk_frame_clock_idle_dispose;
790 
791   frame_clock_class->get_frame_time = gdk_frame_clock_idle_get_frame_time;
792   frame_clock_class->request_phase = gdk_frame_clock_idle_request_phase;
793   frame_clock_class->begin_updating = gdk_frame_clock_idle_begin_updating;
794   frame_clock_class->end_updating = gdk_frame_clock_idle_end_updating;
795   frame_clock_class->freeze = gdk_frame_clock_idle_freeze;
796   frame_clock_class->thaw = gdk_frame_clock_idle_thaw;
797 }
798 
799 GdkFrameClock *
_gdk_frame_clock_idle_new(void)800 _gdk_frame_clock_idle_new (void)
801 {
802   GdkFrameClockIdle *clock;
803 
804   clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
805 
806   return GDK_FRAME_CLOCK (clock);
807 }
808