http://ftp.nluug.nl/pub/os/Linux/distr/pardusrepo/sources/xscreensaver-5.02.tar.gz
[xscreensaver] / utils / visual-gl.c
index fb83fe4f295f716e6718c24bb1ea0084de698fe2..3c8a7a8bd9357baeb437dee07e3500136ab406ef 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1999 by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1999-2007 by Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
 
 /* This file contains code for picking the best visual for GL programs by
    actually asking the GL library to figure it out for us.  The code in
-   visual.c might do a good job of this on most systems, but not, in
-   particular, on SGIs.
-
-   Why?  Because with the SGI O2 X server is weird.
-
-   GL programs tend to work best on a visual that is *half* as deep as the
-   depth of the screen, since that way, they can do double-buffering.  So
-   generally, if the screen is 24 bits deep, but a 12-bit TrueColor visual
-   is available, then that's the visual you should use.
-
-   But on the server that runs on the O2 (a machine that has serious hardware
-   support for GL) the 12-bit PseudoColor visual looks awful (you get a black
-   and white, flickery image.)  On these machines, the visual you want turns
-   out to be 0x31 -- this is but one of the eight 15-bit TrueColor visuals
-   (yes, 8, and yes, 15) that O2s provide.  This is the only visual that works
-   properly -- as far as `xdpyinfo' is concerned, all of the 15-bit TrueColor
-   visuals are identical, but some flicker like mad, and some have deeply
-   weird artifacts (hidden surfaces show through!)  I suppose these other
-   visuals must be tied to some arcane hardware feature...
-
-   So the bottom line is, there exists information about visuals which is
-   available to GL, but which is not available via Xlib calls.  So the only
-   way to know which visual to use (other than impirically) is to actually
-   call GLX routines.
+   visual.c might do a good job of this on most systems, but not on most
+   high end 3D cards (e.g., Silicon Graphics or nVidia.)
+
+   There exists information about visuals which is available to GL, but
+   which is not available via Xlib calls.  So the only way to know
+   which visual to use (other than impirically) is to actually call
+   glXChooseVisual().
  */
 
 #include "utils.h"
 # include <GL/glx.h>
 #endif /* HAVE_GL */
 
