egl.cpp revision 43aa2b1cbf7a03e248e10f4d0fec0463257cd52d
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#define LOG_TAG "GLLogger"
18
19#include <ctype.h>
20#include <string.h>
21#include <errno.h>
22#include <dlfcn.h>
23
24#include <sys/ioctl.h>
25
26#if HAVE_ANDROID_OS
27#include <linux/android_pmem.h>
28#endif
29
30#include <EGL/egl.h>
31#include <EGL/eglext.h>
32#include <GLES/gl.h>
33#include <GLES/glext.h>
34
35#include <cutils/log.h>
36#include <cutils/atomic.h>
37#include <cutils/properties.h>
38#include <cutils/memory.h>
39
40#include <utils/RefBase.h>
41
42#include "hooks.h"
43#include "egl_impl.h"
44
45
46#define MAKE_CONFIG(_impl, _index)  ((EGLConfig)(((_impl)<<24) | (_index)))
47#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
48
49// ----------------------------------------------------------------------------
50namespace android {
51// ----------------------------------------------------------------------------
52
53#define VERSION_MINOR 1
54#define VERSION_MAJOR 4
55static char const * const gVendorString     = "Android";
56static char const * const gVersionString    = "1.31 Android META-EGL";
57static char const * const gClientApiString  = "OpenGL ES";
58static char const * const gExtensionString  = "";
59
60template <int MAGIC>
61struct egl_object_t
62{
63    egl_object_t() : magic(MAGIC) { }
64    ~egl_object_t() { magic = 0; }
65    bool isValid() const { return magic == MAGIC; }
66private:
67    uint32_t    magic;
68};
69
70struct egl_display_t : public egl_object_t<'_dpy'>
71{
72    EGLDisplay  dpys[2];
73    EGLConfig*  configs[2];
74    EGLint      numConfigs[2];
75    EGLint      numTotalConfigs;
76    char const* extensionsString;
77    volatile int32_t refs;
78    struct strings_t {
79        char const * vendor;
80        char const * version;
81        char const * clientApi;
82        char const * extensions;
83    };
84    strings_t   queryString[2];
85};
86
87struct egl_surface_t : public egl_object_t<'_srf'>
88{
89    egl_surface_t(EGLDisplay dpy, EGLSurface surface,
90            NativeWindowType window, int impl, egl_connection_t const* cnx)
91    : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
92    {
93        // NOTE: window must be incRef'ed and connected already
94    }
95    ~egl_surface_t() {
96        if (window) {
97            if (window->disconnect)
98                window->disconnect(window);
99            window->decRef(window);
100        }
101    }
102    EGLDisplay                  dpy;
103    EGLSurface                  surface;
104    NativeWindowType            window;
105    int                         impl;
106    egl_connection_t const*     cnx;
107};
108
109struct egl_context_t : public egl_object_t<'_ctx'>
110{
111    egl_context_t(EGLDisplay dpy, EGLContext context,
112            int impl, egl_connection_t const* cnx)
113    : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
114    {
115    }
116    EGLDisplay                  dpy;
117    EGLContext                  context;
118    EGLSurface                  read;
119    EGLSurface                  draw;
120    int                         impl;
121    egl_connection_t const*     cnx;
122};
123
124struct tls_t
125{
126    tls_t() : error(EGL_SUCCESS), ctx(0) { }
127    EGLint      error;
128    EGLContext  ctx;
129};
130
131static void gl_unimplemented() {
132    LOGE("called unimplemented OpenGL ES API");
133}
134
135// ----------------------------------------------------------------------------
136// GL / EGL hooks
137// ----------------------------------------------------------------------------
138
139#undef GL_ENTRY
140#undef EGL_ENTRY
141#define GL_ENTRY(_r, _api, ...) #_api,
142#define EGL_ENTRY(_r, _api, ...) #_api,
143
144static char const * const gl_names[] = {
145    #include "gl_entries.in"
146    NULL
147};
148
149static char const * const egl_names[] = {
150    #include "egl_entries.in"
151    NULL
152};
153
154#undef GL_ENTRY
155#undef EGL_ENTRY
156
157// ----------------------------------------------------------------------------
158
159egl_connection_t gEGLImpl[2];
160static egl_display_t gDisplay[NUM_DISPLAYS];
161static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
162static pthread_key_t gEGLThreadLocalStorageKey = -1;
163
164// ----------------------------------------------------------------------------
165
166gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
167pthread_key_t gGLWrapperKey = -1;
168
169// ----------------------------------------------------------------------------
170
171static __attribute__((noinline))
172const char *egl_strerror(EGLint err)
173{
174    switch (err){
175        case EGL_SUCCESS:               return "EGL_SUCCESS";
176        case EGL_NOT_INITIALIZED:       return "EGL_NOT_INITIALIZED";
177        case EGL_BAD_ACCESS:            return "EGL_BAD_ACCESS";
178        case EGL_BAD_ALLOC:             return "EGL_BAD_ALLOC";
179        case EGL_BAD_ATTRIBUTE:         return "EGL_BAD_ATTRIBUTE";
180        case EGL_BAD_CONFIG:            return "EGL_BAD_CONFIG";
181        case EGL_BAD_CONTEXT:           return "EGL_BAD_CONTEXT";
182        case EGL_BAD_CURRENT_SURFACE:   return "EGL_BAD_CURRENT_SURFACE";
183        case EGL_BAD_DISPLAY:           return "EGL_BAD_DISPLAY";
184        case EGL_BAD_MATCH:             return "EGL_BAD_MATCH";
185        case EGL_BAD_NATIVE_PIXMAP:     return "EGL_BAD_NATIVE_PIXMAP";
186        case EGL_BAD_NATIVE_WINDOW:     return "EGL_BAD_NATIVE_WINDOW";
187        case EGL_BAD_PARAMETER:         return "EGL_BAD_PARAMETER";
188        case EGL_BAD_SURFACE:           return "EGL_BAD_SURFACE";
189        case EGL_CONTEXT_LOST:          return "EGL_CONTEXT_LOST";
190        default: return "UNKNOWN";
191    }
192}
193
194static __attribute__((noinline))
195void clearTLS() {
196    if (gEGLThreadLocalStorageKey != -1) {
197        tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
198        if (tls) {
199            delete tls;
200            pthread_setspecific(gEGLThreadLocalStorageKey, 0);
201        }
202    }
203}
204
205static tls_t* getTLS()
206{
207    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
208    if (tls == 0) {
209        tls = new tls_t;
210        pthread_setspecific(gEGLThreadLocalStorageKey, tls);
211    }
212    return tls;
213}
214
215template<typename T>
216static __attribute__((noinline))
217T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
218    if (gEGLThreadLocalStorageKey == -1) {
219        pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
220        if (gEGLThreadLocalStorageKey == -1)
221            pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
222        pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
223    }
224    tls_t* tls = getTLS();
225    if (tls->error != error) {
226        LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
227        tls->error = error;
228    }
229    return returnValue;
230}
231
232static __attribute__((noinline))
233GLint getError() {
234    if (gEGLThreadLocalStorageKey == -1)
235        return EGL_SUCCESS;
236    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
237    if (!tls) return EGL_SUCCESS;
238    GLint error = tls->error;
239    tls->error = EGL_SUCCESS;
240    return error;
241}
242
243static __attribute__((noinline))
244void setContext(EGLContext ctx) {
245    if (gEGLThreadLocalStorageKey == -1) {
246        pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
247        if (gEGLThreadLocalStorageKey == -1)
248            pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
249        pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
250    }
251    tls_t* tls = getTLS();
252    tls->ctx = ctx;
253}
254
255static __attribute__((noinline))
256EGLContext getContext() {
257    if (gEGLThreadLocalStorageKey == -1)
258        return EGL_NO_CONTEXT;
259    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
260    if (!tls) return EGL_NO_CONTEXT;
261    return tls->ctx;
262}
263
264
265/*****************************************************************************/
266
267class ISurfaceComposer;
268const sp<ISurfaceComposer>& getSurfaceFlinger();
269request_gpu_t* gpu_acquire(void* user);
270int gpu_release(void*, request_gpu_t* gpu);
271
272static __attribute__((noinline))
273void *load_driver(const char* driver, gl_hooks_t* hooks)
274{
275    void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
276    LOGE_IF(!dso,
277            "couldn't load <%s> library (%s)",
278            driver, dlerror());
279
280    if (dso) {
281        void** curr;
282        char const * const * api;
283        gl_hooks_t::gl_t* gl = &hooks->gl;
284        curr = (void**)gl;
285        api = gl_names;
286        while (*api) {
287            void* f = dlsym(dso, *api);
288            //LOGD("<%s> @ 0x%p", *api, f);
289            if (f == NULL) {
290                //LOGW("<%s> not found in %s", *api, driver);
291                f = (void*)gl_unimplemented;
292            }
293            *curr++ = f;
294            api++;
295        }
296        gl_hooks_t::egl_t* egl = &hooks->egl;
297        curr = (void**)egl;
298        api = egl_names;
299        while (*api) {
300            void* f = dlsym(dso, *api);
301            if (f == NULL) {
302                //LOGW("<%s> not found in %s", *api, driver);
303                f = (void*)0;
304            }
305            *curr++ = f;
306            api++;
307        }
308
309        // hook this driver up with surfaceflinger if needed
310        register_gpu_t register_gpu =
311            (register_gpu_t)dlsym(dso, "oem_register_gpu");
312
313        if (register_gpu != NULL) {
314            if (getSurfaceFlinger() != 0) {
315                register_gpu(dso, gpu_acquire, gpu_release);
316            }
317        }
318    }
319    return dso;
320}
321
322template<typename T>
323static __attribute__((noinline))
324int binarySearch(
325        T const sortedArray[], int first, int last, T key)
326{
327    while (first <= last) {
328        int mid = (first + last) / 2;
329        if (key > sortedArray[mid]) {
330            first = mid + 1;
331        } else if (key < sortedArray[mid]) {
332            last = mid - 1;
333        } else {
334            return mid;
335        }
336    }
337    return -1;
338}
339
340static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
341{
342    // NOTE: this mapping works only if we have no more than two EGLimpl
343    return (i>0 ? dp->numConfigs[0] : 0) + index;
344}
345
346static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
347        int& i, int& index)
348{
349    // NOTE: this mapping works only if we have no more than two EGLimpl
350    size_t numConfigs = dp->numConfigs[0];
351    i = configId / numConfigs;
352    index = configId % numConfigs;
353}
354
355static int cmp_configs(const void* a, const void *b)
356{
357    EGLConfig c0 = *(EGLConfig const *)a;
358    EGLConfig c1 = *(EGLConfig const *)b;
359    return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
360}
361
362struct extention_map_t {
363    const char* name;
364    __eglMustCastToProperFunctionPointerType address;
365};
366
367static const extention_map_t gExtentionMap[] = {
368};
369
370static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
371
372static void(*findProcAddress(const char* name,
373        const extention_map_t* map, size_t n))()
374{
375    for (uint32_t i=0 ; i<n ; i++) {
376        if (!strcmp(name, map[i].name)) {
377            return map[i].address;
378        }
379    }
380    return NULL;
381}
382
383// ----------------------------------------------------------------------------
384
385static int gl_context_lost() {
386    setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
387    return 0;
388}
389static int egl_context_lost() {
390    setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
391    return EGL_FALSE;
392}
393static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
394    usleep(100000); // don't use all the CPU
395    setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
396    return EGL_FALSE;
397}
398static GLint egl_context_lost_get_error() {
399    return EGL_CONTEXT_LOST;
400}
401static int ext_context_lost() {
402    return 0;
403}
404
405static void gl_no_context() {
406    LOGE("call to OpenGL ES API with no current context");
407}
408static void early_egl_init(void)
409{
410#if !USE_FAST_TLS_KEY
411    pthread_key_create(&gGLWrapperKey, NULL);
412#endif
413    uint32_t addr = (uint32_t)((void*)gl_no_context);
414    android_memset32(
415            (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
416            addr,
417            sizeof(gHooks[IMPL_NO_CONTEXT]));
418    setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
419}
420
421static pthread_once_t once_control = PTHREAD_ONCE_INIT;
422static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
423
424
425static inline
426egl_display_t* get_display(EGLDisplay dpy)
427{
428    uintptr_t index = uintptr_t(dpy)-1U;
429    return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
430}
431
432static inline
433egl_surface_t* get_surface(EGLSurface surface)
434{
435    egl_surface_t* s = (egl_surface_t *)surface;
436    return s;
437}
438
439static inline
440egl_context_t* get_context(EGLContext context)
441{
442    egl_context_t* c = (egl_context_t *)context;
443    return c;
444}
445
446static egl_connection_t* validate_display_config(
447        EGLDisplay dpy, EGLConfig config,
448        egl_display_t const*& dp, int& impl, int& index)
449{
450    dp = get_display(dpy);
451    if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
452
453    impl = uintptr_t(config)>>24;
454    if (uint32_t(impl) >= 2) {
455        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
456    }
457    index = uintptr_t(config) & 0xFFFFFF;
458    if (index >= dp->numConfigs[impl]) {
459        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
460    }
461    egl_connection_t* const cnx = &gEGLImpl[impl];
462    if (cnx->dso == 0) {
463        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
464    }
465    return cnx;
466}
467
468static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
469{
470    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
471        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
472    if (!get_display(dpy)->isValid())
473        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
474    if (!ctx) // TODO: make sure context is a valid object
475        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
476    if (!get_context(ctx)->isValid())
477        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
478    return EGL_TRUE;
479}
480
481static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
482{
483    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
484        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
485    if (!get_display(dpy)->isValid())
486        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
487    if (!surface) // TODO: make sure surface is a valid object
488        return setError(EGL_BAD_SURFACE, EGL_FALSE);
489    if (!get_surface(surface)->isValid())
490        return setError(EGL_BAD_SURFACE, EGL_FALSE);
491    return EGL_TRUE;
492}
493
494// ----------------------------------------------------------------------------
495}; // namespace android
496// ----------------------------------------------------------------------------
497
498using namespace android;
499
500EGLDisplay eglGetDisplay(NativeDisplayType display)
501{
502    if (sEarlyInitState) {
503        return EGL_NO_DISPLAY;
504    }
505
506    uint32_t index = uint32_t(display);
507    if (index >= NUM_DISPLAYS) {
508        return EGL_NO_DISPLAY;
509    }
510
511    EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
512    egl_display_t* d = &gDisplay[index];
513
514    // dynamically load all our EGL implementations for that display
515    // and call into the real eglGetGisplay()
516    egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
517    if (cnx->dso == 0) {
518        cnx->hooks = &gHooks[IMPL_SOFTWARE];
519        cnx->dso = load_driver("libagl.so", cnx->hooks);
520    }
521    if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
522        d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
523        LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
524                "No EGLDisplay for software EGL!");
525    }
526
527    cnx = &gEGLImpl[IMPL_HARDWARE];
528    if (cnx->dso == 0 && cnx->unavailable == 0) {
529        char value[PROPERTY_VALUE_MAX];
530        property_get("debug.egl.hw", value, "1");
531        if (atoi(value) != 0) {
532            cnx->hooks = &gHooks[IMPL_HARDWARE];
533            cnx->dso = load_driver("libhgl.so", cnx->hooks);
534        } else {
535            LOGD("3D hardware acceleration is disabled");
536        }
537    }
538    if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
539        android_memset32(
540                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
541                (uint32_t)((void*)gl_context_lost),
542                sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
543        android_memset32(
544                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
545                (uint32_t)((void*)egl_context_lost),
546                sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
547        android_memset32(
548                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
549                (uint32_t)((void*)ext_context_lost),
550                sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
551
552        gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
553                egl_context_lost_swap_buffers;
554
555        gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
556                egl_context_lost_get_error;
557
558        gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
559                gHooks[IMPL_HARDWARE].egl.eglTerminate;
560
561        d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
562        if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
563            LOGE("h/w accelerated eglGetDisplay() failed (%s)",
564                    egl_strerror(cnx->hooks->egl.eglGetError()));
565            dlclose((void*)cnx->dso);
566            cnx->dso = 0;
567            // in case of failure, we want to make sure we don't try again
568            // as it's expensive.
569            cnx->unavailable = 1;
570        }
571    }
572
573    return dpy;
574}
575
576// ----------------------------------------------------------------------------
577// Initialization
578// ----------------------------------------------------------------------------
579
580EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
581{
582    egl_display_t * const dp = get_display(dpy);
583    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
584
585    if (android_atomic_inc(&dp->refs) > 0) {
586        if (major != NULL) *major = VERSION_MAJOR;
587        if (minor != NULL) *minor = VERSION_MINOR;
588        return EGL_TRUE;
589    }
590
591    setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
592
593    // initialize each EGL and
594    // build our own extension string first, based on the extension we know
595    // and the extension supported by our client implementation
596    dp->extensionsString = strdup(gExtensionString);
597    for (int i=0 ; i<2 ; i++) {
598        egl_connection_t* const cnx = &gEGLImpl[i];
599        cnx->major = -1;
600        cnx->minor = -1;
601        if (!cnx->dso)
602            continue;
603
604        if (cnx->hooks->egl.eglInitialize(
605                dp->dpys[i], &cnx->major, &cnx->minor)) {
606
607            //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
608            //        i, dp->dpys[i], cnx->major, cnx->minor, cnx);
609
610            // get the query-strings for this display for each implementation
611            dp->queryString[i].vendor =
612                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
613            dp->queryString[i].version =
614                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
615            dp->queryString[i].extensions = strdup(
616                    cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
617            dp->queryString[i].clientApi =
618                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
619
620        } else {
621            LOGD("%d: eglInitialize() failed (%s)",
622                    i, egl_strerror(cnx->hooks->egl.eglGetError()));
623        }
624    }
625
626    EGLBoolean res = EGL_FALSE;
627    for (int i=0 ; i<2 ; i++) {
628        egl_connection_t* const cnx = &gEGLImpl[i];
629        if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
630            EGLint n;
631            if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
632                dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
633                if (dp->configs[i]) {
634                    if (cnx->hooks->egl.eglGetConfigs(
635                            dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
636                    {
637                        // sort the configurations so we can do binary searches
638                        qsort(  dp->configs[i],
639                                dp->numConfigs[i],
640                                sizeof(EGLConfig), cmp_configs);
641
642                        dp->numTotalConfigs += n;
643                        res = EGL_TRUE;
644                    }
645                }
646            }
647        }
648    }
649
650    if (res == EGL_TRUE) {
651        if (major != NULL) *major = 1;
652        if (minor != NULL) *minor = 2;
653        return EGL_TRUE;
654    }
655    return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
656}
657
658EGLBoolean eglTerminate(EGLDisplay dpy)
659{
660    egl_display_t* const dp = get_display(dpy);
661    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
662    if (android_atomic_dec(&dp->refs) != 1)
663        return EGL_TRUE;
664
665    EGLBoolean res = EGL_FALSE;
666    for (int i=0 ; i<2 ; i++) {
667        egl_connection_t* const cnx = &gEGLImpl[i];
668        if (cnx->dso) {
669            cnx->hooks->egl.eglTerminate(dp->dpys[i]);
670
671            /* REVISIT: it's unclear what to do if eglTerminate() fails,
672             * on one end we shouldn't care, on the other end if it fails
673             * it might not be safe to call dlclose() (there could be some
674             * threads around). */
675
676            free(dp->configs[i]);
677            free((void*)dp->queryString[i].extensions);
678            dp->numConfigs[i] = 0;
679            dp->dpys[i] = EGL_NO_DISPLAY;
680            dlclose((void*)cnx->dso);
681            cnx->dso = 0;
682            res = EGL_TRUE;
683        }
684    }
685    free((void*)dp->extensionsString);
686    dp->extensionsString = 0;
687    dp->numTotalConfigs = 0;
688    clearTLS();
689    return res;
690}
691
692// ----------------------------------------------------------------------------
693// configuration
694// ----------------------------------------------------------------------------
695
696EGLBoolean eglGetConfigs(   EGLDisplay dpy,
697                            EGLConfig *configs,
698                            EGLint config_size, EGLint *num_config)
699{
700    egl_display_t const * const dp = get_display(dpy);
701    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
702
703    GLint numConfigs = dp->numTotalConfigs;
704    if (!configs) {
705        *num_config = numConfigs;
706        return EGL_TRUE;
707    }
708    GLint n = 0;
709    for (int j=0 ; j<2 ; j++) {
710        for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
711            *configs++ = MAKE_CONFIG(j, i);
712            config_size--;
713            n++;
714        }
715    }
716
717    *num_config = n;
718    return EGL_TRUE;
719}
720
721EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
722                            EGLConfig *configs, EGLint config_size,
723                            EGLint *num_config)
724{
725    egl_display_t const * const dp = get_display(dpy);
726    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
727
728    if (configs == 0) {
729        *num_config = 0;
730        return EGL_TRUE;
731    }
732
733    EGLint n;
734    EGLBoolean res = EGL_FALSE;
735    *num_config = 0;
736
737
738    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
739    // to do  this, we have to go through the attrib_list array once
740    // to figure out both its size and if it contains an EGL_CONFIG_ID
741    // key. If so, the full array is copied and patched.
742    // NOTE: we assume that there can be only one occurrence
743    // of EGL_CONFIG_ID.
744
745    EGLint patch_index = -1;
746    GLint attr;
747    size_t size = 0;
748    while ((attr=attrib_list[size])) {
749        if (attr == EGL_CONFIG_ID)
750            patch_index = size;
751        size += 2;
752    }
753    if (patch_index >= 0) {
754        size += 2; // we need copy the sentinel as well
755        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
756        if (new_list == 0)
757            return setError(EGL_BAD_ALLOC, EGL_FALSE);
758        memcpy(new_list, attrib_list, size*sizeof(EGLint));
759
760        // patch the requested EGL_CONFIG_ID
761        int i, index;
762        EGLint& configId(new_list[patch_index+1]);
763        uniqueIdToConfig(dp, configId, i, index);
764
765        egl_connection_t* const cnx = &gEGLImpl[i];
766        if (cnx->dso) {
767            cnx->hooks->egl.eglGetConfigAttrib(
768                    dp->dpys[i], dp->configs[i][index],
769                    EGL_CONFIG_ID, &configId);
770
771            // and switch to the new list
772            attrib_list = const_cast<const EGLint *>(new_list);
773
774            // At this point, the only configuration that can match is
775            // dp->configs[i][index], however, we don't know if it would be
776            // rejected because of the other attributes, so we do have to call
777            // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
778            // through all the EGLimpl[].
779            // We also know we can only get a single config back, and we know
780            // which one.
781
782            res = cnx->hooks->egl.eglChooseConfig(
783                    dp->dpys[i], attrib_list, configs, config_size, &n);
784            if (res && n>0) {
785                // n has to be 0 or 1, by construction, and we already know
786                // which config it will return (since there can be only one).
787                configs[0] = MAKE_CONFIG(i, index);
788                *num_config = 1;
789            }
790        }
791
792        free(const_cast<EGLint *>(attrib_list));
793        return res;
794    }
795
796    for (int i=0 ; i<2 ; i++) {
797        egl_connection_t* const cnx = &gEGLImpl[i];
798        if (cnx->dso) {
799            if (cnx->hooks->egl.eglChooseConfig(
800                    dp->dpys[i], attrib_list, configs, config_size, &n)) {
801                // now we need to convert these client EGLConfig to our
802                // internal EGLConfig format. This is done in O(n log n).
803                for (int j=0 ; j<n ; j++) {
804                    int index = binarySearch<EGLConfig>(
805                            dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
806                    if (index >= 0) {
807                        configs[j] = MAKE_CONFIG(i, index);
808                    } else {
809                        return setError(EGL_BAD_CONFIG, EGL_FALSE);
810                    }
811                }
812                configs += n;
813                config_size -= n;
814                *num_config += n;
815                res = EGL_TRUE;
816            }
817        }
818    }
819    return res;
820}
821
822EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
823        EGLint attribute, EGLint *value)
824{
825    egl_display_t const* dp = 0;
826    int i=0, index=0;
827    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
828    if (!cnx) return EGL_FALSE;
829
830    if (attribute == EGL_CONFIG_ID) {
831        // EGL_CONFIG_IDs must be unique, just use the order of the selected
832        // EGLConfig.
833        *value = configToUniqueId(dp, i, index);
834        return EGL_TRUE;
835    }
836    return cnx->hooks->egl.eglGetConfigAttrib(
837            dp->dpys[i], dp->configs[i][index], attribute, value);
838}
839
840// ----------------------------------------------------------------------------
841// surfaces
842// ----------------------------------------------------------------------------
843
844EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
845                                    NativeWindowType window,
846                                    const EGLint *attrib_list)
847{
848    egl_display_t const* dp = 0;
849    int i=0, index=0;
850    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
851    if (cnx) {
852        // window must be connected upon calling underlying
853        // eglCreateWindowSurface
854        if (window) {
855            window->incRef(window);
856            if (window->connect)
857                window->connect(window);
858        }
859
860        EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
861                dp->dpys[i], dp->configs[i][index], window, attrib_list);
862        if (surface != EGL_NO_SURFACE) {
863            egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
864            return s;
865        }
866
867        // something went wrong, disconnect and free window
868        // (will disconnect() automatically)
869        if (window) {
870            window->decRef(window);
871        }
872    }
873    return EGL_NO_SURFACE;
874}
875
876EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
877                                    NativePixmapType pixmap,
878                                    const EGLint *attrib_list)
879{
880    egl_display_t const* dp = 0;
881    int i=0, index=0;
882    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
883    if (cnx) {
884        EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
885                dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
886        if (surface != EGL_NO_SURFACE) {
887            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
888            return s;
889        }
890    }
891    return EGL_NO_SURFACE;
892}
893
894EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
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.eglCreatePbufferSurface(
902                dp->dpys[i], dp->configs[i][index], attrib_list);
903        if (surface != EGL_NO_SURFACE) {
904            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
905            return s;
906        }
907    }
908    return EGL_NO_SURFACE;
909}
910
911EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
912{
913    if (!validate_display_surface(dpy, surface))
914        return EGL_FALSE;
915    egl_display_t const * const dp = get_display(dpy);
916    egl_surface_t const * const s = get_surface(surface);
917
918    EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
919            dp->dpys[s->impl], s->surface);
920
921    delete s;
922    return result;
923}
924
925EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
926                            EGLint attribute, EGLint *value)
927{
928    if (!validate_display_surface(dpy, surface))
929        return EGL_FALSE;
930    egl_display_t const * const dp = get_display(dpy);
931    egl_surface_t const * const s = get_surface(surface);
932
933    return s->cnx->hooks->egl.eglQuerySurface(
934            dp->dpys[s->impl], s->surface, attribute, value);
935}
936
937// ----------------------------------------------------------------------------
938// contextes
939// ----------------------------------------------------------------------------
940
941EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
942                            EGLContext share_list, const EGLint *attrib_list)
943{
944    egl_display_t const* dp = 0;
945    int i=0, index=0;
946    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
947    if (cnx) {
948        EGLContext context = cnx->hooks->egl.eglCreateContext(
949                dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
950        if (context != EGL_NO_CONTEXT) {
951            egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
952            return c;
953        }
954    }
955    return EGL_NO_CONTEXT;
956}
957
958EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
959{
960    if (!validate_display_context(dpy, ctx))
961        return EGL_FALSE;
962    egl_display_t const * const dp = get_display(dpy);
963    egl_context_t * const c = get_context(ctx);
964    EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
965            dp->dpys[c->impl], c->context);
966    delete c;
967    return result;
968}
969
970EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
971                            EGLSurface read, EGLContext ctx)
972{
973    egl_display_t const * const dp = get_display(dpy);
974    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
975
976    if (read == EGL_NO_SURFACE && draw  == EGL_NO_SURFACE &&
977            ctx == EGL_NO_CONTEXT)
978    {
979        EGLBoolean result = EGL_TRUE;
980        ctx = getContext();
981        if (ctx) {
982            egl_context_t * const c = get_context(ctx);
983            result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
984            if (result == EGL_TRUE) {
985                setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
986                setContext(EGL_NO_CONTEXT);
987            }
988        }
989        return result;
990    }
991
992    if (!validate_display_context(dpy, ctx))
993        return EGL_FALSE;
994
995    egl_context_t * const c = get_context(ctx);
996    if (draw != EGL_NO_SURFACE) {
997        egl_surface_t const * d = get_surface(draw);
998        if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
999        if (d->impl != c->impl)
1000            return setError(EGL_BAD_MATCH, EGL_FALSE);
1001        draw = d->surface;
1002    }
1003    if (read != EGL_NO_SURFACE) {
1004        egl_surface_t const * r = get_surface(read);
1005        if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1006        if (r->impl != c->impl)
1007            return setError(EGL_BAD_MATCH, EGL_FALSE);
1008        read = r->surface;
1009    }
1010    EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1011            dp->dpys[c->impl], draw, read, c->context);
1012
1013    if (result == EGL_TRUE) {
1014        setGlThreadSpecific(c->cnx->hooks);
1015        setContext(ctx);
1016        c->read = read;
1017        c->draw = draw;
1018    }
1019    return result;
1020}
1021
1022
1023EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1024                            EGLint attribute, EGLint *value)
1025{
1026    if (!validate_display_context(dpy, ctx))
1027        return EGL_FALSE;
1028
1029    egl_display_t const * const dp = get_display(dpy);
1030    egl_context_t * const c = get_context(ctx);
1031
1032    return c->cnx->hooks->egl.eglQueryContext(
1033            dp->dpys[c->impl], c->context, attribute, value);
1034}
1035
1036EGLContext eglGetCurrentContext(void)
1037{
1038    EGLContext ctx = getContext();
1039    return ctx;
1040}
1041
1042EGLSurface eglGetCurrentSurface(EGLint readdraw)
1043{
1044    EGLContext ctx = getContext();
1045    if (ctx) {
1046        egl_context_t const * const c = get_context(ctx);
1047        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1048        switch (readdraw) {
1049            case EGL_READ: return c->read;
1050            case EGL_DRAW: return c->draw;
1051            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1052        }
1053    }
1054    return EGL_NO_SURFACE;
1055}
1056
1057EGLDisplay eglGetCurrentDisplay(void)
1058{
1059    EGLContext ctx = getContext();
1060    if (ctx) {
1061        egl_context_t const * const c = get_context(ctx);
1062        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1063        return c->dpy;
1064    }
1065    return EGL_NO_DISPLAY;
1066}
1067
1068EGLBoolean eglWaitGL(void)
1069{
1070    EGLBoolean res = EGL_TRUE;
1071    EGLContext ctx = getContext();
1072    if (ctx) {
1073        egl_context_t const * const c = get_context(ctx);
1074        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1075        if (uint32_t(c->impl)>=2)
1076            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1077        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1078        if (!cnx->dso)
1079            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1080        res = cnx->hooks->egl.eglWaitGL();
1081    }
1082    return res;
1083}
1084
1085EGLBoolean eglWaitNative(EGLint engine)
1086{
1087    EGLBoolean res = EGL_TRUE;
1088    EGLContext ctx = getContext();
1089    if (ctx) {
1090        egl_context_t const * const c = get_context(ctx);
1091        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1092        if (uint32_t(c->impl)>=2)
1093            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1094        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1095        if (!cnx->dso)
1096            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1097        res = cnx->hooks->egl.eglWaitNative(engine);
1098    }
1099    return res;
1100}
1101
1102EGLint eglGetError(void)
1103{
1104    EGLint result = EGL_SUCCESS;
1105    for (int i=0 ; i<2 ; i++) {
1106        EGLint err = EGL_SUCCESS;
1107        egl_connection_t* const cnx = &gEGLImpl[i];
1108        if (cnx->dso)
1109            err = cnx->hooks->egl.eglGetError();
1110        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1111            result = err;
1112    }
1113    if (result == EGL_SUCCESS)
1114        result = getError();
1115    return result;
1116}
1117
1118void (*eglGetProcAddress(const char *procname))()
1119{
1120    __eglMustCastToProperFunctionPointerType addr;
1121    addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1122    if (addr) return addr;
1123
1124    return NULL; // TODO: finish implementation below
1125
1126    addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1127    if (addr) return addr;
1128
1129    addr = 0;
1130    int slot = -1;
1131    for (int i=0 ; i<2 ; i++) {
1132        egl_connection_t* const cnx = &gEGLImpl[i];
1133        if (cnx->dso) {
1134            if (cnx->hooks->egl.eglGetProcAddress) {
1135                addr = cnx->hooks->egl.eglGetProcAddress(procname);
1136                if (addr) {
1137                    if (slot == -1) {
1138                        slot = 0; // XXX: find free slot
1139                        if (slot == -1) {
1140                            addr = 0;
1141                            break;
1142                        }
1143                    }
1144                    cnx->hooks->ext.extensions[slot] = addr;
1145                }
1146            }
1147        }
1148    }
1149
1150    if (slot >= 0) {
1151        addr = 0; // XXX: address of stub 'slot'
1152        gGLExtentionMap[slot].name = strdup(procname);
1153        gGLExtentionMap[slot].address = addr;
1154    }
1155
1156    return addr;
1157
1158
1159    /*
1160     *  TODO: For OpenGL ES extensions, we must generate a stub
1161     *  that looks like
1162     *      mov     r12, #0xFFFF0FFF
1163     *      ldr     r12, [r12, #-15]
1164     *      ldr     r12, [r12, #TLS_SLOT_OPENGL_API*4]
1165     *      mov     r12, [r12, #api_offset]
1166     *      ldrne   pc, r12
1167     *      mov     pc, #unsupported_extension
1168     *
1169     *  and write the address of the extension in *all*
1170     *  gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1171     *
1172     */
1173}
1174
1175EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1176{
1177    if (!validate_display_surface(dpy, draw))
1178        return EGL_FALSE;
1179    egl_display_t const * const dp = get_display(dpy);
1180    egl_surface_t const * const s = get_surface(draw);
1181    return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1182}
1183
1184EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1185                            NativePixmapType target)
1186{
1187    if (!validate_display_surface(dpy, surface))
1188        return EGL_FALSE;
1189    egl_display_t const * const dp = get_display(dpy);
1190    egl_surface_t const * const s = get_surface(surface);
1191    return s->cnx->hooks->egl.eglCopyBuffers(
1192            dp->dpys[s->impl], s->surface, target);
1193}
1194
1195const char* eglQueryString(EGLDisplay dpy, EGLint name)
1196{
1197    egl_display_t const * const dp = get_display(dpy);
1198    switch (name) {
1199        case EGL_VENDOR:
1200            return gVendorString;
1201        case EGL_VERSION:
1202            return gVersionString;
1203        case EGL_EXTENSIONS:
1204            return gExtensionString;
1205        case EGL_CLIENT_APIS:
1206            return gClientApiString;
1207    }
1208    return setError(EGL_BAD_PARAMETER, (const char *)0);
1209}
1210
1211
1212// ----------------------------------------------------------------------------
1213// EGL 1.1
1214// ----------------------------------------------------------------------------
1215
1216EGLBoolean eglSurfaceAttrib(
1217        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1218{
1219    if (!validate_display_surface(dpy, surface))
1220        return EGL_FALSE;
1221    egl_display_t const * const dp = get_display(dpy);
1222    egl_surface_t const * const s = get_surface(surface);
1223    if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1224        return s->cnx->hooks->egl.eglSurfaceAttrib(
1225                dp->dpys[s->impl], s->surface, attribute, value);
1226    }
1227    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1228}
1229
1230EGLBoolean eglBindTexImage(
1231        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1232{
1233    if (!validate_display_surface(dpy, surface))
1234        return EGL_FALSE;
1235    egl_display_t const * const dp = get_display(dpy);
1236    egl_surface_t const * const s = get_surface(surface);
1237    if (s->cnx->hooks->egl.eglBindTexImage) {
1238        return s->cnx->hooks->egl.eglBindTexImage(
1239                dp->dpys[s->impl], s->surface, buffer);
1240    }
1241    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1242}
1243
1244EGLBoolean eglReleaseTexImage(
1245        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1246{
1247    if (!validate_display_surface(dpy, surface))
1248        return EGL_FALSE;
1249    egl_display_t const * const dp = get_display(dpy);
1250    egl_surface_t const * const s = get_surface(surface);
1251    if (s->cnx->hooks->egl.eglReleaseTexImage) {
1252        return s->cnx->hooks->egl.eglReleaseTexImage(
1253                dp->dpys[s->impl], s->surface, buffer);
1254    }
1255    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1256}
1257
1258EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1259{
1260    egl_display_t * const dp = get_display(dpy);
1261    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1262
1263    EGLBoolean res = EGL_TRUE;
1264    for (int i=0 ; i<2 ; i++) {
1265        egl_connection_t* const cnx = &gEGLImpl[i];
1266        if (cnx->dso) {
1267            if (cnx->hooks->egl.eglSwapInterval) {
1268                if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1269                    res = EGL_FALSE;
1270                }
1271            }
1272        }
1273    }
1274    return res;
1275}
1276
1277
1278// ----------------------------------------------------------------------------
1279// EGL 1.2
1280// ----------------------------------------------------------------------------
1281
1282EGLBoolean eglWaitClient(void)
1283{
1284    EGLBoolean res = EGL_TRUE;
1285    EGLContext ctx = getContext();
1286    if (ctx) {
1287        egl_context_t const * const c = get_context(ctx);
1288        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1289        if (uint32_t(c->impl)>=2)
1290            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1291        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1292        if (!cnx->dso)
1293            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1294        if (cnx->hooks->egl.eglWaitClient) {
1295            res = cnx->hooks->egl.eglWaitClient();
1296        } else {
1297            res = cnx->hooks->egl.eglWaitGL();
1298        }
1299    }
1300    return res;
1301}
1302
1303EGLBoolean eglBindAPI(EGLenum api)
1304{
1305    // bind this API on all EGLs
1306    EGLBoolean res = EGL_TRUE;
1307    for (int i=0 ; i<2 ; i++) {
1308        egl_connection_t* const cnx = &gEGLImpl[i];
1309        if (cnx->dso) {
1310            if (cnx->hooks->egl.eglBindAPI) {
1311                if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1312                    res = EGL_FALSE;
1313                }
1314            }
1315        }
1316    }
1317    return res;
1318}
1319
1320EGLenum eglQueryAPI(void)
1321{
1322    for (int i=0 ; i<2 ; i++) {
1323        egl_connection_t* const cnx = &gEGLImpl[i];
1324        if (cnx->dso) {
1325            if (cnx->hooks->egl.eglQueryAPI) {
1326                // the first one we find is okay, because they all
1327                // should be the same
1328                return cnx->hooks->egl.eglQueryAPI();
1329            }
1330        }
1331    }
1332    // or, it can only be OpenGL ES
1333    return EGL_OPENGL_ES_API;
1334}
1335
1336EGLBoolean eglReleaseThread(void)
1337{
1338    for (int i=0 ; i<2 ; i++) {
1339        egl_connection_t* const cnx = &gEGLImpl[i];
1340        if (cnx->dso) {
1341            if (cnx->hooks->egl.eglReleaseThread) {
1342                cnx->hooks->egl.eglReleaseThread();
1343            }
1344        }
1345    }
1346    clearTLS();
1347    return EGL_TRUE;
1348}
1349
1350EGLSurface eglCreatePbufferFromClientBuffer(
1351          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1352          EGLConfig config, const EGLint *attrib_list)
1353{
1354    egl_display_t const* dp = 0;
1355    int i=0, index=0;
1356    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1357    if (!cnx) return EGL_FALSE;
1358    if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1359        return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1360                dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1361    }
1362    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1363}
1364