[Cogl] [PATCH 4/4] guarantee a monotonic nanosecond timestamp
Robert Bragg
robert at sixbynine.org
Fri Jan 11 08:40:45 PST 2013
From: Robert Bragg <robert at linux.intel.com>
Instead of trying to map into the g_get_monotonic_timestamp this instead
only provides a guarantee that the presentation timestamps are measured
in nanoseconds and that they are monotonic (although there is a note in
the documentation explaining which buggy drivers may actually report non
monotonic times)
This also changes the code to no longer report any presentation times if
the time source has not been identified. The previous code did not seem
to consider that the UST timestamps do not have a defined scale and
unless we try to empirically determine the scale I can't see how we can
reliably map these timestamps. This also addresses a bug where the
previous code assumed that monotonic UST timestamps had units of
microseconds consistent with gettimeofday().
TODO: squash this back into owen's patch
---
cogl/cogl-frame-info.h | 14 ++++++-
cogl/winsys/cogl-winsys-glx.c | 85 +++++++++++++++++++++--------------------
2 files changed, 56 insertions(+), 43 deletions(-)
diff --git a/cogl/cogl-frame-info.h b/cogl/cogl-frame-info.h
index 50d7008..c5a7c5a 100644
--- a/cogl/cogl-frame-info.h
+++ b/cogl/cogl-frame-info.h
@@ -74,8 +74,18 @@ int64_t cogl_frame_info_get_frame_counter (CoglFrameInfo *info);
* Gets the presentation time for the frame. This is the time at which
* the frame became visible to the user.
*
- * Return value: the presentation time for the frame, in
- * the timescale of g_get_monotonic_time().
+ * The presentation time measured in nanoseconds is based on a
+ * monotonic time source. The time source is not necessarily
+ * correlated with system/wall clock time and may represent the time
+ * elapsed since some undefined system event such as when the system
+ * last booted.
+ *
+ * <note>Linux kernel version less that 3.8 can result in
+ * non-monotonic timestamps being reported when using a drm based
+ * OpenGL driver. Also some buggy Mesa drivers up to 9.0.1 may also
+ * incorrectly report non-monotonic timestamps.</note>
+ *
+ * Return value: the presentation time for the frame
* Since: 2.0
* Stability: unstable
*/
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index f8114c6..0c7224f 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -55,6 +55,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
+#include <time.h>
#include <glib/gi18n-lib.h>
@@ -171,7 +172,7 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid)
static void
ensure_ust_type (CoglRenderer *renderer,
- GLXDrawable drawable)
+ GLXDrawable drawable)
{
CoglGLXRenderer *glx_renderer = renderer->winsys;
CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
@@ -179,6 +180,7 @@ ensure_ust_type (CoglRenderer *renderer,
int64_t msc;
int64_t sbc;
struct timeval tv;
+ struct timespec ts;
int64_t current_system_time;
int64_t current_monotonic_time;
@@ -194,20 +196,26 @@ ensure_ust_type (CoglRenderer *renderer,
&ust, &msc, &sbc))
goto out;
- /* This is the method that Xorg uses currently */
- gettimeofday(&tv, NULL);
+ /* This is the time source that existing (buggy) linux drm drivers
+ * use */
+ gettimeofday (&tv, NULL);
current_system_time = (tv.tv_sec * G_GINT64_CONSTANT (1000000)) + tv.tv_usec;
- if (current_system_time > ust - 1000000 && current_system_time < ust + 1000000)
+ if (current_system_time > ust - 1000000 &&
+ current_system_time < ust + 1000000)
{
glx_renderer->ust_type = COGL_GLX_UST_IS_GETTIMEOFDAY;
goto out;
}
- /* This is the method that would make sense for a GL implementation to use -
- * clock_gettime (CLOCK_MONOTONIC, &ts) */
- current_monotonic_time = g_get_monotonic_time ();
- if (current_monotonic_time > ust - 1000000 && current_monotonic_time < ust + 1000000)
+ /* This is the time source that the newer (fixed) linux drm
+ * drivers use (Linux >= 3.8) */
+ clock_gettime (CLOCK_MONOTONIC, &ts);
+ current_monotonic_time = (ts.tv_sec * G_GINT64_CONSTANT (1000000)) +
+ (ts.tv_nsec / G_GINT64_CONSTANT (1000));
+
+ if (current_monotonic_time > ust - 1000000 &&
+ current_monotonic_time < ust + 1000000)
{
glx_renderer->ust_type = COGL_GLX_UST_IS_MONOTONIC_TIME;
goto out;
@@ -222,9 +230,9 @@ ensure_ust_type (CoglRenderer *renderer,
}
static int64_t
-ust_to_monotonic_time (CoglRenderer *renderer,
- GLXDrawable drawable,
- int64_t ust)
+ust_to_nanoseconds (CoglRenderer *renderer,
+ GLXDrawable drawable,
+ int64_t ust)
{
CoglGLXRenderer *glx_renderer = renderer->winsys;
CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
@@ -239,34 +247,25 @@ ust_to_monotonic_time (CoglRenderer *renderer,
case COGL_GLX_UST_IS_GETTIMEOFDAY:
{
struct timeval tv;
- int64_t current_system_time;
- int64_t current_monotonic_time;
-
- gettimeofday(&tv, NULL);
- current_system_time = (tv.tv_sec * G_GINT64_CONSTANT (1000000)) + tv.tv_usec;
- current_monotonic_time = g_get_monotonic_time ();
- return ust + current_monotonic_time - current_system_time;
+ gettimeofday (&tv, NULL);
+ return tv.tv_sec * G_GINT64_CONSTANT (1000000000) +
+ tv.tv_usec * G_GINT64_CONSTANT (1000);
}
case COGL_GLX_UST_IS_MONOTONIC_TIME:
return ust;
case COGL_GLX_UST_IS_OTHER:
- {
- if (glx_renderer->pf_glXGetSyncValues)
- {
- int64_t current_monotonic_time;
- int64_t ust;
- int64_t msc;
- int64_t sbc;
-
- glx_renderer->pf_glXGetSyncValues (xlib_renderer->xdpy, drawable,
- &ust, &msc, &sbc);
-
- current_monotonic_time = g_get_monotonic_time ();
- return ust + current_monotonic_time - ust;
- }
- break;
- }
+ /* In this case the scale of UST is undefined so we can't easily
+ * scale to nanoseconds.
+ *
+ * For example the driver may be reporting the rdtsc CPU counter
+ * as UST values and so the scale would need to be determined
+ * empirically.
+ *
+ * Potentially we could block for a known duration within
+ * ensure_ust_type() to measure the timescale of UST but for now
+ * we just ignore unknown time sources */
+ return 0;
}
return 0;
@@ -294,9 +293,9 @@ notify_swap_buffers (CoglContext *context, GLXBufferSwapComplete *swap_event)
{
CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos);
info->presentation_time =
- ust_to_monotonic_time (context->display->renderer,
- glx_onscreen->glxwin,
- swap_event->ust);
+ ust_to_nanoseconds (context->display->renderer,
+ glx_onscreen->glxwin,
+ swap_event->ust);
}
}
@@ -1377,19 +1376,23 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
glx_renderer->pf_glXWaitForMsc (xlib_renderer->xdpy, drawable,
0, 2, (msc + 1) % 2,
&ust, &msc, &sbc);
- info->presentation_time = ust_to_monotonic_time (ctx->display->renderer,
- drawable,
- ust);
+ info->presentation_time = ust_to_nanoseconds (ctx->display->renderer,
+ drawable,
+ ust);
}
else
{
uint32_t current_count;
+ struct timespec ts;
glx_renderer->pf_glXGetVideoSync (¤t_count);
glx_renderer->pf_glXWaitVideoSync (2,
(current_count + 1) % 2,
¤t_count);
- info->presentation_time = g_get_monotonic_time ();
+
+ clock_gettime (CLOCK_MONOTONIC, &ts);
+ info->presentation_time =
+ ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
}
}
}
--
1.7.7.6
More information about the Cogl
mailing list