]> Pileus Git - ~andy/gtk/blobdiff - tests/animated-resizing.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / tests / animated-resizing.c
index a6198cc9fed44eeef9b30519b2d254c3e6f4a928..8a34d9fc38201aaa45661b2b99fff4517d8c7bf9 100644 (file)
@@ -2,6 +2,9 @@
 
 #include <gtk/gtk.h>
 #include <math.h>
+#include <string.h>
+
+#include "variable.h"
 
 #define RADIUS 64
 #define DIAMETER (2*RADIUS)
 static GtkWidget *window;
 static int window_width = WIDTH, window_height = HEIGHT;
 
+gint64 start_frame_time;
 static double angle;
-static int frames_since_last_print = 0;
 
+static int max_stats = -1;
+static double statistics_time = 5.;
 static double load_factor = 1.0;
 static double cb_no_resize = FALSE;
+static gboolean machine_readable = FALSE;
 
 static cairo_surface_t *source_surface;
 
@@ -108,26 +114,114 @@ on_window_draw (GtkWidget *widget,
 }
 
 static void
-on_frame (GtkTimeline *timeline,
-          double       progress)
+print_double (const char *description,
+              double      value)
 {
-  int jitter;
-  double current_time;
+  if (machine_readable)
+    g_print ("%g\t", value);
+  else
+    g_print ("%s: %g\n", description, value);
+}
+
+static void
+print_variable (const char *description,
+                Variable *variable)
+{
+  if (variable->weight != 0)
+    {
+      if (machine_readable)
+        g_print ("%g\t%g\t",
+                 variable_mean (variable),
+                 variable_standard_deviation (variable));
+      else
+        g_print ("%s: %g +/- %g\n", description,
+                 variable_mean (variable),
+                 variable_standard_deviation (variable));
+    }
+  else
+    {
+      if (machine_readable)
+        g_print ("-\t-\t");
+      else
+        g_print ("%s: <n/a>\n", description);
+    }
+}
+
+static void
+handle_frame_stats (GdkFrameClock *frame_clock)
+{
+  static int num_stats = 0;
   static double last_print_time = 0;
+  static int frames_since_last_print = 0;
+  static gint64 frame_counter;
+  static gint64 last_handled_frame = -1;
+
+  static Variable latency = VARIABLE_INIT;
 
-  current_time = g_get_monotonic_time () / 1000000.;
-  if (current_time >= last_print_time + 5)
+  double current_time;
+
+  current_time = g_get_monotonic_time ();
+  if (current_time >= last_print_time + 1000000 * statistics_time)
     {
-      if (frames_since_last_print != 0)
+      if (frames_since_last_print)
         {
-          g_print ("%g\n", frames_since_last_print / (current_time - last_print_time));
-          frames_since_last_print = 0;
+          if (num_stats == 0 && machine_readable)
+            {
+              g_print ("# load_factor frame_rate latency\n");
+            }
+
+          num_stats++;
+          if (machine_readable)
+            g_print ("%g       ", load_factor);
+          print_double ("Frame rate ",
+                        frames_since_last_print / ((current_time - last_print_time) / 1000000.));
+
+          print_variable ("Latency", &latency);
+
+          g_print ("\n");
         }
 
       last_print_time = current_time;
+      frames_since_last_print = 0;
+      variable_reset (&latency);
+
+      if (num_stats == max_stats)
+        gtk_main_quit ();
     }
+
   frames_since_last_print++;
 
+  for (frame_counter = last_handled_frame;
+       frame_counter < gdk_frame_clock_get_frame_counter (frame_clock);
+       frame_counter++)
+    {
+      GdkFrameTimings *timings = gdk_frame_clock_get_timings (frame_clock, frame_counter);
+      GdkFrameTimings *previous_timings = gdk_frame_clock_get_timings (frame_clock, frame_counter - 1);
+
+      if (!timings || gdk_frame_timings_get_complete (timings))
+        last_handled_frame = frame_counter;
+
+      if (timings && gdk_frame_timings_get_complete (timings) && previous_timings &&
+          gdk_frame_timings_get_presentation_time (timings) != 0 &&
+          gdk_frame_timings_get_presentation_time (previous_timings) != 0)
+        {
+          double display_time = (gdk_frame_timings_get_presentation_time (timings) - gdk_frame_timings_get_presentation_time (previous_timings)) / 1000.;
+          double frame_latency = (gdk_frame_timings_get_presentation_time (previous_timings) - gdk_frame_timings_get_frame_time (previous_timings)) / 1000. + display_time / 2;
+
+          variable_add_weighted (&latency, frame_latency, display_time);
+        }
+    }
+}
+
+static void
+on_frame (double progress)
+{
+  GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (window);
+  int jitter;
+
+  if (frame_clock)
+    handle_frame_stats (frame_clock);
+
   angle = 2 * M_PI * progress;
   jitter = WINDOW_SIZE_JITTER * sin(angle);
 
@@ -143,9 +237,38 @@ on_frame (GtkTimeline *timeline,
   gtk_widget_queue_draw (window);
 }
 
+static gboolean
+tick_callback (GtkWidget     *widget,
+               GdkFrameClock *frame_clock,
+               gpointer       user_data)
+{
+  gint64 frame_time = gdk_frame_clock_get_frame_time (frame_clock);
+  double scaled_time;
+
+  if (start_frame_time == 0)
+    start_frame_time = frame_time;
+
+  scaled_time = (frame_time - start_frame_time) / (CYCLE_TIME * 1000000);
+  on_frame (scaled_time - floor (scaled_time));
+
+  return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+on_map_event (GtkWidget          *widget,
+              GdkEventAny *event)
+{
+  gtk_widget_add_tick_callback (window, tick_callback, NULL, NULL);
+
+  return FALSE;
+}
+
 static GOptionEntry options[] = {
   { "factor", 'f', 0, G_OPTION_ARG_DOUBLE, &load_factor, "Load factor", "FACTOR" },
+  { "max-statistics", 'm', 0, G_OPTION_ARG_INT, &max_stats, "Maximum statistics printed", NULL },
+  { "machine-readable", 0, 0, G_OPTION_ARG_NONE, &machine_readable, "Print statistics in columns", NULL },
   { "no-resize", 'n', 0, G_OPTION_ARG_NONE, &cb_no_resize, "No Resize", NULL },
+  { "statistics-time", 's', 0, G_OPTION_ARG_DOUBLE, &statistics_time, "Statistics accumulation time", "TIME" },
   { NULL }
 };
 
@@ -155,15 +278,21 @@ main(int argc, char **argv)
   GError *error = NULL;
   GdkScreen *screen;
   GdkRectangle monitor_bounds;
-  GtkTimeline *timeline;
 
   if (!gtk_init_with_args (&argc, &argv, "",
-                           options, NULL, NULL))
+                           options, NULL, &error))
     {
-      g_printerr ("Option parsing failed: %s", error->message);
+      g_printerr ("Option parsing failed: %s\n", error->message);
       return 1;
     }
 
+  g_print ("%sLoad factor: %g\n",
+           machine_readable ? "# " : "",
+           load_factor);
+  g_print ("%sResizing?: %s\n",
+           machine_readable ? "# " : "",
+           cb_no_resize ? "no" : "yes");
+
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
   gtk_window_set_gravity (GTK_WINDOW (window), GDK_GRAVITY_CENTER);
@@ -174,14 +303,9 @@ main(int argc, char **argv)
   g_signal_connect (window, "destroy",
                     G_CALLBACK (gtk_main_quit), NULL);
 
-  timeline = gtk_timeline_new (window, CYCLE_TIME * 1000);
-  gtk_timeline_set_loop (timeline, TRUE);
-  gtk_timeline_set_progress_type (timeline, GTK_TIMELINE_PROGRESS_LINEAR);
-
-  g_signal_connect (timeline, "frame",
-                    G_CALLBACK (on_frame), NULL);
-  on_frame (timeline, 0.);
-  gtk_timeline_start (timeline);
+  g_signal_connect (window, "map-event",
+                    G_CALLBACK (on_map_event), NULL);
+  on_frame (0.);
 
   screen = gtk_widget_get_screen (window);
   gdk_screen_get_monitor_geometry (screen,