mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-09 18:30:08 +00:00
frameclock: Make timings history dynamic
Keep at least 1 second of frame timings. This is necessary for 2 reasons - a real one and a fun one. First, with the difference in monitor refresh rates, we can have 48Hz latops as well as 240Hz high refresh rate monitors. That's a factor of 4, and tracking frame rates in both situations reliably is kind of hard - either we track over too many frames and the fps take a lot of time to adjust, or we track too little time and the fps fluctuate wildly. Second, when benchmarking with GDK_DEBUG=no-vsync with a somewhat fast renderer (*cough*Vulkan*cough*) frame rates can go into insane dimensions and only very few frames are actually getting presentation times reported. So to report accurate frame rates in those cases, we need a *very* large history that can be 1000s of times larger than the usual history. And that's just a waste for normal usage.
This commit is contained in:
parent
2861ab38ac
commit
8df6e2cdaf
@ -79,14 +79,23 @@ static guint signals[LAST_SIGNAL];
|
|||||||
|
|
||||||
static guint fps_counter;
|
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
|
struct _GdkFrameClockPrivate
|
||||||
{
|
{
|
||||||
gint64 frame_counter;
|
gint64 frame_counter;
|
||||||
int n_timings;
|
|
||||||
int current;
|
int current;
|
||||||
GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
|
Timings timings;
|
||||||
int n_freeze_inhibitors;
|
int n_freeze_inhibitors;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,11 +108,8 @@ static void
|
|||||||
gdk_frame_clock_finalize (GObject *object)
|
gdk_frame_clock_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
GdkFrameClockPrivate *priv = GDK_FRAME_CLOCK (object)->priv;
|
GdkFrameClockPrivate *priv = GDK_FRAME_CLOCK (object)->priv;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < FRAME_HISTORY_MAX_LENGTH; i++)
|
timings_clear (&priv->timings);
|
||||||
if (priv->timings[i] != 0)
|
|
||||||
gdk_frame_timings_unref (priv->timings[i]);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (gdk_frame_clock_parent_class)->finalize (object);
|
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);
|
clock->priv = priv = gdk_frame_clock_get_instance_private (clock);
|
||||||
|
|
||||||
priv->frame_counter = -1;
|
priv->frame_counter = -1;
|
||||||
priv->current = FRAME_HISTORY_MAX_LENGTH - 1;
|
priv->current = 0;
|
||||||
|
timings_init (&priv->timings);
|
||||||
|
|
||||||
if (fps_counter == 0)
|
if (fps_counter == 0)
|
||||||
fps_counter = gdk_profiler_define_counter ("fps", "Frames per Second");
|
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
|
static inline gint64
|
||||||
_gdk_frame_clock_get_history_start (GdkFrameClock *frame_clock)
|
_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
|
void
|
||||||
_gdk_frame_clock_begin_frame (GdkFrameClock *frame_clock)
|
_gdk_frame_clock_begin_frame (GdkFrameClock *frame_clock,
|
||||||
|
gint64 monotonic_time)
|
||||||
{
|
{
|
||||||
GdkFrameClockPrivate *priv;
|
GdkFrameClockPrivate *priv;
|
||||||
|
|
||||||
g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
|
g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
|
||||||
|
|
||||||
priv = frame_clock->priv;
|
priv = frame_clock->priv;
|
||||||
|
|
||||||
priv->frame_counter++;
|
priv->frame_counter++;
|
||||||
priv->current = (priv->current + 1) % FRAME_HISTORY_MAX_LENGTH;
|
|
||||||
|
|
||||||
/* Try to steal the previous frame timing instead of discarding
|
if (G_UNLIKELY (timings_get_size (&priv->timings) == 0))
|
||||||
* and allocating a new one.
|
timings_append (&priv->timings, _gdk_frame_timings_new (priv->frame_counter));
|
||||||
*/
|
|
||||||
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++;
|
|
||||||
else
|
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 *
|
static inline GdkFrameTimings *
|
||||||
@ -477,17 +497,21 @@ _gdk_frame_clock_get_timings (GdkFrameClock *frame_clock,
|
|||||||
gint64 frame_counter)
|
gint64 frame_counter)
|
||||||
{
|
{
|
||||||
GdkFrameClockPrivate *priv = frame_clock->priv;
|
GdkFrameClockPrivate *priv = frame_clock->priv;
|
||||||
int pos;
|
gsize size, pos;
|
||||||
|
|
||||||
if (frame_counter > priv->frame_counter)
|
if (frame_counter > priv->frame_counter)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (frame_counter <= priv->frame_counter - priv->n_timings)
|
size = timings_get_size (&priv->timings);
|
||||||
|
if (G_UNLIKELY (size == 0))
|
||||||
return NULL;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -555,7 +555,7 @@ gdk_frame_clock_paint_idle (void *data)
|
|||||||
priv->smoothed_frame_time_period = frame_interval;
|
priv->smoothed_frame_time_period = frame_interval;
|
||||||
priv->smoothed_frame_time_reported = priv->smoothed_frame_time_base;
|
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 */
|
/* Note "current" is different now so timings != prev_timings */
|
||||||
timings = gdk_frame_clock_get_current_timings (clock);
|
timings = gdk_frame_clock_get_current_timings (clock);
|
||||||
|
|
||||||
|
@ -106,7 +106,8 @@ struct _GdkFrameTimings
|
|||||||
void _gdk_frame_clock_inhibit_freeze (GdkFrameClock *clock);
|
void _gdk_frame_clock_inhibit_freeze (GdkFrameClock *clock);
|
||||||
void _gdk_frame_clock_uninhibit_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,
|
void _gdk_frame_clock_debug_print_timings (GdkFrameClock *clock,
|
||||||
GdkFrameTimings *timings);
|
GdkFrameTimings *timings);
|
||||||
void _gdk_frame_clock_add_timings_to_profiler (GdkFrameClock *frame_clock,
|
void _gdk_frame_clock_add_timings_to_profiler (GdkFrameClock *frame_clock,
|
||||||
|
Loading…
Reference in New Issue
Block a user