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