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