blob: 32866ca1fcad51c47e795f28534cb4bcfb3e21f0 [file] [log] [blame]
Brian Paul2f7ef5f2002-09-06 03:35:43 +00001/* $Id: glxinfo.c,v 1.17 2002/09/06 03:35:43 brianp Exp $ */
Brian Pauld2bfe1e1999-09-16 16:40:46 +00002
3/*
Brian Paul2f7ef5f2002-09-06 03:35:43 +00004 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
Brian Paul76bc4402000-01-27 16:43:56 +00005 *
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.
Brian Pauld2bfe1e1999-09-16 16:40:46 +000022 */
23
24
Brian Paul76bc4402000-01-27 16:43:56 +000025/*
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
Brian Paul39557c32001-03-23 21:41:44 +000031 * -b only print ID of "best" visual on screen 0
Brian Paul2f7ef5f2002-09-06 03:35:43 +000032 * -l print interesting OpenGL limits (added 5 Sep 2002)
Brian Paul76bc4402000-01-27 16:43:56 +000033 *
34 * Brian Paul 26 January 2000
35 */
Brian Pauld2bfe1e1999-09-16 16:40:46 +000036
Brian Paul39557c32001-03-23 21:41:44 +000037#define DO_GLU /* may want to remove this for easier XFree86 building? */
Brian Paul76bc4402000-01-27 16:43:56 +000038
39#include <X11/Xlib.h>
40#include <X11/Xutil.h>
Brian Pauld2bfe1e1999-09-16 16:40:46 +000041#include <GL/gl.h>
Brian Paul39557c32001-03-23 21:41:44 +000042#ifdef DO_GLU
Brian Pauld2bfe1e1999-09-16 16:40:46 +000043#include <GL/glu.h>
Brian Paul39557c32001-03-23 21:41:44 +000044#endif
Brian Paul76bc4402000-01-27 16:43:56 +000045#include <GL/glx.h>
Brian Pauld2bfe1e1999-09-16 16:40:46 +000046#include <stdio.h>
Brian Paul76bc4402000-01-27 16:43:56 +000047#include <string.h>
Brian Paul373aea12001-04-02 22:45:07 +000048#include <stdlib.h>
Brian Pauld2bfe1e1999-09-16 16:40:46 +000049
50
Brian Paul39557c32001-03-23 21:41:44 +000051#ifndef GLX_NONE_EXT
52#define GLX_NONE_EXT 0x8000
53#endif
54
55
Brian Paul76bc4402000-01-27 16:43:56 +000056typedef enum
Brian Pauld2bfe1e1999-09-16 16:40:46 +000057{
Brian Paul76bc4402000-01-27 16:43:56 +000058 Normal,
59 Wide,
60 Verbose
61} InfoMode;
Brian Pauld2bfe1e1999-09-16 16:40:46 +000062
Brian Pauld2bfe1e1999-09-16 16:40:46 +000063
Brian Paul76bc4402000-01-27 16:43:56 +000064struct 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;
Brian Pauld2bfe1e1999-09-16 16:40:46 +000073
Brian Paul76bc4402000-01-27 16:43:56 +000074 /* 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;
Brian Paul25673f02000-03-31 18:17:51 +000088 int visualCaveat;
Brian Paul76bc4402000-01-27 16:43:56 +000089};
90
91
92/*
93 * Print a list of extensions, with word-wrapping.
94 */
95static void
96print_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++;
Brian Paul7ac43502000-02-23 22:50:35 +0000132 if (ext[j] == 0)
133 break;
Brian Paul76bc4402000-01-27 16:43:56 +0000134 printf(", ");
135 width += 2;
136 }
137 }
138 j++;
139 }
140 printf("\n");
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000141}
142
143
Brian Paul76bc4402000-01-27 16:43:56 +0000144static void
Brian Paul373aea12001-04-02 22:45:07 +0000145print_display_info(Display *dpy)
146{
147 printf("name of display: %s\n", DisplayString(dpy));
148}
149
150
151static void
Brian Paul2f7ef5f2002-09-06 03:35:43 +0000152print_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
205static void
206print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits)
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000207{
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000208 Window win;
Brian Paul8460cc92000-02-02 20:57:51 +0000209 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
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000223 XSetWindowAttributes attr;
224 unsigned long mask;
225 Window root;
226 GLXContext ctx;
227 XVisualInfo *visinfo;
228 int width = 100, height = 100;
229
Brian Paul76bc4402000-01-27 16:43:56 +0000230 root = RootWindow(dpy, scrnum);
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000231
Brian Paul8460cc92000-02-02 20:57:51 +0000232 visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000233 if (!visinfo) {
Brian Paul8460cc92000-02-02 20:57:51 +0000234 visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
235 if (!visinfo) {
Brian Paul9cff5582000-05-07 18:07:23 +0000236 fprintf(stderr, "Error: couldn't find RGB GLX visual\n");
Brian Paul8460cc92000-02-02 20:57:51 +0000237 return;
238 }
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000239 }
240
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000241 attr.background_pixel = 0;
242 attr.border_pixel = 0;
Brian Paul9cff5582000-05-07 18:07:23 +0000243 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000244 attr.event_mask = StructureNotifyMask | ExposureMask;
245 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
Brian Paul76bc4402000-01-27 16:43:56 +0000246 win = XCreateWindow(dpy, root, 0, 0, width, height,
247 0, visinfo->depth, InputOutput,
248 visinfo->visual, mask, &attr);
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000249
Brian Paul08b3ff12001-04-24 20:57:36 +0000250 ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect );
Brian Paul34fb5db2000-04-22 20:31:23 +0000251 if (!ctx) {
Brian Paul9cff5582000-05-07 18:07:23 +0000252 fprintf(stderr, "Error: glXCreateContext failed\n");
Brian Paul34fb5db2000-04-22 20:31:23 +0000253 XDestroyWindow(dpy, win);
254 return;
255 }
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000256
Brian Paul9cff5582000-05-07 18:07:23 +0000257 if (glXMakeCurrent(dpy, win, ctx)) {
Brian Paul76bc4402000-01-27 16:43:56 +0000258 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);
Brian Paul34fb5db2000-04-22 20:31:23 +0000261 const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR);
Brian Paul76bc4402000-01-27 16:43:56 +0000262 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);
Brian Paul373aea12001-04-02 22:45:07 +0000269 char *displayName = NULL;
270 char *colon = NULL, *period = NULL;
Brian Paul39557c32001-03-23 21:41:44 +0000271#ifdef DO_GLU
Brian Paul76bc4402000-01-27 16:43:56 +0000272 const char *gluVersion = (const char *) gluGetString(GLU_VERSION);
273 const char *gluExtensions = (const char *) gluGetString(GLU_EXTENSIONS);
Brian Paul39557c32001-03-23 21:41:44 +0000274#endif
Brian Paul373aea12001-04-02 22:45:07 +0000275 /* Strip the screen number from the display name, if present. */
Brian Paulf02a5f62002-07-12 15:54:01 +0000276 if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1))) {
Brian Paul373aea12001-04-02 22:45:07 +0000277 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);
Brian Paule691ee22000-05-08 14:53:57 +0000289 printf("direct rendering: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
Brian Paul76bc4402000-01-27 16:43:56 +0000290 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);
Brian Paul34fb5db2000-04-22 20:31:23 +0000294 printf("client glx vendor string: %s\n", clientVendor);
295 printf("client glx version string: %s\n", clientVersion);
Brian Paul76bc4402000-01-27 16:43:56 +0000296 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);
Brian Paul2f7ef5f2002-09-06 03:35:43 +0000305 if (limits)
306 print_limits();
Brian Paul39557c32001-03-23 21:41:44 +0000307#ifdef DO_GLU
Brian Paul76bc4402000-01-27 16:43:56 +0000308 printf("glu version: %s\n", gluVersion);
309 printf("glu extensions:\n");
310 print_extension_list(gluExtensions);
Brian Paul39557c32001-03-23 21:41:44 +0000311#endif
Brian Paul76bc4402000-01-27 16:43:56 +0000312 }
Brian Paul9cff5582000-05-07 18:07:23 +0000313 else {
314 fprintf(stderr, "Error: glXMakeCurrent failed\n");
315 }
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000316
317 glXDestroyContext(dpy, ctx);
318 XDestroyWindow(dpy, win);
Brian Paul76bc4402000-01-27 16:43:56 +0000319}
320
321
322static const char *
323visual_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
344static const char *
345visual_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
366static void
367get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
368 struct visual_attribs *attribs)
369{
Brian Paul25673f02000-03-31 18:17:51 +0000370 const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
371
Brian Paula9c53fa2000-04-03 15:45:34 +0000372 memset(attribs, 0, sizeof(struct visual_attribs));
373
Brian Paul76bc4402000-01-27 16:43:56 +0000374 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
Brian Paula9c53fa2000-04-03 15:45:34 +0000387 if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0)
388 return;
Brian Paul76bc4402000-01-27 16:43:56 +0000389 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
Brian Paule06c7f32000-01-27 16:53:55 +0000406 /* transparent pixel value not implemented yet */
407 attribs->transparent = 0;
408
409 /* multisample tests not implemented yet */
Brian Paul76bc4402000-01-27 16:43:56 +0000410 attribs->numSamples = 0;
411 attribs->numMultisample = 0;
Brian Paul25673f02000-03-31 18:17:51 +0000412
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
Brian Paul76bc4402000-01-27 16:43:56 +0000423}
424
425
426static void
427print_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);
Brian Paul25673f02000-03-31 18:17:51 +0000444#ifdef GLX_EXT_visual_rating
445 if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
Brian Paula9c53fa2000-04-03 15:45:34 +0000446 printf(" visualCaveat=None\n");
Brian Paul25673f02000-03-31 18:17:51 +0000447 else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
Brian Paula9c53fa2000-04-03 15:45:34 +0000448 printf(" visualCaveat=Slow\n");
Brian Paul25673f02000-03-31 18:17:51 +0000449 else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
Brian Paula9c53fa2000-04-03 15:45:34 +0000450 printf(" visualCaveat=Nonconformant\n");
Brian Paul25673f02000-03-31 18:17:51 +0000451#endif
Brian Paula9c53fa2000-04-03 15:45:34 +0000452 printf(" %s\n", attribs->transparent ? "Transparent." : "Opaque.");
Brian Paul76bc4402000-01-27 16:43:56 +0000453}
454
455
456static void
457print_visual_attribs_short_header(void)
458{
Brian Paula9c53fa2000-04-03 15:45:34 +0000459 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");
Brian Paul25673f02000-03-31 18:17:51 +0000461 printf("----------------------------------------------------------------------\n");
Brian Paul76bc4402000-01-27 16:43:56 +0000462}
463
464
465static void
466print_visual_attribs_short(const struct visual_attribs *attribs)
467{
Brian Paula3e44f42002-03-08 19:44:28 +0000468 char *caveat = NULL;
Brian Paul25673f02000-03-31 18:17:51 +0000469#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
Brian Paul76bc4402000-01-27 16:43:56 +0000480 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
Brian Paul25673f02000-03-31 18:17:51 +0000497 printf(" %2d %2d %2d %2d %2d %1d %s\n",
Brian Paul76bc4402000-01-27 16:43:56 +0000498 attribs->accumRedSize, attribs->accumGreenSize,
499 attribs->accumBlueSize, attribs->accumAlphaSize,
Brian Paul25673f02000-03-31 18:17:51 +0000500 attribs->numSamples, attribs->numMultisample,
501 caveat
Brian Paul76bc4402000-01-27 16:43:56 +0000502 );
503}
504
505
506static void
507print_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
515static void
516print_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
543static void
544print_visual_info(Display *dpy, int scrnum, InfoMode mode)
545{
Brian Paulf02a5f62002-07-12 15:54:01 +0000546 XVisualInfo theTemplate;
Brian Paul76bc4402000-01-27 16:43:56 +0000547 XVisualInfo *visuals;
548 int numVisuals;
549 long mask;
550 int i;
551
552 /* get list of all visuals on this screen */
Brian Paulf02a5f62002-07-12 15:54:01 +0000553 theTemplate.screen = scrnum;
Brian Paul76bc4402000-01-27 16:43:56 +0000554 mask = VisualScreenMask;
Brian Paulf02a5f62002-07-12 15:54:01 +0000555 visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
Brian Paul76bc4402000-01-27 16:43:56 +0000556
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
Brian Paul39557c32001-03-23 21:41:44 +0000585/*
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 */
596static void
597mesa_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 */
626static int
627find_best_visual(Display *dpy, int scrnum)
628{
Brian Paulf02a5f62002-07-12 15:54:01 +0000629 XVisualInfo theTemplate;
Brian Paul39557c32001-03-23 21:41:44 +0000630 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 */
Brian Paulf02a5f62002-07-12 15:54:01 +0000637 theTemplate.screen = scrnum;
Brian Paul39557c32001-03-23 21:41:44 +0000638 mask = VisualScreenMask;
Brian Paulf02a5f62002-07-12 15:54:01 +0000639 visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
Brian Paul39557c32001-03-23 21:41:44 +0000640
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
Brian Paul08b3ff12001-04-24 20:57:36 +0000677static void
678usage(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");
Brian Paul2f7ef5f2002-09-06 03:35:43 +0000687 printf("\t-l: Print interesting OpenGLl imits.\n");
Brian Paul08b3ff12001-04-24 20:57:36 +0000688}
689
690
Brian Paul76bc4402000-01-27 16:43:56 +0000691int
692main(int argc, char *argv[])
693{
Alan Hourihanee18599a2001-03-19 13:58:45 +0000694 char *displayName = NULL;
Brian Paul76bc4402000-01-27 16:43:56 +0000695 Display *dpy;
696 int numScreens, scrnum;
697 InfoMode mode = Normal;
Brian Paul39557c32001-03-23 21:41:44 +0000698 GLboolean findBest = GL_FALSE;
Brian Paul2f7ef5f2002-09-06 03:35:43 +0000699 GLboolean limits = GL_FALSE;
Brian Paul08b3ff12001-04-24 20:57:36 +0000700 Bool allowDirect = True;
Brian Paul76bc4402000-01-27 16:43:56 +0000701 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 }
Brian Paul39557c32001-03-23 21:41:44 +0000714 else if (strcmp(argv[i], "-b") == 0) {
715 findBest = GL_TRUE;
716 }
Brian Paul08b3ff12001-04-24 20:57:36 +0000717 else if (strcmp(argv[i], "-i") == 0) {
718 allowDirect = False;
719 }
Brian Paul2f7ef5f2002-09-06 03:35:43 +0000720 else if (strcmp(argv[i], "-l") == 0) {
721 limits = GL_TRUE;
722 }
Brian Paul08b3ff12001-04-24 20:57:36 +0000723 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 }
Brian Paul76bc4402000-01-27 16:43:56 +0000732 }
733
734 dpy = XOpenDisplay(displayName);
735 if (!dpy) {
736 fprintf(stderr, "Error: unable to open display %s\n", displayName);
737 return -1;
738 }
739
Brian Paul39557c32001-03-23 21:41:44 +0000740 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);
Brian Paul373aea12001-04-02 22:45:07 +0000748 print_display_info(dpy);
Brian Paul39557c32001-03-23 21:41:44 +0000749 for (scrnum = 0; scrnum < numScreens; scrnum++) {
750 mesa_hack(dpy, scrnum);
Brian Paul2f7ef5f2002-09-06 03:35:43 +0000751 print_screen_info(dpy, scrnum, allowDirect, limits);
Brian Paul39557c32001-03-23 21:41:44 +0000752 printf("\n");
753 print_visual_info(dpy, scrnum, mode);
754 if (scrnum + 1 < numScreens)
755 printf("\n\n");
756 }
Brian Paul76bc4402000-01-27 16:43:56 +0000757 }
758
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000759 XCloseDisplay(dpy);
760
761 return 0;
762}