Merge branch 'asm-shader-rework-1'
[mesa.git] / src / egl / drivers / glx / egl_glx.c
index 4274493a5b566337da151572704c1f12b201ac42..3c8f8b6a6845f9b42d227c1c047ade64bf175a33 100644 (file)
@@ -36,8 +36,6 @@
 /*
  * TODO: 
  *
- * Add GLXFBConfig support
- * Pbuffer & Pixmap support
  * test eglBind/ReleaseTexImage
  */
 
@@ -59,7 +57,6 @@
 #include "egldisplay.h"
 #include "egldriver.h"
 #include "eglglobals.h"
-#include "eglhash.h"
 #include "egllog.h"
 #include "eglsurface.h"
 
 
 #define CALLOC_STRUCT(T)   (struct T *) calloc(1, sizeof(struct T))
 
-static const EGLint all_apis = (EGL_OPENGL_ES_BIT |
-                                EGL_OPENGL_ES2_BIT |
-                                EGL_OPENVG_BIT |
-                                EGL_OPENGL_BIT);
+static const EGLint all_apis = (EGL_OPENGL_ES_BIT
+                                | EGL_OPENGL_ES2_BIT
+                                | EGL_OPENVG_BIT
+                                /* | EGL_OPENGL_BIT */); /* can't do */
 
 struct visual_attribs
 {
@@ -110,8 +107,9 @@ struct GLX_egl_driver
    _EGLDriver Base;   /**< base class */
 
    XVisualInfo *visuals;
+   GLXFBConfig *fbconfigs;
 
-   /* GLXFBConfig *fbconfigs - todo */
+   int glx_maj, glx_min;
 };
 
 
@@ -158,6 +156,13 @@ GLX_egl_surface(_EGLSurface *surf)
    return (struct GLX_egl_surface *) surf;
 }
 
+static int
+GLX_egl_config_id(_EGLConfig *conf)
+{
+   /* see create_configs */
+   return (int) _eglPointerToUInt(_eglGetConfigHandle(conf)) - 1;
+}
+
 static GLboolean
 get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
                    struct visual_attribs *attribs)
@@ -191,6 +196,9 @@ get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
    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);
@@ -242,6 +250,106 @@ get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
    return GL_TRUE;
 }
 
+#ifdef GLX_VERSION_1_3
+
+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:
+   default:
+      return 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));
+
+   glXGetFBConfigAttrib(dpy, fbconfig, GLX_FBCONFIG_ID, &fbconfig_id);
+
+   glXGetFBConfigAttrib(dpy, fbconfig, GLX_VISUAL_ID, &attribs->id);
+
+#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
+
+   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);
+   }
+
+   glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLE_BUFFERS, &attribs->numMultisample);
+   glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLES, &attribs->numSamples);
+
+   glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &attribs->visualCaveat);
+
+   if (attribs->id == 0) {
+      attribs->id = fbconfig_id;
+      return EGL_PBUFFER_BIT | EGL_PIXMAP_BIT;
+   }
+
+   return EGL_WINDOW_BIT;
+}
+
+#endif
+
 static EGLBoolean
 create_configs(_EGLDisplay *disp, struct GLX_egl_driver *GLX_drv)
 {
@@ -251,6 +359,51 @@ create_configs(_EGLDisplay *disp, struct GLX_egl_driver *GLX_drv)
    int i;
    struct visual_attribs attribs;
 
+   GLX_drv->fbconfigs = NULL;
+
+#ifdef GLX_VERSION_1_3
+   /* get list of all fbconfigs on this screen */
+   GLX_drv->fbconfigs = glXGetFBConfigs(disp->Xdpy, DefaultScreen(disp->Xdpy), &numVisuals);
+
+   if (numVisuals == 0) {
+      GLX_drv->fbconfigs = NULL;
+      goto xvisual;
+   }
+
+   for (i = 0; i < numVisuals; i++) {
+      struct GLX_egl_config *config;
+      int bit;
+
+      bit = get_fbconfig_attribs(disp->Xdpy, GLX_drv->fbconfigs[i], &attribs);
+      if (!bit)
+         continue;
+
+      config = CALLOC_STRUCT(GLX_egl_config);
+
+      _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);
+   }
+
+   goto end;
+#endif
+
+xvisual:
    /* get list of all visuals on this screen */
    theTemplate.screen = DefaultScreen(disp->Xdpy);
    mask = VisualScreenMask;
@@ -262,10 +415,9 @@ create_configs(_EGLDisplay *disp, struct GLX_egl_driver *GLX_drv)
       if (!get_visual_attribs(disp->Xdpy, &GLX_drv->visuals[i], &attribs))
         continue;
 
