glxinfo.c revision 7ec3b29a
1/*
2 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22
23/*
24 * This program is a work-alike of the IRIX glxinfo program.
25 * Command line options:
26 *  -t                     print wide table
27 *  -v                     print verbose information
28 *  -display DisplayName   specify the X display to interogate
29 *  -B                     brief, print only the basics
30 *  -b                     only print ID of "best" visual on screen 0
31 *  -i                     use indirect rendering connection only
32 *  -l                     print interesting OpenGL limits (added 5 Sep 2002)
33 *
34 * Brian Paul  26 January 2000
35 */
36
37#define GLX_GLXEXT_PROTOTYPES
38#define GL_GLEXT_PROTOTYPES
39
40#include <assert.h>
41#include <X11/Xlib.h>
42#include <X11/Xutil.h>
43#include <GL/gl.h>
44#include <GL/glx.h>
45#include <stdio.h>
46#include <string.h>
47#include <stdlib.h>
48#include "glinfo_common.h"
49
50
51#ifndef GLX_NONE_EXT
52#define GLX_NONE_EXT  0x8000
53#endif
54
55#ifndef GLX_TRANSPARENT_RGB
56#define GLX_TRANSPARENT_RGB 0x8008
57#endif
58
59#ifndef GLX_RGBA_BIT
60#define GLX_RGBA_BIT			0x00000001
61#endif
62
63#ifndef GLX_COLOR_INDEX_BIT
64#define GLX_COLOR_INDEX_BIT		0x00000002
65#endif
66
67
68struct visual_attribs
69{
70   /* X visual attribs */
71   int id;		/* May be visual ID or FBConfig ID */
72   int vis_id;		/* Visual ID.  Only set for FBConfigs */
73   int klass;
74   int depth;
75   int redMask, greenMask, blueMask;
76   int colormapSize;
77   int bitsPerRGB;
78
79   /* GL visual attribs */
80   int supportsGL;
81   int drawableType;
82   int transparentType;
83   int transparentRedValue;
84   int transparentGreenValue;
85   int transparentBlueValue;
86   int transparentAlphaValue;
87   int transparentIndexValue;
88   int bufferSize;
89   int level;
90   int render_type;
91   int doubleBuffer;
92   int stereo;
93   int auxBuffers;
94   int redSize, greenSize, blueSize, alphaSize;
95   int depthSize;
96   int stencilSize;
97   int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
98   int numSamples, numMultisample;
99   int visualCaveat;
100   int floatComponents;
101   int packedfloatComponents;
102   int srgb;
103};
104
105
106/**
107 * Version of the context that was created
108 *
109 * 20, 21, 30, 31, 32, etc.
110 */
111static int version;
112
113/**
114 * GL Error checking/warning.
115 */
116static void
117CheckError(int line)
118{
119   int n;
120   n = glGetError();
121   if (n)
122      printf("Warning: GL error 0x%x at line %d\n", n, line);
123}
124
125
126static void
127print_display_info(Display *dpy)
128{
129   printf("name of display: %s\n", DisplayString(dpy));
130}
131
132
133/**
134 * Choose a simple FB Config.
135 */
136static GLXFBConfig *
137choose_fb_config(Display *dpy, int scrnum)
138{
139   int fbAttribSingle[] = {
140      GLX_RENDER_TYPE,   GLX_RGBA_BIT,
141      GLX_RED_SIZE,      1,
142      GLX_GREEN_SIZE,    1,
143      GLX_BLUE_SIZE,     1,
144      GLX_DOUBLEBUFFER,  False,
145      None };
146   int fbAttribDouble[] = {
147      GLX_RENDER_TYPE,   GLX_RGBA_BIT,
148      GLX_RED_SIZE,      1,
149      GLX_GREEN_SIZE,    1,
150      GLX_BLUE_SIZE,     1,
151      GLX_DOUBLEBUFFER,  True,
152      None };
153   GLXFBConfig *configs;
154   int nConfigs;
155
156   configs = glXChooseFBConfig(dpy, scrnum, fbAttribSingle, &nConfigs);
157   if (!configs)
158      configs = glXChooseFBConfig(dpy, scrnum, fbAttribDouble, &nConfigs);
159
160   return configs;
161}
162
163
164static Bool CreateContextErrorFlag;
165
166static int
167create_context_error_handler(Display *dpy, XErrorEvent *error)
168{
169   (void) dpy;
170   (void) error->error_code;
171   CreateContextErrorFlag = True;
172   return 0;
173}
174
175
176/**
177 * Try to create a GLX context of the given version with flags/options.
178 * Note: A version number is required in order to get a core profile
179 * (at least w/ NVIDIA).
180 */
181static GLXContext
182create_context_flags(Display *dpy, GLXFBConfig fbconfig, int major, int minor,
183                     int contextFlags, int profileMask, Bool direct)
184{
185#ifdef GLX_ARB_create_context
186   static PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB_func = 0;
187   static Bool firstCall = True;
188   int (*old_handler)(Display *, XErrorEvent *);
189   GLXContext context;
190   int attribs[20];
191   int n = 0;
192
193   if (firstCall) {
194      /* See if we have GLX_ARB_create_context_profile and get pointer to
195       * glXCreateContextAttribsARB() function.
196       */
197      const char *glxExt = glXQueryExtensionsString(dpy, 0);
198      if (extension_supported("GLX_ARB_create_context_profile", glxExt)) {
199         glXCreateContextAttribsARB_func = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
200            glXGetProcAddress((const GLubyte *) "glXCreateContextAttribsARB");
201      }
202      firstCall = False;
203   }
204
205   if (!glXCreateContextAttribsARB_func)
206      return 0;
207
208   /* setup attribute array */
209   if (major) {
210      attribs[n++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
211      attribs[n++] = major;
212      attribs[n++] = GLX_CONTEXT_MINOR_VERSION_ARB;
213      attribs[n++] = minor;
214   }
215   if (contextFlags) {
216      attribs[n++] = GLX_CONTEXT_FLAGS_ARB;
217      attribs[n++] = contextFlags;
218   }
219#ifdef GLX_ARB_create_context_profile
220   if (profileMask) {
221      attribs[n++] = GLX_CONTEXT_PROFILE_MASK_ARB;
222      attribs[n++] = profileMask;
223   }
224#endif
225   attribs[n++] = 0;
226
227   /* install X error handler */
228   old_handler = XSetErrorHandler(create_context_error_handler);
229   CreateContextErrorFlag = False;
230
231   /* try creating context */
232   context = glXCreateContextAttribsARB_func(dpy,
233                                             fbconfig,
234                                             0, /* share_context */
235                                             direct,
236                                             attribs);
237
238   /* restore error handler */
239   XSetErrorHandler(old_handler);
240
241   if (CreateContextErrorFlag)
242      context = 0;
243
244   if (context && direct) {
245      if (!glXIsDirect(dpy, context)) {
246         glXDestroyContext(dpy, context);
247         return 0;
248      }
249   }
250
251   return context;
252#else
253   return 0;
254#endif
255}
256
257
258/**
259 * Try to create a GLX context of the newest version.
260 */
261static GLXContext
262create_context_with_config(Display *dpy, GLXFBConfig config,
263                           Bool coreProfile, Bool es2Profile, Bool direct)
264{
265   GLXContext ctx = 0;
266
267   if (coreProfile) {
268      /* Try to create a core profile, starting with the newest version of
269       * GL that we're aware of.  If we don't specify the version
270       */
271      int i;
272      for (i = 0; gl_versions[i].major > 0; i++) {
273          /* don't bother below GL 3.0 */
274          if (gl_versions[i].major == 3 &&
275              gl_versions[i].minor == 0)
276             return 0;
277         ctx = create_context_flags(dpy, config,
278                                    gl_versions[i].major,
279                                    gl_versions[i].minor,
280                                    0x0,
281                                    GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
282                                    direct);
283         if (ctx)
284            return ctx;
285      }
286      /* couldn't get core profile context */
287      return 0;
288   }
289
290   if (es2Profile) {
291#ifdef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
292      if (extension_supported("GLX_EXT_create_context_es2_profile",
293                              glXQueryExtensionsString(dpy, 0))) {
294         ctx = create_context_flags(dpy, config, 2, 0, 0x0,
295                                    GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
296                                    direct);
297         return ctx;
298      }
299#endif
300      return 0;
301   }
302
303   /* GLX should return a context of the latest GL version that supports
304    * the full profile.
305    */
306   ctx = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, direct);
307
308   /* make sure the context is direct, if direct was requested */
309   if (ctx && direct) {
310      if (!glXIsDirect(dpy, ctx)) {
311         glXDestroyContext(dpy, ctx);
312         return 0;
313      }
314   }
315
316   return ctx;
317}
318
319
320static XVisualInfo *
321choose_xvisinfo(Display *dpy, int scrnum)
322{
323   int attribSingle[] = {
324      GLX_RGBA,
325      GLX_RED_SIZE, 1,
326      GLX_GREEN_SIZE, 1,
327      GLX_BLUE_SIZE, 1,
328      None };
329   int attribDouble[] = {
330      GLX_RGBA,
331      GLX_RED_SIZE, 1,
332      GLX_GREEN_SIZE, 1,
333      GLX_BLUE_SIZE, 1,
334      GLX_DOUBLEBUFFER,
335      None };
336   XVisualInfo *visinfo;
337
338   visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
339   if (!visinfo)
340      visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
341
342   return visinfo;
343}
344
345
346static void
347query_renderer(void)
348{
349#ifdef GLX_MESA_query_renderer
350    PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC queryInteger;
351    PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC queryString;
352    unsigned int v[3];
353
354    queryInteger = (PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC)
355	glXGetProcAddressARB((const GLubyte *)
356			     "glXQueryCurrentRendererIntegerMESA");
357    queryString = (PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC)
358	glXGetProcAddressARB((const GLubyte *)
359			     "glXQueryCurrentRendererStringMESA");
360
361    printf("Extended renderer info (GLX_MESA_query_renderer):\n");
362    queryInteger(GLX_RENDERER_VENDOR_ID_MESA, v);
363    printf("    Vendor: %s (0x%x)\n",
364	   queryString(GLX_RENDERER_VENDOR_ID_MESA), *v);
365    queryInteger(GLX_RENDERER_DEVICE_ID_MESA, v);
366    printf("    Device: %s (0x%x)\n",
367	   queryString(GLX_RENDERER_DEVICE_ID_MESA), *v);
368    queryInteger(GLX_RENDERER_VERSION_MESA, v);
369    printf("    Version: %d.%d.%d\n", v[0], v[1], v[2]);
370    queryInteger(GLX_RENDERER_ACCELERATED_MESA, v);
371    printf("    Accelerated: %s\n", *v ? "yes" : "no");
372    queryInteger(GLX_RENDERER_VIDEO_MEMORY_MESA, v);
373    printf("    Video memory: %dMB\n", *v);
374    queryInteger(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA, v);
375    printf("    Unified memory: %s\n", *v ? "yes" : "no");
376    queryInteger(GLX_RENDERER_PREFERRED_PROFILE_MESA, v);
377    printf("    Preferred profile: %s (0x%x)\n",
378	   *v == GLX_CONTEXT_CORE_PROFILE_BIT_ARB ? "core" :
379	   *v == GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ? "compat" :
380	   "unknown", *v);
381    queryInteger(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA, v);
382    printf("    Max core profile version: %d.%d\n", v[0], v[1]);
383    queryInteger(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA, v);
384    printf("    Max compat profile version: %d.%d\n", v[0], v[1]);
385    queryInteger(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA, v);
386    printf("    Max GLES1 profile version: %d.%d\n", v[0], v[1]);
387    queryInteger(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA, v);
388    printf("    Max GLES[23] profile version: %d.%d\n", v[0], v[1]);
389#endif
390}
391
392
393static Bool
394print_screen_info(Display *dpy, int scrnum,
395                  const struct options *opts,
396                  Bool coreProfile, Bool es2Profile, Bool limits,
397                  Bool coreWorked)
398{
399   Window win;
400   XSetWindowAttributes attr;
401   unsigned long mask;
402   Window root;
403   GLXContext ctx = NULL;
404   XVisualInfo *visinfo;
405   int width = 100, height = 100;
406   GLXFBConfig *fbconfigs;
407   const char *oglstring = coreProfile ? "OpenGL core profile" :
408                           es2Profile ? "OpenGL ES profile" : "OpenGL";
409
410   root = RootWindow(dpy, scrnum);
411
412   /*
413    * Choose FBConfig or XVisualInfo and create a context.
414    */
415   fbconfigs = choose_fb_config(dpy, scrnum);
416   if (fbconfigs) {
417      ctx = create_context_with_config(dpy, fbconfigs[0],
418                                       coreProfile, es2Profile,
419                                       opts->allowDirect);
420      if (!ctx && opts->allowDirect && !coreProfile) {
421         /* try indirect */
422         ctx = create_context_with_config(dpy, fbconfigs[0],
423                                          coreProfile, es2Profile, False);
424      }
425
426      visinfo = glXGetVisualFromFBConfig(dpy, fbconfigs[0]);
427      XFree(fbconfigs);
428   }
429   else if (!coreProfile && !es2Profile) {
430      visinfo = choose_xvisinfo(dpy, scrnum);
431      if (visinfo)
432	 ctx = glXCreateContext(dpy, visinfo, NULL, opts->allowDirect);
433   } else
434      visinfo = NULL;
435
436   if (!visinfo && !coreProfile && !es2Profile) {
437      fprintf(stderr, "Error: couldn't find RGB GLX visual or fbconfig\n");
438      return False;
439   }
440
441   if (!ctx) {
442      if (!coreProfile && !es2Profile)
443	 fprintf(stderr, "Error: glXCreateContext failed\n");
444      XFree(visinfo);
445      return False;
446   }
447
448   /*
449    * Create a window so that we can just bind the context.
450    */
451   attr.background_pixel = 0;
452   attr.border_pixel = 0;
453   attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
454   attr.event_mask = StructureNotifyMask | ExposureMask;
455   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
456   win = XCreateWindow(dpy, root, 0, 0, width, height,
457		       0, visinfo->depth, InputOutput,
458		       visinfo->visual, mask, &attr);
459
460   if (glXMakeCurrent(dpy, win, ctx)) {
461      const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR);
462      const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION);
463      const char *serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS);
464      const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR);
465      const char *clientVersion = glXGetClientString(dpy, GLX_VERSION);
466      const char *clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS);
467      const char *glxExtensions = glXQueryExtensionsString(dpy, scrnum);
468      const char *glVendor = (const char *) glGetString(GL_VENDOR);
469      const char *glRenderer = (const char *) glGetString(GL_RENDERER);
470      const char *glVersion = (const char *) glGetString(GL_VERSION);
471      char *glExtensions = NULL;
472      int glxVersionMajor = 0;
473      int glxVersionMinor = 0;
474      char *displayName = NULL;
475      char *colon = NULL, *period = NULL;
476      struct ext_functions extfuncs;
477
478      CheckError(__LINE__);
479
480      /* Get some ext functions */
481      extfuncs.GetProgramivARB = (GETPROGRAMIVARBPROC)
482         glXGetProcAddressARB((GLubyte *) "glGetProgramivARB");
483      extfuncs.GetStringi = (GETSTRINGIPROC)
484         glXGetProcAddressARB((GLubyte *) "glGetStringi");
485      extfuncs.GetConvolutionParameteriv = (GETCONVOLUTIONPARAMETERIVPROC)
486         glXGetProcAddressARB((GLubyte *) "glGetConvolutionParameteriv");
487
488      if (!glXQueryVersion(dpy, & glxVersionMajor, & glxVersionMinor)) {
489         fprintf(stderr, "Error: glXQueryVersion failed\n");
490         exit(1);
491      }
492
493      /* Get list of GL extensions */
494      if (coreProfile && extfuncs.GetStringi)
495         glExtensions = build_core_profile_extension_list(&extfuncs);
496      if (!glExtensions) {
497         coreProfile = False;
498         glExtensions = (char *) glGetString(GL_EXTENSIONS);
499      }
500
501      CheckError(__LINE__);
502
503      if (!coreWorked) {
504         /* Strip the screen number from the display name, if present. */
505         if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1))) {
506            fprintf(stderr, "Error: malloc() failed\n");
507            exit(1);
508         }
509         strcpy(displayName, DisplayString(dpy));
510         colon = strrchr(displayName, ':');
511         if (colon) {
512            period = strchr(colon, '.');
513            if (period)
514               *period = '\0';
515         }
516
517         printf("display: %s  screen: %d\n", displayName, scrnum);
518         free(displayName);
519         printf("direct rendering: ");
520         if (glXIsDirect(dpy, ctx)) {
521            printf("Yes\n");
522         }
523         else {
524            if (!opts->allowDirect) {
525               printf("No (-i specified)\n");
526            }
527            else if (getenv("LIBGL_ALWAYS_INDIRECT")) {
528               printf("No (LIBGL_ALWAYS_INDIRECT set)\n");
529            }
530            else {
531               printf("No (If you want to find out why, try setting "
532                      "LIBGL_DEBUG=verbose)\n");
533            }
534         }
535         if (opts->mode != Brief) {
536            printf("server glx vendor string: %s\n", serverVendor);
537            printf("server glx version string: %s\n", serverVersion);
538            printf("server glx extensions:\n");
539            print_extension_list(serverExtensions, opts->singleLine);
540            printf("client glx vendor string: %s\n", clientVendor);
541            printf("client glx version string: %s\n", clientVersion);
542            printf("client glx extensions:\n");
543            print_extension_list(clientExtensions, opts->singleLine);
544            printf("GLX version: %u.%u\n", glxVersionMajor, glxVersionMinor);
545            printf("GLX extensions:\n");
546            print_extension_list(glxExtensions, opts->singleLine);
547         }
548         if (strstr(glxExtensions, "GLX_MESA_query_renderer"))
549	    query_renderer();
550         print_gpu_memory_info(glExtensions);
551         printf("OpenGL vendor string: %s\n", glVendor);
552         printf("OpenGL renderer string: %s\n", glRenderer);
553      } else
554         printf("\n");
555
556      printf("%s version string: %s\n", oglstring, glVersion);
557
558      version = (glVersion[0] - '0') * 10 + (glVersion[2] - '0');
559
560      CheckError(__LINE__);
561
562#ifdef GL_VERSION_2_0
563      if (version >= 20) {
564         char *v = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
565         printf("%s shading language version string: %s\n", oglstring, v);
566      }
567#endif
568      CheckError(__LINE__);
569#ifdef GL_VERSION_3_0
570      if (version >= 30 && !es2Profile) {
571         GLint flags;
572         glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
573         printf("%s context flags: %s\n", oglstring, context_flags_string(flags));
574      }
575#endif
576      CheckError(__LINE__);
577#ifdef GL_VERSION_3_2
578      if (version >= 32 && !es2Profile) {
579         GLint mask;
580         glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
581         printf("%s profile mask: %s\n", oglstring, profile_mask_string(mask));
582      }
583#endif
584
585      CheckError(__LINE__);
586
587      if (opts->mode != Brief) {
588         printf("%s extensions:\n", oglstring);
589         print_extension_list(glExtensions, opts->singleLine);
590      }
591
592      if (limits) {
593         print_limits(glExtensions, oglstring, version, &extfuncs);
594      }
595
596      if (coreProfile)
597         free(glExtensions);
598   }
599   else {
600      fprintf(stderr, "Error: glXMakeCurrent failed\n");
601   }
602
603   glXDestroyContext(dpy, ctx);
604   XFree(visinfo);
605   XDestroyWindow(dpy, win);
606   XSync(dpy, 1);
607   return True;
608}
609
610
611static const char *
612visual_class_name(int cls)
613{
614   switch (cls) {
615      case StaticColor:
616         return "StaticColor";
617      case PseudoColor:
618         return "PseudoColor";
619      case StaticGray:
620         return "StaticGray";
621      case GrayScale:
622         return "GrayScale";
623      case TrueColor:
624         return "TrueColor";
625      case DirectColor:
626         return "DirectColor";
627      default:
628         return "";
629   }
630}
631
632static const char *
633visual_drawable_type(int type)
634{
635   const static struct bit_info bits[] = {
636      { GLX_WINDOW_BIT, "window" },
637      { GLX_PIXMAP_BIT, "pixmap" },
638      { GLX_PBUFFER_BIT, "pbuffer" }
639   };
640
641   return bitmask_to_string(bits, ELEMENTS(bits), type);
642}
643
644static const char *
645visual_class_abbrev(int cls)
646{
647   switch (cls) {
648      case StaticColor:
649         return "sc";
650      case PseudoColor:
651         return "pc";
652      case StaticGray:
653         return "sg";
654      case GrayScale:
655         return "gs";
656      case TrueColor:
657         return "tc";
658      case DirectColor:
659         return "dc";
660      default:
661         return "";
662   }
663}
664
665static const char *
666visual_render_type_name(int type)
667{
668   switch (type) {
669      case GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT:
670         return "ufloat";
671      case GLX_RGBA_FLOAT_BIT_ARB:
672         return "float";
673      case GLX_RGBA_BIT:
674         return "rgba";
675      case GLX_COLOR_INDEX_BIT:
676         return "ci";
677      case GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT:
678         return "rgba|ci";
679      default:
680         return "";
681   }
682}
683
684static const char *
685caveat_string(int caveat)
686{
687   switch (caveat) {
688#ifdef GLX_EXT_visual_rating
689      case GLX_SLOW_VISUAL_EXT:
690         return "Slow";
691      case GLX_NON_CONFORMANT_VISUAL_EXT:
692         return "Ncon";
693      case GLX_NONE_EXT:
694         /* fall-through */
695#endif
696      case 0:
697         /* fall-through */
698      default:
699         return "None";
700   }
701}
702
703
704static Bool
705get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
706                   struct visual_attribs *attribs)
707{
708   const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
709   int rgba;
710
711   memset(attribs, 0, sizeof(struct visual_attribs));
712
713   attribs->id = vInfo->visualid;
714#if defined(__cplusplus) || defined(c_plusplus)
715   attribs->klass = vInfo->c_class;
716#else
717   attribs->klass = vInfo->class;
718#endif
719   attribs->depth = vInfo->depth;
720   attribs->redMask = vInfo->red_mask;
721   attribs->greenMask = vInfo->green_mask;
722   attribs->blueMask = vInfo->blue_mask;
723   attribs->colormapSize = vInfo->colormap_size;
724   attribs->bitsPerRGB = vInfo->bits_per_rgb;
725
726   if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0 ||
727       !attribs->supportsGL)
728      return False;
729   glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
730   glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
731   glXGetConfig(dpy, vInfo, GLX_RGBA, &rgba);
732   if (rgba)
733      attribs->render_type = GLX_RGBA_BIT;
734   else
735      attribs->render_type = GLX_COLOR_INDEX_BIT;
736
737   glXGetConfig(dpy, vInfo, GLX_DRAWABLE_TYPE, &attribs->drawableType);
738   glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
739   glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
740   glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
741   glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
742   glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
743   glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
744   glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
745   glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
746   glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
747   glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
748   glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
749   glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
750   glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
751
752   /* get transparent pixel stuff */
753   glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
754   if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
755     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
756     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
757     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
758     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
759   }
760   else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
761     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
762   }
763
764   /* multisample attribs */
765#ifdef GLX_ARB_multisample
766   if (ext && strstr(ext, "GLX_ARB_multisample")) {
767      glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample);
768      glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples);
769   }
770#endif
771   else {
772      attribs->numSamples = 0;
773      attribs->numMultisample = 0;
774   }
775
776#if defined(GLX_EXT_visual_rating)
777   if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
778      glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
779   }
780   else {
781      attribs->visualCaveat = GLX_NONE_EXT;
782   }
783#else
784   attribs->visualCaveat = 0;
785#endif
786
787#if defined(GLX_EXT_framebuffer_sRGB)
788   if (ext && strstr(ext, "GLX_EXT_framebuffer_sRGB")) {
789      glXGetConfig(dpy, vInfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, &attribs->srgb);
790   }
791#endif
792
793   return True;
794}
795
796#ifdef GLX_VERSION_1_3
797
798static int
799glx_token_to_visual_class(int visual_type)
800{
801   switch (visual_type) {
802   case GLX_TRUE_COLOR:
803      return TrueColor;
804   case GLX_DIRECT_COLOR:
805      return DirectColor;
806   case GLX_PSEUDO_COLOR:
807      return PseudoColor;
808   case GLX_STATIC_COLOR:
809      return StaticColor;
810   case GLX_GRAY_SCALE:
811      return GrayScale;
812   case GLX_STATIC_GRAY:
813      return StaticGray;
814   case GLX_NONE:
815   default:
816      return None;
817   }
818}
819
820static Bool
821get_fbconfig_attribs(Display *dpy, GLXFBConfig fbconfig,
822		     struct visual_attribs *attribs)
823{
824   const char *ext = glXQueryExtensionsString(dpy, 0);
825   int visual_type;
826   XVisualInfo *vInfo;
827
828   memset(attribs, 0, sizeof(struct visual_attribs));
829
830   glXGetFBConfigAttrib(dpy, fbconfig, GLX_FBCONFIG_ID, &attribs->id);
831
832   vInfo = glXGetVisualFromFBConfig(dpy, fbconfig);
833
834   if (vInfo != NULL) {
835      attribs->vis_id = vInfo->visualid;
836      attribs->depth = vInfo->depth;
837      attribs->redMask = vInfo->red_mask;
838      attribs->greenMask = vInfo->green_mask;
839      attribs->blueMask = vInfo->blue_mask;
840      attribs->colormapSize = vInfo->colormap_size;
841      attribs->bitsPerRGB = vInfo->bits_per_rgb;
842   }
843
844   glXGetFBConfigAttrib(dpy, fbconfig, GLX_X_VISUAL_TYPE, &visual_type);
845   attribs->klass = glx_token_to_visual_class(visual_type);
846
847   glXGetFBConfigAttrib(dpy, fbconfig, GLX_DRAWABLE_TYPE, &attribs->drawableType);
848   glXGetFBConfigAttrib(dpy, fbconfig, GLX_BUFFER_SIZE, &attribs->bufferSize);
849   glXGetFBConfigAttrib(dpy, fbconfig, GLX_LEVEL, &attribs->level);
850   glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &attribs->render_type);
851   glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
852   glXGetFBConfigAttrib(dpy, fbconfig, GLX_STEREO, &attribs->stereo);
853   glXGetFBConfigAttrib(dpy, fbconfig, GLX_AUX_BUFFERS, &attribs->auxBuffers);
854
855   glXGetFBConfigAttrib(dpy, fbconfig, GLX_RED_SIZE, &attribs->redSize);
856   glXGetFBConfigAttrib(dpy, fbconfig, GLX_GREEN_SIZE, &attribs->greenSize);
857   glXGetFBConfigAttrib(dpy, fbconfig, GLX_BLUE_SIZE, &attribs->blueSize);
858   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ALPHA_SIZE, &attribs->alphaSize);
859   glXGetFBConfigAttrib(dpy, fbconfig, GLX_DEPTH_SIZE, &attribs->depthSize);
860   glXGetFBConfigAttrib(dpy, fbconfig, GLX_STENCIL_SIZE, &attribs->stencilSize);
861
862   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
863   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
864   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
865   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
866
867   /* get transparent pixel stuff */
868   glXGetFBConfigAttrib(dpy, fbconfig,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
869   if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
870     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
871     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
872     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
873     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
874   }
875   else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
876     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
877   }
878
879   glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLE_BUFFERS, &attribs->numMultisample);
880   glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLES, &attribs->numSamples);
881   glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &attribs->visualCaveat);
882
883#if defined(GLX_NV_float_buffer)
884   if (ext && strstr(ext, "GLX_NV_float_buffer")) {
885      glXGetFBConfigAttrib(dpy, fbconfig, GLX_FLOAT_COMPONENTS_NV, &attribs->floatComponents);
886   }
887#endif
888#if defined(GLX_ARB_fbconfig_float)
889   if (ext && strstr(ext, "GLX_ARB_fbconfig_float")) {
890      if (attribs->render_type & GLX_RGBA_FLOAT_BIT_ARB) {
891         attribs->floatComponents = True;
892      }
893   }
894#endif
895#if defined(GLX_EXT_fbconfig_packed_float)
896   if (ext && strstr(ext, "GLX_EXT_fbconfig_packed_float")) {
897      if (attribs->render_type & GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT) {
898         attribs->packedfloatComponents = True;
899      }
900   }
901#endif
902
903#if defined(GLX_EXT_framebuffer_sRGB)
904   if (ext && strstr(ext, "GLX_EXT_framebuffer_sRGB")) {
905      glXGetFBConfigAttrib(dpy, fbconfig, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, &attribs->srgb);
906   }
907#endif
908   return True;
909}
910
911#endif
912
913
914
915static void
916print_visual_attribs_verbose(const struct visual_attribs *attribs,
917			     int fbconfigs)
918{
919   if (fbconfigs) {
920      printf("FBConfig ID: %x  Visual ID=%x  depth=%d  class=%s, type=%s\n",
921             attribs->id, attribs->vis_id, attribs->depth,
922             visual_class_name(attribs->klass),
923             visual_drawable_type(attribs->drawableType));
924   }
925   else {
926      printf("Visual ID: %x  depth=%d  class=%s, type=%s\n",
927	     attribs->id, attribs->depth, visual_class_name(attribs->klass),
928	     visual_drawable_type(attribs->drawableType));
929   }
930   printf("    bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n",
931          attribs->bufferSize, attribs->level,
932	  visual_render_type_name(attribs->render_type),
933          attribs->doubleBuffer, attribs->stereo);
934   printf("    rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d float=%c sRGB=%c\n",
935          attribs->redSize, attribs->greenSize,
936          attribs->blueSize, attribs->alphaSize,
937          attribs->packedfloatComponents ? 'P' : attribs->floatComponents ? 'Y' : 'N',
938          attribs->srgb ? 'Y' : 'N');
939   printf("    auxBuffers=%d depthSize=%d stencilSize=%d\n",
940          attribs->auxBuffers, attribs->depthSize, attribs->stencilSize);
941   printf("    accum: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
942          attribs->accumRedSize, attribs->accumGreenSize,
943          attribs->accumBlueSize, attribs->accumAlphaSize);
944   printf("    multiSample=%d  multiSampleBuffers=%d\n",
945          attribs->numSamples, attribs->numMultisample);
946#ifdef GLX_EXT_visual_rating
947   if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
948      printf("    visualCaveat=None\n");
949   else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
950      printf("    visualCaveat=Slow\n");
951   else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
952      printf("    visualCaveat=Nonconformant\n");
953#endif
954   if (attribs->transparentType == GLX_NONE) {
955     printf("    Opaque.\n");
956   }
957   else if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
958     printf("    Transparent RGB: Red=%d Green=%d Blue=%d Alpha=%d\n",attribs->transparentRedValue,attribs->transparentGreenValue,attribs->transparentBlueValue,attribs->transparentAlphaValue);
959   }
960   else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
961     printf("    Transparent index=%d\n",attribs->transparentIndexValue);
962   }
963}
964
965
966static void
967print_visual_attribs_short_header(void)
968{
969 printf("    visual  x   bf lv rg d st  colorbuffer  sr ax dp st accumbuffer  ms  cav\n");
970 printf("  id dep cl sp  sz l  ci b ro  r  g  b  a F gb bf th cl  r  g  b  a ns b eat\n");
971 printf("----------------------------------------------------------------------------\n");
972}
973
974
975static void
976print_visual_attribs_short(const struct visual_attribs *attribs)
977{
978   const char *caveat = caveat_string(attribs->visualCaveat);
979
980   printf("0x%03x %2d %2s %2d %3d %2d %c%c %c %c  %2d %2d %2d %2d %c  %c %2d %2d %2d",
981          attribs->id,
982          attribs->depth,
983          visual_class_abbrev(attribs->klass),
984          attribs->transparentType != GLX_NONE,
985          attribs->bufferSize,
986          attribs->level,
987          (attribs->render_type & GLX_RGBA_BIT) ? 'r' : ' ',
988          (attribs->render_type & GLX_COLOR_INDEX_BIT) ? 'c' : ' ',
989          attribs->doubleBuffer ? 'y' : '.',
990          attribs->stereo ? 'y' : '.',
991          attribs->redSize, attribs->greenSize,
992          attribs->blueSize, attribs->alphaSize,
993          attribs->packedfloatComponents ? 'u' : attribs->floatComponents ? 'f' : '.',
994          attribs->srgb ? 's' : '.',
995          attribs->auxBuffers,
996          attribs->depthSize,
997          attribs->stencilSize
998          );
999
1000   printf(" %2d %2d %2d %2d %2d %1d %s\n",
1001          attribs->accumRedSize, attribs->accumGreenSize,
1002          attribs->accumBlueSize, attribs->accumAlphaSize,
1003          attribs->numSamples, attribs->numMultisample,
1004          caveat
1005          );
1006}
1007
1008
1009static void
1010print_visual_attribs_long_header(void)
1011{
1012 printf("Vis   Vis   Visual Trans  buff lev render DB ste  r   g   b   a      s  aux dep ste  accum buffer   MS   MS         \n");
1013 printf(" ID  Depth   Type  parent size el   type     reo sz  sz  sz  sz flt rgb buf th  ncl  r   g   b   a  num bufs caveats\n");
1014 printf("--------------------------------------------------------------------------------------------------------------------\n");
1015}
1016
1017
1018static void
1019print_visual_attribs_long(const struct visual_attribs *attribs)
1020{
1021   const char *caveat = caveat_string(attribs->visualCaveat);
1022
1023   printf("0x%3x %2d %-11s %2d    %3d %2d  %4s %3d %3d %3d %3d %3d %3d",
1024          attribs->id,
1025          attribs->depth,
1026          visual_class_name(attribs->klass),
1027          attribs->transparentType != GLX_NONE,
1028          attribs->bufferSize,
1029          attribs->level,
1030          visual_render_type_name(attribs->render_type),
1031          attribs->doubleBuffer,
1032          attribs->stereo,
1033          attribs->redSize, attribs->greenSize,
1034          attribs->blueSize, attribs->alphaSize
1035          );
1036
1037   printf("  %c   %c %3d %4d %2d %3d %3d %3d %3d  %2d  %2d %6s\n",
1038          attribs->floatComponents ? 'f' : '.',
1039          attribs->srgb ? 's' : '.',
1040          attribs->auxBuffers,
1041          attribs->depthSize,
1042          attribs->stencilSize,
1043          attribs->accumRedSize, attribs->accumGreenSize,
1044          attribs->accumBlueSize, attribs->accumAlphaSize,
1045          attribs->numSamples, attribs->numMultisample,
1046          caveat
1047          );
1048}
1049
1050
1051static void
1052print_visual_info(Display *dpy, int scrnum, InfoMode mode)
1053{
1054   XVisualInfo theTemplate;
1055   XVisualInfo *visuals;
1056   int numVisuals, numGlxVisuals;
1057   long mask;
1058   int i;
1059   struct visual_attribs attribs;
1060
1061   /* get list of all visuals on this screen */
1062   theTemplate.screen = scrnum;
1063   mask = VisualScreenMask;
1064   visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
1065
1066   numGlxVisuals = 0;
1067   for (i = 0; i < numVisuals; i++) {
1068      if (get_visual_attribs(dpy, &visuals[i], &attribs))
1069	 numGlxVisuals++;
1070   }
1071
1072   if (numGlxVisuals == 0)
1073      return;
1074
1075   printf("%d GLX Visuals\n", numGlxVisuals);
1076
1077   if (mode == Normal)
1078      print_visual_attribs_short_header();
1079   else if (mode == Wide)
1080      print_visual_attribs_long_header();
1081
1082   for (i = 0; i < numVisuals; i++) {
1083      if (!get_visual_attribs(dpy, &visuals[i], &attribs))
1084	 continue;
1085
1086      if (mode == Verbose)
1087	 print_visual_attribs_verbose(&attribs, False);
1088      else if (mode == Normal)
1089         print_visual_attribs_short(&attribs);
1090      else if (mode == Wide)
1091         print_visual_attribs_long(&attribs);
1092   }
1093   printf("\n");
1094
1095   XFree(visuals);
1096}
1097
1098#ifdef GLX_VERSION_1_3
1099
1100static void
1101print_fbconfig_info(Display *dpy, int scrnum, InfoMode mode)
1102{
1103   int numFBConfigs = 0;
1104   struct visual_attribs attribs;
1105   GLXFBConfig *fbconfigs;
1106   int i;
1107
1108   /* get list of all fbconfigs on this screen */
1109   fbconfigs = glXGetFBConfigs(dpy, scrnum, &numFBConfigs);
1110
1111   if (numFBConfigs == 0) {
1112      XFree(fbconfigs);
1113      return;
1114   }
1115
1116   printf("%d GLXFBConfigs:\n", numFBConfigs);
1117   if (mode == Normal)
1118      print_visual_attribs_short_header();
1119   else if (mode == Wide)
1120      print_visual_attribs_long_header();
1121
1122   for (i = 0; i < numFBConfigs; i++) {
1123      get_fbconfig_attribs(dpy, fbconfigs[i], &attribs);
1124
1125      if (mode == Verbose)
1126         print_visual_attribs_verbose(&attribs, True);
1127      else if (mode == Normal)
1128	 print_visual_attribs_short(&attribs);
1129      else if (mode == Wide)
1130         print_visual_attribs_long(&attribs);
1131   }
1132   printf("\n");
1133
1134   XFree(fbconfigs);
1135}
1136
1137#endif
1138
1139/*
1140 * Stand-alone Mesa doesn't really implement the GLX protocol so it
1141 * doesn't really know the GLX attributes associated with an X visual.
1142 * The first time a visual is presented to Mesa's pseudo-GLX it
1143 * attaches ancilliary buffers to it (like depth and stencil).
1144 * But that usually only works if glXChooseVisual is used.
1145 * This function calls glXChooseVisual() to sort of "prime the pump"
1146 * for Mesa's GLX so that the visuals that get reported actually
1147 * reflect what applications will see.
1148 * This has no effect when using true GLX.
1149 */
1150static void
1151mesa_hack(Display *dpy, int scrnum)
1152{
1153   static int attribs[] = {
1154      GLX_RGBA,
1155      GLX_RED_SIZE, 1,
1156      GLX_GREEN_SIZE, 1,
1157      GLX_BLUE_SIZE, 1,
1158      GLX_DEPTH_SIZE, 1,
1159      GLX_STENCIL_SIZE, 1,
1160      GLX_ACCUM_RED_SIZE, 1,
1161      GLX_ACCUM_GREEN_SIZE, 1,
1162      GLX_ACCUM_BLUE_SIZE, 1,
1163      GLX_ACCUM_ALPHA_SIZE, 1,
1164      GLX_DOUBLEBUFFER,
1165      None
1166   };
1167   XVisualInfo *visinfo;
1168
1169   visinfo = glXChooseVisual(dpy, scrnum, attribs);
1170   if (visinfo)
1171      XFree(visinfo);
1172}
1173
1174
1175/*
1176 * Examine all visuals to find the so-called best one.
1177 * We prefer deepest RGBA buffer with depth, stencil and accum
1178 * that has no caveats.
1179 */
1180static int
1181find_best_visual(Display *dpy, int scrnum)
1182{
1183   XVisualInfo theTemplate;
1184   XVisualInfo *visuals;
1185   int numVisuals;
1186   long mask;
1187   int i;
1188   struct visual_attribs bestVis;
1189
1190   /* get list of all visuals on this screen */
1191   theTemplate.screen = scrnum;
1192   mask = VisualScreenMask;
1193   visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
1194
1195   /* init bestVis with first visual info */
1196   get_visual_attribs(dpy, &visuals[0], &bestVis);
1197
1198   /* try to find a "better" visual */
1199   for (i = 1; i < numVisuals; i++) {
1200      struct visual_attribs vis;
1201
1202      get_visual_attribs(dpy, &visuals[i], &vis);
1203
1204      /* always skip visuals with caveats */
1205      if (vis.visualCaveat != GLX_NONE_EXT)
1206         continue;
1207
1208      /* see if this vis is better than bestVis */
1209      if ((!bestVis.supportsGL && vis.supportsGL) ||
1210          (bestVis.visualCaveat != GLX_NONE_EXT) ||
1211          (!(bestVis.render_type & GLX_RGBA_BIT) && (vis.render_type & GLX_RGBA_BIT)) ||
1212          (!bestVis.doubleBuffer && vis.doubleBuffer) ||
1213          (bestVis.redSize < vis.redSize) ||
1214          (bestVis.greenSize < vis.greenSize) ||
1215          (bestVis.blueSize < vis.blueSize) ||
1216          (bestVis.alphaSize < vis.alphaSize) ||
1217          (bestVis.depthSize < vis.depthSize) ||
1218          (bestVis.stencilSize < vis.stencilSize) ||
1219          (bestVis.accumRedSize < vis.accumRedSize)) {
1220         /* found a better visual */
1221         bestVis = vis;
1222      }
1223   }
1224
1225   XFree(visuals);
1226
1227   return bestVis.id;
1228}
1229
1230
1231int
1232main(int argc, char *argv[])
1233{
1234   Display *dpy;
1235   int numScreens, scrnum;
1236   struct options opts;
1237   Bool coreWorked;
1238
1239   parse_args(argc, argv, &opts);
1240
1241   dpy = XOpenDisplay(opts.displayName);
1242   if (!dpy) {
1243      fprintf(stderr, "Error: unable to open display %s\n",
1244              XDisplayName(opts.displayName));
1245      return -1;
1246   }
1247
1248   if (opts.findBest) {
1249      int b;
1250      mesa_hack(dpy, 0);
1251      b = find_best_visual(dpy, 0);
1252      printf("%d\n", b);
1253   }
1254   else {
1255      numScreens = ScreenCount(dpy);
1256      print_display_info(dpy);
1257      for (scrnum = 0; scrnum < numScreens; scrnum++) {
1258         mesa_hack(dpy, scrnum);
1259         coreWorked = print_screen_info(dpy, scrnum, &opts,
1260                                        True, False, opts.limits, False);
1261         print_screen_info(dpy, scrnum, &opts, False, False,
1262                           opts.limits, coreWorked);
1263         print_screen_info(dpy, scrnum, &opts, False, True, False, True);
1264
1265         printf("\n");
1266
1267         if (opts.mode != Brief) {
1268            print_visual_info(dpy, scrnum, opts.mode);
1269#ifdef GLX_VERSION_1_3
1270            print_fbconfig_info(dpy, scrnum, opts.mode);
1271#endif
1272         }
1273
1274         if (scrnum + 1 < numScreens)
1275            printf("\n\n");
1276      }
1277   }
1278
1279   XCloseDisplay(dpy);
1280
1281   return 0;
1282}
1283