Author: tack
Date: Fri Apr 27 03:00:30 2007
New Revision: 2658

Modified:
   trunk/xine/src/drivers/video_out_kaa.c
   trunk/xine/src/drivers/video_out_kaa.h

Log:
Much smarter glx vsync code.  Only waits for vertical retrace if the
frame duration is a multiple of the display refresh and the last frame
was displayed at most 1 retrace ago.


Modified: trunk/xine/src/drivers/video_out_kaa.c
==============================================================================
--- trunk/xine/src/drivers/video_out_kaa.c      (original)
+++ trunk/xine/src/drivers/video_out_kaa.c      Fri Apr 27 03:00:30 2007
@@ -51,27 +51,29 @@
 extern int (*glXGetVideoSyncSGI)(unsigned int *);
 #endif
 
+static long long get_usecs()
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return (long long)((tv.tv_sec * 1000000.0) + tv.tv_usec);
+}
+
 #ifdef STOPWATCH
 static void stopwatch(int n, char *text, ...)
 {
     va_list ap;
-    struct timezone tz;
     static struct {
-        struct timeval tv, last_tv;
+        long long t0, t1;
         char text[250];
     } t[10];
 
     if (n > STOPWATCH)
         return;
-    gettimeofday(&t[n].tv, &tz);
+    t[n].t1 = get_usecs();
     if (!text) {
-        fprintf(stderr, "@@@ Stopwatch (%d): %s: %ld usec\n", n, t[n].text,
-               (t[n].tv.tv_sec - t[n].last_tv.tv_sec) * 1000000 +
-               (t[n].tv.tv_usec - t[n].last_tv.tv_usec));
+        fprintf(stderr, "@@@ Stopwatch (%d): %s: %lld usec\n", n, t[n].text, 
t[n].t1 - t[n].t0);
     } else {
-        t[n].last_tv.tv_sec = t[n].tv.tv_sec;
-        t[n].last_tv.tv_usec = t[n].tv.tv_usec;
-
+        t[n].t0 = t[n].t1;
         va_start(ap, text);
         vsprintf(t[n].text, text, ap);
         va_end(ap);
@@ -917,11 +919,42 @@
     if (this->passthrough && this->do_passthrough)  {
 #ifdef HAVE_OPENGL_VSYNC
         if (this->glx_display) {
-            unsigned int count;
-            int ret;
-            if (glXMakeCurrent(this->glx_display, this->glx_drawable, 
this->glx_context))
-                if (glXGetVideoSyncSGI(&count) == 0)
-                    ret = glXWaitVideoSyncSGI(2, (count+1)%2 ,&count);
+            /* GLX vsync is enabled.  First we need to determine the display's
+             * refresh rate, which is represented by vsync_duration in 1/90000
+             * second units (same units as xine frame duration).  Once that is
+             * determine, we decide whether or not to wait for vertical refresh
+             * iff the frame duration is an integer multiple of of the refresh
+             * rate and the last frame was displayed at most 1 vsyncs ago.
+             */
+            XLockDisplay(this->glx_display);
+            if (glXMakeCurrent(this->glx_display, this->glx_drawable, 
this->glx_context)) {
+                unsigned int count;
+                int ret;
+                if (this->vsync_duration == 0) {
+                    // We still need to figure out vsync of display.
+                    long long t1 = get_usecs();
+                    float delta = (t1 - this->vsync_measure_t0) / 1000000.0;
+                    if (delta >= 2.0) {
+                        // 2 seconds has passed since initial measure, should
+                        // be enough time to reliably determine refresh rate.
+                        glXGetVideoSyncSGI(&count);
+                        this->vsync_duration = (delta / (count - 
this->last_vsync_count) * 90000);
+                    }
+                } else if (glXGetVideoSyncSGI(&count) == 0) {
+                    // We know display refresh rate and current retrace 
counter.
+                    float multiple = frame_gen->duration / 
(float)this->vsync_duration;
+                    if (fabs(roundf(multiple) - multiple) < 0.02 && count - 
this->last_vsync_count <= 1) {
+                        /* Frame duration looks pretty damn close to a multiple
+                         * of the display refresh rate, and our last frame was
+                         * at most 1 refresh ago, so let's wait for next 
+                         * refresh.
+                         */
+                        ret = glXWaitVideoSyncSGI(2, (count+1)%2, &count);
+                    }
+                    this->last_vsync_count = count;
+                }
+            }
+            XUnlockDisplay(this->glx_display);
         }
 #endif
         this->passthrough->display_frame(this->passthrough, 
frame->passthrough_frame);
@@ -961,8 +994,16 @@
 {
     kaa_driver_t *this = (kaa_driver_t *)this_gen;
 
-    // FIXME: handle XINE_GUI_SEND_DRAWABLE_CHANGED for opengl vsync.
     switch(data_type) {
+#ifdef HAVE_OPENGL_VSYNC
+        case XINE_GUI_SEND_DRAWABLE_CHANGED:
+            if (this->glx_context && (GLXDrawable)data != this->glx_drawable) {
+                // FIXME: initialize new glx context
+
+            }
+            break;
+#endif
+
         case GUI_SEND_KAA_VO_SET_PASSTHROUGH:
             pthread_mutex_lock(&this->osd_buffer_lock);
             this->do_passthrough = (int)data;
@@ -1070,14 +1111,20 @@
                         GLX_BLUE_SIZE, 1,
                         None};
 
+    XLockDisplay(vis->display);
     ret = glXQueryExtension(vis->display, &ndummy, &ndummy);
     if (ret <= 0)
-        return;
+        return XUnlockDisplay(vis->display);
 
     xt = glXQueryExtensionsString(vis->display, vis->screen);
     if (!xt || !strstr(xt, "GLX_SGI_video_sync")) {
         printf("OpenGL vsync not supported on this system (no 
GLX_SGI_video_sync)\n");
-        return;
+        return XUnlockDisplay(vis->display);
+    }
+
+    if (this->glx_context) {
+        glXDestroyContext(this->glx_display, this->glx_context);
+        this->glx_context = NULL;
     }
 
     printf("OpenGL vsync supported on this system.\n");
@@ -1087,8 +1134,22 @@
         if (this->glx_context) {
             this->glx_drawable = vis->d;
             this->glx_display = vis->display;
+            if (glXMakeCurrent(this->glx_display, this->glx_drawable, 
this->glx_context)) {
+                /* Take initial measurement in order to determine display
+                 * refresh rate.
+                 */
+                this->vsync_measure_t0 = get_usecs();
+                glXGetVideoSyncSGI(&this->last_vsync_count);
+                /* Clear GLX context.  I'm not sure why this is necessary,
+                 * but without this, glXMakeCurrent in display_frame()
+                 * fails.
+                 */
+                glXMakeCurrent(this->glx_display, None, NULL);
+            }
         }
     }
+    XFree(vi);
+    XUnlockDisplay(vis->display);
 }
 #endif
 
@@ -1149,6 +1210,8 @@
     this->osd_alpha             = 255;
 #ifdef HAVE_OPENGL_VSYNC
     this->glx_display           = NULL;
+    this->glx_context           = NULL;
+    this->vsync_duration        = 0;
     if (visual->use_opengl_vsync && glXWaitVideoSyncSGI && glXGetVideoSyncSGI)
         _kaa_setup_glx(this, (x11_visual_t *)visual->passthrough_visual);
 #endif

Modified: trunk/xine/src/drivers/video_out_kaa.h
==============================================================================
--- trunk/xine/src/drivers/video_out_kaa.h      (original)
+++ trunk/xine/src/drivers/video_out_kaa.h      Fri Apr 27 03:00:30 2007
@@ -123,6 +123,9 @@
     GLXContext  glx_context;
     GLXDrawable glx_drawable;
     Display *glx_display;
+    long long vsync_measure_t0;
+    unsigned int last_vsync_count;
+    int vsync_duration; // duration of one vertical refresh (in 1/90000 sec)
 #endif
 } kaa_driver_t;
 

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to