[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