From http://www.jwz.org/xscreensaver/xscreensaver-5.40.tar.gz
[xscreensaver] / utils / visual-gl.c
1 /* xscreensaver, Copyright (c) 1999-2018 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(GLX_SAMPLE_BUFFERS) /* Needs to come before GL_SAMPLE_BUFFERS */
51 #  define SB GLX_SAMPLE_BUFFERS
52 #  define SM GLX_SAMPLES
53 # elif defined(GLX_SAMPLE_BUFFERS_ARB)
54 #  define SB GLX_SAMPLE_BUFFERS_ARB
55 #  define SM GLX_SAMPLES_ARB
56 # elif defined(GLX_SAMPLE_BUFFERS_SGIS)
57 #  define SB GLX_SAMPLE_BUFFERS_SGIS
58 #  define SM GLX_SAMPLES_SGIS
59 # elif defined(GL_SAMPLE_BUFFERS)
60 #  define SB GL_SAMPLE_BUFFERS
61 #  define SM GL_SAMPLES
62 # endif
63
64
65   int attrs[][40] = {
66 # ifdef SB                                /* rgba double stencil multisample */
67    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,8, 0 },
68    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,6, 0 },
69    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,4, 0 },
70    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,2, 0 },
71 #  define SB_COUNT 4 /* #### Kludgey count of preceeding lines! */
72 # endif
73    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, 0 }, /* rgba double stencil */
74    { GLX_RGBA, R,8, G,8, B,8,      D,8, DB, ST,1, 0 }, /* rgb  double stencil */
75    { GLX_RGBA, R,4, G,4, B,4,      D,4, DB, ST,1, 0 },
76    { GLX_RGBA, R,2, G,2, B,2,      D,2, DB, ST,1, 0 },
77    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB,       0 }, /* rgba double */
78    { GLX_RGBA, R,8, G,8, B,8,      D,8, DB,       0 }, /* rgb  double */
79    { GLX_RGBA, R,4, G,4, B,4,      D,4, DB,       0 },
80    { GLX_RGBA, R,2, G,2, B,2,      D,2, DB,       0 },
81    { GLX_RGBA, R,8, G,8, B,8, A,8, D,8,           0 }, /* rgba single */
82    { GLX_RGBA, R,8, G,8, B,8,      D,8,           0 }, /* rgb  single */
83    { GLX_RGBA, R,4, G,4, B,4,      D,4,           0 },
84    { GLX_RGBA, R,2, G,2, B,2,      D,2,           0 },
85    { I, 8,                         D,8, DB,       0 }, /* cmap double */
86    { I, 4,                         D,4, DB,       0 },
87    { I, 8,                         D,8,           0 }, /* cmap single */
88    { I, 4,                         D,4,           0 },
89    { GLX_RGBA, R,1, G,1, B,1,      D,1,           0 }  /* monochrome */
90   };
91
92   int i = 0;
93
94 # ifdef SB
95   if (! get_boolean_resource (dpy, "multiSample", "MultiSample"))
96     i = SB_COUNT;  /* skip over the multibuffer entries in 'attrs' */
97 # endif /* SB */
98
99   for (; i < sizeof(attrs)/sizeof(*attrs); i++)
100     {
101       XVisualInfo *vi = glXChooseVisual (dpy, screen_num, attrs[i]);
102       if (vi)
103         {
104           Visual *v = vi->visual;
105           XFree (vi);
106           /* describe_gl_visual (stderr, screen, v, False); */
107           return v;
108         }
109     }
110 #endif /* !HAVE_GL */
111
112   return 0;
113 }
114
115
116 void
117 describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
118                     Bool private_cmap_p)
119 {
120   describe_visual (f, screen, visual, private_cmap_p);
121
122 #ifdef HAVE_GL
123   {
124     int status;
125     int value = False;
126
127     Display *dpy = DisplayOfScreen (screen);
128     XVisualInfo vi_in, *vi_out;
129     int out_count;
130
131     vi_in.screen = screen_number (screen);
132     vi_in.visualid = XVisualIDFromVisual (visual);
133     vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
134                              &vi_in, &out_count);
135     if (! vi_out) abort ();
136
137     status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
138
139     if (status == GLX_NO_EXTENSION)
140       /* dpy does not support the GLX extension. */
141       return;
142
143     if (status == GLX_BAD_VISUAL || value == False)
144       /* this visual does not support GLX. */
145       return;
146     
147     if (!glXGetConfig (dpy, vi_out, GLX_LEVEL, &value) &&
148         value != 0)
149       printf ("    GLX level:         %d\n", value);
150
151     if (!glXGetConfig (dpy, vi_out, GLX_RGBA, &value) && value)
152       {
153         int r=0, g=0, b=0, a=0;
154         glXGetConfig (dpy, vi_out, GLX_RED_SIZE,   &r);
155         glXGetConfig (dpy, vi_out, GLX_GREEN_SIZE, &g);
156         glXGetConfig (dpy, vi_out, GLX_BLUE_SIZE,  &b);
157         glXGetConfig (dpy, vi_out, GLX_ALPHA_SIZE, &a);
158         printf ("    GLX type:          RGBA (%2d, %2d, %2d, %2d)\n",
159                 r, g, b, a);
160
161         r=0, g=0, b=0, a=0;
162         glXGetConfig (dpy, vi_out, GLX_ACCUM_RED_SIZE,   &r);
163         glXGetConfig (dpy, vi_out, GLX_ACCUM_GREEN_SIZE, &g);
164         glXGetConfig (dpy, vi_out, GLX_ACCUM_BLUE_SIZE,  &b);
165         glXGetConfig (dpy, vi_out, GLX_ACCUM_ALPHA_SIZE, &a);
166         printf ("    GLX accum:         RGBA (%2d, %2d, %2d, %2d)\n",
167                 r, g, b, a);
168       }
169     else
170       {
171         value = 0;
172         glXGetConfig (dpy, vi_out, GLX_BUFFER_SIZE, &value);
173         printf ("    GLX type:          indexed (%d)\n", value);
174       }
175
176 # ifndef  GLX_NONE_EXT       /* Hooray for gratuitious name changes. */
177 #  define GLX_NONE_EXT                    GLX_NONE
178 #  define GLX_TRANSPARENT_TYPE_EXT        GLX_TRANSPARENT_TYPE
179 #  define GLX_TRANSPARENT_INDEX_EXT       GLX_TRANSPARENT_INDEX
180 #  define GLX_TRANSPARENT_INDEX_VALUE_EXT GLX_TRANSPARENT_INDEX_VALUE
181 #  define GLX_TRANSPARENT_RGB_EXT         GLX_TRANSPARENT_RGB
182 #  define GLX_TRANSPARENT_RED_VALUE_EXT   GLX_TRANSPARENT_RED_VALUE
183 #  define GLX_TRANSPARENT_GREEN_VALUE_EXT GLX_TRANSPARENT_GREEN_VALUE
184 #  define GLX_TRANSPARENT_BLUE_VALUE_EXT  GLX_TRANSPARENT_BLUE_VALUE
185 #  define GLX_TRANSPARENT_ALPHA_VALUE_EXT GLX_TRANSPARENT_ALPHA_VALUE
186 # endif
187
188 # ifdef GLX_VISUAL_CAVEAT_EXT
189     if (!glXGetConfig (dpy, vi_out, GLX_VISUAL_CAVEAT_EXT, &value) &&
190         value != GLX_NONE_EXT)
191 #   ifdef GLX_NON_CONFORMANT_EXT
192       printf ("    GLX rating:        %s\n",
193               (value == GLX_NONE_EXT ? "none" :
194                value == GLX_SLOW_VISUAL_EXT ? "slow" :
195                value == GLX_NON_CONFORMANT_EXT ? "non-conformant" :
196                "???"));
197 #   else      
198       printf ("    GLX rating:        %s\n",
199               (value == GLX_NONE_EXT ? "none" :
200                value == GLX_SLOW_VISUAL_EXT ? "slow" :
201                "???"));
202 #   endif /* GLX_NON_CONFORMANT_EXT */
203 # endif /* GLX_VISUAL_CAVEAT_EXT */
204
205     if (!glXGetConfig (dpy, vi_out, GLX_DOUBLEBUFFER, &value))
206       printf ("    GLX double-buffer: %s\n", (value ? "yes" : "no"));
207
208     if (!glXGetConfig (dpy, vi_out, GLX_STEREO, &value) &&
209         value)
210       printf ("    GLX stereo:        %s\n", (value ? "yes" : "no"));
211
212     if (!glXGetConfig (dpy, vi_out, GLX_AUX_BUFFERS, &value) &&
213         value != 0)
214       printf ("    GLX aux buffers:   %d\n", value);
215
216     if (!glXGetConfig (dpy, vi_out, GLX_DEPTH_SIZE, &value))
217       printf ("    GLX depth size:    %d\n", value);
218
219     if (!glXGetConfig (dpy, vi_out, GLX_STENCIL_SIZE, &value) &&
220         value != 0)
221       printf ("    GLX stencil size:  %d\n", value);
222
223 # ifdef SB  /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */
224     if (!glXGetConfig (dpy, vi_out, SB, &value) &&
225         value != 0)
226       {
227         int bufs = value;
228         if (!glXGetConfig (dpy, vi_out, SM, &value))
229           printf ("    GLX multisample:   %d, %d\n", bufs, value);
230       }
231 # endif  /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */
232
233     if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_TYPE_EXT, &value) &&
234         value != GLX_NONE_EXT)
235       {
236         if (value == GLX_NONE_EXT)
237           printf ("    GLX transparency:  none\n");
238         else if (value == GLX_TRANSPARENT_INDEX_EXT)
239           {
240             if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_INDEX_VALUE_EXT,
241                                &value))
242               printf ("    GLX transparency:  indexed (%d)\n", value);
243           }
244         else if (value == GLX_TRANSPARENT_RGB_EXT)
245           {
246             int r=0, g=0, b=0, a=0;
247             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_RED_VALUE_EXT,   &r);
248             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_GREEN_VALUE_EXT, &g);
249             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_BLUE_VALUE_EXT,  &b);
250             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_ALPHA_VALUE_EXT, &a);
251             printf ("    GLX transparency:  RGBA (%2d, %2d, %2d, %2d)\n",
252                     r, g, b, a);
253           }
254       }
255   }
256 #endif  /* HAVE_GL */
257 }
258
259
260 Bool
261 validate_gl_visual (FILE *out, Screen *screen, const char *window_desc,
262                     Visual *visual)
263 {
264 #ifdef HAVE_GL
265   int status;
266   int value = False;
267
268   Display *dpy = DisplayOfScreen (screen);
269   XVisualInfo vi_in, *vi_out;
270   int out_count;
271   unsigned int id;
272
273   vi_in.screen = screen_number (screen);
274   vi_in.visualid = XVisualIDFromVisual (visual);
275   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
276                              &vi_in, &out_count);
277   if (! vi_out) abort ();
278
279   status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
280
281   id = (unsigned int) vi_out->visualid;
282   XFree ((char *) vi_out);
283
284   if (status == GLX_NO_EXTENSION)
285     {
286       fprintf (out, "%s: display \"%s\" does not support the GLX extension.\n",
287                progname, DisplayString (dpy));
288       return False;
289     }
290   else if (status == GLX_BAD_VISUAL || value == False)
291     {
292       fprintf (out,
293                "%s: %s's visual 0x%x does not support the GLX extension.\n",
294                progname, window_desc, id);
295       return False;
296     }
297   else
298     {
299       return True;
300     }
301
302 #else  /* !HAVE_GL */
303
304   fprintf (out, "%s: GL support was not compiled in to this program.\n",
305            progname);
306   return False;
307
308 #endif  /* !HAVE_GL */
309 }