+ }
+ return buffer;
+}
+
+
+
static void
print_display_info(Display *dpy)
{
@@ -373,7 +452,7 @@ extension_supported(const char *ext, const char
*extensionsList)
* Print interesting OpenGL implementation limits.
*/
static void
-print_limits(const char *extensions)
+print_limits(const char *extensions, const char *oglstring)
{
struct token_name {
GLuint count;
@@ -436,7 +515,7 @@ print_limits(const char *extensions)
};
GLint i, max[2];
- printf("OpenGL limits:\n");
+ printf("%s limits:\n", oglstring);
for (i = 0; limits[i].count; i++) {
if (!limits[i].extension ||
extension_supported(limits[i].extension, extensions)) {
@@ -480,10 +559,249 @@ 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, Bool direct)
+{
+#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 */
+ direct,
+ attribs);
+
+ /* restore error handler */
+ XSetErrorHandler(old_handler);
+
+ if (CreateContextErrorFlag)
+ context = 0;
+
+ if (direct) {
+ if (!glXIsDirect(dpy, context)) {
+ glXDestroyContext(dpy, context);
+ return 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 coreProfile, Bool direct)
+{
+ 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,
+ direct);
+ if (ctx)
+ return 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, direct);
+
+ /* make sure the context is direct, if direct was requested */
+ if (ctx&& direct) {
+ if (!glXIsDirect(dpy, ctx)) {
+ glXDestroyContext(dpy, ctx);
+ return 0;
+ }
+ }
+
+ return ctx;
+}
+
+
+static XVisualInfo *
+choose_xvisinfo(Display *dpy, int scrnum)
{
- Window win;
int attribSingle[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
@@ -497,60 +815,53 @@ 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;
+ const char *oglstring = coreProfile ? "OpenGL core profile" : "OpenGL";
root = RootWindow(dpy, scrnum);
/*
- * Find a basic GLX visual. We'll then create a rendering context and
- * query various info strings.
- */
- 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?
+ * Choose FBConfig or XVisualInfo and create a context.
*/
- 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],
+ coreProfile, allowDirect);
+ if (!ctx&& allowDirect) {
+ /* try indirect */
+ ctx = create_context_with_config(dpy, fbconfigs[0],
+ coreProfile, False);
}
+
+ 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");
@@ -563,6 +874,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);
@@ -583,72 +897,118 @@ 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 */
+
+ CheckError(__LINE__);
+ /* Get list of GL extensions */
+ if (coreProfile) {
+ glExtensions = build_core_profile_extension_list();
+ }
+ else {
+ glExtensions = (char *) glGetString(GL_EXTENSIONS);
+ }
+
+ CheckError(__LINE__);
+
if (! glXQueryVersion( dpy,& glxVersionMajor,& glxVersionMinor )) {
fprintf(stderr, "Error: glXQueryVersion failed\n");
exit(1);
}
- /* Strip the screen number from the display name, if present. */
- if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1))) {
- fprintf(stderr, "Error: malloc() failed\n");
- exit(1);
- }
- strcpy(displayName, DisplayString(dpy));
- colon = strrchr(displayName, ':');
- if (colon) {
- period = strchr(colon, '.');
- if (period)
- *period = '\0';
- }
- printf("display: %s screen: %d\n", displayName, scrnum);
- free(displayName);
- printf("direct rendering: ");
- if (glXIsDirect(dpy, ctx)) {
- printf("Yes\n");
- }
- else {
- if (!allowDirect) {
- printf("No (-i specified)\n");
+ if (!coreProfile) {
+ /* Strip the screen number from the display name, if present. */
+ if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1)))
{
+ fprintf(stderr, "Error: malloc() failed\n");
+ exit(1);
}
- else if (getenv("LIBGL_ALWAYS_INDIRECT")) {
- printf("No (LIBGL_ALWAYS_INDIRECT set)\n");
+ strcpy(displayName, DisplayString(dpy));
+ colon = strrchr(displayName, ':');
+ if (colon) {
+ period = strchr(colon, '.');
+ if (period)
+ *period = '\0';
+ }
+
+ printf("display: %s screen: %d\n", displayName, scrnum);
+ free(displayName);
+ printf("direct rendering: ");
+ if (glXIsDirect(dpy, ctx)) {
+ printf("Yes\n");
}
else {
- printf("No (If you want to find out why, try setting "
- "LIBGL_DEBUG=verbose)\n");
+ if (!allowDirect) {
+ printf("No (-i specified)\n");
+ }
+ else if (getenv("LIBGL_ALWAYS_INDIRECT")) {
+ printf("No (LIBGL_ALWAYS_INDIRECT set)\n");
+ }
+ else {
+ printf("No (If you want to find out why, try setting "
+ "LIBGL_DEBUG=verbose)\n");
+ }
}
- }
- printf("server glx vendor string: %s\n", serverVendor);
- printf("server glx version string: %s\n", serverVersion);
- printf("server glx extensions:\n");
- print_extension_list(serverExtensions, singleLine);
- printf("client glx vendor string: %s\n", clientVendor);
- printf("client glx version string: %s\n", clientVersion);
- printf("client glx extensions:\n");
- print_extension_list(clientExtensions, singleLine);
- printf("GLX version: %u.%u\n", glxVersionMajor, glxVersionMinor);
- printf("GLX extensions:\n");
- print_extension_list(glxExtensions, singleLine);
- printf("OpenGL vendor string: %s\n", glVendor);
- printf("OpenGL renderer string: %s\n", glRenderer);
- printf("OpenGL version string: %s\n", glVersion);
+ printf("server glx vendor string: %s\n", serverVendor);
+ printf("server glx version string: %s\n", serverVersion);
+ printf("server glx extensions:\n");
+ print_extension_list(serverExtensions, singleLine);
+ printf("client glx vendor string: %s\n", clientVendor);
+ printf("client glx version string: %s\n", clientVersion);
+ printf("client glx extensions:\n");
+ print_extension_list(clientExtensions, singleLine);
+ printf("GLX version: %u.%u\n", glxVersionMajor, glxVersionMinor);
+ printf("GLX extensions:\n");
+ print_extension_list(glxExtensions, singleLine);
+ printf("OpenGL vendor string: %s\n", glVendor);
+ printf("OpenGL renderer string: %s\n", glRenderer);
+ } else
+ printf("\n");
+
+ printf("%s version string: %s\n", oglstring, glVersion);
+
+ version = (glVersion[0] - '0') * 10 + (glVersion[2] - '0');
+
+ CheckError(__LINE__);
+
#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);
+ printf("%s shading language version string: %s\n", oglstring, v);
+ }
+#endif
+ CheckError(__LINE__);
+#ifdef GL_VERSION_3_0
+ if (version>= 30) {
+ GLint flags;
+ glGetIntegerv(GL_CONTEXT_FLAGS,&flags);
+ printf("%s context flags: %s\n", oglstring,
context_flags_string(flags));
}
#endif
+ CheckError(__LINE__);
+#ifdef GL_VERSION_3_2
+ if (version>= 32) {
+ GLint mask;
+ glGetIntegerv(GL_CONTEXT_PROFILE_MASK,&mask);
+ printf("%s profile mask: %s\n", oglstring, profile_mask_string(mask));
+ }
+#endif
+
+ CheckError(__LINE__);
- printf("OpenGL extensions:\n");
+ printf("%s extensions:\n", oglstring);
print_extension_list(glExtensions, singleLine);
+
+ CheckError(__LINE__);
+
if (limits)
- print_limits(glExtensions);
+ print_limits(glExtensions, oglstring);
+
+ if (coreProfile)
+ free(glExtensions);
}
else {
fprintf(stderr, "Error: glXMakeCurrent failed\n");
@@ -657,6 +1017,7 @@ print_screen_info(Display *dpy, int scrnum, Bool
allowDirect, Bool limits, Bool
glXDestroyContext(dpy, ctx);
XFree(visinfo);
XDestroyWindow(dpy, win);
+ XSync(dpy, 1);
}
@@ -684,26 +1045,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 *
@@ -1296,7 +1644,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] [-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");
@@ -1372,7 +1720,8 @@ 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, 0, limits, singleLine);
+ print_screen_info(dpy, scrnum, allowDirect, 1, limits, singleLine);