implement a real loader for EGL drivers

we now look for a config file in /system/lib/egl/egl.cfg that describes the association of a display to a driver.
these drivers are named: /system/lib/egl/lib{[EGL|GLESv1_CM|GLESv2] | GLES}_$TAG.so
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
new file mode 100644
index 0000000..0e0f2c2
--- /dev/null
+++ b/opengl/libs/EGL/Loader.cpp
@@ -0,0 +1,278 @@
+/* 
+ ** Copyright 2007, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License"); 
+ ** you may not use this file except in compliance with the License. 
+ ** You may obtain a copy of the License at 
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0 
+ **
+ ** Unless required by applicable law or agreed to in writing, software 
+ ** distributed under the License is distributed on an "AS IS" BASIS, 
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ ** See the License for the specific language governing permissions and 
+ ** limitations under the License.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <limits.h>
+
+#include <cutils/log.h>
+
+#include <EGL/egl.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+#include "Loader.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+
+/*
+ * EGL drivers are called
+ * 
+ * /system/lib/egl/lib{[EGL|GLESv1_CM|GLESv2] | GLES}_$TAG.so 
+ * 
+ */
+
+ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
+
+// ----------------------------------------------------------------------------
+
+Loader::driver_t::driver_t(void* gles) 
+{
+    dso[0] = gles;
+    for (size_t i=1 ; i<NELEM(dso) ; i++)
+        dso[i] = 0;
+}
+
+Loader::driver_t::~driver_t() 
+{
+    for (size_t i=0 ; i<NELEM(dso) ; i++) {
+        if (dso[i]) {
+            dlclose(dso[i]);
+            dso[i] = 0;
+        }
+    }
+}
+
+status_t Loader::driver_t::set(void* hnd, int32_t api)
+{
+    switch (api) {
+        case EGL:
+            dso[0] = hnd;
+            break;
+        case GLESv1_CM:
+            dso[1] = hnd;
+            break;
+        case GLESv2:
+            dso[2] = hnd;
+            break;
+        default:
+            return BAD_INDEX;
+    }
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+Loader::entry_t::entry_t(int dpy, int impl, const char* tag)
+    : dpy(dpy), impl(impl), tag(tag) {
+}
+
+// ----------------------------------------------------------------------------
+
+Loader::Loader()
+{
+    char line[256];
+    char tag[256];
+    FILE* cfg = fopen("/system/lib/egl/egl.cfg", "r");
+    if (cfg == NULL) {
+        // default config
+        LOGD("egl.cfg not found, using default config");
+        gConfig.add( entry_t(0, 0, "android") );
+    } else {
+        while (fgets(line, 256, cfg)) {
+            int dpy;
+            int impl;
+            if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) {
+                LOGD(">>> %u %u %s", dpy, impl, tag);
+                gConfig.add( entry_t(dpy, impl, tag) );
+            }
+        }
+        fclose(cfg);
+    }
+}
+
+Loader::~Loader()
+{
+}
+
+const char* Loader::getTag(int dpy, int impl)
+{
+    const Vector<entry_t>& cfgs(gConfig);    
+    const size_t c = cfgs.size();
+    for (size_t i=0 ; i<c ; i++) {
+        if (dpy == cfgs[i].dpy)
+            if (impl == cfgs[i].impl)
+                return cfgs[i].tag.string();
+    }
+    return 0;
+}
+
+void* Loader::open(EGLNativeDisplayType display, int impl, gl_hooks_t* hooks)
+{
+    /*
+     * TODO: if we don't find display/0, then use 0/0
+     * (0/0 should always work)
+     */
+    
+    void* dso;
+    char path[PATH_MAX];
+    int index = int(display);
+    driver_t* hnd = 0;
+    const char* const format = "egl/lib%s_%s.so";
+    
+    char const* tag = getTag(index, impl);
+    if (tag) {
+        snprintf(path, PATH_MAX, format, "GLES", tag);
+        dso = load_driver(path, hooks, EGL | GLESv1_CM | GLESv2);
+        if (dso) {
+            hnd = new driver_t(dso);
+        } else {
+            // Always load EGL first
+            snprintf(path, PATH_MAX, "lib%s_%s.so", "EGL", tag);
+            dso = load_driver(path, hooks, EGL);
+            if (dso) {
+                hnd = new driver_t(dso);
+
+                // TODO: make this more automated
+                snprintf(path, PATH_MAX, format, "GLESv1_CM", tag);
+                hnd->set( load_driver(path, hooks, GLESv1_CM), GLESv1_CM );
+
+                snprintf(path, PATH_MAX, format, "GLESv2", tag);
+                hnd->set( load_driver(path, hooks, GLESv2), GLESv2 );
+            }
+        }
+    }
+
+    LOG_FATAL_IF(!index && !impl && !hnd, 
+            "couldn't't find the default OpenGL ES implementation "
+            "for default display");
+    
+    return (void*)hnd;
+}
+
+status_t Loader::close(void* driver)
+{
+    driver_t* hnd = (driver_t*)driver;
+    delete hnd;
+    return NO_ERROR;
+}
+
+void Loader::init_api(void* dso, 
+        char const * const * api, 
+        __eglMustCastToProperFunctionPointerType* curr, 
+        getProcAddressType getProcAddress) 
+{
+    char scrap[256];
+    while (*api) {
+        char const * name = *api;
+        __eglMustCastToProperFunctionPointerType f = 
+            (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
+        if (f == NULL) {
+            // couldn't find the entry-point, use eglGetProcAddress()
+            f = getProcAddress(name);
+        }
+        if (f == NULL) {
+            // Try without the OES postfix
+            ssize_t index = ssize_t(strlen(name)) - 3;
+            if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
+                strncpy(scrap, name, index);
+                scrap[index] = 0;
+                f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
+                //LOGD_IF(f, "found <%s> instead", scrap);
+            }
+        }
+        if (f == NULL) {
+            // Try with the OES postfix
+            ssize_t index = ssize_t(strlen(name)) - 3;
+            if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
+                strncpy(scrap, name, index);
+                scrap[index] = 0;
+                strcat(scrap, "OES");
+                f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
+                //LOGD_IF(f, "found <%s> instead", scrap);
+            }
+        }
+        if (f == NULL) {
+            //LOGD("%s", name);
+            f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
+        }
+        *curr++ = f;
+        api++;
+    }
+}
+
+void *Loader::load_driver(const char* driver, gl_hooks_t* hooks, uint32_t mask)
+{
+    //LOGD("%s", driver);
+    void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
+    LOGE_IF(!dso,
+            "couldn't load <%s> library (%s)",
+            driver, dlerror());
+    if (dso == 0)
+        return 0;
+
+    if (mask & EGL) {
+        getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
+
+        LOGE_IF(!getProcAddress, 
+                "can't find eglGetProcAddress() in %s", driver);        
+
+        gl_hooks_t::egl_t* egl = &hooks->egl;
+        __eglMustCastToProperFunctionPointerType* curr =
+            (__eglMustCastToProperFunctionPointerType*)egl;
+        char const * const * api = egl_names;
+        while (*api) {
+            char const * name = *api;
+            __eglMustCastToProperFunctionPointerType f = 
+                (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
+            if (f == NULL) {
+                // couldn't find the entry-point, use eglGetProcAddress()
+                f = getProcAddress(name);
+                if (f == NULL) {
+                    f = (__eglMustCastToProperFunctionPointerType)0;
+                }
+            }
+            *curr++ = f;
+            api++;
+        }
+    }
+    
+    if (mask & GLESv1_CM) {
+        init_api(dso, gl_names,  
+                (__eglMustCastToProperFunctionPointerType*)&hooks->gl, 
+                getProcAddress);
+    }
+
+    if (mask & GLESv2) {
+      init_api(dso, gl2_names, 
+            (__eglMustCastToProperFunctionPointerType*)&hooks->gl2, 
+            getProcAddress);
+    }
+    
+    return dso;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
new file mode 100644
index 0000000..69f6dd5
--- /dev/null
+++ b/opengl/libs/EGL/Loader.h
@@ -0,0 +1,90 @@
+/* 
+ ** Copyright 2009, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License"); 
+ ** you may not use this file except in compliance with the License. 
+ ** You may obtain a copy of the License at 
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0 
+ **
+ ** Unless required by applicable law or agreed to in writing, software 
+ ** distributed under the License is distributed on an "AS IS" BASIS, 
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ ** See the License for the specific language governing permissions and 
+ ** limitations under the License.
+ */
+
+#ifndef ANDROID_EGL_LOADER_H
+#define ANDROID_EGL_LOADER_H
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <EGL/egl.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+struct gl_hooks_t;
+
+class Loader : public Singleton<Loader>
+{
+    friend class Singleton<Loader>;
+
+    typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
+            const char*);
+   
+    enum {
+        EGL         = 0x01,
+        GLESv1_CM   = 0x02,
+        GLESv2      = 0x04
+    };
+    struct driver_t {
+        driver_t(void* gles);
+        ~driver_t();
+        status_t set(void* hnd, int32_t api);
+        void* dso[3];
+    };
+    
+    struct entry_t {
+        entry_t() { }
+        entry_t(int dpy, int impl, const char* tag);
+        int dpy;
+        int impl;
+        String8 tag;
+    };
+
+    Vector<entry_t> gConfig;    
+    getProcAddressType getProcAddress;
+    
+    const char* getTag(int dpy, int impl);
+
+public:
+    ~Loader();
+    
+    void* open(EGLNativeDisplayType display, int impl, gl_hooks_t* hooks);
+    status_t close(void* driver);
+    
+private:
+    Loader();
+    void *load_driver(const char* driver, gl_hooks_t* hooks, uint32_t mask);
+
+    static __attribute__((noinline))
+    void init_api(void* dso, 
+            char const * const * api, 
+            __eglMustCastToProperFunctionPointerType* curr, 
+            getProcAddressType getProcAddress); 
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_EGL_LOADER_H */
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 4eae98e..77648f2 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -38,7 +38,7 @@
 
 #include "hooks.h"
 #include "egl_impl.h"
-
+#include "Loader.h"
 
 #define MAKE_CONFIG(_impl, _index)  ((EGLConfig)(((_impl)<<24) | (_index)))
 #define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
@@ -139,38 +139,6 @@
     EGLContext  ctx;
 };
 
-static void gl_unimplemented() {
-    LOGE("called unimplemented OpenGL ES API");
-}
-
-// ----------------------------------------------------------------------------
-// GL / EGL hooks
-// ----------------------------------------------------------------------------
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
-#define GL_ENTRY(_r, _api, ...) #_api,
-#define EGL_ENTRY(_r, _api, ...) #_api,
-
-static char const * const gl_names[] = {
-    #include "GLES_CM/gl_entries.in"
-    #include "GLES_CM/glext_entries.in"
-    NULL
-};
-
-static char const * const gl2_names[] = {
-    #include "GLES2/gl2_entries.in"
-    #include "GLES2/gl2ext_entries.in"
-    NULL
-};
-
-static char const * const egl_names[] = {
-    #include "egl_entries.in"
-    NULL
-};
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
 
 // ----------------------------------------------------------------------------
 
@@ -281,105 +249,6 @@
 
 /*****************************************************************************/
 
-typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
-        const char*);
-
-static __attribute__((noinline))
-void init_api(void* dso, 
-        char const * const * api, 
-        __eglMustCastToProperFunctionPointerType* curr, 
-        getProcAddressType getProcAddress) 
-{
-    char scrap[256];
-    while (*api) {
-        char const * name = *api;
-        __eglMustCastToProperFunctionPointerType f = 
-            (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
-        if (f == NULL) {
-            // couldn't find the entry-point, use eglGetProcAddress()
-            f = getProcAddress(name);
-        }
-        if (f == NULL) {
-            // Try without the OES postfix
-            ssize_t index = ssize_t(strlen(name)) - 3;
-            if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
-                strncpy(scrap, name, index);
-                scrap[index] = 0;
-                f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
-                //LOGD_IF(f, "found <%s> instead", scrap);
-            }
-        }
-        if (f == NULL) {
-            // Try with the OES postfix
-            ssize_t index = ssize_t(strlen(name)) - 3;
-            if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
-                strncpy(scrap, name, index);
-                scrap[index] = 0;
-                strcat(scrap, "OES");
-                f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
-                //LOGD_IF(f, "found <%s> instead", scrap);
-            }
-        }
-        if (f == NULL) {
-            //LOGD("%s", name);
-            f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
-        }
-        *curr++ = f;
-        api++;
-    }
-}
-
-static __attribute__((noinline))
-void *load_driver(const char* driver, gl_hooks_t* hooks)
-{
-    //LOGD("%s", driver);
-    void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
-    LOGE_IF(!dso,
-            "couldn't load <%s> library (%s)",
-            driver, dlerror());
-
-    if (dso) {
-        // first find the symbol for eglGetProcAddress
-        
-        typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
-                const char*);
-        
-        getProcAddressType getProcAddress = 
-            (getProcAddressType)dlsym(dso, "eglGetProcAddress");
-        
-        LOGE_IF(!getProcAddress, 
-                "can't find eglGetProcAddress() in %s", driver);        
-
-        gl_hooks_t::egl_t* egl = &hooks->egl;
-        __eglMustCastToProperFunctionPointerType* curr =
-                (__eglMustCastToProperFunctionPointerType*)egl;
-        char const * const * api = egl_names;
-        while (*api) {
-            char const * name = *api;
-            __eglMustCastToProperFunctionPointerType f = 
-                (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
-            if (f == NULL) {
-                // couldn't find the entry-point, use eglGetProcAddress()
-                f = getProcAddress(name);
-                if (f == NULL) {
-                    f = (__eglMustCastToProperFunctionPointerType)0;
-                }
-            }
-            *curr++ = f;
-            api++;
-        }
-        
-        init_api(dso, gl_names,  
-                (__eglMustCastToProperFunctionPointerType*)&hooks->gl, 
-                getProcAddress);
-        
-        init_api(dso, gl2_names, 
-                (__eglMustCastToProperFunctionPointerType*)&hooks->gl2, 
-                getProcAddress);
-    }
-    return dso;
-}
-
 template<typename T>
 static __attribute__((noinline))
 int binarySearch(
@@ -605,12 +474,15 @@
     EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
     egl_display_t* d = &gDisplay[index];
 
+    // get our driver loader
+    Loader& loader(Loader::getInstance());    
+    
     // dynamically load all our EGL implementations for that display
     // and call into the real eglGetGisplay()
     egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
     if (cnx->dso == 0) {
         cnx->hooks = &gHooks[IMPL_SOFTWARE];
-        cnx->dso = load_driver("libagl.so", cnx->hooks);
+        cnx->dso = loader.open(display, 0, cnx->hooks);
     }
     if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
         d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
@@ -624,7 +496,7 @@
         property_get("debug.egl.hw", value, "1");
         if (atoi(value) != 0) {
             cnx->hooks = &gHooks[IMPL_HARDWARE];
-            cnx->dso = load_driver("libhgl2.so", cnx->hooks);
+            cnx->dso = loader.open(display, 1, cnx->hooks);
         } else {
             LOGD("3D hardware acceleration is disabled");
         }
@@ -656,7 +528,8 @@
         if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
             LOGE("h/w accelerated eglGetDisplay() failed (%s)",
                     egl_strerror(cnx->hooks->egl.eglGetError()));
-            dlclose((void*)cnx->dso);
+            
+            loader.close(cnx->dso);
             cnx->dso = 0;
             // in case of failure, we want to make sure we don't try again
             // as it's expensive.
@@ -768,6 +641,8 @@
     if (android_atomic_dec(&dp->refs) != 1)
         return EGL_TRUE;
         
+    Loader& loader(Loader::getInstance());    
+
     EGLBoolean res = EGL_FALSE;
     for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
@@ -783,7 +658,8 @@
             free((void*)dp->queryString[i].extensions);
             dp->numConfigs[i] = 0;
             dp->dpys[i] = EGL_NO_DISPLAY;
-            dlclose((void*)cnx->dso);
+
+            loader.close(cnx->dso);
             cnx->dso = 0;
             res = EGL_TRUE;
         }
