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