[mutter/gbsneto/charts] Add frame time chart



commit 9bb8d27326277e8d6d8f340a4072c8c994f23da3
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Thu Mar 21 17:01:08 2019 +0000

    Add frame time chart
    
    Add a chart at the bottom 10% of the screen where each
    bar represents the time the frame took to be painted. The
    red line represents the maximum time to draw. For example,
    if you are on a 60Hz monitor, the red line means 16.6667
    miliseconds.
    
    This only covers paint time; it makes sense to augment this
    chart with layout time as well.
    
    Enjoy.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/502

 clutter/clutter/clutter-main.c            |  1 +
 clutter/clutter/clutter-main.h            |  1 +
 clutter/clutter/clutter-stage-private.h   |  2 +
 clutter/clutter/clutter-stage.c           | 11 +++-
 clutter/clutter/cogl/clutter-stage-cogl.c | 88 +++++++++++++++++++++++++++++++
 5 files changed, 102 insertions(+), 1 deletion(-)
---
diff --git a/clutter/clutter/clutter-main.c b/clutter/clutter/clutter-main.c
index 7616eaae0..cff072331 100644
--- a/clutter/clutter/clutter-main.c
+++ b/clutter/clutter/clutter-main.c
@@ -143,6 +143,7 @@ static const GDebugKey clutter_paint_debug_keys[] = {
   { "continuous-redraw", CLUTTER_DEBUG_CONTINUOUS_REDRAW },
   { "paint-deform-tiles", CLUTTER_DEBUG_PAINT_DEFORM_TILES },
   { "damage-region", CLUTTER_DEBUG_PAINT_DAMAGE_REGION },
+  { "frame-time", CLUTTER_DEBUG_PAINT_FRAME_TIME },
 };
 
 static void
diff --git a/clutter/clutter/clutter-main.h b/clutter/clutter/clutter-main.h
index e0f10c892..6846cef7a 100644
--- a/clutter/clutter/clutter-main.h
+++ b/clutter/clutter/clutter-main.h
@@ -74,6 +74,7 @@ typedef enum
   CLUTTER_DEBUG_CONTINUOUS_REDRAW       = 1 << 6,
   CLUTTER_DEBUG_PAINT_DEFORM_TILES      = 1 << 7,
   CLUTTER_DEBUG_PAINT_DAMAGE_REGION     = 1 << 8,
+  CLUTTER_DEBUG_PAINT_FRAME_TIME        = 1 << 9,
 } ClutterDrawDebugFlag;
 
 /**
diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h
index 4799c29e1..b5357b26f 100644
--- a/clutter/clutter/clutter-stage-private.h
+++ b/clutter/clutter/clutter-stage-private.h
@@ -134,6 +134,8 @@ void            _clutter_stage_presented                (ClutterStage      *stag
 
 GList *         _clutter_stage_peek_stage_views         (ClutterStage *stage);
 
+double          _clutter_stage_get_previous_frame_time  (ClutterStage *stage);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_PRIVATE_H__ */
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index 3440d19a0..8455917d3 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -146,6 +146,8 @@ struct _ClutterStagePrivate
 
   int update_freeze_count;
 
+  double last_frame_time;
+
   guint relayout_pending       : 1;
   guint redraw_pending         : 1;
   guint is_fullscreen          : 1;
@@ -1123,7 +1125,8 @@ clutter_stage_do_redraw (ClutterStage *stage)
 
   end = g_get_monotonic_time ();
 
