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