mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 09:30:45 -05:00
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
This commit is contained in:
parent
6350efc28e
commit
a9b642540c
@ -143,6 +143,7 @@ static const GDebugKey clutter_paint_debug_keys[] = {
|
|||||||
{ "continuous-redraw", CLUTTER_DEBUG_CONTINUOUS_REDRAW },
|
{ "continuous-redraw", CLUTTER_DEBUG_CONTINUOUS_REDRAW },
|
||||||
{ "paint-deform-tiles", CLUTTER_DEBUG_PAINT_DEFORM_TILES },
|
{ "paint-deform-tiles", CLUTTER_DEBUG_PAINT_DEFORM_TILES },
|
||||||
{ "damage-region", CLUTTER_DEBUG_PAINT_DAMAGE_REGION },
|
{ "damage-region", CLUTTER_DEBUG_PAINT_DAMAGE_REGION },
|
||||||
|
{ "frame-time", CLUTTER_DEBUG_PAINT_FRAME_TIME },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -74,6 +74,7 @@ typedef enum
|
|||||||
CLUTTER_DEBUG_CONTINUOUS_REDRAW = 1 << 6,
|
CLUTTER_DEBUG_CONTINUOUS_REDRAW = 1 << 6,
|
||||||
CLUTTER_DEBUG_PAINT_DEFORM_TILES = 1 << 7,
|
CLUTTER_DEBUG_PAINT_DEFORM_TILES = 1 << 7,
|
||||||
CLUTTER_DEBUG_PAINT_DAMAGE_REGION = 1 << 8,
|
CLUTTER_DEBUG_PAINT_DAMAGE_REGION = 1 << 8,
|
||||||
|
CLUTTER_DEBUG_PAINT_FRAME_TIME = 1 << 9,
|
||||||
} ClutterDrawDebugFlag;
|
} ClutterDrawDebugFlag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,6 +136,10 @@ GList * _clutter_stage_peek_stage_views (ClutterStage *stage);
|
|||||||
|
|
||||||
int clutter_stage_get_sync_delay (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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */
|
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */
|
||||||
|
@ -5099,3 +5099,12 @@ _clutter_stage_get_max_view_scale_factor_for_rect (ClutterStage *stage,
|
|||||||
*view_scale = scale;
|
*view_scale = scale;
|
||||||
return TRUE;
|
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;
|
||||||
|
}
|
||||||
|
@ -405,6 +405,215 @@ paint_damage_region (ClutterStageWindow *stage_window,
|
|||||||
cogl_framebuffer_pop_matrix (framebuffer);
|
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
|
||||||
|
get_frame_time_chart_region (ClutterStageWindow *stage_window,
|
||||||
|
ClutterStageView *view,
|
||||||
|
cairo_rectangle_int_t *region)
|
||||||
|
{
|
||||||
|
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
|
||||||
|
cairo_rectangle_int_t painted_region;
|
||||||
|
cairo_rectangle_int_t layout;
|
||||||
|
double refresh_rate_bar_height;
|
||||||
|
double ms_per_frame;
|
||||||
|
float green_line_y;
|
||||||
|
int sync_delay;
|
||||||
|
int n_points;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
clutter_stage_view_get_layout (view, &layout);
|
||||||
|
|
||||||
|
painted_region = (cairo_rectangle_int_t) {
|
||||||
|
.x = layout.x,
|
||||||
|
.y = layout.y + layout.height,
|
||||||
|
.width = layout.width,
|
||||||
|
.height = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
n_points = layout.width / CHART_COLUMN_WIDTH;
|
||||||
|
|
||||||
|
/* 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 layout_bar_height;
|
||||||
|
double paint_bar_height;
|
||||||
|
|
||||||
|
/* Layout time section */
|
||||||
|
layout_bar_height =
|
||||||
|
info->layout_time / ms_per_frame * refresh_rate_bar_height;
|
||||||
|
|
||||||
|
/* Paint time section */
|
||||||
|
paint_bar_height =
|
||||||
|
info->paint_time / ms_per_frame * refresh_rate_bar_height;
|
||||||
|
|
||||||
|
painted_region.height = MAX (painted_region.height,
|
||||||
|
paint_bar_height + layout_bar_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Green line (16.667ms) */
|
||||||
|
green_line_y = layout.height * 0.9;
|
||||||
|
|
||||||
|
painted_region.height = MAX (painted_region.height, green_line_y);
|
||||||
|
|
||||||
|
/* Update the swap region rectangle */
|
||||||
|
painted_region.y -= MIN (layout.height, painted_region.height);
|
||||||
|
|
||||||
|
_clutter_util_rectangle_union (region, &painted_region, region);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
n_points = layout.width / CHART_COLUMN_WIDTH;
|
||||||
|
|
||||||
|
/* 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
|
static gboolean
|
||||||
swap_framebuffer (ClutterStageWindow *stage_window,
|
swap_framebuffer (ClutterStageWindow *stage_window,
|
||||||
ClutterStageView *view,
|
ClutterStageView *view,
|
||||||
@ -672,6 +881,9 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
|||||||
fb_clip_region = (cairo_rectangle_int_t) { 0 };
|
fb_clip_region = (cairo_rectangle_int_t) { 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_FRAME_TIME)))
|
||||||
|
get_frame_time_chart_region (stage_window, view, &fb_clip_region);
|
||||||
|
|
||||||
if (may_use_clipped_redraw &&
|
if (may_use_clipped_redraw &&
|
||||||
G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
|
G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
|
||||||
use_clipped_redraw = TRUE;
|
use_clipped_redraw = TRUE;
|
||||||
@ -827,6 +1039,9 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
|
|||||||
else
|
else
|
||||||
paint_stage (stage_cogl, view, &view_rect);
|
paint_stage (stage_cogl, view, &view_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maybe_paint_frame_times (stage_window, view);
|
||||||
|
|
||||||
cogl_pop_framebuffer ();
|
cogl_pop_framebuffer ();
|
||||||
|
|
||||||
if (may_use_clipped_redraw &&
|
if (may_use_clipped_redraw &&
|
||||||
@ -931,6 +1146,8 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
|||||||
gboolean swap_event = FALSE;
|
gboolean swap_event = FALSE;
|
||||||
GList *l;
|
GList *l;
|
||||||
|
|
||||||
|
append_frame_time_info (stage_cogl);
|
||||||
|
|
||||||
for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
|
for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
|
||||||
{
|
{
|
||||||
ClutterStageView *view = l->data;
|
ClutterStageView *view = l->data;
|
||||||
|
@ -66,6 +66,9 @@ struct _ClutterStageCogl
|
|||||||
/* TRUE if the current paint cycle has a clipped redraw. In that
|
/* TRUE if the current paint cycle has a clipped redraw. In that
|
||||||
case bounding_redraw_clip specifies the the bounds. */
|
case bounding_redraw_clip specifies the the bounds. */
|
||||||
guint using_clipped_redraw : 1;
|
guint using_clipped_redraw : 1;
|
||||||
|
|
||||||
|
gboolean painting_frame_chart;
|
||||||
|
GArray *frame_times;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _ClutterStageCoglClass
|
struct _ClutterStageCoglClass
|
||||||
|
Loading…
Reference in New Issue
Block a user