1 /* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
10 #define DIAMETER (2*RADIUS)
13 #define WINDOW_SIZE_JITTER 200
16 static GtkWidget *window;
17 static int window_width = WIDTH, window_height = HEIGHT;
19 gint64 start_frame_time;
22 static int max_stats = -1;
23 static double statistics_time = 5.;
24 static double load_factor = 1.0;
25 static double cb_no_resize = FALSE;
26 static gboolean machine_readable = FALSE;
28 static cairo_surface_t *source_surface;
31 ensure_resources(cairo_surface_t *target)
36 if (source_surface != NULL)
39 source_surface = cairo_surface_create_similar (target, CAIRO_CONTENT_COLOR_ALPHA,
40 16 * DIAMETER, 16 * DIAMETER);
41 cr = cairo_create(source_surface);
44 cairo_set_source_rgba(cr, 0, 0, 0, 0);
45 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
49 cairo_set_line_width(cr, 1.0);
51 for (j = 0; j < 16; j++)
52 for (i = 0; i < 16; i++)
54 cairo_set_source_rgba(cr,
55 ((i * 41) % 16) / 15.,
56 ((i * 31) % 16) / 15.,
57 ((i * 23) % 16) / 15.,
60 i * DIAMETER + RADIUS, j * DIAMETER + RADIUS,
61 RADIUS - 0.5, 0, 2 * M_PI);
62 cairo_fill_preserve(cr);
63 cairo_set_source_rgba(cr,
64 ((i * 41) % 16) / 15.,
65 ((i * 31) % 16) / 15.,
66 ((i * 23) % 16) / 15.,
73 on_window_draw (GtkWidget *widget,
77 GRand *rand = g_rand_new_with_seed(0);
81 width = gtk_widget_get_allocated_width (widget);
82 height = gtk_widget_get_allocated_height (widget);
84 ensure_resources (cairo_get_target (cr));
86 cairo_set_source_rgb(cr, 1, 1, 1);
89 cairo_set_source_rgb(cr, 0, 0, 0);
90 cairo_set_line_width(cr, 1.0);
91 cairo_rectangle (cr, 0.5, 0.5, width - 1, height - 1);
94 for(i = 0; i < load_factor * 150; i++)
96 int source = g_rand_int_range(rand, 0, 255);
97 double phi = g_rand_double_range(rand, 0, 2 * M_PI) + angle;
98 double r = g_rand_double_range(rand, 0, width / 2 - RADIUS);
101 int source_x = (source % 16) * DIAMETER;
102 int source_y = (source / 16) * DIAMETER;
104 x = round(width / 2 + r * cos(phi) - RADIUS);
105 y = round(height / 2 - r * sin(phi) - RADIUS);
107 cairo_set_source_surface(cr, source_surface,
108 x - source_x, y - source_y);
109 cairo_rectangle(cr, x, y, DIAMETER, DIAMETER);
117 print_double (const char *description,
120 if (machine_readable)
121 g_print ("%g\t", value);
123 g_print ("%s: %g\n", description, value);
127 print_variable (const char *description,
130 if (variable->weight != 0)
132 if (machine_readable)
134 variable_mean (variable),
135 variable_standard_deviation (variable));
137 g_print ("%s: %g +/- %g\n", description,
138 variable_mean (variable),
139 variable_standard_deviation (variable));
143 if (machine_readable)
146 g_print ("%s: <n/a>\n", description);
151 handle_frame_stats (GdkFrameClock *frame_clock)
153 static int num_stats = 0;
154 static double last_print_time = 0;
155 static int frames_since_last_print = 0;
156 static gint64 frame_counter;
157 static gint64 last_handled_frame = -1;
159 static Variable latency = VARIABLE_INIT;
163 current_time = g_get_monotonic_time ();
164 if (current_time >= last_print_time + 1000000 * statistics_time)
166 if (frames_since_last_print)
168 if (num_stats == 0 && machine_readable)
170 g_print ("# load_factor frame_rate latency\n");
174 if (machine_readable)
175 g_print ("%g ", load_factor);
176 print_double ("Frame rate ",
177 frames_since_last_print / ((current_time - last_print_time) / 1000000.));
179 print_variable ("Latency", &latency);
184 last_print_time = current_time;
185 frames_since_last_print = 0;
186 variable_reset (&latency);
188 if (num_stats == max_stats)
192 frames_since_last_print++;
194 for (frame_counter = last_handled_frame;
195 frame_counter < gdk_frame_clock_get_frame_counter (frame_clock);
198 GdkFrameTimings *timings = gdk_frame_clock_get_timings (frame_clock, frame_counter);
199 GdkFrameTimings *previous_timings = gdk_frame_clock_get_timings (frame_clock, frame_counter - 1);
201 if (!timings || gdk_frame_timings_get_complete (timings))
202 last_handled_frame = frame_counter;
204 if (timings && gdk_frame_timings_get_complete (timings) && previous_timings &&
205 gdk_frame_timings_get_presentation_time (timings) != 0 &&
206 gdk_frame_timings_get_presentation_time (previous_timings) != 0)
208 double display_time = (gdk_frame_timings_get_presentation_time (timings) - gdk_frame_timings_get_presentation_time (previous_timings)) / 1000.;
209 double frame_latency = (gdk_frame_timings_get_presentation_time (previous_timings) - gdk_frame_timings_get_frame_time (previous_timings)) / 1000. + display_time / 2;
211 variable_add_weighted (&latency, frame_latency, display_time);
217 on_frame (double progress)
219 GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (window);
223 handle_frame_stats (frame_clock);
225 angle = 2 * M_PI * progress;
226 jitter = WINDOW_SIZE_JITTER * sin(angle);
230 window_width = WIDTH + jitter;
231 window_height = HEIGHT + jitter;
234 gtk_window_resize (GTK_WINDOW (window),
235 window_width, window_height);
237 gtk_widget_queue_draw (window);
241 tick_callback (GtkWidget *widget,
242 GdkFrameClock *frame_clock,
245 gint64 frame_time = gdk_frame_clock_get_frame_time (frame_clock);
248 if (start_frame_time == 0)
249 start_frame_time = frame_time;
251 scaled_time = (frame_time - start_frame_time) / (CYCLE_TIME * 1000000);
252 on_frame (scaled_time - floor (scaled_time));
254 return G_SOURCE_CONTINUE;
258 on_map_event (GtkWidget *widget,
261 gtk_widget_add_tick_callback (window, tick_callback, NULL, NULL);
266 static GOptionEntry options[] = {
267 { "factor", 'f', 0, G_OPTION_ARG_DOUBLE, &load_factor, "Load factor", "FACTOR" },
268 { "max-statistics", 'm', 0, G_OPTION_ARG_INT, &max_stats, "Maximum statistics printed", NULL },
269 { "machine-readable", 0, 0, G_OPTION_ARG_NONE, &machine_readable, "Print statistics in columns", NULL },
270 { "no-resize", 'n', 0, G_OPTION_ARG_NONE, &cb_no_resize, "No Resize", NULL },
271 { "statistics-time", 's', 0, G_OPTION_ARG_DOUBLE, &statistics_time, "Statistics accumulation time", "TIME" },
276 main(int argc, char **argv)
278 GError *error = NULL;
280 GdkRectangle monitor_bounds;
282 if (!gtk_init_with_args (&argc, &argv, "",
283 options, NULL, &error))
285 g_printerr ("Option parsing failed: %s\n", error->message);
289 g_print ("%sLoad factor: %g\n",
290 machine_readable ? "# " : "",
292 g_print ("%sResizing?: %s\n",
293 machine_readable ? "# " : "",
294 cb_no_resize ? "no" : "yes");
296 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
297 gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
298 gtk_window_set_gravity (GTK_WINDOW (window), GDK_GRAVITY_CENTER);
299 gtk_widget_set_app_paintable (window, TRUE);
301 g_signal_connect (window, "draw",
302 G_CALLBACK (on_window_draw), NULL);
303 g_signal_connect (window, "destroy",
304 G_CALLBACK (gtk_main_quit), NULL);
306 g_signal_connect (window, "map-event",
307 G_CALLBACK (on_map_event), NULL);
310 screen = gtk_widget_get_screen (window);
311 gdk_screen_get_monitor_geometry (screen,
312 gdk_screen_get_primary_monitor (screen),
315 gtk_window_move (GTK_WINDOW (window),
316 monitor_bounds.x + (monitor_bounds.width - window_width) / 2,
317 monitor_bounds.y + (monitor_bounds.height - window_height) / 2);
319 gtk_widget_show (window);