-/* xscreensaver, Copyright (c) 1999 by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1999, 2000 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 D GLX_DEPTH_SIZE
+# define I GLX_BUFFER_SIZE
- vi = glXChooseVisual (dpy, screen_num, attrs);
+ int attrs[][20] = {
+ { GLX_RGBA, R, 8, G, 8, B, 8, D, 8, GLX_DOUBLEBUFFER, 0 }, /* rgb double */
+ { GLX_RGBA, R, 4, G, 4, B, 4, D, 4, GLX_DOUBLEBUFFER, 0 },
+ { GLX_RGBA, R, 2, G, 2, B, 2, D, 2, GLX_DOUBLEBUFFER, 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, GLX_DOUBLEBUFFER, 0 }, /* cmap double */
+ { I, 4, D, 4, GLX_DOUBLEBUFFER, 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)
+ printf (" GLX rating: %s\n",
+ (value == GLX_NONE_EXT ? "none" :
+ value == GLX_SLOW_VISUAL_EXT ? "slow" :
+# ifdef GLX_NON_CONFORMANT_EXT
+ value == GLX_NON_CONFORMANT_EXT ? "non-conformant" :
+# 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 */
}