I found some bugs in this code. 2011/6/11 Brian Paul <bri...@vmware.com>: > The -c flag says to try to create a core profile (no legacy features) > using glXCreateContextAttribsARB(). A core profile may advertise a > different set of extensions than a compatibility profile (though, > the only difference with NVIDIA's driver is the presence of > GL_ARB_compatibility). Also note that extensions need to be queried > one at a time with glGetStringi(). > --- > src/xdemos/glxinfo.c | 430 > ++++++++++++++++++++++++++++++++++++++++++-------- > 1 files changed, 366 insertions(+), 64 deletions(-) > > diff --git a/src/xdemos/glxinfo.c b/src/xdemos/glxinfo.c > index fe2f68b..90ad49c 100644 > --- a/src/xdemos/glxinfo.c > +++ b/src/xdemos/glxinfo.c > @@ -29,6 +29,7 @@ > * -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) > + * -c request a core profile rendering context > * > * Brian Paul 26 January 2000 > */ > @@ -62,6 +63,8 @@ > #define GLX_COLOR_INDEX_BIT 0x00000002 > #endif > > +#define ELEMENTS(array) (sizeof(array) / sizeof(array[0])) > + > typedef enum > { > Normal, > @@ -108,6 +111,29 @@ struct visual_attribs > }; > > > +/** list of known OpenGL versions */ > +static struct { int major, minor; } gl_versions[] = { > + {1, 0}, > + {1, 1}, > + {1, 2}, > + {1, 3}, > + {1, 4}, > + {1, 5}, > + {2, 0}, > + {2, 1}, > + {3, 0}, > + {3, 1}, > + {3, 2}, > + {3, 3}, > + {4, 0}, > + {4, 1}, > + {4, 2}, > + {0, 0} /* end of list */ > +}; > + > +#define NUM_GL_VERSIONS ELEMENTS(gl_versions) > + > + > /* > * qsort callback for string comparison. > */ > @@ -219,6 +245,45 @@ print_extension_list(const char *ext, Bool singleLine) > } > > > +/** > + * Get list of OpenGL extensions using core profile's glGetStringi(). > + */ > +static char * > +build_core_profile_extension_list(void) > +{ > + GLint i, n, totalLen; > + char *buffer; > + static PFNGLGETSTRINGIPROC glGetStringi_func = NULL; > + > + if (!glGetStringi_func) { > + glGetStringi_func = (PFNGLGETSTRINGIPROC) > + glXGetProcAddressARB((GLubyte *) "glGetStringi"); > + } > + > + glGetIntegerv(GL_NUM_EXTENSIONS, &n); > + > + /* compute totalLen */ > + totalLen = 0; > + for (i = 0; i < n; i++) { > + const char *ext = (const char *) glGetStringi_func(GL_EXTENSIONS, i); > + totalLen += strlen(ext) + 1; /* plus a space */ > + } > + > + buffer = malloc(totalLen); > + if (buffer) { > + int pos = 0; > + for (i = 0; i < n; i++) { > + const char *ext = (const char *) glGetStringi_func(GL_EXTENSIONS, > i); > + strcpy(buffer + pos, ext); > + pos += strlen(ext); > + buffer[pos++] = ' '; > + } > + } > + return buffer; > +} > + > + > + > static void > print_display_info(Display *dpy) > { > @@ -472,10 +537,235 @@ print_limits(const char *extensions) > } > > > -static void > -print_screen_info(Display *dpy, int scrnum, Bool allowDirect, Bool limits, > Bool singleLine) > +struct bit_info > +{ > + int bit; > + const char *name; > +}; > + > + > +/** > + * Return string representation for bits in a bitmask. > + */ > +static const char * > +bitmask_to_string(const struct bit_info bits[], int numBits, int mask) > +{ > + static char buffer[256], *p; > + int i; > + > + strcpy(buffer, "(none)"); > + p = buffer; > + for (i = 0; i < numBits; i++) { > + if (mask & bits[i].bit) { > + if (p > buffer) > + *p++ = ','; > + strcpy(p, bits[i].name); > + p += strlen(bits[i].name); > + } > + } > + > + return buffer; > +} > + > +/** > + * Return string representation for the bitmask returned by > + * GL_CONTEXT_PROFILE_MASK (OpenGL 3.2 or later). > + */ > +static const char * > +profile_mask_string(int mask) > +{ > + const static struct bit_info bits[] = { > +#ifdef GL_CONTEXT_CORE_PROFILE_BIT > + { GL_CONTEXT_CORE_PROFILE_BIT, "core profile"}, > +#endif > +#ifdef GL_CONTEXT_COMPATIBILITY_PROFILE_BIT > + { GL_CONTEXT_COMPATIBILITY_PROFILE_BIT, "compatibility profile" } > +#endif > + }; > + > + return bitmask_to_string(bits, ELEMENTS(bits), mask); > +} > + > + > +/** > + * Return string representation for the bitmask returned by > + * GL_CONTEXT_FLAGS (OpenGL 3.0 or later). > + */ > +static const char * > +context_flags_string(int mask) > +{ > + const static struct bit_info bits[] = { > +#ifdef GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT > + { GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT, "forward-compatible" }, > +#endif > +#ifdef GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB > + { GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB, "robust-access" }, > +#endif > + }; > + > + return bitmask_to_string(bits, ELEMENTS(bits), mask); > +} > + > + > +/** > + * Choose a simple FB Config. > + */ > +static GLXFBConfig * > +choose_fb_config(Display *dpy, int scrnum) > +{ > + int fbAttribSingle[] = { > + GLX_RENDER_TYPE, GLX_RGBA_BIT, > + GLX_RED_SIZE, 1, > + GLX_GREEN_SIZE, 1, > + GLX_BLUE_SIZE, 1, > + GLX_DOUBLEBUFFER, False, > + None }; > + int fbAttribDouble[] = { > + GLX_RENDER_TYPE, GLX_RGBA_BIT, > + GLX_RED_SIZE, 1, > + GLX_GREEN_SIZE, 1, > + GLX_BLUE_SIZE, 1, > + GLX_DOUBLEBUFFER, True, > + None }; > + GLXFBConfig *configs; > + int nConfigs; > + > + configs = glXChooseFBConfig(dpy, scrnum, fbAttribSingle, &nConfigs); > + if (!configs) > + configs = glXChooseFBConfig(dpy, scrnum, fbAttribDouble, &nConfigs); > + > + return configs; > +} > + > + > +static Bool CreateContextErrorFlag; > + > +static int > +create_context_error_handler(Display *dpy, XErrorEvent *error) > +{ > + (void) dpy; > + (void) error->error_code; > + CreateContextErrorFlag = True; > + return 0; > +} > + > + > +/** > + * Try to create a GLX context of the given version with flags/options. > + * Note: A version number is required in order to get a core profile > + * (at least w/ NVIDIA). > + */ > +static GLXContext > +create_context_flags(Display *dpy, GLXFBConfig fbconfig, int major, int > minor, > + int contextFlags, int profileMask) > +{ > +#ifdef GLX_ARB_create_context > + static PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB_func > = 0; > + static Bool firstCall = True; > + int (*old_handler)(Display *, XErrorEvent *); > + GLXContext context; > + int attribs[20]; > + int n = 0; > + > + if (firstCall) { > + /* See if we have GLX_ARB_create_context_profile and get pointer to > + * glXCreateContextAttribsARB() function. > + */ > + const char *glxExt = glXQueryExtensionsString(dpy, 0); > + if (extension_supported("GLX_ARB_create_context_profile", glxExt)) { > + glXCreateContextAttribsARB_func = > (PFNGLXCREATECONTEXTATTRIBSARBPROC) > + glXGetProcAddress((const GLubyte *) > "glXCreateContextAttribsARB"); > + } > + firstCall = False; > + } > + > + if (!glXCreateContextAttribsARB_func) > + return 0; > + > + /* setup attribute array */ > + if (major) { > + attribs[n++] = GLX_CONTEXT_MAJOR_VERSION_ARB; > + attribs[n++] = major; > + attribs[n++] = GLX_CONTEXT_MINOR_VERSION_ARB; > + attribs[n++] = minor; > + } > + if (contextFlags) { > + attribs[n++] = GLX_CONTEXT_FLAGS_ARB; > + attribs[n++] = contextFlags; > + } > +#ifdef GLX_ARB_create_context_profile > + if (profileMask) { > + attribs[n++] = GLX_CONTEXT_PROFILE_MASK_ARB; > + attribs[n++] = profileMask; > + } > +#endif > + attribs[n++] = 0; > + > + /* install X error handler */ > + old_handler = XSetErrorHandler(create_context_error_handler); > + CreateContextErrorFlag = False; > + > + /* try creating context */ > + context = glXCreateContextAttribsARB_func(dpy, > + fbconfig, > + 0, /* share_context */ > + True, /* direct */ > + attribs); > + > + /* restore error handler */ > + XSetErrorHandler(old_handler); > + > + if (CreateContextErrorFlag) > + context = 0;
The context should be tested against being direct. For example, fglrx will happily create "4.2" context, but it will be just default indirect one. > + > + return context; > +#else > + return 0; > +#endif > +} > + > + > +/** > + * Try to create a GLX context of the newest version. > + */ > +static GLXContext > +create_context_with_config(Display *dpy, GLXFBConfig config, Bool > allowDirect, > + Bool coreProfile) > +{ > + GLXContext ctx = 0; > + > + if (coreProfile) { > + /* Try to create a core profile, starting with the newest version of > + * GL that we're aware of. If we don't specify the version > + */ > + int i; > + for (i = NUM_GL_VERSIONS - 2; i > 0 ; i--) { > + ctx = create_context_flags(dpy, config, > + gl_versions[i].major, > + gl_versions[i].minor, > + 0x0, > + GLX_CONTEXT_CORE_PROFILE_BIT_ARB); > + if (ctx) > + break; > + } > + if (!ctx) { > + /* couldn't get core profile context */ > + return 0; > + } There's something missing here. If ctx is not NULL, it will be overwritten by code below. There should be "return ctx;" line here IMHO. > + } > + > + /* GLX should return a context of the latest GL version that supports > + * the full profile. > + */ > + ctx = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, allowDirect); > + > + return ctx; > +} > + > + > +static XVisualInfo * > +choose_xvisinfo(Display *dpy, int scrnum) > { > - Window win; > int attribSingle[] = { > GLX_RGBA, > GLX_RED_SIZE, 1, > @@ -489,60 +779,46 @@ print_screen_info(Display *dpy, int scrnum, Bool > allowDirect, Bool limits, Bool > GLX_BLUE_SIZE, 1, > GLX_DOUBLEBUFFER, > None }; > + XVisualInfo *visinfo; > + > + visinfo = glXChooseVisual(dpy, scrnum, attribSingle); > + if (!visinfo) > + visinfo = glXChooseVisual(dpy, scrnum, attribDouble); > > + return visinfo; > +} > + > + > +static void > +print_screen_info(Display *dpy, int scrnum, Bool allowDirect, > + Bool coreProfile, Bool limits, Bool singleLine) > +{ > + Window win; > XSetWindowAttributes attr; > unsigned long mask; > Window root; > GLXContext ctx = NULL; > XVisualInfo *visinfo; > int width = 100, height = 100; > + GLXFBConfig *fbconfigs; > > root = RootWindow(dpy, scrnum); > > /* > - * Find a basic GLX visual. We'll then create a rendering context and > - * query various info strings. > + * Choose FBConfig or XVisualInfo and create a context. > */ > - 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, False, > - None }; > - int fbAttribDouble[] = { > - GLX_RENDER_TYPE, GLX_RGBA_BIT, > - GLX_RED_SIZE, 1, > - GLX_GREEN_SIZE, 1, > - GLX_BLUE_SIZE, 1, > - GLX_DOUBLEBUFFER, 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); > - } > + fbconfigs = choose_fb_config(dpy, scrnum); > + if (fbconfigs) { > + ctx = create_context_with_config(dpy, fbconfigs[0], allowDirect, > + coreProfile); > + visinfo = glXGetVisualFromFBConfig(dpy, fbconfigs[0]); > + XFree(fbconfigs); > + } > + else { > + visinfo = choose_xvisinfo(dpy, scrnum); > + if (visinfo) > + ctx = glXCreateContext(dpy, visinfo, NULL, allowDirect); > } > -#endif > > if (!visinfo) { > fprintf(stderr, "Error: couldn't find RGB GLX visual or fbconfig\n"); > @@ -555,6 +831,9 @@ print_screen_info(Display *dpy, int scrnum, Bool > allowDirect, Bool limits, Bool > return; > } > > + /* > + * Create a window so that we can just bind the context. > + */ > attr.background_pixel = 0; > attr.border_pixel = 0; > attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone); > @@ -575,12 +854,21 @@ print_screen_info(Display *dpy, int scrnum, Bool > allowDirect, Bool limits, Bool > 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); > + char *glExtensions; > int glxVersionMajor; > int glxVersionMinor; > char *displayName = NULL; > char *colon = NULL, *period = NULL; > - > + int version; /* 20, 21, 30, 31, 32, etc */ > + > + /* Get list of GL extensions */ > + if (coreProfile) { > + glExtensions = build_core_profile_extension_list(); > + } > + else { > + glExtensions = (char *) glGetString(GL_EXTENSIONS); > + } > + > if (! glXQueryVersion( dpy, & glxVersionMajor, & glxVersionMinor )) { > fprintf(stderr, "Error: glXQueryVersion failed\n"); > exit(1); > @@ -630,17 +918,39 @@ print_screen_info(Display *dpy, int scrnum, Bool > allowDirect, Bool limits, Bool > printf("OpenGL vendor string: %s\n", glVendor); > printf("OpenGL renderer string: %s\n", glRenderer); > printf("OpenGL version string: %s\n", glVersion); > + > + version = (glVersion[0] - '0') * 10 + (glVersion[2] - '0'); > + > #ifdef GL_VERSION_2_0 > - if (glVersion[0] >= '2' && glVersion[1] == '.') { > + if (version >= 20) { > char *v = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION); > printf("OpenGL shading language version string: %s\n", v); > } > #endif > +#ifdef GL_VERSION_3_0 > + if (version >= 30) { > + GLint flags; > + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); > + printf("OpenGL context flags: %s\n", context_flags_string(flags)); > + } > +#endif > +#ifdef GL_VERSION_3_2 > + if (version >= 32) { > + GLint mask; > + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); > + printf("OpenGL profile mask: %s\n", profile_mask_string(mask)); > + } > +#endif > > + assert(glGetError()==0); > printf("OpenGL extensions:\n"); > print_extension_list(glExtensions, singleLine); > + > if (limits) > print_limits(glExtensions); > + > + if (coreProfile) > + free(glExtensions); > } > else { > fprintf(stderr, "Error: glXMakeCurrent failed\n"); > @@ -676,26 +986,13 @@ visual_class_name(int cls) > static const char * > visual_drawable_type(int type) > { > - static char buffer[256], *p; > - const static struct { int bit; const char *name; } bits[] = { > + const static struct bit_info bits[] = { > { GLX_WINDOW_BIT, "window" }, > { GLX_PIXMAP_BIT, "pixmap" }, > { GLX_PBUFFER_BIT, "pbuffer" } > }; > - int i; > > - strcpy(buffer, "(none)"); > - p = buffer; > - for (i = 0; i < 3; i++) { > - if (type & bits[i].bit) { > - if (p > buffer) > - *p++ = ','; > - strcpy(p, bits[i].name); > - p += strlen(bits[i].name); > - } > - } > - > - return buffer; > + return bitmask_to_string(bits, ELEMENTS(bits), type); > } > > static const char * > @@ -1288,7 +1585,7 @@ find_best_visual(Display *dpy, int scrnum) > static void > usage(void) > { > - printf("Usage: glxinfo [-v] [-t] [-h] [-i] [-b] [-s] ][-display > <dname>]\n"); > + printf("Usage: glxinfo [-v] [-t] [-h] [-i] [-b] [-s] [-c]][-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"); > @@ -1297,6 +1594,7 @@ usage(void) > printf("\t-b: Find the 'best' visual and print its number.\n"); > printf("\t-l: Print interesting OpenGL limits.\n"); > printf("\t-s: Print a single extension per line.\n"); > + printf("\t-c: Request a core profile rendering context.\n"); > } > > > @@ -1311,6 +1609,7 @@ main(int argc, char *argv[]) > Bool limits = False; > Bool allowDirect = True; > Bool singleLine = False; > + Bool coreProfile = False; > int i; > > for (i = 1; i < argc; i++) { > @@ -1340,6 +1639,9 @@ main(int argc, char *argv[]) > else if (strcmp(argv[i], "-s") == 0) { > singleLine = True; > } > + else if (strcmp(argv[i], "-c") == 0) { > + coreProfile = True; > + } > else { > printf("Unknown option `%s'\n", argv[i]); > usage(); > @@ -1364,7 +1666,7 @@ main(int argc, char *argv[]) > print_display_info(dpy); > for (scrnum = 0; scrnum < numScreens; scrnum++) { > mesa_hack(dpy, scrnum); > - print_screen_info(dpy, scrnum, allowDirect, limits, singleLine); > + print_screen_info(dpy, scrnum, allowDirect, coreProfile, limits, > singleLine); > printf("\n"); > print_visual_info(dpy, scrnum, mode); > #ifdef GLX_VERSION_1_3 > -- > 1.7.3.4 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev > _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev