egl_glx: Clean up the initialization code.
authorChia-I Wu <olvaffe@gmail.com>
Thu, 1 Oct 2009 10:16:10 +0000 (18:16 +0800)
committerBrian Paul <brianp@vmware.com>
Thu, 22 Oct 2009 15:33:27 +0000 (09:33 -0600)
Proper detection of GLX extensions.  Convert fbconfigs or visuals in a
more unified way and validate the resulting configs.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
src/egl/drivers/glx/egl_glx.c

index 4685f60..404c998 100644 (file)
  */
 
 
-#include <assert.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include "dlfcn.h"
+#include <stdlib.h>
+#include <string.h>
 #include <X11/Xlib.h>
-#include <GL/gl.h>
+#include <dlfcn.h>
+
 #include "glxclient.h"
 
+#include "eglconfigutil.h"
 #include "eglconfig.h"
 #include "eglcontext.h"
 #include "egldisplay.h"
 #include "egllog.h"
 #include "eglsurface.h"
 
-#include <GL/gl.h>
-
 #define CALLOC_STRUCT(T)   (struct T *) calloc(1, sizeof(struct T))
+#define ARRAY_SIZE(a)      (sizeof(a) / sizeof(a[0]))
 
-static const EGLint all_apis = (EGL_OPENGL_ES_BIT
-                                | EGL_OPENGL_ES2_BIT
-                                | EGL_OPENVG_BIT
-                                /* | EGL_OPENGL_BIT */); /* can't do */
+#ifndef GLX_VERSION_1_4
+#error "GL/glx.h must be equal to or greater than GLX 1.4"
+#endif
+
+/*
+ * report OpenGL ES bits because apps usually forget to specify
+ * EGL_RENDERABLE_TYPE when choosing configs
+ */
+#define GLX_EGL_APIS (EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT)
 
-struct visual_attribs
-{
-   /* X visual attribs */
-   int id;
-   int klass;
-   int depth;
-   int redMask, greenMask, blueMask;
-   int colormapSize;
-   int bitsPerRGB;
-
-   /* GL visual attribs */
-   int supportsGL;
-   int transparentType;
-   int transparentRedValue;
-   int transparentGreenValue;
-   int transparentBlueValue;
-   int transparentAlphaValue;
-   int transparentIndexValue;
-   int bufferSize;
-   int level;
-   int render_type;
-   int doubleBuffer;
-   int stereo;
-   int auxBuffers;
-   int redSize, greenSize, blueSize, alphaSize;
-   int depthSize;
-   int stencilSize;
-   int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
-   int numSamples, numMultisample;
-   int visualCaveat;
-};
 
 /** subclass of _EGLDriver */
 struct GLX_egl_driver
@@ -114,6 +85,21 @@ struct GLX_egl_display
    GLXFBConfig *fbconfigs;
 
    int glx_maj, glx_min;
+
+   const char *extensions;
+   EGLBoolean have_1_3;
+   EGLBoolean have_make_current_read;
+   EGLBoolean have_fbconfig;
+   EGLBoolean have_pbuffer;
+
+   /* GLX_SGIX_pbuffer */
+   PFNGLXCREATEGLXPBUFFERSGIXPROC glXCreateGLXPbufferSGIX;
+   PFNGLXDESTROYGLXPBUFFERSGIXPROC glXDestroyGLXPbufferSGIX;
+
+   /* workaround quirks of different GLX implementations */
+   EGLBoolean single_buffered_quirk;
+   EGLBoolean glx_window_quirk;
+
 };
 
 
@@ -139,6 +125,7 @@ struct GLX_egl_surface
 struct GLX_egl_config
 {
    _EGLConfig Base;   /**< base class */
+   EGLBoolean double_buffered;
    int index;
 };
 
@@ -173,288 +160,369 @@ GLX_egl_config_index(_EGLConfig *conf)
    return ((struct GLX_egl_config *) conf)->index;
 }
 
-static GLboolean
-get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
-                   struct visual_attribs *attribs)
-{
-   const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
-   int rgba;
 
-   memset(attribs, 0, sizeof(struct visual_attribs));
+#define MAP_ATTRIB(attr, memb) \
+   { attr, offsetof(__GLcontextModes, memb) }
+
+
+static const struct {
+   int attr;
+   int offset;
+} fbconfig_attributes[] = {
+   /* table 3.1 of GLX 1.4 */
+   MAP_ATTRIB(GLX_FBCONFIG_ID,                  fbconfigID),
+   MAP_ATTRIB(GLX_BUFFER_SIZE,                  rgbBits),
+   MAP_ATTRIB(GLX_LEVEL,                        level),
+   MAP_ATTRIB(GLX_DOUBLEBUFFER,                 doubleBufferMode),
+   MAP_ATTRIB(GLX_STEREO,                       stereoMode),
+   MAP_ATTRIB(GLX_AUX_BUFFERS,                  numAuxBuffers),
+   MAP_ATTRIB(GLX_RED_SIZE,                     redBits),
+   MAP_ATTRIB(GLX_GREEN_SIZE,                   greenBits),
+   MAP_ATTRIB(GLX_BLUE_SIZE,                    blueBits),
+   MAP_ATTRIB(GLX_ALPHA_SIZE,                   alphaBits),
+   MAP_ATTRIB(GLX_DEPTH_SIZE,                   depthBits),
+   MAP_ATTRIB(GLX_STENCIL_SIZE,                 stencilBits),
+   MAP_ATTRIB(GLX_ACCUM_RED_SIZE,               accumRedBits),
+   MAP_ATTRIB(GLX_ACCUM_GREEN_SIZE,             accumGreenBits),
+   MAP_ATTRIB(GLX_ACCUM_BLUE_SIZE,              accumBlueBits),
+   MAP_ATTRIB(GLX_ACCUM_ALPHA_SIZE,             accumAlphaBits),
+   MAP_ATTRIB(GLX_SAMPLE_BUFFERS,               sampleBuffers),
+   MAP_ATTRIB(GLX_SAMPLES,                      samples),
+   MAP_ATTRIB(GLX_RENDER_TYPE,                  renderType),
+   MAP_ATTRIB(GLX_DRAWABLE_TYPE,                drawableType),
+   MAP_ATTRIB(GLX_X_RENDERABLE,                 xRenderable),
+   MAP_ATTRIB(GLX_X_VISUAL_TYPE,                visualType),
+   MAP_ATTRIB(GLX_CONFIG_CAVEAT,                visualRating),
+   MAP_ATTRIB(GLX_TRANSPARENT_TYPE,             transparentPixel),
+   MAP_ATTRIB(GLX_TRANSPARENT_INDEX_VALUE,      transparentIndex),
+   MAP_ATTRIB(GLX_TRANSPARENT_RED_VALUE,        transparentRed),
+   MAP_ATTRIB(GLX_TRANSPARENT_GREEN_VALUE,      transparentGreen),
+   MAP_ATTRIB(GLX_TRANSPARENT_BLUE_VALUE,       transparentBlue),
+   MAP_ATTRIB(GLX_TRANSPARENT_ALPHA_VALUE,      transparentAlpha),
+   MAP_ATTRIB(GLX_MAX_PBUFFER_WIDTH,            maxPbufferWidth),
+   MAP_ATTRIB(GLX_MAX_PBUFFER_HEIGHT,           maxPbufferHeight),
+   MAP_ATTRIB(GLX_MAX_PBUFFER_PIXELS,           maxPbufferPixels),
+   MAP_ATTRIB(GLX_VISUAL_ID,                    visualID),
+};
 
-   attribs->id = vInfo->visualid;
-#if defined(__cplusplus) || defined(c_plusplus)
-   attribs->klass = vInfo->c_class;
-#else
-   attribs->klass = vInfo->class;
-#endif
-   attribs->depth = vInfo->depth;
-   attribs->redMask = vInfo->red_mask;
-   attribs->greenMask = vInfo->green_mask;
-   attribs->blueMask = vInfo->blue_mask;
-   attribs->colormapSize = vInfo->colormap_size;
-   attribs->bitsPerRGB = vInfo->bits_per_rgb;
-
-   if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0 ||
-       !attribs->supportsGL)
-      return GL_FALSE;
-   glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
-   glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
-   glXGetConfig(dpy, vInfo, GLX_RGBA, &rgba);
-   if (!rgba)
-      return GL_FALSE;
-   attribs->render_type = GLX_RGBA_BIT;
-   
-   glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
-   if (!attribs->doubleBuffer)
-      return GL_FALSE;
-
-   glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
-   glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
-   glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
-   glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
-   glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
-   glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
-   glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
-   glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
-   glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
-   glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
-   glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
-   glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
-
-   /* get transparent pixel stuff */
-   glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
-   if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
-     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
-     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
-     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
-     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
-   }
-   else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
-     glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
-   }
 
-   /* multisample attribs */
-#ifdef GLX_ARB_multisample
-   if (ext && strstr(ext, "GLX_ARB_multisample")) {
-      glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample);
-      glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples);
-   }
-#endif
-   else {
-      attribs->numSamples = 0;
-      attribs->numMultisample = 0;
+static EGLBoolean
+convert_fbconfig(Display *dpy, GLXFBConfig fbconfig,
+                 struct GLX_egl_config *GLX_conf)
+{
+   __GLcontextModes mode;
+   int err = 0, attr, val, i;
+
+   memset(&mode, 0, sizeof(mode));
+
+   for (i = 0; i < ARRAY_SIZE(fbconfig_attributes); i++) {
+      int offset = fbconfig_attributes[i].offset;
+      attr = fbconfig_attributes[i].attr;
+      err = glXGetFBConfigAttrib(dpy, fbconfig, attr, &val);
+      if (err) {
+         if (err == GLX_BAD_ATTRIBUTE) {
+            err = 0;
+            continue;
+         }
+         break;
+      }
+      *((int *) ((char *) &mode + offset)) = val;
    }
+   if (err)
+      return EGL_FALSE;
 
-#if defined(GLX_EXT_visual_rating)
-   if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
-      glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
-   }
-   else {
-      attribs->visualCaveat = GLX_NONE_EXT;
+   /* must have rgba bit */
+   if (!(mode.renderType & GLX_RGBA_BIT))
+      return EGL_FALSE;
+
+   /* pixmap and pbuffer surfaces must be single-buffered in EGL */
+   if (mode.doubleBufferMode) {
+      mode.drawableType &= ~(GLX_PIXMAP_BIT | GLX_PBUFFER_BIT);
+      if (!mode.drawableType)
+         return EGL_FALSE;
    }
-#else
-   attribs->visualCaveat = 0;
-#endif
 
-   return GL_TRUE;
+   mode.rgbMode = GL_TRUE;
+   mode.haveAccumBuffer = (mode.accumRedBits +
+                           mode.accumGreenBits +
+                           mode.accumBlueBits +
+                           mode.accumAlphaBits > 0);
+   mode.haveDepthBuffer = (mode.depthBits > 0);
+   mode.haveStencilBuffer = (mode.stencilBits > 0);
+
+   GLX_conf->double_buffered = (mode.doubleBufferMode != 0);
+   return _eglConfigFromContextModesRec(&GLX_conf->Base, &mode,
+                                        GLX_EGL_APIS, GLX_EGL_APIS);
 }
 
-#ifdef GLX_VERSION_1_3
+
+static const struct {
+   int attr;
+   int offset;
+} visual_attributes[] = {
+   /* table 3.7 of GLX 1.4 */
+   /* no GLX_USE_GL */
+   MAP_ATTRIB(GLX_BUFFER_SIZE,         rgbBits),
+   MAP_ATTRIB(GLX_LEVEL,               level),
+   MAP_ATTRIB(GLX_RGBA,                rgbMode),
+   MAP_ATTRIB(GLX_DOUBLEBUFFER,        doubleBufferMode),
+   MAP_ATTRIB(GLX_STEREO,              stereoMode),
+   MAP_ATTRIB(GLX_AUX_BUFFERS,         numAuxBuffers),
+   MAP_ATTRIB(GLX_RED_SIZE,            redBits),
+   MAP_ATTRIB(GLX_GREEN_SIZE,          greenBits),
+   MAP_ATTRIB(GLX_BLUE_SIZE,           blueBits),
+   MAP_ATTRIB(GLX_ALPHA_SIZE,          alphaBits),
+   MAP_ATTRIB(GLX_DEPTH_SIZE,          depthBits),
+   MAP_ATTRIB(GLX_STENCIL_SIZE,        stencilBits),
+   MAP_ATTRIB(GLX_ACCUM_RED_SIZE,      accumRedBits),
+   MAP_ATTRIB(GLX_ACCUM_GREEN_SIZE,    accumGreenBits),
+   MAP_ATTRIB(GLX_ACCUM_BLUE_SIZE,     accumBlueBits),
+   MAP_ATTRIB(GLX_ACCUM_ALPHA_SIZE,    accumAlphaBits),
+   MAP_ATTRIB(GLX_SAMPLE_BUFFERS,      sampleBuffers),
+   MAP_ATTRIB(GLX_SAMPLES,             samples),
+   MAP_ATTRIB(GLX_FBCONFIG_ID,         fbconfigID),
+   /* GLX_EXT_visual_rating */
+   MAP_ATTRIB(GLX_VISUAL_CAVEAT_EXT,   visualRating),
+};
+
 
 static int
-glx_token_to_visual_class(int visual_type)
-{
-   switch (visual_type) {
-   case GLX_TRUE_COLOR:
-      return TrueColor;
-   case GLX_DIRECT_COLOR:
-      return DirectColor;
-   case GLX_PSEUDO_COLOR:
-      return PseudoColor;
-   case GLX_STATIC_COLOR:
-      return StaticColor;
-   case GLX_GRAY_SCALE:
-      return GrayScale;
-   case GLX_STATIC_GRAY:
-      return StaticGray;
-   case GLX_NONE:
+get_visual_type(const XVisualInfo *vis)
+{
+   int klass;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+   klass = vis->c_class;
+#else
+   klass = vis->class;
+#endif
+
+   switch (klass) {
+   case TrueColor:
+      return GLX_TRUE_COLOR;
+   case DirectColor:
+      return GLX_DIRECT_COLOR;
+   case PseudoColor:
+      return GLX_PSEUDO_COLOR;
+   case StaticColor:
+      return GLX_STATIC_COLOR;
+   case GrayScale:
+      return GLX_GRAY_SCALE;
+   case StaticGray:
+      return GLX_STATIC_GRAY;
    default:
-      return None;
+      return GLX_NONE;
    }
 }
 
-static int
-get_fbconfig_attribs(Display *dpy, GLXFBConfig fbconfig,
-                    struct visual_attribs *attribs)
-{
-   int visual_type;
-   int fbconfig_id;
 
-   memset(attribs, 0, sizeof(struct visual_attribs));
+static EGLBoolean
+convert_visual(Display *dpy, XVisualInfo *vinfo,
+               struct GLX_egl_config *GLX_conf)
+{
+   __GLcontextModes mode;
+   int err, attr, val, i;
 
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_FBCONFIG_ID, &fbconfig_id);
+   /* the visual must support OpenGL */
+   err = glXGetConfig(dpy, vinfo, GLX_USE_GL, &val);
+   if (err || !val)
+      return EGL_FALSE;
 
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_VISUAL_ID, &attribs->id);
+   memset(&mode, 0, sizeof(mode));
+
+   for (i = 0; i < ARRAY_SIZE(visual_attributes); i++) {
+      int offset = visual_attributes[i].offset;
+      attr = visual_attributes[i].attr;
+      err = glXGetConfig(dpy, vinfo, attr, &val);
+      if (err) {
+         if (err == GLX_BAD_ATTRIBUTE) {
+            err = 0;
+            continue;
+         }
+         break;
+      }
+      *((int *) ((char *) &mode + offset)) = val;
+   }
+   if (err)
+      return EGL_FALSE;
 
-#if 0
-   attribs->depth = vInfo->depth;
-   attribs->redMask = vInfo->red_mask;
-   attribs->greenMask = vInfo->green_mask;
-   attribs->blueMask = vInfo->blue_mask;
-   attribs->colormapSize = vInfo->colormap_size;
-   attribs->bitsPerRGB = vInfo->bits_per_rgb;
-#endif
+   /* must be RGB mode */
+   if (!mode.rgbMode)
+      return EGL_FALSE;
 
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_X_VISUAL_TYPE, &visual_type);
-   attribs->klass = glx_token_to_visual_class(visual_type);
-
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_BUFFER_SIZE, &attribs->bufferSize);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_LEVEL, &attribs->level);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &attribs->render_type);
-   if (!(attribs->render_type & GLX_RGBA_BIT))
-      return 0;
-
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
-   if (!attribs->doubleBuffer)
-      return 0;
-
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_STEREO, &attribs->stereo);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_AUX_BUFFERS, &attribs->auxBuffers);
-
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_RED_SIZE, &attribs->redSize);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_GREEN_SIZE, &attribs->greenSize);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_BLUE_SIZE, &attribs->blueSize);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ALPHA_SIZE, &attribs->alphaSize);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_DEPTH_SIZE, &attribs->depthSize);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_STENCIL_SIZE, &attribs->stencilSize);
-
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
-
-   /* get transparent pixel stuff */
-   glXGetFBConfigAttrib(dpy, fbconfig,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
-   if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
-     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
-     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
-     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
-     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
-   }
-   else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
-     glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
-   }
+   mode.visualID = vinfo->visualid;
+   mode.visualType = get_visual_type(vinfo);
+   mode.redMask = vinfo->red_mask;
+   mode.greenMask = vinfo->green_mask;
+   mode.blueMask = vinfo->blue_mask;
+
+   mode.drawableType = GLX_WINDOW_BIT;
+   /* pixmap surfaces must be single-buffered in EGL */
+   if (!mode.doubleBufferMode)
+      mode.drawableType |= GLX_PIXMAP_BIT;
+
+   mode.renderType = GLX_RGBA_BIT;
+   mode.xRenderable = GL_TRUE;
+   mode.haveAccumBuffer = (mode.accumRedBits +
+                           mode.accumGreenBits +
+                           mode.accumBlueBits +
+                           mode.accumAlphaBits > 0);
+   mode.haveDepthBuffer = (mode.depthBits > 0);
+   mode.haveStencilBuffer = (mode.stencilBits > 0);
+
+   GLX_conf->double_buffered = (mode.doubleBufferMode != 0);
+   return _eglConfigFromContextModesRec(&GLX_conf->Base, &mode,
+                                        GLX_EGL_APIS, GLX_EGL_APIS);
+}
 
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLE_BUFFERS, &attribs->numMultisample);
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLES, &attribs->numSamples);
 
