Merge branch 'wip/otte/correct-fps' into 'main'

Fix fps display

See merge request GNOME/gtk!7003
This commit is contained in:
Matthias Clasen 2024-03-10 17:31:46 +00:00
commit 1dbc1d67f5
4 changed files with 83 additions and 41 deletions

View File

@ -79,14 +79,23 @@ static guint signals[LAST_SIGNAL];
static guint fps_counter;
#define FRAME_HISTORY_MAX_LENGTH 128
/* 60Hz plus some extra for monotonic time inaccuracy */
#define FRAME_HISTORY_DEFAULT_LENGTH 64
#define frame_timings_unref(x) gdk_frame_timings_unref((GdkFrameTimings *) (x))
#define GDK_ARRAY_NAME timings
#define GDK_ARRAY_TYPE_NAME Timings
#define GDK_ARRAY_ELEMENT_TYPE GdkFrameTimings *
#define GDK_ARRAY_PREALLOC FRAME_HISTORY_DEFAULT_LENGTH
#define GDK_ARRAY_FREE_FUNC frame_timings_unref
#include "gdk/gdkarrayimpl.c"
struct _GdkFrameClockPrivate
{
gint64 frame_counter;
int n_timings;
int current;
GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
Timings timings;
int n_freeze_inhibitors;
};
@ -99,11 +108,8 @@ static void
gdk_frame_clock_finalize (GObject *object)
{
GdkFrameClockPrivate *priv = GDK_FRAME_CLOCK (object)->priv;
int i;
for (i = 0; i < FRAME_HISTORY_MAX_LENGTH; i++)
if (priv->timings[i] != 0)
gdk_frame_timings_unref (priv->timings[i]);
timings_clear (&priv->timings);
G_OBJECT_CLASS (gdk_frame_clock_parent_class)->finalize (object);
}
@ -257,7 +263,8 @@ gdk_frame_clock_init (GdkFrameClock *clock)
clock->priv = priv = gdk_frame_clock_get_instance_private (clock);
priv->frame_counter = -1;
priv->current = FRAME_HISTORY_MAX_LENGTH - 1;
priv->current = 0;
timings_init (&priv->timings);
if (fps_counter == 0)
fps_counter = gdk_profiler_define_counter ("fps", "Frames per Second");
@ -416,7 +423,7 @@ gdk_frame_clock_get_frame_counter (GdkFrameClock *frame_clock)
static inline gint64
_gdk_frame_clock_get_history_start (GdkFrameClock *frame_clock)
{
return frame_clock->priv->frame_counter + 1 - frame_clock->priv->n_timings;
return frame_clock->priv->frame_counter + 1 - timings_get_size (&frame_clock->priv->timings);
}
/**
@ -445,31 +452,44 @@ gdk_frame_clock_get_history_start (GdkFrameClock *frame_clock)
}
void
_gdk_frame_clock_begin_frame (GdkFrameClock *frame_clock)
_gdk_frame_clock_begin_frame (GdkFrameClock *frame_clock,
gint64 monotonic_time)
{
GdkFrameClockPrivate *priv;
g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
priv = frame_clock->priv;
priv->frame_counter++;
priv->current = (priv->current + 1) % FRAME_HISTORY_MAX_LENGTH;
/* Try to steal the previous frame timing instead of discarding
* and allocating a new one.
*/
if G_LIKELY (priv->n_timings == FRAME_HISTORY_MAX_LENGTH &&
_gdk_frame_timings_steal (priv->timings[priv->current],
priv->frame_counter))
return;
if (priv->n_timings < FRAME_HISTORY_MAX_LENGTH)
priv->n_timings++;
if (G_UNLIKELY (timings_get_size (&priv->timings) == 0))
timings_append (&priv->timings, _gdk_frame_timings_new (priv->frame_counter));
else
gdk_frame_timings_unref (priv->timings[priv->current]);
{
GdkFrameTimings *timings;
priv->timings[priv->current] = _gdk_frame_timings_new (priv->frame_counter);
priv->current = (priv->current + 1) % timings_get_size (&priv->timings);
timings = timings_get (&priv->timings, priv->current);
if (timings->frame_time + G_USEC_PER_SEC > monotonic_time)
{
/* Keep the timings, not a second old yet */
timings = _gdk_frame_timings_new (priv->frame_counter);
timings_splice (&priv->timings, priv->current, 0, FALSE, &timings, 1);
}
else if (_gdk_frame_timings_steal (timings, priv->frame_counter))
{
/* Stole the previous frame timing instead of discarding
* and allocating a new one, so nothing to do
*/
}
else
{
timings = _gdk_frame_timings_new (priv->frame_counter);
timings_splice (&priv->timings, priv->current, 1, FALSE, &timings, 1);
}
}
}
static inline GdkFrameTimings *
@ -477,17 +497,21 @@ _gdk_frame_clock_get_timings (GdkFrameClock *frame_clock,
gint64 frame_counter)
{
GdkFrameClockPrivate *priv = frame_clock->priv;
int pos;
gsize size, pos;
if (frame_counter > priv->frame_counter)
return NULL;
if (frame_counter <= priv->frame_counter - priv->n_timings)
size = timings_get_size (&priv->timings);
if (G_UNLIKELY (size == 0))
return NULL;
pos = (priv->current - (priv->frame_counter - frame_counter) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
if (priv->frame_counter - frame_counter >= size)
return NULL;
return priv->timings[pos];
pos = (priv->current - (priv->frame_counter - frame_counter) + size) % size;
return timings_get (&priv->timings, pos);
}
/**
@ -779,7 +803,10 @@ gdk_frame_clock_get_fps (GdkFrameClock *frame_clock)
start_counter = _gdk_frame_clock_get_history_start (frame_clock);
end_counter = _gdk_frame_clock_get_frame_counter (frame_clock);
start = _gdk_frame_clock_get_timings (frame_clock, start_counter);
for (start = _gdk_frame_clock_get_timings (frame_clock, start_counter);
end_counter > start_counter && start != NULL && !gdk_frame_timings_get_complete (start);
start = _gdk_frame_clock_get_timings (frame_clock, start_counter))
start_counter++;
for (end = _gdk_frame_clock_get_timings (frame_clock, end_counter);
end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end);
end = _gdk_frame_clock_get_timings (frame_clock, end_counter))

View File

@ -555,7 +555,7 @@ gdk_frame_clock_paint_idle (void *data)
priv->smoothed_frame_time_period = frame_interval;
priv->smoothed_frame_time_reported = priv->smoothed_frame_time_base;
_gdk_frame_clock_begin_frame (clock);
_gdk_frame_clock_begin_frame (clock, priv->frame_time);
/* Note "current" is different now so timings != prev_timings */
timings = gdk_frame_clock_get_current_timings (clock);

View File

@ -106,7 +106,8 @@ struct _GdkFrameTimings
void _gdk_frame_clock_inhibit_freeze (GdkFrameClock *clock);
void _gdk_frame_clock_uninhibit_freeze (GdkFrameClock *clock);
void _gdk_frame_clock_begin_frame (GdkFrameClock *clock);
void _gdk_frame_clock_begin_frame (GdkFrameClock *clock,
gint64 monotonic_time);
void _gdk_frame_clock_debug_print_timings (GdkFrameClock *clock,
GdkFrameTimings *timings);
void _gdk_frame_clock_add_timings_to_profiler (GdkFrameClock *frame_clock,

View File

@ -83,7 +83,7 @@ gtk_fps_info_new (GtkWidget *widget)
info = g_new0 (GtkFpsInfo, 1);
layout = gtk_widget_create_pango_layout (widget, "0000.00 fps");
layout = gtk_widget_create_pango_layout (widget, "000000.00 fps");
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_font_features_new ("tnum=1"));
pango_layout_set_attributes (layout, attrs);
@ -202,23 +202,37 @@ gtk_fps_overlay_snapshot (GtkInspectorOverlay *overlay,
if (overlay_opacity < 1.0)
gtk_snapshot_push_opacity (snapshot, overlay_opacity);
gtk_snapshot_append_color (snapshot,
&(GdkRGBA) { 0, 0, 0, 0.5 },
&GRAPHENE_RECT_INIT (-1, -1, info->width + 2, info->height + 2));
fps = gtk_fps_overlay_get_fps (widget);
if (fps != 0.0)
{
GskRenderNode *fps_node;
char fps_string[40];
gboolean bg_drawn = FALSE;
float bg_x = 0;
g_snprintf (fps_string, sizeof (fps_string), "%7.2f fps", fps);
for (int i = 0; i < 7; i++)
g_snprintf (fps_string, sizeof (fps_string), "%9.2f fps", fps);
for (int i = 0; i < 9; i++)
{
if (g_ascii_isdigit (fps_string[i]))
info->glyphs->glyphs[i].glyph = info->digits->glyphs[fps_string[i] - '0'].glyph;
else if (fps_string[i] == ' ')
info->glyphs->glyphs[i].glyph = info->digits->glyphs[10].glyph;
if (fps_string[i] == ' ')
{
info->glyphs->glyphs[i].glyph = info->digits->glyphs[10].glyph;
bg_x += (float) info->glyphs->glyphs[i].geometry.width / PANGO_SCALE;
}
else
{
if (!bg_drawn)
{
gtk_snapshot_append_color (snapshot,
&(GdkRGBA) { 0, 0, 0, 0.5 },
&GRAPHENE_RECT_INIT (bg_x - 1, -1,
info->width + 2 - bg_x, info->height + 2));
bg_drawn = TRUE;
}
if (g_ascii_isdigit (fps_string[i]))
info->glyphs->glyphs[i].glyph = info->digits->glyphs[fps_string[i] - '0'].glyph;
}
}
fps_node = gsk_text_node_new (info->font,