3c8a7a8bd9357baeb437dee07e3500136ab406ef
[xscreensaver] / utils / visual-gl.c
1 /* xscreensaver, Copyright (c) 1999-2007 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 # ifdef GLX_VISUAL_CAVEAT_EXT
146     if (!glXGetConfig (dpy, vi_out, GLX_VISUAL_CAVEAT_EXT, &value) &&
147         value != GLX_NONE_EXT)
148 #   ifdef GLX_NON_CONFORMANT_EXT
149       printf ("    GLX rating:        %s\n",
150               (value == GLX_NONE_EXT ? "none" :
151                value == GLX_SLOW_VISUAL_EXT ? "slow" :
152                value == GLX_NON_CONFORMANT_EXT ? "non-conformant" :
153                "???"));
154 #   else      
155       printf ("    GLX rating:        %s\n",
156               (value == GLX_NONE_EXT ? "none" :
157                value == GLX_SLOW_VISUAL_EXT ? "slow" :
158                "???"));
159 #   endif /* GLX_NON_CONFORMANT_EXT */
160 # endif /* GLX_VISUAL_CAVEAT_EXT */
161
162     if (!glXGetConfig (dpy, vi_out, GLX_DOUBLEBUFFER, &value))
163       printf ("    GLX double-buffer: %s\n", (value ? "yes" : "no"));
164
165     if (!glXGetConfig (dpy, vi_out, GLX_STEREO, &value) &&
166         value)
167       printf ("    GLX stereo:        %s\n", (value ? "yes" : "no"));
168
169     if (!glXGetConfig (dpy, vi_out, GLX_AUX_BUFFERS, &value) &&
170         value != 0)
171       printf ("    GLX aux buffers:   %d\n", value);
172
173     if (!glXGetConfig (dpy, vi_out, GLX_DEPTH_SIZE, &value))
174       printf ("    GLX depth size:    %d\n", value);
175
176     if (!glXGetConfig (dpy, vi_out, GLX_STENCIL_SIZE, &value) &&
177         value != 0)
178       printf ("    GLX stencil size:  %d\n", value);
179
180 # ifdef GLX_SAMPLE_BUFFERS_SGIS
181     if (!glXGetConfig (dpy, vi_out, GLX_SAMPLE_BUFFERS_SGIS, &value) &&
182         value != 0)
183       {
184         int bufs = value;
185         if (!glXGetConfig (dpy, vi_out, GLX_SAMPLES_SGIS, &value))
186           printf ("    GLX multisamplers: %d (%d)\n", bufs, value);
187       }
188 # endif /* GLX_SAMPLE_BUFFERS_SGIS */
189
190     if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_TYPE_EXT, &value) &&
191         value != GLX_NONE_EXT)
192       {
193         if (value == GLX_NONE_EXT)
194           printf ("    GLX transparency:  none\n");
195         else if (value == GLX_TRANSPARENT_INDEX_EXT)
196           {
197             if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_INDEX_VALUE_EXT,
198                                &value))
199               printf ("    GLX transparency:  indexed (%d)\n", value);
200           }
201         else if (value == GLX_TRANSPARENT_RGB_EXT)
202           {
203             int r=0, g=0, b=0, a=0;
204             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_RED_VALUE_EXT,   &r);
205             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_GREEN_VALUE_EXT, &g);
206             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_BLUE_VALUE_EXT,  &b);
207             glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_ALPHA_VALUE_EXT, &a);
208             printf ("    GLX transparency:  RGBA (%2d, %2d, %2d, %2d)\n",
209                     r, g, b, a);
210           }
211       }
212   }
213 #endif  /* HAVE_GL */
214 }
215
216
217 Bool
218 validate_gl_visual (FILE *out, Screen *screen, const char *window_desc,
219                     Visual *visual)
220 {
221 #ifdef HAVE_GL
222   int status;
223   int value = False;
224
225   Display *dpy = DisplayOfScreen (screen);
226   XVisualInfo vi_in, *vi_out;
227   int out_count;
228   unsigned int id;
229
230   vi_in.screen = screen_number (screen);
231   vi_in.visualid = XVisualIDFromVisual (visual);
232   vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
233                              &vi_in, &out_count);
234   if (! vi_out) abort ();
235
236   status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
237
238   id = (unsigned int) vi_out->visualid;
239   XFree ((char *) vi_out);
240
241   if (status == GLX_NO_EXTENSION)
242     {
243       fprintf (out, "%s: display \"%s\" does not support the GLX extension.\n",
244                progname, DisplayString (dpy));
245       return False;
246     }
247   else if (status == GLX_BAD_VISUAL || value == False)
248     {
249       fprintf (out,
250                "%s: %s's visual 0x%x does not support the GLX extension.\n",
251                progname, window_desc, id);
252       return False;
253     }
254   else
255     {
256       return True;
257     }
258
259 #else  /* !HAVE_GL */
260
261   fprintf (out, "%s: GL support was not compiled in to this program.\n",
262            progname);
263   return False;
264
265 #endif  /* !HAVE_GL */
266 }