add support for swap and sync extensions (Ian Romanick)
authorBrian Paul <brian.paul@tungstengraphics.com>
Wed, 9 Apr 2003 21:47:19 +0000 (21:47 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Wed, 9 Apr 2003 21:47:19 +0000 (21:47 +0000)
progs/xdemos/glxgears.c

index 5969151..40d2f2f 100644 (file)
  * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
  * Port by Brian Paul  23 March 2001
  *
- * Command line options:
- *    -info      print GL implementation information
+ * Modified by Ian Romanick <idr@us.ibm.com> 09 April 2003 to support
+ * GLX_{MESA,SGI}_swap_control and GLX_OML_sync_control.
  *
+ * Command line options:
+ *    -display       Name of the display to use.
+ *    -info          print GL implementation information
+ *    -swap N        Attempt to set the swap interval to 1/N second
+ *    -forcegetrate  Get the display refresh rate even if the required GLX
+ *                   extension is not supported.
  */
 
 
 #include <string.h>
 #include <X11/Xlib.h>
 #include <X11/keysym.h>
+#include <stdint.h>
+#define GLX_GLXEXT_PROTOTYPES
 #include <GL/gl.h>
 #include <GL/glx.h>
 
+#ifndef GLX_MESA_swap_control
+typedef GLint ( * PFNGLXSWAPINTERVALMESAPROC) (unsigned interval);
+typedef GLint ( * PFNGLXGETSWAPINTERVALMESAPROC) ( void );
+#endif
+
+#if !defined( GLX_OML_sync_control ) && defined( _STDINT_H )
+#define GLX_OML_sync_control 1
+typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
+#endif
 
 #define BENCHMARK
 
@@ -48,6 +65,8 @@
 #include <sys/time.h>
 #include <unistd.h>
 
+#define NUL '\0'
+
 /* return current time (in seconds) */
 static int
 current_time(void)
@@ -84,6 +103,12 @@ static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
 static GLint gear1, gear2, gear3;
 static GLfloat angle = 0.0;
 
+static GLboolean has_OML_sync_control = GL_FALSE;
+static GLboolean has_SGI_swap_control = GL_FALSE;
+static GLboolean has_MESA_swap_control = GL_FALSE;
+
+static char ** extension_table = NULL;
+static unsigned num_extensions;
 
 /*
  *
@@ -452,6 +477,133 @@ event_loop(Display *dpy, Window win)
 }
 
 
+/**
+ * Display the refresh rate of the display using the GLX_OML_sync_control
+ * extension.
+ */
+
+static void
+show_refresh_rate( Display * dpy )
+{
+#ifdef GLX_OML_sync_control
+   PFNGLXGETMSCRATEOMLPROC  get_msc_rate;
+   int32_t  n;
+   int32_t  d;
+
+   get_msc_rate = (PFNGLXGETMSCRATEOMLPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetMscRateOML" );
+   if ( get_msc_rate != NULL ) {
+      (*get_msc_rate)( dpy, glXGetCurrentDrawable(), &n, &d );
+      printf( "refresh rate: %.1fHz\n", (float) n / d );
+      return;
+   }
+#endif
+   printf( "glXGetMscRateOML not supported.\n" );
+}
+
+
+/**
+ * Fill in the table of extension strings from a supplied extensions string
+ * (as returned by glXQueryExtensionsString).
+ *
+ * \param string   String of GLX extensions.
+ * \sa is_extension_supported
+ */
+
+static void
+make_extension_table( const char * string )
+{
+   char ** string_tab;
+   unsigned  num_strings;
+   unsigned  base;
+   unsigned  idx;
+   unsigned  i;
+      
+   /* Count the number of spaces in the string.  That gives a base-line
+    * figure for the number of extension in the string.
+    */
+   
+   num_strings = 1;
+   for ( i = 0 ; string[i] != NUL ; i++ ) {
+      if ( string[i] == ' ' ) {
+        num_strings++;
+      }
+   }
+   
+   string_tab = (char **) malloc( sizeof( char * ) * num_strings );
+   if ( string_tab == NULL ) {
+      return;
+   }
+
+   base = 0;
+   idx = 0;
+
+   while ( string[ base ] != NUL ) {
+      /* Determine the length of the next extension string.
+       */
+
+      for ( i = 0 
+           ; (string[ base + i ] != NUL) && (string[ base + i ] != ' ')
+           ; i++ ) {
+        /* empty */ ;
+      }
+
+      if ( i > 0 ) {
+        /* If the string was non-zero length, add it to the table.  We
+         * can get zero length strings if there is a space at the end of
+         * the string or if there are two (or more) spaces next to each
+         * other in the string.
+         */
+
+        string_tab[ idx ] = malloc( sizeof( char ) * (i + 1) );
+        if ( string_tab[ idx ] == NULL ) {
+           return;
+        }
+
+        (void) memcpy( string_tab[ idx ], & string[ base ], i );
+        string_tab[ idx ][i] = NUL;
+        idx++;
+      }
+
+
+      /* Skip to the start of the next extension string.
+       */
+
+      for ( base += i
+           ; (string[ base ] == ' ') && (string[ base ] != NUL) 
+           ; base++ ) {
+        /* empty */ ;
+      }
+   }
+
+   extension_table = string_tab;
+   num_extensions = idx;
+}
+
+    
+/**
+ * Determine of an extension is supported.  The extension string table
+ * must have already be initialized by calling \c make_extension_table.
+ * 
+ * \praram ext  Extension to be tested.
+ * \return GL_TRUE of the extension is supported, GL_FALSE otherwise.
+ * \sa make_extension_table
+ */
+
+static GLboolean
+is_extension_supported( const char * ext )
+{
+   unsigned   i;
+   
+   for ( i = 0 ; i < num_extensions ; i++ ) {
+      if ( strcmp( ext, extension_table[i] ) == 0 ) {
+        return GL_TRUE;
+      }
+   }
+   
+   return GL_FALSE;
+}
+
+
 int
 main(int argc, char *argv[])
 {
@@ -459,17 +611,46 @@ main(int argc, char *argv[])
    Window win;
    GLXContext ctx;
    char *dpyName = ":0";
+   int swap_interval = 1;
+   GLboolean do_swap_interval = GL_FALSE;
+   GLboolean force_get_rate = GL_FALSE;
    GLboolean printInfo = GL_FALSE;
    int i;
+   PFNGLXSWAPINTERVALMESAPROC set_swap_interval = NULL;
+   PFNGLXGETSWAPINTERVALMESAPROC get_swap_interval = NULL;
+
 
    for (i = 1; i < argc; i++) {
-      if (strcmp(argv[i], "-display") == 0) {
+      if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
          dpyName = argv[i+1];
          i++;
       }
       else if (strcmp(argv[i], "-info") == 0) {
          printInfo = GL_TRUE;
       }
+      else if (strcmp(argv[i], "-swap") == 0 && i + 1 < argc) {
+        swap_interval = atoi( argv[i+1] );
+        do_swap_interval = GL_TRUE;
+        i++;
+      }
+      else if (strcmp(argv[i], "-forcegetrate") == 0) {
+        /* This option was put in because some DRI drivers don't support the
+         * full GLX_OML_sync_control extension, but they do support
+         * glXGetMscRateOML.
+         */
+        force_get_rate = GL_TRUE;
+      }
+      else if (strcmp(argv[i], "-help") == 0) {
+         printf("Usage:\n");
+         printf("  gears [options]\n");
+         printf("Options:\n");
+         printf("  -help                   Print this information\n");
+         printf("  -display displayName    Specify X display\n");
+         printf("  -info                   Display GL information\n");
+         printf("  -swap N                 Swap no more than once per N vertical refreshes\n");
+         printf("  -forcgetrate            Try to use glXGetMscRateOML function\n");
+         return 0;
+      }
    }
 
    dpy = XOpenDisplay(dpyName);
@@ -482,11 +663,53 @@ main(int argc, char *argv[])
    XMapWindow(dpy, win);
    glXMakeCurrent(dpy, win, ctx);
 
+   make_extension_table( (char *) glXQueryExtensionsString(dpy,DefaultScreen(dpy)) );
+   has_OML_sync_control = is_extension_supported( "GLX_OML_sync_control" );
+   has_SGI_swap_control = is_extension_supported( "GLX_SGI_swap_control" );
+   has_MESA_swap_control = is_extension_supported( "GLX_MESA_swap_control" );
+
+   if ( has_MESA_swap_control ) {
+      set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalMESA" );
+      get_swap_interval = (PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetSwapIntervalMESA" );
+   }
+   else if ( has_SGI_swap_control ) {
+      set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalSGI" );
+   }
+
+
    if (printInfo) {
       printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
       printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
       printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
       printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+      if ( has_OML_sync_control || force_get_rate ) {
+        show_refresh_rate( dpy );
+      }
+
+      if ( get_swap_interval != NULL ) {
+        printf("Default swap interval = %d\n", (*get_swap_interval)() );
+      }
+   }
+
+   if ( do_swap_interval ) {
+      if ( set_swap_interval != NULL ) {
+        if ( ((swap_interval == 0) && !has_MESA_swap_control)
+             || (swap_interval < 0) ) {
+           printf( "Swap interval must be non-negative or greater than zero "
+                   "if GLX_MESA_swap_control is not supported.\n" );
+        }
+        else {
+           (*set_swap_interval)( swap_interval );
+        }
+
+        if ( printInfo && (get_swap_interval != NULL) ) {
+           printf("Current swap interval = %d\n", (*get_swap_interval)() );
+        }
+      }
+      else {
+        printf("Unable to set swap-interval.  Neither GLX_SGI_swap_control "
+               "nor GLX_MESA_swap_control are supported.\n" );
+      }
    }
 
    init();