OSDN Git Service

egl: Better report of driver loading error.
[android-x86/external-mesa.git] / src / egl / main / egldriver.c
index 43b1f51..1eb3746 100644 (file)
 #include "eglscreen.h"
 #include "eglstring.h"
 #include "eglsurface.h"
+#include "eglimage.h"
 
 #if defined(_EGL_PLATFORM_X)
 #include <dlfcn.h>
-#include "eglx.h"
-#elif defined(_EGL_PLATFORM_WINDOWS)
-/* Use static linking on Windows for now */
-#define WINDOWS_STATIC_LINK
 #endif
 
+
 /**
  * Wrappers for dlopen/dlclose()
  */
 #if defined(_EGL_PLATFORM_WINDOWS)
-#ifdef WINDOWS_STATIC_LINK
-   static const char *DefaultDriverName = "Windows EGL Static Library";
-#else
-   /* XXX Need to decide how to do dynamic name lookup on Windows */
-   static const char *DefaultDriverName = "TBD";
-#endif
-   static const char *SysFS = NULL;
-   typedef HMODULE lib_handle;
-
-   static HMODULE
-   open_library(const char *filename)
-   {
-#ifdef WINDOWS_STATIC_LINK
-      return 0;
-#else
-      return LoadLibrary(filename);
-#endif
-   }
 
-   static void
-   close_library(HMODULE lib)
-   {
-#ifdef WINDOWS_STATIC_LINK
-#else
-      FreeLibrary(lib);
-#endif
-   }
+
+/* XXX Need to decide how to do dynamic name lookup on Windows */
+static const char DefaultDriverName[] = "TBD";
+
+typedef HMODULE lib_handle;
+
+static HMODULE
+open_library(const char *filename)
+{
+   return LoadLibrary(filename);
+}
+
+static void
+close_library(HMODULE lib)
+{
+   FreeLibrary(lib);
+}
+
 
 #elif defined(_EGL_PLATFORM_X)
-   static const char *DefaultDriverName = ":0";
-   static const char *SysFS = "/sys/class";
 
-   typedef void * lib_handle;
 
-   static void *
-   open_library(const char *filename)
-   {
-      return dlopen(filename, RTLD_LAZY);
-   }
+static const char DefaultDriverName[] = "egl_softpipe";
 
-   static void
-   close_library(void *lib)
-   {
-      dlclose(lib);
-   }
-   
-#endif
+typedef void * lib_handle;
 
-/**
- * Given a card number, use sysfs to determine the DRI driver name.
- */
-const char *
-_eglChooseDRMDriver(int card)
+static void *
+open_library(const char *filename)
 {
-#if 0
-   return _eglstrdup("libEGLdri");
-#else
-   char path[2000], driverName[2000];
-   FILE *f;
-   int length;
+   return dlopen(filename, RTLD_LAZY);
+}
 
-   snprintf(path, sizeof(path), "%s/drm/card%d/dri_library_name", SysFS, card);
+static void
+close_library(void *lib)
+{
+   dlclose(lib);
+}
 
-   f = fopen(path, "r");
-   if (!f)
-      return NULL;
+#else /* _EGL_PLATFORM_NO_OS */
 
-   fgets(driverName, sizeof(driverName), f);
-   fclose(f);
+static const char DefaultDriverName[] = "builtin";
 
-   if ((length = strlen(driverName)) > 1) {
-      /* remove the trailing newline from sysfs */
-      driverName[length - 1] = '\0';
-      strncat(driverName, "_dri", sizeof(driverName));
-      return _eglstrdup(driverName);
-   }
-   else {
-      return NULL;
-   }   
-#endif
+typedef void *lib_handle;
+
+static INLINE void *
+open_library(const char *filename)
+{
+   return (void *) filename;
+}
+
+static INLINE void
+close_library(void *lib)
+{
 }
 
