egl: EGL->DRI adaptor/driver
authorBrian Paul <brian.paul@tungstengraphics.com>
Fri, 6 Jun 2008 21:52:33 +0000 (15:52 -0600)
committerBrian Paul <brian.paul@tungstengraphics.com>
Fri, 6 Jun 2008 21:52:47 +0000 (15:52 -0600)
Allows regular DRI drivers to work with libEGL.

src/egl/drivers/xdri/Makefile [new file with mode: 0644]
src/egl/drivers/xdri/egl_xdri.c [new file with mode: 0644]

diff --git a/src/egl/drivers/xdri/Makefile b/src/egl/drivers/xdri/Makefile
new file mode 100644 (file)
index 0000000..477a751
--- /dev/null
@@ -0,0 +1,67 @@
+# src/egl/drivers/xdri/Makefile
+
+# Build XEGL DRI driver loader library:  egl_xdri.so
+
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+
+DRIVER_NAME = egl_xdri.so
+
+
+INCLUDE_DIRS = \
+       -I. \
+       -I/usr/include \
+       -I/usr/include/drm \
+       -I$(TOP)/include \
+       -I$(TOP)/include/GL/internal \
+       -I$(TOP)/src/mesa/glapi \
+       -I$(TOP)/src/mesa/drivers/dri/common \
+       -I$(TOP)/src/egl/main \
+       -I$(TOP)/src/glx/x11
+
+SOURCES = egl_xdri.c
+
+OBJECTS = $(SOURCES:.c=.o)
+
+DRM_LIB = `pkg-config --libs libdrm`
+
+
+.c.o:
+       $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@
+
+
+.PHONY: library
+
+
+default: depend library Makefile
+
+
+library: $(TOP)/$(LIB_DIR)/$(DRIVER_NAME)
+
+
+# Make the egl_xdri.so library
+$(TOP)/$(LIB_DIR)/$(DRIVER_NAME): $(OBJECTS)
+       $(TOP)/bin/mklib -o $(DRIVER_NAME) \
+               -noprefix \
+               -major 1 -minor 0 \
+               -install $(TOP)/$(LIB_DIR) \
+               -ldl $(OBJECTS) $(DRM_LIB)
+
+
+clean:
+       rm -f *.o
+       rm -f *.so
+       rm -f depend depend.bak
+
+
+depend: $(SOURCES) $(HEADERS)
+       @ echo "running $(MKDEP)"
+       @ rm -f depend
+       @ touch depend
+       $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \
+               $(SOURCES) $(HEADERS) >/dev/null 2>/dev/null
+
+include depend
+# DO NOT DELETE
diff --git a/src/egl/drivers/xdri/egl_xdri.c b/src/egl/drivers/xdri/egl_xdri.c
new file mode 100644 (file)
index 0000000..4c8511f
--- /dev/null
@@ -0,0 +1,833 @@
+/**************************************************************************
+ * 
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * 
+ **************************************************************************/
+
+
+/**
+ * Code to interface a DRI driver to libEGL.
+ * Note that unlike previous DRI/EGL interfaces, this one is meant to
+ * be used _with_ X.  Applications will use eglCreateWindowSurface()
+ * to render into X-created windows.
+ *
+ * This is an EGL driver that, in turn, loads a regular DRI driver.
+ * There are some dependencies on code in libGL, but those coudl be
+ * removed with some effort.
+ *
+ * Authors: Brian Paul
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "dlfcn.h"
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include "xf86dri.h"
+#include "glxclient.h"
+#include "dri_util.h"
+#include "drm_sarea.h"
+
+#define _EGL_PLATFORM_X
+
+#include "eglconfig.h"
+#include "eglcontext.h"
+#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))
+
+
+/** subclass of _EGLDriver */
+struct xdri_egl_driver
+{
+   _EGLDriver Base;   /**< base class */
+
+   const char *dri_driver_name;  /**< name of DRI driver to load */
+   void *dri_driver_handle;      /**< returned by dlopen(dri_driver_name) */
+
+   int chipset;
+   int minor;
+   int drmFD;
+
+   __DRIscreen driScreen;
+   __DRIframebuffer framebuffer;
+   drm_handle_t hSAREA;
+   drmAddress pSAREA;
+   char *busID;
+   drm_magic_t magic;
+};
+
+
+/** subclass of _EGLContext */
+struct xdri_egl_context
+{
+   _EGLContext Base;   /**< base class */
+
+   __DRIcontext driContext;
+};
+
+
+/** subclass of _EGLSurface */
+struct xdri_egl_surface
+{
+   _EGLSurface Base;   /**< base class */
+
+   __DRIid driDrawable;  /**< DRI surface */
+   drm_drawable_t hDrawable;
+};
+
+
+/** subclass of _EGLConfig */
+struct xdri_egl_config
+{
+   _EGLConfig Base;   /**< base class */
+
+   const __GLcontextModes *mode;  /**< corresponding GLX mode */
+};
+
+
+/** cast wrapper */
+static struct xdri_egl_driver *
+xdri_egl_driver(_EGLDriver *drv)
+{
+   return (struct xdri_egl_driver *) drv;
+}
+
+
+/** Map EGLSurface handle to xdri_egl_surface object */
+static struct xdri_egl_surface *
+lookup_surface(EGLSurface surf)
+{
+   _EGLSurface *surface = _eglLookupSurface(surf);
+   return (struct xdri_egl_surface *) surface;
+}
+
+
+/** Map EGLContext handle to xdri_egl_context object */
+static struct xdri_egl_context *
+lookup_context(EGLContext c)
+{
+   _EGLContext *context = _eglLookupContext(c);
+   return (struct xdri_egl_context *) context;
+}
+
+
+/** Map EGLConfig handle to xdri_egl_config object */
+static struct xdri_egl_config *
+lookup_config(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config)
+{
+   _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
+   return (struct xdri_egl_config *) conf;
+}
+
+
+
+/**
+ * Produce a set of EGL configs.
+ * Note that we get the list of GLcontextModes from the GLX library.
+ * This dependency on GLX lib will be removed someday.
+ */
+static void
+create_configs(_EGLDisplay *disp)
+{
+   const __GLcontextModes *m;
+   __GLXdisplayPrivate *priv = __glXInitialize(disp->Xdpy);
+   __GLXscreenConfigs *scrn = priv->screenConfigs;
+   int id = 1;
+
+   for (m = scrn->configs; m; m = m->next) {
+      /* EGL requires double-buffered configs */
+      if (m->doubleBufferMode) {
+         struct xdri_egl_config *config = CALLOC_STRUCT(xdri_egl_config);
+
+         _eglInitConfig(&config->Base, id++);
+
+         SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, m->rgbBits);
+         SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, m->redBits);
+         SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, m->greenBits);
+         SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, m->blueBits);
+         SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, m->alphaBits);
+         SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, m->depthBits);
+         SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, m->stencilBits);
+         SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, m->visualID);
+         SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_TYPE, m->visualType);
+         /* XXX possibly other things to init... */
+
+         /* Ptr from EGL config to GLcontextMode.  Used in CreateContext(). */
+         config->mode = m;
+
+         _eglAddConfig(disp, &config->Base);
+      }
+   }
+}
+
+
+/**
+ * Called via __DRIinterfaceMethods object
+ */
+static __DRIfuncPtr
+dri_get_proc_address(const char * proc_name)
+{
+   return NULL;
+}
+
+
+static void
+dri_context_modes_destroy(__GLcontextModes *modes)
+{
+   _eglLog(_EGL_DEBUG, "%s", __FUNCTION__);
+
+   while (modes) {
+      __GLcontextModes * const next = modes->next;
+      free(modes);
+      modes = next;
+   }
+}
+
+
+/**
+ * Create a linked list of 'count' GLcontextModes.
+ * These are used during the client/server visual negotiation phase,
+ * then discarded.
+ */
+static __GLcontextModes *
+dri_context_modes_create(unsigned count, size_t minimum_size)
+{
+   /* This code copied from libGLX, and modified */
+   const size_t size = (minimum_size > sizeof(__GLcontextModes))
+       ? minimum_size : sizeof(__GLcontextModes);
+   __GLcontextModes * head = NULL;
+   __GLcontextModes ** next;
+   unsigned   i;
+
+   next = & head;
+   for (i = 0 ; i < count ; i++) {
+      *next = (__GLcontextModes *) calloc(1, size);
+      if (*next == NULL) {
+        dri_context_modes_destroy(head);
+        head = NULL;
+        break;
+      }
+      
+      (*next)->doubleBufferMode = 1;
+      (*next)->visualID = GLX_DONT_CARE;
+      (*next)->visualType = GLX_DONT_CARE;
+      (*next)->visualRating = GLX_NONE;
+      (*next)->transparentPixel = GLX_NONE;
+      (*next)->transparentRed = GLX_DONT_CARE;
+      (*next)->transparentGreen = GLX_DONT_CARE;
+      (*next)->transparentBlue = GLX_DONT_CARE;
+      (*next)->transparentAlpha = GLX_DONT_CARE;
+      (*next)->transparentIndex = GLX_DONT_CARE;
+      (*next)->xRenderable = GLX_DONT_CARE;
+      (*next)->fbconfigID = GLX_DONT_CARE;
+      (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
+      (*next)->bindToTextureRgb = GLX_DONT_CARE;
+      (*next)->bindToTextureRgba = GLX_DONT_CARE;
+      (*next)->bindToMipmapTexture = GLX_DONT_CARE;
+      (*next)->bindToTextureTargets = 0;
+      (*next)->yInverted = GLX_DONT_CARE;
+
+      next = & ((*next)->next);
+   }
+
+   return head;
+}
+
+
+static __DRIscreen *
+dri_find_dri_screen(__DRInativeDisplay *ndpy, int scrn)
+{
+   /* unused? */
+   return NULL;
+}
+
+
+static GLboolean
+dri_window_exists(__DRInativeDisplay *dpy, __DRIid draw)
+{
+   return EGL_TRUE;
+}
+
+
+static GLboolean
+dri_create_context(__DRInativeDisplay *dpy, int screenNum, int configID,
+                   void * contextID, drm_context_t * hw_context)
+{
+   assert(configID >= 0);
+   return XF86DRICreateContextWithConfig(dpy, screenNum,
+                                         configID, contextID, hw_context);
+}
+
+
+static GLboolean
+dri_destroy_context(__DRInativeDisplay * ndpy, int screen, __DRIid context)
+{
+   return XF86DRIDestroyContext(ndpy, screen, context);
+}
+
+
+static GLboolean
+dri_create_drawable(__DRInativeDisplay * ndpy, int screen,
+                    __DRIid drawable, drm_drawable_t * hHWDrawable)
+{
+   _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__);
+
+   /* Create DRI drawable for given window ID (drawable) */
+   if (!XF86DRICreateDrawable(ndpy, screen, drawable, hHWDrawable))
+      return EGL_FALSE;
+
+   return EGL_TRUE;
+}
+
+
+static GLboolean
+dri_destroy_drawable(__DRInativeDisplay * ndpy, int screen, __DRIid drawable)
+{
+   _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__);
+   return XF86DRIDestroyDrawable(ndpy, screen, drawable);
+}
+
+
+static GLboolean
+dri_get_drawable_info(__DRInativeDisplay *dpy, int scrn,
+                      __DRIid draw, unsigned int * index, unsigned int * stamp,
+                      int * x, int * y, int * width, int * height,
+                      int * numClipRects, drm_clip_rect_t ** pClipRects,
+                      int * backX, int * backY,
+                      int * numBackClipRects,
+                      drm_clip_rect_t ** pBackClipRects)
+{
+   _eglLog(_EGL_DEBUG, "XDRI: %s", __FUNCTION__);
+
+   if (!XF86DRIGetDrawableInfo(dpy, scrn, draw, index, stamp,
+                               x, y, width, height,
+                               numClipRects, pClipRects,
+                               backX, backY,
+                               numBackClipRects, pBackClipRects)) {
+      return EGL_FALSE;
+   }
+
+   return EGL_TRUE;
+}
+
+
+/**
+ * Table of functions exported by the loader to the driver.
+ */
+static const __DRIinterfaceMethods interface_methods = {
+   dri_get_proc_address,
+
+   dri_context_modes_create,
+   dri_context_modes_destroy,
+
+   dri_find_dri_screen,
+   dri_window_exists,
+
+   dri_create_context,
+   dri_destroy_context,
+
+   dri_create_drawable,
+   dri_destroy_drawable,
+   dri_get_drawable_info,
+
+   NULL,/*__eglGetUST,*/
+   NULL,/*__eglGetMSCRate,*/
+};
+
+
+
+static EGLBoolean
+init_drm(struct xdri_egl_driver *xdri_drv, _EGLDisplay *disp)
+{
+   static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
+   PFNCREATENEWSCREENFUNC createNewScreen;
+   int api_ver = 0;/*__glXGetInternalVersion();*/
+   __DRIversion ddx_version;
+   __DRIversion dri_version;
+   __DRIversion drm_version;
+   drmVersionPtr version;
+   drm_handle_t  hFB;
+   int newlyopened;
+   int status;
+   __GLcontextModes *modes;
+   int scrn = DefaultScreen(disp->Xdpy);
+
+   createNewScreen = (PFNCREATENEWSCREENFUNC)
+      dlsym(xdri_drv->dri_driver_handle, createNewScreenName);
+   if (!createNewScreen) {
+      _eglLog(_EGL_WARNING, "XDRI: Couldn't find %s function in the driver.",
+              createNewScreenName);
+      return EGL_FALSE;
+   }
+   else {
+      _eglLog(_EGL_DEBUG, "XDRI: Found %s", createNewScreenName);
+   }
+
+   /*
+    * Get the DRI X extension version.
+    */
+   dri_version.major = 4;
+   dri_version.minor = 0;
+   dri_version.patch = 0;
+
+
+   if (!XF86DRIOpenConnection(disp->Xdpy, scrn,
+                              &xdri_drv->hSAREA, &xdri_drv->busID)) {
+      _eglLog(_EGL_WARNING, "XF86DRIOpenConnection failed");
+   }
+
+   xdri_drv->drmFD = drmOpenOnce(NULL, xdri_drv->busID, &newlyopened);
+   if (xdri_drv->drmFD < 0) {
+      perror("drmOpenOnce failed: ");
+      return EGL_FALSE;
+   }
+   else {
+      _eglLog(_EGL_DEBUG, "XDRI: drmOpenOnce returned %d", xdri_drv->drmFD);
+   }
+
+
+   if (drmGetMagic(xdri_drv->drmFD, &xdri_drv->magic)) {
+      perror("drmGetMagic failed: ");
+      return EGL_FALSE;
+   }
+
+   version = drmGetVersion(xdri_drv->drmFD);
+   if (version) {
+      drm_version.major = version->version_major;
+      drm_version.minor = version->version_minor;
+      drm_version.patch = version->version_patchlevel;
+      drmFreeVersion(version);
+      _eglLog(_EGL_DEBUG, "XDRI: Got DRM version %d.%d.%d",
+              drm_version.major,
+              drm_version.minor,
+              drm_version.patch);
+   }
+   else {
+      drm_version.major = -1;
+      drm_version.minor = -1;
+      drm_version.patch = -1;
+      _eglLog(_EGL_WARNING, "XDRI: drmGetVersion() failed");
+      return EGL_FALSE;
+   }
+
+   /* Authenticate w/ server.
+    */
+   if (!XF86DRIAuthConnection(disp->Xdpy, scrn, xdri_drv->magic)) {
+      _eglLog(_EGL_WARNING, "XDRI: XF86DRIAuthConnection() failed");
+      return EGL_FALSE;
+   }
+   else {
+      _eglLog(_EGL_DEBUG, "XDRI: XF86DRIAuthConnection() success");
+   }
+
+   /* Get ddx version.
+    */
+   {
+      char *driverName;
+
+      /*
+       * Get device name (like "tdfx") and the ddx version
+       * numbers.  We'll check the version in each DRI driver's
+       * "createNewScreen" function.
+       */
+      if (!XF86DRIGetClientDriverName(disp->Xdpy, scrn,
+                                     &ddx_version.major,
+                                     &ddx_version.minor,
+                                     &ddx_version.patch,
+                                     &driverName)) {
+         _eglLog(_EGL_WARNING, "XDRI: XF86DRIGetClientDriverName failed");
+         return EGL_FALSE;
+      }
+      else {
+         _eglLog(_EGL_DEBUG, "XDRI: XF86DRIGetClientDriverName returned %s", driverName);
+      }
+   }
+
+   /* Get framebuffer info.
+    */
+   {
+      int junk;
+      if (!XF86DRIGetDeviceInfo(disp->Xdpy, scrn,
+                                &hFB,
+                                &junk,
+                                &xdri_drv->framebuffer.size,
+                                &xdri_drv->framebuffer.stride,
+                                &xdri_drv->framebuffer.dev_priv_size,
+                                &xdri_drv->framebuffer.dev_priv)) {
+         _eglLog(_EGL_WARNING, "XDRI: XF86DRIGetDeviceInfo() failed");
+         return EGL_FALSE;
+      }
+      else {
+         _eglLog(_EGL_DEBUG, "XDRI: XF86DRIGetDeviceInfo() success");
+      }
+      xdri_drv->framebuffer.width = DisplayWidth(disp->Xdpy, scrn);
+      xdri_drv->framebuffer.height = DisplayHeight(disp->Xdpy, scrn);
+   }
+
+   /* Map the framebuffer region. (this may not be needed)
+    */
+   status = drmMap(xdri_drv->drmFD, hFB, xdri_drv->framebuffer.size, 
+                   (drmAddressPtr) &xdri_drv->framebuffer.base);
+   if (status != 0) {
+      _eglLog(_EGL_WARNING, "XDRI: drmMap(framebuffer) failed");
+      return EGL_FALSE;
+   }
+   else {
+      _eglLog(_EGL_DEBUG, "XDRI: drmMap(framebuffer) success");
+   }
+
+   /* Map the SAREA region.
+    */
+   status = drmMap(xdri_drv->drmFD, xdri_drv->hSAREA, SAREA_MAX, &xdri_drv->pSAREA);
+   if (status != 0) {
+      _eglLog(_EGL_WARNING, "XDRI: drmMap(sarea) failed");
+      return EGL_FALSE;
+   }
+   else {
+      _eglLog(_EGL_DEBUG, "XDRI: drmMap(sarea) success");
+   }
+
+   /* Create the DRI screen.
+    */
+   xdri_drv->driScreen.private = createNewScreen(disp->Xdpy,
+                                             scrn,  /* screen number */
+                                             &xdri_drv->driScreen,
+                                             NULL,  /* visuals */
+                                             &ddx_version,
+                                             &dri_version,
+                                             &drm_version,
+                                             &xdri_drv->framebuffer,
+                                             xdri_drv->pSAREA,
+                                             xdri_drv->drmFD,
+                                             api_ver,
+                                             &interface_methods,
+                                             &modes);
+   if (!xdri_drv->driScreen.private) {
+      _eglLog(_EGL_WARNING, "XDRI: create new screen failed");
+      return EGL_FALSE;
+   }
+   else {
+      _eglLog(_EGL_DEBUG, "XDRI: create new screen success");
+   }
+
+   create_configs(disp);
+
+   /* print modes / debug */
+   if (0) {
+      __GLcontextModes *m;
+
+      for (m = modes; m; m = m->next) {
+         _eglLog(_EGL_DEBUG,
+                 "mode ID 0x%x rgba %d %d %d %d  z %d  s %d  db %d\n", m->visualID,
+                 m->redBits, m->greenBits, m->blueBits, m->alphaBits,
+                 m->depthBits, m->stencilBits, m->doubleBufferMode);
+      }
+   }
+
+   return EGL_TRUE;
+}
+
+
+static EGLBoolean
+load_dri_driver(struct xdri_egl_driver *xdri_drv)
+{
+   char filename[100];
+   int flags = RTLD_NOW;
+
+   snprintf(filename, sizeof(filename), "%s.so", xdri_drv->dri_driver_name);
+   _eglLog(_EGL_DEBUG, "XDRI: dlopen(%s)", filename);
+
+   xdri_drv->dri_driver_handle = dlopen(filename, flags);
+   if (!xdri_drv->dri_driver_handle) {
+      _eglLog(_EGL_WARNING, "XDRI Could not open %s (%s)",
+              filename, dlerror());
+
+      return EGL_FALSE;
+   }
+   return EGL_TRUE;
+}
+
+
+/**
+ * Called via eglInitialize(), xdri_drv->API.Initialize().
+ */
+static EGLBoolean
+xdri_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
+                   EGLint *minor, EGLint *major)
+{
+   struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
+   _EGLDisplay *disp = _eglLookupDisplay(dpy);
+   static char name[100];
+
+   _eglLog(_EGL_DEBUG, "XDRI: eglInitialize");
+
+   if (!disp->Xdpy) {
+      disp->Xdpy = XOpenDisplay(NULL);
+      if (!disp->Xdpy) {
+         _eglLog(_EGL_WARNING, "XDRI: XOpenDisplay failed");
+         return EGL_FALSE;
+      }
+   }
+
+   /* choose the DRI driver to load */
+   xdri_drv->dri_driver_name = _eglChooseDRMDriver(0);
+   if (!load_dri_driver(xdri_drv))
+      return EGL_FALSE;
+
+   if (!init_drm(xdri_drv, disp))
+      return EGL_FALSE;
+
+   xdri_drv->Base.Initialized = EGL_TRUE;
+
+   snprintf(name, sizeof(name), "X/DRI:%s", xdri_drv->dri_driver_name);
+   xdri_drv->Base.Name = name;
+
+   /* we're supporting EGL 1.4 */
+   *minor = 1;
+   *major = 4;
+
+   return EGL_TRUE;
+}
+
+
+/**
+ * Called via eglTerminate(), drv->API.Terminate().
+ */
+static EGLBoolean
+xdri_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
+{
+   struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
+
+   _eglLog(_EGL_DEBUG, "XDRI: eglTerminate");
+
+   _eglLog(_EGL_DEBUG, "XDRI: Closing %s", xdri_drv->dri_driver_name);
+   dlclose(xdri_drv->dri_driver_handle);
+   xdri_drv->dri_driver_handle = NULL;
+
+   free((void*) xdri_drv->dri_driver_name);
+
+   return EGL_TRUE;
+}
+
+
+/**
+ * Called via eglCreateContext(), drv->API.CreateContext().
+ */
+static EGLContext
+xdri_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
+                      EGLContext share_list, const EGLint *attrib_list)
+{
+   struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
+   _EGLDisplay *disp = _eglLookupDisplay(dpy);
+   struct xdri_egl_config *xdri_config = lookup_config(drv, dpy, config);
+   void *shared = NULL;
+   int renderType = GLX_RGBA_BIT;
+
+   struct xdri_egl_context *xdri_ctx = CALLOC_STRUCT(xdri_egl_context);
+   if (!xdri_ctx)
+      return EGL_NO_CONTEXT;
+
+   if (!_eglInitContext(drv, dpy, &xdri_ctx->Base, config, attrib_list)) {
+      free(xdri_ctx);
+      return EGL_NO_CONTEXT;
+   }
+
+   assert(xdri_config);
+
+   xdri_ctx->driContext.private = 
+      xdri_drv->driScreen.createNewContext(disp->Xdpy,
+                                           xdri_config->mode, renderType,
+                                           shared, &xdri_ctx->driContext);
+   if (!xdri_ctx->driContext.private) {
+      free(xdri_ctx);
+      return EGL_NO_CONTEXT;
+   }
+
+   xdri_ctx->driContext.mode = xdri_config->mode;
+
+   return _eglGetContextHandle(&xdri_ctx->Base);
+}
+
+
+/**
+ * Called via eglMakeCurrent(), drv->API.MakeCurrent().
+ */
+static EGLBoolean
+xdri_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
+                    EGLSurface r, EGLContext context)
+{
+   _EGLDisplay *disp = _eglLookupDisplay(dpy);
+   struct xdri_egl_context *xdri_ctx = lookup_context(context);
+   struct xdri_egl_surface *xdri_draw = lookup_surface(d);
+   struct xdri_egl_surface *xdri_read = lookup_surface(r);
+   __DRIid draw = xdri_draw->driDrawable;
+   __DRIid read = xdri_read->driDrawable;
+   int scrn = DefaultScreen(disp->Xdpy);
+
+   if (!_eglMakeCurrent(drv, dpy, d, r, context))
+      return EGL_FALSE;
+
+
+   if (!xdri_ctx->driContext.bindContext(disp->Xdpy, scrn, draw, read,
+                                         &xdri_ctx->driContext)) {
+      return EGL_FALSE;
+   }
+
+   return EGL_TRUE;
+}
+
+
+/**
+ * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
+ */
+static EGLSurface
+xdri_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
+                            NativeWindowType window, const EGLint *attrib_list)
+{
+   _EGLDisplay *disp = _eglLookupDisplay(dpy);
+   struct xdri_egl_surface *xdri_surf;
+   int scrn = DefaultScreen(disp->Xdpy);
+
+   xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
+   if (!xdri_surf)
+      return EGL_NO_SURFACE;
+
+   if (!_eglInitSurface(drv, dpy, &xdri_surf->Base, EGL_WINDOW_BIT,
+                        config, attrib_list)) {
+      free(xdri_surf);
+      return EGL_FALSE;
+   }
+
+   if (!XF86DRICreateDrawable(disp->Xdpy, scrn, window, &xdri_surf->hDrawable)) {
+      free(xdri_surf);
+      return EGL_FALSE;
+   }
+
+   xdri_surf->driDrawable = window;
+
+   _eglSaveSurface(&xdri_surf->Base);
+
+   _eglLog(_EGL_DEBUG,
+           "XDRI: CreateWindowSurface win 0x%x  handle %d  hDrawable %d",
+           (int) window, _eglGetSurfaceHandle(&xdri_surf->Base),
+           (int) xdri_surf->hDrawable);
+
+   return _eglGetSurfaceHandle(&xdri_surf->Base);
+}
+
+
+static EGLBoolean
+xdri_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
+{
+   struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
+   if (xdri_surf) {
+      _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
+      if (xdri_surf->Base.IsBound) {
+         xdri_surf->Base.DeletePending = EGL_TRUE;
+      }
+      else {
+         /*
+         st_unreference_framebuffer(&surf->Framebuffer);
+         */
+         free(xdri_surf);
+      }
+      return EGL_TRUE;
+   }
+   else {
+      _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
+      return EGL_FALSE;
+   }
+}
+
+
+static EGLBoolean
+xdri_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
+{
+   _EGLDisplay *disp = _eglLookupDisplay(dpy);
+
+   _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers");
+
+   /* error checking step: */
+   if (!_eglSwapBuffers(drv, dpy, draw))
+      return EGL_FALSE;
+
+   {
+      struct xdri_egl_surface *xdri_surf = lookup_surface(draw);
+      __GLXdisplayPrivate *priv = __glXInitialize(disp->Xdpy);
+      __GLXscreenConfigs *scrn = priv->screenConfigs;
+      __DRIscreen *psc = &scrn->driScreen;
+      __DRIdrawable * const pdraw = psc->getDrawable(disp->Xdpy,
+                                                     xdri_surf->driDrawable,
+                                                     psc->private);
+
+      if (pdraw)
+         pdraw->swapBuffers(disp->Xdpy, pdraw->private);
+      else
+         _eglLog(_EGL_WARNING, "pdraw is null in SwapBuffers");
+   }
+
+   return EGL_TRUE;
+}
+
+
+/**
+ * This is the main entrypoint into the driver, called by libEGL.
+ * Create a new _EGLDriver object and init its dispatch table.
+ */
+_EGLDriver *
+_eglMain(_EGLDisplay *disp, const char *args)
+{
+   struct xdri_egl_driver *xdri_drv = CALLOC_STRUCT(xdri_egl_driver);
+   if (!xdri_drv)
+      return NULL;
+
+   _eglInitDriverFallbacks(&xdri_drv->Base);
+   xdri_drv->Base.API.Initialize = xdri_eglInitialize;
+   xdri_drv->Base.API.Terminate = xdri_eglTerminate;
+
+   xdri_drv->Base.API.CreateContext = xdri_eglCreateContext;
+   xdri_drv->Base.API.MakeCurrent = xdri_eglMakeCurrent;
+   xdri_drv->Base.API.CreateWindowSurface = xdri_eglCreateWindowSurface;
+   xdri_drv->Base.API.DestroySurface = xdri_eglDestroySurface;
+   xdri_drv->Base.API.SwapBuffers = xdri_eglSwapBuffers;
+
+   xdri_drv->Base.ClientAPIsMask = EGL_OPENGL_BIT /*| EGL_OPENGL_ES_BIT*/;
+   xdri_drv->Base.Name = "X/DRI";
+
+   _eglLog(_EGL_DEBUG, "XDRI: main(%s)", args);
+
+   return &xdri_drv->Base;
+}