-  CLUTTER_NOTE (FRAME_TIME, "%lf", (end - start) / 1000.0);
+  priv->last_frame_time = (end - start) / 1000.0;
+  CLUTTER_NOTE (FRAME_TIME, "%lf", priv->last_frame_time);
 
   CLUTTER_NOTE (PAINT, "Redraw finished for stage '%s'[%p]",
                 _clutter_actor_get_debug_name (actor),
@@ -5078,3 +5081,9 @@ _clutter_stage_get_max_view_scale_factor_for_rect (ClutterStage *stage,
   *view_scale = scale;
   return TRUE;
 }
+
+double
+_clutter_stage_get_previous_frame_time (ClutterStage *stage)
+{
+  return stage->priv->last_frame_time;
+}
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
index e0c39185b..84ef474b6 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
@@ -405,6 +405,90 @@ paint_damage_region (ClutterStageWindow    *stage_window,
   cogl_framebuffer_pop_matrix (framebuffer);
 }
 
+#define CHART_COLUMN_WIDTH 6 //px
+#define THRESHOLD_LINE_HEIGHT 2 //px
+
+static void
+paint_frame_time_chart (ClutterStageWindow *stage_window,
+                        ClutterStageView   *view)
+{
+  CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
+  static CoglPipeline *threshold_pipeline = NULL;
+  static CoglPipeline *paint_time_pipeline = NULL;
+  static GArray *frame_times = NULL;
+  CoglMatrix modelview;
+  double frame_time;
+  float green_line_y;
+  int width, height;
+  int n_points;
+  int i;
+
+  if (G_UNLIKELY (paint_time_pipeline == NULL))
+    {
+      paint_time_pipeline = cogl_pipeline_new (ctx);
+      cogl_pipeline_set_color4ub (paint_time_pipeline, 0x00, 0x00, 0x60, 0xa0);
+    }
+
+  if (G_UNLIKELY (threshold_pipeline == NULL))
+    {
+      threshold_pipeline = cogl_pipeline_new (ctx);
+      cogl_pipeline_set_color4ub (threshold_pipeline, 0x40,  0x00, 0x00, 0x80);
+    }
+
+  cogl_framebuffer_push_matrix (framebuffer);
+  cogl_matrix_init_identity (&modelview);
+  _clutter_actor_apply_modelview_transform (actor, &modelview);
+  cogl_framebuffer_set_modelview_matrix (framebuffer, &modelview);
+
+  width = cogl_framebuffer_get_width (framebuffer);
+  height = cogl_framebuffer_get_height (framebuffer);
+
+  /* Frame time */
+  n_points = width / CHART_COLUMN_WIDTH;
+
+  if (G_UNLIKELY (frame_times == NULL))
+    frame_times = g_array_sized_new (FALSE, TRUE, sizeof (double), n_points);
+
+  frame_time = _clutter_stage_get_previous_frame_time (stage_cogl->wrapper);
+  g_array_append_val (frame_times, frame_time);
+
+  if (frame_times->len > n_points)
+    g_array_remove_range (frame_times, 0, frame_times->len - n_points);
+
+  /* Chart */
+  for (i = 0; i < MIN (frame_times->len, n_points); i++)
+    {
+      int element = frame_times->len - i - 1;
+      double refresh_rate_ms = 1000.0 / stage_cogl->refresh_rate;
+      double refresh_rate_height = height * 0.1;
+      double frame_time_entry = g_array_index (frame_times, double, element);
+      double bar_height =
+        frame_time_entry / refresh_rate_ms * refresh_rate_height;
+      double x_1 = width - (i + 1) * CHART_COLUMN_WIDTH;
+      double x_2 = width - i * CHART_COLUMN_WIDTH;
+
+      cogl_framebuffer_draw_rectangle (framebuffer,
+                                       paint_time_pipeline,
+                                       x_1,
+                                       height - bar_height,
+                                       x_2,
+                                       height);
+    }
+
+  /* Green line (16.667ms) */
+  green_line_y = height * 0.9;
+  cogl_framebuffer_draw_rectangle (framebuffer,
+                                   threshold_pipeline,
+                                   0.0f,
+                                   green_line_y,
+                                   width,
+                                   green_line_y + THRESHOLD_LINE_HEIGHT);
+
+  cogl_framebuffer_pop_matrix (framebuffer);
+}
+
 static gboolean
 swap_framebuffer (ClutterStageWindow    *stage_window,
                   ClutterStageView      *view,
@@ -427,6 +511,9 @@ swap_framebuffer (ClutterStageWindow    *stage_window,
   if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION)))
     paint_damage_region (stage_window, view, swap_region);
 
+  if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_FRAME_TIME)))
+    paint_frame_time_chart (stage_window, view);
+
   if (cogl_is_onscreen (framebuffer))
     {
       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
@@ -572,6 +659,7 @@ is_buffer_age_enabled (void)
   /* Buffer age is disabled when running with CLUTTER_PAINT=damage-region,
    * to ensure the red damage represents the currently damaged area */
   return !(clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION) &&
+         !(clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_FRAME_TIME) &&
          cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]