-   glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &attribs->visualCaveat);
+static void
+fix_config(struct GLX_egl_display *GLX_dpy, struct GLX_egl_config *GLX_conf)
+{
+   _EGLConfig *conf = &GLX_conf->Base;
+   EGLint surface_type, r, g, b, a;
+
+   surface_type = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
+   if (!GLX_conf->double_buffered && GLX_dpy->single_buffered_quirk) {
+      /* some GLX impls do not like single-buffered window surface */
+      surface_type &= ~EGL_WINDOW_BIT;
+      /* pbuffer bit is usually not set */
+      if (GLX_dpy->have_pbuffer)
+         surface_type |= EGL_PBUFFER_BIT;
+      SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type);
+   }
 
-   if (attribs->id == 0) {
-      attribs->id = fbconfig_id;
-      return EGL_PBUFFER_BIT | EGL_PIXMAP_BIT;
+   /* no visual attribs unless window bit is set */
+   if (!(surface_type & EGL_WINDOW_BIT)) {
+      SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, 0);
+      SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_NONE);
    }
 
-   return EGL_WINDOW_BIT;
+   /* make sure buffer size is set correctly */
+   r = GET_CONFIG_ATTRIB(conf, EGL_RED_SIZE);
+   g = GET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE);
+   b = GET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE);
+   a = GET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE);
+   SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, r + g + b + a);
 }
 
