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