eclair snapshot
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
new file mode 100644
index 0000000..5d6ac26
--- /dev/null
+++ b/opengl/libs/EGL/Loader.cpp
@@ -0,0 +1,287 @@
+/* 
+ ** 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, egl_connection_t* cnx)
+{
+    /*
+     * 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 = "/system/lib/egl/lib%s_%s.so";
+    
+    char const* tag = getTag(index, impl);
+    if (tag) {
+        snprintf(path, PATH_MAX, format, "GLES", tag);
+        dso = load_driver(path, cnx, EGL | GLESv1_CM | GLESv2);
+        if (dso) {
+            hnd = new driver_t(dso);
+        } else {
+            // Always load EGL first
+            snprintf(path, PATH_MAX, format, "EGL", tag);
+            dso = load_driver(path, cnx, 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, cnx, GLESv1_CM), GLESv1_CM );
+
+                snprintf(path, PATH_MAX, format, "GLESv2", tag);
+                hnd->set( load_driver(path, cnx, GLESv2), GLESv2 );
+            }
+        }
+    }
+
+    LOG_FATAL_IF(!index && !impl && !hnd, 
+            "couldn'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_absolute_path,
+        egl_connection_t* cnx, uint32_t mask)
+{
+    if (access(driver_absolute_path, R_OK)) {
+        // this happens often, we don't want to log an error
+        return 0;
+    }
+
+    void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
+    if (dso == 0) {
+        const char* err = dlerror();
+        LOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
+        return 0;
+    }
+
+    LOGD("loaded %s", driver_absolute_path);
+
+    if (mask & EGL) {
+        getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
+
+        LOGE_IF(!getProcAddress, 
+                "can't find eglGetProcAddress() in %s", driver_absolute_path);
+
+        egl_t* egl = &cnx->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*)
+                &cnx->hooks[GLESv1_INDEX]->gl,
+            getProcAddress);
+    }
+
+    if (mask & GLESv2) {
+      init_api(dso, gl_names,
+            (__eglMustCastToProperFunctionPointerType*)
+                &cnx->hooks[GLESv2_INDEX]->gl,
+            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..8659b0b
--- /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 egl_connection_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, egl_connection_t* cnx);
+    status_t close(void* driver);
+    
+private:
+    Loader();
+    void *load_driver(const char* driver, egl_connection_t* cnx, 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 c6e0f50..c22c21b 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -14,9 +14,8 @@
  ** limitations under the License.
  */
 
-#define LOG_TAG "libEGL"
-
 #include <ctype.h>
+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <dlfcn.h>
@@ -37,11 +36,11 @@
 #include <cutils/properties.h>
 #include <cutils/memory.h>
 
-#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
 
 #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)
@@ -53,64 +52,152 @@
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 4
 static char const * const gVendorString     = "Android";
-static char const * const gVersionString    = "1.31 Android META-EGL";
+static char const * const gVersionString    = "1.4 Android META-EGL";
 static char const * const gClientApiString  = "OpenGL ES";
-static char const * const gExtensionString  = "";
+static char const * const gExtensionString  = 
+        "EGL_KHR_image "
+        "EGL_KHR_image_base "
+        "EGL_KHR_image_pixmap "
+        "EGL_ANDROID_image_native_buffer "
+        "EGL_ANDROID_swap_rectangle "
+        "EGL_ANDROID_get_render_buffer "
+        ;
 
-template <int MAGIC>
-struct egl_object_t
-{
-    egl_object_t() : magic(MAGIC) { }
-    ~egl_object_t() { magic = 0; }
-    bool isValid() const { return magic == MAGIC; }
+// ----------------------------------------------------------------------------
+
+class egl_object_t {
+    static SortedVector<egl_object_t*> sObjects;
+    static Mutex sLock;
+
+            volatile int32_t  terminated;
+    mutable volatile int32_t  count;
+
+public:
+    egl_object_t() : terminated(0), count(1) { 
+        Mutex::Autolock _l(sLock);
+        sObjects.add(this);
+    }
+
+    inline bool isAlive() const { return !terminated; }
+
 private:
-    uint32_t    magic;
+    bool get() {
+        Mutex::Autolock _l(sLock);
+        if (egl_object_t::sObjects.indexOf(this) >= 0) {
+            android_atomic_inc(&count);
+            return true;
+        }
+        return false;
+    }
+
+    bool put() {
+        Mutex::Autolock _l(sLock);
+        if (android_atomic_dec(&count) == 1) {
+            sObjects.remove(this);
+            return true;
+        }
+        return false;
+    }    
+
+public:
+    template <typename N, typename T>
+    struct LocalRef {
+        N* ref;
+        LocalRef(T o) : ref(0) {
+            N* native = reinterpret_cast<N*>(o);
+            if (o && native->get()) {
+                ref = native;
+            }
+        }
+        ~LocalRef() { 
+            if (ref && ref->put()) {
+                delete ref;
+            }
+        }
+        inline N* get() {
+            return ref;
+        }
+        void acquire() const {
+            if (ref) {
+                android_atomic_inc(&ref->count);
+            }
+        }
+        void release() const {
+            if (ref) {
+                int32_t c = android_atomic_dec(&ref->count);
+                // ref->count cannot be 1 prior atomic_dec because we have
+                // a reference, and if we have one, it means there was
+                // already one before us.
+                LOGE_IF(c==1, "refcount is now 0 in release()");
+            }
+        }
+        void terminate() {
+            if (ref) {
+                ref->terminated = 1;
+                release();
+            }
+        }
+    };
 };
 
-struct egl_display_t : public egl_object_t<'_dpy'>
-{
-    EGLDisplay  dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
-    EGLConfig*  configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
-    EGLint      numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
-    EGLint      numTotalConfigs;
-    char const* extensionsString;
-    volatile int32_t refs;
+SortedVector<egl_object_t*> egl_object_t::sObjects;
+Mutex egl_object_t::sLock;
+
+struct egl_display_t {
+    enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
+    
     struct strings_t {
         char const * vendor;
         char const * version;
         char const * clientApi;
         char const * extensions;
     };
-    strings_t   queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+
+    struct DisplayImpl {
+        DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
+                        state(NOT_INITIALIZED), numConfigs(0) { }
+        EGLDisplay  dpy;
+        EGLConfig*  config;
+        EGLint      state;
+        EGLint      numConfigs;
+        strings_t   queryString;
+    };
+
+    uint32_t    magic;
+    DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
+    EGLint      numTotalConfigs;
+    volatile int32_t refs;
+    
+    egl_display_t() : magic('_dpy'), numTotalConfigs(0) { }
+    ~egl_display_t() { magic = 0; }
+    inline bool isValid() const { return magic == '_dpy'; }
+    inline bool isAlive() const { return isValid(); }
 };
 
-struct egl_surface_t : public egl_object_t<'_srf'>
+struct egl_surface_t : public egl_object_t
 {
+    typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
+
     egl_surface_t(EGLDisplay dpy, EGLSurface surface,
-            NativeWindowType window, int impl, egl_connection_t const* cnx) 
-    : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
-    {
-        // NOTE: window must be incRef'ed and connected already
+            int impl, egl_connection_t const* cnx) 
+    : dpy(dpy), surface(surface), impl(impl), cnx(cnx) {
     }
     ~egl_surface_t() {
-        if (window) {
-            if (window->disconnect)
-                window->disconnect(window);
-            window->decRef(window);
-        }
     }
     EGLDisplay                  dpy;
     EGLSurface                  surface;
-    NativeWindowType            window;
     int                         impl;
     egl_connection_t const*     cnx;
 };
 
-struct egl_context_t : public egl_object_t<'_ctx'>
+struct egl_context_t : public egl_object_t
 {
+    typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
+    
     egl_context_t(EGLDisplay dpy, EGLContext context,
-            int impl, egl_connection_t const* cnx) 
-    : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
+            int impl, egl_connection_t const* cnx, int version) 
+    : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx),
+      version(version)
     {
     }
     EGLDisplay                  dpy;
@@ -119,52 +206,47 @@
     EGLSurface                  draw;
     int                         impl;
     egl_connection_t const*     cnx;
+    int                         version;
 };
 
