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