-#endif
 
 static EGLBoolean
-create_configs(_EGLDisplay *disp, struct GLX_egl_display *GLX_dpy)
+create_configs(_EGLDisplay *dpy, struct GLX_egl_display *GLX_dpy,
+               EGLint screen)
 {
-   XVisualInfo theTemplate;
-   int numVisuals;
-   long mask;
-   int i;
-   struct visual_attribs attribs;
+   EGLint num_configs = 0, i;
+   EGLint id = 1;
 
-   GLX_dpy->fbconfigs = NULL;
-
-#ifdef GLX_VERSION_1_3
-   /* get list of all fbconfigs on this screen */
-   GLX_dpy->fbconfigs = glXGetFBConfigs(GLX_dpy->dpy, DefaultScreen(GLX_dpy->dpy), &numVisuals);
+   if (GLX_dpy->have_fbconfig) {
+      GLX_dpy->fbconfigs = glXGetFBConfigs(GLX_dpy->dpy, screen, &num_configs);
+   }
+   else {
+      XVisualInfo vinfo_template;
+      long mask;
 
-   if (numVisuals == 0) {
-      GLX_dpy->fbconfigs = NULL;
-      goto xvisual;
+      vinfo_template.screen = screen;
+      mask = VisualScreenMask;
+      GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &vinfo_template,
+                                        &num_configs);
    }
 
-   for (i = 0; i < numVisuals; i++) {
-      struct GLX_egl_config *config;
-      int bit;
+   if (!num_configs)
+      return EGL_FALSE;
 
-      bit = get_fbconfig_attribs(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &attribs);
-      if (!bit)
+   for (i = 0; i < num_configs; i++) {
+      struct GLX_egl_config *GLX_conf, template;
+      EGLBoolean ok;
+
+      memset(&template, 0, sizeof(template));
+      _eglInitConfig(&template.Base, id);
+      if (GLX_dpy->have_fbconfig)
+         ok = convert_fbconfig(GLX_dpy->dpy, GLX_dpy->fbconfigs[i], &template);
+      else
+         ok = convert_visual(GLX_dpy->dpy, &GLX_dpy->visuals[i], &template);
+      if (!ok)
+        continue;
+
+      fix_config(GLX_dpy, &template);
+      if (!_eglValidateConfig(&template.Base, EGL_FALSE)) {
+         _eglLog(_EGL_DEBUG, "GLX: failed to validate config %d", i);
          continue;
+      }
+
+      GLX_conf = CALLOC_STRUCT(GLX_egl_config);
+      if (GLX_conf) {
+         memcpy(GLX_conf, &template, sizeof(template));
+         GLX_conf->index = i;
 
-      config = CALLOC_STRUCT(GLX_egl_config);
-
-      config->index = i;
-      _eglInitConfig(&config->Base, (i+1));
-      SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, attribs.id);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, attribs.bufferSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, attribs.redSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, attribs.greenSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, attribs.blueSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, attribs.alphaSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, attribs.depthSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, attribs.stencilSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLES, attribs.numSamples);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLE_BUFFERS, attribs.numMultisample);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_CONFORMANT, all_apis);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_RENDERABLE_TYPE, all_apis);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE, bit);
-
-      /* XXX possibly other things to init... */
-
-      _eglAddConfig(disp, &config->Base);
+         _eglAddConfig(dpy, &GLX_conf->Base);
+         id++;
+      }
    }
 