-      if (attribs.doubleBuffer) {
       config = CALLOC_STRUCT(GLX_egl_config);
 
-      _eglInitConfig(&config->Base, i+1);
+      _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);
@@ -284,9 +436,9 @@ create_configs(_EGLDisplay *disp, struct GLX_egl_driver *GLX_drv)
       /* XXX possibly other things to init... */
 
       _eglAddConfig(disp, &config->Base);
-      }
    }
 
+end:
    return EGL_TRUE;
 }
 
@@ -294,24 +446,25 @@ create_configs(_EGLDisplay *disp, struct GLX_egl_driver *GLX_drv)
  * Called via eglInitialize(), GLX_drv->API.Initialize().
  */
 static EGLBoolean
-GLX_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
+GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp,
                    EGLint *minor, EGLint *major)
 {
    struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
-   _EGLDisplay *disp = _eglLookupDisplay(dpy);
 
-   _eglLog(_EGL_DEBUG, "XDRI: eglInitialize");
+   _eglLog(_EGL_DEBUG, "GLX: eglInitialize");
 
    if (!disp->Xdpy) {
       disp->Xdpy = XOpenDisplay(NULL);
       if (!disp->Xdpy) {
-         _eglLog(_EGL_WARNING, "XDRI: XOpenDisplay failed");
+         _eglLog(_EGL_WARNING, "GLX: XOpenDisplay failed");
          return EGL_FALSE;
       }
-   }
+   } 
 
-   GLX_drv->Base.Initialized = EGL_TRUE;
+   disp->ClientAPIsMask = all_apis;
 
+   glXQueryVersion(disp->Xdpy, &GLX_drv->glx_maj, &GLX_drv->glx_min);
+   
    GLX_drv->Base.Name = "GLX";
 
    /* we're supporting EGL 1.4 */
@@ -323,18 +476,45 @@ GLX_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
    return EGL_TRUE;
 }
 
+/*
+ * Do some clean-up that normally occurs in XCloseDisplay().
+ * We do this here because we're about to unload a dynamic library
+ * that has added some per-display extension data and callbacks.
+ * If we don't do this here we'll crash in XCloseDisplay() because it'll
+ * try to call functions that went away when the driver library was unloaded.
+ */
+static void
+FreeDisplayExt(Display *dpy)
+{
+   _XExtension *ext, *next;
+
+   for (ext = dpy->ext_procs; ext; ext = next) {
+      next = ext->next;
+      if (ext->close_display) {
+         ext->close_display(dpy, &ext->codes);
+         ext->close_display = NULL;
+      }
+      if (ext->name)
+         Xfree(ext->name);
+      Xfree(ext);
+   }
+   dpy->ext_procs = NULL;
+
+   _XFreeExtData (dpy->ext_data);
+   dpy->ext_data = NULL;
+}
 
 /**
  * Called via eglTerminate(), drv->API.Terminate().
  */
 static EGLBoolean
-GLX_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
+GLX_eglTerminate(_EGLDriver *drv, _EGLDisplay *disp)
 {
-   _EGLDisplay *disp = _eglLookupDisplay(dpy);
+   _eglLog(_EGL_DEBUG, "GLX: eglTerminate");
 
-   _eglLog(_EGL_DEBUG, "XDRI: eglTerminate");
-
-//   XCloseDisplay(disp->Xdpy);
+   _eglReleaseDisplayResources(drv, disp);
+   FreeDisplayExt(disp->Xdpy);
+   _eglCleanupDisplay(disp);
 
    return EGL_TRUE;
 }
@@ -343,45 +523,47 @@ GLX_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
 /**
  * Called via eglCreateContext(), drv->API.CreateContext().
  */
