egl: Change the way drivers are loaded.
authorChia-I Wu <olvaffe@gmail.com>
Thu, 13 Aug 2009 05:01:48 +0000 (13:01 +0800)
committerBrian Paul <brianp@vmware.com>
Tue, 18 Aug 2009 14:44:44 +0000 (08:44 -0600)
Driver is chosen and preloaded when eglGetDisplay is called.  Later when
eglInitialize is called, the same driver is matched to initialize the
display.  Also, add new, but unused, hooks to EGLDriver to allow a
driver to probe a display or unload itself.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
src/egl/main/eglapi.c
src/egl/main/egldisplay.c
src/egl/main/egldisplay.h
src/egl/main/egldriver.c
src/egl/main/egldriver.h
src/egl/main/eglglobals.c

index e8a5b18912041b8b907c4154a40ebbed068225a7..464da00fe2ce0cb71a613a8308121616ed2a29b2 100644 (file)
@@ -77,7 +77,7 @@ eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
 
    drv = disp->Driver;
    if (!drv) {
-      drv = _eglOpenDriver(disp, disp->DriverName, disp->DriverArgs);
+      drv = _eglOpenDriver(disp);
       if (!drv)
          return _eglError(EGL_NOT_INITIALIZED, __FUNCTION__);
 
index c684e4291eed435dd14ce0215d63977e0cc75fb7..ba7e634c9d602750f46c83714764f3885e670eaa 100644 (file)
@@ -94,7 +94,7 @@ _eglNewDisplay(NativeDisplayType nativeDisplay)
       _eglInitDisplay();
       dpy->SurfaceHash = _eglSurfaceHash;
 
-      dpy->DriverName = _eglChooseDriver(dpy);
+      dpy->DriverName = _eglPreloadDriver(dpy);
       if (!dpy->DriverName) {
          free(dpy);
          return NULL;
@@ -244,11 +244,6 @@ _eglCleanupDisplay(_EGLDisplay *disp)
    disp->Configs = NULL;
 
    /* XXX incomplete */
-
-   free((void *) disp->DriverName);
-   disp->DriverName = NULL;
-
-   /* driver deletes the _EGLDisplay object */
 }
 
 
index 1ebc0fcb59ec99d74c0ba5450883315c2013af33..78fbf5b8401f9c4d878a3c5ae372e1b16f273f1d 100644 (file)
@@ -15,7 +15,6 @@ struct _egl_display
    EGLDisplay Handle;
 
    const char *DriverName;
-   const char *DriverArgs;
    _EGLDriver *Driver;
 
    EGLint NumScreens;
index a8ac7b3233ba6db2659b52641114365a4b6c84d0..36cc2948c0ea55dd13f867875c92ae66b9326068 100644 (file)
@@ -114,11 +114,12 @@ _eglChooseDRMDriver(int card)
 #endif
 }
 
+
 /**
  * XXX this function is totally subject change!!!
  *
  *
- * Determine/return the name of the driver to use for the given _EGLDisplay.
+ * Determine/return the path of the driver to use for the given native display.
  *
  * Try to be clever and determine if nativeDisplay is an Xlib Display
  * ptr or a string (naming a driver or screen number, etc).
@@ -128,89 +129,69 @@ _eglChooseDRMDriver(int card)
  * Else if the first character is '!' we interpret it as specific driver name
  * (i.e. "!r200" or "!i830".
  *
- * Whatever follows ':' is copied and put into dpy->DriverArgs.
+ * Whatever follows ':' is interpreted as arguments.
  *
- * The caller may free() the returned string.
+ * The caller may free() the returned strings.
  */