+struct egl_image_t : public egl_object_t
+{
+    typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
+
+    egl_image_t(EGLDisplay dpy, EGLContext context)
+        : dpy(dpy), context(context)
+    {
+        memset(images, 0, sizeof(images));
+    }
+    EGLDisplay dpy;
+    EGLConfig context;
+    EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
+};
+
+typedef egl_surface_t::Ref  SurfaceRef;
+typedef egl_context_t::Ref  ContextRef;
+typedef egl_image_t::Ref    ImageRef;
+
 struct tls_t
 {
-    tls_t() : error(EGL_SUCCESS), ctx(0) { }
+    tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
     EGLint      error;
     EGLContext  ctx;
+    EGLBoolean  logCallWithNoContext;
 };
 
-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 "gl_entries.in"
-    #include "glext_entries.in"
-    NULL
-};
-
-static char const * const egl_names[] = {
-    #include "egl_entries.in"
-    NULL
-};
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
 
 // ----------------------------------------------------------------------------
 
-egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
 static egl_display_t gDisplay[NUM_DISPLAYS];
 static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_key_t gEGLThreadLocalStorageKey = -1;
 
 // ----------------------------------------------------------------------------
 
-EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
+EGLAPI gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+EGLAPI gl_hooks_t gHooksNoContext;
 EGLAPI pthread_key_t gGLWrapperKey = -1;
 
 // ----------------------------------------------------------------------------
@@ -262,110 +344,8 @@
     return tls->ctx;
 }
 
-
 /*****************************************************************************/
 
-class ISurfaceComposer;
-const sp<ISurfaceComposer>& getSurfaceFlinger();
-request_gpu_t* gpu_acquire(void* user);
-int gpu_release(void*, request_gpu_t* gpu);
-
-static __attribute__((noinline))
-void *load_driver(const char* driver, gl_hooks_t* hooks)
-{
-    //LOGD("%s", driver);
-    char scrap[256];
-    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);        
-        
-        __eglMustCastToProperFunctionPointerType* curr;
-        char const * const * api;
-
-        gl_hooks_t::egl_t* egl = &hooks->egl;
-        curr = (__eglMustCastToProperFunctionPointerType*)egl;
-        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++;
-        }
-
-        gl_hooks_t::gl_t* gl = &hooks->gl;
-        curr = (__eglMustCastToProperFunctionPointerType*)gl;
-        api = gl_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) {
-                // 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++;
-        }
-
-        // hook this driver up with surfaceflinger if needed
-        register_gpu_t register_gpu = 
-            (register_gpu_t)dlsym(dso, "oem_register_gpu");
-
-        if (register_gpu != NULL) {
-            if (getSurfaceFlinger() != 0) {
-                register_gpu(dso, gpu_acquire, gpu_release);
-            }
-        }
-    }
-    return dso;
-}
-
 template<typename T>
 static __attribute__((noinline))
 int binarySearch(
@@ -387,14 +367,14 @@
 static EGLint configToUniqueId(egl_display_t const* dp, int i, int index) 
 {
     // NOTE: this mapping works only if we have no more than two EGLimpl
-    return (i>0 ? dp->numConfigs[0] : 0) + index;
+    return (i>0 ? dp->disp[0].numConfigs : 0) + index;
 }
 
 static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
         int& i, int& index) 
 {
     // NOTE: this mapping works only if we have no more than two EGLimpl
-    size_t numConfigs = dp->numConfigs[0];
+    size_t numConfigs = dp->disp[0].numConfigs;
     i = configId / numConfigs;
     index = configId % numConfigs;
 }
