2012-10-03 22:34:01 +00:00
|
|
|
/* GDK - The GIMP Drawing Kit
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Modified by the GTK+ Team and others 1997-2010. See the AUTHORS
|
|
|
|
* file for a list of people on the GTK+ Team. See the ChangeLog
|
|
|
|
* files for a list of changes. These files are distributed with
|
|
|
|
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2013-02-12 20:02:21 +00:00
|
|
|
#include "gdkframeclockprivate.h"
|
2013-02-12 20:47:38 +00:00
|
|
|
#include "gdkinternals.h"
|
2012-10-03 22:34:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:frameclock
|
|
|
|
* @Short_description: Frame clock syncs painting to a window or display
|
|
|
|
* @Title: Frame clock
|
|
|
|
*
|
|
|
|
* A #GdkFrameClock tells the application when to repaint a window.
|
|
|
|
* This may be synced to the vertical refresh rate of the monitor, for
|
|
|
|
* example. Even when the frame clock uses a simple timer rather than
|
|
|
|
* a hardware-based vertical sync, the frame clock helps because it
|
|
|
|
* ensures everything paints at the same time (reducing the total
|
|
|
|
* number of frames). The frame clock can also automatically stop
|
|
|
|
* painting when it knows the frames will not be visible, or scale back
|
|
|
|
* animation framerates.
|
|
|
|
*
|
|
|
|
* #GdkFrameClock is designed to be compatible with an OpenGL-based
|
|
|
|
* implementation or with mozRequestAnimationFrame in Firefox,
|
|
|
|
* for example.
|
|
|
|
*
|
|
|
|
* A frame clock is idle until someone requests a frame with
|
2012-10-03 23:38:40 +00:00
|
|
|
* gdk_frame_clock_request_phase(). At that time, the frame clock
|
2012-10-03 22:34:01 +00:00
|
|
|
* emits its GdkFrameClock:frame-requested signal if no frame was
|
|
|
|
* already pending.
|
|
|
|
*
|
|
|
|
* At some later time after the frame is requested, the frame clock
|
|
|
|
* MAY indicate that a frame should be painted. To paint a frame the
|
|
|
|
* clock will: Emit GdkFrameClock:before-paint; update the frame time
|
|
|
|
* in the default handler for GdkFrameClock:before-paint; emit
|
|
|
|
* GdkFrameClock:paint; emit GdkFrameClock:after-paint. The app
|
|
|
|
* should paint in a handler for the paint signal.
|
|
|
|
*
|
|
|
|
* If a given frame is not painted (the clock is idle), the frame time
|
|
|
|
* should still update to a conceptual "last frame." i.e. the frame
|
|
|
|
* time will keep moving forward roughly with wall clock time.
|
|
|
|
*
|
|
|
|
* The frame time is in milliseconds. However, it should not be
|
|
|
|
* thought of as having any particular relationship to wall clock
|
|
|
|
* time. Unlike wall clock time, it "snaps" to conceptual frame times
|
|
|
|
* so is low-resolution; it is guaranteed to never move backward (so
|
|
|
|
* say you reset your computer clock, the frame clock will not reset);
|
|
|
|
* and the frame clock is allowed to drift. For example nicer
|
|
|
|
* results when painting with vertical refresh sync may be obtained by
|
|
|
|
* painting as rapidly as possible, but always incrementing the frame
|
|
|
|
* time by the frame length on each frame. This results in a frame
|
|
|
|
* time that doesn't have a lot to do with wall clock time.
|
|
|
|
*/
|
|
|
|
|
2013-02-12 20:02:21 +00:00
|
|
|
G_DEFINE_ABSTRACT_TYPE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
|
2012-10-03 22:34:01 +00:00
|
|
|
|
|
|
|
enum {
|
|
|
|
FRAME_REQUESTED,
|
2012-09-26 14:28:06 +00:00
|
|
|
FLUSH_EVENTS,
|
2012-10-03 22:34:01 +00:00
|
|
|
BEFORE_PAINT,
|
2012-09-26 19:44:30 +00:00
|
|
|
UPDATE,
|
2012-09-18 13:00:57 +00:00
|
|
|
LAYOUT,
|
2012-10-03 22:34:01 +00:00
|
|
|
PAINT,
|
|
|
|
AFTER_PAINT,
|
2012-09-26 14:28:06 +00:00
|
|
|
RESUME_EVENTS,
|
2012-10-03 22:34:01 +00:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL];
|
|
|
|
|
2013-02-12 20:47:38 +00:00
|
|
|
#define FRAME_HISTORY_MAX_LENGTH 16
|
|
|
|
|
2013-02-12 20:02:21 +00:00
|
|
|
struct _GdkFrameClockPrivate
|
|
|
|
{
|
2013-02-12 20:47:38 +00:00
|
|
|
gint64 frame_counter;
|
|
|
|
gint n_timings;
|
|
|
|
gint current;
|
|
|
|
GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
|
2013-02-12 20:02:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_frame_clock_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
GdkFrameClockPrivate *priv = GDK_FRAME_CLOCK (object)->priv;
|
2013-02-12 20:47:38 +00:00
|
|
|
int i;
|
2013-02-12 20:02:21 +00:00
|
|
|
|
2013-02-12 20:47:38 +00:00
|
|
|
for (i = 0; i < FRAME_HISTORY_MAX_LENGTH; i++)
|
|
|
|
if (priv->timings[i] != 0)
|
|
|
|
gdk_frame_timings_unref (priv->timings[i]);
|
2013-02-12 20:02:21 +00:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (gdk_frame_clock_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
2012-10-03 22:34:01 +00:00
|
|
|
static void
|
2013-02-12 20:02:21 +00:00
|
|
|
gdk_frame_clock_class_init (GdkFrameClockClass *klass)
|
2012-10-03 22:34:01 +00:00
|
|
|
{
|
2013-02-12 20:02:21 +00:00
|
|
|
GObjectClass *gobject_class = (GObjectClass*) klass;
|
|
|
|
|
|
|
|
gobject_class->finalize = gdk_frame_clock_finalize;
|
|
|
|
|
2012-10-03 22:34:01 +00:00
|
|
|
/**
|
|
|
|
* GdkFrameClock::frame-requested:
|
|
|
|
* @clock: the frame clock emitting the signal
|
|
|
|
*
|
|
|
|
* This signal is emitted when a frame is not pending, and
|
|
|
|
* gdk_frame_clock_request_frame() is called to request a frame.
|
|
|
|
*/
|
|
|
|
signals[FRAME_REQUESTED] =
|
|
|
|
g_signal_new (g_intern_static_string ("frame-requested"),
|
|
|
|
GDK_TYPE_FRAME_CLOCK,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2012-09-26 14:28:06 +00:00
|
|
|
/**
|
|
|
|
* GdkFrameClock::flush-events:
|
|
|
|
* @clock: the frame clock emitting the signal
|
|
|
|
*
|
|
|
|
* FIXME.
|
|
|
|
*/
|
|
|
|
signals[FLUSH_EVENTS] =
|
|
|
|
g_signal_new (g_intern_static_string ("flush-events"),
|
|
|
|
GDK_TYPE_FRAME_CLOCK,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2012-10-03 22:34:01 +00:00
|
|
|
/**
|
|
|
|
* GdkFrameClock::before-paint:
|
|
|
|
* @clock: the frame clock emitting the signal
|
|
|
|
*
|
|
|
|
* This signal is emitted immediately before the paint signal and
|
|
|
|
* indicates that the frame time has been updated, and signal
|
|
|
|
* handlers should perform any preparatory work before painting.
|
|
|
|
*/
|
|
|
|
signals[BEFORE_PAINT] =
|
|
|
|
g_signal_new (g_intern_static_string ("before-paint"),
|
|
|
|
GDK_TYPE_FRAME_CLOCK,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
2012-09-26 19:44:30 +00:00
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GdkFrameClock::update:
|
|
|
|
* @clock: the frame clock emitting the signal
|
|
|
|
*
|
|
|
|
* FIXME.
|
|
|
|
*/
|
|
|
|
signals[UPDATE] =
|
|
|
|
g_signal_new (g_intern_static_string ("update"),
|
|
|
|
GDK_TYPE_FRAME_CLOCK,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
2012-10-03 22:34:01 +00:00
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2012-09-18 13:00:57 +00:00
|
|
|
/**
|
|
|
|
* GdkFrameClock::layout:
|
|
|
|
* @clock: the frame clock emitting the signal
|
|
|
|
*
|
|
|
|
* This signal is emitted immediately before the paint signal and
|
|
|
|
* indicates that the frame time has been updated, and signal
|
|
|
|
* handlers should perform any preparatory work before painting.
|
|
|
|
*/
|
|
|
|
signals[LAYOUT] =
|
|
|
|
g_signal_new (g_intern_static_string ("layout"),
|
|
|
|
GDK_TYPE_FRAME_CLOCK,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2012-10-03 22:34:01 +00:00
|
|
|
/**
|
|
|
|
* GdkFrameClock::paint:
|
|
|
|
* @clock: the frame clock emitting the signal
|
|
|
|
*
|
|
|
|
* Signal handlers for this signal should paint the window, screen,
|
|
|
|
* or whatever they normally paint.
|
|
|
|
*/
|
|
|
|
signals[PAINT] =
|
|
|
|
g_signal_new (g_intern_static_string ("paint"),
|
|
|
|
GDK_TYPE_FRAME_CLOCK,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GdkFrameClock::after-paint:
|
|
|
|
* @clock: the frame clock emitting the signal
|
|
|
|
*
|
|
|
|
* This signal is emitted immediately after the paint signal and
|
|
|
|
* allows signal handlers to do anything they'd like to do after
|
|
|
|
* painting has been completed. This is a relatively good time to do
|
|
|
|
* "expensive" processing in order to get it done in between frames.
|
|
|
|
*/
|
|
|
|
signals[AFTER_PAINT] =
|
|
|
|
g_signal_new (g_intern_static_string ("after-paint"),
|
|
|
|
GDK_TYPE_FRAME_CLOCK,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2012-09-26 14:28:06 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* GdkFrameClock::resume-events:
|
|
|
|
* @clock: the frame clock emitting the signal
|
|
|
|
*
|
|
|
|
* FIXME.
|
|
|
|
*/
|
|
|
|
signals[RESUME_EVENTS] =
|
|
|
|
g_signal_new (g_intern_static_string ("resume-events"),
|
|
|
|
GDK_TYPE_FRAME_CLOCK,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2013-02-12 20:02:21 +00:00
|
|
|
|
|
|
|
g_type_class_add_private (klass, sizeof (GdkFrameClockPrivate));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_frame_clock_init (GdkFrameClock *clock)
|
|
|
|
{
|
|
|
|
GdkFrameClockPrivate *priv;
|
|
|
|
|
|
|
|
clock->priv = G_TYPE_INSTANCE_GET_PRIVATE (clock,
|
|
|
|
GDK_TYPE_FRAME_CLOCK,
|
|
|
|
GdkFrameClockPrivate);
|
|
|
|
priv = clock->priv;
|
|
|
|
|
2013-02-12 20:47:38 +00:00
|
|
|
priv->frame_counter = -1;
|
|
|
|
priv->current = FRAME_HISTORY_MAX_LENGTH - 1;
|
2012-10-03 22:34:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_frame_clock_get_frame_time:
|
|
|
|
* @clock: the clock
|
|
|
|
*
|
|
|
|
* Gets the time that should currently be used for animations. Inside
|
|
|
|
* a paint, it's the time used to compute the animation position of
|
|
|
|
* everything in a frame. Outside a paint, it's the time of the
|
|
|
|
* conceptual "previous frame," which may be either the actual
|
|
|
|
* previous frame time, or if that's too old, an updated time.
|
|
|
|
*
|
|
|
|
* The returned time has no relationship to wall clock time. It
|
|
|
|
* increases roughly at 1 millisecond per wall clock millisecond, and
|
|
|
|
* it never decreases, but its value is only meaningful relative to
|
|
|
|
* previous frame clock times.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Since: 3.0
|
|
|
|
* Return value: a timestamp in milliseconds
|
|
|
|
*/
|
|
|
|
guint64
|
|
|
|
gdk_frame_clock_get_frame_time (GdkFrameClock *clock)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), 0);
|
|
|
|
|
2013-02-12 20:02:21 +00:00
|
|
|
return GDK_FRAME_CLOCK_GET_CLASS (clock)->get_frame_time (clock);
|
2012-10-03 22:34:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-10-03 23:38:40 +00:00
|
|
|
* gdk_frame_clock_request_phase:
|
2012-10-03 22:34:01 +00:00
|
|
|
* @clock: the clock
|
|
|
|
*
|
|
|
|
* Asks the frame clock to paint a frame. The frame
|
|
|
|
* may or may not ever be painted (the frame clock may
|
|
|
|
* stop itself for whatever reason), but the goal in
|
|
|
|
* normal circumstances would be to paint the frame
|
|
|
|
* at the next expected frame time. For example
|
|
|
|
* if the clock is running at 60fps the frame would
|
|
|
|
* ideally be painted within 1000/60=16 milliseconds.
|
|
|
|
*
|
|
|
|
* Since: 3.0
|
|
|
|
*/
|
|
|
|
void
|
2012-10-03 23:38:40 +00:00
|
|
|
gdk_frame_clock_request_phase (GdkFrameClock *clock,
|
|
|
|
GdkFrameClockPhase phase)
|
2012-10-03 22:34:01 +00:00
|
|
|
{
|
|
|
|
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
|
|
|
|
|
2013-02-12 20:02:21 +00:00
|
|
|
GDK_FRAME_CLOCK_GET_CLASS (clock)->request_phase (clock, phase);
|
2012-10-03 22:34:01 +00:00
|
|
|
}
|
|
|
|
|
2012-10-03 23:38:40 +00:00
|
|
|
|
2012-10-03 23:42:13 +00:00
|
|
|
void
|
|
|
|
gdk_frame_clock_freeze (GdkFrameClock *clock)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
|
|
|
|
|
2013-02-12 20:02:21 +00:00
|
|
|
GDK_FRAME_CLOCK_GET_CLASS (clock)->freeze (clock);
|
2012-10-03 23:42:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gdk_frame_clock_thaw (GdkFrameClock *clock)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
|
|
|
|
|
2013-02-12 20:02:21 +00:00
|
|
|
GDK_FRAME_CLOCK_GET_CLASS (clock)->thaw (clock);
|
2012-10-03 23:42:13 +00:00
|
|
|
}
|
|
|
|
|
2012-10-03 22:34:01 +00:00
|
|
|
/**
|
2012-10-03 23:38:40 +00:00
|
|
|
* gdk_frame_clock_get_requested:
|
2012-10-03 22:34:01 +00:00
|
|
|
* @clock: the clock
|
|
|
|
*
|
|
|
|
* Gets whether a frame paint has been requested but has not been
|
|
|
|
* performed.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Since: 3.0
|
|
|
|
* Return value: TRUE if a frame paint is pending
|
|
|
|
*/
|
2012-10-03 23:38:40 +00:00
|
|
|
GdkFrameClockPhase
|
|
|
|
gdk_frame_clock_get_requested (GdkFrameClock *clock)
|
2012-10-03 22:34:01 +00:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), FALSE);
|
|
|
|
|
2013-02-12 20:02:21 +00:00
|
|
|
return GDK_FRAME_CLOCK_GET_CLASS (clock)->get_requested (clock);
|
2012-10-03 22:34:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_frame_clock_get_frame_time_val:
|
|
|
|
* @clock: the clock
|
|
|
|
* @timeval: #GTimeVal to fill in with frame time
|
|
|
|
*
|
|
|
|
* Like gdk_frame_clock_get_frame_time() but returns the time as a
|
|
|
|
* #GTimeVal which may be handy with some APIs (such as
|
|
|
|
* #GdkPixbufAnimation).
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gdk_frame_clock_get_frame_time_val (GdkFrameClock *clock,
|
|
|
|
GTimeVal *timeval)
|
|
|
|
{
|
|
|
|
guint64 time_ms;
|
|
|
|
|
|
|
|
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
|
|
|
|
|
|
|
|
time_ms = gdk_frame_clock_get_frame_time (clock);
|
|
|
|
|
|
|
|
timeval->tv_sec = time_ms / 1000;
|
|
|
|
timeval->tv_usec = (time_ms % 1000) * 1000;
|
|
|
|
}
|
|
|
|
|
2013-02-12 20:47:38 +00:00
|
|
|
gint64
|
|
|
|
gdk_frame_clock_get_frame_counter (GdkFrameClock *clock)
|
|
|
|
{
|
|
|
|
GdkFrameClockPrivate *priv;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), 0);
|
|
|
|
|
|
|
|
priv = clock->priv;
|
|
|
|
|
|
|
|
return priv->frame_counter;
|
|
|
|
}
|
|
|
|
|
|
|
|
gint64
|
|
|
|
gdk_frame_clock_get_start (GdkFrameClock *clock)
|
|
|
|
{
|
|
|
|
GdkFrameClockPrivate *priv;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), 0);
|
|
|
|
|
|
|
|
priv = clock->priv;
|
|
|
|
|
|
|
|
return priv->frame_counter + 1 - priv->n_timings;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gdk_frame_clock_begin_frame (GdkFrameClock *clock)
|
|
|
|
{
|
|
|
|
GdkFrameClockPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
|
|
|
|
|
|
|
|
priv = clock->priv;
|
|
|
|
|
|
|
|
priv->frame_counter++;
|
|
|
|
priv->current = (priv->current + 1) % FRAME_HISTORY_MAX_LENGTH;
|
|
|
|
|
|
|
|
if (priv->n_timings < FRAME_HISTORY_MAX_LENGTH)
|
|
|
|
priv->n_timings++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gdk_frame_timings_unref(priv->timings[priv->current]);
|
|
|
|
}
|
|
|
|
|
2013-02-12 21:14:24 +00:00
|
|
|
priv->timings[priv->current] = _gdk_frame_timings_new (priv->frame_counter);
|
2013-02-12 20:47:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GdkFrameTimings *
|
|
|
|
gdk_frame_clock_get_timings (GdkFrameClock *clock,
|
|
|
|
gint64 frame_counter)
|
|
|
|
{
|
|
|
|
GdkFrameClockPrivate *priv;
|
|
|
|
gint pos;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), NULL);
|
|
|
|
|
|
|
|
priv = clock->priv;
|
|
|
|
|
|
|
|
if (frame_counter > priv->frame_counter)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (frame_counter <= priv->frame_counter - priv->n_timings)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
pos = (priv->current - (priv->frame_counter - frame_counter) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
|
|
|
|
|
|
|
|
return priv->timings[pos];
|
|
|
|
}
|
|
|
|
|
2012-11-15 19:11:41 +00:00
|
|
|
GdkFrameTimings *
|
|
|
|
gdk_frame_clock_get_current_frame_timings (GdkFrameClock *clock)
|
|
|
|
{
|
2013-02-12 20:47:38 +00:00
|
|
|
GdkFrameClockPrivate *priv;
|
2012-11-15 19:11:41 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), 0);
|
|
|
|
|
2013-02-12 20:47:38 +00:00
|
|
|
priv = clock->priv;
|
|
|
|
|
|
|
|
return gdk_frame_clock_get_timings (clock, priv->frame_counter);
|
2012-11-15 19:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-12 20:47:38 +00:00
|
|
|
GdkFrameTimings *
|
|
|
|
gdk_frame_clock_get_last_complete (GdkFrameClock *clock)
|
|
|
|
{
|
|
|
|
GdkFrameClockPrivate *priv;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), NULL);
|
|
|
|
|
|
|
|
priv = clock->priv;
|
|
|
|
|
|
|
|
for (i = 0; i < priv->n_timings; i++)
|
|
|
|
{
|
|
|
|
gint pos = ((priv->current - i) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
|
2013-02-12 21:14:24 +00:00
|
|
|
if (priv->timings[pos]->complete)
|
2013-02-12 20:47:38 +00:00
|
|
|
return priv->timings[pos];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
|
|
void
|
|
|
|
_gdk_frame_clock_debug_print_timings (GdkFrameClock *clock,
|
|
|
|
GdkFrameTimings *timings)
|
|
|
|
{
|
|
|
|
gint64 previous_frame_time = 0;
|
|
|
|
GdkFrameTimings *previous_timings = gdk_frame_clock_get_timings (clock,
|
2013-02-12 21:14:24 +00:00
|
|
|
timings->frame_counter - 1);
|
2013-02-12 20:47:38 +00:00
|
|
|
|
|
|
|
if (previous_timings != NULL)
|
2013-02-12 21:14:24 +00:00
|
|
|
previous_frame_time = previous_timings->frame_time;
|
2013-02-12 20:47:38 +00:00
|
|
|
|
2013-02-12 21:14:24 +00:00
|
|
|
g_print ("%5" G_GINT64_FORMAT ":", timings->frame_counter);
|
2013-02-12 20:47:38 +00:00
|
|
|
if (previous_frame_time != 0)
|
|
|
|
{
|
2013-02-12 21:14:24 +00:00
|
|
|
g_print (" interval=%-4.1f", (timings->frame_time - previous_frame_time) / 1000.);
|
|
|
|
g_print (timings->slept_before ? " (sleep)" : " ");
|
2013-02-12 20:47:38 +00:00
|
|
|
}
|
2013-02-12 21:14:24 +00:00
|
|
|
if (timings->layout_start_time != 0)
|
|
|
|
g_print (" layout_start=%-4.1f", (timings->layout_start_time - timings->frame_time) / 1000.);
|
|
|
|
if (timings->paint_start_time != 0)
|
|
|
|
g_print (" paint_start=%-4.1f", (timings->paint_start_time - timings->frame_time) / 1000.);
|
|
|
|
if (timings->frame_end_time != 0)
|
|
|
|
g_print (" frame_end=%-4.1f", (timings->frame_end_time - timings->frame_time) / 1000.);
|
|
|
|
if (timings->presentation_time != 0)
|
|
|
|
g_print (" present=%-4.1f", (timings->presentation_time - timings->frame_time) / 1000.);
|
|
|
|
if (timings->predicted_presentation_time != 0)
|
|
|
|
g_print (" predicted=%-4.1f", (timings->predicted_presentation_time - timings->frame_time) / 1000.);
|
|
|
|
if (timings->refresh_interval != 0)
|
|
|
|
g_print (" refresh_interval=%-4.1f", timings->refresh_interval / 1000.);
|
2013-02-12 20:47:38 +00:00
|
|
|
g_print ("\n");
|
|
|
|
}
|
|
|
|
#endif /* G_ENABLE_DEBUG */
|
|
|
|
|
2012-11-15 19:11:41 +00:00
|
|
|
#define DEFAULT_REFRESH_INTERVAL 16667 /* 16.7ms (1/60th second) */
|
|
|
|
#define MAX_HISTORY_AGE 150000 /* 150ms */
|
|
|
|
|
|
|
|
void
|
|
|
|
gdk_frame_clock_get_refresh_info (GdkFrameClock *clock,
|
|
|
|
gint64 base_time,
|
|
|
|
gint64 *refresh_interval_return,
|
|
|
|
gint64 *presentation_time_return)
|
|
|
|
{
|
|
|
|
gint64 frame_counter;
|
|
|
|
|
|
|
|
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
|
|
|
|
|
2013-02-12 20:47:38 +00:00
|
|
|
frame_counter = gdk_frame_clock_get_frame_counter (clock);
|
2012-11-15 19:11:41 +00:00
|
|
|
|
|
|
|
if (presentation_time_return)
|
|
|
|
*presentation_time_return = 0;
|
|
|
|
if (refresh_interval_return)
|
|
|
|
*refresh_interval_return = DEFAULT_REFRESH_INTERVAL;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
2013-02-12 20:47:38 +00:00
|
|
|
GdkFrameTimings *timings = gdk_frame_clock_get_timings (clock, frame_counter);
|
2012-11-15 19:11:41 +00:00
|
|
|
gint64 presentation_time;
|
|
|
|
gint64 refresh_interval;
|
|
|
|
|
|
|
|
if (timings == NULL)
|
|
|
|
return;
|
|
|
|
|
2013-02-12 21:14:24 +00:00
|
|
|
refresh_interval = timings->refresh_interval;
|
|
|
|
presentation_time = timings->presentation_time;
|
2012-11-15 19:11:41 +00:00
|
|
|
|
|
|
|
if (presentation_time != 0)
|
|
|
|
{
|
|
|
|
if (presentation_time > base_time - MAX_HISTORY_AGE &&
|
|
|
|
presentation_time_return)
|
|
|
|
{
|
|
|
|
if (refresh_interval == 0)
|
|
|
|
refresh_interval = DEFAULT_REFRESH_INTERVAL;
|
|
|
|
|
|
|
|
if (refresh_interval_return)
|
|
|
|
*refresh_interval_return = refresh_interval;
|
|
|
|
|
|
|
|
while (presentation_time < base_time)
|
|
|
|
presentation_time += refresh_interval;
|
|
|
|
|
|
|
|
if (presentation_time_return)
|
|
|
|
*presentation_time_return = presentation_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
frame_counter--;
|
|
|
|
}
|
|
|
|
}
|