+
+#endif
+
+
 /**
- * XXX this function is totally subject change!!!
- *
- *
- * Determine/return the name of the driver to use for the given _EGLDisplay.
- *
- * Try to be clever and determine if nativeDisplay is an Xlib Display
- * ptr or a string (naming a driver or screen number, etc).
- *
- * If the first character is ':' we interpret it as a screen or card index
- * number (i.e. ":0" or ":1", etc)
- * 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.
- *
- * The caller may free() the returned string.
+ * Choose a driver for a given display.
+ * 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;
+   const char *suffix = NULL;
+   const char *p;
 
-   (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
-
-#if 0
-   if (!displayString) {
-      /* choose a default */
-      displayString = DefaultDriverName;
+   if (!path && dpy && dpy->NativeDisplay) {
+      /* assume (wrongly!) that the native display is a display string */
+      path = _eglSplitDisplayString((const char *) dpy->NativeDisplay, &args);
    }
-#endif
-   /* extract default DriverArgs = whatever follows ':' */
-   if (displayString &&
-       (displayString[0] == '!' ||
-        displayString[0] == ':')) {
-      const char *args = strchr(displayString, ':');
-      if (args)
-         dpy->DriverArgs = _eglstrdup(args + 1);
+   suffix = "so";
+#elif defined(_EGL_PLATFORM_WINDOWS)
+   suffix = "dll";
+#else /* _EGL_PLATFORM_NO_OS */
+   if (path) {
+      /* force the use of the default driver */
+      _eglLog(_EGL_DEBUG, "ignore EGL_DRIVER");
+      free(path);
+      path = NULL;
    }
+   suffix = NULL;
+#endif
 
-   /* 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 (!path)
+      path = _eglstrdup(DefaultDriverName);
+
+   /* append suffix if there isn't */
+   p = strrchr(path, '.');
+   if (!p && suffix) {
+      size_t len = strlen(path);
+      char *tmp = malloc(len + strlen(suffix) + 2);
+      if (tmp) {
+         memcpy(tmp, path, len);
+         tmp[len++] = '.';
+         tmp[len] = '\0';
+         strcat(tmp + len, suffix);
+
+         free(path);
+         path = tmp;
       }
    }
-   else 
-   {
-      /* NativeDisplay is not a string! */
-#if defined(_EGL_PLATFORM_X)
-      driverName = _xeglChooseDriver(dpy);
-#else
-      driverName = DefaultDriverName;
-#endif
-   }
 
-   return driverName;
+   if (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 *driverPath, lib_handle *handle)
 {
-   _EGLDriver *drv;
-   _EGLMain_t mainFunc;
    lib_handle lib;
-   char driverFilename[1000];
+   _EGLMain_t mainFunc = NULL;
+   const char *error = "unknown error";
 
-   assert(driverName);
+   assert(driverPath);
+
+   _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
+   lib = open_library(driverPath);
 
 #if defined(_EGL_PLATFORM_WINDOWS)
-/* Use static linking on Windows for now */
-#ifdef WINDOWS_STATIC_LINK
-   lib = 0;
-   mainFunc = (_EGLMain_t)_eglMain;
-#else
    /* XXX untested */
-   sprintf(driverFilename, "%s.dll", driverName);
-   _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename);
-   lib = open_library(driverFilename);
-   if (!lib) {
-      _eglLog(_EGL_WARNING, "Could not open %s",
-              driverFilename);
-      return NULL;
+   if (lib)
+      mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
+#elif defined(_EGL_PLATFORM_X)
+   if (lib) {
+      mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
+      if (!mainFunc)
+         error = dlerror();
    }
-   mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
+   else {
+      error = dlerror();
+   }
+#else /* _EGL_PLATFORM_NO_OS */
+   /* must be the default driver name */
+   if (strcmp(driverPath, DefaultDriverName) == 0)
+      mainFunc = (_EGLMain_t) _eglMain;
+   else
+      error = "not builtin driver";
 #endif
-#elif defined(_EGL_PLATFORM_X)
-   /* XXX also prepend a directory path??? */
-   sprintf(driverFilename, "%s.so", driverName);
-   _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename);
-   lib = open_library(driverFilename);
+
    if (!lib) {
-      _eglLog(_EGL_WARNING, "Could not open %s (%s)",
-              driverFilename, dlerror());
+      _eglLog(_EGL_WARNING, "Could not open driver %s (%s)",
+              driverPath, error);
+      if (!getenv("EGL_DRIVER"))
+         _eglLog(_EGL_WARNING,
+                 "The driver can be overridden by setting EGL_DRIVER");
       return NULL;
    }
-   mainFunc = (_EGLMain_t) dlsym(lib, "_eglMain");
-#endif
 
    if (!mainFunc) {
-      _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverFilename);
-      close_library(lib);
+      _eglLog(_EGL_WARNING, "_eglMain not found in %s (%s)",
+              driverPath, error);
+      if (lib)
+         close_library(lib);
       return NULL;
    }
 