-static EGLContext
-GLX_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
-                      EGLContext share_list, const EGLint *attrib_list)
+static _EGLContext *
+GLX_eglCreateContext(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
+                      _EGLContext *share_list, const EGLint *attrib_list)
 {
-   _EGLDisplay *disp = _eglLookupDisplay(dpy);
    struct GLX_egl_context *GLX_ctx = CALLOC_STRUCT(GLX_egl_context);
    struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
-   struct GLX_egl_context *GLX_ctx_shared = NULL;
-   _EGLConfig *conf;
+   struct GLX_egl_context *GLX_ctx_shared = GLX_egl_context(share_list);
 
    if (!GLX_ctx)
-      return EGL_NO_CONTEXT;
+      return NULL;
 
-   if (!_eglInitContext(drv, dpy, &GLX_ctx->Base, config, attrib_list)) {
+   if (!_eglInitContext(drv, &GLX_ctx->Base, conf, attrib_list)) {
       free(GLX_ctx);
-      return EGL_NO_CONTEXT;
-   }
-
-   if (share_list != EGL_NO_CONTEXT) {
-      _EGLContext *shareCtx = _eglLookupContext(share_list);
-      if (!shareCtx) {
-         _eglError(EGL_BAD_CONTEXT, "eglCreateContext(share_list)");
-         return EGL_FALSE;
-      }
-      GLX_ctx_shared = GLX_egl_context(shareCtx);
+      return NULL;
    }
 
-   conf = _eglLookupConfig(drv, dpy, config);
-   assert(conf);
-
-   GLX_ctx->context = glXCreateContext(disp->Xdpy, &GLX_drv->visuals[(int)config-1], GLX_ctx_shared ? GLX_ctx_shared->context : NULL, GL_TRUE);
+#ifdef GLX_VERSION_1_3
+   if (GLX_drv->fbconfigs)
+      GLX_ctx->context =
+         glXCreateNewContext(disp->Xdpy,
+                             GLX_drv->fbconfigs[GLX_egl_config_id(conf)],
+                             GLX_RGBA_TYPE,
+                             GLX_ctx_shared ? GLX_ctx_shared->context : NULL,
+                             GL_TRUE);
+   else
+#endif
+      GLX_ctx->context =
+         glXCreateContext(disp->Xdpy,
+                          &GLX_drv->visuals[GLX_egl_config_id(conf)],
+                          GLX_ctx_shared ? GLX_ctx_shared->context : NULL,
+                          GL_TRUE);
    if (!GLX_ctx->context)
       return EGL_FALSE;
 
-   /* need to have a direct rendering context */
+#if 1
+   /* (maybe?) need to have a direct rendering context */
    if (!glXIsDirect(disp->Xdpy, GLX_ctx->context))
       return EGL_FALSE;
+#endif
 
-   return _eglGetContextHandle(&GLX_ctx->Base);
+   return &GLX_ctx->Base;
 }
 
 
@@ -389,23 +571,21 @@ GLX_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
  * Called via eglMakeCurrent(), drv->API.MakeCurrent().
  */
 static EGLBoolean
-GLX_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
-                    EGLSurface r, EGLContext context)
+GLX_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
+                   _EGLSurface *rsurf, _EGLContext *ctx)
 {
-   _EGLDisplay *disp = _eglLookupDisplay(dpy);
-   _EGLContext *ctx = _eglLookupContext(context);
-   _EGLSurface *dsurf = _eglLookupSurface(d);
-   _EGLSurface *rsurf = _eglLookupSurface(r);
    struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
    struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
    struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
 
-   if (!_eglMakeCurrent(drv, dpy, d, r, context))
+   if (!_eglMakeCurrent(drv, disp, dsurf, rsurf, ctx))
       return EGL_FALSE;
 
-//   if (!glXMakeContextCurrent(disp->Xdpy, GLX_dsurf->drawable, GLX_rsurf->drawable, GLX_ctx->context))
-   if (!glXMakeCurrent(disp->Xdpy, GLX_dsurf ? GLX_dsurf->drawable : 0, GLX_ctx ? GLX_ctx->context : NULL))
-      return EGL_FALSE;
+#ifdef GLX_VERSION_1_3
+   if (!glXMakeContextCurrent(disp->Xdpy, GLX_dsurf ? GLX_dsurf->drawable : 0, GLX_rsurf ? GLX_rsurf->drawable : 0, GLX_ctx ? GLX_ctx->context : NULL))
+#endif
+      if (!glXMakeCurrent(disp->Xdpy, GLX_dsurf ? GLX_dsurf->drawable : 0, GLX_ctx ? GLX_ctx->context : NULL))
+         return EGL_FALSE;
 
    return EGL_TRUE;
 }
@@ -427,64 +607,135 @@ get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
 /**
  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
  */
