static gboolean gtk_gears_tick (GtkWidget *widget, GdkFrameClock *frame_clock, gpointer user_data) { GtkGears *gears = GTK_GEARS (widget); GtkGearsPrivate *priv = gtk_gears_get_instance_private (gears); GdkFrameTimings *timings, *previous_timings; gint64 previous_frame_time = 0; gint64 frame_time; gint64 history_start, history_len; gint64 frame; char *s; frame = gdk_frame_clock_get_frame_counter (frame_clock); frame_time = gdk_frame_clock_get_frame_time (frame_clock); if (priv->first_frame_time == 0) { /* No need for changes on first frame */ priv->first_frame_time = frame_time; if (priv->fps_label) gtk_label_set_label (priv->fps_label, "FPS: ---"); return G_SOURCE_CONTINUE; } /* glxgears advances 70 degrees per second, so do the same */ priv->angle = fmod ((frame_time - priv->first_frame_time) / (double)G_USEC_PER_SEC * 70.0, 360.0); gtk_widget_queue_draw (widget); history_start = gdk_frame_clock_get_history_start (frame_clock); if (priv->fps_label && frame % 60 == 0) { history_len = frame - history_start; if (history_len > 0) { previous_timings = gdk_frame_clock_get_timings (frame_clock, frame - history_len); previous_frame_time = gdk_frame_timings_get_frame_time (previous_timings); s = g_strdup_printf ("FPS: %-4.1f", (G_USEC_PER_SEC * history_len) / (double)(frame_time - previous_frame_time)); gtk_label_set_label (priv->fps_label, s); g_free (s); } } timings = gdk_frame_clock_get_current_timings (frame_clock); previous_timings = gdk_frame_clock_get_timings (frame_clock, gdk_frame_timings_get_frame_counter (timings) - 1); if (previous_timings != NULL) previous_frame_time = gdk_frame_timings_get_frame_time (previous_timings); return G_SOURCE_CONTINUE; }
static void on_update (GdkFrameClock *frame_clock, gpointer data) { GdkFrameTimings *timings = gdk_frame_clock_get_current_timings (frame_clock); gint64 frame_time = gdk_frame_timings_get_frame_time (timings); gint64 predicted_presentation_time = gdk_frame_timings_get_predicted_presentation_time (timings); gint64 refresh_interval; FrameData *pending_frame; if (clock_time_base == 0) clock_time_base = frame_time + PRE_BUFFER_TIME; gdk_frame_clock_get_refresh_info (frame_clock, frame_time, &refresh_interval, NULL); pending_frame = peek_pending_frame (); if (stream_time_to_clock_time (pending_frame->stream_time) < predicted_presentation_time + refresh_interval / 2) { while (TRUE) { FrameData *next_frame = peek_next_frame (); if (next_frame && stream_time_to_clock_time (next_frame->stream_time) < predicted_presentation_time + refresh_interval / 2) { g_slice_free (FrameData, unqueue_frame ()); n_frames++; dropped_frames++; pending_frame = next_frame; } else break; } if (displayed_frame) past_frames = g_list_prepend (past_frames, displayed_frame); n_frames++; displayed_frame = unqueue_frame (); displayed_frame->clock_time = stream_time_to_clock_time (displayed_frame->stream_time); displayed_frame->frame_counter = gdk_frame_timings_get_frame_counter (timings); variable_add (&time_factor_stats, time_factor); collect_old_frames (); print_statistics (); gtk_widget_queue_draw (window); } }
static gboolean gdk_frame_clock_paint_idle (void *data) { GdkFrameClock *clock = GDK_FRAME_CLOCK (data); GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); GdkFrameClockIdlePrivate *priv = clock_idle->priv; gboolean skip_to_resume_events; GdkFrameTimings *timings = NULL; 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 && priv->updating_count == 0; if (priv->phase > GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT) { timings = gdk_frame_clock_get_current_timings (clock); } if (!skip_to_resume_events) { switch (priv->phase) { case GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS: break; case GDK_FRAME_CLOCK_PHASE_NONE: case GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT: if (priv->freeze_count == 0) { priv->frame_time = compute_frame_time (clock_idle); _gdk_frame_clock_begin_frame (clock); timings = gdk_frame_clock_get_current_timings (clock); timings->frame_time = priv->frame_time; timings->slept_before = priv->sleep_serial != get_sleep_serial (); priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT; /* We always emit ::before-paint and ::after-paint if * any of the intermediate phases are requested and * they don't get repeated if you freeze/thaw while * in them. */ priv->requested &= ~GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT; g_signal_emit_by_name (G_OBJECT (clock), "before-paint"); priv->phase = GDK_FRAME_CLOCK_PHASE_UPDATE; } /* fallthrough */ case GDK_FRAME_CLOCK_PHASE_UPDATE: if (priv->freeze_count == 0) { if ((priv->requested & GDK_FRAME_CLOCK_PHASE_UPDATE) != 0 || priv->updating_count > 0) { priv->requested &= ~GDK_FRAME_CLOCK_PHASE_UPDATE; g_signal_emit_by_name (G_OBJECT (clock), "update"); } } /* fallthrough */ case GDK_FRAME_CLOCK_PHASE_LAYOUT: if (priv->freeze_count == 0) { int iter; #ifdef G_ENABLE_DEBUG if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0) { if (priv->phase != GDK_FRAME_CLOCK_PHASE_LAYOUT && (priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT)) timings->layout_start_time = g_get_monotonic_time (); } #endif /* G_ENABLE_DEBUG */ priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT; /* We loop in the layout phase, because we don't want to progress * into the paint phase with invalid size allocations. This may * happen in some situation like races between user window * resizes and natural size changes. */ iter = 0; while ((priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT) && priv->freeze_count == 0 && iter++ < 4) { priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT; g_signal_emit_by_name (G_OBJECT (clock), "layout"); } if (iter == 5) g_warning ("gdk-frame-clock: layout continuously requested, giving up after 4 tries"); } /* fallthrough */ case GDK_FRAME_CLOCK_PHASE_PAINT: if (priv->freeze_count == 0) { #ifdef G_ENABLE_DEBUG if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0) { if (priv->phase != GDK_FRAME_CLOCK_PHASE_PAINT && (priv->requested & GDK_FRAME_CLOCK_PHASE_PAINT)) timings->paint_start_time = g_get_monotonic_time (); } #endif /* G_ENABLE_DEBUG */ priv->phase = GDK_FRAME_CLOCK_PHASE_PAINT; if (priv->requested & GDK_FRAME_CLOCK_PHASE_PAINT) { priv->requested &= ~GDK_FRAME_CLOCK_PHASE_PAINT; g_signal_emit_by_name (G_OBJECT (clock), "paint"); } } /* fallthrough */ case GDK_FRAME_CLOCK_PHASE_AFTER_PAINT: if (priv->freeze_count == 0) { priv->requested &= ~GDK_FRAME_CLOCK_PHASE_AFTER_PAINT; g_signal_emit_by_name (G_OBJECT (clock), "after-paint"); /* the ::after-paint phase doesn't get repeated on freeze/thaw, */ priv->phase = GDK_FRAME_CLOCK_PHASE_NONE; #ifdef G_ENABLE_DEBUG if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0) timings->frame_end_time = g_get_monotonic_time (); #endif /* G_ENABLE_DEBUG */ } /* fallthrough */ case GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS: ; } } #ifdef G_ENABLE_DEBUG if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0) { if (timings && timings->complete) _gdk_frame_clock_debug_print_timings (clock, timings); } #endif /* G_ENABLE_DEBUG */ if (priv->requested & GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS) { priv->requested &= ~GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS; g_signal_emit_by_name (G_OBJECT (clock), "resume-events"); } if (priv->freeze_count == 0) priv->phase = GDK_FRAME_CLOCK_PHASE_NONE; priv->in_paint_idle = FALSE; /* 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) { priv->min_next_frame_time = compute_min_next_frame_time (clock_idle, priv->frame_time); maybe_start_idle (clock_idle); } if (priv->freeze_count == 0) priv->sleep_serial = get_sleep_serial (); return FALSE; }