#include <assert.h>
#include <string.h>
-#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include "eglconfig.h"
#include "eglscreen.h"
#include "eglstring.h"
#include "eglsurface.h"
+#include "eglimage.h"
#if defined(_EGL_PLATFORM_X)
-#include "eglx.h"
+#include <dlfcn.h>
#elif defined(_EGL_PLATFORM_WINDOWS)
-/* XXX to do */
-#elif defined(_EGL_PLATFORM_WINCE)
-/* XXX to do */
+/* Use static linking on Windows for now */
+#define WINDOWS_STATIC_LINK
#endif
-
-static const char *DefaultDriverName = ":0";
-static const char *SysFS = "/sys/class";
-
-
-
-
/**
- * Given a card number, use sysfs to determine the DRI driver name.
+ * Wrappers for dlopen/dlclose()
*/
-const char *
-_eglChooseDRMDriver(int card)
-{
-#if 0
- return _eglstrdup("libEGLdri");
+#if defined(_EGL_PLATFORM_WINDOWS)
+#ifdef WINDOWS_STATIC_LINK
+ static const char *DefaultDriverName = "Windows EGL Static Library";
#else
- char path[2000], driverName[2000];
- FILE *f;
- int length;
+ /* XXX Need to decide how to do dynamic name lookup on Windows */
+ static const char *DefaultDriverName = "TBD";
+#endif
+ typedef HMODULE lib_handle;
- snprintf(path, sizeof(path), "%s/drm/card%d/dri_library_name", SysFS, card);
+ static HMODULE
+ open_library(const char *filename)
+ {
+#ifdef WINDOWS_STATIC_LINK
+ return 0;
+#else
+ return LoadLibrary(filename);
+#endif
+ }
- f = fopen(path, "r");
- if (!f)
- return NULL;
+ static void
+ close_library(HMODULE lib)
+ {
+#ifdef WINDOWS_STATIC_LINK
+#else
+ FreeLibrary(lib);
+#endif
+ }
+
+#elif defined(_EGL_PLATFORM_X)
+ static const char *DefaultDriverName = "egl_softpipe";
- fgets(driverName, sizeof(driverName), f);
- fclose(f);
+ typedef void * lib_handle;
- if ((length = strlen(driverName)) > 1) {
- /* remove the trailing newline from sysfs */
- driverName[length - 1] = '\0';
- strncat(driverName, "_dri", sizeof(driverName));
- return _eglstrdup(driverName);
+ static void *
+ open_library(const char *filename)
+ {
+ return dlopen(filename, RTLD_LAZY);
}
- else {
- return NULL;
- }
+
+ static void
+ close_library(void *lib)
+ {
+ dlclose(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)
{
- const char *displayString = (const char *) dpy->NativeDisplay;
- 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);
- /* First, if the EGL_DRIVER env var is set, use that */
- driverName = getenv("EGL_DRIVER");
- if (driverName)
- return _eglstrdup(driverName);
-
-#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);
- }
-
- /* 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;
- }
- }
- }
- else {
- /* NativeDisplay is not a string! */
#if defined(_EGL_PLATFORM_X)
- driverName = _xeglChooseDriver(dpy);
+ if (!path && dpy->NativeDisplay) {
+ /* assume (wrongly!) that the native display is a display string */
+ path = _eglSplitDisplayString((const char *) dpy->NativeDisplay, &args);
+ }
+ suffix = "so";
#elif defined(_EGL_PLATFORM_WINDOWS)
- /* XXX to do */
- driverName = _weglChooseDriver(dpy);
-#elif defined(_EGL_PLATFORM_WINCE)
- /* XXX to do */
-#else
- driverName = DefaultDriverName;
-#endif
+ suffix = "dll";
+#endif /* _EGL_PLATFORM_X */
+
+ 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;
+ }
}
- 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;
- void *lib;
- char driverFilename[1000];
+ lib_handle lib;
- assert(driverName);
+ assert(driverPath);
- /* XXX also prepend a directory path??? */
- sprintf(driverFilename, "%s.so", driverName);
-
- _eglLog(_EGL_DEBUG, "dlopen(%s)", driverFilename);
- lib = dlopen(driverFilename, RTLD_NOW);
+#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 */
+ _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
+ lib = open_library(driverPath);
+ if (!lib) {
+ _eglLog(_EGL_WARNING, "Could not open %s",
+ driverPath);
+ return NULL;
+ }
+ mainFunc = (_EGLMain_t) GetProcAddress(lib, "_eglMain");
+#endif
+#elif defined(_EGL_PLATFORM_X)
+ _eglLog(_EGL_DEBUG, "dlopen(%s)", driverPath);
+ lib = open_library(driverPath);
if (!lib) {
_eglLog(_EGL_WARNING, "Could not open %s (%s)",
- driverFilename, dlerror());
+ driverPath, dlerror());
+ 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);
- dlclose(lib);
+ _eglLog(_EGL_WARNING, "_eglMain not found in %s", driverPath);
+ 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) {
- dlclose(lib);
+ if (lib)
+ close_library(lib);
return NULL;
}
- /* with a recurvise open you want the inner most handle */
- if (!drv->LibHandle)
- drv->LibHandle = lib;
- else
- dlclose(lib);
- /* update the global notion of supported APIs */
- _eglGlobal.ClientAPIsMask |= drv->ClientAPIsMask;
+ if (!drv->Name) {
+ _eglLog(_EGL_WARNING, "Driver loaded from %s has no name", path);
+ drv->Name = "UNNAMED";
+ }
- _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);
- dlclose(handle);
- return b;
+ return defaultDriver;
}
/**
- * Save the given driver pointer in the list of all known drivers.
+ * 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;
+}
+
+
+/**
+ * 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;
}
#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 */
+}
+
+
+
+/**
+ * Try to determine which EGL APIs (OpenGL, OpenGL ES, OpenVG, etc)
+ * are supported on the system by looking for standard library names.
+ */
+EGLint
+_eglFindAPIs(void)
+{
+ EGLint mask = 0x0;
+ lib_handle lib;
+#if defined(_EGL_PLATFORM_WINDOWS)
+ /* XXX not sure about these names */
+ const char *es1_libname = "libGLESv1_CM.dll";
+ const char *es2_libname = "libGLESv2.dll";
+ const char *gl_libname = "OpenGL32.dll";
+ const char *vg_libname = "libOpenVG.dll";
+#elif defined(_EGL_PLATFORM_X)
+ const char *es1_libname = "libGLESv1_CM.so";
+ const char *es2_libname = "libGLESv2.so";
+ const char *gl_libname = "libGL.so";
+ const char *vg_libname = "libOpenVG.so";
+#endif
+
+ if ((lib = open_library(es1_libname))) {
+ close_library(lib);
+ mask |= EGL_OPENGL_ES_BIT;
+ }
+
+ if ((lib = open_library(es2_libname))) {
+ close_library(lib);
+ mask |= EGL_OPENGL_ES2_BIT;
+ }
+
+ if ((lib = open_library(gl_libname))) {
+ close_library(lib);
+ mask |= EGL_OPENGL_BIT;
+ }
+
+ if ((lib = open_library(vg_libname))) {
+ close_library(lib);
+ mask |= EGL_OPENVG_BIT;
+ }
+
+ return mask;
}