blob: 58baf82345fff3449572b5a26bd20c871961e60f [file] [log] [blame]
Brian Paul08b3ff12001-04-24 20:57:36 +00001/* $Id: glxinfo.c,v 1.14 2001/04/24 20:57:36 brianp Exp $ */
Brian Pauld2bfe1e1999-09-16 16:40:46 +00002
3/*
Brian Paul39557c32001-03-23 21:41:44 +00004 * Copyright (C) 1999-2001 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 Paul76bc4402000-01-27 16:43:56 +000032 *
33 * Brian Paul 26 January 2000
34 */
Brian Pauld2bfe1e1999-09-16 16:40:46 +000035
Brian Paul39557c32001-03-23 21:41:44 +000036#define DO_GLU /* may want to remove this for easier XFree86 building? */
Brian Paul76bc4402000-01-27 16:43:56 +000037
38#include <X11/Xlib.h>
39#include <X11/Xutil.h>
Brian Pauld2bfe1e1999-09-16 16:40:46 +000040#include <GL/gl.h>
Brian Paul39557c32001-03-23 21:41:44 +000041#ifdef DO_GLU
Brian Pauld2bfe1e1999-09-16 16:40:46 +000042#include <GL/glu.h>
Brian Paul39557c32001-03-23 21:41:44 +000043#endif
Brian Paul76bc4402000-01-27 16:43:56 +000044#include <GL/glx.h>
Brian Pauld2bfe1e1999-09-16 16:40:46 +000045#include <stdio.h>
Brian Paul76bc4402000-01-27 16:43:56 +000046#include <string.h>
Brian Paul373aea12001-04-02 22:45:07 +000047#include <stdlib.h>
Brian Pauld2bfe1e1999-09-16 16:40:46 +000048
49
Brian Paul39557c32001-03-23 21:41:44 +000050#ifndef GLX_NONE_EXT
51#define GLX_NONE_EXT 0x8000
52#endif
53
54
Brian Paul76bc4402000-01-27 16:43:56 +000055typedef enum
Brian Pauld2bfe1e1999-09-16 16:40:46 +000056{
Brian Paul76bc4402000-01-27 16:43:56 +000057 Normal,
58 Wide,
59 Verbose
60} InfoMode;
Brian Pauld2bfe1e1999-09-16 16:40:46 +000061
Brian Pauld2bfe1e1999-09-16 16:40:46 +000062
Brian Paul76bc4402000-01-27 16:43:56 +000063struct visual_attribs
64{
65 /* X visual attribs */
66 int id;
67 int klass;
68 int depth;
69 int redMask, greenMask, blueMask;
70 int colormapSize;
71 int bitsPerRGB;
Brian Pauld2bfe1e1999-09-16 16:40:46 +000072
Brian Paul76bc4402000-01-27 16:43:56 +000073 /* GL visual attribs */
74 int supportsGL;
75 int transparent;
76 int bufferSize;
77 int level;
78 int rgba;
79 int doubleBuffer;
80 int stereo;
81 int auxBuffers;
82 int redSize, greenSize, blueSize, alphaSize;
83 int depthSize;
84 int stencilSize;
85 int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
86 int numSamples, numMultisample;
Brian Paul25673f02000-03-31 18:17:51 +000087 int visualCaveat;
Brian Paul76bc4402000-01-27 16:43:56 +000088};
89
90
91/*
92 * Print a list of extensions, with word-wrapping.
93 */
94static void
95print_extension_list(const char *ext)
96{
97 const char *indentString = " ";
98 const int indent = 4;
99 const int max = 79;
100 int width, i, j;
101
102 if (!ext || !ext[0])
103 return;
104
105 width = indent;
106 printf(indentString);
107 i = j = 0;
108 while (1) {
109 if (ext[j] == ' ' || ext[j] == 0) {
110 /* found end of an extension name */
111 const int len = j - i;
112 if (width + len > max) {
113 /* start a new line */
114 printf("\n");
115 width = indent;
116 printf(indentString);
117 }
118 /* print the extension name between ext[i] and ext[j] */
119 while (i < j) {
120 printf("%c", ext[i]);
121 i++;
122 }
123 /* either we're all done, or we'll continue with next extension */
124 width += len + 1;
125 if (ext[j] == 0) {
126 break;
127 }
128 else {
129 i++;
130 j++;
Brian Paul7ac43502000-02-23 22:50:35 +0000131 if (ext[j] == 0)
132 break;
Brian Paul76bc4402000-01-27 16:43:56 +0000133 printf(", ");
134 width += 2;
135 }
136 }
137 j++;
138 }
139 printf("\n");
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000140}
141
142
Brian Paul76bc4402000-01-27 16:43:56 +0000143static void
Brian Paul373aea12001-04-02 22:45:07 +0000144print_display_info(Display *dpy)
145{
146 printf("name of display: %s\n", DisplayString(dpy));
147}
148
149
150static void
Brian Paul08b3ff12001-04-24 20:57:36 +0000151print_screen_info(Display *dpy, int scrnum, Bool allowDirect)
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000152{
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000153 Window win;
Brian Paul8460cc92000-02-02 20:57:51 +0000154 int attribSingle[] = {
155 GLX_RGBA,
156 GLX_RED_SIZE, 1,
157 GLX_GREEN_SIZE, 1,
158 GLX_BLUE_SIZE, 1,
159 None };
160 int attribDouble[] = {
161 GLX_RGBA,
162 GLX_RED_SIZE, 1,
163 GLX_GREEN_SIZE, 1,
164 GLX_BLUE_SIZE, 1,
165 GLX_DOUBLEBUFFER,
166 None };
167
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000168 XSetWindowAttributes attr;
169 unsigned long mask;
170 Window root;
171 GLXContext ctx;
172 XVisualInfo *visinfo;
173 int width = 100, height = 100;
174
Brian Paul76bc4402000-01-27 16:43:56 +0000175 root = RootWindow(dpy, scrnum);
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000176
Brian Paul8460cc92000-02-02 20:57:51 +0000177 visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000178 if (!visinfo) {
Brian Paul8460cc92000-02-02 20:57:51 +0000179 visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
180 if (!visinfo) {
Brian Paul9cff5582000-05-07 18:07:23 +0000181 fprintf(stderr, "Error: couldn't find RGB GLX visual\n");
Brian Paul8460cc92000-02-02 20:57:51 +0000182 return;
183 }
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000184 }
185
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000186 attr.background_pixel = 0;
187 attr.border_pixel = 0;
Brian Paul9cff5582000-05-07 18:07:23 +0000188 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000189 attr.event_mask = StructureNotifyMask | ExposureMask;
190 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
Brian Paul76bc4402000-01-27 16:43:56 +0000191 win = XCreateWindow(dpy, root, 0, 0, width, height,
192 0, visinfo->depth, InputOutput,
193 visinfo->visual, mask, &attr);
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000194
Brian Paul08b3ff12001-04-24 20:57:36 +0000195 ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect );
Brian Paul34fb5db2000-04-22 20:31:23 +0000196 if (!ctx) {
Brian Paul9cff5582000-05-07 18:07:23 +0000197 fprintf(stderr, "Error: glXCreateContext failed\n");
Brian Paul34fb5db2000-04-22 20:31:23 +0000198 XDestroyWindow(dpy, win);
199 return;
200 }
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000201
Brian Paul9cff5582000-05-07 18:07:23 +0000202 if (glXMakeCurrent(dpy, win, ctx)) {
Brian Paul76bc4402000-01-27 16:43:56 +0000203 const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR);
204 const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION);
205 const char *serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS);
Brian Paul34fb5db2000-04-22 20:31:23 +0000206 const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR);
Brian Paul76bc4402000-01-27 16:43:56 +0000207 const char *clientVersion = glXGetClientString(dpy, GLX_VERSION);
208 const char *clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS);
209 const char *glxExtensions = glXQueryExtensionsString(dpy, scrnum);
210 const char *glVendor = (const char *) glGetString(GL_VENDOR);
211 const char *glRenderer = (const char *) glGetString(GL_RENDERER);
212 const char *glVersion = (const char *) glGetString(GL_VERSION);
213 const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);
Brian Paul373aea12001-04-02 22:45:07 +0000214 char *displayName = NULL;
215 char *colon = NULL, *period = NULL;
Brian Paul39557c32001-03-23 21:41:44 +0000216#ifdef DO_GLU
Brian Paul76bc4402000-01-27 16:43:56 +0000217 const char *gluVersion = (const char *) gluGetString(GLU_VERSION);
218 const char *gluExtensions = (const char *) gluGetString(GLU_EXTENSIONS);
Brian Paul39557c32001-03-23 21:41:44 +0000219#endif
Brian Paul373aea12001-04-02 22:45:07 +0000220 /* Strip the screen number from the display name, if present. */
221 if (!(displayName = malloc(strlen(DisplayString(dpy)) + 1))) {
222 fprintf(stderr, "Error: malloc() failed\n");
223 exit(1);
224 }
225 strcpy(displayName, DisplayString(dpy));
226 colon = strrchr(displayName, ':');
227 if (colon) {
228 period = strchr(colon, '.');
229 if (period)
230 *period = '\0';
231 }
232 printf("display: %s screen: %d\n", displayName, scrnum);
233 free(displayName);
Brian Paule691ee22000-05-08 14:53:57 +0000234 printf("direct rendering: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
Brian Paul76bc4402000-01-27 16:43:56 +0000235 printf("server glx vendor string: %s\n", serverVendor);
236 printf("server glx version string: %s\n", serverVersion);
237 printf("server glx extensions:\n");
238 print_extension_list(serverExtensions);
Brian Paul34fb5db2000-04-22 20:31:23 +0000239 printf("client glx vendor string: %s\n", clientVendor);
240 printf("client glx version string: %s\n", clientVersion);
Brian Paul76bc4402000-01-27 16:43:56 +0000241 printf("client glx extensions:\n");
242 print_extension_list(clientExtensions);
243 printf("GLX extensions:\n");
244 print_extension_list(glxExtensions);
245 printf("OpenGL vendor string: %s\n", glVendor);
246 printf("OpenGL renderer string: %s\n", glRenderer);
247 printf("OpenGL version string: %s\n", glVersion);
248 printf("OpenGL extensions:\n");
249 print_extension_list(glExtensions);
Brian Paul39557c32001-03-23 21:41:44 +0000250#ifdef DO_GLU
Brian Paul76bc4402000-01-27 16:43:56 +0000251 printf("glu version: %s\n", gluVersion);
252 printf("glu extensions:\n");
253 print_extension_list(gluExtensions);
Brian Paul39557c32001-03-23 21:41:44 +0000254#endif
Brian Paul76bc4402000-01-27 16:43:56 +0000255 }
Brian Paul9cff5582000-05-07 18:07:23 +0000256 else {
257 fprintf(stderr, "Error: glXMakeCurrent failed\n");
258 }
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000259
260 glXDestroyContext(dpy, ctx);
261 XDestroyWindow(dpy, win);
Brian Paul76bc4402000-01-27 16:43:56 +0000262}
263
264
265static const char *
266visual_class_name(int cls)
267{
268 switch (cls) {
269 case StaticColor:
270 return "StaticColor";
271 case PseudoColor:
272 return "PseudoColor";
273 case StaticGray:
274 return "StaticGray";
275 case GrayScale:
276 return "GrayScale";
277 case TrueColor:
278 return "TrueColor";
279 case DirectColor:
280 return "DirectColor";
281 default:
282 return "";
283 }
284}
285
286
287static const char *
288visual_class_abbrev(int cls)
289{
290 switch (cls) {
291 case StaticColor:
292 return "sc";
293 case PseudoColor:
294 return "pc";
295 case StaticGray:
296 return "sg";
297 case GrayScale:
298 return "gs";
299 case TrueColor:
300 return "tc";
301 case DirectColor:
302 return "dc";
303 default:
304 return "";
305 }
306}
307
308
309static void
310get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
311 struct visual_attribs *attribs)
312{
Brian Paul25673f02000-03-31 18:17:51 +0000313 const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
314
Brian Paula9c53fa2000-04-03 15:45:34 +0000315 memset(attribs, 0, sizeof(struct visual_attribs));
316
Brian Paul76bc4402000-01-27 16:43:56 +0000317 attribs->id = vInfo->visualid;
318#if defined(__cplusplus) || defined(c_plusplus)
319 attribs->klass = vInfo->c_class;
320#else
321 attribs->klass = vInfo->class;
322#endif
323 attribs->depth = vInfo->depth;
324 attribs->redMask = vInfo->red_mask;
325 attribs->greenMask = vInfo->green_mask;
326 attribs->blueMask = vInfo->blue_mask;
327 attribs->colormapSize = vInfo->colormap_size;
328 attribs->bitsPerRGB = vInfo->bits_per_rgb;
329
Brian Paula9c53fa2000-04-03 15:45:34 +0000330 if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0)
331 return;
Brian Paul76bc4402000-01-27 16:43:56 +0000332 glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
333 glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
334 glXGetConfig(dpy, vInfo, GLX_RGBA, &attribs->rgba);
335 glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
336 glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
337 glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
338 glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
339 glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
340 glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
341 glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
342 glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
343 glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
344 glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
345 glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
346 glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
347 glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
348
Brian Paule06c7f32000-01-27 16:53:55 +0000349 /* transparent pixel value not implemented yet */
350 attribs->transparent = 0;
351
352 /* multisample tests not implemented yet */
Brian Paul76bc4402000-01-27 16:43:56 +0000353 attribs->numSamples = 0;
354 attribs->numMultisample = 0;
Brian Paul25673f02000-03-31 18:17:51 +0000355
356#if defined(GLX_EXT_visual_rating)
357 if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
358 glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
359 }
360 else {
361 attribs->visualCaveat = GLX_NONE_EXT;
362 }
363#else
364 attribs->visualCaveat = 0;
365#endif
Brian Paul76bc4402000-01-27 16:43:56 +0000366}
367
368
369static void
370print_visual_attribs_verbose(const struct visual_attribs *attribs)
371{
372 printf("Visual ID: %x depth=%d class=%s\n",
373 attribs->id, attribs->depth, visual_class_name(attribs->klass));
374 printf(" bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n",
375 attribs->bufferSize, attribs->level, attribs->rgba ? "rgba" : "ci",
376 attribs->doubleBuffer, attribs->stereo);
377 printf(" rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
378 attribs->redSize, attribs->greenSize,
379 attribs->blueSize, attribs->alphaSize);
380 printf(" auxBuffers=%d depthSize=%d stencilSize=%d\n",
381 attribs->auxBuffers, attribs->depthSize, attribs->stencilSize);
382 printf(" accum: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
383 attribs->accumRedSize, attribs->accumGreenSize,
384 attribs->accumBlueSize, attribs->accumAlphaSize);
385 printf(" multiSample=%d multiSampleBuffers=%d\n",
386 attribs->numSamples, attribs->numMultisample);
Brian Paul25673f02000-03-31 18:17:51 +0000387#ifdef GLX_EXT_visual_rating
388 if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
Brian Paula9c53fa2000-04-03 15:45:34 +0000389 printf(" visualCaveat=None\n");
Brian Paul25673f02000-03-31 18:17:51 +0000390 else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
Brian Paula9c53fa2000-04-03 15:45:34 +0000391 printf(" visualCaveat=Slow\n");
Brian Paul25673f02000-03-31 18:17:51 +0000392 else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
Brian Paula9c53fa2000-04-03 15:45:34 +0000393 printf(" visualCaveat=Nonconformant\n");
Brian Paul25673f02000-03-31 18:17:51 +0000394#endif
Brian Paula9c53fa2000-04-03 15:45:34 +0000395 printf(" %s\n", attribs->transparent ? "Transparent." : "Opaque.");
Brian Paul76bc4402000-01-27 16:43:56 +0000396}
397
398
399static void
400print_visual_attribs_short_header(void)
401{
Brian Paula9c53fa2000-04-03 15:45:34 +0000402 printf(" visual x bf lv rg d st colorbuffer ax dp st accumbuffer ms cav\n");
403 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 +0000404 printf("----------------------------------------------------------------------\n");
Brian Paul76bc4402000-01-27 16:43:56 +0000405}
406
407
408static void
409print_visual_attribs_short(const struct visual_attribs *attribs)
410{
Brian Paul25673f02000-03-31 18:17:51 +0000411 char *caveat;
412#ifdef GLX_EXT_visual_rating
413 if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
414 caveat = "None";
415 else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
416 caveat = "Slow";
417 else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
418 caveat = "Ncon";
419#else
420 caveat = "None";
421#endif
422
Brian Paul76bc4402000-01-27 16:43:56 +0000423 printf("0x%2x %2d %2s %2d %2d %2d %1s %2s %2s %2d %2d %2d %2d %2d %2d %2d",
424 attribs->id,
425 attribs->depth,
426 visual_class_abbrev(attribs->klass),
427 attribs->transparent,
428 attribs->bufferSize,
429 attribs->level,
430 attribs->rgba ? "r" : "c",
431 attribs->doubleBuffer ? "y" : ".",
432 attribs->stereo ? "y" : ".",
433 attribs->redSize, attribs->greenSize,
434 attribs->blueSize, attribs->alphaSize,
435 attribs->auxBuffers,
436 attribs->depthSize,
437 attribs->stencilSize
438 );
439
Brian Paul25673f02000-03-31 18:17:51 +0000440 printf(" %2d %2d %2d %2d %2d %1d %s\n",
Brian Paul76bc4402000-01-27 16:43:56 +0000441 attribs->accumRedSize, attribs->accumGreenSize,
442 attribs->accumBlueSize, attribs->accumAlphaSize,
Brian Paul25673f02000-03-31 18:17:51 +0000443 attribs->numSamples, attribs->numMultisample,
444 caveat
Brian Paul76bc4402000-01-27 16:43:56 +0000445 );
446}
447
448
449static void
450print_visual_attribs_long_header(void)
451{
452 printf("Vis Vis Visual Trans buff lev render DB ste r g b a aux dep ste accum buffers MS MS\n");
453 printf(" ID Depth Type parent size el type reo sz sz sz sz buf th ncl r g b a num bufs\n");
454 printf("----------------------------------------------------------------------------------------------------\n");
455}
456
457
458static void
459print_visual_attribs_long(const struct visual_attribs *attribs)
460{
461 printf("0x%2x %2d %-11s %2d %2d %2d %4s %3d %3d %3d %3d %3d %3d",
462 attribs->id,
463 attribs->depth,
464 visual_class_name(attribs->klass),
465 attribs->transparent,
466 attribs->bufferSize,
467 attribs->level,
468 attribs->rgba ? "rgba" : "ci ",
469 attribs->doubleBuffer,
470 attribs->stereo,
471 attribs->redSize, attribs->greenSize,
472 attribs->blueSize, attribs->alphaSize
473 );
474
475 printf(" %3d %4d %2d %3d %3d %3d %3d %2d %2d\n",
476 attribs->auxBuffers,
477 attribs->depthSize,
478 attribs->stencilSize,
479 attribs->accumRedSize, attribs->accumGreenSize,
480 attribs->accumBlueSize, attribs->accumAlphaSize,
481 attribs->numSamples, attribs->numMultisample
482 );
483}
484
485
486static void
487print_visual_info(Display *dpy, int scrnum, InfoMode mode)
488{
489 XVisualInfo template;
490 XVisualInfo *visuals;
491 int numVisuals;
492 long mask;
493 int i;
494
495 /* get list of all visuals on this screen */
496 template.screen = scrnum;
497 mask = VisualScreenMask;
498 visuals = XGetVisualInfo(dpy, mask, &template, &numVisuals);
499
500 if (mode == Verbose) {
501 for (i = 0; i < numVisuals; i++) {
502 struct visual_attribs attribs;
503 get_visual_attribs(dpy, &visuals[i], &attribs);
504 print_visual_attribs_verbose(&attribs);
505 }
506 }
507 else if (mode == Normal) {
508 print_visual_attribs_short_header();
509 for (i = 0; i < numVisuals; i++) {
510 struct visual_attribs attribs;
511 get_visual_attribs(dpy, &visuals[i], &attribs);
512 print_visual_attribs_short(&attribs);
513 }
514 }
515 else if (mode == Wide) {
516 print_visual_attribs_long_header();
517 for (i = 0; i < numVisuals; i++) {
518 struct visual_attribs attribs;
519 get_visual_attribs(dpy, &visuals[i], &attribs);
520 print_visual_attribs_long(&attribs);
521 }
522 }
523
524 XFree(visuals);
525}
526
527
Brian Paul39557c32001-03-23 21:41:44 +0000528/*
529 * Stand-alone Mesa doesn't really implement the GLX protocol so it
530 * doesn't really know the GLX attributes associated with an X visual.
531 * The first time a visual is presented to Mesa's pseudo-GLX it
532 * attaches ancilliary buffers to it (like depth and stencil).
533 * But that usually only works if glXChooseVisual is used.
534 * This function calls glXChooseVisual() to sort of "prime the pump"
535 * for Mesa's GLX so that the visuals that get reported actually
536 * reflect what applications will see.
537 * This has no effect when using true GLX.
538 */
539static void
540mesa_hack(Display *dpy, int scrnum)
541{
542 static int attribs[] = {
543 GLX_RGBA,
544 GLX_RED_SIZE, 1,
545 GLX_GREEN_SIZE, 1,
546 GLX_BLUE_SIZE, 1,
547 GLX_DEPTH_SIZE, 1,
548 GLX_STENCIL_SIZE, 1,
549 GLX_ACCUM_RED_SIZE, 1,
550 GLX_ACCUM_GREEN_SIZE, 1,
551 GLX_ACCUM_BLUE_SIZE, 1,
552 GLX_ACCUM_ALPHA_SIZE, 1,
553 GLX_DOUBLEBUFFER,
554 None
555 };
556 XVisualInfo *visinfo;
557
558 visinfo = glXChooseVisual(dpy, scrnum, attribs);
559 if (visinfo)
560 XFree(visinfo);
561}
562
563
564/*
565 * Examine all visuals to find the so-called best one.
566 * We prefer deepest RGBA buffer with depth, stencil and accum
567 * that has no caveats.
568 */
569static int
570find_best_visual(Display *dpy, int scrnum)
571{
572 XVisualInfo template;
573 XVisualInfo *visuals;
574 int numVisuals;
575 long mask;
576 int i;
577 struct visual_attribs bestVis;
578
579 /* get list of all visuals on this screen */
580 template.screen = scrnum;
581 mask = VisualScreenMask;
582 visuals = XGetVisualInfo(dpy, mask, &template, &numVisuals);
583
584 /* init bestVis with first visual info */
585 get_visual_attribs(dpy, &visuals[0], &bestVis);
586
587 /* try to find a "better" visual */
588 for (i = 1; i < numVisuals; i++) {
589 struct visual_attribs vis;
590
591 get_visual_attribs(dpy, &visuals[i], &vis);
592
593 /* always skip visuals with caveats */
594 if (vis.visualCaveat != GLX_NONE_EXT)
595 continue;
596
597 /* see if this vis is better than bestVis */
598 if ((!bestVis.supportsGL && vis.supportsGL) ||
599 (bestVis.visualCaveat != GLX_NONE_EXT) ||
600 (!bestVis.rgba && vis.rgba) ||
601 (!bestVis.doubleBuffer && vis.doubleBuffer) ||
602 (bestVis.redSize < vis.redSize) ||
603 (bestVis.greenSize < vis.greenSize) ||
604 (bestVis.blueSize < vis.blueSize) ||
605 (bestVis.alphaSize < vis.alphaSize) ||
606 (bestVis.depthSize < vis.depthSize) ||
607 (bestVis.stencilSize < vis.stencilSize) ||
608 (bestVis.accumRedSize < vis.accumRedSize)) {
609 /* found a better visual */
610 bestVis = vis;
611 }
612 }
613
614 XFree(visuals);
615
616 return bestVis.id;
617}
618
619
Brian Paul08b3ff12001-04-24 20:57:36 +0000620static void
621usage(void)
622{
623 printf("Usage: glxinfo [-v] [-t] [-h] [-i] [-b] [-display <dname>]\n");
624 printf("\t-v: Print visuals info in verbose form.\n");
625 printf("\t-t: Print verbose table.\n");
626 printf("\t-display <dname>: Print GLX visuals on specified server.\n");
627 printf("\t-h: This information.\n");
628 printf("\t-i: Force an indirect rendering context.\n");
629 printf("\t-b: Find the 'best' visual and print it's number.\n");
630}
631
632
Brian Paul76bc4402000-01-27 16:43:56 +0000633int
634main(int argc, char *argv[])
635{
Alan Hourihanee18599a2001-03-19 13:58:45 +0000636 char *displayName = NULL;
Brian Paul76bc4402000-01-27 16:43:56 +0000637 Display *dpy;
638 int numScreens, scrnum;
639 InfoMode mode = Normal;
Brian Paul39557c32001-03-23 21:41:44 +0000640 GLboolean findBest = GL_FALSE;
Brian Paul08b3ff12001-04-24 20:57:36 +0000641 Bool allowDirect = True;
Brian Paul76bc4402000-01-27 16:43:56 +0000642 int i;
643
644 for (i = 1; i < argc; i++) {
645 if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
646 displayName = argv[i + 1];
647 i++;
648 }
649 else if (strcmp(argv[i], "-t") == 0) {
650 mode = Wide;
651 }
652 else if (strcmp(argv[i], "-v") == 0) {
653 mode = Verbose;
654 }
Brian Paul39557c32001-03-23 21:41:44 +0000655 else if (strcmp(argv[i], "-b") == 0) {
656 findBest = GL_TRUE;
657 }
Brian Paul08b3ff12001-04-24 20:57:36 +0000658 else if (strcmp(argv[i], "-i") == 0) {
659 allowDirect = False;
660 }
661 else if (strcmp(argv[i], "-h") == 0) {
662 usage();
663 return 0;
664 }
665 else {
666 printf("Unknown option `%s'\n", argv[i]);
667 usage();
668 return 0;
669 }
Brian Paul76bc4402000-01-27 16:43:56 +0000670 }
671
672 dpy = XOpenDisplay(displayName);
673 if (!dpy) {
674 fprintf(stderr, "Error: unable to open display %s\n", displayName);
675 return -1;
676 }
677
Brian Paul39557c32001-03-23 21:41:44 +0000678 if (findBest) {
679 int b;
680 mesa_hack(dpy, 0);
681 b = find_best_visual(dpy, 0);
682 printf("%d\n", b);
683 }
684 else {
685 numScreens = ScreenCount(dpy);
Brian Paul373aea12001-04-02 22:45:07 +0000686 print_display_info(dpy);
Brian Paul39557c32001-03-23 21:41:44 +0000687 for (scrnum = 0; scrnum < numScreens; scrnum++) {
688 mesa_hack(dpy, scrnum);
Brian Paul08b3ff12001-04-24 20:57:36 +0000689 print_screen_info(dpy, scrnum, allowDirect);
Brian Paul39557c32001-03-23 21:41:44 +0000690 printf("\n");
691 print_visual_info(dpy, scrnum, mode);
692 if (scrnum + 1 < numScreens)
693 printf("\n\n");
694 }
Brian Paul76bc4402000-01-27 16:43:56 +0000695 }
696
Brian Pauld2bfe1e1999-09-16 16:40:46 +0000697 XCloseDisplay(dpy);
698
699 return 0;
700}