[cogl/wip/rib/frame-synchronization: 202/206] guarantee a monotonic nanosecond timestamp



commit 14fc192bdaf4c8ee1d3418afb85607d24f395b2f
Author: Robert Bragg <robert linux intel com>
Date:   Fri Jan 11 15:09:39 2013 +0000

    guarantee a monotonic nanosecond timestamp
    
    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 7a8b620..8fe812d 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -56,6 +56,7 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <fcntl.h>
+#include <time.h>
 
 #include <glib/gi18n-lib.h>
 
@@ -175,7 +176,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);
@@ -183,6 +184,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;
 
@@ -198,20 +200,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;
@@ -226,9 +234,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);
@@ -243,34 +251,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->glXGetSyncValues)
-          {
-            int64_t current_monotonic_time;
-            int64_t ust;
-            int64_t msc;
-            int64_t sbc;
-
-            glx_renderer->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;
@@ -298,9 +297,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);
     }
 }
 
@@ -1410,19 +1409,23 @@ _cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
           glx_renderer->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->glXGetVideoSync (&current_count);
           glx_renderer->glXWaitVideoSync (2,
                                           (current_count + 1) % 2,
                                           &current_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;
         }
     }
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]