[Mesa-dev] [PATCH] glxinfo: add support for creating/querying core-profile contexts
Gustaw Smolarczyk
wielkiegie at gmail.com
Sun Jun 12 11:56:07 PDT 2011
I found some bugs in this code.
2011/6/11 Brian Paul <brianp at 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 at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
More information about the mesa-dev
mailing list