http://www.jwz.org/xscreensaver/xscreensaver-5.13.tar.gz
[xscreensaver] / utils / visual-gl.c
1 /* xscreensaver, Copyright (c) 1999-2011 by Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 /* This file contains code for picking the best visual for GL programs by
13    actually asking the GL library to figure it out for us.  The code in
14    visual.c might do a good job of this on most systems, but not on most
15    high end 3D cards (e.g., Silicon Graphics or nVidia.)
16
17    There exists information about visuals which is available to GL, but
18    which is not available via Xlib calls.  So the only way to know
19    which visual to use (other than impirically) is to actually call
20    glXChooseVisual().
21  */
22
23 #include "utils.h"
24 #include "visual.h"
25 #include "resources.h"
26
27 #ifdef HAVE_GL
28 # include <GL/gl.h>
29 # include <GL/glx.h>
30 #endif /* HAVE_GL */
31
32 extern char *progname;
33
34 Visual *
35 get_gl_visual (Screen *screen)
36 {
37 #ifdef HAVE_GL
38   Display *dpy = DisplayOfScreen (screen);
39   int screen_num = screen_number (screen);
40
41 # define R GLX_RED_SIZE
42 # define G GLX_GREEN_SIZE
43 # define B GLX_BLUE_SIZE
44 # define A GLX_ALPHA_SIZE
45 # define D GLX_DEPTH_SIZE
46 # define I GLX_BUFFER_SIZE
47 # define DB GLX_DOUBLEBUFFER
48 # define ST GLX_STENCIL_SIZE
49
50 # if defined(GL_SAMPLE_BUFFERS)
51 #  define SB GL_SAMPLE_BUFFERS
52 #  define SM GL_SAMPLES
53 # elif defined(GLX_SAMPLE_BUFFERS)
54 #  define SB GLX_SAMPLE_BUFFERS
55 #  define SM GLX_SAMPLES
56 # elif defined(GLX_SAMPLE_BUFFERS_ARB)
57 #  define SB GLX_SAMPLE_BUFFERS_ARB
58 #  define SM GLX_SAMPLES_ARB
59 # elif defined(GLX_SAMPLE_BUFFERS_SGIS)
60 #  define SB GLX_SAMPLE_BUFFERS_SGIS
61 #  define SM GLX_SAMPLES_SGIS
62 # endif
63
64   int attrs[][40] = {
65 # ifdef SB                                /* rgba double stencil multisample */
66    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,8, 0 },
67    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,6, 0 },
68    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,4, 0 },
69    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,2, 0 },
70 #  define SB_COUNT 4 /* #### Kludgey count of preceeding lines! */
71 # endif
72    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, 0 }, /* rgba double stencil */
73    { GLX_RGBA, R,8, G,8, B,8,      D,8, DB, ST,1, 0 }, /* rgb  double stencil */
74    { GLX_RGBA, R,4, G,4, B,4,      D,4, DB, ST,1, 0 },
75    { GLX_RGBA, R,2, G,2, B,2,      D,2, DB, ST,1, 0 },
76    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB,       0 }, /* rgba double */
77    { GLX_RGBA, R,8, G,8, B,8,      D,8, DB,       0 }, /* rgb  double */
78    { GLX_RGBA, R,4, G,4, B,4,      D,4, DB,       0 },
79    { GLX_RGBA, R,2, G,2, B,2,      D,2, DB,       0 },
80    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8,           0 }, /* rgba single */
81    { GLX_RGBA, R,8, G,8, B,8,      D,8,           0 }, /* rgb  single */
82    { GLX_RGBA, R,4, G,4, B,4,      D,4,           0 },
83    { GLX_RGBA, R,2, G,2, B,2,      D,2,           0 },
84    { I, 8,                         D,8, DB,       0 }, /* cmap double */
85    { I, 4,                         D,4, DB,       0 },
86    { I, 8,                         D,8,           0 }, /* cmap single */
87    { I, 4,                         D,4,           0 },
88    { GLX_RGBA, R,1, G,1, B,1,      D,1,           0 }  /* monochrome */
89   };
90
91   int i = 0;
92
93 # ifdef SB
94   if (! get_boolean_resource (dpy, "multiSample", "MultiSample"))
95     i = SB_COUNT;  /* skip over the multibuffer entries in 'attrs' */
96 # endif /* SB */
97
98   for (; i < sizeof(attrs)/sizeof(*attrs); i++)
99     {
100       XVisualInfo *vi = glXChooseVisual (dpy, screen_num, attrs[i]);
101       if (vi)
102         {
103           Visual *v = vi->visual;
104           XFree (vi);
105           /* describe_gl_visual (stderr, screen, v, False); */
106           return v;
107         }
108     }
109 #endif /* !HAVE_GL */
110
111   return 0;
112 }
113
114
115 void
116 describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
117                     Bool private_cmap_p)
118 {
119   describe_visual (f, screen, visual, private_cmap_p);
120
121 #ifdef HAVE_GL
122   {
123     int status;
124     int value = False;
125
126     Display *dpy = DisplayOfScreen (screen);
127     XVisualInfo vi_in, *vi_out;
128     int out_count;
129
130     vi_in.screen = screen_number (screen);
131     vi_in.visualid = XVisualIDFromVisual (visual);
132     vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
133                              &vi_in, &out_count);
134     if (! vi_out) abort ();
135
136     status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
137
138     if (status == GLX_NO_EXTENSION)
139       /* dpy does not support the GLX extension. */
140       return;
141
142     if (status == GLX_BAD_VISUAL || value == False)
143       /* this visual does not support GLX. */
144       return;
145     
146     if (!glXGetConfig (dpy, vi_out, GLX_LEVEL, &value) &&
147         value != 0)
148       printf ("    GLX level:         %d\n", value);
149
150     if (!glXGetConfig (dpy, vi_out, GLX_RGBA, &value) && value)
151       {
152         int r=0, g=0, b=0, a=0;
153         glXGetConfig (dpy, vi_out, GLX_RED_SIZE,   &r);
154         glXGetConfig (dpy, vi_out, GLX_GREEN_SIZE, &g);
155         glXGetConfig (dpy, vi_out, GLX_BLUE_SIZE,  &b);
156         glXGetConfig (dpy, vi_out, GLX_ALPHA_SIZE, &a);
157         printf ("    GLX type:          RGBA (%2d, %2d, %2d, %2d)\n",
158                 r, g, b, a);
159
160         r=0, g=0, b=0, a=0;
161         glXGetConfig (dpy, vi_out, GLX_ACCUM_RED_SIZE,   &r);
162         glXGetConfig (dpy, vi_out, GLX_ACCUM_GREEN_SIZE, &g);
163         glXGetConfig (dpy, vi_out, GLX_ACCUM_BLUE_SIZE,  &b);
164         glXGetConfig (dpy, vi_out, GLX_ACCUM_ALPHA_SIZE, &a);
165         printf ("    GLX accum:         RGBA (%2d, %2d, %2d, %2d)\n",
166                 r, g, b, a);
167       }
168     else
169       {
170         value = 0;
171         glXGetConfig (dpy, vi_out, GLX_BUFFER_SIZE, &value);
172         printf ("    GLX type:          indexed (%d)\n", value);
173       }
174
175 # ifndef  GLX_NONE_EXT       /* Hooray for gratuitious name changes. */
176 #  define GLX_NONE_EXT                    GLX_NONE
177 #  define GLX_TRANSPARENT_TYPE_EXT        GLX_TRANSPARENT_TYPE
178 #  define GLX_TRANSPARENT_INDEX_EXT       GLX_TRANSPARENT_INDEX
179 #  define GLX_TRANSPARENT_INDEX_VALUE_EXT GLX_TRANSPARENT_INDEX_VALUE
180 #  define GLX_TRANSPARENT_RGB_EXT         GLX_TRANSPARENT_RGB
181 #  define GLX_TRANSPARENT_RED_VALUE_EXT   GLX_TRANSPARENT_RED_VALUE
182 #  define GLX_TRANSPARENT_GREEN_VALUE_EXT GLX_TRANSPARENT_GREEN_VALUE
183 #  define GLX_TRANSPARENT_BLUE_VALUE_EXT  GLX_TRANSPARENT_BLUE_VALUE
184 #  define GLX_TRANSPARENT_ALPHA_VALUE_EXT GLX_TRANSPARENT_ALPHA_VALUE
185 # endif
186
187 # ifdef GLX_VISUAL_CAVEAT_EXT
188     if (!glXGetConfig (dpy, vi_out, GLX_VISUAL_CAVEAT_EXT, &value) &&
189         value != GLX_NONE_EXT)
190 #   ifdef GLX_NON_CONFORMANT_EXT
191       printf ("    GLX rating:        %s\n",
192               (value == GLX_NONE_EXT ? "none" :
193                value == GLX_SLOW_VISUAL_EXT ? "slow" :
194                value == GLX_NON_CONFORMANT_EXT ? "non-conformant" :
195                "???"));
196 #   else      
197       printf ("    GLX rating:        %s\n",
198               (value == GLX_NONE_EXT ? "none" :
199                value == GLX_SLOW_VISUAL_EXT ? "slow" :
200                "???"));
201 #   endif /* GLX_NON_CONFORMANT_EXT */
202 # endif /* GLX_VISUAL_CAVEAT_EXT */
203
204     if (!glXGetConfig (dpy, vi_out, GLX_DOUBLEBUFFER, &value))
205       printf ("    GLX double-buffer: %s\n", (value ? "yes" : "no"));
206
207     if (!glXGetConfig (dpy, vi_out, GLX_STEREO, &value) &&
208         value)
209       printf ("    GLX stereo:        %s\n", (value ? "yes" : "no"));
210
211     if (!glXGetConfig (dpy, vi_out, GLX_AUX_BUFFERS, &value) &&
212         value != 0)
213       printf ("    GLX aux buffers:   %d\n", value);
214
215     if (!glXGetConfig (dpy, vi_out, GLX_DEPTH_SIZE, &value))
216       printf ("    GLX depth size:    %d\n", value);
217
218     if (!glXGetConfig (dpy, vi_out, GLX_STENCIL_SIZE, &value) &&
219         value != 0)
220       printf ("    GLX stencil size:  %d\n", value);
221
222 # ifdef SB  /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */
223     if (!glXGetConfig (dpy, vi_out, SB, &value) &&
224         value != 0)
225       {
226         int bufs = value;
227         if (!glXGetConfig (dpy, vi_out, SM, &value))
228           printf ("    GLX multisample:   %d, %d\n", bufs, value);
229       }
230 # endif  /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */
231
232     if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_TYPE_EXT, &value) &&
233         value != GLX_NONE_EXT)
234       {
235         if (value == GLX_NONE_EXT)
236           printf ("    GLX transparency:  none\n");
237         else if (value == GLX_TRANSPARENT_INDEX_EXT)
238           {
239             if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_INDEX_VALUE_EXT,
240                                &value))
241               printf ("    GLX transparency:  indexed (%d)\n", value);
242           }
243         else if (value == GLX_TRANSPARENT_RGB_EXT)
244           {
245             int r=0, g=0, b=0, a=0;
246             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_RED_VALUE_EXT,   &r);
247             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_GREEN_VALUE_EXT, &g);
248             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_BLUE_VALUE_EXT,  &b);
249             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_ALPHA_VALUE_EXT, &a);
250             printf ("    GLX transparency:  RGBA (%2d, %2d, %2d, %2d)\n",
251                     r, g, b, a);
252           }
253       }
254   }
255 #endif  /* HAVE_GL */
256 }
257
258
259 Bool
260 validate_gl_visual (FILE *out, Screen *screen, const char *window_desc,
261                     Visual *visual)
262 {
263 #ifdef HAVE_GL
264   int status;
265   int value = False;
266
267   Display *dpy = DisplayOfScreen (screen);
268   XVisualInfo vi_in, *vi_out;
269   int out_count;
270   unsigned int id;
271
272   vi_in.screen = screen_number (screen);
273   vi_in.visualid = XVisualIDFromVisual (visual);
274   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
275                              &vi_in, &out_count);
276   if (! vi_out) abort ();
277
278   status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
279
280   id = (unsigned int) vi_out->visualid;
281   XFree ((char *) vi_out);
282
283   if (status == GLX_NO_EXTENSION)
284     {
285       fprintf (out, "%s: display \"%s\" does not support the GLX extension.\n",
286                progname, DisplayString (dpy));
287       return False;
288     }
289   else if (status == GLX_BAD_VISUAL || value == False)
290     {
291       fprintf (out,
292                "%s: %s's visual 0x%x does not support the GLX extension.\n",
293                progname, window_desc, id);
294       return False;
295     }
296   else
297     {
298       return True;
299     }
300
301 #else  /* !HAVE_GL */
302
303   fprintf (out, "%s: GL support was not compiled in to this program.\n",
304            progname);
305   return False;
306
307 #endif  /* !HAVE_GL */
308 }