added -l option to print interesting OpenGL limits
[mesa.git] / progs / xdemos / glxinfo.c
1 /* $Id: glxinfo.c,v 1.17 2002/09/06 03:35:43 brianp Exp $ */
2
3 /*
4 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24
25 /*
26 * This program is a work-alike of the IRIX glxinfo program.
27 * Command line options:
28 * -t print wide table
29 * -v print verbose information
30 * -display DisplayName specify the X display to interogate
31 * -b only print ID of "best" visual on screen 0
32 * -l print interesting OpenGL limits (added 5 Sep 2002)
33 *
34 * Brian Paul 26 January 2000
35 */
36
37 #define DO_GLU /* may want to remove this for easier XFree86 building? */
38
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <GL/gl.h>
42 #ifdef DO_GLU
43 #include <GL/glu.h>
44 #endif
45 #include <GL/glx.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49
50
51 #ifndef GLX_NONE_EXT
52 #define GLX_NONE_EXT 0x8000
53 #endif
54
55
56 typedef enum
57 {
58 Normal,
59 Wide,
60 Verbose
61 } InfoMode;
62
63
64 struct visual_attribs
65 {
66 /* X visual attribs */
67 int id;
68 int klass;
69 int depth;
70 int redMask, greenMask, blueMask;
71 int colormapSize;
72 int bitsPerRGB;
73
74 /* GL visual attribs */
75 int supportsGL;
76 int transparent;
77 int bufferSize;
78 int level;
79 int rgba;
80 int doubleBuffer;
81 int stereo;
82 int auxBuffers;
83 int redSize, greenSize, blueSize, alphaSize;
84 int depthSize;
85 int stencilSize;
86 int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
87 int numSamples, numMultisample;
88 int visualCaveat;
89 };
90
91
92 /*
93 * Print a list of extensions, with word-wrapping.
94 */
95 static void
96 print_extension_list(const char *ext)
97 {
98 const char *indentString = " ";
99 const int indent = 4;
100 const int max = 79;
101 int width, i, j;
102
103 if (!ext || !ext[0])
104 return;
105
106 width = indent;
107 printf(indentString);
108 i = j = 0;
109 while (1) {
110 if (ext[j] == ' ' || ext[j] == 0) {
111 /* found end of an extension name */
112 const int len = j - i;
113 if (width + len > max) {
114 /* start a new line */
115 printf("\n");
116 width = indent;
117 printf(indentString);
118 }
119 /* print the extension name between ext[i] and ext[j] */
120 while (i < j) {
121 printf("%c", ext[i]);
122 i++;
123 }
124 /* either we're all done, or we'll continue with next extension */
125 width += len + 1;
126 if (ext[j] == 0) {
127 break;
128 }
129 else {
130 i++;
131 j++;
132 if (ext[j] == 0)
133 break;
134 printf(", ");
135 width += 2;
136 }
137 }
138 j++;
139 }
140 printf("\n");
141 }
142
143
144 static void
145 print_display_info(Display *dpy)
146 {
147 printf("name of display: %s\n", DisplayString(dpy));
148 }
149
150
151 static void
152 print_limits(void)
153 {
154 struct token_name {
155 GLuint count;
156 GLenum token;
157 const char *name;
158 };
159 static const struct token_name limits[] = {
160 { 1, GL_MAX_ATTRIB_STACK_DEPTH, "GL_MAX_ATTRIB_STACK_DEPTH" },
161 { 1, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH" },
162 { 1, GL_MAX_CLIP_PLANES, "GL_MAX_CLIP_PLANES" },
163 { 1, GL_MAX_COLOR_MATRIX_STACK_DEPTH, "GL_MAX_COLOR_MATRIX_STACK_DEPTH" },
164 { 1, GL_MAX_CONVOLUTION_WIDTH_EXT, "GL_MAX_CONVOLUTION_WIDTH_EXT" },
165 { 1, GL_MAX_CONVOLUTION_HEIGHT_EXT, "GL_MAX_CONVOLUTION_HEIGHT_EXT" },
166 { 1, GL_MAX_ELEMENTS_VERTICES, "GL_MAX_ELEMENTS_VERTICES" },
167 { 1, GL_MAX_ELEMENTS_INDICES, "GL_MAX_ELEMENTS_INDICES" },
168 { 1, GL_MAX_EVAL_ORDER, "GL_MAX_EVAL_ORDER" },
169 { 1, GL_MAX_LIGHTS, "GL_MAX_LIGHTS" },
170 { 1, GL_MAX_LIST_NESTING, "GL_MAX_LIST_NESTING" },
171 { 1, GL_MAX_MODELVIEW_STACK_DEPTH, "GL_MAX_MODELVIEW_STACK_DEPTH" },
172 { 1, GL_MAX_NAME_STACK_DEPTH, "GL_MAX_NAME_STACK_DEPTH" },
173 { 1, GL_MAX_PIXEL_MAP_TABLE, "GL_MAX_PIXEL_MAP_TABLE" },
174 { 1, GL_MAX_PROJECTION_STACK_DEPTH, "GL_MAX_PROJECTION_STACK_DEPTH" },
175 { 1, GL_MAX_TEXTURE_STACK_DEPTH, "GL_MAX_TEXTURE_STACK_DEPTH" },
176 { 1, GL_MAX_TEXTURE_SIZE, "GL_MAX_TEXTURE_SIZE" },
177 { 1, GL_MAX_3D_TEXTURE_SIZE, "GL_MAX_3D_TEXTURE_SIZE" },
178 { 1, GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB" },
179 { 1, GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV" },
180 { 1, GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, "GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB" },
181 { 1, GL_MAX_TEXTURE_UNITS_ARB, "GL_MAX_TEXTURE_UNITS_ARB" },
182 { 1, GL_MAX_TEXTURE_LOD_BIAS_EXT, "GL_MAX_TEXTURE_LOD_BIAS_EXT" },
183 { 1, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT" },
184 { 2, GL_MAX_VIEWPORT_DIMS, "GL_MAX_VIEWPORT_DIMS" },
185 { 2, GL_ALIASED_LINE_WIDTH_RANGE, "GL_ALIASED_LINE_WIDTH_RANGE" },
186 { 2, GL_SMOOTH_LINE_WIDTH_RANGE, "GL_SMOOTH_LINE_WIDTH_RANGE" },
187 { 2, GL_ALIASED_POINT_SIZE_RANGE, "GL_ALIASED_POINT_SIZE_RANGE" },
188 { 2, GL_SMOOTH_POINT_SIZE_RANGE, "GL_SMOOTH_POINT_SIZE_RANGE" },
189 { 0, (GLenum) 0, NULL }
190 };
191 GLint i, max[2];
192 printf("OpenGL limits:\n");
193 for (i = 0; limits[i].count; i++) {
194 glGetIntegerv(limits[i].token, max);
195 if (glGetError() == GL_NONE) {
196 if (limits[i].count == 1)
197 printf(" %s = %d\n", limits[i].name, max[0]);
198 else /* XXX fix if we ever query something with more than 2 values */
199 printf(" %s = %d, %d\n", limits[i].name, max[0], max[1]);
200 }
201 }
202 }
203
204
205 static void
206 print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits)
207 {
208 Window win;
209 int attribSingle[] = {
210 GLX_RGBA,
211 GLX_RED_SIZE, 1,
212 GLX_GREEN_SIZE, 1,
213 GLX_BLUE_SIZE, 1,
214 None };
215 int attribDouble[] = {
216 GLX_RGBA,
217 GLX_RED_SIZE, 1,
218 GLX_GREEN_SIZE, 1,
219 GLX_BLUE_SIZE, 1,
220 GLX_DOUBLEBUFFER,
221 None };
222
223 XSetWindowAttributes attr;
224 unsigned long mask;
225 Window root;
226 GLXContext ctx;
227 XVisualInfo *visinfo;
228 int width = 100, height = 100;
229
230 root = RootWindow(dpy, scrnum);
231
232 visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
233 if (!visinfo) {
234 visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
235 if (!visinfo) {
236 fprintf(stderr, "Error: couldn't find RGB GLX visual\n");
237 return;
238 }
239 }
240
241 attr.background_pixel = 0;
242 attr.border_pixel = 0;
243 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
244 attr.event_mask = StructureNotifyMask | ExposureMask;
245 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
246 win = XCreateWindow(dpy, root, 0, 0, width, height,
247 0, visinfo->depth, InputOutput,
248 visinfo->visual, mask, &attr);
249
250 ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect );
251 if (!ctx) {
252 fprintf(stderr, "Error: glXCreateContext failed\n");
253 XDestroyWindow(dpy, win);
254 return;
255 }
256
257 if (glXMakeCurrent(dpy, win, ctx)) {
258 const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR);
259 const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION);
260 const char *serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS);
261 const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR);
262 const char *clientVersion = glXGetClientString(dpy, GLX_VERSION);
263 const char *clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS);
264 const char *glxExtensions = glXQueryExtensionsString(dpy, scrnum);
265 const char *glVendor = (const char *) glGetString(GL_VENDOR);
266 const char *glRenderer = (const char *) glGetString(GL_RENDERER);
267 const char *glVersion = (const char *) glGetString(GL_VERSION);
268 const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);
269 char *displayName = NULL;
270 char *colon = NULL, *period = NULL;
271 #ifdef DO_GLU
272 const char *gluVersion = (const char *) gluGetString(GLU_VERSION);
273 const char *gluExtensions = (const char *) gluGetString(GLU_EXTENSIONS);
274 #endif
275 /* Strip the screen number from the display name, if present. */
276 if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1))) {
277 fprintf(stderr, "Error: malloc() failed\n");
278 exit(1);
279 }
280 strcpy(displayName, DisplayString(dpy));
281 colon = strrchr(displayName, ':');
282 if (colon) {
283 period = strchr(colon, '.');
284 if (period)
285 *period = '\0';
286 }
287 printf("display: %s screen: %d\n", displayName, scrnum);
288 free(displayName);
289 printf("direct rendering: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
290 printf("server glx vendor string: %s\n", serverVendor);
291 printf("server glx version string: %s\n", serverVersion);
292 printf("server glx extensions:\n");
293 print_extension_list(serverExtensions);
294 printf("client glx vendor string: %s\n", clientVendor);
295 printf("client glx version string: %s\n", clientVersion);
296 printf("client glx extensions:\n");
297 print_extension_list(clientExtensions);
298 printf("GLX extensions:\n");
299 print_extension_list(glxExtensions);
300 printf("OpenGL vendor string: %s\n", glVendor);
301 printf("OpenGL renderer string: %s\n", glRenderer);
302 printf("OpenGL version string: %s\n", glVersion);
303 printf("OpenGL extensions:\n");
304 print_extension_list(glExtensions);
305 if (limits)
306 print_limits();
307 #ifdef DO_GLU
308 printf("glu version: %s\n", gluVersion);
309 printf("glu extensions:\n");
310 print_extension_list(gluExtensions);
311 #endif
312 }
313 else {
314 fprintf(stderr, "Error: glXMakeCurrent failed\n");
315 }
316
317 glXDestroyContext(dpy, ctx);
318 XDestroyWindow(dpy, win);
319 }
320
321
322 static const char *
323 visual_class_name(int cls)
324 {
325 switch (cls) {
326 case StaticColor:
327 return "StaticColor";
328 case PseudoColor:
329 return "PseudoColor";
330 case StaticGray:
331 return "StaticGray";
332 case GrayScale:
333 return "GrayScale";
334 case TrueColor:
335 return "TrueColor";
336 case DirectColor:
337 return "DirectColor";
338 default:
339 return "";
340 }
341 }
342
343
344 static const char *
345 visual_class_abbrev(int cls)
346 {
347 switch (cls) {
348 case StaticColor:
349 return "sc";
350 case PseudoColor:
351 return "pc";
352 case StaticGray:
353 return "sg";
354 case GrayScale:
355 return "gs";
356 case TrueColor:
357 return "tc";
358 case DirectColor:
359 return "dc";
360 default:
361 return "";
362 }
363 }
364
365
366 static void
367 get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
368 struct visual_attribs *attribs)
369 {
370 const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
371
372 memset(attribs, 0, sizeof(struct visual_attribs));
373
374 attribs->id = vInfo->visualid;
375 #if defined(__cplusplus) || defined(c_plusplus)
376 attribs->klass = vInfo->c_class;
377 #else
378 attribs->klass = vInfo->class;
379 #endif
380 attribs->depth = vInfo->depth;
381 attribs->redMask = vInfo->red_mask;
382 attribs->greenMask = vInfo->green_mask;
383 attribs->blueMask = vInfo->blue_mask;
384 attribs->colormapSize = vInfo->colormap_size;
385 attribs->bitsPerRGB = vInfo->bits_per_rgb;
386
387 if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0)
388 return;
389 glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
390 glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
391 glXGetConfig(dpy, vInfo, GLX_RGBA, &attribs->rgba);
392 glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
393 glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
394 glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
395 glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
396 glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
397 glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
398 glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
399 glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
400 glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
401 glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
402 glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
403 glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
404 glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
405
406 /* transparent pixel value not implemented yet */
407 attribs->transparent = 0;
408
409 /* multisample tests not implemented yet */
410 attribs->numSamples = 0;
411 attribs->numMultisample = 0;
412
413 #if defined(GLX_EXT_visual_rating)
414 if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
415 glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
416 }
417 else {
418 attribs->visualCaveat = GLX_NONE_EXT;
419 }
420 #else
421 attribs->visualCaveat = 0;
422 #endif
423 }
424
425
426 static void
427 print_visual_attribs_verbose(const struct visual_attribs *attribs)
428 {
429 printf("Visual ID: %x depth=%d class=%s\n",
430 attribs->id, attribs->depth, visual_class_name(attribs->klass));
431 printf(" bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n",
432 attribs->bufferSize, attribs->level, attribs->rgba ? "rgba" : "ci",
433 attribs->doubleBuffer, attribs->stereo);
434 printf(" rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
435 attribs->redSize, attribs->greenSize,
436 attribs->blueSize, attribs->alphaSize);
437 printf(" auxBuffers=%d depthSize=%d stencilSize=%d\n",
438 attribs->auxBuffers, attribs->depthSize, attribs->stencilSize);
439 printf(" accum: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
440 attribs->accumRedSize, attribs->accumGreenSize,
441 attribs->accumBlueSize, attribs->accumAlphaSize);
442 printf(" multiSample=%d multiSampleBuffers=%d\n",
443 attribs->numSamples, attribs->numMultisample);
444 #ifdef GLX_EXT_visual_rating
445 if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
446 printf(" visualCaveat=None\n");
447 else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
448 printf(" visualCaveat=Slow\n");
449 else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
450 printf(" visualCaveat=Nonconformant\n");
451 #endif
452 printf(" %s\n", attribs->transparent ? "Transparent." : "Opaque.");
453 }
454
455
456 static void
457 print_visual_attribs_short_header(void)
458 {
459 printf(" visual x bf lv rg d st colorbuffer ax dp st accumbuffer ms cav\n");
460 printf(" id dep cl sp sz l ci b ro r g b a bf th cl r g b a ns b eat\n");
461 printf("----------------------------------------------------------------------\n");
462 }
463
464
465 static void
466 print_visual_attribs_short(const struct visual_attribs *attribs)
467 {
468 char *caveat = NULL;
469 #ifdef GLX_EXT_visual_rating
470 if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
471 caveat = "None";
472 else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
473 caveat = "Slow";
474 else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
475 caveat = "Ncon";
476 #else
477 caveat = "None";
478 #endif
479
480 printf("0x%2x %2d %2s %2d %2d %2d %1s %2s %2s %2d %2d %2d %2d %2d %2d %2d",
481 attribs->id,
482 attribs->depth,
483 visual_class_abbrev(attribs->klass),
484 attribs->transparent,
485 attribs->bufferSize,
486 attribs->level,
487 attribs->rgba ? "r" : "c",
488 attribs->doubleBuffer ? "y" : ".",
489 attribs->stereo ? "y" : ".",
490 attribs->redSize, attribs->greenSize,
491 attribs->blueSize, attribs->alphaSize,
492 attribs->auxBuffers,
493 attribs->depthSize,
494 attribs->stencilSize
495 );
496
497 printf(" %2d %2d %2d %2d %2d %1d %s\n",
498 attribs->accumRedSize, attribs->accumGreenSize,
499 attribs->accumBlueSize, attribs->accumAlphaSize,
500 attribs->numSamples, attribs->numMultisample,
501 caveat
502 );
503 }
504
505
506 static void
507 print_visual_attribs_long_header(void)
508 {
509 printf("Vis Vis Visual Trans buff lev render DB ste r g b a aux dep ste accum buffers MS MS\n");
510 printf(" ID Depth Type parent size el type reo sz sz sz sz buf th ncl r g b a num bufs\n");
511 printf("----------------------------------------------------------------------------------------------------\n");
512 }
513
514
515 static void
516 print_visual_attribs_long(const struct visual_attribs *attribs)
517 {
518 printf("0x%2x %2d %-11s %2d %2d %2d %4s %3d %3d %3d %3d %3d %3d",
519 attribs->id,
520 attribs->depth,
521 visual_class_name(attribs->klass),
522 attribs->transparent,
523 attribs->bufferSize,
524 attribs->level,
525 attribs->rgba ? "rgba" : "ci ",
526 attribs->doubleBuffer,
527 attribs->stereo,
528 attribs->redSize, attribs->greenSize,
529 attribs->blueSize, attribs->alphaSize
530 );
531
532 printf(" %3d %4d %2d %3d %3d %3d %3d %2d %2d\n",
533 attribs->auxBuffers,
534 attribs->depthSize,
535 attribs->stencilSize,
536 attribs->accumRedSize, attribs->accumGreenSize,
537 attribs->accumBlueSize, attribs->accumAlphaSize,
538 attribs->numSamples, attribs->numMultisample
539 );
540 }
541
542
543 static void
544 print_visual_info(Display *dpy, int scrnum, InfoMode mode)
545 {
546 XVisualInfo theTemplate;
547 XVisualInfo *visuals;
548 int numVisuals;
549 long mask;
550 int i;
551
552 /* get list of all visuals on this screen */
553 theTemplate.screen = scrnum;
554 mask = VisualScreenMask;
555 visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
556
557 if (mode == Verbose) {
558 for (i = 0; i < numVisuals; i++) {
559 struct visual_attribs attribs;
560 get_visual_attribs(dpy, &visuals[i], &attribs);
561 print_visual_attribs_verbose(&attribs);
562 }
563 }
564 else if (mode == Normal) {
565 print_visual_attribs_short_header();
566 for (i = 0; i < numVisuals; i++) {
567 struct visual_attribs attribs;
568 get_visual_attribs(dpy, &visuals[i], &attribs);
569 print_visual_attribs_short(&attribs);
570 }
571 }
572 else if (mode == Wide) {
573 print_visual_attribs_long_header();
574 for (i = 0; i < numVisuals; i++) {
575 struct visual_attribs attribs;
576 get_visual_attribs(dpy, &visuals[i], &attribs);
577 print_visual_attribs_long(&attribs);
578 }
579 }
580
581 XFree(visuals);
582 }
583
584
585 /*
586 * Stand-alone Mesa doesn't really implement the GLX protocol so it
587 * doesn't really know the GLX attributes associated with an X visual.
588 * The first time a visual is presented to Mesa's pseudo-GLX it
589 * attaches ancilliary buffers to it (like depth and stencil).
590 * But that usually only works if glXChooseVisual is used.
591 * This function calls glXChooseVisual() to sort of "prime the pump"
592 * for Mesa's GLX so that the visuals that get reported actually
593 * reflect what applications will see.
594 * This has no effect when using true GLX.
595 */
596 static void
597 mesa_hack(Display *dpy, int scrnum)
598 {
599 static int attribs[] = {
600 GLX_RGBA,
601 GLX_RED_SIZE, 1,
602 GLX_GREEN_SIZE, 1,
603 GLX_BLUE_SIZE, 1,
604 GLX_DEPTH_SIZE, 1,
605 GLX_STENCIL_SIZE, 1,
606 GLX_ACCUM_RED_SIZE, 1,
607 GLX_ACCUM_GREEN_SIZE, 1,
608 GLX_ACCUM_BLUE_SIZE, 1,
609 GLX_ACCUM_ALPHA_SIZE, 1,
610 GLX_DOUBLEBUFFER,
611 None
612 };
613 XVisualInfo *visinfo;
614
615 visinfo = glXChooseVisual(dpy, scrnum, attribs);
616 if (visinfo)
617 XFree(visinfo);
618 }
619
620
621 /*
622 * Examine all visuals to find the so-called best one.
623 * We prefer deepest RGBA buffer with depth, stencil and accum
624 * that has no caveats.
625 */
626 static int
627 find_best_visual(Display *dpy, int scrnum)
628 {
629 XVisualInfo theTemplate;
630 XVisualInfo *visuals;
631 int numVisuals;
632 long mask;
633 int i;
634 struct visual_attribs bestVis;
635
636 /* get list of all visuals on this screen */
637 theTemplate.screen = scrnum;
638 mask = VisualScreenMask;
639 visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
640
641 /* init bestVis with first visual info */
642 get_visual_attribs(dpy, &visuals[0], &bestVis);
643
644 /* try to find a "better" visual */
645 for (i = 1; i < numVisuals; i++) {
646 struct visual_attribs vis;
647
648 get_visual_attribs(dpy, &visuals[i], &vis);
649
650 /* always skip visuals with caveats */
651 if (vis.visualCaveat != GLX_NONE_EXT)
652 continue;
653
654 /* see if this vis is better than bestVis */
655 if ((!bestVis.supportsGL && vis.supportsGL) ||
656 (bestVis.visualCaveat != GLX_NONE_EXT) ||
657 (!bestVis.rgba && vis.rgba) ||
658 (!bestVis.doubleBuffer && vis.doubleBuffer) ||
659 (bestVis.redSize < vis.redSize) ||
660 (bestVis.greenSize < vis.greenSize) ||
661 (bestVis.blueSize < vis.blueSize) ||
662 (bestVis.alphaSize < vis.alphaSize) ||
663 (bestVis.depthSize < vis.depthSize) ||
664 (bestVis.stencilSize < vis.stencilSize) ||
665 (bestVis.accumRedSize < vis.accumRedSize)) {
666 /* found a better visual */
667 bestVis = vis;
668 }
669 }
670
671 XFree(visuals);
672
673 return bestVis.id;
674 }
675
676
677 static void
678 usage(void)
679 {
680 printf("Usage: glxinfo [-v] [-t] [-h] [-i] [-b] [-display <dname>]\n");
681 printf("\t-v: Print visuals info in verbose form.\n");
682 printf("\t-t: Print verbose table.\n");
683 printf("\t-display <dname>: Print GLX visuals on specified server.\n");
684 printf("\t-h: This information.\n");
685 printf("\t-i: Force an indirect rendering context.\n");
686 printf("\t-b: Find the 'best' visual and print it's number.\n");
687 printf("\t-l: Print interesting OpenGLl imits.\n");
688 }
689
690
691 int
692 main(int argc, char *argv[])
693 {
694 char *displayName = NULL;
695 Display *dpy;
696 int numScreens, scrnum;
697 InfoMode mode = Normal;
698 GLboolean findBest = GL_FALSE;
699 GLboolean limits = GL_FALSE;
700 Bool allowDirect = True;
701 int i;
702
703 for (i = 1; i < argc; i++) {
704 if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
705 displayName = argv[i + 1];
706 i++;
707 }
708 else if (strcmp(argv[i], "-t") == 0) {
709 mode = Wide;
710 }
711 else if (strcmp(argv[i], "-v") == 0) {
712 mode = Verbose;
713 }
714 else if (strcmp(argv[i], "-b") == 0) {
715 findBest = GL_TRUE;
716 }
717 else if (strcmp(argv[i], "-i") == 0) {
718 allowDirect = False;
719 }
720 else if (strcmp(argv[i], "-l") == 0) {
721 limits = GL_TRUE;
722 }
723 else if (strcmp(argv[i], "-h") == 0) {
724 usage();
725 return 0;
726 }
727 else {
728 printf("Unknown option `%s'\n", argv[i]);
729 usage();
730 return 0;
731 }
732 }
733
734 dpy = XOpenDisplay(displayName);
735 if (!dpy) {
736 fprintf(stderr, "Error: unable to open display %s\n", displayName);
737 return -1;
738 }
739
740 if (findBest) {
741 int b;
742 mesa_hack(dpy, 0);
743 b = find_best_visual(dpy, 0);
744 printf("%d\n", b);
745 }
746 else {
747 numScreens = ScreenCount(dpy);
748 print_display_info(dpy);
749 for (scrnum = 0; scrnum < numScreens; scrnum++) {
750 mesa_hack(dpy, scrnum);
751 print_screen_info(dpy, scrnum, allowDirect, limits);
752 printf("\n");
753 print_visual_info(dpy, scrnum, mode);
754 if (scrnum + 1 < numScreens)
755 printf("\n\n");
756 }
757 }
758
759 XCloseDisplay(dpy);
760
761 return 0;
762 }