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; + + 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; + } + } + + /* 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