@@ -412,6 +392,18 @@
 };
 
 static const extention_map_t gExtentionMap[] = {
+    { "eglLockSurfaceKHR",  
+            (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR }, 
+    { "eglUnlockSurfaceKHR", 
+            (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR }, 
+    { "eglCreateImageKHR",  
+            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, 
+    { "eglDestroyImageKHR", 
+            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, 
+    { "eglSetSwapRectangleANDROID", 
+            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID }, 
+    { "eglGetRenderBufferANDROID", 
+            (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID }, 
 };
 
 static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
@@ -429,29 +421,15 @@
 
 // ----------------------------------------------------------------------------
 
-static int gl_context_lost() {
-    setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
-    return 0;
-}
-static int egl_context_lost() {
-    setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
-    return EGL_FALSE;
-}
-static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
-    usleep(100000); // don't use all the CPU
-    setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
-    return EGL_FALSE;
-}
-static GLint egl_context_lost_get_error() {
-    return EGL_CONTEXT_LOST;
-}
-static int ext_context_lost() {
-    return 0;
+static void gl_no_context() {
+    tls_t* tls = getTLS();
+    if (tls->logCallWithNoContext == EGL_TRUE) {
+        tls->logCallWithNoContext = EGL_FALSE;
+        LOGE("call to OpenGL ES API with no current context "
+             "(logged once per thread)");
+    }
 }
 
-static void gl_no_context() {
-    LOGE("call to OpenGL ES API with no current context");
-}
 static void early_egl_init(void) 
 {
 #if !USE_FAST_TLS_KEY
@@ -459,10 +437,10 @@
 #endif
     uint32_t addr = (uint32_t)((void*)gl_no_context);
     android_memset32(
-            (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT], 
+            (uint32_t*)(void*)&gHooksNoContext, 
             addr, 
-            sizeof(gHooks[IMPL_NO_CONTEXT]));
-    setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+            sizeof(gHooksNoContext));
+    setGlThreadSpecific(&gHooksNoContext);
 }
 
 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
@@ -491,6 +469,11 @@
     return egl_to_native_cast<egl_context_t>(context);
 }
 
+static inline
+egl_image_t* get_image(EGLImageKHR image) {
+    return egl_to_native_cast<egl_image_t>(image);
+}
+
 static egl_connection_t* validate_display_config(
         EGLDisplay dpy, EGLConfig config,
         egl_display_t const*& dp, int& impl, int& index)
@@ -499,11 +482,11 @@
     if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
 
     impl = uintptr_t(config)>>24;
-    if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
+    if (uint32_t(impl) >= IMPL_NUM_IMPLEMENTATIONS) {
         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
     } 
     index = uintptr_t(config) & 0xFFFFFF;
-    if (index >= dp->numConfigs[impl]) {
+    if (index >= dp->disp[impl].numConfigs) {
         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
     }
     egl_connection_t* const cnx = &gEGLImpl[impl];
@@ -517,11 +500,9 @@
 {
     if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (!get_display(dpy)->isValid())
+    if (!get_display(dpy)->isAlive())
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (!ctx) // TODO: make sure context is a valid object
-        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-    if (!get_context(ctx)->isValid())
+    if (!get_context(ctx)->isAlive())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
     return EGL_TRUE;
 }
@@ -530,92 +511,108 @@
 {
     if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (!get_display(dpy)->isValid())
+    if (!get_display(dpy)->isAlive())
         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (!surface) // TODO: make sure surface is a valid object
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-    if (!get_surface(surface)->isValid())
+    if (!get_surface(surface)->isAlive())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
     return EGL_TRUE;
 }
 
+EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
+{
+    ImageRef _i(image);
+    if (!_i.get()) return EGL_NO_IMAGE_KHR;
+    
+    EGLContext context = getContext();
+    if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
+        return EGL_NO_IMAGE_KHR;
+    
+    egl_context_t const * const c = get_context(context);
+    if (!c->isAlive())
+        return EGL_NO_IMAGE_KHR;
 
-EGLDisplay egl_init_displays(NativeDisplayType display)
+    egl_image_t const * const i = get_image(image);
+    return i->images[c->impl];
+}
+
+// ----------------------------------------------------------------------------
+
+// this mutex protects:
+//    d->disp[]
+//    egl_init_drivers_locked()
+//
+static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
+
+EGLBoolean egl_init_drivers_locked()
 {
     if (sEarlyInitState) {
-        return EGL_NO_DISPLAY;
+        // initialized by static ctor. should be set here.
+        return EGL_FALSE;
     }
 
-    uint32_t index = uint32_t(display);
-    if (index >= NUM_DISPLAYS) {
-        return EGL_NO_DISPLAY;
-    }
+    // get our driver loader
+    Loader& loader(Loader::getInstance());
     
-    EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
-    egl_display_t* d = &gDisplay[index];
+    // dynamically load all our EGL implementations for all displays
+    // and retrieve the corresponding EGLDisplay
+    // if that fails, don't use this driver.
+    // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
+    egl_connection_t* cnx;
+    egl_display_t* d = &gDisplay[0];
 
-    // dynamically load all our EGL implementations for that display
-    // and call into the real eglGetGisplay()
-    egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
+    cnx = &gEGLImpl[IMPL_SOFTWARE];
     if (cnx->dso == 0) {
-        cnx->hooks = &gHooks[IMPL_SOFTWARE];
-        cnx->dso = load_driver("libagl.so", cnx->hooks);
-    }
-    if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
-        d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
-        LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
-                "No EGLDisplay for software EGL!");
+        cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
+        cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
+        cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
+        if (cnx->dso) {
+            EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+            LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
+            d->disp[IMPL_SOFTWARE].dpy = dpy; 
+            if (dpy == EGL_NO_DISPLAY) {
+                loader.close(cnx->dso);
+                cnx->dso = NULL;
+            }
+        }
     }
 
     cnx = &gEGLImpl[IMPL_HARDWARE];
-    if (cnx->dso == 0 && cnx->unavailable == 0) {
+    if (cnx->dso == 0) {
         char value[PROPERTY_VALUE_MAX];
         property_get("debug.egl.hw", value, "1");
         if (atoi(value) != 0) {
-            cnx->hooks = &gHooks[IMPL_HARDWARE];
-            cnx->dso = load_driver("libhgl.so", cnx->hooks);
+            cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
+            cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
+            cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
+            if (cnx->dso) {
+                EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+                LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
+                d->disp[IMPL_HARDWARE].dpy = dpy; 
+                if (dpy == EGL_NO_DISPLAY) {
+                    loader.close(cnx->dso);
+                    cnx->dso = NULL;
+                }
+            }
         } else {
             LOGD("3D hardware acceleration is disabled");
         }
     }
-    if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
-        android_memset32(
-                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
-                (uint32_t)((void*)gl_context_lost),
-                sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
-        android_memset32(
-                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
-                (uint32_t)((void*)egl_context_lost),
-                sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
-        android_memset32(
-                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
-                (uint32_t)((void*)ext_context_lost),
-                sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
 
-        gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
-                egl_context_lost_swap_buffers;
-        
-        gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
-                egl_context_lost_get_error;
-
-        gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
-                gHooks[IMPL_HARDWARE].egl.eglTerminate;
-        
-        d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
-        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);
-            cnx->dso = 0;
-            // in case of failure, we want to make sure we don't try again
-            // as it's expensive.
-            cnx->unavailable = 1;
-        }
+    if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
+        return EGL_FALSE;
     }
 
-    return dpy;
+    return EGL_TRUE;
 }
 
+EGLBoolean egl_init_drivers()
+{
+    EGLBoolean res;
+    pthread_mutex_lock(&gInitDriverMutex);
+    res = egl_init_drivers_locked();
+    pthread_mutex_unlock(&gInitDriverMutex);
+    return res;
+}
 
 // ----------------------------------------------------------------------------
 }; // namespace android
@@ -625,7 +622,17 @@
 
 EGLDisplay eglGetDisplay(NativeDisplayType display)
 {
-    return egl_init_displays(display);
+    uint32_t index = uint32_t(display);
+    if (index >= NUM_DISPLAYS) {
+        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+    }
+
+    if (egl_init_drivers() == EGL_FALSE) {
+        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+    }
+    
+    EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
+    return dpy;
 }
 
 // ----------------------------------------------------------------------------
@@ -643,55 +650,73 @@
         return EGL_TRUE;
     }
     
-    setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+    setGlThreadSpecific(&gHooksNoContext);
     
     // initialize each EGL and
     // build our own extension string first, based on the extension we know
     // and the extension supported by our client implementation
-    dp->extensionsString = strdup(gExtensionString);
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         cnx->major = -1;
         cnx->minor = -1;
         if (!cnx->dso) 
             continue;
 
-        if (cnx->hooks->egl.eglInitialize(
-                dp->dpys[i], &cnx->major, &cnx->minor)) {
+#if defined(ADRENO130)
+#warning "Adreno-130 eglInitialize() workaround"
+        /*
+         * The ADRENO 130 driver returns a different EGLDisplay each time
+         * eglGetDisplay() is called, but also makes the EGLDisplay invalid
+         * after eglTerminate() has been called, so that eglInitialize() 
+         * cannot be called again. Therefore, we need to make sure to call
+         * eglGetDisplay() before calling eglInitialize();
+         */
+        if (i == IMPL_HARDWARE) {
+            dp->disp[i].dpy =
+                cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        }
+#endif
 
+
+        EGLDisplay idpy = dp->disp[i].dpy;
+        if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
             //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
-            //        i, dp->dpys[i], cnx->major, cnx->minor, cnx);
+            //        i, idpy, cnx->major, cnx->minor, cnx);
+
+            // display is now initialized
+            dp->disp[i].state = egl_display_t::INITIALIZED;
 
             // get the query-strings for this display for each implementation
-            dp->queryString[i].vendor =
-                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
-            dp->queryString[i].version =
-                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
-            dp->queryString[i].extensions = strdup(
-                    cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
-            dp->queryString[i].clientApi =
-                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
+            dp->disp[i].queryString.vendor =
+                cnx->egl.eglQueryString(idpy, EGL_VENDOR);
+            dp->disp[i].queryString.version =
+                cnx->egl.eglQueryString(idpy, EGL_VERSION);
+            dp->disp[i].queryString.extensions =
+                    cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS);
+            dp->disp[i].queryString.clientApi =
+                cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
 
         } else {
-            LOGD("%d: eglInitialize() failed (%s)", 
-                    i, egl_strerror(cnx->hooks->egl.eglGetError()));
+            LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
+                    egl_strerror(cnx->egl.eglGetError()));
         }
     }
 
     EGLBoolean res = EGL_FALSE;
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
             EGLint n;