+extern char *progname;
+
 Visual *
 get_gl_visual (Screen *screen)
 {
 #ifdef HAVE_GL
-  XVisualInfo *vi = 0;
   Display *dpy = DisplayOfScreen (screen);
   int screen_num = screen_number (screen);
-  int attrs[20];
-  int i = 0;
 
-  attrs[i++] = GLX_RGBA;
-  attrs[i++] = GLX_RED_SIZE;     attrs[i++] = 1;
-  attrs[i++] = GLX_GREEN_SIZE;   attrs[i++] = 1;
-  attrs[i++] = GLX_BLUE_SIZE;    attrs[i++] = 1;
-  attrs[i++] = GLX_DEPTH_SIZE;   attrs[i++] = 1;
-  attrs[i++] = GLX_DOUBLEBUFFER;
-  attrs[i++] = 0;
+# define R GLX_RED_SIZE
+# define G GLX_GREEN_SIZE
+# define B GLX_BLUE_SIZE
+# define A GLX_ALPHA_SIZE
+# define D GLX_DEPTH_SIZE
+# define I GLX_BUFFER_SIZE
+# define DB GLX_DOUBLEBUFFER
+# define ST GLX_STENCIL_SIZE
 
-  vi = glXChooseVisual (dpy, screen_num, attrs);
+  int attrs[][20] = {
+   { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, 0 }, /* rgb double, stencil */
+   { GLX_RGBA, R,8, G,8, B,8,      D,8, DB, ST,1, 0 }, /* rgb double, stencil */
+   { GLX_RGBA, R,4, G,4, B,4,      D,4, DB, ST,1, 0 },
+   { GLX_RGBA, R,2, G,2, B,2,      D,2, DB, ST,1, 0 },
+   { GLX_RGBA, R,8, G,8, B,8,      D,8, DB,       0 }, /* rgb double */
+   { GLX_RGBA, R,4, G,4, B,4,      D,4, DB,       0 },
+   { GLX_RGBA, R,2, G,2, B,2,      D,2, DB,       0 },
+   { GLX_RGBA, R,8, G,8, B,8,      D,8,           0 }, /* rgb single */
+   { GLX_RGBA, R,4, G,4, B,4,      D,4,           0 },
+   { GLX_RGBA, R,2, G,2, B,2,      D,2,           0 },
+   { I, 8,                         D,8, DB,       0 }, /* cmap double */
+   { I, 4,                         D,4, DB,       0 },
+   { I, 8,                         D,8,           0 }, /* cmap single */
+   { I, 4,                         D,4,           0 },
+   { GLX_RGBA, R,1, G,1, B,1,      D,1,           0 }  /* monochrome */
+  };
 
-  if (!vi)                             /* Try without double-buffering. */
+  int i;
+  for (i = 0; i < sizeof(attrs)/sizeof(*attrs); i++)
     {
-      attrs[i-1] = 0;
-      vi = glXChooseVisual (dpy, screen_num, attrs);
+      XVisualInfo *vi = glXChooseVisual (dpy, screen_num, attrs[i]);
+      if (vi)
+        {
+          Visual *v = vi->visual;
+          XFree (vi);
+          /* describe_gl_visual (stderr, screen, v, False); */
+          return v;
+        }
     }
+#endif /* !HAVE_GL */
+
+  return 0;
+}
+
+
+void
+describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
+                    Bool private_cmap_p)
+{
+  describe_visual (f, screen, visual, private_cmap_p);
+
+#ifdef HAVE_GL
+  {
+    int status;
+    int value = False;
+
+    Display *dpy = DisplayOfScreen (screen);
+    XVisualInfo vi_in, *vi_out;
+    int out_count;
+
+    vi_in.screen = screen_number (screen);
+    vi_in.visualid = XVisualIDFromVisual (visual);
+    vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
+                             &vi_in, &out_count);
+    if (! vi_out) abort ();
+
+    status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
+
+    if (status == GLX_NO_EXTENSION)
+      /* dpy does not support the GLX extension. */
+      return;
+
+    if (status == GLX_BAD_VISUAL || value == False)
+      /* this visual does not support GLX. */
+      return;
+    
+    if (!glXGetConfig (dpy, vi_out, GLX_LEVEL, &value) &&
+        value != 0)
+      printf ("    GLX level:         %d\n", value);
+
+    if (!glXGetConfig (dpy, vi_out, GLX_RGBA, &value) && value)
+      {
+        int r=0, g=0, b=0, a=0;
+        glXGetConfig (dpy, vi_out, GLX_RED_SIZE,   &r);
+        glXGetConfig (dpy, vi_out, GLX_GREEN_SIZE, &g);
+        glXGetConfig (dpy, vi_out, GLX_BLUE_SIZE,  &b);
+        glXGetConfig (dpy, vi_out, GLX_ALPHA_SIZE, &a);
+        printf ("    GLX type:          RGBA (%2d, %2d, %2d, %2d)\n",
+                r, g, b, a);
+
+        r=0, g=0, b=0, a=0;
+        glXGetConfig (dpy, vi_out, GLX_ACCUM_RED_SIZE,   &r);
+        glXGetConfig (dpy, vi_out, GLX_ACCUM_GREEN_SIZE, &g);
+        glXGetConfig (dpy, vi_out, GLX_ACCUM_BLUE_SIZE,  &b);
+        glXGetConfig (dpy, vi_out, GLX_ACCUM_ALPHA_SIZE, &a);
+        printf ("    GLX accum:         RGBA (%2d, %2d, %2d, %2d)\n",
+                r, g, b, a);
+      }
+    else
+      {
+        value = 0;
+        glXGetConfig (dpy, vi_out, GLX_BUFFER_SIZE, &value);
+        printf ("    GLX type:          indexed (%d)\n", value);
+      }
+
+# ifdef GLX_VISUAL_CAVEAT_EXT
+    if (!glXGetConfig (dpy, vi_out, GLX_VISUAL_CAVEAT_EXT, &value) &&
+        value != GLX_NONE_EXT)
+#   ifdef GLX_NON_CONFORMANT_EXT
+      printf ("    GLX rating:        %s\n",
+              (value == GLX_NONE_EXT ? "none" :
+               value == GLX_SLOW_VISUAL_EXT ? "slow" :
+               value == GLX_NON_CONFORMANT_EXT ? "non-conformant" :
+               "???"));
+#   else      
+      printf ("    GLX rating:        %s\n",
+              (value == GLX_NONE_EXT ? "none" :
+               value == GLX_SLOW_VISUAL_EXT ? "slow" :
+               "???"));
+#   endif /* GLX_NON_CONFORMANT_EXT */
+# endif /* GLX_VISUAL_CAVEAT_EXT */
+
+    if (!glXGetConfig (dpy, vi_out, GLX_DOUBLEBUFFER, &value))
+      printf ("    GLX double-buffer: %s\n", (value ? "yes" : "no"));
+
+    if (!glXGetConfig (dpy, vi_out, GLX_STEREO, &value) &&
+        value)
+      printf ("    GLX stereo:        %s\n", (value ? "yes" : "no"));
+
+    if (!glXGetConfig (dpy, vi_out, GLX_AUX_BUFFERS, &value) &&
+        value != 0)
+      printf ("    GLX aux buffers:   %d\n", value);
 
-  if (!vi)                             /* Try mono. */
+    if (!glXGetConfig (dpy, vi_out, GLX_DEPTH_SIZE, &value))
+      printf ("    GLX depth size:    %d\n", value);
+
+    if (!glXGetConfig (dpy, vi_out, GLX_STENCIL_SIZE, &value) &&
+        value != 0)
+      printf ("    GLX stencil size:  %d\n", value);
+
+# ifdef GLX_SAMPLE_BUFFERS_SGIS
+    if (!glXGetConfig (dpy, vi_out, GLX_SAMPLE_BUFFERS_SGIS, &value) &&
+        value != 0)
+      {
+        int bufs = value;
+        if (!glXGetConfig (dpy, vi_out, GLX_SAMPLES_SGIS, &value))
+          printf ("    GLX multisamplers: %d (%d)\n", bufs, value);
+      }
+# endif /* GLX_SAMPLE_BUFFERS_SGIS */
+
+    if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_TYPE_EXT, &value) &&
+        value != GLX_NONE_EXT)
+      {
+        if (value == GLX_NONE_EXT)
+          printf ("    GLX transparency:  none\n");
+        else if (value == GLX_TRANSPARENT_INDEX_EXT)
+          {
+            if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_INDEX_VALUE_EXT,
+                               &value))
+              printf ("    GLX transparency:  indexed (%d)\n", value);
+          }
+        else if (value == GLX_TRANSPARENT_RGB_EXT)
+          {
+            int r=0, g=0, b=0, a=0;
+            glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_RED_VALUE_EXT,   &r);
+            glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_GREEN_VALUE_EXT, &g);
+            glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_BLUE_VALUE_EXT,  &b);
+            glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_ALPHA_VALUE_EXT, &a);
+            printf ("    GLX transparency:  RGBA (%2d, %2d, %2d, %2d)\n",
+                    r, g, b, a);
+          }
+      }
+  }
+#endif  /* HAVE_GL */
+}
+
+
+Bool
+validate_gl_visual (FILE *out, Screen *screen, const char *window_desc,
+                    Visual *visual)
+{
+#ifdef HAVE_GL
+  int status;
+  int value = False;
+
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  int out_count;
+  unsigned int id;
+
+  vi_in.screen = screen_number (screen);
+  vi_in.visualid = XVisualIDFromVisual (visual);
+  vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
+                             &vi_in, &out_count);
+  if (! vi_out) abort ();
+
+  status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
+
+  id = (unsigned int) vi_out->visualid;
+  XFree ((char *) vi_out);
+
+  if (status == GLX_NO_EXTENSION)
     {
-      i = 0;
-      attrs[i++] = GLX_DOUBLEBUFFER;
-      attrs[i++] = 0;
-      vi = glXChooseVisual (dpy, screen_num, attrs);
+      fprintf (out, "%s: display \"%s\" does not support the GLX extension.\n",
+               progname, DisplayString (dpy));
+      return False;
     }
-
-  if (!vi)                             /* Try mono without double-buffer. */
+  else if (status == GLX_BAD_VISUAL || value == False)
     {
-      attrs[0] = 0;
-      vi = glXChooseVisual (dpy, screen_num, attrs);
+      fprintf (out,
+               "%s: %s's visual 0x%x does not support the GLX extension.\n",
+               progname, window_desc, id);
+      return False;
     }
-
-  if (!vi)
-    return 0;
   else
     {
-      Visual *v = vi->visual;
-      XFree (vi);
-      return v;
+      return True;
     }
+
 #else  /* !HAVE_GL */
-  return 0;
-#endif /* !HAVE_GL */
+
+  fprintf (out, "%s: GL support was not compiled in to this program.\n",
+           progname);
+  return False;
+
+#endif  /* !HAVE_GL */
 }