-static EGLSurface
-GLX_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
+static _EGLSurface *
+GLX_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
                             NativeWindowType window, const EGLint *attrib_list)
 {
-   _EGLDisplay *disp = _eglLookupDisplay(dpy);
    struct GLX_egl_surface *GLX_surf;
    uint width, height;
 
    GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
    if (!GLX_surf)
-      return EGL_NO_SURFACE;
+      return NULL;
 
-   if (!_eglInitSurface(drv, dpy, &GLX_surf->Base, EGL_WINDOW_BIT,
-                        config, attrib_list)) {
+   if (!_eglInitSurface(drv, &GLX_surf->Base, EGL_WINDOW_BIT,
+                        conf, attrib_list)) {
       free(GLX_surf);
-      return EGL_FALSE;
+      return NULL;
    }
 
-   _eglSaveSurface(&GLX_surf->Base);
-
    GLX_surf->drawable = window;
    get_drawable_size(disp->Xdpy, window, &width, &height);
    GLX_surf->Base.Width = width;
    GLX_surf->Base.Height = height;
 
-   return _eglGetSurfaceHandle(&GLX_surf->Base);
+   return &GLX_surf->Base;
 }
 
-static EGLBoolean
-GLX_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
+#ifdef GLX_VERSION_1_3
+static _EGLSurface *
+GLX_eglCreatePixmapSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
+                          NativePixmapType pixmap, const EGLint *attrib_list)
 {
-   _EGLDisplay *disp = _eglLookupDisplay(dpy);
-   _EGLSurface *surf = _eglLookupSurface(surface);
-   return EGL_TRUE;
-   if (surf) {
-      _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
-      if (surf->IsBound) {
-         surf->DeletePending = EGL_TRUE;
-      }
-      else {
-         free(surf);
+   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
+   struct GLX_egl_surface *GLX_surf;
+   int i;
+
+   GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
+   if (!GLX_surf)
+      return NULL;
+
+   if (!_eglInitSurface(drv, &GLX_surf->Base, EGL_PIXMAP_BIT,
+                        conf, attrib_list)) {
+      free(GLX_surf);
+      return NULL;
+   }
+
+   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
+      switch (attrib_list[i]) {
+         /* no attribs at this time */
+      default:
+         _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePixmapSurface");
+         return NULL;
       }
+   }
 
-      return EGL_TRUE;
+   GLX_surf->drawable =
+      glXCreatePixmap(disp->Xdpy,
+                      GLX_drv->fbconfigs[GLX_egl_config_id(conf)],
+                      pixmap, NULL);
+
+   return &GLX_surf->Base;
+}
+
+static _EGLSurface *
+GLX_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
+                            const EGLint *attrib_list)
+{
+   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
+   struct GLX_egl_surface *GLX_surf;
+   int attribs[5];
+   int i = 0, j = 0;
+
+   GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
+   if (!GLX_surf)
+      return NULL;
+
+   if (!_eglInitSurface(drv, &GLX_surf->Base, EGL_PBUFFER_BIT,
+                        conf, attrib_list)) {
+      free(GLX_surf);
+      return NULL;
    }
-   else {
-      _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
-      return EGL_FALSE;
+
+   while(attrib_list[i] != EGL_NONE) {
+      switch (attrib_list[i]) {
+         case EGL_WIDTH:
+           attribs[j++] = GLX_PBUFFER_WIDTH;
+           attribs[j++] = attrib_list[i+1];
+           break;
+        case EGL_HEIGHT:
+           attribs[j++] = GLX_PBUFFER_HEIGHT;
+           attribs[j++] = attrib_list[i+1];
+           break;
+      }
+      i++;
    }
+   attribs[j++] = 0;
+
+   GLX_surf->drawable =
+      glXCreatePbuffer(disp->Xdpy,
+                       GLX_drv->fbconfigs[GLX_egl_config_id(conf)], attribs);
+
+   return &GLX_surf->Base;
+}
+#endif
+
+static EGLBoolean
+GLX_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
+{
+   if (!_eglIsSurfaceBound(surf)) {
+      struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
+      switch (surf->Type) {
+      case EGL_PBUFFER_BIT:
+         glXDestroyPbuffer(disp->Xdpy, GLX_surf->drawable);
+         break;
+      case EGL_PIXMAP_BIT:
+         glXDestroyPixmap(disp->Xdpy, GLX_surf->drawable);
+         break;
+      default:
+         break;
+      }
+      free(surf);
+   }
+
+   return EGL_TRUE;
 }
 
 
 static EGLBoolean
-GLX_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
+GLX_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
                      EGLint buffer)
 {
-   _EGLDisplay *disp = _eglLookupDisplay(dpy);
-   _EGLSurface *surf = _eglLookupSurface(surface);
    struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
 
    /* buffer ?? */
@@ -495,11 +746,9 @@ GLX_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
 
 
 static EGLBoolean
-GLX_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
+GLX_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
                         EGLint buffer)
 {
-   _EGLDisplay *disp = _eglLookupDisplay(dpy);
-   _EGLSurface *surf = _eglLookupSurface(surface);
    struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
 
    /* buffer ?? */
@@ -510,16 +759,14 @@ GLX_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
 
 
 static EGLBoolean
-GLX_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
+GLX_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
 {
-   _EGLDisplay *disp = _eglLookupDisplay(dpy);
-   _EGLSurface *surf = _eglLookupSurface(draw);
-   struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
+   struct GLX_egl_surface *GLX_surf = GLX_egl_surface(draw);
 
-   _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers 0x%x",draw);
+   _eglLog(_EGL_DEBUG, "GLX: EGL SwapBuffers 0x%x",draw);
 
    /* error checking step: */
-   if (!_eglSwapBuffers(drv, dpy, draw))
+   if (!_eglSwapBuffers(drv, disp, draw))
       return EGL_FALSE;
 
    glXSwapBuffers(disp->Xdpy, GLX_surf->drawable);
@@ -533,7 +780,29 @@ GLX_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
 static _EGLProc
 GLX_eglGetProcAddress(const char *procname)
 {
-   return (_EGLProc)glXGetProcAddress((const GLubyte *)procname);   
+   /* This is a bit of a hack to get at the gallium/Mesa state tracker
+    * function st_get_proc_address().  This will probably change at
+    * some point.
+    */
+   _EGLProc (*get_proc_addr)(const char *procname);
+   _EGLProc proc_addr;
+   get_proc_addr = dlsym(NULL, "st_get_proc_address");
+   if (get_proc_addr)
+      return get_proc_addr(procname);
+
+   proc_addr = glXGetProcAddress((const GLubyte *)procname);
+   if (proc_addr)
+      return proc_addr;
+
+   return (_EGLProc)dlsym(NULL, procname);
+}
+
+
+static void
+GLX_Unload(_EGLDriver *drv)
+{
+   struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
+   free(GLX_drv);
 }
 
 
@@ -542,9 +811,11 @@ GLX_eglGetProcAddress(const char *procname)
  * Create a new _EGLDriver object and init its dispatch table.
  */
 _EGLDriver *
-_eglMain(_EGLDisplay *disp, const char *args)
+_eglMain(const char *args)
 {
    struct GLX_egl_driver *GLX_drv = CALLOC_STRUCT(GLX_egl_driver);
+   char *env;
+
    if (!GLX_drv)
       return NULL;
 
@@ -554,21 +825,37 @@ _eglMain(_EGLDisplay *disp, const char *args)
    GLX_drv->Base.API.CreateContext = GLX_eglCreateContext;
    GLX_drv->Base.API.MakeCurrent = GLX_eglMakeCurrent;
    GLX_drv->Base.API.CreateWindowSurface = GLX_eglCreateWindowSurface;
+#ifdef GLX_VERSION_1_3
+   if (GLX_drv->glx_maj == 1 && GLX_drv->glx_min >= 3) {
+      GLX_drv->Base.API.CreatePixmapSurface = GLX_eglCreatePixmapSurface;
+      GLX_drv->Base.API.CreatePbufferSurface = GLX_eglCreatePbufferSurface;
+      printf("GLX: Pbuffer and Pixmap support\n");
+   } else {
+      printf("GLX: No pbuffer or pixmap support\n");
+   }
+#endif
    GLX_drv->Base.API.DestroySurface = GLX_eglDestroySurface;
    GLX_drv->Base.API.BindTexImage = GLX_eglBindTexImage;
    GLX_drv->Base.API.ReleaseTexImage = GLX_eglReleaseTexImage;
    GLX_drv->Base.API.SwapBuffers = GLX_eglSwapBuffers;
    GLX_drv->Base.API.GetProcAddress = GLX_eglGetProcAddress;
 
-   GLX_drv->Base.ClientAPIsMask = all_apis;
    GLX_drv->Base.Name = "GLX";
+   GLX_drv->Base.Unload = GLX_Unload;
 
    _eglLog(_EGL_DEBUG, "GLX: main(%s)", args);
 
-   /* set new DRI path to pick up EGL version (no mesa code), but don't
-    * override if one is already set.
+   /* set new DRI path to pick up EGL version (which doesn't contain any mesa 
+    * code), but don't override if one is already set.
     */
-   setenv("LIBGL_DRIVERS_PATH", DEFAULT_DRIVER_DIR"/egl", 0);
+   env = getenv("LIBGL_DRIVERS_PATH");
+   if (env) {
+      if (!strstr(env, "egl")) {
+         sprintf(env, "%s/egl", env);
+         setenv("LIBGL_DRIVERS_PATH", env, 1);
+      }
+   } else
+      setenv("LIBGL_DRIVERS_PATH", DEFAULT_DRIVER_DIR"/egl", 0);
 
    return &GLX_drv->Base;
 }