-            if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
-                dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
-                if (dp->configs[i]) {
-                    if (cnx->hooks->egl.eglGetConfigs(
-                            dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
+            if (cnx->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
+                dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
+                if (dp->disp[i].config) {
+                    if (cnx->egl.eglGetConfigs(
+                            dp->disp[i].dpy, dp->disp[i].config, n,
+                            &dp->disp[i].numConfigs))
                     {
                         // sort the configurations so we can do binary searches
-                        qsort(  dp->configs[i],
-                                dp->numConfigs[i],
+                        qsort(  dp->disp[i].config,
+                                dp->disp[i].numConfigs,
                                 sizeof(EGLConfig), cmp_configs);
 
                         dp->numTotalConfigs += n;
@@ -712,33 +737,36 @@
 
 EGLBoolean eglTerminate(EGLDisplay dpy)
 {
+    // NOTE: don't unload the drivers b/c some APIs can be called
+    // after eglTerminate() has been called. eglTerminate() only
+    // terminates an EGLDisplay, not a EGL itself.
+
     egl_display_t* const dp = get_display(dpy);
     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
     if (android_atomic_dec(&dp->refs) != 1)
         return EGL_TRUE;
-        
+
     EGLBoolean res = EGL_FALSE;
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso) {
-            cnx->hooks->egl.eglTerminate(dp->dpys[i]);
-            
-            /* REVISIT: it's unclear what to do if eglTerminate() fails,
-             * on one end we shouldn't care, on the other end if it fails
-             * it might not be safe to call dlclose() (there could be some
-             * threads around). */
-            
-            free(dp->configs[i]);
-            free((void*)dp->queryString[i].extensions);
-            dp->numConfigs[i] = 0;
-            dp->dpys[i] = EGL_NO_DISPLAY;
-            dlclose((void*)cnx->dso);
-            cnx->dso = 0;
+        if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
+            if (cnx->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
+                LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
+                        egl_strerror(cnx->egl.eglGetError()));
+            }
+            // REVISIT: it's unclear what to do if eglTerminate() fails
+            free(dp->disp[i].config);
+
+            dp->disp[i].numConfigs = 0;
+            dp->disp[i].config = 0;
+            dp->disp[i].state = egl_display_t::TERMINATED;
+
             res = EGL_TRUE;
         }
     }
-    free((void*)dp->extensionsString);
-    dp->extensionsString = 0;
+    
+    // TODO: all egl_object_t should be marked for termination
+    
     dp->numTotalConfigs = 0;
     clearTLS();
     return res;
@@ -761,8 +789,8 @@
         return EGL_TRUE;
     }
     GLint n = 0;
-    for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
-        for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
+    for (int j=0 ; j<IMPL_NUM_IMPLEMENTATIONS ; j++) {
+        for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) {
             *configs++ = MAKE_CONFIG(j, i);
             config_size--;
             n++;
@@ -818,8 +846,8 @@
         
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
-            cnx->hooks->egl.eglGetConfigAttrib(
-                    dp->dpys[i], dp->configs[i][index], 
+            cnx->egl.eglGetConfigAttrib(
+                    dp->disp[i].dpy, dp->disp[i].config[index], 
                     EGL_CONFIG_ID, &configId);
 
             // and switch to the new list
@@ -828,13 +856,13 @@
             // At this point, the only configuration that can match is
             // dp->configs[i][index], however, we don't know if it would be
             // rejected because of the other attributes, so we do have to call
-            // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
+            // cnx->egl.eglChooseConfig() -- but we don't have to loop
             // through all the EGLimpl[].
             // We also know we can only get a single config back, and we know
             // which one.
 
-            res = cnx->hooks->egl.eglChooseConfig(
-                    dp->dpys[i], attrib_list, configs, config_size, &n);
+            res = cnx->egl.eglChooseConfig(
+                    dp->disp[i].dpy, attrib_list, configs, config_size, &n);
             if (res && n>0) {
                 // n has to be 0 or 1, by construction, and we already know
                 // which config it will return (since there can be only one).
@@ -849,17 +877,18 @@
         return res;
     }
 
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
-            if (cnx->hooks->egl.eglChooseConfig(
-                    dp->dpys[i], attrib_list, configs, config_size, &n)) {
+            if (cnx->egl.eglChooseConfig(
+                    dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
                 if (configs) {
                     // now we need to convert these client EGLConfig to our
                     // internal EGLConfig format. This is done in O(n log n).
                     for (int j=0 ; j<n ; j++) {
                         int index = binarySearch<EGLConfig>(
-                                dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
+                                dp->disp[i].config, 0,
+                                dp->disp[i].numConfigs-1, configs[j]);
                         if (index >= 0) {
                             if (configs) {
                                 configs[j] = MAKE_CONFIG(i, index);
@@ -893,8 +922,8 @@
         *value = configToUniqueId(dp, i, index);
         return EGL_TRUE;
     }
-    return cnx->hooks->egl.eglGetConfigAttrib(
-            dp->dpys[i], dp->configs[i][index], attribute, value);
+    return cnx->egl.eglGetConfigAttrib(
+            dp->disp[i].dpy, dp->disp[i].config[index], attribute, value);
 }
 
 // ----------------------------------------------------------------------------
@@ -909,26 +938,12 @@
     int i=0, index=0;
     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
     if (cnx) {
-        // window must be connected upon calling underlying
-        // eglCreateWindowSurface
-        if (window) {
-            window->incRef(window);
-            if (window->connect)
-                window->connect(window);
-        }
-
-        EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
-                dp->dpys[i], dp->configs[i][index], window, attrib_list);       
+        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
+                dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list);       
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
+            egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
             return s;
         }
-        
-        // something went wrong, disconnect and free window
-        // (will disconnect() automatically)
-        if (window) {
-            window->decRef(window);
-        }        
     }
     return EGL_NO_SURFACE;
 }
@@ -941,10 +956,10 @@
     int i=0, index=0;
     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
     if (cnx) {
-        EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
-                dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
+        EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
+                dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+            egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
             return s;
         }
     }
@@ -958,10 +973,10 @@
     int i=0, index=0;
     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
     if (cnx) {
-        EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
-                dp->dpys[i], dp->configs[i][index], attrib_list);
+        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
+                dp->disp[i].dpy, dp->disp[i].config[index], attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+            egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
             return s;
         }
     }
@@ -970,28 +985,35 @@
                                     
 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
 {
+    SurfaceRef _s(surface);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
     egl_display_t const * const dp = get_display(dpy);
-    egl_surface_t const * const s = get_surface(surface);
 
-    EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
-            dp->dpys[s->impl], s->surface);
-    
-    delete s;
+    egl_surface_t * const s = get_surface(surface);
+    EGLBoolean result = s->cnx->egl.eglDestroySurface(
+            dp->disp[s->impl].dpy, s->surface);
+    if (result == EGL_TRUE) {
+        _s.terminate();
+    }
     return result;
 }
 
 EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
                             EGLint attribute, EGLint *value)
 {
+    SurfaceRef _s(surface);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
     egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
 
-    return s->cnx->hooks->egl.eglQuerySurface(
-            dp->dpys[s->impl], s->surface, attribute, value);
+    return s->cnx->egl.eglQuerySurface(
+            dp->disp[s->impl].dpy, s->surface, attribute, value);
 }
 
 // ----------------------------------------------------------------------------
@@ -1005,10 +1027,26 @@
     int i=0, index=0;
     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
     if (cnx) {
-        EGLContext context = cnx->hooks->egl.eglCreateContext(
-                dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
+        EGLContext context = cnx->egl.eglCreateContext(
+                dp->disp[i].dpy, dp->disp[i].config[index],
+                share_list, attrib_list);
         if (context != EGL_NO_CONTEXT) {
-            egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
+            // figure out if it's a GLESv1 or GLESv2
+            int version = 0;
+            if (attrib_list) {
+                while (*attrib_list != EGL_NONE) {
+                    GLint attr = *attrib_list++;
+                    GLint value = *attrib_list++;
+                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
+                        if (value == 1) {
+                            version = GLESv1_INDEX;
+                        } else if (value == 2) {
+                            version = GLESv2_INDEX;
+                        }
+                    }
+                };
+            }
+            egl_context_t* c = new egl_context_t(dpy, context, i, cnx, version);
             return c;
         }
     }
@@ -1017,66 +1055,125 @@
 
 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
 {
+    ContextRef _c(ctx);
+    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+    
     if (!validate_display_context(dpy, ctx))
         return EGL_FALSE;
     egl_display_t const * const dp = get_display(dpy);
     egl_context_t * const c = get_context(ctx);
-    EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
-            dp->dpys[c->impl], c->context);
-    delete c;
+    EGLBoolean result = c->cnx->egl.eglDestroyContext(
+            dp->disp[c->impl].dpy, c->context);
+    if (result == EGL_TRUE) {
+        _c.terminate();
+    }
     return result;
 }
 
 EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
                             EGLSurface read, EGLContext ctx)
 {
+    // get a reference to the object passed in
+    ContextRef _c(ctx);
+    SurfaceRef _d(draw);
+    SurfaceRef _r(read);
+
+    // validate the display and the context (if not EGL_NO_CONTEXT)
     egl_display_t const * const dp = get_display(dpy);
     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    if (read == EGL_NO_SURFACE && draw  == EGL_NO_SURFACE &&
-            ctx == EGL_NO_CONTEXT) 
-    {
-        EGLBoolean result = EGL_TRUE;
-        ctx = getContext();
-        if (ctx) {
-            egl_context_t * const c = get_context(ctx);
-            result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
-            if (result == EGL_TRUE) {
-                setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
-                setContext(EGL_NO_CONTEXT);
-            }
-        }
-        return result;
+    if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
+        // EGL_NO_CONTEXT is valid
+        return EGL_FALSE;
     }
 
-    if (!validate_display_context(dpy, ctx))
-        return EGL_FALSE;    
-    
+    // these are the underlying implementation's object
+    EGLContext impl_ctx  = EGL_NO_CONTEXT;
     EGLSurface impl_draw = EGL_NO_SURFACE;
     EGLSurface impl_read = EGL_NO_SURFACE;
-    egl_context_t * const c = get_context(ctx);
+
+    // these are our objects structs passed in
+    egl_context_t       * c = NULL;
+    egl_surface_t const * d = NULL;
+    egl_surface_t const * r = NULL;
+
+    // these are the current objects structs
+    egl_context_t * cur_c = get_context(getContext());
+    egl_surface_t * cur_r = NULL;
+    egl_surface_t * cur_d = NULL;
+    
+    if (ctx != EGL_NO_CONTEXT) {
+        c = get_context(ctx);
+        cur_r = get_surface(c->read);
+        cur_d = get_surface(c->draw);
+        impl_ctx = c->context;
+    } else {
+        // no context given, use the implementation of the current context
+        if (cur_c == NULL) {
+            // no current context
+            if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
+                // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
+                return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+            }
+            // not an error, there is just not current context.
+            return EGL_TRUE;
+        }
+    }
+
+    // retrieve the underlying implementation's draw EGLSurface
     if (draw != EGL_NO_SURFACE) {
-        egl_surface_t const * d = get_surface(draw);
-        if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-        if (d->impl != c->impl)
+        d = get_surface(draw);
+        // make sure the EGLContext and EGLSurface passed in are for
+        // the same driver
+        if (c && d->impl != c->impl)
             return setError(EGL_BAD_MATCH, EGL_FALSE);
         impl_draw = d->surface;
     }
