a93a93d007
Bug 1495 - Timelines run 4% short Previously the timelines were timed by calculating the interval between each frame stored as an integer number of milliseconds so some precision is lost. For example, requesting 60 frames per second gets converted to 16 ms per frame which is actually 62.5 frames per second. This makes the timeline shorter by 4%. This patch merges the common code for timing from the timeout pools and frame sources into an internal clutter-timeout-interval file. This stores the interval directly as the FPS and counts the number of frames that have been reached instead of the elapsed time.
127 lines
3.8 KiB
C
127 lines
3.8 KiB
C
/*
|
|
* Clutter.
|
|
*
|
|
* An OpenGL based 'interactive canvas' library.
|
|
*
|
|
* Authored By Neil Roberts <neil@linux.intel.com>
|
|
*
|
|
* Copyright (C) 2009 Intel Corporation.
|
|
*
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
/* This file contains the common code to check whether an interval has
|
|
expired used in clutter-frame-source and clutter-timeout-pool. */
|
|
|
|
#include "clutter-timeout-interval.h"
|
|
|
|
void
|
|
_clutter_timeout_interval_init (ClutterTimeoutInterval *interval,
|
|
guint fps)
|
|
{
|
|
g_get_current_time (&interval->start_time);
|
|
interval->fps = fps;
|
|
interval->frame_count = 0;
|
|
}
|
|
|
|
static guint
|
|
_clutter_timeout_interval_get_ticks (const GTimeVal *current_time,
|
|
ClutterTimeoutInterval *interval)
|
|
{
|
|
return ((current_time->tv_sec - interval->start_time.tv_sec) * 1000
|
|
+ (current_time->tv_usec - interval->start_time.tv_usec) / 1000);
|
|
}
|
|
|
|
gboolean
|
|
_clutter_timeout_interval_prepare (const GTimeVal *current_time,
|
|
ClutterTimeoutInterval *interval,
|
|
gint *delay)
|
|
{
|
|
guint elapsed_time
|
|
= _clutter_timeout_interval_get_ticks (current_time, interval);
|
|
guint new_frame_num = elapsed_time * interval->fps / 1000;
|
|
|
|
/* If time has gone backwards or the time since the last frame is
|
|
greater than the two frames worth then reset the time and do a
|
|
frame now */
|
|
if (new_frame_num < interval->frame_count ||
|
|
new_frame_num - interval->frame_count > 2)
|
|
{
|
|
/* Get the frame time rounded up to the nearest ms */
|
|
guint frame_time = (1000 + interval->fps - 1) / interval->fps;
|
|
|
|
/* Reset the start time */
|
|
interval->start_time = *current_time;
|
|
/* Move the start time as if one whole frame has elapsed */
|
|
g_time_val_add (&interval->start_time, -(gint) frame_time * 1000);
|
|
|
|
interval->frame_count = 0;
|
|
|
|
if (delay)
|
|
*delay = 0;
|
|
return TRUE;
|
|
}
|
|
else if (new_frame_num > interval->frame_count)
|
|
{
|
|
if (delay)
|
|
*delay = 0;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (delay)
|
|
*delay = ((interval->frame_count + 1) * 1000 / interval->fps
|
|
- elapsed_time);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
_clutter_timeout_interval_dispatch (ClutterTimeoutInterval *interval,
|
|
GSourceFunc callback,
|
|
gpointer user_data)
|
|
{
|
|
if ((* callback) (user_data))
|
|
{
|
|
interval->frame_count++;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
gint
|
|
_clutter_timeout_interval_compare_expiration (const ClutterTimeoutInterval *a,
|
|
const ClutterTimeoutInterval *b)
|
|
{
|
|
guint a_delay = 1000 / a->fps;
|
|
guint b_delay = 1000 / b->fps;
|
|
glong b_difference;
|
|
gint comparison;
|
|
|
|
b_difference = ((a->start_time.tv_sec - b->start_time.tv_sec) * 1000
|
|
+ (a->start_time.tv_usec - b->start_time.tv_usec) / 1000);
|
|
|
|
comparison = ((gint) ((a->frame_count + 1) * a_delay)
|
|
- (gint) ((b->frame_count + 1) * b_delay + b_difference));
|
|
|
|
return (comparison < 0 ? -1
|
|
: comparison > 0 ? 1
|
|
: 0);
|
|
}
|