egl.cpp revision 749c63dbff0ab66223f30af1bad4ca56bd26d5d2
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_MAJOR 1
54#define VERSION_MINOR 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 = VERSION_MAJOR;
652        if (minor != NULL) *minor = VERSION_MINOR;
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 (num_config==0) {
729        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
730    }
731
732    EGLint n;
733    EGLBoolean res = EGL_FALSE;
734    *num_config = 0;
735
736
737    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
738    // to do  this, we have to go through the attrib_list array once
739    // to figure out both its size and if it contains an EGL_CONFIG_ID
740    // key. If so, the full array is copied and patched.
741    // NOTE: we assume that there can be only one occurrence
742    // of EGL_CONFIG_ID.
743
744    EGLint patch_index = -1;
745    GLint attr;
746    size_t size = 0;
747    while ((attr=attrib_list[size])) {
748        if (attr == EGL_CONFIG_ID)
749            patch_index = size;
750        size += 2;
751    }
752    if (patch_index >= 0) {
753        size += 2; // we need copy the sentinel as well
754        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
755        if (new_list == 0)
756            return setError(EGL_BAD_ALLOC, EGL_FALSE);
757        memcpy(new_list, attrib_list, size*sizeof(EGLint));
758
759        // patch the requested EGL_CONFIG_ID
760        int i, index;
761        EGLint& configId(new_list[patch_index+1]);
762        uniqueIdToConfig(dp, configId, i, index);
763
764        egl_connection_t* const cnx = &gEGLImpl[i];
765        if (cnx->dso) {
766            cnx->hooks->egl.eglGetConfigAttrib(
767                    dp->dpys[i], dp->configs[i][index],
768                    EGL_CONFIG_ID, &configId);
769
770            // and switch to the new list
771            attrib_list = const_cast<const EGLint *>(new_list);
772
773            // At this point, the only configuration that can match is
774            // dp->configs[i][index], however, we don't know if it would be
775            // rejected because of the other attributes, so we do have to call
776            // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
777            // through all the EGLimpl[].
778            // We also know we can only get a single config back, and we know
779            // which one.
780
781            res = cnx->hooks->egl.eglChooseConfig(
782                    dp->dpys[i], attrib_list, configs, config_size, &n);
783            if (res && n>0) {
784                // n has to be 0 or 1, by construction, and we already know
785                // which config it will return (since there can be only one).
786                if (configs) {
787                    configs[0] = MAKE_CONFIG(i, index);
788                }
789                *num_config = 1;
790            }
791        }
792
793        free(const_cast<EGLint *>(attrib_list));
794        return res;
795    }
796
797    for (int i=0 ; i<2 ; i++) {
798        egl_connection_t* const cnx = &gEGLImpl[i];
799        if (cnx->dso) {
800            if (cnx->hooks->egl.eglChooseConfig(
801                    dp->dpys[i], attrib_list, configs, config_size, &n)) {
802                if (configs) {
803                    // now we need to convert these client EGLConfig to our
804                    // internal EGLConfig format. This is done in O(n log n).
805                    for (int j=0 ; j<n ; j++) {
806                        int index = binarySearch<EGLConfig>(
807                                dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
808                        if (index >= 0) {
809                            if (configs) {
810                                configs[j] = MAKE_CONFIG(i, index);
811                            }
812                        } else {
813                            return setError(EGL_BAD_CONFIG, EGL_FALSE);
814                        }
815                    }
816                    configs += n;
817                    config_size -= n;
818                }
819                *num_config += n;
820                res = EGL_TRUE;
821            }
822        }
823    }
824    return res;
825}
826
827EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
828        EGLint attribute, EGLint *value)
829{
830    egl_display_t const* dp = 0;
831    int i=0, index=0;
832    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
833    if (!cnx) return EGL_FALSE;
834
835    if (attribute == EGL_CONFIG_ID) {
836        // EGL_CONFIG_IDs must be unique, just use the order of the selected
837        // EGLConfig.
838        *value = configToUniqueId(dp, i, index);
839        return EGL_TRUE;
840    }
841    return cnx->hooks->egl.eglGetConfigAttrib(
842            dp->dpys[i], dp->configs[i][index], attribute, value);
843}
844
845// ----------------------------------------------------------------------------
846// surfaces
847// ----------------------------------------------------------------------------
848
849EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
850                                    NativeWindowType window,
851                                    const EGLint *attrib_list)
852{
853    egl_display_t const* dp = 0;
854    int i=0, index=0;
855    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
856    if (cnx) {
857        // window must be connected upon calling underlying
858        // eglCreateWindowSurface
859        if (window) {
860            window->incRef(window);
861            if (window->connect)
862                window->connect(window);
863        }
864
865        EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
866                dp->dpys[i], dp->configs[i][index], window, attrib_list);
867        if (surface != EGL_NO_SURFACE) {
868            egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
869            return s;
870        }
871
872        // something went wrong, disconnect and free window
873        // (will disconnect() automatically)
874        if (window) {
875            window->decRef(window);
876        }
877    }
878    return EGL_NO_SURFACE;
879}
880
881EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
882                                    NativePixmapType pixmap,
883                                    const EGLint *attrib_list)
884{
885    egl_display_t const* dp = 0;
886    int i=0, index=0;
887    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
888    if (cnx) {
889        EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
890                dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
891        if (surface != EGL_NO_SURFACE) {
892            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
893            return s;
894        }
895    }
896    return EGL_NO_SURFACE;
897}
898
899EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
900                                    const EGLint *attrib_list)
901{
902    egl_display_t const* dp = 0;
903    int i=0, index=0;
904    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
905    if (cnx) {
906        EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
907                dp->dpys[i], dp->configs[i][index], attrib_list);
908        if (surface != EGL_NO_SURFACE) {
909            egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
910            return s;
911        }
912    }
913    return EGL_NO_SURFACE;
914}
915
916EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
917{
918    if (!validate_display_surface(dpy, surface))
919        return EGL_FALSE;
920    egl_display_t const * const dp = get_display(dpy);
921    egl_surface_t const * const s = get_surface(surface);
922
923    EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
924            dp->dpys[s->impl], s->surface);
925
926    delete s;
927    return result;
928}
929
930EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
931                            EGLint attribute, EGLint *value)
932{
933    if (!validate_display_surface(dpy, surface))
934        return EGL_FALSE;
935    egl_display_t const * const dp = get_display(dpy);
936    egl_surface_t const * const s = get_surface(surface);
937
938    return s->cnx->hooks->egl.eglQuerySurface(
939            dp->dpys[s->impl], s->surface, attribute, value);
940}
941
942// ----------------------------------------------------------------------------
943// contextes
944// ----------------------------------------------------------------------------
945
946EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
947                            EGLContext share_list, const EGLint *attrib_list)
948{
949    egl_display_t const* dp = 0;
950    int i=0, index=0;
951    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
952    if (cnx) {
953        EGLContext context = cnx->hooks->egl.eglCreateContext(
954                dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
955        if (context != EGL_NO_CONTEXT) {
956            egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
957            return c;
958        }
959    }
960    return EGL_NO_CONTEXT;
961}
962
963EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
964{
965    if (!validate_display_context(dpy, ctx))
966        return EGL_FALSE;
967    egl_display_t const * const dp = get_display(dpy);
968    egl_context_t * const c = get_context(ctx);
969    EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
970            dp->dpys[c->impl], c->context);
971    delete c;
972    return result;
973}
974
975EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
976                            EGLSurface read, EGLContext ctx)
977{
978    egl_display_t const * const dp = get_display(dpy);
979    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
980
981    if (read == EGL_NO_SURFACE && draw  == EGL_NO_SURFACE &&
982            ctx == EGL_NO_CONTEXT)
983    {
984        EGLBoolean result = EGL_TRUE;
985        ctx = getContext();
986        if (ctx) {
987            egl_context_t * const c = get_context(ctx);
988            result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
989            if (result == EGL_TRUE) {
990                setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
991                setContext(EGL_NO_CONTEXT);
992            }
993        }
994        return result;
995    }
996
997    if (!validate_display_context(dpy, ctx))
998        return EGL_FALSE;
999
1000    egl_context_t * const c = get_context(ctx);
1001    if (draw != EGL_NO_SURFACE) {
1002        egl_surface_t const * d = get_surface(draw);
1003        if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1004        if (d->impl != c->impl)
1005            return setError(EGL_BAD_MATCH, EGL_FALSE);
1006        draw = d->surface;
1007    }
1008    if (read != EGL_NO_SURFACE) {
1009        egl_surface_t const * r = get_surface(read);
1010        if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1011        if (r->impl != c->impl)
1012            return setError(EGL_BAD_MATCH, EGL_FALSE);
1013        read = r->surface;
1014    }
1015    EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1016            dp->dpys[c->impl], draw, read, c->context);
1017
1018    if (result == EGL_TRUE) {
1019        setGlThreadSpecific(c->cnx->hooks);
1020        setContext(ctx);
1021        c->read = read;
1022        c->draw = draw;
1023    }
1024    return result;
1025}
1026
1027
1028EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1029                            EGLint attribute, EGLint *value)
1030{
1031    if (!validate_display_context(dpy, ctx))
1032        return EGL_FALSE;
1033
1034    egl_display_t const * const dp = get_display(dpy);
1035    egl_context_t * const c = get_context(ctx);
1036
1037    return c->cnx->hooks->egl.eglQueryContext(
1038            dp->dpys[c->impl], c->context, attribute, value);
1039}
1040
1041EGLContext eglGetCurrentContext(void)
1042{
1043    EGLContext ctx = getContext();
1044    return ctx;
1045}
1046
1047EGLSurface eglGetCurrentSurface(EGLint readdraw)
1048{
1049    EGLContext ctx = getContext();
1050    if (ctx) {
1051        egl_context_t const * const c = get_context(ctx);
1052        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1053        switch (readdraw) {
1054            case EGL_READ: return c->read;
1055            case EGL_DRAW: return c->draw;
1056            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1057        }
1058    }
1059    return EGL_NO_SURFACE;
1060}
1061
1062EGLDisplay eglGetCurrentDisplay(void)
1063{
1064    EGLContext ctx = getContext();
1065    if (ctx) {
1066        egl_context_t const * const c = get_context(ctx);
1067        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1068        return c->dpy;
1069    }
1070    return EGL_NO_DISPLAY;
1071}
1072
1073EGLBoolean eglWaitGL(void)
1074{
1075    EGLBoolean res = EGL_TRUE;
1076    EGLContext ctx = getContext();
1077    if (ctx) {
1078        egl_context_t const * const c = get_context(ctx);
1079        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1080        if (uint32_t(c->impl)>=2)
1081            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1082        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1083        if (!cnx->dso)
1084            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1085        res = cnx->hooks->egl.eglWaitGL();
1086    }
1087    return res;
1088}
1089
1090EGLBoolean eglWaitNative(EGLint engine)
1091{
1092    EGLBoolean res = EGL_TRUE;
1093    EGLContext ctx = getContext();
1094    if (ctx) {
1095        egl_context_t const * const c = get_context(ctx);
1096        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1097        if (uint32_t(c->impl)>=2)
1098            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1099        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1100        if (!cnx->dso)
1101            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1102        res = cnx->hooks->egl.eglWaitNative(engine);
1103    }
1104    return res;
1105}
1106
1107EGLint eglGetError(void)
1108{
1109    EGLint result = EGL_SUCCESS;
1110    for (int i=0 ; i<2 ; i++) {
1111        EGLint err = EGL_SUCCESS;
1112        egl_connection_t* const cnx = &gEGLImpl[i];
1113        if (cnx->dso)
1114            err = cnx->hooks->egl.eglGetError();
1115        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1116            result = err;
1117    }
1118    if (result == EGL_SUCCESS)
1119        result = getError();
1120    return result;
1121}
1122
1123void (*eglGetProcAddress(const char *procname))()
1124{
1125    __eglMustCastToProperFunctionPointerType addr;
1126    addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1127    if (addr) return addr;
1128
1129    return NULL; // TODO: finish implementation below
1130
1131    addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1132    if (addr) return addr;
1133
1134    addr = 0;
1135    int slot = -1;
1136    for (int i=0 ; i<2 ; i++) {
1137        egl_connection_t* const cnx = &gEGLImpl[i];
1138        if (cnx->dso) {
1139            if (cnx->hooks->egl.eglGetProcAddress) {
1140                addr = cnx->hooks->egl.eglGetProcAddress(procname);
1141                if (addr) {
1142                    if (slot == -1) {
1143                        slot = 0; // XXX: find free slot
1144                        if (slot == -1) {
1145                            addr = 0;
1146                            break;
1147                        }
1148                    }
1149                    cnx->hooks->ext.extensions[slot] = addr;
1150                }
1151            }
1152        }
1153    }
1154
1155    if (slot >= 0) {
1156        addr = 0; // XXX: address of stub 'slot'
1157        gGLExtentionMap[slot].name = strdup(procname);
1158        gGLExtentionMap[slot].address = addr;
1159    }
1160
1161    return addr;
1162
1163
1164    /*
1165     *  TODO: For OpenGL ES extensions, we must generate a stub
1166     *  that looks like
1167     *      mov     r12, #0xFFFF0FFF
1168     *      ldr     r12, [r12, #-15]
1169     *      ldr     r12, [r12, #TLS_SLOT_OPENGL_API*4]
1170     *      mov     r12, [r12, #api_offset]
1171     *      ldrne   pc, r12
1172     *      mov     pc, #unsupported_extension
1173     *
1174     *  and write the address of the extension in *all*
1175     *  gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1176     *
1177     */
1178}
1179
1180EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1181{
1182    if (!validate_display_surface(dpy, draw))
1183        return EGL_FALSE;
1184    egl_display_t const * const dp = get_display(dpy);
1185    egl_surface_t const * const s = get_surface(draw);
1186    return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1187}
1188
1189EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1190                            NativePixmapType target)
1191{
1192    if (!validate_display_surface(dpy, surface))
1193        return EGL_FALSE;
1194    egl_display_t const * const dp = get_display(dpy);
1195    egl_surface_t const * const s = get_surface(surface);
1196    return s->cnx->hooks->egl.eglCopyBuffers(
1197            dp->dpys[s->impl], s->surface, target);
1198}
1199
1200const char* eglQueryString(EGLDisplay dpy, EGLint name)
1201{
1202    egl_display_t const * const dp = get_display(dpy);
1203    switch (name) {
1204        case EGL_VENDOR:
1205            return gVendorString;
1206        case EGL_VERSION:
1207            return gVersionString;
1208        case EGL_EXTENSIONS:
1209            return gExtensionString;
1210        case EGL_CLIENT_APIS:
1211            return gClientApiString;
1212    }
1213    return setError(EGL_BAD_PARAMETER, (const char *)0);
1214}
1215
1216
1217// ----------------------------------------------------------------------------
1218// EGL 1.1
1219// ----------------------------------------------------------------------------
1220
1221EGLBoolean eglSurfaceAttrib(
1222        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1223{
1224    if (!validate_display_surface(dpy, surface))
1225        return EGL_FALSE;
1226    egl_display_t const * const dp = get_display(dpy);
1227    egl_surface_t const * const s = get_surface(surface);
1228    if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1229        return s->cnx->hooks->egl.eglSurfaceAttrib(
1230                dp->dpys[s->impl], s->surface, attribute, value);
1231    }
1232    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1233}
1234
1235EGLBoolean eglBindTexImage(
1236        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1237{
1238    if (!validate_display_surface(dpy, surface))
1239        return EGL_FALSE;
1240    egl_display_t const * const dp = get_display(dpy);
1241    egl_surface_t const * const s = get_surface(surface);
1242    if (s->cnx->hooks->egl.eglBindTexImage) {
1243        return s->cnx->hooks->egl.eglBindTexImage(
1244                dp->dpys[s->impl], s->surface, buffer);
1245    }
1246    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1247}
1248
1249EGLBoolean eglReleaseTexImage(
1250        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1251{
1252    if (!validate_display_surface(dpy, surface))
1253        return EGL_FALSE;
1254    egl_display_t const * const dp = get_display(dpy);
1255    egl_surface_t const * const s = get_surface(surface);
1256    if (s->cnx->hooks->egl.eglReleaseTexImage) {
1257        return s->cnx->hooks->egl.eglReleaseTexImage(
1258                dp->dpys[s->impl], s->surface, buffer);
1259    }
1260    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1261}
1262
1263EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1264{
1265    egl_display_t * const dp = get_display(dpy);
1266    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1267
1268    EGLBoolean res = EGL_TRUE;
1269    for (int i=0 ; i<2 ; i++) {
1270        egl_connection_t* const cnx = &gEGLImpl[i];
1271        if (cnx->dso) {
1272            if (cnx->hooks->egl.eglSwapInterval) {
1273                if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1274                    res = EGL_FALSE;
1275                }
1276            }
1277        }
1278    }
1279    return res;
1280}
1281
1282
1283// ----------------------------------------------------------------------------
1284// EGL 1.2
1285// ----------------------------------------------------------------------------
1286
1287EGLBoolean eglWaitClient(void)
1288{
1289    EGLBoolean res = EGL_TRUE;
1290    EGLContext ctx = getContext();
1291    if (ctx) {
1292        egl_context_t const * const c = get_context(ctx);
1293        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1294        if (uint32_t(c->impl)>=2)
1295            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1296        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1297        if (!cnx->dso)
1298            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1299        if (cnx->hooks->egl.eglWaitClient) {
1300            res = cnx->hooks->egl.eglWaitClient();
1301        } else {
1302            res = cnx->hooks->egl.eglWaitGL();
1303        }
1304    }
1305    return res;
1306}
1307
1308EGLBoolean eglBindAPI(EGLenum api)
1309{
1310    // bind this API on all EGLs
1311    EGLBoolean res = EGL_TRUE;
1312    for (int i=0 ; i<2 ; i++) {
1313        egl_connection_t* const cnx = &gEGLImpl[i];
1314        if (cnx->dso) {
1315            if (cnx->hooks->egl.eglBindAPI) {
1316                if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1317                    res = EGL_FALSE;
1318                }
1319            }
1320        }
1321    }
1322    return res;
1323}
1324
1325EGLenum eglQueryAPI(void)
1326{
1327    for (int i=0 ; i<2 ; i++) {
1328        egl_connection_t* const cnx = &gEGLImpl[i];
1329        if (cnx->dso) {
1330            if (cnx->hooks->egl.eglQueryAPI) {
1331                // the first one we find is okay, because they all
1332                // should be the same
1333                return cnx->hooks->egl.eglQueryAPI();
1334            }
1335        }
1336    }
1337    // or, it can only be OpenGL ES
1338    return EGL_OPENGL_ES_API;
1339}
1340
1341EGLBoolean eglReleaseThread(void)
1342{
1343    for (int i=0 ; i<2 ; i++) {
1344        egl_connection_t* const cnx = &gEGLImpl[i];
1345        if (cnx->dso) {
1346            if (cnx->hooks->egl.eglReleaseThread) {
1347                cnx->hooks->egl.eglReleaseThread();
1348            }
1349        }
1350    }
1351    clearTLS();
1352    return EGL_TRUE;
1353}
1354
1355EGLSurface eglCreatePbufferFromClientBuffer(
1356          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1357          EGLConfig config, const EGLint *attrib_list)
1358{
1359    egl_display_t const* dp = 0;
1360    int i=0, index=0;
1361    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1362    if (!cnx) return EGL_FALSE;
1363    if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1364        return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1365                dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1366    }
1367    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1368}
1369