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