glxinfo: Add support for GLX_MESA_query_renderer
[mesa-demos.git] / src / xdemos / glxinfo.c
blobc3e4ca3bd46f497a2b16a88e591a71a5a8e30eeb
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:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
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.
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 only print ID of "best" visual on screen 0
30 * -i use indirect rendering connection only
31 * -l print interesting OpenGL limits (added 5 Sep 2002)
33 * Brian Paul 26 January 2000
36 #define GLX_GLXEXT_PROTOTYPES
37 #define GL_GLEXT_PROTOTYPES
39 #include <assert.h>
40 #include <X11/Xlib.h>
41 #include <X11/Xutil.h>
42 #include <GL/gl.h>
43 #include <GL/glx.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include "glinfo_common.h"
50 #ifndef GLX_NONE_EXT
51 #define GLX_NONE_EXT 0x8000
52 #endif
54 #ifndef GLX_TRANSPARENT_RGB
55 #define GLX_TRANSPARENT_RGB 0x8008
56 #endif
58 #ifndef GLX_RGBA_BIT
59 #define GLX_RGBA_BIT 0x00000001
60 #endif
62 #ifndef GLX_COLOR_INDEX_BIT
63 #define GLX_COLOR_INDEX_BIT 0x00000002
64 #endif
67 struct visual_attribs
69 /* X visual attribs */
70 int id; /* May be visual ID or FBConfig ID */
71 int vis_id; /* Visual ID. Only set for FBConfigs */
72 int klass;
73 int depth;
74 int redMask, greenMask, blueMask;
75 int colormapSize;
76 int bitsPerRGB;
78 /* GL visual attribs */
79 int supportsGL;
80 int drawableType;
81 int transparentType;
82 int transparentRedValue;
83 int transparentGreenValue;
84 int transparentBlueValue;
85 int transparentAlphaValue;
86 int transparentIndexValue;
87 int bufferSize;
88 int level;
89 int render_type;
90 int doubleBuffer;
91 int stereo;
92 int auxBuffers;
93 int redSize, greenSize, blueSize, alphaSize;
94 int depthSize;
95 int stencilSize;
96 int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
97 int numSamples, numMultisample;
98 int visualCaveat;
99 int floatComponents;
100 int packedfloatComponents;
101 int srgb;
106 * Version of the context that was created
108 * 20, 21, 30, 31, 32, etc.
110 static int version;
113 * GL Error checking/warning.
115 static void
116 CheckError(int line)
118 int n;
119 n = glGetError();
120 if (n)
121 printf("Warning: GL error 0x%x at line %d\n", n, line);
125 static void
126 print_display_info(Display *dpy)
128 printf("name of display: %s\n", DisplayString(dpy));
133 * Choose a simple FB Config.
135 static GLXFBConfig *
136 choose_fb_config(Display *dpy, int scrnum)
138 int fbAttribSingle[] = {
139 GLX_RENDER_TYPE, GLX_RGBA_BIT,
140 GLX_RED_SIZE, 1,
141 GLX_GREEN_SIZE, 1,
142 GLX_BLUE_SIZE, 1,
143 GLX_DOUBLEBUFFER, False,
144 None };
145 int fbAttribDouble[] = {
146 GLX_RENDER_TYPE, GLX_RGBA_BIT,
147 GLX_RED_SIZE, 1,
148 GLX_GREEN_SIZE, 1,
149 GLX_BLUE_SIZE, 1,
150 GLX_DOUBLEBUFFER, True,
151 None };
152 GLXFBConfig *configs;
153 int nConfigs;
155 configs = glXChooseFBConfig(dpy, scrnum, fbAttribSingle, &nConfigs);
156 if (!configs)
157 configs = glXChooseFBConfig(dpy, scrnum, fbAttribDouble, &nConfigs);
159 return configs;
163 static Bool CreateContextErrorFlag;
165 static int
166 create_context_error_handler(Display *dpy, XErrorEvent *error)
168 (void) dpy;
169 (void) error->error_code;
170 CreateContextErrorFlag = True;
171 return 0;
176 * Try to create a GLX context of the given version with flags/options.
177 * Note: A version number is required in order to get a core profile
178 * (at least w/ NVIDIA).
180 static GLXContext
181 create_context_flags(Display *dpy, GLXFBConfig fbconfig, int major, int minor,
182 int contextFlags, int profileMask, Bool direct)
184 #ifdef GLX_ARB_create_context
185 static PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB_func = 0;
186 static Bool firstCall = True;
187 int (*old_handler)(Display *, XErrorEvent *);
188 GLXContext context;
189 int attribs[20];
190 int n = 0;
192 if (firstCall) {
193 /* See if we have GLX_ARB_create_context_profile and get pointer to
194 * glXCreateContextAttribsARB() function.
196 const char *glxExt = glXQueryExtensionsString(dpy, 0);
197 if (extension_supported("GLX_ARB_create_context_profile", glxExt)) {
198 glXCreateContextAttribsARB_func = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
199 glXGetProcAddress((const GLubyte *) "glXCreateContextAttribsARB");
201 firstCall = False;
204 if (!glXCreateContextAttribsARB_func)
205 return 0;
207 /* setup attribute array */
208 if (major) {
209 attribs[n++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
210 attribs[n++] = major;
211 attribs[n++] = GLX_CONTEXT_MINOR_VERSION_ARB;
212 attribs[n++] = minor;
214 if (contextFlags) {
215 attribs[n++] = GLX_CONTEXT_FLAGS_ARB;
216 attribs[n++] = contextFlags;
218 #ifdef GLX_ARB_create_context_profile
219 if (profileMask) {
220 attribs[n++] = GLX_CONTEXT_PROFILE_MASK_ARB;
221 attribs[n++] = profileMask;
223 #endif
224 attribs[n++] = 0;
226 /* install X error handler */
227 old_handler = XSetErrorHandler(create_context_error_handler);
228 CreateContextErrorFlag = False;
230 /* try creating context */
231 context = glXCreateContextAttribsARB_func(dpy,
232 fbconfig,
233 0, /* share_context */
234 direct,
235 attribs);
237 /* restore error handler */
238 XSetErrorHandler(old_handler);
240 if (CreateContextErrorFlag)
241 context = 0;
243 if (context && direct) {
244 if (!glXIsDirect(dpy, context)) {
245 glXDestroyContext(dpy, context);
246 return 0;
250 return context;
251 #else
252 return 0;
253 #endif
258 * Try to create a GLX context of the newest version.
260 static GLXContext
261 create_context_with_config(Display *dpy, GLXFBConfig config,
262 Bool coreProfile, Bool es2Profile, Bool direct)
264 GLXContext ctx = 0;
266 if (coreProfile) {
267 /* Try to create a core profile, starting with the newest version of
268 * GL that we're aware of. If we don't specify the version
270 int i;
271 for (i = 0; gl_versions[i].major > 0; i++) {
272 /* don't bother below GL 3.0 */
273 if (gl_versions[i].major == 3 &&
274 gl_versions[i].minor == 0)
275 return 0;
276 ctx = create_context_flags(dpy, config,
277 gl_versions[i].major,
278 gl_versions[i].minor,
279 0x0,
280 GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
281 direct);
282 if (ctx)
283 return ctx;
285 /* couldn't get core profile context */
286 return 0;
289 if (es2Profile) {
290 #ifdef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
291 if (extension_supported("GLX_EXT_create_context_es2_profile",
292 glXQueryExtensionsString(dpy, 0))) {
293 ctx = create_context_flags(dpy, config, 2, 0, 0x0,
294 GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
295 direct);
296 return ctx;
298 #endif
299 return 0;
302 /* GLX should return a context of the latest GL version that supports
303 * the full profile.
305 ctx = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, direct);
307 /* make sure the context is direct, if direct was requested */
308 if (ctx && direct) {
309 if (!glXIsDirect(dpy, ctx)) {
310 glXDestroyContext(dpy, ctx);
311 return 0;
315 return ctx;
319 static XVisualInfo *
320 choose_xvisinfo(Display *dpy, int scrnum)
322 int attribSingle[] = {
323 GLX_RGBA,
324 GLX_RED_SIZE, 1,
325 GLX_GREEN_SIZE, 1,
326 GLX_BLUE_SIZE, 1,
327 None };
328 int attribDouble[] = {
329 GLX_RGBA,
330 GLX_RED_SIZE, 1,
331 GLX_GREEN_SIZE, 1,
332 GLX_BLUE_SIZE, 1,
333 GLX_DOUBLEBUFFER,
334 None };
335 XVisualInfo *visinfo;
337 visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
338 if (!visinfo)
339 visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
341 return visinfo;
345 static void
346 query_renderer(void)
348 #ifdef GLX_MESA_query_renderer
349 PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC queryInteger;
350 PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC queryString;
351 unsigned int v[3];
353 queryInteger = (PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC)
354 glXGetProcAddressARB((const GLubyte *)
355 "glXQueryCurrentRendererIntegerMESA");
356 queryString = (PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC)
357 glXGetProcAddressARB((const GLubyte *)
358 "glXQueryCurrentRendererStringMESA");
360 printf("Extended renderer info (GLX_MESA_query_renderer):\n");
361 queryInteger(GLX_RENDERER_VENDOR_ID_MESA, v);
362 printf(" Vendor: %s (0x%x)\n",
363 queryString(GLX_RENDERER_VENDOR_ID_MESA), *v);
364 queryInteger(GLX_RENDERER_DEVICE_ID_MESA, v);
365 printf(" Device: %s (0x%x)\n",
366 queryString(GLX_RENDERER_DEVICE_ID_MESA), *v);
367 queryInteger(GLX_RENDERER_VERSION_MESA, v);
368 printf(" Version: %d.%d.%d\n", v[0], v[1], v[2]);
369 queryInteger(GLX_RENDERER_ACCELERATED_MESA, v);
370 printf(" Accelerated: %s\n", *v ? "yes" : "no");
371 queryInteger(GLX_RENDERER_VIDEO_MEMORY_MESA, v);
372 printf(" Video memory: %dMB\n", *v);
373 queryInteger(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA, v);
374 printf(" Unified memory: %s\n", *v ? "yes" : "no");
375 queryInteger(GLX_RENDERER_PREFERRED_PROFILE_MESA, v);
376 printf(" Preferred profile: %s (0x%x)\n",
377 *v == GLX_CONTEXT_CORE_PROFILE_BIT_ARB ? "core" :
378 *v == GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ? "compat" :
379 "unknown", *v);
380 queryInteger(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA, v);
381 printf(" Max core profile version: %d.%d\n", v[0], v[1]);
382 queryInteger(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA, v);
383 printf(" Max compat profile version: %d.%d\n", v[0], v[1]);
384 queryInteger(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA, v);
385 printf(" Max GLES1 profile version: %d.%d\n", v[0], v[1]);
386 queryInteger(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA, v);
387 printf(" Max GLES[23] profile version: %d.%d\n", v[0], v[1]);
388 #endif
392 static Bool
393 print_screen_info(Display *dpy, int scrnum, Bool allowDirect,
394 Bool coreProfile, Bool es2Profile, Bool limits,
395 Bool singleLine, Bool coreWorked)
397 Window win;
398 XSetWindowAttributes attr;
399 unsigned long mask;
400 Window root;
401 GLXContext ctx = NULL;
402 XVisualInfo *visinfo;
403 int width = 100, height = 100;
404 GLXFBConfig *fbconfigs;
405 const char *oglstring = coreProfile ? "OpenGL core profile" :
406 es2Profile ? "OpenGL ES profile" : "OpenGL";
408 root = RootWindow(dpy, scrnum);
411 * Choose FBConfig or XVisualInfo and create a context.
413 fbconfigs = choose_fb_config(dpy, scrnum);
414 if (fbconfigs) {
415 ctx = create_context_with_config(dpy, fbconfigs[0],
416 coreProfile, es2Profile, allowDirect);
417 if (!ctx && allowDirect && !coreProfile) {
418 /* try indirect */
419 ctx = create_context_with_config(dpy, fbconfigs[0],
420 coreProfile, es2Profile, False);
423 visinfo = glXGetVisualFromFBConfig(dpy, fbconfigs[0]);
424 XFree(fbconfigs);
426 else if (!coreProfile && !es2Profile) {
427 visinfo = choose_xvisinfo(dpy, scrnum);
428 if (visinfo)
429 ctx = glXCreateContext(dpy, visinfo, NULL, allowDirect);
430 } else
431 visinfo = NULL;
433 if (!visinfo && !coreProfile && !es2Profile) {
434 fprintf(stderr, "Error: couldn't find RGB GLX visual or fbconfig\n");
435 return False;
438 if (!ctx) {
439 if (!coreProfile && !es2Profile)
440 fprintf(stderr, "Error: glXCreateContext failed\n");
441 XFree(visinfo);
442 return False;
446 * Create a window so that we can just bind the context.
448 attr.background_pixel = 0;
449 attr.border_pixel = 0;
450 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
451 attr.event_mask = StructureNotifyMask | ExposureMask;
452 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
453 win = XCreateWindow(dpy, root, 0, 0, width, height,
454 0, visinfo->depth, InputOutput,
455 visinfo->visual, mask, &attr);
457 if (glXMakeCurrent(dpy, win, ctx)) {
458 const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR);
459 const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION);
460 const char *serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS);
461 const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR);
462 const char *clientVersion = glXGetClientString(dpy, GLX_VERSION);
463 const char *clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS);
464 const char *glxExtensions = glXQueryExtensionsString(dpy, scrnum);
465 const char *glVendor = (const char *) glGetString(GL_VENDOR);
466 const char *glRenderer = (const char *) glGetString(GL_RENDERER);
467 const char *glVersion = (const char *) glGetString(GL_VERSION);
468 char *glExtensions;
469 int glxVersionMajor;
470 int glxVersionMinor;
471 char *displayName = NULL;
472 char *colon = NULL, *period = NULL;
473 struct ext_functions extfuncs;
475 CheckError(__LINE__);
477 /* Get some ext functions */
478 extfuncs.GetProgramivARB = (GETPROGRAMIVARBPROC)
479 glXGetProcAddressARB((GLubyte *) "glGetProgramivARB");
480 extfuncs.GetStringi = (GETSTRINGIPROC)
481 glXGetProcAddressARB((GLubyte *) "glGetStringi");
482 extfuncs.GetConvolutionParameteriv = (GETCONVOLUTIONPARAMETERIVPROC)
483 glXGetProcAddressARB((GLubyte *) "glGetConvolutionParameteriv");
485 /* Get list of GL extensions */
486 if (coreProfile) {
487 glExtensions = build_core_profile_extension_list(&extfuncs);
489 else {
490 glExtensions = (char *) glGetString(GL_EXTENSIONS);
493 CheckError(__LINE__);
495 if (! glXQueryVersion( dpy, & glxVersionMajor, & glxVersionMinor )) {
496 fprintf(stderr, "Error: glXQueryVersion failed\n");
497 exit(1);
500 if (!coreWorked) {
501 /* Strip the screen number from the display name, if present. */
502 if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1))) {
503 fprintf(stderr, "Error: malloc() failed\n");
504 exit(1);
506 strcpy(displayName, DisplayString(dpy));
507 colon = strrchr(displayName, ':');
508 if (colon) {
509 period = strchr(colon, '.');
510 if (period)
511 *period = '\0';
514 printf("display: %s screen: %d\n", displayName, scrnum);
515 free(displayName);
516 printf("direct rendering: ");
517 if (glXIsDirect(dpy, ctx)) {
518 printf("Yes\n");
520 else {
521 if (!allowDirect) {
522 printf("No (-i specified)\n");
524 else if (getenv("LIBGL_ALWAYS_INDIRECT")) {
525 printf("No (LIBGL_ALWAYS_INDIRECT set)\n");
527 else {
528 printf("No (If you want to find out why, try setting "
529 "LIBGL_DEBUG=verbose)\n");
532 printf("server glx vendor string: %s\n", serverVendor);
533 printf("server glx version string: %s\n", serverVersion);
534 printf("server glx extensions:\n");
535 print_extension_list(serverExtensions, singleLine);
536 printf("client glx vendor string: %s\n", clientVendor);
537 printf("client glx version string: %s\n", clientVersion);
538 printf("client glx extensions:\n");
539 print_extension_list(clientExtensions, singleLine);
540 printf("GLX version: %u.%u\n", glxVersionMajor, glxVersionMinor);
541 printf("GLX extensions:\n");
542 print_extension_list(glxExtensions, singleLine);
543 if (strstr(glxExtensions, "GLX_MESA_query_renderer"))
544 query_renderer();
545 printf("OpenGL vendor string: %s\n", glVendor);
546 printf("OpenGL renderer string: %s\n", glRenderer);
547 } else
548 printf("\n");
550 printf("%s version string: %s\n", oglstring, glVersion);
552 version = (glVersion[0] - '0') * 10 + (glVersion[2] - '0');
554 CheckError(__LINE__);
556 #ifdef GL_VERSION_2_0
557 if (version >= 20) {
558 char *v = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
559 printf("%s shading language version string: %s\n", oglstring, v);
561 #endif
562 CheckError(__LINE__);
563 #ifdef GL_VERSION_3_0
564 if (version >= 30 && !es2Profile) {
565 GLint flags;
566 glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
567 printf("%s context flags: %s\n", oglstring, context_flags_string(flags));
569 #endif
570 CheckError(__LINE__);
571 #ifdef GL_VERSION_3_2
572 if (version >= 32 && !es2Profile) {
573 GLint mask;
574 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
575 printf("%s profile mask: %s\n", oglstring, profile_mask_string(mask));
577 #endif
579 CheckError(__LINE__);
581 printf("%s extensions:\n", oglstring);
582 print_extension_list(glExtensions, singleLine);
584 CheckError(__LINE__);
586 if (limits) {
587 print_limits(glExtensions, oglstring, version, &extfuncs);
590 if (coreProfile)
591 free(glExtensions);
593 else {
594 fprintf(stderr, "Error: glXMakeCurrent failed\n");
597 glXDestroyContext(dpy, ctx);
598 XFree(visinfo);
599 XDestroyWindow(dpy, win);
600 XSync(dpy, 1);
601 return True;
605 static const char *
606 visual_class_name(int cls)
608 switch (cls) {
609 case StaticColor:
610 return "StaticColor";
611 case PseudoColor:
612 return "PseudoColor";
613 case StaticGray:
614 return "StaticGray";
615 case GrayScale:
616 return "GrayScale";
617 case TrueColor:
618 return "TrueColor";
619 case DirectColor:
620 return "DirectColor";
621 default:
622 return "";
626 static const char *
627 visual_drawable_type(int type)
629 const static struct bit_info bits[] = {
630 { GLX_WINDOW_BIT, "window" },
631 { GLX_PIXMAP_BIT, "pixmap" },
632 { GLX_PBUFFER_BIT, "pbuffer" }
635 return bitmask_to_string(bits, ELEMENTS(bits), type);
638 static const char *
639 visual_class_abbrev(int cls)
641 switch (cls) {
642 case StaticColor:
643 return "sc";
644 case PseudoColor:
645 return "pc";
646 case StaticGray:
647 return "sg";
648 case GrayScale:
649 return "gs";
650 case TrueColor:
651 return "tc";
652 case DirectColor:
653 return "dc";
654 default:
655 return "";
659 static const char *
660 visual_render_type_name(int type)
662 switch (type) {
663 case GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT:
664 return "ufloat";
665 case GLX_RGBA_FLOAT_BIT_ARB:
666 return "float";
667 case GLX_RGBA_BIT:
668 return "rgba";
669 case GLX_COLOR_INDEX_BIT:
670 return "ci";
671 case GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT:
672 return "rgba|ci";
673 default:
674 return "";
678 static const char *
679 caveat_string(int caveat)
681 switch (caveat) {
682 #ifdef GLX_EXT_visual_rating
683 case GLX_SLOW_VISUAL_EXT:
684 return "Slow";
685 case GLX_NON_CONFORMANT_VISUAL_EXT:
686 return "Ncon";
687 case GLX_NONE_EXT:
688 /* fall-through */
689 #endif
690 case 0:
691 /* fall-through */
692 default:
693 return "None";
698 static Bool
699 get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
700 struct visual_attribs *attribs)
702 const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
703 int rgba;
705 memset(attribs, 0, sizeof(struct visual_attribs));
707 attribs->id = vInfo->visualid;
708 #if defined(__cplusplus) || defined(c_plusplus)
709 attribs->klass = vInfo->c_class;
710 #else
711 attribs->klass = vInfo->class;
712 #endif
713 attribs->depth = vInfo->depth;
714 attribs->redMask = vInfo->red_mask;
715 attribs->greenMask = vInfo->green_mask;
716 attribs->blueMask = vInfo->blue_mask;
717 attribs->colormapSize = vInfo->colormap_size;
718 attribs->bitsPerRGB = vInfo->bits_per_rgb;
720 if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0 ||
721 !attribs->supportsGL)
722 return False;
723 glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
724 glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
725 glXGetConfig(dpy, vInfo, GLX_RGBA, &rgba);
726 if (rgba)
727 attribs->render_type = GLX_RGBA_BIT;
728 else
729 attribs->render_type = GLX_COLOR_INDEX_BIT;
731 glXGetConfig(dpy, vInfo, GLX_DRAWABLE_TYPE, &attribs->drawableType);
732 glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
733 glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
734 glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
735 glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
736 glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
737 glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
738 glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
739 glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
740 glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
741 glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
742 glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
743 glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
744 glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
746 /* get transparent pixel stuff */
747 glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
748 if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
749 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
750 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
751 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
752 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
754 else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
755 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
758 /* multisample attribs */
759 #ifdef GLX_ARB_multisample
760 if (ext && strstr(ext, "GLX_ARB_multisample")) {
761 glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample);
762 glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples);
764 #endif
765 else {
766 attribs->numSamples = 0;
767 attribs->numMultisample = 0;
770 #if defined(GLX_EXT_visual_rating)
771 if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
772 glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
774 else {
775 attribs->visualCaveat = GLX_NONE_EXT;
777 #else
778 attribs->visualCaveat = 0;
779 #endif
781 #if defined(GLX_EXT_framebuffer_sRGB)
782 if (ext && strstr(ext, "GLX_EXT_framebuffer_sRGB")) {
783 glXGetConfig(dpy, vInfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, &attribs->srgb);
785 #endif
787 return True;
790 #ifdef GLX_VERSION_1_3
792 static int
793 glx_token_to_visual_class(int visual_type)
795 switch (visual_type) {
796 case GLX_TRUE_COLOR:
797 return TrueColor;
798 case GLX_DIRECT_COLOR:
799 return DirectColor;
800 case GLX_PSEUDO_COLOR:
801 return PseudoColor;
802 case GLX_STATIC_COLOR:
803 return StaticColor;
804 case GLX_GRAY_SCALE:
805 return GrayScale;
806 case GLX_STATIC_GRAY:
807 return StaticGray;
808 case GLX_NONE:
809 default:
810 return None;
814 static Bool
815 get_fbconfig_attribs(Display *dpy, GLXFBConfig fbconfig,
816 struct visual_attribs *attribs)
818 const char *ext = glXQueryExtensionsString(dpy, 0);
819 int visual_type;
820 XVisualInfo *vInfo;
822 memset(attribs, 0, sizeof(struct visual_attribs));
824 glXGetFBConfigAttrib(dpy, fbconfig, GLX_FBCONFIG_ID, &attribs->id);
826 vInfo = glXGetVisualFromFBConfig(dpy, fbconfig);
828 if (vInfo != NULL) {
829 attribs->vis_id = vInfo->visualid;
830 attribs->depth = vInfo->depth;
831 attribs->redMask = vInfo->red_mask;
832 attribs->greenMask = vInfo->green_mask;
833 attribs->blueMask = vInfo->blue_mask;
834 attribs->colormapSize = vInfo->colormap_size;
835 attribs->bitsPerRGB = vInfo->bits_per_rgb;
838 glXGetFBConfigAttrib(dpy, fbconfig, GLX_X_VISUAL_TYPE, &visual_type);
839 attribs->klass = glx_token_to_visual_class(visual_type);
841 glXGetFBConfigAttrib(dpy, fbconfig, GLX_DRAWABLE_TYPE, &attribs->drawableType);
842 glXGetFBConfigAttrib(dpy, fbconfig, GLX_BUFFER_SIZE, &attribs->bufferSize);
843 glXGetFBConfigAttrib(dpy, fbconfig, GLX_LEVEL, &attribs->level);
844 glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &attribs->render_type);
845 glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
846 glXGetFBConfigAttrib(dpy, fbconfig, GLX_STEREO, &attribs->stereo);
847 glXGetFBConfigAttrib(dpy, fbconfig, GLX_AUX_BUFFERS, &attribs->auxBuffers);
849 glXGetFBConfigAttrib(dpy, fbconfig, GLX_RED_SIZE, &attribs->redSize);
850 glXGetFBConfigAttrib(dpy, fbconfig, GLX_GREEN_SIZE, &attribs->greenSize);
851 glXGetFBConfigAttrib(dpy, fbconfig, GLX_BLUE_SIZE, &attribs->blueSize);
852 glXGetFBConfigAttrib(dpy, fbconfig, GLX_ALPHA_SIZE, &attribs->alphaSize);
853 glXGetFBConfigAttrib(dpy, fbconfig, GLX_DEPTH_SIZE, &attribs->depthSize);
854 glXGetFBConfigAttrib(dpy, fbconfig, GLX_STENCIL_SIZE, &attribs->stencilSize);
856 glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
857 glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
858 glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
859 glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
861 /* get transparent pixel stuff */
862 glXGetFBConfigAttrib(dpy, fbconfig,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
863 if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
864 glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
865 glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
866 glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
867 glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
869 else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
870 glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
873 glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLE_BUFFERS, &attribs->numMultisample);
874 glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLES, &attribs->numSamples);
875 glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &attribs->visualCaveat);
877 #if defined(GLX_NV_float_buffer)
878 if (ext && strstr(ext, "GLX_NV_float_buffer")) {
879 glXGetFBConfigAttrib(dpy, fbconfig, GLX_FLOAT_COMPONENTS_NV, &attribs->floatComponents);
881 #endif
882 #if defined(GLX_ARB_fbconfig_float)
883 if (ext && strstr(ext, "GLX_ARB_fbconfig_float")) {
884 if (attribs->render_type & GLX_RGBA_FLOAT_BIT_ARB) {
885 attribs->floatComponents = True;
888 #endif
889 #if defined(GLX_EXT_fbconfig_packed_float)
890 if (ext && strstr(ext, "GLX_EXT_fbconfig_packed_float")) {
891 if (attribs->render_type & GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT) {
892 attribs->packedfloatComponents = True;
895 #endif
897 #if defined(GLX_EXT_framebuffer_sRGB)
898 if (ext && strstr(ext, "GLX_EXT_framebuffer_sRGB")) {
899 glXGetFBConfigAttrib(dpy, fbconfig, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, &attribs->srgb);
901 #endif
902 return True;
905 #endif
909 static void
910 print_visual_attribs_verbose(const struct visual_attribs *attribs,
911 int fbconfigs)
913 if (fbconfigs) {
914 printf("FBConfig ID: %x Visual ID=%x depth=%d class=%s, type=%s\n",
915 attribs->id, attribs->vis_id, attribs->depth,
916 visual_class_name(attribs->klass),
917 visual_drawable_type(attribs->drawableType));
919 else {
920 printf("Visual ID: %x depth=%d class=%s, type=%s\n",
921 attribs->id, attribs->depth, visual_class_name(attribs->klass),
922 visual_drawable_type(attribs->drawableType));
924 printf(" bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n",
925 attribs->bufferSize, attribs->level,
926 visual_render_type_name(attribs->render_type),
927 attribs->doubleBuffer, attribs->stereo);
928 printf(" rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d float=%c sRGB=%c\n",
929 attribs->redSize, attribs->greenSize,
930 attribs->blueSize, attribs->alphaSize,
931 attribs->packedfloatComponents ? 'P' : attribs->floatComponents ? 'Y' : 'N',
932 attribs->srgb ? 'Y' : 'N');
933 printf(" auxBuffers=%d depthSize=%d stencilSize=%d\n",
934 attribs->auxBuffers, attribs->depthSize, attribs->stencilSize);
935 printf(" accum: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
936 attribs->accumRedSize, attribs->accumGreenSize,
937 attribs->accumBlueSize, attribs->accumAlphaSize);
938 printf(" multiSample=%d multiSampleBuffers=%d\n",
939 attribs->numSamples, attribs->numMultisample);
940 #ifdef GLX_EXT_visual_rating
941 if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
942 printf(" visualCaveat=None\n");
943 else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
944 printf(" visualCaveat=Slow\n");
945 else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
946 printf(" visualCaveat=Nonconformant\n");
947 #endif
948 if (attribs->transparentType == GLX_NONE) {
949 printf(" Opaque.\n");
951 else if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
952 printf(" Transparent RGB: Red=%d Green=%d Blue=%d Alpha=%d\n",attribs->transparentRedValue,attribs->transparentGreenValue,attribs->transparentBlueValue,attribs->transparentAlphaValue);
954 else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
955 printf(" Transparent index=%d\n",attribs->transparentIndexValue);
960 static void
961 print_visual_attribs_short_header(void)
963 printf(" visual x bf lv rg d st colorbuffer sr ax dp st accumbuffer ms cav\n");
964 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");
965 printf("----------------------------------------------------------------------------\n");
969 static void
970 print_visual_attribs_short(const struct visual_attribs *attribs)
972 const char *caveat = caveat_string(attribs->visualCaveat);
974 printf("0x%03x %2d %2s %2d %3d %2d %c%c %c %c %2d %2d %2d %2d %c %c %2d %2d %2d",
975 attribs->id,
976 attribs->depth,
977 visual_class_abbrev(attribs->klass),
978 attribs->transparentType != GLX_NONE,
979 attribs->bufferSize,
980 attribs->level,
981 (attribs->render_type & GLX_RGBA_BIT) ? 'r' : ' ',
982 (attribs->render_type & GLX_COLOR_INDEX_BIT) ? 'c' : ' ',
983 attribs->doubleBuffer ? 'y' : '.',
984 attribs->stereo ? 'y' : '.',
985 attribs->redSize, attribs->greenSize,
986 attribs->blueSize, attribs->alphaSize,
987 attribs->packedfloatComponents ? 'u' : attribs->floatComponents ? 'f' : '.',
988 attribs->srgb ? 's' : '.',
989 attribs->auxBuffers,
990 attribs->depthSize,
991 attribs->stencilSize
994 printf(" %2d %2d %2d %2d %2d %1d %s\n",
995 attribs->accumRedSize, attribs->accumGreenSize,
996 attribs->accumBlueSize, attribs->accumAlphaSize,
997 attribs->numSamples, attribs->numMultisample,
998 caveat
1003 static void
1004 print_visual_attribs_long_header(void)
1006 printf("Vis Vis Visual Trans buff lev render DB ste r g b a s aux dep ste accum buffer MS MS \n");
1007 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");
1008 printf("--------------------------------------------------------------------------------------------------------------------\n");
1012 static void
1013 print_visual_attribs_long(const struct visual_attribs *attribs)
1015 const char *caveat = caveat_string(attribs->visualCaveat);
1017 printf("0x%3x %2d %-11s %2d %3d %2d %4s %3d %3d %3d %3d %3d %3d",
1018 attribs->id,
1019 attribs->depth,
1020 visual_class_name(attribs->klass),
1021 attribs->transparentType != GLX_NONE,
1022 attribs->bufferSize,
1023 attribs->level,
1024 visual_render_type_name(attribs->render_type),
1025 attribs->doubleBuffer,
1026 attribs->stereo,
1027 attribs->redSize, attribs->greenSize,
1028 attribs->blueSize, attribs->alphaSize
1031 printf(" %c %c %3d %4d %2d %3d %3d %3d %3d %2d %2d %6s\n",
1032 attribs->floatComponents ? 'f' : '.',
1033 attribs->srgb ? 's' : '.',
1034 attribs->auxBuffers,
1035 attribs->depthSize,
1036 attribs->stencilSize,
1037 attribs->accumRedSize, attribs->accumGreenSize,
1038 attribs->accumBlueSize, attribs->accumAlphaSize,
1039 attribs->numSamples, attribs->numMultisample,
1040 caveat
1045 static void
1046 print_visual_info(Display *dpy, int scrnum, InfoMode mode)
1048 XVisualInfo theTemplate;
1049 XVisualInfo *visuals;
1050 int numVisuals, numGlxVisuals;
1051 long mask;
1052 int i;
1053 struct visual_attribs attribs;
1055 /* get list of all visuals on this screen */
1056 theTemplate.screen = scrnum;
1057 mask = VisualScreenMask;
1058 visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
1060 numGlxVisuals = 0;
1061 for (i = 0; i < numVisuals; i++) {
1062 if (get_visual_attribs(dpy, &visuals[i], &attribs))
1063 numGlxVisuals++;
1066 if (numGlxVisuals == 0)
1067 return;
1069 printf("%d GLX Visuals\n", numGlxVisuals);
1071 if (mode == Normal)
1072 print_visual_attribs_short_header();
1073 else if (mode == Wide)
1074 print_visual_attribs_long_header();
1076 for (i = 0; i < numVisuals; i++) {
1077 if (!get_visual_attribs(dpy, &visuals[i], &attribs))
1078 continue;
1080 if (mode == Verbose)
1081 print_visual_attribs_verbose(&attribs, False);
1082 else if (mode == Normal)
1083 print_visual_attribs_short(&attribs);
1084 else if (mode == Wide)
1085 print_visual_attribs_long(&attribs);
1087 printf("\n");
1089 XFree(visuals);
1092 #ifdef GLX_VERSION_1_3
1094 static void
1095 print_fbconfig_info(Display *dpy, int scrnum, InfoMode mode)
1097 int numFBConfigs = 0;
1098 struct visual_attribs attribs;
1099 GLXFBConfig *fbconfigs;
1100 int i;
1102 /* get list of all fbconfigs on this screen */
1103 fbconfigs = glXGetFBConfigs(dpy, scrnum, &numFBConfigs);
1105 if (numFBConfigs == 0) {
1106 XFree(fbconfigs);
1107 return;
1110 printf("%d GLXFBConfigs:\n", numFBConfigs);
1111 if (mode == Normal)
1112 print_visual_attribs_short_header();
1113 else if (mode == Wide)
1114 print_visual_attribs_long_header();
1116 for (i = 0; i < numFBConfigs; i++) {
1117 get_fbconfig_attribs(dpy, fbconfigs[i], &attribs);
1119 if (mode == Verbose)
1120 print_visual_attribs_verbose(&attribs, True);
1121 else if (mode == Normal)
1122 print_visual_attribs_short(&attribs);
1123 else if (mode == Wide)
1124 print_visual_attribs_long(&attribs);
1126 printf("\n");
1128 XFree(fbconfigs);
1131 #endif
1134 * Stand-alone Mesa doesn't really implement the GLX protocol so it
1135 * doesn't really know the GLX attributes associated with an X visual.
1136 * The first time a visual is presented to Mesa's pseudo-GLX it
1137 * attaches ancilliary buffers to it (like depth and stencil).
1138 * But that usually only works if glXChooseVisual is used.
1139 * This function calls glXChooseVisual() to sort of "prime the pump"
1140 * for Mesa's GLX so that the visuals that get reported actually
1141 * reflect what applications will see.
1142 * This has no effect when using true GLX.
1144 static void
1145 mesa_hack(Display *dpy, int scrnum)
1147 static int attribs[] = {
1148 GLX_RGBA,
1149 GLX_RED_SIZE, 1,
1150 GLX_GREEN_SIZE, 1,
1151 GLX_BLUE_SIZE, 1,
1152 GLX_DEPTH_SIZE, 1,
1153 GLX_STENCIL_SIZE, 1,
1154 GLX_ACCUM_RED_SIZE, 1,
1155 GLX_ACCUM_GREEN_SIZE, 1,
1156 GLX_ACCUM_BLUE_SIZE, 1,
1157 GLX_ACCUM_ALPHA_SIZE, 1,
1158 GLX_DOUBLEBUFFER,
1159 None
1161 XVisualInfo *visinfo;
1163 visinfo = glXChooseVisual(dpy, scrnum, attribs);
1164 if (visinfo)
1165 XFree(visinfo);
1170 * Examine all visuals to find the so-called best one.
1171 * We prefer deepest RGBA buffer with depth, stencil and accum
1172 * that has no caveats.
1174 static int
1175 find_best_visual(Display *dpy, int scrnum)
1177 XVisualInfo theTemplate;
1178 XVisualInfo *visuals;
1179 int numVisuals;
1180 long mask;
1181 int i;
1182 struct visual_attribs bestVis;
1184 /* get list of all visuals on this screen */
1185 theTemplate.screen = scrnum;
1186 mask = VisualScreenMask;
1187 visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
1189 /* init bestVis with first visual info */
1190 get_visual_attribs(dpy, &visuals[0], &bestVis);
1192 /* try to find a "better" visual */
1193 for (i = 1; i < numVisuals; i++) {
1194 struct visual_attribs vis;
1196 get_visual_attribs(dpy, &visuals[i], &vis);
1198 /* always skip visuals with caveats */
1199 if (vis.visualCaveat != GLX_NONE_EXT)
1200 continue;
1202 /* see if this vis is better than bestVis */
1203 if ((!bestVis.supportsGL && vis.supportsGL) ||
1204 (bestVis.visualCaveat != GLX_NONE_EXT) ||
1205 (!(bestVis.render_type & GLX_RGBA_BIT) && (vis.render_type & GLX_RGBA_BIT)) ||
1206 (!bestVis.doubleBuffer && vis.doubleBuffer) ||
1207 (bestVis.redSize < vis.redSize) ||
1208 (bestVis.greenSize < vis.greenSize) ||
1209 (bestVis.blueSize < vis.blueSize) ||
1210 (bestVis.alphaSize < vis.alphaSize) ||
1211 (bestVis.depthSize < vis.depthSize) ||
1212 (bestVis.stencilSize < vis.stencilSize) ||
1213 (bestVis.accumRedSize < vis.accumRedSize)) {
1214 /* found a better visual */
1215 bestVis = vis;
1219 XFree(visuals);
1221 return bestVis.id;
1226 main(int argc, char *argv[])
1228 Display *dpy;
1229 int numScreens, scrnum;
1230 struct options opts;
1231 Bool coreWorked;
1233 parse_args(argc, argv, &opts);
1235 dpy = XOpenDisplay(opts.displayName);
1236 if (!dpy) {
1237 fprintf(stderr, "Error: unable to open display %s\n",
1238 XDisplayName(opts.displayName));
1239 return -1;
1242 if (opts.findBest) {
1243 int b;
1244 mesa_hack(dpy, 0);
1245 b = find_best_visual(dpy, 0);
1246 printf("%d\n", b);
1248 else {
1249 numScreens = ScreenCount(dpy);
1250 print_display_info(dpy);
1251 for (scrnum = 0; scrnum < numScreens; scrnum++) {
1252 mesa_hack(dpy, scrnum);
1253 coreWorked = print_screen_info(dpy, scrnum, opts.allowDirect,
1254 True, False, opts.limits,
1255 opts.singleLine, False);
1256 print_screen_info(dpy, scrnum, opts.allowDirect, False, False,
1257 opts.limits, opts.singleLine, coreWorked);
1258 print_screen_info(dpy, scrnum, opts.allowDirect, False, True, False,
1259 opts.singleLine, True);
1261 printf("\n");
1262 print_visual_info(dpy, scrnum, opts.mode);
1263 #ifdef GLX_VERSION_1_3
1264 print_fbconfig_info(dpy, scrnum, opts.mode);
1265 #endif
1266 if (scrnum + 1 < numScreens)
1267 printf("\n\n");
1271 XCloseDisplay(dpy);
1273 return 0;