egl.cpp revision eccc8cfb2fc83e7f924016ef31e3a4a12e347e99
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    egl_context_t * const c = get_context(ctx);
1056    if (draw != EGL_NO_SURFACE) {
1057        egl_surface_t const * d = get_surface(draw);
1058        if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1059        if (d->impl != c->impl)
1060            return setError(EGL_BAD_MATCH, EGL_FALSE);
1061        draw = d->surface;
1062    }
1063    if (read != EGL_NO_SURFACE) {
1064        egl_surface_t const * r = get_surface(read);
1065        if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1066        if (r->impl != c->impl)
1067            return setError(EGL_BAD_MATCH, EGL_FALSE);
1068        read = r->surface;
1069    }
1070    EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1071            dp->dpys[c->impl], draw, read, c->context);
1072
1073    if (result == EGL_TRUE) {
1074        setGlThreadSpecific(c->cnx->hooks);
1075        setContext(ctx);
1076        c->read = read;
1077        c->draw = draw;
1078    }
1079    return result;
1080}
1081
1082
1083EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1084                            EGLint attribute, EGLint *value)
1085{
1086    if (!validate_display_context(dpy, ctx))
1087        return EGL_FALSE;
1088
1089    egl_display_t const * const dp = get_display(dpy);
1090    egl_context_t * const c = get_context(ctx);
1091
1092    return c->cnx->hooks->egl.eglQueryContext(
1093            dp->dpys[c->impl], c->context, attribute, value);
1094}
1095
1096EGLContext eglGetCurrentContext(void)
1097{
1098    EGLContext ctx = getContext();
1099    return ctx;
1100}
1101
1102EGLSurface eglGetCurrentSurface(EGLint readdraw)
1103{
1104    EGLContext ctx = getContext();
1105    if (ctx) {
1106        egl_context_t const * const c = get_context(ctx);
1107        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1108        switch (readdraw) {
1109            case EGL_READ: return c->read;
1110            case EGL_DRAW: return c->draw;
1111            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1112        }
1113    }
1114    return EGL_NO_SURFACE;
1115}
1116
1117EGLDisplay eglGetCurrentDisplay(void)
1118{
1119    EGLContext ctx = getContext();
1120    if (ctx) {
1121        egl_context_t const * const c = get_context(ctx);
1122        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1123        return c->dpy;
1124    }
1125    return EGL_NO_DISPLAY;
1126}
1127
1128EGLBoolean eglWaitGL(void)
1129{
1130    EGLBoolean res = EGL_TRUE;
1131    EGLContext ctx = getContext();
1132    if (ctx) {
1133        egl_context_t const * const c = get_context(ctx);
1134        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1135        if (uint32_t(c->impl)>=2)
1136            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1137        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1138        if (!cnx->dso)
1139            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1140        res = cnx->hooks->egl.eglWaitGL();
1141    }
1142    return res;
1143}
1144
1145EGLBoolean eglWaitNative(EGLint engine)
1146{
1147    EGLBoolean res = EGL_TRUE;
1148    EGLContext ctx = getContext();
1149    if (ctx) {
1150        egl_context_t const * const c = get_context(ctx);
1151        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1152        if (uint32_t(c->impl)>=2)
1153            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1154        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1155        if (!cnx->dso)
1156            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1157        res = cnx->hooks->egl.eglWaitNative(engine);
1158    }
1159    return res;
1160}
1161
1162EGLint eglGetError(void)
1163{
1164    EGLint result = EGL_SUCCESS;
1165    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1166        EGLint err = EGL_SUCCESS;
1167        egl_connection_t* const cnx = &gEGLImpl[i];
1168        if (cnx->dso)
1169            err = cnx->hooks->egl.eglGetError();
1170        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1171            result = err;
1172    }
1173    if (result == EGL_SUCCESS)
1174        result = getError();
1175    return result;
1176}
1177
1178__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
1179{
1180    // eglGetProcAddress() could be the very first function called
1181    // in which case we must make sure we've initialized ourselves, this
1182    // happens the first time egl_get_display() is called.
1183
1184    if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
1185        return NULL;
1186
1187    __eglMustCastToProperFunctionPointerType addr;
1188    addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1189    if (addr) return addr;
1190
1191    return NULL; // TODO: finish implementation below
1192
1193    addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1194    if (addr) return addr;
1195
1196    addr = 0;
1197    int slot = -1;
1198    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1199        egl_connection_t* const cnx = &gEGLImpl[i];
1200        if (cnx->dso) {
1201            if (cnx->hooks->egl.eglGetProcAddress) {
1202                addr = cnx->hooks->egl.eglGetProcAddress(procname);
1203                if (addr) {
1204                    if (slot == -1) {
1205                        slot = 0; // XXX: find free slot
1206                        if (slot == -1) {
1207                            addr = 0;
1208                            break;
1209                        }
1210                    }
1211                    cnx->hooks->ext.extensions[slot] = addr;
1212                }
1213            }
1214        }
1215    }
1216
1217    if (slot >= 0) {
1218        addr = 0; // XXX: address of stub 'slot'
1219        gGLExtentionMap[slot].name = strdup(procname);
1220        gGLExtentionMap[slot].address = addr;
1221    }
1222
1223    return addr;
1224
1225
1226    /*
1227     *  TODO: For OpenGL ES extensions, we must generate a stub
1228     *  that looks like
1229     *      mov     r12, #0xFFFF0FFF
1230     *      ldr     r12, [r12, #-15]
1231     *      ldr     r12, [r12, #TLS_SLOT_OPENGL_API*4]
1232     *      mov     r12, [r12, #api_offset]
1233     *      ldrne   pc, r12
1234     *      mov     pc, #unsupported_extension
1235     *
1236     *  and write the address of the extension in *all*
1237     *  gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1238     *
1239     */
1240}
1241
1242EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1243{
1244    if (!validate_display_surface(dpy, draw))
1245        return EGL_FALSE;
1246    egl_display_t const * const dp = get_display(dpy);
1247    egl_surface_t const * const s = get_surface(draw);
1248    return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1249}
1250
1251EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1252                            NativePixmapType target)
1253{
1254    if (!validate_display_surface(dpy, surface))
1255        return EGL_FALSE;
1256    egl_display_t const * const dp = get_display(dpy);
1257    egl_surface_t const * const s = get_surface(surface);
1258    return s->cnx->hooks->egl.eglCopyBuffers(
1259            dp->dpys[s->impl], s->surface, target);
1260}
1261
1262const char* eglQueryString(EGLDisplay dpy, EGLint name)
1263{
1264    egl_display_t const * const dp = get_display(dpy);
1265    switch (name) {
1266        case EGL_VENDOR:
1267            return gVendorString;
1268        case EGL_VERSION:
1269            return gVersionString;
1270        case EGL_EXTENSIONS:
1271            return gExtensionString;
1272        case EGL_CLIENT_APIS:
1273            return gClientApiString;
1274    }
1275    return setError(EGL_BAD_PARAMETER, (const char *)0);
1276}
1277
1278
1279// ----------------------------------------------------------------------------
1280// EGL 1.1
1281// ----------------------------------------------------------------------------
1282
1283EGLBoolean eglSurfaceAttrib(
1284        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1285{
1286    if (!validate_display_surface(dpy, surface))
1287        return EGL_FALSE;
1288    egl_display_t const * const dp = get_display(dpy);
1289    egl_surface_t const * const s = get_surface(surface);
1290    if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1291        return s->cnx->hooks->egl.eglSurfaceAttrib(
1292                dp->dpys[s->impl], s->surface, attribute, value);
1293    }
1294    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1295}
1296
1297EGLBoolean eglBindTexImage(
1298        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1299{
1300    if (!validate_display_surface(dpy, surface))
1301        return EGL_FALSE;
1302    egl_display_t const * const dp = get_display(dpy);
1303    egl_surface_t const * const s = get_surface(surface);
1304    if (s->cnx->hooks->egl.eglBindTexImage) {
1305        return s->cnx->hooks->egl.eglBindTexImage(
1306                dp->dpys[s->impl], s->surface, buffer);
1307    }
1308    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1309}
1310
1311EGLBoolean eglReleaseTexImage(
1312        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1313{
1314    if (!validate_display_surface(dpy, surface))
1315        return EGL_FALSE;
1316    egl_display_t const * const dp = get_display(dpy);
1317    egl_surface_t const * const s = get_surface(surface);
1318    if (s->cnx->hooks->egl.eglReleaseTexImage) {
1319        return s->cnx->hooks->egl.eglReleaseTexImage(
1320                dp->dpys[s->impl], s->surface, buffer);
1321    }
1322    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1323}
1324
1325EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1326{
1327    egl_display_t * const dp = get_display(dpy);
1328    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1329
1330    EGLBoolean res = EGL_TRUE;
1331    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1332        egl_connection_t* const cnx = &gEGLImpl[i];
1333        if (cnx->dso) {
1334            if (cnx->hooks->egl.eglSwapInterval) {
1335                if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1336                    res = EGL_FALSE;
1337                }
1338            }
1339        }
1340    }
1341    return res;
1342}
1343
1344
1345// ----------------------------------------------------------------------------
1346// EGL 1.2
1347// ----------------------------------------------------------------------------
1348
1349EGLBoolean eglWaitClient(void)
1350{
1351    EGLBoolean res = EGL_TRUE;
1352    EGLContext ctx = getContext();
1353    if (ctx) {
1354        egl_context_t const * const c = get_context(ctx);
1355        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1356        if (uint32_t(c->impl)>=2)
1357            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1358        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1359        if (!cnx->dso)
1360            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1361        if (cnx->hooks->egl.eglWaitClient) {
1362            res = cnx->hooks->egl.eglWaitClient();
1363        } else {
1364            res = cnx->hooks->egl.eglWaitGL();
1365        }
1366    }
1367    return res;
1368}
1369
1370EGLBoolean eglBindAPI(EGLenum api)
1371{
1372    // bind this API on all EGLs
1373    EGLBoolean res = EGL_TRUE;
1374    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1375        egl_connection_t* const cnx = &gEGLImpl[i];
1376        if (cnx->dso) {
1377            if (cnx->hooks->egl.eglBindAPI) {
1378                if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1379                    res = EGL_FALSE;
1380                }
1381            }
1382        }
1383    }
1384    return res;
1385}
1386
1387EGLenum eglQueryAPI(void)
1388{
1389    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1390        egl_connection_t* const cnx = &gEGLImpl[i];
1391        if (cnx->dso) {
1392            if (cnx->hooks->egl.eglQueryAPI) {
1393                // the first one we find is okay, because they all
1394                // should be the same
1395                return cnx->hooks->egl.eglQueryAPI();
1396            }
1397        }
1398    }
1399    // or, it can only be OpenGL ES
1400    return EGL_OPENGL_ES_API;
1401}
1402
1403EGLBoolean eglReleaseThread(void)
1404{
1405    for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1406        egl_connection_t* const cnx = &gEGLImpl[i];
1407        if (cnx->dso) {
1408            if (cnx->hooks->egl.eglReleaseThread) {
1409                cnx->hooks->egl.eglReleaseThread();
1410            }
1411        }
1412    }
1413    clearTLS();
1414    return EGL_TRUE;
1415}
1416
1417EGLSurface eglCreatePbufferFromClientBuffer(
1418          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1419          EGLConfig config, const EGLint *attrib_list)
1420{
1421    egl_display_t const* dp = 0;
1422    int i=0, index=0;
1423    egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1424    if (!cnx) return EGL_FALSE;
1425    if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1426        return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1427                dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1428    }
1429    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1430}
1431