From: Benjamin Otte Date: Tue, 24 Apr 2018 17:04:44 +0000 (+0200) Subject: demo: Move benchmarking implementation to fishbowl widget X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2~22^2~407 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=db5b8ca9970a94960f23fb25108f2cc73de9061b;p=gtk4.git demo: Move benchmarking implementation to fishbowl widget --- diff --git a/demos/gtk-demo/fishbowl.c b/demos/gtk-demo/fishbowl.c index 7aeaf3206e..bc4650a5dd 100644 --- a/demos/gtk-demo/fishbowl.c +++ b/demos/gtk-demo/fishbowl.c @@ -9,162 +9,6 @@ #include "gtkfishbowl.h" -GtkWidget *info_label; -GtkWidget *allow_changes; - -#define N_STATS 5 - -#define STATS_UPDATE_TIME G_USEC_PER_SEC - -typedef struct _Stats Stats; -struct _Stats { - gint last_suggestion; -}; - -static Stats * -get_stats (GtkWidget *widget) -{ - static GQuark stats_quark = 0; - Stats *stats; - - if (G_UNLIKELY (stats_quark == 0)) - stats_quark = g_quark_from_static_string ("stats"); - - stats = g_object_get_qdata (G_OBJECT (widget), stats_quark); - if (stats == NULL) - { - stats = g_new0 (Stats, 1); - g_object_set_qdata_full (G_OBJECT (widget), stats_quark, stats, g_free); - } - - return stats; -} - -static gint64 -guess_refresh_interval (GdkFrameClock *frame_clock) -{ - gint64 interval; - gint64 i; - - interval = G_MAXINT64; - - for (i = gdk_frame_clock_get_history_start (frame_clock); - i < gdk_frame_clock_get_frame_counter (frame_clock); - i++) - { - GdkFrameTimings *t, *before; - gint64 ts, before_ts; - - t = gdk_frame_clock_get_timings (frame_clock, i); - before = gdk_frame_clock_get_timings (frame_clock, i - 1); - if (t == NULL || before == NULL) - continue; - - ts = gdk_frame_timings_get_frame_time (t); - before_ts = gdk_frame_timings_get_frame_time (before); - if (ts == 0 || before_ts == 0) - continue; - - interval = MIN (interval, ts - before_ts); - } - - if (interval == G_MAXINT64) - return 0; - - return interval; -} - -static void -do_stats (GtkWidget *widget, - gint *suggested_change) -{ - GdkFrameClock *frame_clock; - Stats *stats; - GdkFrameTimings *start, *end; - gint64 start_counter, end_counter; - gint64 n_frames, expected_frames; - gint64 start_timestamp, end_timestamp; - gint64 interval; - char *new_label; - - stats = get_stats (widget); - frame_clock = gtk_widget_get_frame_clock (widget); - if (frame_clock == NULL) - return; - - start_counter = gdk_frame_clock_get_history_start (frame_clock); - end_counter = gdk_frame_clock_get_frame_counter (frame_clock); - start = gdk_frame_clock_get_timings (frame_clock, start_counter); - for (end = gdk_frame_clock_get_timings (frame_clock, end_counter); - end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end); - end = gdk_frame_clock_get_timings (frame_clock, end_counter)) - end_counter--; - if (end_counter - start_counter < 4) - return; - - start_timestamp = gdk_frame_timings_get_presentation_time (start); - end_timestamp = gdk_frame_timings_get_presentation_time (end); - if (start_timestamp == 0 || end_timestamp == 0) - { - start_timestamp = gdk_frame_timings_get_frame_time (start); - end_timestamp = gdk_frame_timings_get_frame_time (end); - } - - interval = gdk_frame_timings_get_refresh_interval (end); - if (interval == 0) - { - interval = guess_refresh_interval (frame_clock); - if (interval == 0) - return; - } - n_frames = end_counter - start_counter; - expected_frames = round ((double) (end_timestamp - start_timestamp) / interval); - - new_label = g_strdup_printf ("icons - %.1f fps", - ((double) n_frames) * G_USEC_PER_SEC / (end_timestamp - start_timestamp)); - gtk_label_set_label (GTK_LABEL (info_label), new_label); - g_free (new_label); - - if (n_frames >= expected_frames) - { - if (stats->last_suggestion > 0) - stats->last_suggestion *= 2; - else - stats->last_suggestion = 1; - } - else if (n_frames + 1 < expected_frames) - { - if (stats->last_suggestion < 0) - stats->last_suggestion--; - else - stats->last_suggestion = -1; - } - else - { - stats->last_suggestion = 0; - } - - if (suggested_change) - *suggested_change = stats->last_suggestion; - else - stats->last_suggestion = 0; -} - -static gboolean -move_fish (gpointer bowl) -{ - gint suggested_change = 0, new_count; - - do_stats (bowl, - !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (allow_changes)) ? &suggested_change : NULL); - - new_count = gtk_fishbowl_get_count (GTK_FISHBOWL (bowl)) + suggested_change; - new_count = MAX (1, new_count); - gtk_fishbowl_set_count (GTK_FISHBOWL (bowl), new_count); - - return G_SOURCE_CONTINUE; -} - GtkWidget * do_fishbowl (GtkWidget *do_widget) { @@ -182,19 +26,12 @@ do_fishbowl (GtkWidget *do_widget) window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); bowl = GTK_WIDGET (gtk_builder_get_object (builder, "bowl")); gtk_fishbowl_set_use_icons (GTK_FISHBOWL (bowl), TRUE); - info_label = GTK_WIDGET (gtk_builder_get_object (builder, "info_label")); - allow_changes = GTK_WIDGET (gtk_builder_get_object (builder, "changes_allow")); gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget)); g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window); gtk_widget_realize (window); - g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE, - 1, - move_fish, - bowl, - NULL); } if (!gtk_widget_get_visible (window)) diff --git a/demos/gtk-demo/fishbowl.ui b/demos/gtk-demo/fishbowl.ui index a6899dbfa9..5cd82a6648 100644 --- a/demos/gtk-demo/fishbowl.ui +++ b/demos/gtk-demo/fishbowl.ui @@ -7,7 +7,24 @@ 1 - + + fps + + + end + + + + + + + + end + + + + + Icons, end @@ -48,6 +65,7 @@ True True + True diff --git a/demos/gtk-demo/gtkfishbowl.c b/demos/gtk-demo/gtkfishbowl.c index ee0b5f9365..a15f1e9470 100644 --- a/demos/gtk-demo/gtkfishbowl.c +++ b/demos/gtk-demo/gtkfishbowl.c @@ -28,9 +28,14 @@ struct _GtkFishbowlPrivate guint count; gint64 last_frame_time; + gint64 update_delay; guint tick_id; - guint use_icons: 1; + double framerate; + int last_benchmark_change; + + guint use_icons : 1; + guint benchmark : 1; }; struct _GtkFishbowlChild @@ -45,7 +50,10 @@ struct _GtkFishbowlChild enum { PROP_0, PROP_ANIMATING, + PROP_BENCHMARK, PROP_COUNT, + PROP_FRAMERATE, + PROP_UPDATE_DELAY, NUM_PROPERTIES }; @@ -56,7 +64,11 @@ G_DEFINE_TYPE_WITH_PRIVATE (GtkFishbowl, gtk_fishbowl, GTK_TYPE_CONTAINER) static void gtk_fishbowl_init (GtkFishbowl *fishbowl) { + GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl); + gtk_widget_set_has_surface (GTK_WIDGET (fishbowl), FALSE); + + priv->update_delay = G_USEC_PER_SEC; } /** @@ -264,10 +276,18 @@ gtk_fishbowl_set_property (GObject *object, gtk_fishbowl_set_animating (fishbowl, g_value_get_boolean (value)); break; + case PROP_BENCHMARK: + gtk_fishbowl_set_benchmark (fishbowl, g_value_get_boolean (value)); + break; + case PROP_COUNT: gtk_fishbowl_set_count (fishbowl, g_value_get_uint (value)); break; + case PROP_UPDATE_DELAY: + gtk_fishbowl_set_update_delay (fishbowl, g_value_get_int64 (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -288,10 +308,22 @@ gtk_fishbowl_get_property (GObject *object, g_value_set_boolean (value, gtk_fishbowl_get_animating (fishbowl)); break; + case PROP_BENCHMARK: + g_value_set_boolean (value, gtk_fishbowl_get_benchmark (fishbowl)); + break; + case PROP_COUNT: g_value_set_uint (value, gtk_fishbowl_get_count (fishbowl)); break; + case PROP_FRAMERATE: + g_value_set_double (value, gtk_fishbowl_get_framerate (fishbowl)); + break; + + case PROP_UPDATE_DELAY: + g_value_set_int64 (value, gtk_fishbowl_get_update_delay (fishbowl)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -323,13 +355,36 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass) FALSE, G_PARAM_READWRITE); + props[PROP_BENCHMARK] = + g_param_spec_boolean ("benchmark", + "Benchmark", + "Adapt the count property to hit the maximum framerate", + FALSE, + G_PARAM_READWRITE); + props[PROP_COUNT] = g_param_spec_uint ("count", "Count", "Number of widgets", 0, G_MAXUINT, 0, - G_PARAM_READABLE); + G_PARAM_READWRITE); + + props[PROP_FRAMERATE] = + g_param_spec_double ("framerate", + "Framerate", + "Framerate of this widget in frames per second", + 0, G_MAXDOUBLE, + 0, + G_PARAM_READABLE); + + props[PROP_UPDATE_DELAY] = + g_param_spec_int64 ("update-delay", + "Update delay", + "Number of usecs between updates", + 0, G_MAXINT64, + G_USEC_PER_SEC, + G_PARAM_READWRITE); g_object_class_install_properties (object_class, NUM_PROPERTIES, props); } @@ -432,6 +487,30 @@ gtk_fishbowl_set_count (GtkFishbowl *fishbowl, g_object_thaw_notify (G_OBJECT (fishbowl)); } +gboolean +gtk_fishbowl_get_benchmark (GtkFishbowl *fishbowl) +{ + GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl); + + return priv->benchmark; +} + +void +gtk_fishbowl_set_benchmark (GtkFishbowl *fishbowl, + gboolean benchmark) +{ + GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl); + + if (priv->benchmark == benchmark) + return; + + priv->benchmark = benchmark; + if (!benchmark) + priv->last_benchmark_change = 0; + + g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_BENCHMARK]); +} + gboolean gtk_fishbowl_get_animating (GtkFishbowl *fishbowl) { @@ -440,6 +519,111 @@ gtk_fishbowl_get_animating (GtkFishbowl *fishbowl) return priv->tick_id != 0; } +static gint64 +guess_refresh_interval (GdkFrameClock *frame_clock) +{ + gint64 interval; + gint64 i; + + interval = G_MAXINT64; + + for (i = gdk_frame_clock_get_history_start (frame_clock); + i < gdk_frame_clock_get_frame_counter (frame_clock); + i++) + { + GdkFrameTimings *t, *before; + gint64 ts, before_ts; + + t = gdk_frame_clock_get_timings (frame_clock, i); + before = gdk_frame_clock_get_timings (frame_clock, i - 1); + if (t == NULL || before == NULL) + continue; + + ts = gdk_frame_timings_get_frame_time (t); + before_ts = gdk_frame_timings_get_frame_time (before); + if (ts == 0 || before_ts == 0) + continue; + + interval = MIN (interval, ts - before_ts); + } + + if (interval == G_MAXINT64) + return 0; + + return interval; +} + +static void +gtk_fishbowl_do_update (GtkFishbowl *fishbowl) +{ + GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl); + GdkFrameClock *frame_clock; + GdkFrameTimings *start, *end; + gint64 start_counter, end_counter; + gint64 n_frames, expected_frames; + gint64 start_timestamp, end_timestamp; + gint64 interval; + + frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (fishbowl)); + if (frame_clock == NULL) + return; + + start_counter = gdk_frame_clock_get_history_start (frame_clock); + end_counter = gdk_frame_clock_get_frame_counter (frame_clock); + start = gdk_frame_clock_get_timings (frame_clock, start_counter); + for (end = gdk_frame_clock_get_timings (frame_clock, end_counter); + end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end); + end = gdk_frame_clock_get_timings (frame_clock, end_counter)) + end_counter--; + if (end_counter - start_counter < 4) + return; + + start_timestamp = gdk_frame_timings_get_presentation_time (start); + end_timestamp = gdk_frame_timings_get_presentation_time (end); + if (start_timestamp == 0 || end_timestamp == 0) + { + start_timestamp = gdk_frame_timings_get_frame_time (start); + end_timestamp = gdk_frame_timings_get_frame_time (end); + } + + n_frames = end_counter - start_counter; + priv->framerate = ((double) n_frames) * G_USEC_PER_SEC / (end_timestamp - start_timestamp); + g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE]); + + if (!priv->benchmark) + return; + + interval = gdk_frame_timings_get_refresh_interval (end); + if (interval == 0) + { + interval = guess_refresh_interval (frame_clock); + if (interval == 0) + return; + } + expected_frames = round ((double) (end_timestamp - start_timestamp) / interval); + + if (n_frames >= expected_frames) + { + if (priv->last_benchmark_change > 0) + priv->last_benchmark_change *= 2; + else + priv->last_benchmark_change = 1; + } + else if (n_frames + 1 < expected_frames) + { + if (priv->last_benchmark_change < 0) + priv->last_benchmark_change--; + else + priv->last_benchmark_change = -1; + } + else + { + priv->last_benchmark_change = 0; + } + + gtk_fishbowl_set_count (fishbowl, MAX (1, priv->count + priv->last_benchmark_change)); +} + static gboolean gtk_fishbowl_tick (GtkWidget *widget, GdkFrameClock *frame_clock, @@ -450,9 +634,11 @@ gtk_fishbowl_tick (GtkWidget *widget, GtkFishbowlChild *child; GList *l; gint64 frame_time, elapsed; + gboolean do_update; frame_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget)); elapsed = frame_time - priv->last_frame_time; + do_update = frame_time / priv->update_delay != priv->last_frame_time / priv->update_delay; priv->last_frame_time = frame_time; /* last frame was 0, so we're just starting to animate */ @@ -491,6 +677,9 @@ gtk_fishbowl_tick (GtkWidget *widget, gtk_widget_queue_allocate (widget); + if (do_update) + gtk_fishbowl_do_update (fishbowl); + return G_SOURCE_CONTINUE; } @@ -515,8 +704,40 @@ gtk_fishbowl_set_animating (GtkFishbowl *fishbowl, priv->last_frame_time = 0; gtk_widget_remove_tick_callback (GTK_WIDGET (fishbowl), priv->tick_id); priv->tick_id = 0; + priv->framerate = 0; + g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE]); } g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_ANIMATING]); } +double +gtk_fishbowl_get_framerate (GtkFishbowl *fishbowl) +{ + GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl); + + return priv->framerate; +} + +gint64 +gtk_fishbowl_get_update_delay (GtkFishbowl *fishbowl) +{ + GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl); + + return priv->update_delay; +} + +void +gtk_fishbowl_set_update_delay (GtkFishbowl *fishbowl, + gint64 update_delay) +{ + GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl); + + if (priv->update_delay == update_delay) + return; + + priv->update_delay = update_delay; + + g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_UPDATE_DELAY]); +} + diff --git a/demos/gtk-demo/gtkfishbowl.h b/demos/gtk-demo/gtkfishbowl.h index b1559d0b26..83f2c249d7 100644 --- a/demos/gtk-demo/gtkfishbowl.h +++ b/demos/gtk-demo/gtkfishbowl.h @@ -55,6 +55,13 @@ void gtk_fishbowl_set_count (GtkFishbowl *fishbowl, gboolean gtk_fishbowl_get_animating (GtkFishbowl *fishbowl); void gtk_fishbowl_set_animating (GtkFishbowl *fishbowl, gboolean animating); +gboolean gtk_fishbowl_get_benchmark (GtkFishbowl *fishbowl); +void gtk_fishbowl_set_benchmark (GtkFishbowl *fishbowl, + gboolean animating); +double gtk_fishbowl_get_framerate (GtkFishbowl *fishbowl); +gint64 gtk_fishbowl_get_update_delay (GtkFishbowl *fishbowl); +void gtk_fishbowl_set_update_delay (GtkFishbowl *fishbowl, + gint64 update_delay); G_END_DECLS