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