Move make install logic for libGL back into src/mesa/Makefile.
[mesa.git] / src / glx / x11 / dri_glx.c
index 0875361d0b60256c662e6eda3e3bb4ca5ad5abb3..a6581465bc20c3479c40148e424d45e990bc8d1d 100644 (file)
@@ -24,7 +24,6 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 **************************************************************************/
-/* $XFree86: xc/lib/GL/dri/dri_glx.c,v 1.14 2003/07/16 00:54:00 dawes Exp $ */
 
 /*
  * Authors:
@@ -39,14 +38,18 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <X11/Xlibint.h>
 #include <X11/extensions/Xext.h>
 #include <X11/extensions/extutil.h>
+#include "glheader.h"
 #include "glxclient.h"
 #include "xf86dri.h"
 #include "sarea.h"
 #include <stdio.h>
 #include <dlfcn.h>
-#include "dri_glx.h"
 #include <sys/types.h>
 #include <stdarg.h>
+#include "glcontextmodes.h"
+#include <sys/mman.h>
+#include "xf86drm.h"
+
 
 #ifndef RTLD_NOW
 #define RTLD_NOW 0
@@ -55,19 +58,31 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define RTLD_GLOBAL 0
 #endif
 
+typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate;
+typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate;
+
+struct __GLXDRIdisplayPrivateRec {
+    __GLXDRIdisplay base;
+
+    /*
+    ** XFree86-DRI version information
+    */
+    int driMajor;
+    int driMinor;
+    int driPatch;
+};
+
+struct __GLXDRIcontextPrivateRec {
+    __GLXDRIcontext base;
+    __DRIcontext driContext;
+    XID hwContextID;
+};
 
 #ifndef DEFAULT_DRIVER_DIR
 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
 #define DEFAULT_DRIVER_DIR "/usr/X11R6/lib/modules/dri"
 #endif
 
-static __DRIdriver *Drivers = NULL;
-
-
-/*
- * printf wrappers
- */
-
 static void InfoMessageF(const char *f, ...)
 {
     va_list args;
@@ -81,11 +96,15 @@ static void InfoMessageF(const char *f, ...)
     }
 }
 
