[mutter/gbsneto/charts: 2/3] Add frame time chart



commit d28b3d8d941e16e1b0e5b638883de5356e0fc0b1
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Fri Mar 22 01:29:36 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 covers both layout time (green) and paint time (blue).
    
    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   |   4 +
 clutter/clutter/clutter-stage.c           |   9 ++
 clutter/clutter/cogl/clutter-stage-cogl.c | 156 ++++++++++++++++++++++++++++++
 clutter/clutter/cogl/clutter-stage-cogl.h |   3 +
 6 files changed, 174 insertions(+)
---
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 cb887ea32..abe83c321 100644
--- a/clutter/clutter/clutter-stage-private.h
+++ b/clutter/clutter/clutter-stage-private.h
@@ -136,6 +136,10 @@ GList *         _clutter_stage_peek_stage_views         (ClutterStage *stage);
 
 int             clutter_stage_get_sync_delay            (ClutterStage *stage);
 
+void            clutter_stage_get_frame_times           (ClutterStage *stage,
+                                                         double       *paint_time,
+                                                         double       *layout_time);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_PRIVATE_H__ */
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index 1cb5cb9b6..2eda55595 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -5099,3 +5099,12 @@ _clutter_stage_get_max_view_scale_factor_for_rect (ClutterStage *stage,
   *view_scale = scale;
   return TRUE;
 }
+
+void
+clutter_stage_get_frame_times (ClutterStage *stage,
+                               double       *paint_time,
+                               double       *layout_time)
+{
+  *paint_time = stage->priv->last_paint_time;
+  *layout_time = stage->priv->last_layout_time;
+}
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
index e0c39185b..0f7398c1f 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
@@ -405,6 +405,157 @@ paint_damage_region (ClutterStageWindow    *stage_window,
   cogl_framebuffer_pop_matrix (framebuffer);
 }
 
