[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