diff --git a/opengl/libs/EGL/hooks.cpp b/opengl/libs/EGL/hooks.cpp
new file mode 100644
index 0000000..2246366
--- /dev/null
+++ b/opengl/libs/EGL/hooks.cpp
@@ -0,0 +1,67 @@
+/* 
+ ** Copyright 2009, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License"); 
+ ** you may not use this file except in compliance with the License. 
+ ** You may obtain a copy of the License at 
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0 
+ **
+ ** Unless required by applicable law or agreed to in writing, software 
+ ** distributed under the License is distributed on an "AS IS" BASIS, 
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ ** See the License for the specific language governing permissions and 
+ ** limitations under the License.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+void gl_unimplemented() {
+    LOGE("called unimplemented OpenGL ES API");
+}
+
+
+// ----------------------------------------------------------------------------
+// GL / EGL hooks
+// ----------------------------------------------------------------------------
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) #_api,
+#define EGL_ENTRY(_r, _api, ...) #_api,
+
+char const * const gl_names[] = {
+    #include "GLES_CM/gl_entries.in"
+    #include "GLES_CM/glext_entries.in"
+    NULL
+};
+
+char const * const gl2_names[] = {
+    #include "GLES2/gl2_entries.in"
+    #include "GLES2/gl2ext_entries.in"
+    NULL
+};
+
+char const * const egl_names[] = {
+    #include "egl_entries.in"
+    NULL
+};
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+