-   goto end;
-#endif
+   return EGL_TRUE;
+}
+
+
+static void
+check_extensions(struct GLX_egl_display *GLX_dpy, EGLint screen)
+{
+   GLX_dpy->extensions =
+      glXQueryExtensionsString(GLX_dpy->dpy, screen);
+   if (GLX_dpy->extensions) {
+      /* glXGetProcAddress is assumed */
+
+      if (strstr(GLX_dpy->extensions, "GLX_SGI_make_current_read")) {
+         /* GLX 1.3 entry points are used */
+         GLX_dpy->have_make_current_read = EGL_TRUE;
+      }
 
-xvisual:
-   /* get list of all visuals on this screen */
-   theTemplate.screen = DefaultScreen(GLX_dpy->dpy);
-   mask = VisualScreenMask;
-   GLX_dpy->visuals = XGetVisualInfo(GLX_dpy->dpy, mask, &theTemplate, &numVisuals);
-
-   for (i = 0; i < numVisuals; i++) {
-      struct GLX_egl_config *config;
-
-      if (!get_visual_attribs(GLX_dpy->dpy, &GLX_dpy->visuals[i], &attribs))
-        continue;
-
-      config = CALLOC_STRUCT(GLX_egl_config);
-
-      config->index = i;
-      _eglInitConfig(&config->Base, (i+1));
-      SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, attribs.id);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, attribs.bufferSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, attribs.redSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, attribs.greenSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, attribs.blueSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, attribs.alphaSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, attribs.depthSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, attribs.stencilSize);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLES, attribs.numSamples);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLE_BUFFERS, attribs.numMultisample);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_CONFORMANT, all_apis);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_RENDERABLE_TYPE, all_apis);
-      SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE,
-                        (EGL_WINDOW_BIT /*| EGL_PBUFFER_BIT | EGL_PIXMAP_BIT*/));
-
-      /* XXX possibly other things to init... */
-
-      _eglAddConfig(disp, &config->Base);
+      if (strstr(GLX_dpy->extensions, "GLX_SGIX_fbconfig")) {
+         /* GLX 1.3 entry points are used */
+         GLX_dpy->have_fbconfig = EGL_TRUE;
+      }
+
+      if (strstr(GLX_dpy->extensions, "GLX_SGIX_pbuffer")) {
+         GLX_dpy->glXCreateGLXPbufferSGIX = (PFNGLXCREATEGLXPBUFFERSGIXPROC)
+            glXGetProcAddress((const GLubyte *) "glXCreateGLXPbufferSGIX");
+         GLX_dpy->glXDestroyGLXPbufferSGIX = (PFNGLXDESTROYGLXPBUFFERSGIXPROC)
+            glXGetProcAddress((const GLubyte *) "glXDestroyGLXPbufferSGIX");
+
+         if (GLX_dpy->glXCreateGLXPbufferSGIX &&
+             GLX_dpy->glXDestroyGLXPbufferSGIX &&
+             GLX_dpy->have_fbconfig)
+            GLX_dpy->have_pbuffer = EGL_TRUE;
+      }
    }
 