-   drv = mainFunc(dpy, args);
+   *handle = lib;
+   return mainFunc;
+}
+
+
+/**
+ * Load the named driver.  The path and args passed will be
+ * owned by the driver and freed.
+ */
+static _EGLDriver *
+_eglLoadDriver(char *path, char *args)
+{
+   _EGLMain_t mainFunc;
+   lib_handle lib;
+   _EGLDriver *drv = NULL;
+
+   mainFunc = _eglOpenLibrary(path, &lib);
+   if (!mainFunc)
+      return NULL;
+
+   drv = mainFunc(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);
-   }
-
-   /* update the global notion of supported APIs */
-   _eglGlobal.ClientAPIsMask |= drv->ClientAPIsMask;
 
-   _eglSaveDriver(drv);
+   drv->Path = path;
+   drv->Args = args;
+   drv->LibHandle = lib;
 
    return drv;
 }
 
 
-EGLBoolean
-_eglCloseDriver(_EGLDriver *drv, EGLDisplay dpy)
+/**
+ * Match a display to a preloaded driver.
+ */
+static _EGLDriver *
+_eglMatchDriver(_EGLDisplay *dpy)
 {
-   void *handle = drv->LibHandle;
-   EGLBoolean b;
+   _EGLDriver *defaultDriver = NULL;
+   EGLint i;
 
-   _eglLog(_EGL_DEBUG, "Closing %s", drv->Name);
+   for (i = 0; i < _eglGlobal.NumDrivers; i++) {
+      _EGLDriver *drv = _eglGlobal.Drivers[i];
 
-   /*
-    * XXX check for currently bound context/surfaces and delete them?
-    */
+      /* 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;
+      }
+   }
 
-   b = drv->API.Terminate(drv, dpy);
+   return defaultDriver;
+}
 
-   close_library(handle);
 
-   return b;
+/**
+ * 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(path, args);
+   if (!drv)
+      return NULL;
+
+   _eglGlobal.Drivers[_eglGlobal.NumDrivers++] = drv;
+
+   return drv->Name;
+}
+
+
+/**
+ * Open a preloaded driver.
+ */
+_EGLDriver *
+_eglOpenDriver(_EGLDisplay *dpy)
+{
+   _EGLDriver *drv = _eglMatchDriver(dpy);
+   return drv;
 }
 
 
 /**
- * Save the given driver pointer in the list of all known drivers.
+ * Close a preloaded driver.
+ */
+EGLBoolean
+_eglCloseDriver(_EGLDriver *drv, _EGLDisplay *dpy)
+{
+   return EGL_TRUE;
+}
+
+
+/**
+ * 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;
 }
 
 
@@ -375,6 +429,11 @@ _eglInitDriverFallbacks(_EGLDriver *drv)
 #ifdef EGL_VERSION_1_2
    drv->API.CreatePbufferFromClientBuffer = _eglCreatePbufferFromClientBuffer;
 #endif /* EGL_VERSION_1_2 */
+
+#ifdef EGL_KHR_image_base
+   drv->API.CreateImageKHR = _eglCreateImageKHR;
+   drv->API.DestroyImageKHR = _eglDestroyImageKHR;
+#endif /* EGL_KHR_image_base */
 }
 
 
@@ -399,6 +458,11 @@ _eglFindAPIs(void)
    const char *es2_libname = "libGLESv2.so";
    const char *gl_libname = "libGL.so";
    const char *vg_libname = "libOpenVG.so";
+#else /* _EGL_PLATFORM_NO_OS */
+   const char *es1_libname = NULL;
+   const char *es2_libname = NULL;
+   const char *gl_libname = NULL;
+   const char *vg_libname = NULL;
 #endif
 
    if ((lib = open_library(es1_libname))) {