| /* |
| * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
| * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| |
| /* |
| * This program is a work-alike of the IRIX glxinfo program. |
| * Command line options: |
| * -t print wide table |
| * -v print verbose information |
| * -display DisplayName specify the X display to interogate |
| * -b only print ID of "best" visual on screen 0 |
| * -i use indirect rendering connection only |
| * -l print interesting OpenGL limits (added 5 Sep 2002) |
| * |
| * Brian Paul 26 January 2000 |
| */ |
| |
| #define GLX_GLXEXT_PROTOTYPES |
| |
| #include <X11/Xlib.h> |
| #include <X11/Xutil.h> |
| #include <GL/gl.h> |
| #include <GL/glx.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| |
| |
| #ifndef GLX_NONE_EXT |
| #define GLX_NONE_EXT 0x8000 |
| #endif |
| |
| #ifndef GLX_TRANSPARENT_RGB |
| #define GLX_TRANSPARENT_RGB 0x8008 |
| #endif |
| |
| #ifndef GLX_RGBA_BIT |
| #define GLX_RGBA_BIT 0x00000001 |
| #endif |
| |
| #ifndef GLX_COLOR_INDEX_BIT |
| #define GLX_COLOR_INDEX_BIT 0x00000002 |
| #endif |
| |
| typedef enum |
| { |
| Normal, |
| Wide, |
| Verbose |
| } InfoMode; |
| |
| |
| struct visual_attribs |
| { |
| /* X visual attribs */ |
| int id; |
| int klass; |
| int depth; |
| int redMask, greenMask, blueMask; |
| int colormapSize; |
| int bitsPerRGB; |
| |
| /* GL visual attribs */ |
| int supportsGL; |
| int transparentType; |
| int transparentRedValue; |
| int transparentGreenValue; |
| int transparentBlueValue; |
| int transparentAlphaValue; |
| int transparentIndexValue; |
| int bufferSize; |
| int level; |
| int render_type; |
| int doubleBuffer; |
| int stereo; |
| int auxBuffers; |
| int redSize, greenSize, blueSize, alphaSize; |
| int depthSize; |
| int stencilSize; |
| int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize; |
| int numSamples, numMultisample; |
| int visualCaveat; |
| }; |
| |
| |
| /* |
| * Print a list of extensions, with word-wrapping. |
| */ |
| static void |
| print_extension_list(const char *ext) |
| { |
| const char *indentString = " "; |
| const int indent = 4; |
| const int max = 79; |
| int width, i, j; |
| |
| if (!ext || !ext[0]) |
| return; |
| |
| width = indent; |
| printf("%s", indentString); |
| i = j = 0; |
| while (1) { |
| if (ext[j] == ' ' || ext[j] == 0) { |
| /* found end of an extension name */ |
| const int len = j - i; |
| if (width + len > max) { |
| /* start a new line */ |
| printf("\n"); |
| width = indent; |
| printf("%s", indentString); |
| } |
| /* print the extension name between ext[i] and ext[j] */ |
| while (i < j) { |
| printf("%c", ext[i]); |
| i++; |
| } |
| /* either we're all done, or we'll continue with next extension */ |
| width += len + 1; |
| if (ext[j] == 0) { |
| break; |
| } |
| else { |
| i++; |
| j++; |
| if (ext[j] == 0) |
| break; |
| printf(", "); |
| width += 2; |
| } |
| } |
| j++; |
| } |
| printf("\n"); |
| } |
| |
| |
| static void |
| print_display_info(Display *dpy) |
| { |
| printf("name of display: %s\n", DisplayString(dpy)); |
| } |
| |
| |
| /** |
| * Print interesting limits for vertex/fragment programs. |
| */ |
| static void |
| print_program_limits(GLenum target) |
| { |
| #if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) |
| struct token_name { |
| GLenum token; |
| const char *name; |
| }; |
| static const struct token_name limits[] = { |
| { GL_MAX_PROGRAM_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_INSTRUCTIONS_ARB" }, |
| { GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB" }, |
| { GL_MAX_PROGRAM_TEMPORARIES_ARB, "GL_MAX_PROGRAM_TEMPORARIES_ARB" }, |
| { GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, "GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB" }, |
| { GL_MAX_PROGRAM_PARAMETERS_ARB, "GL_MAX_PROGRAM_PARAMETERS_ARB" }, |
| { GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB, "GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB" }, |
| { GL_MAX_PROGRAM_ATTRIBS_ARB, "GL_MAX_PROGRAM_ATTRIBS_ARB" }, |
| { GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, "GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB" }, |
| { GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB" }, |
| { GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB" }, |
| { GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, "GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB" }, |
| { GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, "GL_MAX_PROGRAM_ENV_PARAMETERS_ARB" }, |
| { GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB" }, |
| { GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB" }, |
| { GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB" }, |
| { GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB" }, |
| { GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB" }, |
| { GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB" }, |
| { (GLenum) 0, NULL } |
| }; |
| PFNGLGETPROGRAMIVARBPROC GetProgramivARB_func = (PFNGLGETPROGRAMIVARBPROC) |
| glXGetProcAddressARB((GLubyte *) "glGetProgramivARB"); |
| GLint max[1]; |
| int i; |
| |
| if (target == GL_VERTEX_PROGRAM_ARB) { |
| printf(" GL_VERTEX_PROGRAM_ARB:\n"); |
| } |
| else if (target == GL_FRAGMENT_PROGRAM_ARB) { |
| printf(" GL_FRAGMENT_PROGRAM_ARB:\n"); |
| } |
| else { |
| return; /* something's wrong */ |
| } |
| |
| for (i = 0; limits[i].token; i++) { |
| GetProgramivARB_func(target, limits[i].token, max); |
| if (glGetError() == GL_NO_ERROR) { |
| printf(" %s = %d\n", limits[i].name, max[0]); |
| } |
| } |
| #endif /* GL_ARB_vertex_program / GL_ARB_fragment_program */ |
| } |
| |
| |
| /** |
| * Print interesting limits for vertex/fragment shaders. |
| */ |
| static void |
| print_shader_limits(GLenum target) |
| { |
| struct token_name { |
| GLenum token; |
| const char *name; |
| }; |
| #if defined(GL_ARB_vertex_shader) |
| static const struct token_name vertex_limits[] = { |
| { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, "GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB" }, |
| { GL_MAX_VARYING_FLOATS_ARB, "GL_MAX_VARYING_FLOATS_ARB" }, |
| { GL_MAX_VERTEX_ATTRIBS_ARB, "GL_MAX_VERTEX_ATTRIBS_ARB" }, |
| { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" }, |
| { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB" }, |
| { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB" }, |
| { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" }, |
| { (GLenum) 0, NULL } |
| }; |
| #endif |
| #if defined(GL_ARB_fragment_shader) |
| static const struct token_name fragment_limits[] = { |
| { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB" }, |
| { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" }, |
| { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" }, |
| { (GLenum) 0, NULL } |
| }; |
| #endif |
| GLint max[1]; |
| int i; |
| |
| #if defined(GL_ARB_vertex_shader) |
| if (target == GL_VERTEX_SHADER_ARB) { |
| printf(" GL_VERTEX_SHADER_ARB:\n"); |
| for (i = 0; vertex_limits[i].token; i++) { |
| glGetIntegerv(vertex_limits[i].token, max); |
| if (glGetError() == GL_NO_ERROR) { |
| printf(" %s = %d\n", vertex_limits[i].name, max[0]); |
| } |
| } |
| } |
| #endif |
| #if defined(GL_ARB_fragment_shader) |
| if (target == GL_FRAGMENT_SHADER_ARB) { |
| printf(" GL_FRAGMENT_SHADER_ARB:\n"); |
| for (i = 0; fragment_limits[i].token; i++) { |
| glGetIntegerv(fragment_limits[i].token, max); |
| if (glGetError() == GL_NO_ERROR) { |
| printf(" %s = %d\n", fragment_limits[i].name, max[0]); |
| } |
| } |
| } |
| #endif |
| } |
| |
| |
| /** |
| * Print interesting OpenGL implementation limits. |
| */ |
| static void |
| print_limits(const char *extensions) |
| { |
| struct token_name { |
| GLuint count; |
| GLenum token; |
| const char *name; |
| }; |
| static const struct token_name limits[] = { |
| { 1, GL_MAX_ATTRIB_STACK_DEPTH, "GL_MAX_ATTRIB_STACK_DEPTH" }, |
| { 1, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH" }, |
| { 1, GL_MAX_CLIP_PLANES, "GL_MAX_CLIP_PLANES" }, |
| { 1, GL_MAX_COLOR_MATRIX_STACK_DEPTH, "GL_MAX_COLOR_MATRIX_STACK_DEPTH" }, |
| { 1, GL_MAX_ELEMENTS_VERTICES, "GL_MAX_ELEMENTS_VERTICES" }, |
| { 1, GL_MAX_ELEMENTS_INDICES, "GL_MAX_ELEMENTS_INDICES" }, |
| { 1, GL_MAX_EVAL_ORDER, "GL_MAX_EVAL_ORDER" }, |
| { 1, GL_MAX_LIGHTS, "GL_MAX_LIGHTS" }, |
| { 1, GL_MAX_LIST_NESTING, "GL_MAX_LIST_NESTING" }, |
| { 1, GL_MAX_MODELVIEW_STACK_DEPTH, "GL_MAX_MODELVIEW_STACK_DEPTH" }, |
| { 1, GL_MAX_NAME_STACK_DEPTH, "GL_MAX_NAME_STACK_DEPTH" }, |
| { 1, GL_MAX_PIXEL_MAP_TABLE, "GL_MAX_PIXEL_MAP_TABLE" }, |
| { 1, GL_MAX_PROJECTION_STACK_DEPTH, "GL_MAX_PROJECTION_STACK_DEPTH" }, |
| { 1, GL_MAX_TEXTURE_STACK_DEPTH, "GL_MAX_TEXTURE_STACK_DEPTH" }, |
| { 1, GL_MAX_TEXTURE_SIZE, "GL_MAX_TEXTURE_SIZE" }, |
| { 1, GL_MAX_3D_TEXTURE_SIZE, "GL_MAX_3D_TEXTURE_SIZE" }, |
| { 2, GL_MAX_VIEWPORT_DIMS, "GL_MAX_VIEWPORT_DIMS" }, |
| { 2, GL_ALIASED_LINE_WIDTH_RANGE, "GL_ALIASED_LINE_WIDTH_RANGE" }, |
| { 2, GL_SMOOTH_LINE_WIDTH_RANGE, "GL_SMOOTH_LINE_WIDTH_RANGE" }, |
| { 2, GL_ALIASED_POINT_SIZE_RANGE, "GL_ALIASED_POINT_SIZE_RANGE" }, |
| { 2, GL_SMOOTH_POINT_SIZE_RANGE, "GL_SMOOTH_POINT_SIZE_RANGE" }, |
| #if defined(GL_ARB_texture_cube_map) |
| { 1, GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB" }, |
| #endif |
| #if defined(GLX_NV_texture_rectangle) |
| { 1, GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV" }, |
| #endif |
| #if defined(GL_ARB_texture_compression) |
| { 1, GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, "GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB" }, |
| #endif |
| #if defined(GL_ARB_multitexture) |
| { 1, GL_MAX_TEXTURE_UNITS_ARB, "GL_MAX_TEXTURE_UNITS_ARB" }, |
| #endif |
| #if defined(GL_EXT_texture_lod_bias) |
| { 1, GL_MAX_TEXTURE_LOD_BIAS_EXT, "GL_MAX_TEXTURE_LOD_BIAS_EXT" }, |
| #endif |
| #if defined(GL_EXT_texture_filter_anisotropic) |
| { 1, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT" }, |
| #endif |
| #if defined(GL_ARB_draw_buffers) |
| { 1, GL_MAX_DRAW_BUFFERS_ARB, "GL_MAX_DRAW_BUFFERS_ARB" }, |
| #endif |
| { 0, (GLenum) 0, NULL } |
| }; |
| GLint i, max[2]; |
| |
| printf("OpenGL limits:\n"); |
| for (i = 0; limits[i].count; i++) { |
| glGetIntegerv(limits[i].token, max); |
| if (glGetError() == GL_NO_ERROR) { |
| if (limits[i].count == 1) |
| printf(" %s = %d\n", limits[i].name, max[0]); |
| else /* XXX fix if we ever query something with more than 2 values */ |
| printf(" %s = %d, %d\n", limits[i].name, max[0], max[1]); |
| } |
| } |
| |
| /* these don't fit into the above mechanism, unfortunately */ |
| glGetConvolutionParameteriv(GL_CONVOLUTION_2D, GL_MAX_CONVOLUTION_WIDTH, max); |
| glGetConvolutionParameteriv(GL_CONVOLUTION_2D, GL_MAX_CONVOLUTION_HEIGHT, max+1); |
| if (glGetError() == GL_NONE) { |
| printf(" GL_MAX_CONVOLUTION_WIDTH/HEIGHT = %d, %d\n", max[0], max[1]); |
| } |
| |
| #if defined(GL_ARB_vertex_program) |
| if (strstr(extensions, "GL_ARB_vertex_program")) { |
| print_program_limits(GL_VERTEX_PROGRAM_ARB); |
| } |
| #endif |
| #if defined(GL_ARB_fragment_program) |
| if (strstr(extensions, "GL_ARB_fragment_program")) { |
| print_program_limits(GL_FRAGMENT_PROGRAM_ARB); |
| } |
| #endif |
| #if defined(GL_ARB_vertex_shader) |
| if (strstr(extensions, "GL_ARB_vertex_shader")) { |
| print_shader_limits(GL_VERTEX_SHADER_ARB); |
| } |
| #endif |
| #if defined(GL_ARB_fragment_shader) |
| if (strstr(extensions, "GL_ARB_fragment_shader")) { |
| print_shader_limits(GL_FRAGMENT_SHADER_ARB); |
| } |
| #endif |
| } |
| |
| |
| static void |
| print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits) |
| { |
| Window win; |
| int attribSingle[] = { |
| GLX_RGBA, |
| GLX_RED_SIZE, 1, |
| GLX_GREEN_SIZE, 1, |
| GLX_BLUE_SIZE, 1, |
| None }; |
| int attribDouble[] = { |
| GLX_RGBA, |
| GLX_RED_SIZE, 1, |
| GLX_GREEN_SIZE, 1, |
| GLX_BLUE_SIZE, 1, |
| GLX_DOUBLEBUFFER, |
| None }; |
| |
| XSetWindowAttributes attr; |
| unsigned long mask; |
| Window root; |
| GLXContext ctx = NULL; |
| XVisualInfo *visinfo; |
| int width = 100, height = 100; |
| |
| root = RootWindow(dpy, scrnum); |
| |
| /* |
| * Find a basic GLX visual. We'll then create a rendering context and |
| * query various info strings. |
| */ |
| visinfo = glXChooseVisual(dpy, scrnum, attribSingle); |
| if (!visinfo) |
| visinfo = glXChooseVisual(dpy, scrnum, attribDouble); |
| |
| if (visinfo) |
| ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect ); |
| |
| #ifdef GLX_VERSION_1_3 |
| /* Try glXChooseFBConfig() if glXChooseVisual didn't work. |
| * XXX when would that happen? |
| */ |
| if (!visinfo) { |
| int fbAttribSingle[] = { |
| GLX_RENDER_TYPE, GLX_RGBA_BIT, |
| GLX_RED_SIZE, 1, |
| GLX_GREEN_SIZE, 1, |
| GLX_BLUE_SIZE, 1, |
| GLX_DOUBLEBUFFER, GL_FALSE, |
| None }; |
| int fbAttribDouble[] = { |
| GLX_RENDER_TYPE, GLX_RGBA_BIT, |
| GLX_RED_SIZE, 1, |
| GLX_GREEN_SIZE, 1, |
| GLX_BLUE_SIZE, 1, |
| GLX_DOUBLEBUFFER, GL_TRUE, |
| None }; |
| GLXFBConfig *configs = NULL; |
| int nConfigs; |
| |
| configs = glXChooseFBConfig(dpy, scrnum, fbAttribSingle, &nConfigs); |
| if (!configs) |
| configs = glXChooseFBConfig(dpy, scrnum, fbAttribDouble, &nConfigs); |
| |
| if (configs) { |
| visinfo = glXGetVisualFromFBConfig(dpy, configs[0]); |
| ctx = glXCreateNewContext(dpy, configs[0], GLX_RGBA_TYPE, NULL, allowDirect); |
| XFree(configs); |
| } |
| } |
| #endif |
| |
| if (!visinfo) { |
| fprintf(stderr, "Error: couldn't find RGB GLX visual or fbconfig\n"); |
| return; |
| } |
| |
| if (!ctx) { |
| fprintf(stderr, "Error: glXCreateContext failed\n"); |
| XFree(visinfo); |
| return; |
| } |
| |
| attr.background_pixel = 0; |
| attr.border_pixel = 0; |
| attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone); |
| attr.event_mask = StructureNotifyMask | ExposureMask; |
| mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; |
| win = XCreateWindow(dpy, root, 0, 0, width, height, |
| 0, visinfo->depth, InputOutput, |
| visinfo->visual, mask, &attr); |
| |
| if (glXMakeCurrent(dpy, win, ctx)) { |
| const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR); |
| const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION); |
| const char *serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS); |
| const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR); |
| const char *clientVersion = glXGetClientString(dpy, GLX_VERSION); |
| const char *clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS); |
| const char *glxExtensions = glXQueryExtensionsString(dpy, scrnum); |
| const char *glVendor = (const char *) glGetString(GL_VENDOR); |
| const char *glRenderer = (const char *) glGetString(GL_RENDERER); |
| const char *glVersion = (const char *) glGetString(GL_VERSION); |
| const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS); |
| int glxVersionMajor; |
| int glxVersionMinor; |
| char *displayName = NULL; |
| char *colon = NULL, *period = NULL; |
| |
| if (! glXQueryVersion( dpy, & glxVersionMajor, & glxVersionMinor )) { |
| fprintf(stderr, "Error: glXQueryVersion failed\n"); |
| exit(1); |
| } |
| |
| /* Strip the screen number from the display name, if present. */ |
| if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1))) { |
| fprintf(stderr, "Error: malloc() failed\n"); |
| exit(1); |
| } |
| strcpy(displayName, DisplayString(dpy)); |
| colon = strrchr(displayName, ':'); |
| if (colon) { |
| period = strchr(colon, '.'); |
| if (period) |
| *period = '\0'; |
| } |
| printf("display: %s screen: %d\n", displayName, scrnum); |
| free(displayName); |
| printf("direct rendering: "); |
| if (glXIsDirect(dpy, ctx)) { |
| printf("Yes\n"); |
| } else { |
| if (!allowDirect) { |
| printf("No (-i specified)\n"); |
| } else if (getenv("LIBGL_ALWAYS_INDIRECT")) { |
| printf("No (LIBGL_ALWAYS_INDIRECT set)\n"); |
| } else { |
| printf("No (If you want to find out why, try setting " |
| "LIBGL_DEBUG=verbose)\n"); |
| } |
| } |
| printf("server glx vendor string: %s\n", serverVendor); |
| printf("server glx version string: %s\n", serverVersion); |
| printf("server glx extensions:\n"); |
| print_extension_list(serverExtensions); |
| printf("client glx vendor string: %s\n", clientVendor); |
| printf("client glx version string: %s\n", clientVersion); |
| printf("client glx extensions:\n"); |
| print_extension_list(clientExtensions); |
| printf("GLX version: %u.%u\n", glxVersionMajor, glxVersionMinor); |
| printf("GLX extensions:\n"); |
| print_extension_list(glxExtensions); |
| printf("OpenGL vendor string: %s\n", glVendor); |
| printf("OpenGL renderer string: %s\n", glRenderer); |
| printf("OpenGL version string: %s\n", glVersion); |
| #ifdef GL_VERSION_2_0 |
| if (glVersion[0] >= '2' && glVersion[1] == '.') { |
| char *v = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION); |
| printf("OpenGL shading language version string: %s\n", v); |
| } |
| #endif |
| |
| printf("OpenGL extensions:\n"); |
| print_extension_list(glExtensions); |
| if (limits) |
| print_limits(glExtensions); |
| } |
| else { |
| fprintf(stderr, "Error: glXMakeCurrent failed\n"); |
| } |
| |
| glXDestroyContext(dpy, ctx); |
| XFree(visinfo); |
| XDestroyWindow(dpy, win); |
| } |
| |
| |
| static const char * |
| visual_class_name(int cls) |
| { |
| switch (cls) { |
| case StaticColor: |
| return "StaticColor"; |
| case PseudoColor: |
| return "PseudoColor"; |
| case StaticGray: |
| return "StaticGray"; |
| case GrayScale: |
| return "GrayScale"; |
| case TrueColor: |
| return "TrueColor"; |
| case DirectColor: |
| return "DirectColor"; |
| default: |
| return ""; |
| } |
| } |
| |
| |
| static const char * |
| visual_class_abbrev(int cls) |
| { |
| switch (cls) { |
| case StaticColor: |
| return "sc"; |
| case PseudoColor: |
| return "pc"; |
| case StaticGray: |
| return "sg"; |
| case GrayScale: |
| return "gs"; |
| case TrueColor: |
| return "tc"; |
| case DirectColor: |
| return "dc"; |
| default: |
| return ""; |
| } |
| } |
| |
| static const char * |
| visual_render_type_name(int type) |
| { |
| switch (type) { |
| case GLX_RGBA_BIT: |
| return "rgba"; |
| case GLX_COLOR_INDEX_BIT: |
| return "ci"; |
| case GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT: |
| return "rgba|ci"; |
| default: |
| return ""; |
| } |
| } |
| |
| static GLboolean |
| get_visual_attribs(Display *dpy, XVisualInfo *vInfo, |
| struct visual_attribs *attribs) |
| { |
| const char *ext = glXQueryExtensionsString(dpy, vInfo->screen); |
| int rgba; |
| |
| memset(attribs, 0, sizeof(struct visual_attribs)); |
| |
| attribs->id = vInfo->visualid; |
| #if defined(__cplusplus) || defined(c_plusplus) |
| attribs->klass = vInfo->c_class; |
| #else |
| attribs->klass = vInfo->class; |
| #endif |
| attribs->depth = vInfo->depth; |
| attribs->redMask = vInfo->red_mask; |
| attribs->greenMask = vInfo->green_mask; |
| attribs->blueMask = vInfo->blue_mask; |
| attribs->colormapSize = vInfo->colormap_size; |
| attribs->bitsPerRGB = vInfo->bits_per_rgb; |
| |
| if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0 || |
| !attribs->supportsGL) |
| return GL_FALSE; |
| glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize); |
| glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level); |
| glXGetConfig(dpy, vInfo, GLX_RGBA, &rgba); |
| if (rgba) |
| attribs->render_type = GLX_RGBA_BIT; |
| else |
| attribs->render_type = GLX_COLOR_INDEX_BIT; |
| |
| glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer); |
| glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo); |
| glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers); |
| glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize); |
| glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize); |
| glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize); |
| glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize); |
| glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize); |
| glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize); |
| glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize); |
| glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize); |
| glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize); |
| glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize); |
| |
| /* get transparent pixel stuff */ |
| glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType); |
| if (attribs->transparentType == GLX_TRANSPARENT_RGB) { |
| glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue); |
| glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue); |
| glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue); |
| glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue); |
| } |
| else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) { |
| glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue); |
| } |
| |
| /* multisample attribs */ |
| #ifdef GLX_ARB_multisample |
| if (ext && strstr(ext, "GLX_ARB_multisample")) { |
| glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample); |
| glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples); |
| } |
| #endif |
| else { |
| attribs->numSamples = 0; |
| attribs->numMultisample = 0; |
| } |
| |
| #if defined(GLX_EXT_visual_rating) |
| if (ext && strstr(ext, "GLX_EXT_visual_rating")) { |
| glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat); |
| } |
| else { |
| attribs->visualCaveat = GLX_NONE_EXT; |
| } |
| #else |
| attribs->visualCaveat = 0; |
| #endif |
| |
| return GL_TRUE; |
| } |
| |
| #ifdef GLX_VERSION_1_3 |
| |
| static int |
| glx_token_to_visual_class(int visual_type) |
| { |
| switch (visual_type) { |
| case GLX_TRUE_COLOR: |
| return TrueColor; |
| case GLX_DIRECT_COLOR: |
| return DirectColor; |
| case GLX_PSEUDO_COLOR: |
| return PseudoColor; |
| case GLX_STATIC_COLOR: |
| return StaticColor; |
| case GLX_GRAY_SCALE: |
| return GrayScale; |
| case GLX_STATIC_GRAY: |
| return StaticGray; |
| case GLX_NONE: |
| default: |
| return None; |
| } |
| } |
| |
| static GLboolean |
| get_fbconfig_attribs(Display *dpy, GLXFBConfig fbconfig, |
| struct visual_attribs *attribs) |
| { |
| int visual_type; |
| |
| memset(attribs, 0, sizeof(struct visual_attribs)); |
| |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_FBCONFIG_ID, &attribs->id); |
| |
| #if 0 |
| attribs->depth = vInfo->depth; |
| attribs->redMask = vInfo->red_mask; |
| attribs->greenMask = vInfo->green_mask; |
| attribs->blueMask = vInfo->blue_mask; |
| attribs->colormapSize = vInfo->colormap_size; |
| attribs->bitsPerRGB = vInfo->bits_per_rgb; |
| #endif |
| |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_X_VISUAL_TYPE, &visual_type); |
| attribs->klass = glx_token_to_visual_class(visual_type); |
| |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_BUFFER_SIZE, &attribs->bufferSize); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_LEVEL, &attribs->level); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &attribs->render_type); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &attribs->doubleBuffer); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_STEREO, &attribs->stereo); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_AUX_BUFFERS, &attribs->auxBuffers); |
| |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_RED_SIZE, &attribs->redSize); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_GREEN_SIZE, &attribs->greenSize); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_BLUE_SIZE, &attribs->blueSize); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_ALPHA_SIZE, &attribs->alphaSize); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_DEPTH_SIZE, &attribs->depthSize); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_STENCIL_SIZE, &attribs->stencilSize); |
| |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize); |
| |
| /* get transparent pixel stuff */ |
| glXGetFBConfigAttrib(dpy, fbconfig,GLX_TRANSPARENT_TYPE, &attribs->transparentType); |
| if (attribs->transparentType == GLX_TRANSPARENT_RGB) { |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue); |
| } |
| else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) { |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue); |
| } |
| |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLE_BUFFERS, &attribs->numMultisample); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLES, &attribs->numSamples); |
| glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &attribs->visualCaveat); |
| |
| return GL_TRUE; |
| } |
| |
| #endif |
| |
| |
| |
| static void |
| print_visual_attribs_verbose(const struct visual_attribs *attribs) |
| { |
| printf("Visual ID: %x depth=%d class=%s\n", |
| attribs->id, attribs->depth, visual_class_name(attribs->klass)); |
| printf(" bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n", |
| attribs->bufferSize, attribs->level, |
| visual_render_type_name(attribs->render_type), |
| attribs->doubleBuffer, attribs->stereo); |
| printf(" rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n", |
| attribs->redSize, attribs->greenSize, |
| attribs->blueSize, attribs->alphaSize); |
| printf(" auxBuffers=%d depthSize=%d stencilSize=%d\n", |
| attribs->auxBuffers, attribs->depthSize, attribs->stencilSize); |
| printf(" accum: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n", |
| attribs->accumRedSize, attribs->accumGreenSize, |
| attribs->accumBlueSize, attribs->accumAlphaSize); |
| printf(" multiSample=%d multiSampleBuffers=%d\n", |
| attribs->numSamples, attribs->numMultisample); |
| #ifdef GLX_EXT_visual_rating |
| if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0) |
| printf(" visualCaveat=None\n"); |
| else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT) |
| printf(" visualCaveat=Slow\n"); |
| else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT) |
| printf(" visualCaveat=Nonconformant\n"); |
| #endif |
| if (attribs->transparentType == GLX_NONE) { |
| printf(" Opaque.\n"); |
| } |
| else if (attribs->transparentType == GLX_TRANSPARENT_RGB) { |
| printf(" Transparent RGB: Red=%d Green=%d Blue=%d Alpha=%d\n",attribs->transparentRedValue,attribs->transparentGreenValue,attribs->transparentBlueValue,attribs->transparentAlphaValue); |
| } |
| else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) { |
| printf(" Transparent index=%d\n",attribs->transparentIndexValue); |
| } |
| } |
| |
| |
| static void |
| print_visual_attribs_short_header(void) |
| { |
| printf(" visual x bf lv rg d st colorbuffer ax dp st accumbuffer ms cav\n"); |
| 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"); |
| printf("----------------------------------------------------------------------\n"); |
| } |
| |
| |
| static void |
| print_visual_attribs_short(const struct visual_attribs *attribs) |
| { |
| char *caveat = NULL; |
| #ifdef GLX_EXT_visual_rating |
| if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0) |
| caveat = "None"; |
| else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT) |
| caveat = "Slow"; |
| else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT) |
| caveat = "Ncon"; |
| else |
| caveat = "None"; |
| #else |
| caveat = "None"; |
| #endif |
| |
| printf("0x%02x %2d %2s %2d %2d %2d %c%c %c %c %2d %2d %2d %2d %2d %2d %2d", |
| attribs->id, |
| attribs->depth, |
| visual_class_abbrev(attribs->klass), |
| attribs->transparentType != GLX_NONE, |
| attribs->bufferSize, |
| attribs->level, |
| (attribs->render_type & GLX_RGBA_BIT) ? 'r' : ' ', |
| (attribs->render_type & GLX_COLOR_INDEX_BIT) ? 'c' : ' ', |
| attribs->doubleBuffer ? 'y' : '.', |
| attribs->stereo ? 'y' : '.', |
| attribs->redSize, attribs->greenSize, |
| attribs->blueSize, attribs->alphaSize, |
| attribs->auxBuffers, |
| attribs->depthSize, |
| attribs->stencilSize |
| ); |
| |
| printf(" %2d %2d %2d %2d %2d %1d %s\n", |
| attribs->accumRedSize, attribs->accumGreenSize, |
| attribs->accumBlueSize, attribs->accumAlphaSize, |
| attribs->numSamples, attribs->numMultisample, |
| caveat |
| ); |
| } |
| |
| |
| static void |
| print_visual_attribs_long_header(void) |
| { |
| printf("Vis Vis Visual Trans buff lev render DB ste r g b a aux dep ste accum buffers MS MS\n"); |
| printf(" ID Depth Type parent size el type reo sz sz sz sz buf th ncl r g b a num bufs\n"); |
| printf("----------------------------------------------------------------------------------------------------\n"); |
| } |
| |
| |
| static void |
| print_visual_attribs_long(const struct visual_attribs *attribs) |
| { |
| printf("0x%2x %2d %-11s %2d %2d %2d %4s %3d %3d %3d %3d %3d %3d", |
| attribs->id, |
| attribs->depth, |
| visual_class_name(attribs->klass), |
| attribs->transparentType != GLX_NONE, |
| attribs->bufferSize, |
| attribs->level, |
| visual_render_type_name(attribs->render_type), |
| attribs->doubleBuffer, |
| attribs->stereo, |
| attribs->redSize, attribs->greenSize, |
| attribs->blueSize, attribs->alphaSize |
| ); |
| |
| printf(" %3d %4d %2d %3d %3d %3d %3d %2d %2d\n", |
| attribs->auxBuffers, |
| attribs->depthSize, |
| attribs->stencilSize, |
| attribs->accumRedSize, attribs->accumGreenSize, |
| attribs->accumBlueSize, attribs->accumAlphaSize, |
| attribs->numSamples, attribs->numMultisample |
| ); |
| } |
| |
| |
| static void |
| print_visual_info(Display *dpy, int scrnum, InfoMode mode) |
| { |
| XVisualInfo theTemplate; |
| XVisualInfo *visuals; |
| int numVisuals, numGlxVisuals; |
| long mask; |
| int i; |
| struct visual_attribs attribs; |
| |
| /* get list of all visuals on this screen */ |
| theTemplate.screen = scrnum; |
| mask = VisualScreenMask; |
| visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals); |
| |
| numGlxVisuals = 0; |
| for (i = 0; i < numVisuals; i++) { |
| if (get_visual_attribs(dpy, &visuals[i], &attribs)) |
| numGlxVisuals++; |
| } |
| |
| if (numGlxVisuals == 0) |
| return; |
| |
| printf("%d GLX Visuals\n", numGlxVisuals); |
| |
| if (mode == Normal) |
| print_visual_attribs_short_header(); |
| else if (mode == Wide) |
| print_visual_attribs_long_header(); |
| |
| for (i = 0; i < numVisuals; i++) { |
| if (!get_visual_attribs(dpy, &visuals[i], &attribs)) |
| continue; |
| |
| if (mode == Verbose) |
| print_visual_attribs_verbose(&attribs); |
| else if (mode == Normal) |
| print_visual_attribs_short(&attribs); |
| else if (mode == Wide) |
| print_visual_attribs_long(&attribs); |
| } |
| printf("\n"); |
| |
| XFree(visuals); |
| } |
| |
| #ifdef GLX_VERSION_1_3 |
| |
| static void |
| print_fbconfig_info(Display *dpy, int scrnum, InfoMode mode) |
| { |
| int numFBConfigs; |
| struct visual_attribs attribs; |
| GLXFBConfig *fbconfigs; |
| int i; |
| |
| /* get list of all fbconfigs on this screen */ |
| fbconfigs = glXGetFBConfigs(dpy, scrnum, &numFBConfigs); |
| |
| if (numFBConfigs == 0) { |
| XFree(fbconfigs); |
| return; |
| } |
| |
| printf("%d GLXFBConfigs:\n", numFBConfigs); |
| if (mode == Normal) |
| print_visual_attribs_short_header(); |
| else if (mode == Wide) |
| print_visual_attribs_long_header(); |
| |
| for (i = 0; i < numFBConfigs; i++) { |
| get_fbconfig_attribs(dpy, fbconfigs[i], &attribs); |
| |
| if (mode == Verbose) |
| print_visual_attribs_verbose(&attribs); |
| else if (mode == Normal) |
| print_visual_attribs_short(&attribs); |
| else if (mode == Wide) |
| print_visual_attribs_long(&attribs); |
| } |
| printf("\n"); |
| |
| XFree(fbconfigs); |
| } |
| |
| #endif |
| |
| /* |
| * Stand-alone Mesa doesn't really implement the GLX protocol so it |
| * doesn't really know the GLX attributes associated with an X visual. |
| * The first time a visual is presented to Mesa's pseudo-GLX it |
| * attaches ancilliary buffers to it (like depth and stencil). |
| * But that usually only works if glXChooseVisual is used. |
| * This function calls glXChooseVisual() to sort of "prime the pump" |
| * for Mesa's GLX so that the visuals that get reported actually |
| * reflect what applications will see. |
| * This has no effect when using true GLX. |
| */ |
| static void |
| mesa_hack(Display *dpy, int scrnum) |
| { |
| static int attribs[] = { |
| GLX_RGBA, |
| GLX_RED_SIZE, 1, |
| GLX_GREEN_SIZE, 1, |
| GLX_BLUE_SIZE, 1, |
| GLX_DEPTH_SIZE, 1, |
| GLX_STENCIL_SIZE, 1, |
| GLX_ACCUM_RED_SIZE, 1, |
| GLX_ACCUM_GREEN_SIZE, 1, |
| GLX_ACCUM_BLUE_SIZE, 1, |
| GLX_ACCUM_ALPHA_SIZE, 1, |
| GLX_DOUBLEBUFFER, |
| None |
| }; |
| XVisualInfo *visinfo; |
| |
| visinfo = glXChooseVisual(dpy, scrnum, attribs); |
| if (visinfo) |
| XFree(visinfo); |
| } |
| |
| |
| /* |
| * Examine all visuals to find the so-called best one. |
| * We prefer deepest RGBA buffer with depth, stencil and accum |
| * that has no caveats. |
| */ |
| static int |
| find_best_visual(Display *dpy, int scrnum) |
| { |
| XVisualInfo theTemplate; |
| XVisualInfo *visuals; |
| int numVisuals; |
| long mask; |
| int i; |
| struct visual_attribs bestVis; |
| |
| /* get list of all visuals on this screen */ |
| theTemplate.screen = scrnum; |
| mask = VisualScreenMask; |
| visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals); |
| |
| /* init bestVis with first visual info */ |
| get_visual_attribs(dpy, &visuals[0], &bestVis); |
| |
| /* try to find a "better" visual */ |
| for (i = 1; i < numVisuals; i++) { |
| struct visual_attribs vis; |
| |
| get_visual_attribs(dpy, &visuals[i], &vis); |
| |
| /* always skip visuals with caveats */ |
| if (vis.visualCaveat != GLX_NONE_EXT) |
| continue; |
| |
| /* see if this vis is better than bestVis */ |
| if ((!bestVis.supportsGL && vis.supportsGL) || |
| (bestVis.visualCaveat != GLX_NONE_EXT) || |
| (!(bestVis.render_type & GLX_RGBA_BIT) && (vis.render_type & GLX_RGBA_BIT)) || |
| (!bestVis.doubleBuffer && vis.doubleBuffer) || |
| (bestVis.redSize < vis.redSize) || |
| (bestVis.greenSize < vis.greenSize) || |
| (bestVis.blueSize < vis.blueSize) || |
| (bestVis.alphaSize < vis.alphaSize) || |
| (bestVis.depthSize < vis.depthSize) || |
| (bestVis.stencilSize < vis.stencilSize) || |
| (bestVis.accumRedSize < vis.accumRedSize)) { |
| /* found a better visual */ |
| bestVis = vis; |
| } |
| } |
| |
| XFree(visuals); |
| |
| return bestVis.id; |
| } |
| |
| |
| static void |
| usage(void) |
| { |
| printf("Usage: glxinfo [-v] [-t] [-h] [-i] [-b] [-display <dname>]\n"); |
| printf("\t-v: Print visuals info in verbose form.\n"); |
| printf("\t-t: Print verbose table.\n"); |
| printf("\t-display <dname>: Print GLX visuals on specified server.\n"); |
| printf("\t-h: This information.\n"); |
| printf("\t-i: Force an indirect rendering context.\n"); |
| printf("\t-b: Find the 'best' visual and print it's number.\n"); |
| printf("\t-l: Print interesting OpenGL limits.\n"); |
| } |
| |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| char *displayName = NULL; |
| Display *dpy; |
| int numScreens, scrnum; |
| InfoMode mode = Normal; |
| GLboolean findBest = GL_FALSE; |
| GLboolean limits = GL_FALSE; |
| Bool allowDirect = True; |
| int i; |
| |
| for (i = 1; i < argc; i++) { |
| if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) { |
| displayName = argv[i + 1]; |
| i++; |
| } |
| else if (strcmp(argv[i], "-t") == 0) { |
| mode = Wide; |
| } |
| else if (strcmp(argv[i], "-v") == 0) { |
| mode = Verbose; |
| } |
| else if (strcmp(argv[i], "-b") == 0) { |
| findBest = GL_TRUE; |
| } |
| else if (strcmp(argv[i], "-i") == 0) { |
| allowDirect = False; |
| } |
| else if (strcmp(argv[i], "-l") == 0) { |
| limits = GL_TRUE; |
| } |
| else if (strcmp(argv[i], "-h") == 0) { |
| usage(); |
| return 0; |
| } |
| else { |
| printf("Unknown option `%s'\n", argv[i]); |
| usage(); |
| return 0; |
| } |
| } |
| |
| dpy = XOpenDisplay(displayName); |
| if (!dpy) { |
| fprintf(stderr, "Error: unable to open display %s\n", XDisplayName(displayName)); |
| return -1; |
| } |
| |
| if (findBest) { |
| int b; |
| mesa_hack(dpy, 0); |
| b = find_best_visual(dpy, 0); |
| printf("%d\n", b); |
| } |
| else { |
| numScreens = ScreenCount(dpy); |
| print_display_info(dpy); |
| for (scrnum = 0; scrnum < numScreens; scrnum++) { |
| mesa_hack(dpy, scrnum); |
| print_screen_info(dpy, scrnum, allowDirect, limits); |
| printf("\n"); |
| print_visual_info(dpy, scrnum, mode); |
| #ifdef GLX_VERSION_1_3 |
| print_fbconfig_info(dpy, scrnum, mode); |
| #endif |
| if (scrnum + 1 < numScreens) |
| printf("\n\n"); |
| } |
| } |
| |
| XCloseDisplay(dpy); |
| |
| return 0; |
| } |