-const char *
-_eglChooseDriver(_EGLDisplay *dpy)
+static char *
+_eglChooseDriver(_EGLDisplay *dpy, char **argsRet)
 {
-   /* Under Windows, the NativeDisplay is an HDC handle, therefore */
-   /* it can't be interpreted as a string or a pointer. */
-#if defined(_EGL_PLATFORM_WINDOWS)
-   const char *displayString = NULL;
-#else
-   const char *displayString = (const char *) dpy->NativeDisplay;
-#endif
-   const char *driverName = NULL;
+   char *path = NULL;
+   const char *args = NULL;
 
-   (void) DefaultDriverName;
+   path = getenv("EGL_DRIVER");
+   if (path)
+      path = _eglstrdup(path);
 
 #if defined(_EGL_PLATFORM_X)
-   /* First, if the EGL_DRIVER env var is set, use that */
-   driverName = getenv("EGL_DRIVER");
-   if (driverName)
-      return _eglstrdup(driverName);
-#endif
+   (void) DefaultDriverName;
 
-#if 0
-   if (!displayString) {
-      /* choose a default */
-      displayString = DefaultDriverName;
-   }
-#endif
-   /* extract default DriverArgs = whatever follows ':' */
-   if (displayString &&
-       (displayString[0] == '!' ||
-        displayString[0] == ':')) {
-      const char *args = strchr(displayString, ':');
-      if (args)
-         dpy->DriverArgs = _eglstrdup(args + 1);
-   }
+   if (!path && dpy->NativeDisplay) {
+      const char *dpyString = (const char *) dpy->NativeDisplay;
+      char *p;
+      /* parse the display string */
+      if (dpyString[0] == '!' || dpyString[0] == ':') {
+         if (dpyString[0] == '!') {
+            path = _eglstrdup(dpyString);
+            p = strchr(path, ':');
+            if (p)
+               *p++ = '\0';
+         } else {
+            p = strchr(dpyString, ':');
+            if (p)
+               p++;
+         }
 
-   /* determine driver name now */
-   if (displayString && displayString[0] == ':' &&
-       (displayString[1] >= '0' && displayString[1] <= '9') &&
-       !displayString[2]) {
-      int card = atoi(displayString + 1);
-      driverName = _eglChooseDRMDriver(card);
-   }
-   else if (displayString && displayString[0] == '!') {
-      /* use user-specified driver name */
-      driverName = _eglstrdup(displayString + 1);
-      /* truncate driverName at ':' if present */
-      {
-         char *args = strchr(driverName, ':');
-         if (args) {
-            *args = 0;
+         if (p) {
+            if (!path && p[0] >= '0' && p[0] <= '9' && !p[1]) {
+               int card = atoi(p);
+               path = (char *) _eglChooseDRMDriver(card);
+            }
+            args = p;
          }
       }
+      else {
+         path = (char *) _xeglChooseDriver(dpy);
+      }
    }
-   else 
-   {
-      /* NativeDisplay is not a string! */
-#if defined(_EGL_PLATFORM_X)
-      driverName = _xeglChooseDriver(dpy);
-#else
-      driverName = DefaultDriverName;
-#endif
-   }
+#elif defined(_EGL_PLATFORM_WINDOWS)
+   if (!path)
+      path = _eglstrdup(DefaultDriverName);
+#endif /* _EGL_PLATFORM_X */
 
-   return driverName;
+   if (path && argsRet)
+      *argsRet = (args) ? _eglstrdup(args) : NULL;
+
+   return path;
 }
 
 
 /**
- * Open/load the named driver and call its bootstrap function: _eglMain().
- * By the time this function is called, the dpy->DriverName should have
- * been determined.
- *
- * \return  new _EGLDriver object.
+ * Open the named driver and find its bootstrap function: _eglMain().
  */
-_EGLDriver *
-_eglOpenDriver(_EGLDisplay *dpy, const char *driverName, const char *args)
+static _EGLMain_t
+_eglOpenLibrary(const char *driverName, lib_handle *handle)
 {
-   _EGLDriver *drv;
    _EGLMain_t mainFunc;
    lib_handle lib;
    char driverFilename[1000];
@@ -249,58 +230,170 @@ _eglOpenDriver(_EGLDisplay *dpy, const char *driverName, const char *args)
 
    if (!mainFunc) {
       _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverFilename);
-      close_library(lib);
+      if (lib)
+         close_library(lib);
       return NULL;
    }
 
+   *handle = lib;
+   return mainFunc;
+}
+
+
+/**
+ * Load the named driver.  The path and args passed will be
+ * owned by the driver and freed.
+ */
+static _EGLDriver *
+_eglLoadDriver(_EGLDisplay *dpy, char *path, char *args)
+{
+   _EGLMain_t mainFunc;
+   lib_handle lib;
+   _EGLDriver *drv = NULL;
+
+   mainFunc = _eglOpenLibrary(path, &lib);
+   if (!mainFunc)
+      return NULL;
+
    drv = mainFunc(dpy, args);
    if (!drv) {
-      close_library(lib);
+      if (lib)
+         close_library(lib);
       return NULL;
    }
 
-   /* with a recurvise open you want the inner most handle */
-   if (!drv->LibHandle) {
-      drv->LibHandle = lib;
+   if (!drv->Name) {
+      _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", path);
+      drv->Name = "UNNAMED";
    }
-   else {
-      close_library(lib);
+
+   drv->Path = path;
+   drv->Args = args;
+   drv->LibHandle = lib;
+
+   return drv;
+}
+
+
+/**
+ * Match a display to a preloaded driver.
+ */
+static _EGLDriver *
+_eglMatchDriver(_EGLDisplay *dpy)
+{
+   _EGLDriver *defaultDriver = NULL;
+   EGLint i;
+
+   for (i = 0; i < _eglGlobal.NumDrivers; i++) {
+      _EGLDriver *drv = _eglGlobal.Drivers[i];
+
+      /* display specifies a driver */
+      if (dpy->DriverName) {
+         if (strcmp(dpy->DriverName, drv->Name) == 0)
+            return drv;
+      }
+      else if (drv->Probe) {
+         if (drv->Probe(drv, dpy))
+            return drv;
+      }
+      else {
+         if (!defaultDriver)
+            defaultDriver = drv;
+      }
    }
 
+   return defaultDriver;
+}
+
+
+/**
+ * Load a driver and save it.
+ */
+const char *
+_eglPreloadDriver(_EGLDisplay *dpy)
+{
+   char *path, *args;
+   _EGLDriver *drv;
+   EGLint i;
+
+   path = _eglChooseDriver(dpy, &args);
+   if (!path)
+      return NULL;
+
+   for (i = 0; i < _eglGlobal.NumDrivers; i++) {
+      drv = _eglGlobal.Drivers[i];
+      if (strcmp(drv->Path, path) == 0) {
+         _eglLog(_EGL_DEBUG, "Driver %s is already preloaded",
+                 drv->Name);
+         free(path);
+         if (args)
+            free(args);
+         return drv->Name;
+      }
+   }
+
+   drv = _eglLoadDriver(dpy, path, args);
+   if (!drv)
+      return NULL;
+
    /* update the global notion of supported APIs */
    _eglGlobal.ClientAPIsMask |= drv->ClientAPIsMask;
 
-   _eglSaveDriver(drv);
+   _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
 
+   return drv->Name;
+}
+
+
+/**
+ * Open a preloaded driver.
+ */
+_EGLDriver *
+_eglOpenDriver(_EGLDisplay *dpy)
+{
+   _EGLDriver *drv = _eglMatchDriver(dpy);
    return drv;
 }
 
 
+/**
+ * Close a preloaded driver.
+ */
 EGLBoolean
 _eglCloseDriver(_EGLDriver *drv, _EGLDisplay *dpy)
 {
-   void *handle = drv->LibHandle;
-   EGLBoolean b;
-
-   _eglLog(_EGL_DEBUG, "Closing %s", drv->Name);
-
    _eglReleaseDisplayResources(drv, dpy);
-
-   b = drv->API.Terminate(drv, dpy);
-
-   close_library(handle);
-
-   return b;
+   drv->API.Terminate(drv, dpy);
+   return EGL_TRUE;
 }
 
 
 /**
- * Save the given driver pointer in the list of all known drivers.
+ * Unload preloaded drivers.
  */
 void
-_eglSaveDriver(_EGLDriver *drv)
+_eglUnloadDrivers(void)
 {
-   _eglGlobal.Drivers[ _eglGlobal.NumDrivers++ ] = drv;
+   EGLint i;
+   for (i = 0; i < _eglGlobal.NumDrivers; i++) {
+      _EGLDriver *drv = _eglGlobal.Drivers[i];
+      lib_handle handle = drv->LibHandle;
+
+      if (drv->Path)
+         free((char *) drv->Path);
+      if (drv->Args)
+         free((char *) drv->Args);
+
+      /* destroy driver */
+      if (drv->Unload)
+         drv->Unload(drv);
+
+      if (handle)
+         close_library(handle);
+      _eglGlobal.Drivers[i] = NULL;
+   }
+
+   _eglGlobal.NumDrivers = 0;
 }
 
 
index d97a24db1d595b1d9adc8650a913f9f89738fdec..430c0949d447de45d497aa86a563edca2bb1f3a5 100644 (file)
@@ -27,8 +27,14 @@ struct _egl_driver
    EGLBoolean Initialized; /**< set by driver after initialized */
 
    void *LibHandle; /**< dlopen handle */
+   const char *Path;  /**< path to this driver */
+   const char *Args;  /**< args to load this driver */
 
    const char *Name;  /**< name of this driver */
+   /**< probe a display to see if it is supported */
+   EGLBoolean (*Probe)(_EGLDriver *drv, _EGLDisplay *dpy);
+   /**< called before dlclose to release this driver */
+   void (*Unload)(_EGLDriver *drv);
 
    int APImajor, APIminor; /**< as returned by eglInitialize() */
    char Version[1000];       /**< initialized from APImajor/minor, Name */
@@ -50,20 +56,21 @@ extern _EGLDriver *_eglMain(_EGLDisplay *dpy, const char *args);
 extern const char *
 _eglChooseDRMDriver(int card);
 
+
 extern const char *
-_eglChooseDriver(_EGLDisplay *dpy);
+_eglPreloadDriver(_EGLDisplay *dpy);
 
 
 extern _EGLDriver *
-_eglOpenDriver(_EGLDisplay *dpy, const char *driverName, const char *args);
+_eglOpenDriver(_EGLDisplay *dpy);
 
 
 extern EGLBoolean
 _eglCloseDriver(_EGLDriver *drv, _EGLDisplay *dpy);
 
 
-extern void
-_eglSaveDriver(_EGLDriver *drv);
+void
+_eglUnloadDrivers(void);
 
 
 extern _EGLDriver *
index e93b48e03b80bb58e8c368babc040594bbf4af2d..a532f142b7eec12fb98ff2804f50cc54b2203f9c 100644 (file)
@@ -1,7 +1,7 @@
 #include <stdlib.h>
 #include <assert.h>
 #include "eglglobals.h"
-#include "egldisplay.h"
+#include "egldriver.h"
 #include "egllog.h"
 #include "eglmutex.h"
 
@@ -18,8 +18,10 @@ struct _egl_global _eglGlobal =
    { 0x0 },                /* ClientAPIs */
    0,                      /* NumDrivers */
    { NULL },               /* Drivers */
-   0,                      /* NumAtExitCalls */
-   { NULL },               /* AtExitCalls */
+   1,                      /* NumAtExitCalls */
+   {                       /* AtExitCalls */
+      _eglUnloadDrivers
+   },
 };