+/**
+ * Print error to stderr, unless LIBGL_DEBUG=="quiet".
+ */
 static void ErrorMessageF(const char *f, ...)
 {
     va_list args;
+    const char *env;
 
-    if (getenv("LIBGL_DEBUG")) {
+    if ((env = getenv("LIBGL_DEBUG")) && !strstr(env, "quiet")) {
        fprintf(stderr, "libGL error: ");
        va_start(args, f);
        vfprintf(stderr, f, args);
@@ -94,79 +113,14 @@ static void ErrorMessageF(const char *f, ...)
 }
 
 
-/**
- * Extract the ith directory path out of a colon-separated list of paths.  No
- * more than \c dirLen characters, including the terminating \c NUL, will be
- * written to \c dir.
- *
- * \param index  Index of path to extract (starting at zero)
- * \param paths  The colon-separated list of paths
- * \param dirLen Maximum length of result to store in \c dir
- * \param dir    Buffer to hold the extracted directory path
- *
- * \returns
- * The number of characters that would have been written to \c dir had there
- * been enough room.  This does not include the terminating \c NUL.  When
- * extraction fails, zero will be returned.
- * 
- * \todo
- * It seems like this function could be rewritten to use \c strchr.
- */
-static size_t
-ExtractDir(int index, const char *paths, int dirLen, char *dir)
-{
-   int i, len;
-   const char *start, *end;
-
-   /* find ith colon */
-   start = paths;
-   i = 0;
-   while (i < index) {
-      if (*start == ':') {
-         i++;
-         start++;
-      }
-      else if (*start == 0) {
-         /* end of string and couldn't find ith colon */
-         dir[0] = 0;
-         return 0;
-      }
-      else {
-         start++;
-      }
-   }
-
-   while (*start == ':')
-      start++;
-
-   /* find next colon, or end of string */
-   end = start + 1;
-   while (*end != ':' && *end != 0) {
-      end++;
-   }
-
-   /* copy string between <start> and <end> into result string */
-   len = end - start;
-   if (len > dirLen - 1)
-      len = dirLen - 1;
-   strncpy(dir, start, len);
-   dir[len] = 0;
-
-   return( end - start );
-}
-
-
 /**
  * Versioned name of the expected \c __driCreateNewScreen function.
  * 
  * The version of the last incompatible loader/driver inteface change is
  * appended to the name of the \c __driCreateNewScreen function.  This
  * prevents loaders from trying to load drivers that are too old.
- * 
- * \todo
- * Create a macro or something so that this is automatically updated.
  */
-static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
+static const char createNewScreenName[] = __DRI_CREATE_NEW_SCREEN_STRING;
 
 
 /**
@@ -181,100 +135,64 @@ static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
  * \returns
  * A handle from \c dlopen, or \c NULL if driver file not found.
  */
-static __DRIdriver *OpenDriver(const char *driverName)
+static void *OpenDriver(const char *driverName)
 {
-   void *glhandle = NULL;
-   char *libPaths = NULL;
-   char libDir[1000];
-   int i;
-   __DRIdriver *driver;
-
-   /* First, search Drivers list to see if we've already opened this driver */
-   for (driver = Drivers; driver; driver = driver->next) {
-      if (strcmp(driver->name, driverName) == 0) {
-         /* found it */
-         return driver;
-      }
-   }
+   void *glhandle, *handle;
+   const char *libPaths, *p, *next;
+   char realDriverName[200];
+   int len;
 
    /* Attempt to make sure libGL symbols will be visible to the driver */
    glhandle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
 
+   libPaths = NULL;
    if (geteuid() == getuid()) {
       /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
       libPaths = getenv("LIBGL_DRIVERS_PATH");
       if (!libPaths)
          libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
    }
-   if (!libPaths)
-      libPaths = DEFAULT_DRIVER_DIR;
+   if (libPaths == NULL)
+       libPaths = DEFAULT_DRIVER_DIR;
+
+   handle = NULL;
+   for (p = libPaths; *p; p = next) {
+       next = strchr(p, ':');
+       if (next == NULL) {
+          len = strlen(p);
+          next = p + len;
+       } else {
+          len = next - p;
+          next++;
+       }
 
-   for ( i = 0 ; ExtractDir(i, libPaths, 1000, libDir) != 0 ; i++ ) {
-      char realDriverName[200];
-      void *handle = NULL;
-
-      
-      /* If TLS support is enabled, try to open the TLS version of the driver
-       * binary first.  If that fails, try the non-TLS version.
-       */
 #ifdef GLX_USE_TLS
-      snprintf(realDriverName, 200, "%s/tls/%s_dri.so", libDir, driverName);
+      snprintf(realDriverName, sizeof realDriverName,
+              "%.*s/tls/%s_dri.so", len, p, driverName);
       InfoMessageF("OpenDriver: trying %s\n", realDriverName);
       handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
 #endif
 
       if ( handle == NULL ) {
-        snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName);
+        snprintf(realDriverName, sizeof realDriverName,
+                 "%.*s/%s_dri.so", len, p, driverName);
         InfoMessageF("OpenDriver: trying %s\n", realDriverName);
         handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
       }
 
-      if ( handle != NULL ) {
-         /* allocate __DRIdriver struct */
-         driver = (__DRIdriver *) Xmalloc(sizeof(__DRIdriver));
-         if (!driver)
-            break; /* out of memory! */
-         /* init the struct */
-         driver->name = __glXstrdup(driverName);
-         if (!driver->name) {
-            Xfree(driver);
-            driver = NULL;
-            break; /* out of memory! */
-         }
-
-         driver->createNewScreenFunc = (PFNCREATENEWSCREENFUNC)
-            dlsym(handle, createNewScreenName);
-
-         if ( driver->createNewScreenFunc == NULL ) {
-            /* If the driver doesn't have this symbol then something's
-             * really, really wrong.
-             */
-            ErrorMessageF("%s not defined in %s_dri.so!\n"
-                         "Your driver may be too old for this libGL.\n",
-                         createNewScreenName, driverName);
-            Xfree(driver);
-            driver = NULL;
-            dlclose(handle);
-            continue;
-         }
-         driver->handle = handle;
-         /* put at head of linked list */
-         driver->next = Drivers;
-         Drivers = driver;
-         break;
-      }
-      else {
+      if ( handle != NULL )
+         break;
+      else
         ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
-      }
    }
 
-   if (!driver)
+   if (!handle)
       ErrorMessageF("unable to load driver: %s_dri.so\n", driverName);
 
    if (glhandle)
       dlclose(glhandle);
 
-   return driver;
+   return handle;
 }
 
 
@@ -318,11 +236,12 @@ static Bool GetDriverName(Display *dpy, int scrNum, char **driverName)
  * Given a display pointer and screen number, return a __DRIdriver handle.
  * Return NULL if anything goes wrong.
  */
-__DRIdriver *driGetDriver(Display *dpy, int scrNum)
+static void *driGetDriver(Display *dpy, int scrNum)
 {
    char *driverName;
+   void *ret;
+
    if (GetDriverName(dpy, scrNum, &driverName)) {
-      __DRIdriver *ret;
       ret = OpenDriver(driverName);
       if (driverName)
         Xfree(driverName);
@@ -331,14 +250,13 @@ __DRIdriver *driGetDriver(Display *dpy, int scrNum)
    return NULL;
 }
 
-
 /*
  * Exported function for querying the DRI driver for a given screen.
  *
  * The returned char pointer points to a static array that will be
  * overwritten by subsequent calls.
  */
-const char *glXGetScreenDriver (Display *dpy, int scrNum) {
+PUBLIC const char *glXGetScreenDriver (Display *dpy, int scrNum) {
    static char ret[32];
    char *driverName;
    if (GetDriverName(dpy, scrNum, &driverName)) {
@@ -367,53 +285,574 @@ const char *glXGetScreenDriver (Display *dpy, int scrNum) {
  *
  * Note: The driver remains opened after this function returns.
  */
-const char *glXGetDriverConfig (const char *driverName) {
-   __DRIdriver *driver = OpenDriver (driverName);
-   if (driver)
-      return dlsym (driver->handle, "__driConfigOptions");
+PUBLIC const char *glXGetDriverConfig (const char *driverName) {
+   void *handle = OpenDriver (driverName);
+   if (handle)
+      return dlsym (handle, "__driConfigOptions");
    else
       return NULL;
 }
 
+static void
+filter_modes( __GLcontextModes ** server_modes,
+             const __GLcontextModes * driver_modes )
+{
+    __GLcontextModes * m;
+    __GLcontextModes ** prev_next;
+    const __GLcontextModes * check;
+
+    if (driver_modes == NULL) {
+       fprintf(stderr, "libGL warning: 3D driver returned no fbconfigs.\n");
+       return;
+    }
+
+    /* For each mode in server_modes, check to see if a matching mode exists
+     * in driver_modes.  If not, then the mode is not available.
+     */
+
+    prev_next = server_modes;
+    for ( m = *prev_next ; m != NULL ; m = *prev_next ) {
+       GLboolean do_delete = GL_TRUE;
+
+       for ( check = driver_modes ; check != NULL ; check = check->next ) {
+           if ( _gl_context_modes_are_same( m, check ) ) {
+               do_delete = GL_FALSE;
+               break;
+           }
+       }
+
+       /* The 3D has to support all the modes that match the GLX visuals
+        * sent from the X server.
+        */
+       if ( do_delete && (m->visualID != 0) ) {
+           do_delete = GL_FALSE;
+
+           /* don't warn for this visual (Novell #247471 / X.Org #6689) */
+           if (m->visualRating != GLX_NON_CONFORMANT_CONFIG) {
+               fprintf(stderr, "libGL warning: 3D driver claims to not "
+                       "support visual 0x%02x\n", m->visualID);
+           }
+       }
+
+       if ( do_delete ) {
+           *prev_next = m->next;
+
+           m->next = NULL;
+           _gl_context_modes_destroy( m );
+       }
+       else {
+           prev_next = & m->next;
+       }
+    }
+}
+
+#ifdef XDAMAGE_1_1_INTERFACE
+static GLboolean has_damage_post(Display *dpy)
+{
+    static GLboolean inited = GL_FALSE;
+    static GLboolean has_damage;
+
+    if (!inited) {
+       int major, minor;
+
+       if (XDamageQueryVersion(dpy, &major, &minor) &&
+           major == 1 && minor >= 1)
+       {
+           has_damage = GL_TRUE;
+       } else {
+           has_damage = GL_FALSE;
+       }
+       inited = GL_TRUE;
+    }
 
-/* This function isn't currently used.
+    return has_damage;
+}
+#endif /* XDAMAGE_1_1_INTERFACE */
+
+static void __glXReportDamage(__DRIdrawable *driDraw,
+                             int x, int y,
+                             drm_clip_rect_t *rects, int num_rects,
+                             GLboolean front_buffer)
+{
+#ifdef XDAMAGE_1_1_INTERFACE
+    XRectangle *xrects;
+    XserverRegion region;
+    int i;
+    int x_off, y_off;
+    __GLXdrawable *glxDraw =
+       containerOf(driDraw, __GLXdrawable, driDrawable);
+    __GLXscreenConfigs *psc = glxDraw->psc;
+    Display *dpy = psc->dpy;
+    Drawable drawable;
+
+    if (!has_damage_post(dpy))
+       return;
+
+    if (front_buffer) {
+       x_off = x;
+       y_off = y;
+       drawable = RootWindow(dpy, psc->scr);
+    } else{
+       x_off = 0;
+       y_off = 0;
+       drawable = glxDraw->drawable;
+    }
+
+    xrects = malloc(sizeof(XRectangle) * num_rects);
+    if (xrects == NULL)
+       return;
+
+    for (i = 0; i < num_rects; i++) {
+       xrects[i].x = rects[i].x1 + x_off;
+       xrects[i].y = rects[i].y1 + y_off;
+       xrects[i].width = rects[i].x2 - rects[i].x1;
+       xrects[i].height = rects[i].y2 - rects[i].y1;
+    }
+    region = XFixesCreateRegion(dpy, xrects, num_rects);
+    free(xrects);
+    XDamageAdd(dpy, drawable, region);
+    XFixesDestroyRegion(dpy, region);
+#endif
+}
+
+static GLboolean
+__glXDRIGetDrawableInfo(__DRIdrawable *drawable,
+                       unsigned int *index, unsigned int *stamp, 
+                       int *X, int *Y, int *W, int *H,
+                       int *numClipRects, drm_clip_rect_t ** pClipRects,
+                       int *backX, int *backY,
+                       int *numBackClipRects, drm_clip_rect_t **pBackClipRects)
+{
+    __GLXDRIdrawable *glxDraw =
+       containerOf(drawable, __GLXDRIdrawable, driDrawable);
+    __GLXscreenConfigs *psc = glxDraw->psc;
+    Display *dpy = psc->dpy;
+
+    return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
+                                 index, stamp, X, Y, W, H,
+                                 numClipRects, pClipRects,
+                                 backX, backY,
+                                 numBackClipRects, pBackClipRects);
+}
+
+
+/**
+ * Table of functions exported by the loader to the driver.
+ */
+static const __DRIcontextModesExtension contextModesExtension = {
+    { __DRI_CONTEXT_MODES, __DRI_CONTEXT_MODES_VERSION },
+    _gl_context_modes_create,
+    _gl_context_modes_destroy,
+};
+
+static const __DRIsystemTimeExtension systemTimeExtension = {
+    { __DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION },
+    __glXGetUST,
+    __driGetMscRateOML,
+};
+
+static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
+    { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION },
+    __glXDRIGetDrawableInfo
+};
+
+static const __DRIdamageExtension damageExtension = {
+    { __DRI_DAMAGE, __DRI_DAMAGE_VERSION },
+    __glXReportDamage,
+};
+
+static const __DRIextension *loader_extensions[] = {
+    &contextModesExtension.base,
+    &systemTimeExtension.base,
+    &getDrawableInfoExtension.base,
+    &damageExtension.base,
+    NULL
+};
+
+
+/**
+ * Perform the required libGL-side initialization and call the client-side
+ * driver's \c __driCreateNewScreen function.
+ * 
+ * \param dpy    Display pointer.
+ * \param scrn   Screen number on the display.
+ * \param psc    DRI screen information.
+ * \param driDpy DRI display information.
+ * \param createNewScreen  Pointer to the client-side driver's
+ *               \c __driCreateNewScreen function.
+ * \returns A pointer to the \c __DRIscreenPrivate structure returned by
+ *          the client-side driver on success, or \c NULL on failure.
+ * 
+ * \todo This function needs to be modified to remove context-modes from the
+ *       list stored in the \c __GLXscreenConfigsRec to match the list
+ *       returned by the client-side driver.
  */
-static void driDestroyDisplay(Display *dpy, void *private)
+static void *
+CallCreateNewScreen(Display *dpy, int scrn, __GLXscreenConfigs *psc,
+                   __GLXDRIdisplayPrivate * driDpy,
+                   PFNCREATENEWSCREENFUNC createNewScreen)
 {
-    __DRIdisplayPrivate *pdpyp = (__DRIdisplayPrivate *)private;
-
-    if (pdpyp) {
-        const int numScreens = ScreenCount(dpy);
-        int i;
-        for (i = 0; i < numScreens; i++) {
-            if (pdpyp->libraryHandles[i])
-                dlclose(pdpyp->libraryHandles[i]);
-        }
-        Xfree(pdpyp->libraryHandles);
-       Xfree(pdpyp);
+    void *psp = NULL;
+#ifndef GLX_USE_APPLEGL
+    drm_handle_t hSAREA;
+    drmAddress pSAREA = MAP_FAILED;
+    char *BusID;
+    __DRIversion   ddx_version;
+    __DRIversion   dri_version;
+    __DRIversion   drm_version;
+    __DRIframebuffer  framebuffer;
+    int   fd = -1;
+    int   status;
+    const char * err_msg;
+    const char * err_extra;
+
+    dri_version.major = driDpy->driMajor;
+    dri_version.minor = driDpy->driMinor;
+    dri_version.patch = driDpy->driPatch;
+
+
+    err_msg = "XF86DRIOpenConnection";
+    err_extra = NULL;
+
+    framebuffer.base = MAP_FAILED;
+    framebuffer.dev_priv = NULL;
+
+    if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
+        int newlyopened;
+       fd = drmOpenOnce(NULL,BusID, &newlyopened);
+       Xfree(BusID); /* No longer needed */
+
+       err_msg = "open DRM";
+       err_extra = strerror( -fd );
+
+       if (fd >= 0) {
+           drm_magic_t magic;
+
+           err_msg = "drmGetMagic";
+           err_extra = NULL;
+
+           if (!drmGetMagic(fd, &magic)) {
+               drmVersionPtr version = drmGetVersion(fd);
+               if (version) {
+                   drm_version.major = version->version_major;
+                   drm_version.minor = version->version_minor;
+                   drm_version.patch = version->version_patchlevel;
+                   drmFreeVersion(version);
+               }
+               else {
+                   drm_version.major = -1;
+                   drm_version.minor = -1;
+                   drm_version.patch = -1;
+               }
+
+               err_msg = "XF86DRIAuthConnection";
+               if (!newlyopened || XF86DRIAuthConnection(dpy, scrn, magic)) {
+                   char *driverName;
+
+                   /*
+                    * Get device name (like "tdfx") and the ddx version
+                    * numbers.  We'll check the version in each DRI driver's
+                    * "createNewScreen" function.
+                    */
+                   err_msg = "XF86DRIGetClientDriverName";
+                   if (XF86DRIGetClientDriverName(dpy, scrn,
+                                                  &ddx_version.major,
+                                                  &ddx_version.minor,
+                                                  &ddx_version.patch,
+                                                  &driverName)) {
+                       drm_handle_t  hFB;
+                       int        junk;
+
+                       /* No longer needed. */
+                       Xfree( driverName );
+
+
+                       /*
+                        * Get device-specific info.  pDevPriv will point to a struct
+                        * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
+                        * that has information about the screen size, depth, pitch,
+                        * ancilliary buffers, DRM mmap handles, etc.
+                        */
+                       err_msg = "XF86DRIGetDeviceInfo";
+                       if (XF86DRIGetDeviceInfo(dpy, scrn,
+                                                &hFB,
+                                                &junk,
+                                                &framebuffer.size,
+                                                &framebuffer.stride,
+                                                &framebuffer.dev_priv_size,
+                                                &framebuffer.dev_priv)) {
+                           framebuffer.width = DisplayWidth(dpy, scrn);
+                           framebuffer.height = DisplayHeight(dpy, scrn);
+
+                           /*
+                            * Map the framebuffer region.
+                            */
+                           status = drmMap(fd, hFB, framebuffer.size, 
+                                           (drmAddressPtr)&framebuffer.base);
+
+                           err_msg = "drmMap of framebuffer";
+                           err_extra = strerror( -status );
+
+                           if ( status == 0 ) {
+                               /*
+                                * Map the SAREA region.  Further mmap regions
+                                * may be setup in each DRI driver's
+                                * "createNewScreen" function.
+                                */
+                               status = drmMap(fd, hSAREA, SAREA_MAX, 
+                                               &pSAREA);
+
+                               err_msg = "drmMap of sarea";
+                               err_extra = strerror( -status );
+
+                               if ( status == 0 ) {
+                                   __GLcontextModes * driver_modes = NULL;
+
+                                   err_msg = "InitDriver";
+                                   err_extra = NULL;
+                                   psp = (*createNewScreen)(scrn,
+                                                            &psc->__driScreen,
+                                                            & ddx_version,
+                                                            & dri_version,
+                                                            & drm_version,
+                                                            & framebuffer,
+                                                            pSAREA,
+                                                            fd,
+                                                            loader_extensions,
+                                                            & driver_modes );
+
+                                   filter_modes(&psc->configs, driver_modes);
+                                   filter_modes(&psc->visuals, driver_modes);
+                                   _gl_context_modes_destroy(driver_modes);
+                               }
+                           }
+                       }
+                   }
+               }
+           }
+       }
     }
+
+    if ( psp == NULL ) {
+       if ( pSAREA != MAP_FAILED ) {
+           (void)drmUnmap(pSAREA, SAREA_MAX);
+       }
+
+       if ( framebuffer.base != MAP_FAILED ) {
+           (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
+       }
+
+       if ( framebuffer.dev_priv != NULL ) {
+           Xfree(framebuffer.dev_priv);
+       }
+
+       if ( fd >= 0 ) {
+           (void)drmCloseOnce(fd);
+       }
+
+       (void)XF86DRICloseConnection(dpy, scrn);
+
+       if ( err_extra != NULL ) {
+           fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
+                   err_extra);
+       }
+       else {
+           fprintf(stderr, "libGL error: %s failed\n", err_msg );
+       }
+
+        fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
+    }
+#endif /* !GLX_USE_APPLEGL */
+
+    return psp;
+}
+
+static void driDestroyContext(__GLXDRIcontext *context,
+                             __GLXscreenConfigs *psc, Display *dpy)
+{
+    __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
+                       
+    (*pcp->driContext.destroyContext)(&pcp->driContext);
+
+    XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
+}
+
+static Bool driBindContext(__GLXDRIcontext *context,
+                          __GLXDRIdrawable *draw, __GLXDRIdrawable *read)
+{
+    __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
+
+    return (*pcp->driContext.bindContext)(&pcp->driContext,
+                                         &draw->driDrawable,
+                                         &read->driDrawable);
+}
+
+static void driUnbindContext(__GLXDRIcontext *context)
+{
+    __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context;
+
+    (*pcp->driContext.unbindContext)(&pcp->driContext);
+}
+
+static __GLXDRIcontext *driCreateContext(__GLXscreenConfigs *psc,
+                                        const __GLcontextModes *mode,
+                                        GLXContext gc,
+                                        GLXContext shareList, int renderType)
+{
+    __GLXDRIcontextPrivate *pcp, *pcp_shared;
+    drm_context_t hwContext;
+    __DRIcontext *shared = NULL;
+
+    if (psc && psc->driScreen) {
+       if (shareList) {
+           pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext;
+           shared = &pcp_shared->driContext;
+       }
+
+       pcp = Xmalloc(sizeof *pcp);
+       if (pcp == NULL)
+           return NULL;
+
+       if (!XF86DRICreateContextWithConfig(psc->dpy, psc->scr,
+                                           mode->visualID,
+                                           &pcp->hwContextID, &hwContext)) {
+           Xfree(pcp);
+           return NULL;
+       }
+
+       pcp->driContext.private = 
+           (*psc->__driScreen.createNewContext)(&psc->__driScreen,
+                                                mode, renderType,
+                                                shared,
+                                                hwContext,
+                                                &pcp->driContext);
+       if (pcp->driContext.private == NULL) {
+           XF86DRIDestroyContext(psc->dpy, psc->scr, pcp->hwContextID);
+           Xfree(pcp);
+           return NULL;
+       }
+
+       pcp->base.destroyContext = driDestroyContext;
+       pcp->base.bindContext = driBindContext;
+       pcp->base.unbindContext = driUnbindContext;
+
+       return &pcp->base;
+    }
+
+    return NULL;
+}
+
+
+static __GLXDRIdrawable *driCreateDrawable(__GLXscreenConfigs *psc,
+                                          GLXDrawable drawable,
+                                          GLXContext gc)
+{
+    __GLXDRIdrawable *pdraw;
+    drm_drawable_t hwDrawable;
+    void *empty_attribute_list = NULL;
+
+    pdraw = Xmalloc(sizeof(*pdraw));
+    if (!pdraw)
+       return NULL;
+
+    pdraw->drawable = drawable;
+    pdraw->psc = psc;
+
+    if (!XF86DRICreateDrawable(psc->dpy, psc->scr, drawable, &hwDrawable))
+       return NULL;
+
+    /* Create a new drawable */
+    pdraw->driDrawable.private =
+       (*psc->__driScreen.createNewDrawable)(&psc->__driScreen,
+                                             gc->mode,
+                                             &pdraw->driDrawable,
+                                             hwDrawable,
+                                             GLX_WINDOW_BIT,
+                                             0,
+                                             empty_attribute_list);
+
+    if (!pdraw->driDrawable.private) {
+       XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
+       Xfree(pdraw);
+       return NULL;
+    }
+
+    if (__glxHashInsert(psc->drawHash, drawable, pdraw)) {
+       (*pdraw->driDrawable.destroyDrawable)(&pdraw->driDrawable);
+       XF86DRIDestroyDrawable(psc->dpy, psc->scr, drawable);
+       Xfree(pdraw);
+       return NULL;
+    }
+
+    return pdraw;
+}
+
+static void driDestroyScreen(__GLXscreenConfigs *psc)
+{
+    /* Free the direct rendering per screen data */
+    if (psc->__driScreen.private)
+       (*psc->__driScreen.destroyScreen)(&psc->__driScreen);
+    psc->__driScreen.private = NULL;
+    if (psc->drawHash)
+       __glxHashDestroy(psc->drawHash);
+    if (psc->driver)
+       dlclose(psc->driver);
 }
 
+static __GLXDRIscreen *driCreateScreen(__GLXscreenConfigs *psc, int screen,
+                                      __GLXdisplayPrivate *priv)
+{
+    PFNCREATENEWSCREENFUNC createNewScreen;
+    __GLXDRIdisplayPrivate *pdp;
+    __GLXDRIscreen *psp;
+
+    psp = Xmalloc(sizeof *psp);
+    if (psp == NULL)
+       return NULL;
+
+    /* Create drawable hash */
+    psc->drawHash = __glxHashCreate();
+    if ( psc->drawHash == NULL )
+       return NULL;
+
+    /* Initialize per screen dynamic client GLX extensions */
+    psc->ext_list_first_time = GL_TRUE;
+
+    psc->driver = driGetDriver(priv->dpy, screen);
+    createNewScreen = dlsym(psc->driver, createNewScreenName);
+    if (createNewScreenName == NULL)
+       return NULL;
+
+    pdp = (__GLXDRIdisplayPrivate *) priv->driDisplay;
+    psc->__driScreen.private =
+       CallCreateNewScreen(psc->dpy, screen, psc, pdp, createNewScreen);
+    if (psc->__driScreen.private != NULL)
+       __glXScrEnableDRIExtension(psc);
+
+    psp->destroyScreen = driDestroyScreen;
+    psp->createContext = driCreateContext;
+    psp->createDrawable = driCreateDrawable;
+
+    return psp;
+}
+
+/* Called from __glXFreeDisplayPrivate.
+ */
+static void driDestroyDisplay(__GLXDRIdisplay *dpy)
+{
+    Xfree(dpy);
+}
 
 /*
  * Allocate, initialize and return a __DRIdisplayPrivate object.
  * This is called from __glXInitialize() when we are given a new
  * display pointer.
  */
-void *driCreateDisplay(Display *dpy, __DRIdisplay *pdisp)
+_X_HIDDEN __GLXDRIdisplay *driCreateDisplay(Display *dpy)
 {
-    const int numScreens = ScreenCount(dpy);
-    __DRIdisplayPrivate *pdpyp;
+    __GLXDRIdisplayPrivate *pdpyp;
     int eventBase, errorBase;
     int major, minor, patch;
-    int scrn;
-
-    /* Initialize these fields to NULL in case we fail.
-     * If we don't do this we may later get segfaults trying to free random
-     * addresses when the display is closed.
-     */
-    pdisp->private = NULL;
-    pdisp->destroyDisplay = NULL;
 
     if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
        return NULL;
@@ -423,7 +862,7 @@ void *driCreateDisplay(Display *dpy, __DRIdisplay *pdisp)
        return NULL;
     }
 
-    pdpyp = (__DRIdisplayPrivate *)Xmalloc(sizeof(__DRIdisplayPrivate));
+    pdpyp = Xmalloc(sizeof *pdpyp);
     if (!pdpyp) {
        return NULL;
     }
@@ -432,41 +871,10 @@ void *driCreateDisplay(Display *dpy, __DRIdisplay *pdisp)
     pdpyp->driMinor = minor;
     pdpyp->driPatch = patch;
 
-    pdisp->destroyDisplay = driDestroyDisplay;
-
-    /* allocate array of pointers to createNewScreen funcs */
-    pdisp->createNewScreen = (PFNCREATENEWSCREENFUNC *)
-      Xmalloc(numScreens * sizeof(void *));
-    if (!pdisp->createNewScreen) {
-       Xfree(pdpyp);
-       return NULL;
-    }
-
-    /* allocate array of library handles */
-    pdpyp->libraryHandles = (void **) Xmalloc(numScreens * sizeof(void*));
-    if (!pdpyp->libraryHandles) {
-       Xfree(pdisp->createNewScreen);
-       Xfree(pdpyp);
-       return NULL;
-    }
-
-    /* dynamically discover DRI drivers for all screens, saving each
-     * driver's "__driCreateScreen" function pointer.  That's the bootstrap
-     * entrypoint for all DRI drivers.
-     */
-    for (scrn = 0; scrn < numScreens; scrn++) {
-        __DRIdriver *driver = driGetDriver(dpy, scrn);
-        if (driver) {
-           pdisp->createNewScreen[scrn] = driver->createNewScreenFunc;
-           pdpyp->libraryHandles[scrn] = driver->handle;
-        }
-        else {
-           pdisp->createNewScreen[scrn] = NULL;
-           pdpyp->libraryHandles[scrn] = NULL;
-        }
-    }
+    pdpyp->base.destroyDisplay = driDestroyDisplay;
+    pdpyp->base.createScreen = driCreateScreen;
 
-    return (void *)pdpyp;
+    return &pdpyp->base;
 }
 
 #endif /* GLX_DIRECT_RENDERING */