-end:
-   return EGL_TRUE;
+   if (GLX_dpy->glx_maj == 1 && GLX_dpy->glx_min >= 3) {
+      GLX_dpy->have_1_3 = EGL_TRUE;
+      GLX_dpy->have_make_current_read = EGL_TRUE;
+      GLX_dpy->have_fbconfig = EGL_TRUE;
+      GLX_dpy->have_pbuffer = EGL_TRUE;
+   }
+}
+
+
+static void
+check_quirks(struct GLX_egl_display *GLX_dpy, EGLint screen)
+{
+   const char *vendor;
+
+   GLX_dpy->single_buffered_quirk = EGL_TRUE;
+   GLX_dpy->glx_window_quirk = EGL_TRUE;
+
+   vendor = glXGetClientString(GLX_dpy->dpy, GLX_VENDOR);
+   if (vendor && strstr(vendor, "NVIDIA")) {
+      vendor = glXQueryServerString(GLX_dpy->dpy, screen, GLX_VENDOR);
+      if (vendor && strstr(vendor, "NVIDIA")) {
+         _eglLog(_EGL_DEBUG, "disable quirks");
+         GLX_dpy->single_buffered_quirk = EGL_FALSE;
+         GLX_dpy->glx_window_quirk = EGL_FALSE;
+      }
+   }
 }
 
+
 /**
  * Called via eglInitialize(), GLX_drv->API.Initialize().
  */
@@ -478,17 +546,33 @@ GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp,
       }
    }
 
-   disp->DriverData = (void *) GLX_dpy;
-   disp->ClientAPIsMask = all_apis;
+   if (!glXQueryVersion(GLX_dpy->dpy, &GLX_dpy->glx_maj, &GLX_dpy->glx_min)) {
+      _eglLog(_EGL_WARNING, "GLX: glXQueryVersion failed");
+      if (!disp->NativeDisplay)
+         XCloseDisplay(GLX_dpy->dpy);
+      free(GLX_dpy);
+      return EGL_FALSE;
+   }
 
-   glXQueryVersion(GLX_dpy->dpy, &GLX_dpy->glx_maj, &GLX_dpy->glx_min);
+   check_extensions(GLX_dpy, DefaultScreen(GLX_dpy->dpy));
+   check_quirks(GLX_dpy, DefaultScreen(GLX_dpy->dpy));
+
+   create_configs(disp, GLX_dpy, DefaultScreen(GLX_dpy->dpy));
+   if (!disp->NumConfigs) {
+      _eglLog(_EGL_WARNING, "GLX: failed to create any config");
+      if (!disp->NativeDisplay)
+         XCloseDisplay(GLX_dpy->dpy);
+      free(GLX_dpy);
+      return EGL_FALSE;
+   }
+
+   disp->DriverData = (void *) GLX_dpy;
+   disp->ClientAPIsMask = GLX_EGL_APIS;
 
    /* we're supporting EGL 1.4 */
    *major = 1;
    *minor = 4;
 
-   create_configs(disp, GLX_dpy);
-
    return EGL_TRUE;
 }