egl.cpp revision 9429e9c8ad8ae41104c693235a9376b3086da2e9
1/*
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 **     http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17#include <ctype.h>
18#include <stdlib.h>
19#include <string.h>
20#include <errno.h>
21#include <dlfcn.h>
22
23#include <sys/ioctl.h>
24
25#if HAVE_ANDROID_OS
26#include <linux/android_pmem.h>
27#endif
28
29#include <EGL/egl.h>
30#include <EGL/eglext.h>
31#include <GLES/gl.h>
32#include <GLES/glext.h>
33
34#include <cutils/log.h>
35#include <cutils/atomic.h>
36#include <cutils/properties.h>
37#include <cutils/memory.h>
38
39#include <utils/SortedVector.h>
40
41#include "hooks.h"
42#include "egl_impl.h"
43#include "Loader.h"
44
45#define MAKE_CONFIG(_impl, _index)  ((EGLConfig)(((_impl)<<24) | (_index)))
46#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
47
48// ----------------------------------------------------------------------------
49namespace android {
50// ----------------------------------------------------------------------------
51
52#define VERSION_MAJOR 1
53#define VERSION_MINOR 4
54static char const * const gVendorString     = "Android";
55static char const * const gVersionString    = "1.4 Android META-EGL";
56static char const * const gClientApiString  = "OpenGL ES";
57static char const * const gExtensionString  =
58        "EGL_KHR_image "
59        "EGL_KHR_image_base "
60        "EGL_KHR_image_pixmap "
61        "EGL_ANDROID_image_native_buffer "
62        "EGL_ANDROID_swap_rectangle "
63        "EGL_ANDROID_get_render_buffer "
64        ;
65
66// ----------------------------------------------------------------------------
67
68class egl_object_t {
69    static SortedVector<egl_object_t*> sObjects;
70    static Mutex sLock;
71
72            volatile int32_t  terminated;
73    mutable volatile int32_t  count;
74
75public:
76    egl_object_t() : terminated(0), count(1) {
77        Mutex::Autolock _l(sLock);
78        sObjects.add(this);
79    }
80
81    inline bool isAlive() const { return !terminated; }
82
83private:
84    bool get() {
85        Mutex::Autolock _l(sLock);
86        if (egl_object_t::sObjects.indexOf(this) >= 0) {
87            android_atomic_inc(&count);
88            return true;
89        }
90        return false;
91    }
92
93    bool put() {
94        Mutex::Autolock _l(sLock);
95        if (android_atomic_dec(&count) == 1) {
96            sObjects.remove(this);
97            return true;
98        }
99        return false;
100    }
101
102public:
103    template <typename N, typename T>
104    struct LocalRef {
105        N* ref;
106        LocalRef(T o) : ref(0) {
107            N* native = reinterpret_cast<N*>(o);
108            if (o && native->get()) {
109                ref = native;
110            }
111        }
112        ~LocalRef() {
113            if (ref && ref->put()) {
114                delete ref;
115            }
116        }
117        inline N* get() {
118            return ref;
119        }
120        void acquire() const {
121            if (ref) {
122                android_atomic_inc(&ref->count);
123            }
124        }
125        void release() const {
126            if (ref) {
127                int32_t c = android_atomic_dec(&ref->count);
128                // ref->count cannot be 1 prior atomic_dec because we have
129                // a reference, and if we have one, it means there was
130                // already one before us.
131                LOGE_IF(c==1, "refcount is now 0 in release()");
132            }
133        }
134        void terminate() {
135            if (ref) {
136                ref->terminated = 1;
137                release();
138            }
139        }
140    };
141};
142
143SortedVector<egl_object_t*> egl_object_t::sObjects;
144Mutex egl_object_t::sLock;
145
146struct egl_display_t
147{
148    uint32_t    magic;
149    EGLDisplay  dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
150    EGLConfig*  configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
151    EGLint      numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
152    EGLint      numTotalConfigs;
153    volatile int32_t refs;
154    struct strings_t {
155        char const * vendor;
156        char const * version;
157        char const * clientApi;
158        char const * extensions;
159    };
160    strings_t   queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
161    egl_display_t() : magic('_dpy') { }
162    ~egl_display_t() { magic = 0; }
163    inline bool isValid() const { return magic == '_dpy'; }
164    inline bool isAlive() const { return isValid(); }
165};
166
167struct egl_surface_t : public egl_object_t
168{
169    typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
170
171    egl_surface_t(EGLDisplay dpy, EGLSurface surface,
172            int impl, egl_connection_t const* cnx)
173    : dpy(dpy), surface(surface), impl(impl), cnx(cnx) {
174    }
175    ~egl_surface_t() {
176    }
177    EGLDisplay                  dpy;
178    EGLSurface                  surface;
179    int                         impl;
180    egl_connection_t const*     cnx;
181};
182
183struct egl_context_t : public egl_object_t
184{
185    typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
186
187    egl_context_t(EGLDisplay dpy, EGLContext context,
188            int impl, egl_connection_t const* cnx)
189    : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
190    {
191    }
192    EGLDisplay                  dpy;
193    EGLContext                  context;
194    EGLSurface                  read;
195    EGLSurface                  draw;
196    int                         impl;
197    egl_connection_t const*     cnx;
198};
199
200struct egl_image_t : public egl_object_t
201{
202    typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
203
204    egl_image_t(EGLDisplay dpy, EGLContext context)
205        : dpy(dpy), context(context)
206    {
207        memset(images, 0, sizeof(images));
208    }
209    EGLDisplay dpy;
210    EGLConfig context;
211    EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
212};
213
214typedef egl_surface_t::Ref  SurfaceRef;
215typedef egl_context_t::Ref  ContextRef;
216typedef egl_image_t::Ref    ImageRef;
217
218struct tls_t
219{
220    tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
221    EGLint      error;
222    EGLContext  ctx;
223    EGLBoolean  logCallWithNoContext;
224};
225
226
227// ----------------------------------------------------------------------------
228
229egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
230static egl_display_t gDisplay[NUM_DISPLAYS];
231static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
232static pthread_key_t gEGLThreadLocalStorageKey = -1;
233
234// ----------------------------------------------------------------------------
235
236EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
237EGLAPI pthread_key_t gGLWrapperKey = -1;
238
239// ----------------------------------------------------------------------------
240
241static __attribute__((noinline))
242const char *egl_strerror(EGLint err)
243{
244    switch (err){
245        case EGL_SUCCESS:               return "EGL_SUCCESS";
246        case EGL_NOT_INITIALIZED:       return "EGL_NOT_INITIALIZED";
247        case EGL_BAD_ACCESS:            return "EGL_BAD_ACCESS";
248        case EGL_BAD_ALLOC:             return "EGL_BAD_ALLOC";
249        case EGL_BAD_ATTRIBUTE:         return "EGL_BAD_ATTRIBUTE";
250        case EGL_BAD_CONFIG:            return "EGL_BAD_CONFIG";
251        case EGL_BAD_CONTEXT:           return "EGL_BAD_CONTEXT";
252        case EGL_BAD_CURRENT_SURFACE:   return "EGL_BAD_CURRENT_SURFACE";
253        case EGL_BAD_DISPLAY:           return "EGL_BAD_DISPLAY";
254        case EGL_BAD_MATCH:             return "EGL_BAD_MATCH";
255        case EGL_BAD_NATIVE_PIXMAP:     return "EGL_BAD_NATIVE_PIXMAP";
256        case EGL_BAD_NATIVE_WINDOW:     return "EGL_BAD_NATIVE_WINDOW";
257        case EGL_BAD_PARAMETER:         return "EGL_BAD_PARAMETER";
258        case EGL_BAD_SURFACE:           return "EGL_BAD_SURFACE";
259        case EGL_CONTEXT_LOST:          return "EGL_CONTEXT_LOST";
260        default: return "UNKNOWN";
261    }
262}
263
264static __attribute__((noinline))
265void clearTLS() {
266    if (gEGLThreadLocalStorageKey != -1) {
267        tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
268        if (tls) {
269            delete tls;
270            pthread_setspecific(gEGLThreadLocalStorageKey, 0);
271        }
272    }
273}
274
275static tls_t* getTLS()
276{
277    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
278    if (tls == 0) {
279        tls = new tls_t;
280        pthread_setspecific(gEGLThreadLocalStorageKey, tls);
281    }
282    return tls;
283}
284
285template<typename T>
286static __attribute__((noinline))
287T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
288    if (gEGLThreadLocalStorageKey == -1) {
289        pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
290        if (gEGLThreadLocalStorageKey == -1)
291            pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
292        pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
293    }
294    tls_t* tls = getTLS();
295    if (tls->error != error) {
296        LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
297        tls->error = error;
298    }
299    return returnValue;
300}
301
302static __attribute__((noinline))
303GLint getError() {
304    if (gEGLThreadLocalStorageKey == -1)
305        return EGL_SUCCESS;
306    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
307    if (!tls) return EGL_SUCCESS;
308    GLint error = tls->error;
309    tls->error = EGL_SUCCESS;
310    return error;
311}
312
313static __attribute__((noinline))
314void setContext(EGLContext ctx) {
315    if (gEGLThreadLocalStorageKey == -1) {
316        pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
317        if (gEGLThreadLocalStorageKey == -1)
318            pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
319        pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
320    }
321    tls_t* tls = getTLS();
322    tls->ctx = ctx;
323}
324
325static __attribute__((noinline))
326EGLContext getContext() {
327    if (gEGLThreadLocalStorageKey == -1)
328        return EGL_NO_CONTEXT;
329    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
330    if (!tls) return EGL_NO_CONTEXT;
331    return tls->ctx;
332}
333
334/*****************************************************************************/
335
336template<typename T>
337static __attribute__((noinline))
338int binarySearch(
339        T const sortedArray[], int first, int last, T key)
340{
341    while (first <= last) {
342        int mid = (first + last) / 2;
343        if (key > sortedArray[mid]) {
344            first = mid + 1;
345        } else if (key < sortedArray[mid]) {
346            last = mid - 1;
347        } else {
348            return mid;
349        }
350    }
351    return -1;
352}
353
354static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
355{
356    // NOTE: this mapping works only if we have no more than two EGLimpl
357    return (i>0 ? dp->numConfigs[0] : 0) + index;
358}
359
360static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
361        int& i, int& index)
362{
363    // NOTE: this mapping works only if we have no more than two EGLimpl
364    size_t numConfigs = dp->numConfigs[0];
365    i = configId / numConfigs;
366    index = configId % numConfigs;
367}
368
369static int cmp_configs(const void* a, const void *b)
370{
371    EGLConfig c0 = *(EGLConfig const *)a;
372    EGLConfig c1 = *(EGLConfig const *)b;
373    return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
374}
375
376struct extention_map_t {
377    const char* name;
378    __eglMustCastToProperFunctionPointerType address;
379};
380
381static const extention_map_t gExtentionMap[] = {
382    { "eglLockSurfaceKHR",
383            (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
384    { "eglUnlockSurfaceKHR",
385            (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
386    { "eglCreateImageKHR",
387            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
388    { "eglDestroyImageKHR",
389            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
390    { "eglSetSwapRectangleANDROID",
391            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
392    { "eglGetRenderBufferANDROID",
393            (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
394};
395
396static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
397
398static void(*findProcAddress(const char* name,
399        const extention_map_t* map, size_t n))()
400{
401    for (uint32_t i=0 ; i<n ; i++) {
402        if (!strcmp(name, map[i].name)) {
403            return map[i].address;
404        }
405    }
406    return NULL;
407}
408
409// ----------------------------------------------------------------------------
410
411static void gl_no_context() {
412    tls_t* tls = getTLS();
413    if (tls->logCallWithNoContext == EGL_TRUE) {
414        tls->logCallWithNoContext = EGL_FALSE;
415        LOGE("call to OpenGL ES API with no current context "
416             "(logged once per thread)");
417    }
418}
419
420static void early_egl_init(void)
421{
422#if !USE_FAST_TLS_KEY
423    pthread_key_create(&gGLWrapperKey, NULL);
424#endif
425    uint32_t addr = (uint32_t)((void*)gl_no_context);
426    android_memset32(
427            (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
428            addr,
429            sizeof(gHooks[IMPL_NO_CONTEXT]));
430    setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
431}
432
433static pthread_once_t once_control = PTHREAD_ONCE_INIT;
434static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
435
436
437static inline
438egl_display_t* get_display(EGLDisplay dpy)
439{
440    uintptr_t index = uintptr_t(dpy)-1U;
441    return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
442}
443
444template<typename NATIVE, typename EGL>
445static inline NATIVE* egl_to_native_cast(EGL arg) {
446    return reinterpret_cast<NATIVE*>(arg);
447}
448
449static inline
450egl_surface_t* get_surface(EGLSurface surface) {
451    return egl_to_native_cast<egl_surface_t>(surface);
452}
453
454static inline
455egl_context_t* get_context(EGLContext context) {
456    return egl_to_native_cast<egl_context_t>(context);
457}
458
459static inline
460egl_image_t* get_image(EGLImageKHR image) {
461    return egl_to_native_cast<egl_image_t>(image);
462}
463
464static egl_connection_t* validate_display_config(
465        EGLDisplay dpy, EGLConfig config,
466        egl_display_t const*& dp, int& impl, int& index)
467{
468    dp = get_display(dpy);
469    if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
470
471    impl = uintptr_t(config)>>24;
472    if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
473        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
474    }
475    index = uintptr_t(config) & 0xFFFFFF;
476    if (index >= dp->numConfigs[impl]) {
477        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
478    }
479    egl_connection_t* const cnx = &gEGLImpl[impl];
480    if (cnx->dso == 0) {
481        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
482    }
483    return cnx;
484}
485
486static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
487{
488    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
489        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
490    if (!get_display(dpy)->isAlive())
491        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
492    if (!get_context(ctx)->isAlive())
493        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
494    return EGL_TRUE;
495}
496
497static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
498{
499    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
500        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
501    if (!get_display(dpy)->isAlive())
502        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
503    if (!get_surface(surface)->isAlive())
504        return setError(EGL_BAD_SURFACE, EGL_FALSE);
505    return EGL_TRUE;
506}
507
508EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
509{
510    ImageRef _i(image);
511    if (!_i.get()) return EGL_NO_IMAGE_KHR;
512
513    EGLContext context = getContext();
514    if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
515        return EGL_NO_IMAGE_KHR;
516
517    egl_context_t const * const c = get_context(context);
518    if (!c->isAlive())
519        return EGL_NO_IMAGE_KHR;
520
521    egl_image_t const * const i = get_image(image);
522    return i->images[c->impl];
523}
524
525// ----------------------------------------------------------------------------
526
527// this mutex protects:
528//    d->dpys[]
529//    egl_init_drivers_locked()
530//
531static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
532
533EGLBoolean egl_init_drivers_locked()
534{
535    if (sEarlyInitState) {
536        // initialized by static ctor. should be set here.
537        return EGL_FALSE;
538    }
539
540    // get our driver loader
541    Loader& loader(Loader::getInstance());
542
543    // dynamically load all our EGL implementations for all displays
544    // and retrieve the corresponding EGLDisplay
545    // if that fails, don't use this driver.
546    // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
547    egl_connection_t* cnx;
548    egl_display_t* d = &gDisplay[0];
549
550    cnx = &gEGLImpl[IMPL_SOFTWARE];
551    if (cnx->dso == 0) {
552        cnx->hooks = &gHooks[IMPL_SOFTWARE];
553        cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx->hooks);
554        if (cnx->dso) {
555            EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
556            LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
557            d->dpys[IMPL_SOFTWARE] = dpy;
558            if (dpy == EGL_NO_DISPLAY) {
559                loader.close(cnx->dso);
560                cnx->dso = NULL;
561            }
562        }
563    }
564
565    cnx = &gEGLImpl[IMPL_HARDWARE];
566    if (cnx->dso == 0) {
567        char value[PROPERTY_VALUE_MAX];
568        property_get("debug.egl.hw", value, "1");
569        if (atoi(value) != 0) {
570            cnx->hooks = &gHooks[IMPL_HARDWARE];
571            cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx->hooks);
572            if (cnx->dso) {
573                EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
574                LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
575                d->dpys[IMPL_HARDWARE] = dpy;
576                if (dpy == EGL_NO_DISPLAY) {
577                    loader.close(cnx->dso);
578                    cnx->dso = NULL;
579                }
580            }
581        } else {
582            LOGD("3D hardware acceleration is disabled");
583        }
584    }
585
586    if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
587        return EGL_FALSE;
588    }
589
590    return EGL_TRUE;
591}
592
593EGLBoolean egl_init_drivers()
594{
595    EGLBoolean res;
596    pthread_mutex_lock(&gInitDriverMutex);
597    res = egl_init_drivers_locked();
598    pthread_mutex_unlock(&gInitDriverMutex);
599    return res;
600}
601
602// ----------------------------------------------------------------------------
603}; // namespace android
604// ----------------------------------------------------------------------------
605
606using namespace android;
607
608EGLDisplay eglGetDisplay(NativeDisplayType display)
609{
610    uint32_t index = uint32_t(display);
611    if (index >= NUM_DISPLAYS) {
612        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
613    }
614
615    if (egl_init_drivers() == EGL_FALSE) {
616        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
617    }
618
619    EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
620    return dpy;
621}
622
623// ----------------------------------------------------------------------------
624// Initialization
625// ----------------------------------------------------------------------------
626
627EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
628{
629    egl_display_t * const dp = get_display(dpy);
630    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
631
632    if (android_atomic_inc(&dp->refs) > 0) {
633        if (major != NULL) *major = VERSION_MAJOR;
634        if (minor != NULL) *minor = VERSION_MINOR;
635        return EGL_TRUE;
636    }
637
638    setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
639
640    // initialize each EGL and
641    // build our own extension string first, based on the extension we know
642    // and the extension supported by our client implementation
643    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
644        egl_connection_t* const cnx = &gEGLImpl[i];
645        cnx->major = -1;
646        cnx->minor = -1;
647        if (!cnx->dso)
648            continue;
649
650        if (cnx->hooks->egl.eglInitialize(
651                dp->dpys[i], &cnx->major, &cnx->minor)) {
652
653            //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
654            //        i, dp->dpys[i], cnx->major, cnx->minor, cnx);
655
656            // get the query-strings for this display for each implementation
657            dp->queryString[i].vendor =
658                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
659            dp->queryString[i].version =
660                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
661            dp->queryString[i].extensions = strdup(
662                    cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
663            dp->queryString[i].clientApi =
664                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
665
666        } else {
667            LOGD("%d: eglInitialize() failed (%s)",
668                    i, egl_strerror(cnx->hooks->egl.eglGetError()));
669        }
670    }
671
672    EGLBoolean res = EGL_FALSE;
673    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
674        egl_connection_t* const cnx = &gEGLImpl[i];
675        if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
676            EGLint n;
677            if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
678                dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
679                if (dp->configs[i]) {
680                    if (cnx->hooks->egl.eglGetConfigs(
681                            dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
682                    {
683                        // sort the configurations so we can do binary searches
684                        qsort(  dp->configs[i],
685                                dp->numConfigs[i],
686                                sizeof(EGLConfig), cmp_configs);
687
688                        dp->numTotalConfigs += n;
689                        res = EGL_TRUE;
690                    }
691                }
692            }
693        }
694    }
695
696    if (res == EGL_TRUE) {
697        if (major != NULL) *major = VERSION_MAJOR;
698        if (minor != NULL) *minor = VERSION_MINOR;
699        return EGL_TRUE;
700    }
701    return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
702}
703
704EGLBoolean eglTerminate(EGLDisplay dpy)
705{
706    // NOTE: don't unload the drivers b/c some APIs can be called
707    // after eglTerminate() has been called. eglTerminate() only
708    // terminates an EGLDisplay, not a EGL itself.
709
710    egl_display_t* const dp = get_display(dpy);
711    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
712    if (android_atomic_dec(&dp->refs) != 1)
713        return EGL_TRUE;
714
715    EGLBoolean res = EGL_FALSE;
716    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
717        egl_connection_t* const cnx = &gEGLImpl[i];
718        if (cnx->dso) {
719            cnx->hooks->egl.eglTerminate(dp->dpys[i]);
720            // REVISIT: it's unclear what to do if eglTerminate() fails
721            free(dp->configs[i]);
722            free((void*)dp->queryString[i].extensions);
723            dp->numConfigs[i] = 0;
724            dp->dpys[i] = EGL_NO_DISPLAY;
725            res = EGL_TRUE;
726        }
727    }
728
729    // TODO: all egl_object_t should be marked for termination
730
731    dp->numTotalConfigs = 0;
732    clearTLS();
733    return res;
734}
735
736// ----------------------------------------------------------------------------
737// configuration
738// ----------------------------------------------------------------------------
739
740EGLBoolean eglGetConfigs(   EGLDisplay dpy,
741                            EGLConfig *configs,
742                            EGLint config_size, EGLint *num_config)
743{
744    egl_display_t const * const dp = get_display(dpy);
745    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
746
747    GLint numConfigs = dp->numTotalConfigs;
748    if (!configs) {
749        *num_config = numConfigs;
750        return EGL_TRUE;
751    }
752    GLint n = 0;
753    for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
754        for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
755            *configs++ = MAKE_CONFIG(j, i);
756            config_size--;
757            n++;
758        }
759    }
760
761    *num_config = n;
762    return EGL_TRUE;
763}
764
765EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
766                            EGLConfig *configs, EGLint config_size,
767                            EGLint *num_config)
768{
769    egl_display_t const * const dp = get_display(dpy);
770    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
771
772    if (num_config==0) {
773        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
774    }
775
776    EGLint n;
777    EGLBoolean res = EGL_FALSE;
778    *num_config = 0;
779
780
781    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
782    // to do  this, we have to go through the attrib_list array once
783    // to figure out both its size and if it contains an EGL_CONFIG_ID
784    // key. If so, the full array is copied and patched.
785    // NOTE: we assume that there can be only one occurrence
786    // of EGL_CONFIG_ID.
787
788    EGLint patch_index = -1;
789    GLint attr;
790    size_t size = 0;
791    while ((attr=attrib_list[size]) != EGL_NONE) {
792        if (attr == EGL_CONFIG_ID)
793            patch_index = size;
794        size += 2;
795    }
796    if (patch_index >= 0) {
797        size += 2; // we need copy the sentinel as well
798        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
799        if (new_list == 0)
800            return setError(EGL_BAD_ALLOC, EGL_FALSE);
801        memcpy(new_list, attrib_list, size*sizeof(EGLint));
802
803        // patch the requested EGL_CONFIG_ID
804        int i, index;
805        EGLint& configId(new_list[patch_index+1]);
806        uniqueIdToConfig(dp, configId, i, index);
807
808        egl_connection_t* const cnx = &gEGLImpl[i];
809        if (cnx->dso) {
810            cnx->hooks->egl.eglGetConfigAttrib(
811                    dp->dpys[i], dp->configs[i][index],
812                    EGL_CONFIG_ID, &configId);
813
814            // and switch to the new list
815            attrib_list = const_cast<const EGLint *>(new_list);
816
817            // At this point, the only configuration that can match is
818            // dp->configs[i][index], however, we don't know if it would be
819            // rejected because of the other attributes, so we do have to call
820            // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
821            // through all the EGLimpl[].
822            // We also know we can only get a single config back, and we know
823            // which one.
824
825            res = cnx->hooks->egl.eglChooseConfig(
826                    dp->dpys[i], attrib_list, configs, config_size, &n);
827            if (res && n>0) {
828                // n has to be 0 or 1, by construction, and we already know
829                // which config it will return (since there can be only one).
830                if (configs) {
831                    configs[0] = MAKE_CONFIG(i, index);
832                }
833                *num_config = 1;
834            }
835        }
836
837        free(const_cast<EGLint *>(attrib_list));
838        return res;
839    }
840
841    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
842        egl_connection_t* const cnx = &gEGLImpl[i];
843        if (cnx->dso) {
844            if (cnx->hooks->egl.eglChooseConfig(
845                    dp->dpys[i], attrib_list, configs, config_size, &n)) {
846                if (configs) {
847                    // now we need to convert these client EGLConfig to our
848                    // internal EGLConfig format. This is done in O(n log n).
849                    for (int j=0 ; j<n ; j++) {
850                        int index = binarySearch<EGLConfig>(
851                                dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
852                        if (index >= 0) {
853                            if (configs) {
854                                configs[j] = MAKE_CONFIG(i, index);
855                            }
856                        } else {
857                            return setError(EGL_BAD_CONFIG, EGL_FALSE);
858                        }
859                    }
860                    configs += n;
861                    config_size -= n;
862                }
863                *num_config += n;
864                res = EGL_TRUE;
865            }
866        }
867    }
868    return res;
869}
870
871EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
872        EGLint attribute, EGLint *value)
873{
874    egl_display_t const* dp = 0;
875    int i=0, index=0;
876    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
877    if (!cnx) return EGL_FALSE;
878
879    if (attribute == EGL_CONFIG_ID) {
880        // EGL_CONFIG_IDs must be unique, just use the order of the selected
881        // EGLConfig.
882        *value = configToUniqueId(dp, i, index);
883        return EGL_TRUE;
884    }
885    return cnx->hooks->egl.eglGetConfigAttrib(
886            dp->dpys[i], dp->configs[i][index], attribute, value);
887}
888
889// ----------------------------------------------------------------------------
890// surfaces
891// ----------------------------------------------------------------------------
892
893EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
894                                    NativeWindowType window,
895                                    const EGLint *attrib_list)
896{
897    egl_display_t const* dp = 0;
898    int i=0, index=0;
899    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
900    if (cnx) {
901        EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
902                dp->dpys[i], dp->configs[i][index], window, attrib_list);
903        if (surface != EGL_NO_SURFACE) {
904            egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
905            return s;
906        }
907    }
908    return EGL_NO_SURFACE;
909}
910
911EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
912                                    NativePixmapType pixmap,
913                                    const EGLint *attrib_list)
914{
915    egl_display_t const* dp = 0;
916    int i=0, index=0;
917    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
918    if (cnx) {
919        EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
920                dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
921        if (surface != EGL_NO_SURFACE) {
922            egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
923            return s;
924        }
925    }
926    return EGL_NO_SURFACE;
927}
928
929EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
930                                    const EGLint *attrib_list)
931{
932    egl_display_t const* dp = 0;
933    int i=0, index=0;
934    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
935    if (cnx) {
936        EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
937                dp->dpys[i], dp->configs[i][index], attrib_list);
938        if (surface != EGL_NO_SURFACE) {
939            egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
940            return s;
941        }
942    }
943    return EGL_NO_SURFACE;
944}
945
946EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
947{
948    SurfaceRef _s(surface);
949    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
950
951    if (!validate_display_surface(dpy, surface))
952        return EGL_FALSE;
953    egl_display_t const * const dp = get_display(dpy);
954
955    egl_surface_t * const s = get_surface(surface);
956    EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
957            dp->dpys[s->impl], s->surface);
958    if (result == EGL_TRUE) {
959        _s.terminate();
960    }
961    return result;
962}
963
964EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
965                            EGLint attribute, EGLint *value)
966{
967    SurfaceRef _s(surface);
968    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
969
970    if (!validate_display_surface(dpy, surface))
971        return EGL_FALSE;
972    egl_display_t const * const dp = get_display(dpy);
973    egl_surface_t const * const s = get_surface(surface);
974
975    return s->cnx->hooks->egl.eglQuerySurface(
976            dp->dpys[s->impl], s->surface, attribute, value);
977}
978
979// ----------------------------------------------------------------------------
980// contextes
981// ----------------------------------------------------------------------------
982
983EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
984                            EGLContext share_list, const EGLint *attrib_list)
985{
986    egl_display_t const* dp = 0;
987    int i=0, index=0;
988    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
989    if (cnx) {
990        EGLContext context = cnx->hooks->egl.eglCreateContext(
991                dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
992        if (context != EGL_NO_CONTEXT) {
993            egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
994            return c;
995        }
996    }
997    return EGL_NO_CONTEXT;
998}
999
1000EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1001{
1002    ContextRef _c(ctx);
1003    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1004
1005    if (!validate_display_context(dpy, ctx))
1006        return EGL_FALSE;
1007    egl_display_t const * const dp = get_display(dpy);
1008    egl_context_t * const c = get_context(ctx);
1009    EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
1010            dp->dpys[c->impl], c->context);
1011    if (result == EGL_TRUE) {
1012        _c.terminate();
1013    }
1014    return result;
1015}
1016
1017EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
1018                            EGLSurface read, EGLContext ctx)
1019{
1020    // get a reference to the object passed in
1021    ContextRef _c(ctx);
1022    SurfaceRef _d(draw);
1023    SurfaceRef _r(read);
1024
1025    // validate the display and the context (if not EGL_NO_CONTEXT)
1026    egl_display_t const * const dp = get_display(dpy);
1027    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1028    if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
1029        // EGL_NO_CONTEXT is valid
1030        return EGL_FALSE;
1031    }
1032
1033    // these are the underlying implementation's object
1034    EGLContext impl_ctx  = EGL_NO_CONTEXT;
1035    EGLSurface impl_draw = EGL_NO_SURFACE;
1036    EGLSurface impl_read = EGL_NO_SURFACE;
1037
1038    // these are our objects structs passed in
1039    egl_context_t       * c = NULL;
1040    egl_surface_t const * d = NULL;
1041    egl_surface_t const * r = NULL;
1042
1043    // these are the current objects structs
1044    egl_context_t * cur_c = get_context(getContext());
1045    egl_surface_t * cur_r = NULL;
1046    egl_surface_t * cur_d = NULL;
1047
1048    if (ctx != EGL_NO_CONTEXT) {
1049        c = get_context(ctx);
1050        cur_r = get_surface(c->read);
1051        cur_d = get_surface(c->draw);
1052        impl_ctx = c->context;
1053    } else {
1054        // no context given, use the implementation of the current context
1055        if (cur_c == NULL) {
1056            // no current context
1057            if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
1058                // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
1059                return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1060            }
1061            // not an error, there is just not current context.
1062            return EGL_TRUE;
1063        }
1064    }
1065
1066    // retrieve the underlying implementation's draw EGLSurface
1067    if (draw != EGL_NO_SURFACE) {
1068        d = get_surface(draw);
1069        // make sure the EGLContext and EGLSurface passed in are for the same driver
1070        if (c && d->impl != c->impl)
1071            return setError(EGL_BAD_MATCH, EGL_FALSE);
1072        impl_draw = d->surface;
1073    }
1074
1075    // retrieve the underlying implementation's read EGLSurface
1076    if (read != EGL_NO_SURFACE) {
1077        r = get_surface(read);
1078        // make sure the EGLContext and EGLSurface passed in are for the same driver
1079        if (c && r->impl != c->impl)
1080            return setError(EGL_BAD_MATCH, EGL_FALSE);
1081        impl_read = r->surface;
1082    }
1083
1084    EGLBoolean result;
1085
1086    if (c) {
1087        result = c->cnx->hooks->egl.eglMakeCurrent(
1088                dp->dpys[c->impl], impl_draw, impl_read, impl_ctx);
1089    } else {
1090        result = cur_c->cnx->hooks->egl.eglMakeCurrent(
1091                dp->dpys[cur_c->impl], impl_draw, impl_read, impl_ctx);
1092    }
1093
1094    if (result == EGL_TRUE) {
1095        // by construction, these are either 0 or valid (possibly terminated)
1096        // it should be impossible for these to be invalid
1097        ContextRef _cur_c(cur_c);
1098        SurfaceRef _cur_r(cur_r);
1099        SurfaceRef _cur_d(cur_d);
1100
1101        // cur_c has to be valid here (but could be terminated)
1102        if (ctx != EGL_NO_CONTEXT) {
1103            setGlThreadSpecific(c->cnx->hooks);
1104            setContext(ctx);
1105            _c.acquire();
1106        } else {
1107            setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
1108            setContext(EGL_NO_CONTEXT);
1109        }
1110        _cur_c.release();
1111
1112        _r.acquire();
1113        _cur_r.release();
1114        if (c) c->read = read;
1115
1116        _d.acquire();
1117        _cur_d.release();
1118        if (c) c->draw = draw;
1119    }
1120    return result;
1121}
1122
1123
1124EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1125                            EGLint attribute, EGLint *value)
1126{
1127    ContextRef _c(ctx);
1128    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1129
1130    if (!validate_display_context(dpy, ctx))
1131        return EGL_FALSE;
1132
1133    egl_display_t const * const dp = get_display(dpy);
1134    egl_context_t * const c = get_context(ctx);
1135
1136    return c->cnx->hooks->egl.eglQueryContext(
1137            dp->dpys[c->impl], c->context, attribute, value);
1138}
1139
1140EGLContext eglGetCurrentContext(void)
1141{
1142    // could be called before eglInitialize(), but we wouldn't have a context
1143    // then, and this function would correctly return EGL_NO_CONTEXT.
1144
1145    EGLContext ctx = getContext();
1146    return ctx;
1147}
1148
1149EGLSurface eglGetCurrentSurface(EGLint readdraw)
1150{
1151    // could be called before eglInitialize(), but we wouldn't have a context
1152    // then, and this function would correctly return EGL_NO_SURFACE.
1153
1154    EGLContext ctx = getContext();
1155    if (ctx) {
1156        egl_context_t const * const c = get_context(ctx);
1157        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1158        switch (readdraw) {
1159            case EGL_READ: return c->read;
1160            case EGL_DRAW: return c->draw;
1161            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1162        }
1163    }
1164    return EGL_NO_SURFACE;
1165}
1166
1167EGLDisplay eglGetCurrentDisplay(void)
1168{
1169    // could be called before eglInitialize(), but we wouldn't have a context
1170    // then, and this function would correctly return EGL_NO_DISPLAY.
1171
1172    EGLContext ctx = getContext();
1173    if (ctx) {
1174        egl_context_t const * const c = get_context(ctx);
1175        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1176        return c->dpy;
1177    }
1178    return EGL_NO_DISPLAY;
1179}
1180
1181EGLBoolean eglWaitGL(void)
1182{
1183    // could be called before eglInitialize(), but we wouldn't have a context
1184    // then, and this function would return GL_TRUE, which isn't wrong.
1185
1186    EGLBoolean res = EGL_TRUE;
1187    EGLContext ctx = getContext();
1188    if (ctx) {
1189        egl_context_t const * const c = get_context(ctx);
1190        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1191        if (uint32_t(c->impl)>=2)
1192            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1193        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1194        if (!cnx->dso)
1195            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1196        res = cnx->hooks->egl.eglWaitGL();
1197    }
1198    return res;
1199}
1200
1201EGLBoolean eglWaitNative(EGLint engine)
1202{
1203    // could be called before eglInitialize(), but we wouldn't have a context
1204    // then, and this function would return GL_TRUE, which isn't wrong.
1205
1206    EGLBoolean res = EGL_TRUE;
1207    EGLContext ctx = getContext();
1208    if (ctx) {
1209        egl_context_t const * const c = get_context(ctx);
1210        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1211        if (uint32_t(c->impl)>=2)
1212            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1213        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1214        if (!cnx->dso)
1215            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1216        res = cnx->hooks->egl.eglWaitNative(engine);
1217    }
1218    return res;
1219}
1220
1221EGLint eglGetError(void)
1222{
1223    EGLint result = EGL_SUCCESS;
1224    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1225        EGLint err = EGL_SUCCESS;
1226        egl_connection_t* const cnx = &gEGLImpl[i];
1227        if (cnx->dso)
1228            err = cnx->hooks->egl.eglGetError();
1229        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1230            result = err;
1231    }
1232    if (result == EGL_SUCCESS)
1233        result = getError();
1234    return result;
1235}
1236
1237__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
1238{
1239    // eglGetProcAddress() could be the very first function called
1240    // in which case we must make sure we've initialized ourselves, this
1241    // happens the first time egl_get_display() is called.
1242
1243    if (egl_init_drivers() == EGL_FALSE) {
1244        setError(EGL_BAD_PARAMETER, NULL);
1245        return  NULL;
1246    }
1247
1248    __eglMustCastToProperFunctionPointerType addr;
1249    addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1250    if (addr) return addr;
1251
1252    return NULL; // TODO: finish implementation below
1253
1254    addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1255    if (addr) return addr;
1256
1257    addr = 0;
1258    int slot = -1;
1259    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1260        egl_connection_t* const cnx = &gEGLImpl[i];
1261        if (cnx->dso) {
1262            if (cnx->hooks->egl.eglGetProcAddress) {
1263                addr = cnx->hooks->egl.eglGetProcAddress(procname);
1264                if (addr) {
1265                    if (slot == -1) {
1266                        slot = 0; // XXX: find free slot
1267                        if (slot == -1) {
1268                            addr = 0;
1269                            break;
1270                        }
1271                    }
1272                    cnx->hooks->ext.extensions[slot] = addr;
1273                }
1274            }
1275        }
1276    }
1277
1278    if (slot >= 0) {
1279        addr = 0; // XXX: address of stub 'slot'
1280        gGLExtentionMap[slot].name = strdup(procname);
1281        gGLExtentionMap[slot].address = addr;
1282    }
1283
1284    return addr;
1285
1286
1287    /*
1288     *  TODO: For OpenGL ES extensions, we must generate a stub
1289     *  that looks like
1290     *      mov     r12, #0xFFFF0FFF
1291     *      ldr     r12, [r12, #-15]
1292     *      ldr     r12, [r12, #TLS_SLOT_OPENGL_API*4]
1293     *      mov     r12, [r12, #api_offset]
1294     *      ldrne   pc, r12
1295     *      mov     pc, #unsupported_extension
1296     *
1297     *  and write the address of the extension in *all*
1298     *  gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1299     *
1300     */
1301}
1302
1303EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1304{
1305    SurfaceRef _s(draw);
1306    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1307
1308    if (!validate_display_surface(dpy, draw))
1309        return EGL_FALSE;
1310    egl_display_t const * const dp = get_display(dpy);
1311    egl_surface_t const * const s = get_surface(draw);
1312    return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1313}
1314
1315EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1316                            NativePixmapType target)
1317{
1318    SurfaceRef _s(surface);
1319    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1320
1321    if (!validate_display_surface(dpy, surface))
1322        return EGL_FALSE;
1323    egl_display_t const * const dp = get_display(dpy);
1324    egl_surface_t const * const s = get_surface(surface);
1325    return s->cnx->hooks->egl.eglCopyBuffers(
1326            dp->dpys[s->impl], s->surface, target);
1327}
1328
1329const char* eglQueryString(EGLDisplay dpy, EGLint name)
1330{
1331    egl_display_t const * const dp = get_display(dpy);
1332    switch (name) {
1333        case EGL_VENDOR:
1334            return gVendorString;
1335        case EGL_VERSION:
1336            return gVersionString;
1337        case EGL_EXTENSIONS:
1338            return gExtensionString;
1339        case EGL_CLIENT_APIS:
1340            return gClientApiString;
1341    }
1342    return setError(EGL_BAD_PARAMETER, (const char *)0);
1343}
1344
1345
1346// ----------------------------------------------------------------------------
1347// EGL 1.1
1348// ----------------------------------------------------------------------------
1349
1350EGLBoolean eglSurfaceAttrib(
1351        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1352{
1353    SurfaceRef _s(surface);
1354    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1355
1356    if (!validate_display_surface(dpy, surface))
1357        return EGL_FALSE;
1358    egl_display_t const * const dp = get_display(dpy);
1359    egl_surface_t const * const s = get_surface(surface);
1360    if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1361        return s->cnx->hooks->egl.eglSurfaceAttrib(
1362                dp->dpys[s->impl], s->surface, attribute, value);
1363    }
1364    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1365}
1366
1367EGLBoolean eglBindTexImage(
1368        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1369{
1370    SurfaceRef _s(surface);
1371    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1372
1373    if (!validate_display_surface(dpy, surface))
1374        return EGL_FALSE;
1375    egl_display_t const * const dp = get_display(dpy);
1376    egl_surface_t const * const s = get_surface(surface);
1377    if (s->cnx->hooks->egl.eglBindTexImage) {
1378        return s->cnx->hooks->egl.eglBindTexImage(
1379                dp->dpys[s->impl], s->surface, buffer);
1380    }
1381    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1382}
1383
1384EGLBoolean eglReleaseTexImage(
1385        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1386{
1387    SurfaceRef _s(surface);
1388    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1389
1390    if (!validate_display_surface(dpy, surface))
1391        return EGL_FALSE;
1392    egl_display_t const * const dp = get_display(dpy);
1393    egl_surface_t const * const s = get_surface(surface);
1394    if (s->cnx->hooks->egl.eglReleaseTexImage) {
1395        return s->cnx->hooks->egl.eglReleaseTexImage(
1396                dp->dpys[s->impl], s->surface, buffer);
1397    }
1398    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1399}
1400
1401EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1402{
1403    egl_display_t * const dp = get_display(dpy);
1404    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1405
1406    EGLBoolean res = EGL_TRUE;
1407    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1408        egl_connection_t* const cnx = &gEGLImpl[i];
1409        if (cnx->dso) {
1410            if (cnx->hooks->egl.eglSwapInterval) {
1411                if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1412                    res = EGL_FALSE;
1413                }
1414            }
1415        }
1416    }
1417    return res;
1418}
1419
1420
1421// ----------------------------------------------------------------------------
1422// EGL 1.2
1423// ----------------------------------------------------------------------------
1424
1425EGLBoolean eglWaitClient(void)
1426{
1427    // could be called before eglInitialize(), but we wouldn't have a context
1428    // then, and this function would return GL_TRUE, which isn't wrong.
1429    EGLBoolean res = EGL_TRUE;
1430    EGLContext ctx = getContext();
1431    if (ctx) {
1432        egl_context_t const * const c = get_context(ctx);
1433        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1434        if (uint32_t(c->impl)>=2)
1435            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1436        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1437        if (!cnx->dso)
1438            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1439        if (cnx->hooks->egl.eglWaitClient) {
1440            res = cnx->hooks->egl.eglWaitClient();
1441        } else {
1442            res = cnx->hooks->egl.eglWaitGL();
1443        }
1444    }
1445    return res;
1446}
1447
1448EGLBoolean eglBindAPI(EGLenum api)
1449{
1450    if (egl_init_drivers() == EGL_FALSE) {
1451        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1452    }
1453
1454    // bind this API on all EGLs
1455    EGLBoolean res = EGL_TRUE;
1456    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1457        egl_connection_t* const cnx = &gEGLImpl[i];
1458        if (cnx->dso) {
1459            if (cnx->hooks->egl.eglBindAPI) {
1460                if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1461                    res = EGL_FALSE;
1462                }
1463            }
1464        }
1465    }
1466    return res;
1467}
1468
1469EGLenum eglQueryAPI(void)
1470{
1471    if (egl_init_drivers() == EGL_FALSE) {
1472        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1473    }
1474
1475    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1476        egl_connection_t* const cnx = &gEGLImpl[i];
1477        if (cnx->dso) {
1478            if (cnx->hooks->egl.eglQueryAPI) {
1479                // the first one we find is okay, because they all
1480                // should be the same
1481                return cnx->hooks->egl.eglQueryAPI();
1482            }
1483        }
1484    }
1485    // or, it can only be OpenGL ES
1486    return EGL_OPENGL_ES_API;
1487}
1488
1489EGLBoolean eglReleaseThread(void)
1490{
1491    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1492        egl_connection_t* const cnx = &gEGLImpl[i];
1493        if (cnx->dso) {
1494            if (cnx->hooks->egl.eglReleaseThread) {
1495                cnx->hooks->egl.eglReleaseThread();
1496            }
1497        }
1498    }
1499    clearTLS();
1500    return EGL_TRUE;
1501}
1502
1503EGLSurface eglCreatePbufferFromClientBuffer(
1504          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1505          EGLConfig config, const EGLint *attrib_list)
1506{
1507    egl_display_t const* dp = 0;
1508    int i=0, index=0;
1509    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1510    if (!cnx) return EGL_FALSE;
1511    if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1512        return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1513                dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1514    }
1515    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1516}
1517
1518// ----------------------------------------------------------------------------
1519// EGL_EGLEXT_VERSION 3
1520// ----------------------------------------------------------------------------
1521
1522EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1523        const EGLint *attrib_list)
1524{
1525    SurfaceRef _s(surface);
1526    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1527
1528    if (!validate_display_surface(dpy, surface))
1529        return EGL_FALSE;
1530
1531    egl_display_t const * const dp = get_display(dpy);
1532    egl_surface_t const * const s = get_surface(surface);
1533
1534    if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
1535        return s->cnx->hooks->egl.eglLockSurfaceKHR(
1536                dp->dpys[s->impl], s->surface, attrib_list);
1537    }
1538    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1539}
1540
1541EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1542{
1543    SurfaceRef _s(surface);
1544    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1545
1546    if (!validate_display_surface(dpy, surface))
1547        return EGL_FALSE;
1548
1549    egl_display_t const * const dp = get_display(dpy);
1550    egl_surface_t const * const s = get_surface(surface);
1551
1552    if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
1553        return s->cnx->hooks->egl.eglUnlockSurfaceKHR(
1554                dp->dpys[s->impl], s->surface);
1555    }
1556    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1557}
1558
1559EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1560        EGLClientBuffer buffer, const EGLint *attrib_list)
1561{
1562    if (ctx != EGL_NO_CONTEXT) {
1563        ContextRef _c(ctx);
1564        if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1565        if (!validate_display_context(dpy, ctx))
1566            return EGL_NO_IMAGE_KHR;
1567        egl_display_t const * const dp = get_display(dpy);
1568        egl_context_t * const c = get_context(ctx);
1569        // since we have an EGLContext, we know which implementation to use
1570        EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
1571                dp->dpys[c->impl], c->context, target, buffer, attrib_list);
1572        if (image == EGL_NO_IMAGE_KHR)
1573            return image;
1574
1575        egl_image_t* result = new egl_image_t(dpy, ctx);
1576        result->images[c->impl] = image;
1577        return (EGLImageKHR)result;
1578    } else {
1579        // EGL_NO_CONTEXT is a valid parameter
1580        egl_display_t const * const dp = get_display(dpy);
1581        if (dp == 0) {
1582            return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1583        }
1584        // since we don't have a way to know which implementation to call,
1585        // we're calling all of them
1586
1587        EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
1588        bool success = false;
1589        for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1590            egl_connection_t* const cnx = &gEGLImpl[i];
1591            implImages[i] = EGL_NO_IMAGE_KHR;
1592            if (cnx->dso) {
1593                if (cnx->hooks->egl.eglCreateImageKHR) {
1594                    implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
1595                            dp->dpys[i], ctx, target, buffer, attrib_list);
1596                    if (implImages[i] != EGL_NO_IMAGE_KHR) {
1597                        success = true;
1598                    }
1599                }
1600            }
1601        }
1602        if (!success)
1603            return EGL_NO_IMAGE_KHR;
1604
1605        egl_image_t* result = new egl_image_t(dpy, ctx);
1606        memcpy(result->images, implImages, sizeof(implImages));
1607        return (EGLImageKHR)result;
1608    }
1609}
1610
1611EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1612{
1613    egl_display_t const * const dp = get_display(dpy);
1614     if (dp == 0) {
1615         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1616     }
1617
1618     ImageRef _i(img);
1619     if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1620
1621     egl_image_t* image = get_image(img);
1622     bool success = false;
1623     for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1624         egl_connection_t* const cnx = &gEGLImpl[i];
1625         if (image->images[i] != EGL_NO_IMAGE_KHR) {
1626             if (cnx->dso) {
1627                 if (cnx->hooks->egl.eglCreateImageKHR) {
1628                     if (cnx->hooks->egl.eglDestroyImageKHR(
1629                             dp->dpys[i], image->images[i])) {
1630                         success = true;
1631                     }
1632                 }
1633             }
1634         }
1635     }
1636     if (!success)
1637         return EGL_FALSE;
1638
1639     _i.terminate();
1640
1641     return EGL_TRUE;
1642}
1643
1644
1645// ----------------------------------------------------------------------------
1646// ANDROID extensions
1647// ----------------------------------------------------------------------------
1648
1649EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1650        EGLint left, EGLint top, EGLint width, EGLint height)
1651{
1652    SurfaceRef _s(draw);
1653    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1654
1655    if (!validate_display_surface(dpy, draw))
1656        return EGL_FALSE;
1657    egl_display_t const * const dp = get_display(dpy);
1658    egl_surface_t const * const s = get_surface(draw);
1659    if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) {
1660        return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(dp->dpys[s->impl],
1661                s->surface, left, top, width, height);
1662    }
1663    return setError(EGL_BAD_DISPLAY, NULL);
1664}
1665
1666EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
1667{
1668    SurfaceRef _s(draw);
1669    if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
1670
1671    if (!validate_display_surface(dpy, draw))
1672        return 0;
1673    egl_display_t const * const dp = get_display(dpy);
1674    egl_surface_t const * const s = get_surface(draw);
1675    if (s->cnx->hooks->egl.eglGetRenderBufferANDROID) {
1676        return s->cnx->hooks->egl.eglGetRenderBufferANDROID(dp->dpys[s->impl],
1677                s->surface);
1678    }
1679    return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
1680}
1681