egl.cpp revision a6938bab1f6fa76ae98ebbe44f4e534e05fa0993
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            property_get("debug.egl.profiler", value, "0");
534            if (atoi(value) == 0) {
535                cnx->dso = load_driver("libhgl.so", cnx->hooks);
536            } else {
537                LOGW("Using instrumented h/w OpenGL ES library");
538                cnx->dso = load_driver("libhgld.so", cnx->hooks);
539            }
540        } else {
541            LOGD("3D hardware acceleration is disabled");
542        }
543    }
544    if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
545        android_memset32(
546                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
547                (uint32_t)((void*)gl_context_lost),
548                sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
549        android_memset32(
550                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
551                (uint32_t)((void*)egl_context_lost),
552                sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
553        android_memset32(
554                (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
555                (uint32_t)((void*)ext_context_lost),
556                sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
557
558        gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
559                egl_context_lost_swap_buffers;
560
561        gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
562                egl_context_lost_get_error;
563
564        gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
565                gHooks[IMPL_HARDWARE].egl.eglTerminate;
566
567        d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
568        if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
569            LOGE("h/w accelerated eglGetDisplay() failed (%s)",
570                    egl_strerror(cnx->hooks->egl.eglGetError()));
571            dlclose((void*)cnx->dso);
572            cnx->dso = 0;
573            // in case of failure, we want to make sure we don't try again
574            // as it's expensive.
575            cnx->unavailable = 1;
576        }
577    }
578
579    return dpy;
580}
581
582// ----------------------------------------------------------------------------
583// Initialization
584// ----------------------------------------------------------------------------
585
586EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
587{
588    egl_display_t * const dp = get_display(dpy);
589    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
590
591    if (android_atomic_inc(&dp->refs) > 0) {
592        if (major != NULL) *major = VERSION_MAJOR;
593        if (minor != NULL) *minor = VERSION_MINOR;
594        return EGL_TRUE;
595    }
596
597    setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
598
599    // initialize each EGL and
600    // build our own extension string first, based on the extension we know
601    // and the extension supported by our client implementation
602    dp->extensionsString = strdup(gExtensionString);
603    for (int i=0 ; i<2 ; i++) {
604        egl_connection_t* const cnx = &gEGLImpl[i];
605        cnx->major = -1;
606        cnx->minor = -1;
607        if (!cnx->dso)
608            continue;
609
610        if (cnx->hooks->egl.eglInitialize(
611                dp->dpys[i], &cnx->major, &cnx->minor)) {
612
613            //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
614            //        i, dp->dpys[i], cnx->major, cnx->minor, cnx);
615
616            // get the query-strings for this display for each implementation
617            dp->queryString[i].vendor =
618                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
619            dp->queryString[i].version =
620                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
621            dp->queryString[i].extensions = strdup(
622                    cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
623            dp->queryString[i].clientApi =
624                cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
625
626        } else {
627            LOGD("%d: eglInitialize() failed (%s)",
628                    i, egl_strerror(cnx->hooks->egl.eglGetError()));
629        }
630    }
631
632    EGLBoolean res = EGL_FALSE;
633    for (int i=0 ; i<2 ; i++) {
634        egl_connection_t* const cnx = &gEGLImpl[i];
635        if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
636            EGLint n;
637            if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
638                dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
639                if (dp->configs[i]) {
640                    if (cnx->hooks->egl.eglGetConfigs(
641                            dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
642                    {
643                        // sort the configurations so we can do binary searches
644                        qsort(  dp->configs[i],
645                                dp->numConfigs[i],
646                                sizeof(EGLConfig), cmp_configs);
647
648                        dp->numTotalConfigs += n;
649                        res = EGL_TRUE;
650                    }
651                }
652            }
653        }
654    }
655
656    if (res == EGL_TRUE) {
657        if (major != NULL) *major = 1;
658        if (minor != NULL) *minor = 2;
659        return EGL_TRUE;
660    }
661    return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
662}
663
664EGLBoolean eglTerminate(EGLDisplay dpy)
665{
666    egl_display_t* const dp = get_display(dpy);
667    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
668    if (android_atomic_dec(&dp->refs) != 1)
669        return EGL_TRUE;
670
671    EGLBoolean res = EGL_FALSE;
672    for (int i=0 ; i<2 ; i++) {
673        egl_connection_t* const cnx = &gEGLImpl[i];
674        if (cnx->dso) {
675            cnx->hooks->egl.eglTerminate(dp->dpys[i]);
676
677            /* REVISIT: it's unclear what to do if eglTerminate() fails,
678             * on one end we shouldn't care, on the other end if it fails
679             * it might not be safe to call dlclose() (there could be some
680             * threads around). */
681
682            free(dp->configs[i]);
683            free((void*)dp->queryString[i].extensions);
684            dp->numConfigs[i] = 0;
685            dp->dpys[i] = EGL_NO_DISPLAY;
686            dlclose((void*)cnx->dso);
687            cnx->dso = 0;
688            res = EGL_TRUE;
689        }
690    }
691    free((void*)dp->extensionsString);
692    dp->extensionsString = 0;
693    dp->numTotalConfigs = 0;
694    clearTLS();
695    return res;
696}
697
698// ----------------------------------------------------------------------------
699// configuration
700// ----------------------------------------------------------------------------
701
702EGLBoolean eglGetConfigs(   EGLDisplay dpy,
703                            EGLConfig *configs,
704                            EGLint config_size, EGLint *num_config)
705{
706    egl_display_t const * const dp = get_display(dpy);
707    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
708
709    GLint numConfigs = dp->numTotalConfigs;
710    if (!configs) {
711        *num_config = numConfigs;
712        return EGL_TRUE;
713    }
714    GLint n = 0;
715    for (int j=0 ; j<2 ; j++) {
716        for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
717            *configs++ = MAKE_CONFIG(j, i);
718            config_size--;
719            n++;
720        }
721    }
722
723    *num_config = n;
724    return EGL_TRUE;
725}
726
727EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
728                            EGLConfig *configs, EGLint config_size,
729                            EGLint *num_config)
730{
731    egl_display_t const * const dp = get_display(dpy);
732    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
733
734    if (configs == 0) {
735        *num_config = 0;
736        return EGL_TRUE;
737    }
738
739    EGLint n;
740    EGLBoolean res = EGL_FALSE;
741    *num_config = 0;
742
743
744    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
745    // to do  this, we have to go through the attrib_list array once
746    // to figure out both its size and if it contains an EGL_CONFIG_ID
747    // key. If so, the full array is copied and patched.
748    // NOTE: we assume that there can be only one occurrence
749    // of EGL_CONFIG_ID.
750
751    EGLint patch_index = -1;
752    GLint attr;
753    size_t size = 0;
754    while ((attr=attrib_list[size])) {
755        if (attr == EGL_CONFIG_ID)
756            patch_index = size;
757        size += 2;
758    }
759    if (patch_index >= 0) {
760        size += 2; // we need copy the sentinel as well
761        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
762        if (new_list == 0)
763            return setError(EGL_BAD_ALLOC, EGL_FALSE);
764        memcpy(new_list, attrib_list, size*sizeof(EGLint));
765
766        // patch the requested EGL_CONFIG_ID
767        int i, index;
768        EGLint& configId(new_list[patch_index+1]);
769        uniqueIdToConfig(dp, configId, i, index);
770
771        egl_connection_t* const cnx = &gEGLImpl[i];
772        if (cnx->dso) {
773            cnx->hooks->egl.eglGetConfigAttrib(
774                    dp->dpys[i], dp->configs[i][index],
775                    EGL_CONFIG_ID, &configId);
776
777            // and switch to the new list
778            attrib_list = const_cast<const EGLint *>(new_list);
779
780            // At this point, the only configuration that can match is
781            // dp->configs[i][index], however, we don't know if it would be
782            // rejected because of the other attributes, so we do have to call
783            // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
784            // through all the EGLimpl[].
785            // We also know we can only get a single config back, and we know
786            // which one.
787
788            res = cnx->hooks->egl.eglChooseConfig(
789                    dp->dpys[i], attrib_list, configs, config_size, &n);
790            if (res && n>0) {
791                // n has to be 0 or 1, by construction, and we already know
792                // which config it will return (since there can be only one).
793                configs[0] = MAKE_CONFIG(i, index);
794                *num_config = 1;
795            }
796        }
797
798        free(const_cast<EGLint *>(attrib_list));
799        return res;
800    }
801
802    for (int i=0 ; i<2 ; i++) {
803        egl_connection_t* const cnx = &gEGLImpl[i];
804        if (cnx->dso) {
805            if (cnx->hooks->egl.eglChooseConfig(
806                    dp->dpys[i], attrib_list, configs, config_size, &n)) {
807                // now we need to convert these client EGLConfig to our
808                // internal EGLConfig format. This is done in O(n log n).
809                for (int j=0 ; j<n ; j++) {
810                    int index = binarySearch<EGLConfig>(
811                            dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
812                    if (index >= 0) {
813                        configs[j] = MAKE_CONFIG(i, index);
814                    } else {
815                        return setError(EGL_BAD_CONFIG, EGL_FALSE);
816                    }
817                }
818                configs += n;
819                config_size -= n;
820                *num_config += n;
821                res = EGL_TRUE;
822            }
823        }
824    }
825    return res;
826}
827
828EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
829        EGLint attribute, EGLint *value)
830{
831    egl_display_t const* dp = 0;
832    int i=0, index=0;
833    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
834    if (!cnx) return EGL_FALSE;
835
836    if (attribute == EGL_CONFIG_ID) {
837        // EGL_CONFIG_IDs must be unique, just use the order of the selected
838        // EGLConfig.
839        *value = configToUniqueId(dp, i, index);
840        return EGL_TRUE;
841    }
842    return cnx->hooks->egl.eglGetConfigAttrib(
843            dp->dpys[i], dp->configs[i][index], attribute, value);
844}
845
846// ----------------------------------------------------------------------------
847// surfaces
848// ----------------------------------------------------------------------------
849
850EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
851                                    NativeWindowType window,
852                                    const EGLint *attrib_list)
853{
854    egl_display_t const* dp = 0;
855    int i=0, index=0;
856    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
857    if (cnx) {
858        // window must be connected upon calling underlying
859        // eglCreateWindowSurface
860        if (window) {
861            window->incRef(window);
862            if (window->connect)
863                window->connect(window);
864        }
865
866        EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
867                dp->dpys[i], dp->configs[i][index], window, attrib_list);
868        if (surface != EGL_NO_SURFACE) {
869            egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
870            return s;
871        }
872
873        // something went wrong, disconnect and free window
874        // (will disconnect() automatically)
875        if (window) {
876            window->decRef(window);
877        }
878    }
879    return EGL_NO_SURFACE;
880}
881
882EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
883                                    NativePixmapType pixmap,
884                                    const EGLint *attrib_list)
885{
886    egl_display_t const* dp = 0;
887    int i=0, index=0;
888    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
889    if (cnx) {
890        EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
891                dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
892        if (surface != EGL_NO_SURFACE) {
893            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
894            return s;
895        }
896    }
897    return EGL_NO_SURFACE;
898}
899
900EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
901                                    const EGLint *attrib_list)
902{
903    egl_display_t const* dp = 0;
904    int i=0, index=0;
905    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
906    if (cnx) {
907        EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
908                dp->dpys[i], dp->configs[i][index], attrib_list);
909        if (surface != EGL_NO_SURFACE) {
910            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
911            return s;
912        }
913    }
914    return EGL_NO_SURFACE;
915}
916
917EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
918{
919    if (!validate_display_surface(dpy, surface))
920        return EGL_FALSE;
921    egl_display_t const * const dp = get_display(dpy);
922    egl_surface_t const * const s = get_surface(surface);
923
924    EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
925            dp->dpys[s->impl], s->surface);
926
927    delete s;
928    return result;
929}
930
931EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
932                            EGLint attribute, EGLint *value)
933{
934    if (!validate_display_surface(dpy, surface))
935        return EGL_FALSE;
936    egl_display_t const * const dp = get_display(dpy);
937    egl_surface_t const * const s = get_surface(surface);
938
939    return s->cnx->hooks->egl.eglQuerySurface(
940            dp->dpys[s->impl], s->surface, attribute, value);
941}
942
943// ----------------------------------------------------------------------------
944// contextes
945// ----------------------------------------------------------------------------
946
947EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
948                            EGLContext share_list, 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        EGLContext context = cnx->hooks->egl.eglCreateContext(
955                dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
956        if (context != EGL_NO_CONTEXT) {
957            egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
958            return c;
959        }
960    }
961    return EGL_NO_CONTEXT;
962}
963
964EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
965{
966    if (!validate_display_context(dpy, ctx))
967        return EGL_FALSE;
968    egl_display_t const * const dp = get_display(dpy);
969    egl_context_t * const c = get_context(ctx);
970    EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
971            dp->dpys[c->impl], c->context);
972    delete c;
973    return result;
974}
975
976EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
977                            EGLSurface read, EGLContext ctx)
978{
979    egl_display_t const * const dp = get_display(dpy);
980    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
981
982    if (read == EGL_NO_SURFACE && draw  == EGL_NO_SURFACE &&
983            ctx == EGL_NO_CONTEXT)
984    {
985        EGLBoolean result = EGL_TRUE;
986        ctx = getContext();
987        if (ctx) {
988            egl_context_t * const c = get_context(ctx);
989            result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
990            if (result == EGL_TRUE) {
991                setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
992                setContext(EGL_NO_CONTEXT);
993            }
994        }
995        return result;
996    }
997
998    if (!validate_display_context(dpy, ctx))
999        return EGL_FALSE;
1000
1001    egl_context_t * const c = get_context(ctx);
1002    if (draw != EGL_NO_SURFACE) {
1003        egl_surface_t const * d = get_surface(draw);
1004        if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1005        if (d->impl != c->impl)
1006            return setError(EGL_BAD_MATCH, EGL_FALSE);
1007        draw = d->surface;
1008    }
1009    if (read != EGL_NO_SURFACE) {
1010        egl_surface_t const * r = get_surface(read);
1011        if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1012        if (r->impl != c->impl)
1013            return setError(EGL_BAD_MATCH, EGL_FALSE);
1014        read = r->surface;
1015    }
1016    EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1017            dp->dpys[c->impl], draw, read, c->context);
1018
1019    if (result == EGL_TRUE) {
1020        setGlThreadSpecific(c->cnx->hooks);
1021        setContext(ctx);
1022        c->read = read;
1023        c->draw = draw;
1024    }
1025    return result;
1026}
1027
1028
1029EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1030                            EGLint attribute, EGLint *value)
1031{
1032    if (!validate_display_context(dpy, ctx))
1033        return EGL_FALSE;
1034
1035    egl_display_t const * const dp = get_display(dpy);
1036    egl_context_t * const c = get_context(ctx);
1037
1038    return c->cnx->hooks->egl.eglQueryContext(
1039            dp->dpys[c->impl], c->context, attribute, value);
1040}
1041
1042EGLContext eglGetCurrentContext(void)
1043{
1044    EGLContext ctx = getContext();
1045    return ctx;
1046}
1047
1048EGLSurface eglGetCurrentSurface(EGLint readdraw)
1049{
1050    EGLContext ctx = getContext();
1051    if (ctx) {
1052        egl_context_t const * const c = get_context(ctx);
1053        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1054        switch (readdraw) {
1055            case EGL_READ: return c->read;
1056            case EGL_DRAW: return c->draw;
1057            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1058        }
1059    }
1060    return EGL_NO_SURFACE;
1061}
1062
1063EGLDisplay eglGetCurrentDisplay(void)
1064{
1065    EGLContext ctx = getContext();
1066    if (ctx) {
1067        egl_context_t const * const c = get_context(ctx);
1068        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1069        return c->dpy;
1070    }
1071    return EGL_NO_DISPLAY;
1072}
1073
1074EGLBoolean eglWaitGL(void)
1075{
1076    EGLBoolean res = EGL_TRUE;
1077    EGLContext ctx = getContext();
1078    if (ctx) {
1079        egl_context_t const * const c = get_context(ctx);
1080        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1081        if (uint32_t(c->impl)>=2)
1082            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1083        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1084        if (!cnx->dso)
1085            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1086        res = cnx->hooks->egl.eglWaitGL();
1087    }
1088    return res;
1089}
1090
1091EGLBoolean eglWaitNative(EGLint engine)
1092{
1093    EGLBoolean res = EGL_TRUE;
1094    EGLContext ctx = getContext();
1095    if (ctx) {
1096        egl_context_t const * const c = get_context(ctx);
1097        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1098        if (uint32_t(c->impl)>=2)
1099            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1100        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1101        if (!cnx->dso)
1102            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1103        res = cnx->hooks->egl.eglWaitNative(engine);
1104    }
1105    return res;
1106}
1107
1108EGLint eglGetError(void)
1109{
1110    EGLint result = EGL_SUCCESS;
1111    for (int i=0 ; i<2 ; i++) {
1112        EGLint err = EGL_SUCCESS;
1113        egl_connection_t* const cnx = &gEGLImpl[i];
1114        if (cnx->dso)
1115            err = cnx->hooks->egl.eglGetError();
1116        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1117            result = err;
1118    }
1119    if (result == EGL_SUCCESS)
1120        result = getError();
1121    return result;
1122}
1123
1124void (*eglGetProcAddress(const char *procname))()
1125{
1126    __eglMustCastToProperFunctionPointerType addr;
1127    addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1128    if (addr) return addr;
1129
1130    return NULL; // TODO: finish implementation below
1131
1132    addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1133    if (addr) return addr;
1134
1135    addr = 0;
1136    int slot = -1;
1137    for (int i=0 ; i<2 ; i++) {
1138        egl_connection_t* const cnx = &gEGLImpl[i];
1139        if (cnx->dso) {
1140            if (cnx->hooks->egl.eglGetProcAddress) {
1141                addr = cnx->hooks->egl.eglGetProcAddress(procname);
1142                if (addr) {
1143                    if (slot == -1) {
1144                        slot = 0; // XXX: find free slot
1145                        if (slot == -1) {
1146                            addr = 0;
1147                            break;
1148                        }
1149                    }
1150                    cnx->hooks->ext.extensions[slot] = addr;
1151                }
1152            }
1153        }
1154    }
1155
1156    if (slot >= 0) {
1157        addr = 0; // XXX: address of stub 'slot'
1158        gGLExtentionMap[slot].name = strdup(procname);
1159        gGLExtentionMap[slot].address = addr;
1160    }
1161
1162    return addr;
1163
1164
1165    /*
1166     *  TODO: For OpenGL ES extensions, we must generate a stub
1167     *  that looks like
1168     *      mov     r12, #0xFFFF0FFF
1169     *      ldr     r12, [r12, #-15]
1170     *      ldr     r12, [r12, #TLS_SLOT_OPENGL_API*4]
1171     *      mov     r12, [r12, #api_offset]
1172     *      ldrne   pc, r12
1173     *      mov     pc, #unsupported_extension
1174     *
1175     *  and write the address of the extension in *all*
1176     *  gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1177     *
1178     */
1179}
1180
1181EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1182{
1183    if (!validate_display_surface(dpy, draw))
1184        return EGL_FALSE;
1185    egl_display_t const * const dp = get_display(dpy);
1186    egl_surface_t const * const s = get_surface(draw);
1187    return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1188}
1189
1190EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1191                            NativePixmapType target)
1192{
1193    if (!validate_display_surface(dpy, surface))
1194        return EGL_FALSE;
1195    egl_display_t const * const dp = get_display(dpy);
1196    egl_surface_t const * const s = get_surface(surface);
1197    return s->cnx->hooks->egl.eglCopyBuffers(
1198            dp->dpys[s->impl], s->surface, target);
1199}
1200
1201const char* eglQueryString(EGLDisplay dpy, EGLint name)
1202{
1203    egl_display_t const * const dp = get_display(dpy);
1204    switch (name) {
1205        case EGL_VENDOR:
1206            return gVendorString;
1207        case EGL_VERSION:
1208            return gVersionString;
1209        case EGL_EXTENSIONS:
1210            return gExtensionString;
1211        case EGL_CLIENT_APIS:
1212            return gClientApiString;
1213    }
1214    return setError(EGL_BAD_PARAMETER, (const char *)0);
1215}
1216
1217
1218// ----------------------------------------------------------------------------
1219// EGL 1.1
1220// ----------------------------------------------------------------------------
1221
1222EGLBoolean eglSurfaceAttrib(
1223        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1224{
1225    if (!validate_display_surface(dpy, surface))
1226        return EGL_FALSE;
1227    egl_display_t const * const dp = get_display(dpy);
1228    egl_surface_t const * const s = get_surface(surface);
1229    if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1230        return s->cnx->hooks->egl.eglSurfaceAttrib(
1231                dp->dpys[s->impl], s->surface, attribute, value);
1232    }
1233    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1234}
1235
1236EGLBoolean eglBindTexImage(
1237        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1238{
1239    if (!validate_display_surface(dpy, surface))
1240        return EGL_FALSE;
1241    egl_display_t const * const dp = get_display(dpy);
1242    egl_surface_t const * const s = get_surface(surface);
1243    if (s->cnx->hooks->egl.eglBindTexImage) {
1244        return s->cnx->hooks->egl.eglBindTexImage(
1245                dp->dpys[s->impl], s->surface, buffer);
1246    }
1247    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1248}
1249
1250EGLBoolean eglReleaseTexImage(
1251        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1252{
1253    if (!validate_display_surface(dpy, surface))
1254        return EGL_FALSE;
1255    egl_display_t const * const dp = get_display(dpy);
1256    egl_surface_t const * const s = get_surface(surface);
1257    if (s->cnx->hooks->egl.eglReleaseTexImage) {
1258        return s->cnx->hooks->egl.eglReleaseTexImage(
1259                dp->dpys[s->impl], s->surface, buffer);
1260    }
1261    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1262}
1263
1264EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1265{
1266    egl_display_t * const dp = get_display(dpy);
1267    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1268
1269    EGLBoolean res = EGL_TRUE;
1270    for (int i=0 ; i<2 ; i++) {
1271        egl_connection_t* const cnx = &gEGLImpl[i];
1272        if (cnx->dso) {
1273            if (cnx->hooks->egl.eglSwapInterval) {
1274                if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1275                    res = EGL_FALSE;
1276                }
1277            }
1278        }
1279    }
1280    return res;
1281}
1282
1283
1284// ----------------------------------------------------------------------------
1285// EGL 1.2
1286// ----------------------------------------------------------------------------
1287
1288EGLBoolean eglWaitClient(void)
1289{
1290    EGLBoolean res = EGL_TRUE;
1291    EGLContext ctx = getContext();
1292    if (ctx) {
1293        egl_context_t const * const c = get_context(ctx);
1294        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1295        if (uint32_t(c->impl)>=2)
1296            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1297        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1298        if (!cnx->dso)
1299            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1300        if (cnx->hooks->egl.eglWaitClient) {
1301            res = cnx->hooks->egl.eglWaitClient();
1302        } else {
1303            res = cnx->hooks->egl.eglWaitGL();
1304        }
1305    }
1306    return res;
1307}
1308
1309EGLBoolean eglBindAPI(EGLenum api)
1310{
1311    // bind this API on all EGLs
1312    EGLBoolean res = EGL_TRUE;
1313    for (int i=0 ; i<2 ; i++) {
1314        egl_connection_t* const cnx = &gEGLImpl[i];
1315        if (cnx->dso) {
1316            if (cnx->hooks->egl.eglBindAPI) {
1317                if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1318                    res = EGL_FALSE;
1319                }
1320            }
1321        }
1322    }
1323    return res;
1324}
1325
1326EGLenum eglQueryAPI(void)
1327{
1328    for (int i=0 ; i<2 ; i++) {
1329        egl_connection_t* const cnx = &gEGLImpl[i];
1330        if (cnx->dso) {
1331            if (cnx->hooks->egl.eglQueryAPI) {
1332                // the first one we find is okay, because they all
1333                // should be the same
1334                return cnx->hooks->egl.eglQueryAPI();
1335            }
1336        }
1337    }
1338    // or, it can only be OpenGL ES
1339    return EGL_OPENGL_ES_API;
1340}
1341
1342EGLBoolean eglReleaseThread(void)
1343{
1344    for (int i=0 ; i<2 ; i++) {
1345        egl_connection_t* const cnx = &gEGLImpl[i];
1346        if (cnx->dso) {
1347            if (cnx->hooks->egl.eglReleaseThread) {
1348                cnx->hooks->egl.eglReleaseThread();
1349            }
1350        }
1351    }
1352    clearTLS();
1353    return EGL_TRUE;
1354}
1355
1356EGLSurface eglCreatePbufferFromClientBuffer(
1357          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1358          EGLConfig config, const EGLint *attrib_list)
1359{
1360    egl_display_t const* dp = 0;
1361    int i=0, index=0;
1362    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1363    if (!cnx) return EGL_FALSE;
1364    if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1365        return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1366                dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1367    }
1368    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1369}
1370