+#define CHART_COLUMN_WIDTH 6 //px
+#define THRESHOLD_LINE_HEIGHT 2 //px
+#define MAX_FRAME_TIME_INFO_ENTRIES 1000
+
+typedef struct
+{
+  double layout_time;
+  double paint_time;
+} FrameTimeInfo;
+
+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);
+  ClutterActor *actor = CLUTTER_ACTOR (stage_cogl->wrapper);
+  cairo_rectangle_int_t layout;
+  static CoglPipeline *threshold_pipeline = NULL;
+  static CoglPipeline *paint_time_pipeline = NULL;
+  static CoglPipeline *layout_time_pipeline = NULL;
+  CoglMatrix modelview;
+  double refresh_rate_bar_height;
+  double ms_per_frame;
+  float green_line_y;
+  int sync_delay;
+  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 (layout_time_pipeline == NULL))
+    {
+      layout_time_pipeline = cogl_pipeline_new (ctx);
+      cogl_pipeline_set_color4ub (layout_time_pipeline, 0x00, 0x60, 0x00, 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);
+
+  clutter_stage_view_get_layout (view, &layout);
+  g_message ("  Onscreen: %p", framebuffer);
+  g_message ("  View layout: %dx%d", layout.width, layout.height);
+
+  n_points = layout.width / CHART_COLUMN_WIDTH;
+  g_message ("  n_points: %d", n_points);
+
+  /* Chart */
+  sync_delay = clutter_stage_get_sync_delay (stage_cogl->wrapper);
+  ms_per_frame = 1000.0 / stage_cogl->refresh_rate - sync_delay;
+  refresh_rate_bar_height = layout.height * 0.1;
+
+  for (i = 0; i < MIN (stage_cogl->frame_times->len, n_points); i++)
+    {
+      int element = stage_cogl->frame_times->len - i - 1;
+      FrameTimeInfo *info = &g_array_index (stage_cogl->frame_times, FrameTimeInfo, element);
+      double x_1 = layout.width - (i + 1) * CHART_COLUMN_WIDTH;
+      double x_2 = layout.width - i * CHART_COLUMN_WIDTH;
+      double layout_bar_height;
+      double paint_bar_height;
+
+      /* Layout time section */
+      layout_bar_height =
+        info->layout_time / ms_per_frame * refresh_rate_bar_height;
+      cogl_framebuffer_draw_rectangle (framebuffer,
+                                       layout_time_pipeline,
+                                       x_1,
+                                       layout.height - layout_bar_height,
+                                       x_2,
+                                       layout.height);
+
+      /* Paint time section */
+      paint_bar_height =
+        info->paint_time / ms_per_frame * refresh_rate_bar_height;
+      cogl_framebuffer_draw_rectangle (framebuffer,
+                                       paint_time_pipeline,
+                                       x_1,
+                                       layout.height - paint_bar_height - layout_bar_height,
+                                       x_2,
+                                       layout.height - layout_bar_height);
+    }
+
+  /* Green line (16.667ms) */
+  green_line_y = layout.height * 0.9;
+  cogl_framebuffer_draw_rectangle (framebuffer,
+                                   threshold_pipeline,
+                                   0.0f,
+                                   green_line_y,
+                                   layout.width,
+                                   green_line_y + THRESHOLD_LINE_HEIGHT);
+
+  cogl_framebuffer_pop_matrix (framebuffer);
+}
+
+static inline void
+append_frame_time_info (ClutterStageCogl *stage_cogl)
+{
+  FrameTimeInfo previous_frame_info;
+
+  if (G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_FRAME_TIME)))
+    return;
+
+  if (G_UNLIKELY (stage_cogl->frame_times == NULL))
+    stage_cogl->frame_times = g_array_sized_new (FALSE, TRUE,
+                                                 sizeof (FrameTimeInfo),
+                                                 MAX_FRAME_TIME_INFO_ENTRIES);
+
+  clutter_stage_get_frame_times (stage_cogl->wrapper,
+                                 &previous_frame_info.paint_time,
+                                 &previous_frame_info.layout_time);
+
+  g_array_append_val (stage_cogl->frame_times, previous_frame_info);
+
+  if (stage_cogl->frame_times->len > MAX_FRAME_TIME_INFO_ENTRIES)
+    g_array_remove_range (stage_cogl->frame_times, 0,
+                          stage_cogl->frame_times->len - MAX_FRAME_TIME_INFO_ENTRIES);
+
+}
+
+static inline void
+maybe_paint_frame_times (ClutterStageWindow *stage_window,
+                         ClutterStageView   *view)
+{
+  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
+
+  if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_FRAME_TIME)))
+    {
+      paint_frame_time_chart (stage_window, view);
+      stage_cogl->painting_frame_chart = TRUE;
+    }
+  else if (stage_cogl->painting_frame_chart)
+    {
+      g_array_free (stage_cogl->frame_times, TRUE);
+      stage_cogl->frame_times = NULL;
+      stage_cogl->painting_frame_chart = FALSE;
+    }
+}
+
 static gboolean
 swap_framebuffer (ClutterStageWindow    *stage_window,
                   ClutterStageView      *view,
@@ -427,6 +578,8 @@ 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);
 
+  maybe_paint_frame_times (stage_window, view);
+
   if (cogl_is_onscreen (framebuffer))
     {
       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
@@ -572,6 +725,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);
 }
 
@@ -931,6 +1085,8 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
   gboolean swap_event = FALSE;
   GList *l;
 
+  append_frame_time_info (stage_cogl);
+
   for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
     {
       ClutterStageView *view = l->data;
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.h b/clutter/clutter/cogl/clutter-stage-cogl.h
index 17958cd24..6c56abb85 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.h
+++ b/clutter/clutter/cogl/clutter-stage-cogl.h
@@ -66,6 +66,9 @@ struct _ClutterStageCogl
   /* TRUE if the current paint cycle has a clipped redraw. In that
      case bounding_redraw_clip specifies the the bounds. */
   guint using_clipped_redraw : 1;
+
+  gboolean painting_frame_chart;
+  GArray *frame_times;
 };
 
 struct _ClutterStageCoglClass


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