[Mesa-dev] [PATCH] glxinfo: add support for creating/querying core-profile contexts

Brian Paul brianp at vmware.com
Fri Jun 10 19:35:42 PDT 2011


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



More information about the mesa-dev mailing list