+
+    // retrieve the underlying implementation's read EGLSurface
     if (read != EGL_NO_SURFACE) {
-        egl_surface_t const * r = get_surface(read);
-        if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-        if (r->impl != c->impl)
+        r = get_surface(read);
+        // make sure the EGLContext and EGLSurface passed in are for
+        // the same driver
+        if (c && r->impl != c->impl)
             return setError(EGL_BAD_MATCH, EGL_FALSE);
         impl_read = r->surface;
     }
-    EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
-            dp->dpys[c->impl], impl_draw, impl_read, c->context);
+
+    EGLBoolean result;
+
+    if (c) {
+        result = c->cnx->egl.eglMakeCurrent(
+                dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
+    } else {
+        result = cur_c->cnx->egl.eglMakeCurrent(
+                dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
+    }
 
     if (result == EGL_TRUE) {
-        setGlThreadSpecific(c->cnx->hooks);
-        setContext(ctx);
-        c->read = read;
-        c->draw = draw;
+        // by construction, these are either 0 or valid (possibly terminated)
+        // it should be impossible for these to be invalid
+        ContextRef _cur_c(cur_c);
+        SurfaceRef _cur_r(cur_r);
+        SurfaceRef _cur_d(cur_d);
+
+        // cur_c has to be valid here (but could be terminated)
+        if (ctx != EGL_NO_CONTEXT) {
+            setGlThreadSpecific(c->cnx->hooks[c->version]);
+            setContext(ctx);
+            _c.acquire();
+        } else {
+            setGlThreadSpecific(&gHooksNoContext);
+            setContext(EGL_NO_CONTEXT);
+        }
+        _cur_c.release();
+
+        _r.acquire();
+        _cur_r.release();
+        if (c) c->read = read;
+
+        _d.acquire();
+        _cur_d.release();
+        if (c) c->draw = draw;
     }
     return result;
 }
@@ -1085,24 +1182,33 @@
 EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
                             EGLint attribute, EGLint *value)
 {
+    ContextRef _c(ctx);
+    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
     if (!validate_display_context(dpy, ctx))
         return EGL_FALSE;    
     
     egl_display_t const * const dp = get_display(dpy);
     egl_context_t * const c = get_context(ctx);
 
-    return c->cnx->hooks->egl.eglQueryContext(
-            dp->dpys[c->impl], c->context, attribute, value);
+    return c->cnx->egl.eglQueryContext(
+            dp->disp[c->impl].dpy, c->context, attribute, value);
 }
 
 EGLContext eglGetCurrentContext(void)
 {
+    // could be called before eglInitialize(), but we wouldn't have a context
+    // then, and this function would correctly return EGL_NO_CONTEXT.
+
     EGLContext ctx = getContext();
     return ctx;
 }
 
 EGLSurface eglGetCurrentSurface(EGLint readdraw)
 {
+    // could be called before eglInitialize(), but we wouldn't have a context
+    // then, and this function would correctly return EGL_NO_SURFACE.
+
     EGLContext ctx = getContext();
     if (ctx) {
         egl_context_t const * const c = get_context(ctx);
@@ -1118,6 +1224,9 @@
 
 EGLDisplay eglGetCurrentDisplay(void)
 {
+    // could be called before eglInitialize(), but we wouldn't have a context
+    // then, and this function would correctly return EGL_NO_DISPLAY.
+
     EGLContext ctx = getContext();
     if (ctx) {
         egl_context_t const * const c = get_context(ctx);
@@ -1129,6 +1238,9 @@
 
 EGLBoolean eglWaitGL(void)
 {
+    // could be called before eglInitialize(), but we wouldn't have a context
+    // then, and this function would return GL_TRUE, which isn't wrong.
+
     EGLBoolean res = EGL_TRUE;
     EGLContext ctx = getContext();
     if (ctx) {
@@ -1139,13 +1251,16 @@
         egl_connection_t* const cnx = &gEGLImpl[c->impl];
         if (!cnx->dso) 
             return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        res = cnx->hooks->egl.eglWaitGL();
+        res = cnx->egl.eglWaitGL();
     }
     return res;
 }
 
 EGLBoolean eglWaitNative(EGLint engine)
 {
+    // could be called before eglInitialize(), but we wouldn't have a context
+    // then, and this function would return GL_TRUE, which isn't wrong.
+    
     EGLBoolean res = EGL_TRUE;
     EGLContext ctx = getContext();
     if (ctx) {
@@ -1156,7 +1271,7 @@
         egl_connection_t* const cnx = &gEGLImpl[c->impl];
         if (!cnx->dso) 
             return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        res = cnx->hooks->egl.eglWaitNative(engine);
+        res = cnx->egl.eglWaitNative(engine);
     }
     return res;
 }
@@ -1164,11 +1279,11 @@
 EGLint eglGetError(void)
 {
     EGLint result = EGL_SUCCESS;
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         EGLint err = EGL_SUCCESS;
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso)
-            err = cnx->hooks->egl.eglGetError();
+            err = cnx->egl.eglGetError();
         if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
             result = err;
     }
@@ -1182,9 +1297,11 @@
     // eglGetProcAddress() could be the very first function called
     // in which case we must make sure we've initialized ourselves, this
     // happens the first time egl_get_display() is called.
-    
-    if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
-        return NULL;
+
+    if (egl_init_drivers() == EGL_FALSE) {
+        setError(EGL_BAD_PARAMETER, NULL);
+        return  NULL;
+    }
 
     __eglMustCastToProperFunctionPointerType addr;
     addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
@@ -1197,11 +1314,11 @@
     
     addr = 0;
     int slot = -1;
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
-            if (cnx->hooks->egl.eglGetProcAddress) {
-                addr = cnx->hooks->egl.eglGetProcAddress(procname);
+            if (cnx->egl.eglGetProcAddress) {
+                addr = cnx->egl.eglGetProcAddress(procname);
                 if (addr) {
                     if (slot == -1) {
                         slot = 0; // XXX: find free slot
@@ -1210,7 +1327,7 @@
                             break;
                         }
                     }
-                    cnx->hooks->ext.extensions[slot] = addr;
+                    //cnx->hooks->ext.extensions[slot] = addr;
                 }
             }
         }
@@ -1243,22 +1360,28 @@
 
 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
 {
+    SurfaceRef _s(draw);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
     if (!validate_display_surface(dpy, draw))
         return EGL_FALSE;    
     egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(draw);
-    return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
+    return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
 }
 
 EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
                             NativePixmapType target)
 {
+    SurfaceRef _s(surface);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
     egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
-    return s->cnx->hooks->egl.eglCopyBuffers(
-            dp->dpys[s->impl], s->surface, target);
+    return s->cnx->egl.eglCopyBuffers(
+            dp->disp[s->impl].dpy, s->surface, target);
 }
 
 const char* eglQueryString(EGLDisplay dpy, EGLint name)
@@ -1285,13 +1408,16 @@
 EGLBoolean eglSurfaceAttrib(
         EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
 {
+    SurfaceRef _s(surface);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
     egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
-    if (s->cnx->hooks->egl.eglSurfaceAttrib) {
-        return s->cnx->hooks->egl.eglSurfaceAttrib(
-                dp->dpys[s->impl], s->surface, attribute, value);
+    if (s->cnx->egl.eglSurfaceAttrib) {
+        return s->cnx->egl.eglSurfaceAttrib(
+                dp->disp[s->impl].dpy, s->surface, attribute, value);
     }
     return setError(EGL_BAD_SURFACE, EGL_FALSE);
 }
@@ -1299,13 +1425,16 @@
 EGLBoolean eglBindTexImage(
         EGLDisplay dpy, EGLSurface surface, EGLint buffer)
 {
+    SurfaceRef _s(surface);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
     egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
-    if (s->cnx->hooks->egl.eglBindTexImage) {
-        return s->cnx->hooks->egl.eglBindTexImage(
-                dp->dpys[s->impl], s->surface, buffer);
+    if (s->cnx->egl.eglBindTexImage) {
+        return s->cnx->egl.eglBindTexImage(
+                dp->disp[s->impl].dpy, s->surface, buffer);
     }
     return setError(EGL_BAD_SURFACE, EGL_FALSE);
 }
@@ -1313,13 +1442,16 @@
 EGLBoolean eglReleaseTexImage(
         EGLDisplay dpy, EGLSurface surface, EGLint buffer)
 {
+    SurfaceRef _s(surface);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
     if (!validate_display_surface(dpy, surface))
         return EGL_FALSE;    
     egl_display_t const * const dp = get_display(dpy);
     egl_surface_t const * const s = get_surface(surface);
-    if (s->cnx->hooks->egl.eglReleaseTexImage) {
-        return s->cnx->hooks->egl.eglReleaseTexImage(
-                dp->dpys[s->impl], s->surface, buffer);
+    if (s->cnx->egl.eglReleaseTexImage) {
+        return s->cnx->egl.eglReleaseTexImage(
+                dp->disp[s->impl].dpy, s->surface, buffer);
     }
     return setError(EGL_BAD_SURFACE, EGL_FALSE);
 }
@@ -1330,11 +1462,12 @@
     if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
 
     EGLBoolean res = EGL_TRUE;
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
-            if (cnx->hooks->egl.eglSwapInterval) {
-                if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
+            if (cnx->egl.eglSwapInterval) {
+                if (cnx->egl.eglSwapInterval(
+                        dp->disp[i].dpy, interval) == EGL_FALSE) {
                     res = EGL_FALSE;
                 }
             }
@@ -1350,6 +1483,8 @@
 
 EGLBoolean eglWaitClient(void)
 {
+    // could be called before eglInitialize(), but we wouldn't have a context
+    // then, and this function would return GL_TRUE, which isn't wrong.
     EGLBoolean res = EGL_TRUE;
     EGLContext ctx = getContext();
     if (ctx) {
@@ -1360,10 +1495,10 @@
         egl_connection_t* const cnx = &gEGLImpl[c->impl];
         if (!cnx->dso) 
             return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        if (cnx->hooks->egl.eglWaitClient) {
-            res = cnx->hooks->egl.eglWaitClient();
+        if (cnx->egl.eglWaitClient) {
+            res = cnx->egl.eglWaitClient();
         } else {
-            res = cnx->hooks->egl.eglWaitGL();
+            res = cnx->egl.eglWaitGL();
         }
     }
     return res;
@@ -1371,13 +1506,17 @@
 
 EGLBoolean eglBindAPI(EGLenum api)
 {
+    if (egl_init_drivers() == EGL_FALSE) {
+        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+    }
+
     // bind this API on all EGLs
     EGLBoolean res = EGL_TRUE;
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
-            if (cnx->hooks->egl.eglBindAPI) {
-                if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
+            if (cnx->egl.eglBindAPI) {
+                if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
                     res = EGL_FALSE;
                 }
             }
@@ -1388,13 +1527,17 @@
 
 EGLenum eglQueryAPI(void)
 {
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    if (egl_init_drivers() == EGL_FALSE) {
+        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+    }
+
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
-            if (cnx->hooks->egl.eglQueryAPI) {
+            if (cnx->egl.eglQueryAPI) {
                 // the first one we find is okay, because they all
                 // should be the same
-                return cnx->hooks->egl.eglQueryAPI();
+                return cnx->egl.eglQueryAPI();
             }
         }
     }
@@ -1404,11 +1547,11 @@
 
 EGLBoolean eglReleaseThread(void)
 {
-    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
         if (cnx->dso) {
-            if (cnx->hooks->egl.eglReleaseThread) {
-                cnx->hooks->egl.eglReleaseThread();
+            if (cnx->egl.eglReleaseThread) {
+                cnx->egl.eglReleaseThread();
             }
         }
     }
@@ -1424,9 +1567,194 @@
     int i=0, index=0;
     egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
     if (!cnx) return EGL_FALSE;
-    if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
-        return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
-                dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
+    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
+        return cnx->egl.eglCreatePbufferFromClientBuffer(
+                dp->disp[i].dpy, buftype, buffer, 
+                dp->disp[i].config[index], attrib_list);
     }
     return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
 }
+
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 3
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+        const EGLint *attrib_list)
+{
+    SurfaceRef _s(surface);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+    if (!validate_display_surface(dpy, surface))
+        return EGL_FALSE;
+
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(surface);
+
+    if (s->cnx->egl.eglLockSurfaceKHR) {
+        return s->cnx->egl.eglLockSurfaceKHR(
+                dp->disp[s->impl].dpy, s->surface, attrib_list);
+    }
+    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
+    SurfaceRef _s(surface);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+    if (!validate_display_surface(dpy, surface))
+        return EGL_FALSE;
+
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(surface);
+
+    if (s->cnx->egl.eglUnlockSurfaceKHR) {
+        return s->cnx->egl.eglUnlockSurfaceKHR(
+                dp->disp[s->impl].dpy, s->surface);
+    }
+    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+        EGLClientBuffer buffer, const EGLint *attrib_list)
+{
+    if (ctx != EGL_NO_CONTEXT) {
+        ContextRef _c(ctx);
+        if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
+        if (!validate_display_context(dpy, ctx))
+            return EGL_NO_IMAGE_KHR;
+        egl_display_t const * const dp = get_display(dpy);
+        egl_context_t * const c = get_context(ctx);
+        // since we have an EGLContext, we know which implementation to use
+        EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
+                dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
+        if (image == EGL_NO_IMAGE_KHR)
+            return image;
+            
+        egl_image_t* result = new egl_image_t(dpy, ctx);
+        result->images[c->impl] = image;
+        return (EGLImageKHR)result;
+    } else {
+        // EGL_NO_CONTEXT is a valid parameter
+        egl_display_t const * const dp = get_display(dpy);
+        if (dp == 0) {
+            return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
+        }
+
+        /* Since we don't have a way to know which implementation to call,
+         * we're calling all of them. If at least one of the implementation
+         * succeeded, this is a success.
+         */
+
+        EGLint currentError = eglGetError();
+
+        EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
+        bool success = false;
+        for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+            egl_connection_t* const cnx = &gEGLImpl[i];
+            implImages[i] = EGL_NO_IMAGE_KHR;
+            if (cnx->dso) {
+                if (cnx->egl.eglCreateImageKHR) {
+                    implImages[i] = cnx->egl.eglCreateImageKHR(
+                            dp->disp[i].dpy, ctx, target, buffer, attrib_list);
+                    if (implImages[i] != EGL_NO_IMAGE_KHR) {
+                        success = true;
+                    }
+                }
+            }
+        }
+
+        if (!success) {
+            // failure, if there was an error when we entered this function,
+            // the error flag must not be updated.
+            // Otherwise, the error is whatever happened in the implementation
+            // that faulted.
+            if (currentError != EGL_SUCCESS) {
+                setError(currentError, EGL_NO_IMAGE_KHR);
+            }
+            return EGL_NO_IMAGE_KHR;
+        } else {
+            // In case of success, we need to clear all error flags
+            // (especially those caused by the implementation that didn't
+            // succeed). TODO: we could avoid this if we knew this was
+            // a "full" success (all implementation succeeded).
+            eglGetError();
+        }
+
+        egl_image_t* result = new egl_image_t(dpy, ctx);
+        memcpy(result->images, implImages, sizeof(implImages));
+        return (EGLImageKHR)result;
+    }
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
+    egl_display_t const * const dp = get_display(dpy);
+     if (dp == 0) {
+         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+     }
+
+     ImageRef _i(img);
+     if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+     egl_image_t* image = get_image(img);
+     bool success = false;
+     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+         egl_connection_t* const cnx = &gEGLImpl[i];
+         if (image->images[i] != EGL_NO_IMAGE_KHR) {
+             if (cnx->dso) {
+                 if (cnx->egl.eglCreateImageKHR) {
+                     if (cnx->egl.eglDestroyImageKHR(
+                             dp->disp[i].dpy, image->images[i])) {
+                         success = true;
+                     }
+                 }
+             }
+         }
+     }
+     if (!success)
+         return EGL_FALSE;
+
+     _i.terminate();
+
+     return EGL_TRUE;
+}
+
+
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+        EGLint left, EGLint top, EGLint width, EGLint height)
+{
+    SurfaceRef _s(draw);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+    if (!validate_display_surface(dpy, draw))
+        return EGL_FALSE;    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(draw);
+    if (s->cnx->egl.eglSetSwapRectangleANDROID) {
+        return s->cnx->egl.eglSetSwapRectangleANDROID(
+                dp->disp[s->impl].dpy, s->surface, left, top, width, height);
+    }
+    return setError(EGL_BAD_DISPLAY, NULL);
+}
+
+EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
+{
+    SurfaceRef _s(draw);
+    if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
+
+    if (!validate_display_surface(dpy, draw))
+        return 0;    
+    egl_display_t const * const dp = get_display(dpy);
+    egl_surface_t const * const s = get_surface(draw);
+    if (s->cnx->egl.eglGetRenderBufferANDROID) {
+        return s->cnx->egl.eglGetRenderBufferANDROID(
+                dp->disp[s->impl].dpy, s->surface);
+    }
+    return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
+}
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
new file mode 100644
index 0000000..5d89287
--- /dev/null
+++ b/opengl/libs/EGL/egl_entries.in
@@ -0,0 +1,57 @@
+EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)
+EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
+EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
+EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
+EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)
+
+EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *)
+EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePbufferSurface,  EGLDisplay, EGLConfig, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglQuerySurface,  EGLDisplay, EGLSurface, EGLint, EGLint *)
+EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext)
+EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext)
+EGL_ENTRY(EGLContext, eglGetCurrentContext, void)
+EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint)
+EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void)
+EGL_ENTRY(EGLBoolean, eglQueryContext,  EGLDisplay, EGLContext, EGLint, EGLint *)
+EGL_ENTRY(EGLBoolean, eglWaitGL, void)
+EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType)
+EGL_ENTRY(EGLint, eglGetError, void)
+EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint)
+EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char *)
+
+/* EGL 1.1 */
+
+EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint)
+EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint)
+
+/* EGL 1.2 */
+
+EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum)
+EGL_ENTRY(EGLenum, eglQueryAPI, void)
+EGL_ENTRY(EGLBoolean, eglWaitClient, void)
+EGL_ENTRY(EGLBoolean, eglReleaseThread, void)
+EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint *)
+
+/* EGL 1.3 */
+
+/* EGL 1.4 */
+
+/* EGL_EGLEXT_VERSION 3 */
+
+EGL_ENTRY(EGLBoolean,  eglLockSurfaceKHR,   EGLDisplay, EGLSurface, const EGLint *)
+EGL_ENTRY(EGLBoolean,  eglUnlockSurfaceKHR, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLImageKHR, eglCreateImageKHR,   EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *)
+EGL_ENTRY(EGLBoolean,  eglDestroyImageKHR,  EGLDisplay, EGLImageKHR)
+
+/* ANDROID extensions */
+
+EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint)
+EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface)
diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp
deleted file mode 100644
index 4c902c8..0000000
--- a/opengl/libs/EGL/gpu.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/* 
- ** 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.
- */
-
-#define LOG_TAG "EGL"
-
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/ioctl.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
-#include <utils/IMemory.h>
-#include <utils/threads.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Parcel.h>
-
-#include <ui/EGLDisplaySurface.h>
-#include <ui/ISurfaceComposer.h>
-
-#include "hooks.h"
-#include "egl_impl.h"
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-/*
- * we provide our own allocators for the GPU regions, these
- * allocators go through surfaceflinger 
- */
-
-static Mutex                            gRegionsLock;
-static request_gpu_t                    gRegions;
-static sp<ISurfaceComposer>             gSurfaceManager;
-GL_API ISurfaceComposer*                GLES_localSurfaceManager = 0;
-
-extern egl_connection_t gEGLImpl[2];
-
-const sp<ISurfaceComposer>& getSurfaceFlinger()
-{
-    Mutex::Autolock _l(gRegionsLock);
-
-    /*
-     * There is a little bit of voodoo magic here. We want to access
-     * surfaceflinger for allocating GPU regions, however, when we are
-     * running as part of surfaceflinger, we want to bypass the
-     * service manager because surfaceflinger might not be registered yet.
-     * SurfaceFlinger will populate "GLES_localSurfaceManager" with its
-     * own address, so we can just use that.
-     */
-    if (gSurfaceManager == 0) {
-        if (GLES_localSurfaceManager) {
-            // we're running in SurfaceFlinger's context
-            gSurfaceManager =  GLES_localSurfaceManager;
-        } else {
-            // we're a remote process or not part of surfaceflinger,
-            // go through the service manager
-            sp<IServiceManager> sm = defaultServiceManager();
-            if (sm != NULL) {
-                sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
-                gSurfaceManager = interface_cast<ISurfaceComposer>(binder);
-            }
-        }
-    }
-    return gSurfaceManager;
-}
-
-class GPURevokeRequester : public BnGPUCallback
-{
-public:
-    virtual void gpuLost() {
-        LOGD("CONTEXT_LOST: Releasing GPU upon request from SurfaceFlinger.");
-        gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
-    }
-};
-
-static sp<GPURevokeRequester> gRevokerCallback;
-
-
-request_gpu_t* gpu_acquire(void* user)
-{
-    sp<ISurfaceComposer> server( getSurfaceFlinger() );
-
-    Mutex::Autolock _l(gRegionsLock);
-    if (server == NULL) {
-        return 0;
-    }
-    
-    ISurfaceComposer::gpu_info_t info;
-    
-    if (gRevokerCallback == 0)
-        gRevokerCallback = new GPURevokeRequester();
-
-    status_t err = server->requestGPU(gRevokerCallback, &info);
-    if (err != NO_ERROR) {
-        LOGD("requestGPU returned %d", err);
-        return 0;
-    }
-
-    if (info.regs == 0) {
-        LOGD("requestGPU() failed");
-        return 0;
-    }
-
-    bool failed = false;
-    request_gpu_t* gpu = &gRegions;
-    memset(gpu, 0, sizeof(*gpu));
-    
-    if (info.regs != 0) {
-        sp<IMemoryHeap> heap(info.regs->getMemory());
-        if (heap != 0) {
-            int fd = heap->heapID();
-            gpu->regs.fd = fd;
-            gpu->regs.base = info.regs->pointer(); 
-            gpu->regs.size = info.regs->size(); 
-            gpu->regs.user = info.regs.get();
-#if HAVE_ANDROID_OS
-            struct pmem_region region;
-            if (ioctl(fd, PMEM_GET_PHYS, &region) >= 0)
-                gpu->regs.phys = (void*)region.offset;
-#endif
-            info.regs->incStrong(gpu);
-        } else {
-            LOGE("GPU register handle %p is invalid!", info.regs.get());
-            failed = true;
-        }
-    }
-
-    for (size_t i=0 ; i<info.count && !failed ; i++) {
-        sp<IMemory>& region(info.regions[i].region);
-        if (region != 0) {
-            sp<IMemoryHeap> heap(region->getMemory());
-            if (heap != 0) {
-                const int fd = heap->heapID();
-                gpu->gpu[i].fd = fd;
-                gpu->gpu[i].base = region->pointer(); 
-                gpu->gpu[i].size = region->size(); 
-                gpu->gpu[i].user = region.get();
-                gpu->gpu[i].offset = info.regions[i].reserved;
-#if HAVE_ANDROID_OS
-                struct pmem_region reg;
-                if (ioctl(fd, PMEM_GET_PHYS, &reg) >= 0)
-                    gpu->gpu[i].phys = (void*)reg.offset;
-#endif
-                region->incStrong(gpu);
-            } else {
-                LOGE("GPU region handle [%d, %p] is invalid!", i, region.get());
-                failed = true;
-            }
-        }
-    }
-    
-    if (failed) {
-        // something went wrong, clean up everything!
-        if (gpu->regs.user) {
-            static_cast<IMemory*>(gpu->regs.user)->decStrong(gpu);
-            for (size_t i=0 ; i<info.count ; i++) {
-                if (gpu->gpu[i].user) {
-                    static_cast<IMemory*>(gpu->gpu[i].user)->decStrong(gpu);
-                }
-            }
-        }
-    }
-    
-    gpu->count = info.count;
-    return gpu;
-}
-
-int gpu_release(void*, request_gpu_t* gpu)
-{
-    sp<IMemory> regs;
-
-    { // scope for lock
-        Mutex::Autolock _l(gRegionsLock);
-        regs = static_cast<IMemory*>(gpu->regs.user);   
-        gpu->regs.user = 0;
-        if (regs != 0) regs->decStrong(gpu);
-        
-        for (int i=0 ; i<gpu->count ; i++) {
-            sp<IMemory> r(static_cast<IMemory*>(gpu->gpu[i].user));
-            gpu->gpu[i].user = 0;
-            if (r != 0) r->decStrong(gpu);
-        }
-    }
-    
-    // there is a special transaction to relinquish the GPU
-    // (it will happen automatically anyway if we don't do this)
-    Parcel data, reply;
-    // NOTE: this transaction does not require an interface token
-    regs->asBinder()->transact(1000, data, &reply);
-    return 1;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/hooks.cpp b/opengl/libs/EGL/hooks.cpp
new file mode 100644
index 0000000..72ad6b3
--- /dev/null
+++ b/opengl/libs/EGL/hooks.cpp
@@ -0,0 +1,60 @@
+/* 
+ ** 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 "entries.in"
+    NULL
+};
+
+char const * const egl_names[] = {
+    #include "egl_entries.in"
+    NULL
+};
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+