egl.cpp revision aa22d205549f5c9604f5d66b5368c53b484c3638
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 <utils/SortedVector.h>
40#include <utils/KeyedVector.h>
41#include <utils/String8.h>
42
43#include "hooks.h"
44#include "egl_impl.h"
45#include "Loader.h"
46
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.4 Android META-EGL";
57static char const * const gClientApiString  = "OpenGL ES";
58static char const * const gExtensionString  =
59        "EGL_KHR_image "
60        "EGL_KHR_image_base "
61        "EGL_KHR_image_pixmap "
62        "EGL_KHR_gl_texture_2D_image "
63        "EGL_KHR_fence_sync "
64        "EGL_ANDROID_image_native_buffer "
65        "EGL_ANDROID_swap_rectangle "
66        ;
67
68// ----------------------------------------------------------------------------
69
70class egl_object_t {
71    static SortedVector<egl_object_t*> sObjects;
72    static Mutex sLock;
73
74            volatile int32_t  terminated;
75    mutable volatile int32_t  count;
76
77public:
78    egl_object_t() : terminated(0), count(1) {
79        Mutex::Autolock _l(sLock);
80        sObjects.add(this);
81    }
82
83    inline bool isAlive() const { return !terminated; }
84
85private:
86    bool get() {
87        Mutex::Autolock _l(sLock);
88        if (egl_object_t::sObjects.indexOf(this) >= 0) {
89            android_atomic_inc(&count);
90            return true;
91        }
92        return false;
93    }
94
95    bool put() {
96        Mutex::Autolock _l(sLock);
97        if (android_atomic_dec(&count) == 1) {
98            sObjects.remove(this);
99            return true;
100        }
101        return false;
102    }
103
104public:
105    template <typename N, typename T>
106    struct LocalRef {
107        N* ref;
108        LocalRef(T o) : ref(0) {
109            N* native = reinterpret_cast<N*>(o);
110            if (o && native->get()) {
111                ref = native;
112            }
113        }
114        ~LocalRef() {
115            if (ref && ref->put()) {
116                delete ref;
117            }
118        }
119        inline N* get() {
120            return ref;
121        }
122        void acquire() const {
123            if (ref) {
124                android_atomic_inc(&ref->count);
125            }
126        }
127        void release() const {
128            if (ref) {
129                int32_t c = android_atomic_dec(&ref->count);
130                // ref->count cannot be 1 prior atomic_dec because we have
131                // a reference, and if we have one, it means there was
132                // already one before us.
133                LOGE_IF(c==1, "refcount is now 0 in release()");
134            }
135        }
136        void terminate() {
137            if (ref) {
138                ref->terminated = 1;
139                release();
140            }
141        }
142    };
143};
144
145SortedVector<egl_object_t*> egl_object_t::sObjects;
146Mutex egl_object_t::sLock;
147
148
149struct egl_config_t {
150    egl_config_t() {}
151    egl_config_t(int impl, EGLConfig config)
152        : impl(impl), config(config), configId(0), implConfigId(0) { }
153    int         impl;           // the implementation this config is for
154    EGLConfig   config;         // the implementation's EGLConfig
155    EGLint      configId;       // our CONFIG_ID
156    EGLint      implConfigId;   // the implementation's CONFIG_ID
157    inline bool operator < (const egl_config_t& rhs) const {
158        if (impl < rhs.impl) return true;
159        if (impl > rhs.impl) return false;
160        return config < rhs.config;
161    }
162};
163
164struct egl_display_t {
165    enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
166
167    struct strings_t {
168        char const * vendor;
169        char const * version;
170        char const * clientApi;
171        char const * extensions;
172    };
173
174    struct DisplayImpl {
175        DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
176                        state(NOT_INITIALIZED), numConfigs(0) { }
177        EGLDisplay  dpy;
178        EGLConfig*  config;
179        EGLint      state;
180        EGLint      numConfigs;
181        strings_t   queryString;
182    };
183
184    uint32_t        magic;
185    DisplayImpl     disp[IMPL_NUM_IMPLEMENTATIONS];
186    EGLint          numTotalConfigs;
187    egl_config_t*   configs;
188    uint32_t        refs;
189    Mutex           lock;
190
191    egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0) { }
192    ~egl_display_t() { magic = 0; }
193    inline bool isValid() const { return magic == '_dpy'; }
194    inline bool isAlive() const { return isValid(); }
195};
196
197struct egl_surface_t : public egl_object_t
198{
199    typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
200
201    egl_surface_t(EGLDisplay dpy, EGLSurface surface, EGLConfig config,
202            int impl, egl_connection_t const* cnx)
203    : dpy(dpy), surface(surface), config(config), impl(impl), cnx(cnx) {
204    }
205    ~egl_surface_t() {
206    }
207    EGLDisplay                  dpy;
208    EGLSurface                  surface;
209    EGLConfig                   config;
210    int                         impl;
211    egl_connection_t const*     cnx;
212};
213
214struct egl_context_t : public egl_object_t
215{
216    typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
217
218    egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
219            int impl, egl_connection_t const* cnx, int version)
220    : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx),
221      version(version)
222    {
223    }
224    EGLDisplay                  dpy;
225    EGLContext                  context;
226    EGLConfig                   config;
227    EGLSurface                  read;
228    EGLSurface                  draw;
229    int                         impl;
230    egl_connection_t const*     cnx;
231    int                         version;
232};
233
234struct egl_image_t : public egl_object_t
235{
236    typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
237
238    egl_image_t(EGLDisplay dpy, EGLContext context)
239        : dpy(dpy), context(context)
240    {
241        memset(images, 0, sizeof(images));
242    }
243    EGLDisplay dpy;
244    EGLContext context;
245    EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
246};
247
248struct egl_sync_t : public egl_object_t
249{
250    typedef egl_object_t::LocalRef<egl_sync_t, EGLSyncKHR> Ref;
251
252    egl_sync_t(EGLDisplay dpy, EGLContext context, EGLSyncKHR sync)
253        : dpy(dpy), context(context), sync(sync)
254    {
255    }
256    EGLDisplay dpy;
257    EGLContext context;
258    EGLSyncKHR sync;
259};
260
261typedef egl_surface_t::Ref  SurfaceRef;
262typedef egl_context_t::Ref  ContextRef;
263typedef egl_image_t::Ref    ImageRef;
264typedef egl_sync_t::Ref     SyncRef;
265
266struct tls_t
267{
268    tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
269    EGLint      error;
270    EGLContext  ctx;
271    EGLBoolean  logCallWithNoContext;
272};
273
274
275// ----------------------------------------------------------------------------
276
277static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
278static egl_display_t gDisplay[NUM_DISPLAYS];
279static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
280static pthread_key_t gEGLThreadLocalStorageKey = -1;
281
282// ----------------------------------------------------------------------------
283
284EGLAPI gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
285EGLAPI gl_hooks_t gHooksNoContext;
286EGLAPI pthread_key_t gGLWrapperKey = -1;
287
288// ----------------------------------------------------------------------------
289
290static __attribute__((noinline))
291const char *egl_strerror(EGLint err)
292{
293    switch (err){
294        case EGL_SUCCESS:               return "EGL_SUCCESS";
295        case EGL_NOT_INITIALIZED:       return "EGL_NOT_INITIALIZED";
296        case EGL_BAD_ACCESS:            return "EGL_BAD_ACCESS";
297        case EGL_BAD_ALLOC:             return "EGL_BAD_ALLOC";
298        case EGL_BAD_ATTRIBUTE:         return "EGL_BAD_ATTRIBUTE";
299        case EGL_BAD_CONFIG:            return "EGL_BAD_CONFIG";
300        case EGL_BAD_CONTEXT:           return "EGL_BAD_CONTEXT";
301        case EGL_BAD_CURRENT_SURFACE:   return "EGL_BAD_CURRENT_SURFACE";
302        case EGL_BAD_DISPLAY:           return "EGL_BAD_DISPLAY";
303        case EGL_BAD_MATCH:             return "EGL_BAD_MATCH";
304        case EGL_BAD_NATIVE_PIXMAP:     return "EGL_BAD_NATIVE_PIXMAP";
305        case EGL_BAD_NATIVE_WINDOW:     return "EGL_BAD_NATIVE_WINDOW";
306        case EGL_BAD_PARAMETER:         return "EGL_BAD_PARAMETER";
307        case EGL_BAD_SURFACE:           return "EGL_BAD_SURFACE";
308        case EGL_CONTEXT_LOST:          return "EGL_CONTEXT_LOST";
309        default: return "UNKNOWN";
310    }
311}
312
313static __attribute__((noinline))
314void clearTLS() {
315    if (gEGLThreadLocalStorageKey != -1) {
316        tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
317        if (tls) {
318            delete tls;
319            pthread_setspecific(gEGLThreadLocalStorageKey, 0);
320        }
321    }
322}
323
324static tls_t* getTLS()
325{
326    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
327    if (tls == 0) {
328        tls = new tls_t;
329        pthread_setspecific(gEGLThreadLocalStorageKey, tls);
330    }
331    return tls;
332}
333
334template<typename T>
335static __attribute__((noinline))
336T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
337    if (gEGLThreadLocalStorageKey == -1) {
338        pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
339        if (gEGLThreadLocalStorageKey == -1)
340            pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
341        pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
342    }
343    tls_t* tls = getTLS();
344    if (tls->error != error) {
345        LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
346        tls->error = error;
347    }
348    return returnValue;
349}
350
351static __attribute__((noinline))
352GLint getError() {
353    if (gEGLThreadLocalStorageKey == -1)
354        return EGL_SUCCESS;
355    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
356    if (!tls) return EGL_SUCCESS;
357    GLint error = tls->error;
358    tls->error = EGL_SUCCESS;
359    return error;
360}
361
362static __attribute__((noinline))
363void setContext(EGLContext ctx) {
364    if (gEGLThreadLocalStorageKey == -1) {
365        pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
366        if (gEGLThreadLocalStorageKey == -1)
367            pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
368        pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
369    }
370    tls_t* tls = getTLS();
371    tls->ctx = ctx;
372}
373
374static __attribute__((noinline))
375EGLContext getContext() {
376    if (gEGLThreadLocalStorageKey == -1)
377        return EGL_NO_CONTEXT;
378    tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
379    if (!tls) return EGL_NO_CONTEXT;
380    return tls->ctx;
381}
382
383/*****************************************************************************/
384
385template<typename T>
386static __attribute__((noinline))
387int binarySearch(
388        T const sortedArray[], int first, int last, T key)
389{
390    while (first <= last) {
391        int mid = (first + last) / 2;
392        if (sortedArray[mid] < key) {
393            first = mid + 1;
394        } else if (key < sortedArray[mid]) {
395            last = mid - 1;
396        } else {
397            return mid;
398        }
399    }
400    return -1;
401}
402
403static int cmp_configs(const void* a, const void *b)
404{
405    const egl_config_t& c0 = *(egl_config_t const *)a;
406    const egl_config_t& c1 = *(egl_config_t const *)b;
407    return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
408}
409
410struct extention_map_t {
411    const char* name;
412    __eglMustCastToProperFunctionPointerType address;
413};
414
415static const extention_map_t gExtentionMap[] = {
416    { "eglLockSurfaceKHR",
417            (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
418    { "eglUnlockSurfaceKHR",
419            (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
420    { "eglCreateImageKHR",
421            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
422    { "eglDestroyImageKHR",
423            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
424    { "eglSetSwapRectangleANDROID",
425            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
426};
427
428extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
429
430// accesses protected by gInitDriverMutex
431static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> gGLExtentionMap;
432static int gGLExtentionSlot = 0;
433
434static void(*findProcAddress(const char* name,
435        const extention_map_t* map, size_t n))()
436{
437    for (uint32_t i=0 ; i<n ; i++) {
438        if (!strcmp(name, map[i].name)) {
439            return map[i].address;
440        }
441    }
442    return NULL;
443}
444
445// ----------------------------------------------------------------------------
446
447static void gl_no_context() {
448    tls_t* tls = getTLS();
449    if (tls->logCallWithNoContext == EGL_TRUE) {
450        tls->logCallWithNoContext = EGL_FALSE;
451        LOGE("call to OpenGL ES API with no current context "
452             "(logged once per thread)");
453    }
454}
455
456// Always return GL_INVALID_OPERATION from glGetError() when called from
457// a thread without a bound context.
458static GLenum gl_no_context_glGetError() {
459    return GL_INVALID_OPERATION;
460}
461
462static void early_egl_init(void)
463{
464#if !USE_FAST_TLS_KEY
465    pthread_key_create(&gGLWrapperKey, NULL);
466#endif
467    uint32_t addr = (uint32_t)((void*)gl_no_context);
468    android_memset32(
469            (uint32_t*)(void*)&gHooksNoContext,
470            addr,
471            sizeof(gHooksNoContext));
472
473    gHooksNoContext.gl.glGetError = gl_no_context_glGetError;
474
475    setGlThreadSpecific(&gHooksNoContext);
476}
477
478static pthread_once_t once_control = PTHREAD_ONCE_INIT;
479static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
480
481
482static inline
483egl_display_t* get_display(EGLDisplay dpy)
484{
485    uintptr_t index = uintptr_t(dpy)-1U;
486    return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
487}
488
489template<typename NATIVE, typename EGL>
490static inline NATIVE* egl_to_native_cast(EGL arg) {
491    return reinterpret_cast<NATIVE*>(arg);
492}
493
494static inline
495egl_surface_t* get_surface(EGLSurface surface) {
496    return egl_to_native_cast<egl_surface_t>(surface);
497}
498
499static inline
500egl_context_t* get_context(EGLContext context) {
501    return egl_to_native_cast<egl_context_t>(context);
502}
503
504static inline
505egl_image_t* get_image(EGLImageKHR image) {
506    return egl_to_native_cast<egl_image_t>(image);
507}
508
509static inline
510egl_sync_t* get_sync(EGLSyncKHR sync) {
511    return egl_to_native_cast<egl_sync_t>(sync);
512}
513
514static egl_connection_t* validate_display_config(
515        EGLDisplay dpy, EGLConfig config,
516        egl_display_t const*& dp)
517{
518    dp = get_display(dpy);
519    if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
520
521    if (intptr_t(config) >= dp->numTotalConfigs) {
522        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
523    }
524    egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(config)].impl];
525    if (cnx->dso == 0) {
526        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
527    }
528    return cnx;
529}
530
531static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
532{
533    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
534        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
535    if (!get_display(dpy)->isAlive())
536        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
537    if (!get_context(ctx)->isAlive())
538        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
539    return EGL_TRUE;
540}
541
542static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
543{
544    if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
545        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
546    if (!get_display(dpy)->isAlive())
547        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
548    if (!get_surface(surface)->isAlive())
549        return setError(EGL_BAD_SURFACE, EGL_FALSE);
550    return EGL_TRUE;
551}
552
553EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
554{
555    ImageRef _i(image);
556    if (!_i.get()) return EGL_NO_IMAGE_KHR;
557
558    EGLContext context = getContext();
559    if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
560        return EGL_NO_IMAGE_KHR;
561
562    egl_context_t const * const c = get_context(context);
563    if (!c->isAlive())
564        return EGL_NO_IMAGE_KHR;
565
566    egl_image_t const * const i = get_image(image);
567    return i->images[c->impl];
568}
569
570// ----------------------------------------------------------------------------
571
572// this mutex protects:
573//    d->disp[]
574//    egl_init_drivers_locked()
575//
576static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
577
578EGLBoolean egl_init_drivers_locked()
579{
580    if (sEarlyInitState) {
581        // initialized by static ctor. should be set here.
582        return EGL_FALSE;
583    }
584
585    // get our driver loader
586    Loader& loader(Loader::getInstance());
587
588    // dynamically load all our EGL implementations for all displays
589    // and retrieve the corresponding EGLDisplay
590    // if that fails, don't use this driver.
591    // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
592    egl_connection_t* cnx;
593    egl_display_t* d = &gDisplay[0];
594
595    cnx = &gEGLImpl[IMPL_SOFTWARE];
596    if (cnx->dso == 0) {
597        cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
598        cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
599        cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
600        if (cnx->dso) {
601            EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
602            LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
603            d->disp[IMPL_SOFTWARE].dpy = dpy;
604            if (dpy == EGL_NO_DISPLAY) {
605                loader.close(cnx->dso);
606                cnx->dso = NULL;
607            }
608        }
609    }
610
611    cnx = &gEGLImpl[IMPL_HARDWARE];
612    if (cnx->dso == 0) {
613        char value[PROPERTY_VALUE_MAX];
614        property_get("debug.egl.hw", value, "1");
615        if (atoi(value) != 0) {
616            cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
617            cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
618            cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
619            if (cnx->dso) {
620                EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
621                LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
622                d->disp[IMPL_HARDWARE].dpy = dpy;
623                if (dpy == EGL_NO_DISPLAY) {
624                    loader.close(cnx->dso);
625                    cnx->dso = NULL;
626                }
627            }
628        } else {
629            LOGD("3D hardware acceleration is disabled");
630        }
631    }
632
633    if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
634        return EGL_FALSE;
635    }
636
637    return EGL_TRUE;
638}
639
640EGLBoolean egl_init_drivers()
641{
642    EGLBoolean res;
643    pthread_mutex_lock(&gInitDriverMutex);
644    res = egl_init_drivers_locked();
645    pthread_mutex_unlock(&gInitDriverMutex);
646    return res;
647}
648
649// ----------------------------------------------------------------------------
650}; // namespace android
651// ----------------------------------------------------------------------------
652
653using namespace android;
654
655EGLDisplay eglGetDisplay(NativeDisplayType display)
656{
657    uint32_t index = uint32_t(display);
658    if (index >= NUM_DISPLAYS) {
659        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
660    }
661
662    if (egl_init_drivers() == EGL_FALSE) {
663        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
664    }
665
666    EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
667    return dpy;
668}
669
670// ----------------------------------------------------------------------------
671// Initialization
672// ----------------------------------------------------------------------------
673
674EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
675{
676    egl_display_t * const dp = get_display(dpy);
677    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
678
679    Mutex::Autolock _l(dp->lock);
680
681    if (dp->refs > 0) {
682        if (major != NULL) *major = VERSION_MAJOR;
683        if (minor != NULL) *minor = VERSION_MINOR;
684        dp->refs++;
685        return EGL_TRUE;
686    }
687
688    setGlThreadSpecific(&gHooksNoContext);
689
690    // initialize each EGL and
691    // build our own extension string first, based on the extension we know
692    // and the extension supported by our client implementation
693    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
694        egl_connection_t* const cnx = &gEGLImpl[i];
695        cnx->major = -1;
696        cnx->minor = -1;
697        if (!cnx->dso)
698            continue;
699
700#if defined(ADRENO130)
701#warning "Adreno-130 eglInitialize() workaround"
702        /*
703         * The ADRENO 130 driver returns a different EGLDisplay each time
704         * eglGetDisplay() is called, but also makes the EGLDisplay invalid
705         * after eglTerminate() has been called, so that eglInitialize()
706         * cannot be called again. Therefore, we need to make sure to call
707         * eglGetDisplay() before calling eglInitialize();
708         */
709        if (i == IMPL_HARDWARE) {
710            dp->disp[i].dpy =
711                cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
712        }
713#endif
714
715
716        EGLDisplay idpy = dp->disp[i].dpy;
717        if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
718            //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
719            //        i, idpy, cnx->major, cnx->minor, cnx);
720
721            // display is now initialized
722            dp->disp[i].state = egl_display_t::INITIALIZED;
723
724            // get the query-strings for this display for each implementation
725            dp->disp[i].queryString.vendor =
726                cnx->egl.eglQueryString(idpy, EGL_VENDOR);
727            dp->disp[i].queryString.version =
728                cnx->egl.eglQueryString(idpy, EGL_VERSION);
729            dp->disp[i].queryString.extensions =
730                    cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS);
731            dp->disp[i].queryString.clientApi =
732                cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
733
734        } else {
735            LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
736                    egl_strerror(cnx->egl.eglGetError()));
737        }
738    }
739
740    EGLBoolean res = EGL_FALSE;
741    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
742        egl_connection_t* const cnx = &gEGLImpl[i];
743        if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
744            EGLint n;
745            if (cnx->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
746                dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
747                if (dp->disp[i].config) {
748                    if (cnx->egl.eglGetConfigs(
749                            dp->disp[i].dpy, dp->disp[i].config, n,
750                            &dp->disp[i].numConfigs))
751                    {
752                        dp->numTotalConfigs += n;
753                        res = EGL_TRUE;
754                    }
755                }
756            }
757        }
758    }
759
760    if (res == EGL_TRUE) {
761        dp->configs = new egl_config_t[ dp->numTotalConfigs ];
762        for (int i=0, k=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
763            egl_connection_t* const cnx = &gEGLImpl[i];
764            if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
765                for (int j=0 ; j<dp->disp[i].numConfigs ; j++) {
766                    dp->configs[k].impl = i;
767                    dp->configs[k].config = dp->disp[i].config[j];
768                    dp->configs[k].configId = k + 1; // CONFIG_ID start at 1
769                    // store the implementation's CONFIG_ID
770                    cnx->egl.eglGetConfigAttrib(
771                            dp->disp[i].dpy,
772                            dp->disp[i].config[j],
773                            EGL_CONFIG_ID,
774                            &dp->configs[k].implConfigId);
775                    k++;
776                }
777            }
778        }
779
780        // sort our configurations so we can do binary-searches
781        qsort(  dp->configs,
782                dp->numTotalConfigs,
783                sizeof(egl_config_t), cmp_configs);
784
785        dp->refs++;
786        if (major != NULL) *major = VERSION_MAJOR;
787        if (minor != NULL) *minor = VERSION_MINOR;
788        return EGL_TRUE;
789    }
790    return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
791}
792
793EGLBoolean eglTerminate(EGLDisplay dpy)
794{
795    // NOTE: don't unload the drivers b/c some APIs can be called
796    // after eglTerminate() has been called. eglTerminate() only
797    // terminates an EGLDisplay, not a EGL itself.
798
799    egl_display_t* const dp = get_display(dpy);
800    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
801
802    Mutex::Autolock _l(dp->lock);
803
804    if (dp->refs == 0) {
805        return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
806    }
807
808    // this is specific to Android, display termination is ref-counted.
809    if (dp->refs > 1) {
810        dp->refs--;
811        return EGL_TRUE;
812    }
813
814    EGLBoolean res = EGL_FALSE;
815    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
816        egl_connection_t* const cnx = &gEGLImpl[i];
817        if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
818            if (cnx->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
819                LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
820                        egl_strerror(cnx->egl.eglGetError()));
821            }
822            // REVISIT: it's unclear what to do if eglTerminate() fails
823            free(dp->disp[i].config);
824
825            dp->disp[i].numConfigs = 0;
826            dp->disp[i].config = 0;
827            dp->disp[i].state = egl_display_t::TERMINATED;
828
829            res = EGL_TRUE;
830        }
831    }
832
833    // TODO: all egl_object_t should be marked for termination
834
835    dp->refs--;
836    dp->numTotalConfigs = 0;
837    delete [] dp->configs;
838    clearTLS();
839    return res;
840}
841
842// ----------------------------------------------------------------------------
843// configuration
844// ----------------------------------------------------------------------------
845
846EGLBoolean eglGetConfigs(   EGLDisplay dpy,
847                            EGLConfig *configs,
848                            EGLint config_size, EGLint *num_config)
849{
850    egl_display_t const * const dp = get_display(dpy);
851    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
852
853    GLint numConfigs = dp->numTotalConfigs;
854    if (!configs) {
855        *num_config = numConfigs;
856        return EGL_TRUE;
857    }
858
859    GLint n = 0;
860    for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
861        *configs++ = EGLConfig(i);
862        config_size--;
863        n++;
864    }
865
866    *num_config = n;
867    return EGL_TRUE;
868}
869
870EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
871                            EGLConfig *configs, EGLint config_size,
872                            EGLint *num_config)
873{
874    egl_display_t const * const dp = get_display(dpy);
875    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
876
877    if (num_config==0) {
878        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
879    }
880
881    EGLint n;
882    EGLBoolean res = EGL_FALSE;
883    *num_config = 0;
884
885
886    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
887    // to do this, we have to go through the attrib_list array once
888    // to figure out both its size and if it contains an EGL_CONFIG_ID
889    // key. If so, the full array is copied and patched.
890    // NOTE: we assume that there can be only one occurrence
891    // of EGL_CONFIG_ID.
892
893    EGLint patch_index = -1;
894    GLint attr;
895    size_t size = 0;
896    if (attrib_list) {
897        while ((attr=attrib_list[size]) != EGL_NONE) {
898            if (attr == EGL_CONFIG_ID)
899                patch_index = size;
900            size += 2;
901        }
902    }
903    if (patch_index >= 0) {
904        size += 2; // we need copy the sentinel as well
905        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
906        if (new_list == 0)
907            return setError(EGL_BAD_ALLOC, EGL_FALSE);
908        memcpy(new_list, attrib_list, size*sizeof(EGLint));
909
910        // patch the requested EGL_CONFIG_ID
911        bool found = false;
912        EGLConfig ourConfig(0);
913        EGLint& configId(new_list[patch_index+1]);
914        for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
915            if (dp->configs[i].configId == configId) {
916                ourConfig = EGLConfig(i);
917                configId = dp->configs[i].implConfigId;
918                found = true;
919                break;
920            }
921        }
922
923        egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
924        if (found && cnx->dso) {
925            // and switch to the new list
926            attrib_list = const_cast<const EGLint *>(new_list);
927
928            // At this point, the only configuration that can match is
929            // dp->configs[i][index], however, we don't know if it would be
930            // rejected because of the other attributes, so we do have to call
931            // cnx->egl.eglChooseConfig() -- but we don't have to loop
932            // through all the EGLimpl[].
933            // We also know we can only get a single config back, and we know
934            // which one.
935
936            res = cnx->egl.eglChooseConfig(
937                    dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
938                    attrib_list, configs, config_size, &n);
939            if (res && n>0) {
940                // n has to be 0 or 1, by construction, and we already know
941                // which config it will return (since there can be only one).
942                if (configs) {
943                    configs[0] = ourConfig;
944                }
945                *num_config = 1;
946            }
947        }
948
949        free(const_cast<EGLint *>(attrib_list));
950        return res;
951    }
952
953
954    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
955        egl_connection_t* const cnx = &gEGLImpl[i];
956        if (cnx->dso) {
957            if (cnx->egl.eglChooseConfig(
958                    dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
959                if (configs) {
960                    // now we need to convert these client EGLConfig to our
961                    // internal EGLConfig format.
962                    // This is done in O(n Log(n)) time.
963                    for (int j=0 ; j<n ; j++) {
964                        egl_config_t key(i, configs[j]);
965                        intptr_t index = binarySearch<egl_config_t>(
966                                dp->configs, 0, dp->numTotalConfigs, key);
967                        if (index >= 0) {
968                            configs[j] = EGLConfig(index);
969                        } else {
970                            return setError(EGL_BAD_CONFIG, EGL_FALSE);
971                        }
972                    }
973                    configs += n;
974                    config_size -= n;
975                }
976                *num_config += n;
977                res = EGL_TRUE;
978            }
979        }
980    }
981    return res;
982}
983
984EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
985        EGLint attribute, EGLint *value)
986{
987    egl_display_t const* dp = 0;
988    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
989    if (!cnx) return EGL_FALSE;
990
991    if (attribute == EGL_CONFIG_ID) {
992        *value = dp->configs[intptr_t(config)].configId;
993        return EGL_TRUE;
994    }
995    return cnx->egl.eglGetConfigAttrib(
996            dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
997            dp->configs[intptr_t(config)].config, attribute, value);
998}
999
1000// ----------------------------------------------------------------------------
1001// surfaces
1002// ----------------------------------------------------------------------------
1003
1004EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
1005                                    NativeWindowType window,
1006                                    const EGLint *attrib_list)
1007{
1008    egl_display_t const* dp = 0;
1009    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1010    if (cnx) {
1011        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
1012                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1013                dp->configs[intptr_t(config)].config, window, attrib_list);
1014        if (surface != EGL_NO_SURFACE) {
1015            egl_surface_t* s = new egl_surface_t(dpy, surface, config,
1016                    dp->configs[intptr_t(config)].impl, cnx);
1017            return s;
1018        }
1019    }
1020    return EGL_NO_SURFACE;
1021}
1022
1023EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
1024                                    NativePixmapType pixmap,
1025                                    const EGLint *attrib_list)
1026{
1027    egl_display_t const* dp = 0;
1028    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1029    if (cnx) {
1030        EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
1031                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1032                dp->configs[intptr_t(config)].config, pixmap, attrib_list);
1033        if (surface != EGL_NO_SURFACE) {
1034            egl_surface_t* s = new egl_surface_t(dpy, surface, config,
1035                    dp->configs[intptr_t(config)].impl, cnx);
1036            return s;
1037        }
1038    }
1039    return EGL_NO_SURFACE;
1040}
1041
1042EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
1043                                    const EGLint *attrib_list)
1044{
1045    egl_display_t const* dp = 0;
1046    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1047    if (cnx) {
1048        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
1049                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1050                dp->configs[intptr_t(config)].config, attrib_list);
1051        if (surface != EGL_NO_SURFACE) {
1052            egl_surface_t* s = new egl_surface_t(dpy, surface, config,
1053                    dp->configs[intptr_t(config)].impl, cnx);
1054            return s;
1055        }
1056    }
1057    return EGL_NO_SURFACE;
1058}
1059
1060EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
1061{
1062    SurfaceRef _s(surface);
1063    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1064
1065    if (!validate_display_surface(dpy, surface))
1066        return EGL_FALSE;
1067    egl_display_t const * const dp = get_display(dpy);
1068
1069    egl_surface_t * const s = get_surface(surface);
1070    EGLBoolean result = s->cnx->egl.eglDestroySurface(
1071            dp->disp[s->impl].dpy, s->surface);
1072    if (result == EGL_TRUE) {
1073        _s.terminate();
1074    }
1075    return result;
1076}
1077
1078EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
1079                            EGLint attribute, EGLint *value)
1080{
1081    SurfaceRef _s(surface);
1082    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1083
1084    if (!validate_display_surface(dpy, surface))
1085        return EGL_FALSE;
1086    egl_display_t const * const dp = get_display(dpy);
1087    egl_surface_t const * const s = get_surface(surface);
1088
1089    EGLBoolean result(EGL_TRUE);
1090    if (attribute == EGL_CONFIG_ID) {
1091        // We need to remap EGL_CONFIG_IDs
1092        *value = dp->configs[intptr_t(s->config)].configId;
1093    } else {
1094        result = s->cnx->egl.eglQuerySurface(
1095                dp->disp[s->impl].dpy, s->surface, attribute, value);
1096    }
1097
1098    return result;
1099}
1100
1101// ----------------------------------------------------------------------------
1102// Contexts
1103// ----------------------------------------------------------------------------
1104
1105EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1106                            EGLContext share_list, const EGLint *attrib_list)
1107{
1108    egl_display_t const* dp = 0;
1109    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1110    if (cnx) {
1111        if (share_list != EGL_NO_CONTEXT) {
1112            egl_context_t* const c = get_context(share_list);
1113            share_list = c->context;
1114        }
1115        EGLContext context = cnx->egl.eglCreateContext(
1116                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1117                dp->configs[intptr_t(config)].config,
1118                share_list, attrib_list);
1119        if (context != EGL_NO_CONTEXT) {
1120            // figure out if it's a GLESv1 or GLESv2
1121            int version = 0;
1122            if (attrib_list) {
1123                while (*attrib_list != EGL_NONE) {
1124                    GLint attr = *attrib_list++;
1125                    GLint value = *attrib_list++;
1126                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
1127                        if (value == 1) {
1128                            version = GLESv1_INDEX;
1129                        } else if (value == 2) {
1130                            version = GLESv2_INDEX;
1131                        }
1132                    }
1133                };
1134            }
1135            egl_context_t* c = new egl_context_t(dpy, context, config,
1136                    dp->configs[intptr_t(config)].impl, cnx, version);
1137            return c;
1138        }
1139    }
1140    return EGL_NO_CONTEXT;
1141}
1142
1143EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1144{
1145    ContextRef _c(ctx);
1146    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1147
1148    if (!validate_display_context(dpy, ctx))
1149        return EGL_FALSE;
1150    egl_display_t const * const dp = get_display(dpy);
1151    egl_context_t * const c = get_context(ctx);
1152    EGLBoolean result = c->cnx->egl.eglDestroyContext(
1153            dp->disp[c->impl].dpy, c->context);
1154    if (result == EGL_TRUE) {
1155        _c.terminate();
1156    }
1157    return result;
1158}
1159
1160EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
1161                            EGLSurface read, EGLContext ctx)
1162{
1163    // get a reference to the object passed in
1164    ContextRef _c(ctx);
1165    SurfaceRef _d(draw);
1166    SurfaceRef _r(read);
1167
1168    // validate the display and the context (if not EGL_NO_CONTEXT)
1169    egl_display_t const * const dp = get_display(dpy);
1170    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1171    if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
1172        // EGL_NO_CONTEXT is valid
1173        return EGL_FALSE;
1174    }
1175
1176    // these are the underlying implementation's object
1177    EGLContext impl_ctx  = EGL_NO_CONTEXT;
1178    EGLSurface impl_draw = EGL_NO_SURFACE;
1179    EGLSurface impl_read = EGL_NO_SURFACE;
1180
1181    // these are our objects structs passed in
1182    egl_context_t       * c = NULL;
1183    egl_surface_t const * d = NULL;
1184    egl_surface_t const * r = NULL;
1185
1186    // these are the current objects structs
1187    egl_context_t * cur_c = get_context(getContext());
1188    egl_surface_t * cur_r = NULL;
1189    egl_surface_t * cur_d = NULL;
1190
1191    if (ctx != EGL_NO_CONTEXT) {
1192        c = get_context(ctx);
1193        cur_r = get_surface(c->read);
1194        cur_d = get_surface(c->draw);
1195        impl_ctx = c->context;
1196    } else {
1197        // no context given, use the implementation of the current context
1198        if (cur_c == NULL) {
1199            // no current context
1200            if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
1201                // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
1202                return setError(EGL_BAD_MATCH, EGL_FALSE);
1203            }
1204            // not an error, there is just no current context.
1205            return EGL_TRUE;
1206        }
1207    }
1208
1209    // retrieve the underlying implementation's draw EGLSurface
1210    if (draw != EGL_NO_SURFACE) {
1211        d = get_surface(draw);
1212        // make sure the EGLContext and EGLSurface passed in are for
1213        // the same driver
1214        if (c && d->impl != c->impl)
1215            return setError(EGL_BAD_MATCH, EGL_FALSE);
1216        impl_draw = d->surface;
1217    }
1218
1219    // retrieve the underlying implementation's read EGLSurface
1220    if (read != EGL_NO_SURFACE) {
1221        r = get_surface(read);
1222        // make sure the EGLContext and EGLSurface passed in are for
1223        // the same driver
1224        if (c && r->impl != c->impl)
1225            return setError(EGL_BAD_MATCH, EGL_FALSE);
1226        impl_read = r->surface;
1227    }
1228
1229    EGLBoolean result;
1230
1231    if (c) {
1232        result = c->cnx->egl.eglMakeCurrent(
1233                dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
1234    } else {
1235        result = cur_c->cnx->egl.eglMakeCurrent(
1236                dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
1237    }
1238
1239    if (result == EGL_TRUE) {
1240        // by construction, these are either 0 or valid (possibly terminated)
1241        // it should be impossible for these to be invalid
1242        ContextRef _cur_c(cur_c);
1243        SurfaceRef _cur_r(cur_r);
1244        SurfaceRef _cur_d(cur_d);
1245
1246        // cur_c has to be valid here (but could be terminated)
1247        if (ctx != EGL_NO_CONTEXT) {
1248            setGlThreadSpecific(c->cnx->hooks[c->version]);
1249            setContext(ctx);
1250            _c.acquire();
1251        } else {
1252            setGlThreadSpecific(&gHooksNoContext);
1253            setContext(EGL_NO_CONTEXT);
1254        }
1255        _cur_c.release();
1256
1257        _r.acquire();
1258        _cur_r.release();
1259        if (c) c->read = read;
1260
1261        _d.acquire();
1262        _cur_d.release();
1263        if (c) c->draw = draw;
1264    }
1265    return result;
1266}
1267
1268
1269EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1270                            EGLint attribute, EGLint *value)
1271{
1272    ContextRef _c(ctx);
1273    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1274
1275    if (!validate_display_context(dpy, ctx))
1276        return EGL_FALSE;
1277
1278    egl_display_t const * const dp = get_display(dpy);
1279    egl_context_t * const c = get_context(ctx);
1280
1281    EGLBoolean result(EGL_TRUE);
1282    if (attribute == EGL_CONFIG_ID) {
1283        *value = dp->configs[intptr_t(c->config)].configId;
1284    } else {
1285        // We need to remap EGL_CONFIG_IDs
1286        result = c->cnx->egl.eglQueryContext(
1287                dp->disp[c->impl].dpy, c->context, attribute, value);
1288    }
1289
1290    return result;
1291}
1292
1293EGLContext eglGetCurrentContext(void)
1294{
1295    // could be called before eglInitialize(), but we wouldn't have a context
1296    // then, and this function would correctly return EGL_NO_CONTEXT.
1297
1298    EGLContext ctx = getContext();
1299    return ctx;
1300}
1301
1302EGLSurface eglGetCurrentSurface(EGLint readdraw)
1303{
1304    // could be called before eglInitialize(), but we wouldn't have a context
1305    // then, and this function would correctly return EGL_NO_SURFACE.
1306
1307    EGLContext ctx = getContext();
1308    if (ctx) {
1309        egl_context_t const * const c = get_context(ctx);
1310        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1311        switch (readdraw) {
1312            case EGL_READ: return c->read;
1313            case EGL_DRAW: return c->draw;
1314            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1315        }
1316    }
1317    return EGL_NO_SURFACE;
1318}
1319
1320EGLDisplay eglGetCurrentDisplay(void)
1321{
1322    // could be called before eglInitialize(), but we wouldn't have a context
1323    // then, and this function would correctly return EGL_NO_DISPLAY.
1324
1325    EGLContext ctx = getContext();
1326    if (ctx) {
1327        egl_context_t const * const c = get_context(ctx);
1328        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1329        return c->dpy;
1330    }
1331    return EGL_NO_DISPLAY;
1332}
1333
1334EGLBoolean eglWaitGL(void)
1335{
1336    // could be called before eglInitialize(), but we wouldn't have a context
1337    // then, and this function would return GL_TRUE, which isn't wrong.
1338
1339    EGLBoolean res = EGL_TRUE;
1340    EGLContext ctx = getContext();
1341    if (ctx) {
1342        egl_context_t const * const c = get_context(ctx);
1343        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1344        if (uint32_t(c->impl)>=2)
1345            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1346        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1347        if (!cnx->dso)
1348            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1349        res = cnx->egl.eglWaitGL();
1350    }
1351    return res;
1352}
1353
1354EGLBoolean eglWaitNative(EGLint engine)
1355{
1356    // could be called before eglInitialize(), but we wouldn't have a context
1357    // then, and this function would return GL_TRUE, which isn't wrong.
1358
1359    EGLBoolean res = EGL_TRUE;
1360    EGLContext ctx = getContext();
1361    if (ctx) {
1362        egl_context_t const * const c = get_context(ctx);
1363        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1364        if (uint32_t(c->impl)>=2)
1365            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1366        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1367        if (!cnx->dso)
1368            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1369        res = cnx->egl.eglWaitNative(engine);
1370    }
1371    return res;
1372}
1373
1374EGLint eglGetError(void)
1375{
1376    EGLint result = EGL_SUCCESS;
1377    EGLint err;
1378    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1379        err = EGL_SUCCESS;
1380        egl_connection_t* const cnx = &gEGLImpl[i];
1381        if (cnx->dso)
1382            err = cnx->egl.eglGetError();
1383        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1384            result = err;
1385    }
1386    err = getError();
1387    if (result == EGL_SUCCESS)
1388        result = err;
1389    return result;
1390}
1391
1392__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
1393{
1394    // eglGetProcAddress() could be the very first function called
1395    // in which case we must make sure we've initialized ourselves, this
1396    // happens the first time egl_get_display() is called.
1397
1398    if (egl_init_drivers() == EGL_FALSE) {
1399        setError(EGL_BAD_PARAMETER, NULL);
1400        return  NULL;
1401    }
1402
1403    __eglMustCastToProperFunctionPointerType addr;
1404    addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1405    if (addr) return addr;
1406
1407    // this protects accesses to gGLExtentionMap and gGLExtentionSlot
1408    pthread_mutex_lock(&gInitDriverMutex);
1409
1410        /*
1411         * Since eglGetProcAddress() is not associated to anything, it needs
1412         * to return a function pointer that "works" regardless of what
1413         * the current context is.
1414         *
1415         * For this reason, we return a "forwarder", a small stub that takes
1416         * care of calling the function associated with the context
1417         * currently bound.
1418         *
1419         * We first look for extensions we've already resolved, if we're seeing
1420         * this extension for the first time, we go through all our
1421         * implementations and call eglGetProcAddress() and record the
1422         * result in the appropriate implementation hooks and return the
1423         * address of the forwarder corresponding to that hook set.
1424         *
1425         */
1426
1427        const String8 name(procname);
1428        addr = gGLExtentionMap.valueFor(name);
1429        const int slot = gGLExtentionSlot;
1430
1431        LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
1432                "no more slots for eglGetProcAddress(\"%s\")",
1433                procname);
1434
1435        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
1436            bool found = false;
1437            for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1438                egl_connection_t* const cnx = &gEGLImpl[i];
1439                if (cnx->dso && cnx->egl.eglGetProcAddress) {
1440                    found = true;
1441                    // Extensions are independent of the bound context
1442                    cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
1443                    cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
1444                            cnx->egl.eglGetProcAddress(procname);
1445                }
1446            }
1447            if (found) {
1448                addr = gExtensionForwarders[slot];
1449                gGLExtentionMap.add(name, addr);
1450                gGLExtentionSlot++;
1451            }
1452        }
1453
1454    pthread_mutex_unlock(&gInitDriverMutex);
1455    return addr;
1456}
1457
1458EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1459{
1460    SurfaceRef _s(draw);
1461    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1462
1463    if (!validate_display_surface(dpy, draw))
1464        return EGL_FALSE;
1465    egl_display_t const * const dp = get_display(dpy);
1466    egl_surface_t const * const s = get_surface(draw);
1467    return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
1468}
1469
1470EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1471                            NativePixmapType target)
1472{
1473    SurfaceRef _s(surface);
1474    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1475
1476    if (!validate_display_surface(dpy, surface))
1477        return EGL_FALSE;
1478    egl_display_t const * const dp = get_display(dpy);
1479    egl_surface_t const * const s = get_surface(surface);
1480    return s->cnx->egl.eglCopyBuffers(
1481            dp->disp[s->impl].dpy, s->surface, target);
1482}
1483
1484const char* eglQueryString(EGLDisplay dpy, EGLint name)
1485{
1486    egl_display_t const * const dp = get_display(dpy);
1487    switch (name) {
1488        case EGL_VENDOR:
1489            return gVendorString;
1490        case EGL_VERSION:
1491            return gVersionString;
1492        case EGL_EXTENSIONS:
1493            return gExtensionString;
1494        case EGL_CLIENT_APIS:
1495            return gClientApiString;
1496    }
1497    return setError(EGL_BAD_PARAMETER, (const char *)0);
1498}
1499
1500
1501// ----------------------------------------------------------------------------
1502// EGL 1.1
1503// ----------------------------------------------------------------------------
1504
1505EGLBoolean eglSurfaceAttrib(
1506        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1507{
1508    SurfaceRef _s(surface);
1509    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1510
1511    if (!validate_display_surface(dpy, surface))
1512        return EGL_FALSE;
1513    egl_display_t const * const dp = get_display(dpy);
1514    egl_surface_t const * const s = get_surface(surface);
1515    if (s->cnx->egl.eglSurfaceAttrib) {
1516        return s->cnx->egl.eglSurfaceAttrib(
1517                dp->disp[s->impl].dpy, s->surface, attribute, value);
1518    }
1519    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1520}
1521
1522EGLBoolean eglBindTexImage(
1523        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1524{
1525    SurfaceRef _s(surface);
1526    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1527
1528    if (!validate_display_surface(dpy, surface))
1529        return EGL_FALSE;
1530    egl_display_t const * const dp = get_display(dpy);
1531    egl_surface_t const * const s = get_surface(surface);
1532    if (s->cnx->egl.eglBindTexImage) {
1533        return s->cnx->egl.eglBindTexImage(
1534                dp->disp[s->impl].dpy, s->surface, buffer);
1535    }
1536    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1537}
1538
1539EGLBoolean eglReleaseTexImage(
1540        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1541{
1542    SurfaceRef _s(surface);
1543    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1544
1545    if (!validate_display_surface(dpy, surface))
1546        return EGL_FALSE;
1547    egl_display_t const * const dp = get_display(dpy);
1548    egl_surface_t const * const s = get_surface(surface);
1549    if (s->cnx->egl.eglReleaseTexImage) {
1550        return s->cnx->egl.eglReleaseTexImage(
1551                dp->disp[s->impl].dpy, s->surface, buffer);
1552    }
1553    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1554}
1555
1556EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1557{
1558    egl_display_t * const dp = get_display(dpy);
1559    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1560
1561    EGLBoolean res = EGL_TRUE;
1562    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1563        egl_connection_t* const cnx = &gEGLImpl[i];
1564        if (cnx->dso) {
1565            if (cnx->egl.eglSwapInterval) {
1566                if (cnx->egl.eglSwapInterval(
1567                        dp->disp[i].dpy, interval) == EGL_FALSE) {
1568                    res = EGL_FALSE;
1569                }
1570            }
1571        }
1572    }
1573    return res;
1574}
1575
1576
1577// ----------------------------------------------------------------------------
1578// EGL 1.2
1579// ----------------------------------------------------------------------------
1580
1581EGLBoolean eglWaitClient(void)
1582{
1583    // could be called before eglInitialize(), but we wouldn't have a context
1584    // then, and this function would return GL_TRUE, which isn't wrong.
1585    EGLBoolean res = EGL_TRUE;
1586    EGLContext ctx = getContext();
1587    if (ctx) {
1588        egl_context_t const * const c = get_context(ctx);
1589        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1590        if (uint32_t(c->impl)>=2)
1591            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1592        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1593        if (!cnx->dso)
1594            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1595        if (cnx->egl.eglWaitClient) {
1596            res = cnx->egl.eglWaitClient();
1597        } else {
1598            res = cnx->egl.eglWaitGL();
1599        }
1600    }
1601    return res;
1602}
1603
1604EGLBoolean eglBindAPI(EGLenum api)
1605{
1606    if (egl_init_drivers() == EGL_FALSE) {
1607        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1608    }
1609
1610    // bind this API on all EGLs
1611    EGLBoolean res = EGL_TRUE;
1612    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1613        egl_connection_t* const cnx = &gEGLImpl[i];
1614        if (cnx->dso) {
1615            if (cnx->egl.eglBindAPI) {
1616                if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
1617                    res = EGL_FALSE;
1618                }
1619            }
1620        }
1621    }
1622    return res;
1623}
1624
1625EGLenum eglQueryAPI(void)
1626{
1627    if (egl_init_drivers() == EGL_FALSE) {
1628        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1629    }
1630
1631    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1632        egl_connection_t* const cnx = &gEGLImpl[i];
1633        if (cnx->dso) {
1634            if (cnx->egl.eglQueryAPI) {
1635                // the first one we find is okay, because they all
1636                // should be the same
1637                return cnx->egl.eglQueryAPI();
1638            }
1639        }
1640    }
1641    // or, it can only be OpenGL ES
1642    return EGL_OPENGL_ES_API;
1643}
1644
1645EGLBoolean eglReleaseThread(void)
1646{
1647    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1648        egl_connection_t* const cnx = &gEGLImpl[i];
1649        if (cnx->dso) {
1650            if (cnx->egl.eglReleaseThread) {
1651                cnx->egl.eglReleaseThread();
1652            }
1653        }
1654    }
1655    clearTLS();
1656    return EGL_TRUE;
1657}
1658
1659EGLSurface eglCreatePbufferFromClientBuffer(
1660          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1661          EGLConfig config, const EGLint *attrib_list)
1662{
1663    egl_display_t const* dp = 0;
1664    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1665    if (!cnx) return EGL_FALSE;
1666    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1667        return cnx->egl.eglCreatePbufferFromClientBuffer(
1668                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1669                buftype, buffer,
1670                dp->configs[intptr_t(config)].config, attrib_list);
1671    }
1672    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1673}
1674
1675// ----------------------------------------------------------------------------
1676// EGL_EGLEXT_VERSION 3
1677// ----------------------------------------------------------------------------
1678
1679EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1680        const EGLint *attrib_list)
1681{
1682    SurfaceRef _s(surface);
1683    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1684
1685    if (!validate_display_surface(dpy, surface))
1686        return EGL_FALSE;
1687
1688    egl_display_t const * const dp = get_display(dpy);
1689    egl_surface_t const * const s = get_surface(surface);
1690
1691    if (s->cnx->egl.eglLockSurfaceKHR) {
1692        return s->cnx->egl.eglLockSurfaceKHR(
1693                dp->disp[s->impl].dpy, s->surface, attrib_list);
1694    }
1695    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1696}
1697
1698EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1699{
1700    SurfaceRef _s(surface);
1701    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1702
1703    if (!validate_display_surface(dpy, surface))
1704        return EGL_FALSE;
1705
1706    egl_display_t const * const dp = get_display(dpy);
1707    egl_surface_t const * const s = get_surface(surface);
1708
1709    if (s->cnx->egl.eglUnlockSurfaceKHR) {
1710        return s->cnx->egl.eglUnlockSurfaceKHR(
1711                dp->disp[s->impl].dpy, s->surface);
1712    }
1713    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1714}
1715
1716EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1717        EGLClientBuffer buffer, const EGLint *attrib_list)
1718{
1719    if (ctx != EGL_NO_CONTEXT) {
1720        ContextRef _c(ctx);
1721        if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1722        if (!validate_display_context(dpy, ctx))
1723            return EGL_NO_IMAGE_KHR;
1724        egl_display_t const * const dp = get_display(dpy);
1725        egl_context_t * const c = get_context(ctx);
1726        // since we have an EGLContext, we know which implementation to use
1727        EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
1728                dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
1729        if (image == EGL_NO_IMAGE_KHR)
1730            return image;
1731
1732        egl_image_t* result = new egl_image_t(dpy, ctx);
1733        result->images[c->impl] = image;
1734        return (EGLImageKHR)result;
1735    } else {
1736        // EGL_NO_CONTEXT is a valid parameter
1737        egl_display_t const * const dp = get_display(dpy);
1738        if (dp == 0) {
1739            return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1740        }
1741
1742        /* Since we don't have a way to know which implementation to call,
1743         * we're calling all of them. If at least one of the implementation
1744         * succeeded, this is a success.
1745         */
1746
1747        EGLint currentError = eglGetError();
1748
1749        EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
1750        bool success = false;
1751        for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1752            egl_connection_t* const cnx = &gEGLImpl[i];
1753            implImages[i] = EGL_NO_IMAGE_KHR;
1754            if (cnx->dso) {
1755                if (cnx->egl.eglCreateImageKHR) {
1756                    implImages[i] = cnx->egl.eglCreateImageKHR(
1757                            dp->disp[i].dpy, ctx, target, buffer, attrib_list);
1758                    if (implImages[i] != EGL_NO_IMAGE_KHR) {
1759                        success = true;
1760                    }
1761                }
1762            }
1763        }
1764
1765        if (!success) {
1766            // failure, if there was an error when we entered this function,
1767            // the error flag must not be updated.
1768            // Otherwise, the error is whatever happened in the implementation
1769            // that faulted.
1770            if (currentError != EGL_SUCCESS) {
1771                setError(currentError, EGL_NO_IMAGE_KHR);
1772            }
1773            return EGL_NO_IMAGE_KHR;
1774        } else {
1775            // In case of success, we need to clear all error flags
1776            // (especially those caused by the implementation that didn't
1777            // succeed). TODO: we could avoid this if we knew this was
1778            // a "full" success (all implementation succeeded).
1779            eglGetError();
1780        }
1781
1782        egl_image_t* result = new egl_image_t(dpy, ctx);
1783        memcpy(result->images, implImages, sizeof(implImages));
1784        return (EGLImageKHR)result;
1785    }
1786}
1787
1788EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1789{
1790    egl_display_t const * const dp = get_display(dpy);
1791     if (dp == 0) {
1792         return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1793     }
1794
1795     ImageRef _i(img);
1796     if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1797
1798     egl_image_t* image = get_image(img);
1799     bool success = false;
1800     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1801         egl_connection_t* const cnx = &gEGLImpl[i];
1802         if (image->images[i] != EGL_NO_IMAGE_KHR) {
1803             if (cnx->dso) {
1804                 if (cnx->egl.eglDestroyImageKHR) {
1805                     if (cnx->egl.eglDestroyImageKHR(
1806                             dp->disp[i].dpy, image->images[i])) {
1807                         success = true;
1808                     }
1809                 }
1810             }
1811         }
1812     }
1813     if (!success)
1814         return EGL_FALSE;
1815
1816     _i.terminate();
1817
1818     return EGL_TRUE;
1819}
1820
1821// ----------------------------------------------------------------------------
1822// EGL_EGLEXT_VERSION 5
1823// ----------------------------------------------------------------------------
1824
1825
1826EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1827{
1828    EGLContext ctx = eglGetCurrentContext();
1829    ContextRef _c(ctx);
1830    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
1831    if (!validate_display_context(dpy, ctx))
1832        return EGL_NO_SYNC_KHR;
1833    egl_display_t const * const dp = get_display(dpy);
1834    egl_context_t * const c = get_context(ctx);
1835    EGLSyncKHR result = EGL_NO_SYNC_KHR;
1836    if (c->cnx->egl.eglCreateSyncKHR) {
1837        EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
1838                dp->disp[c->impl].dpy, type, attrib_list);
1839        if (sync == EGL_NO_SYNC_KHR)
1840            return sync;
1841        result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
1842    }
1843    return (EGLSyncKHR)result;
1844}
1845
1846EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1847{
1848    egl_display_t const * const dp = get_display(dpy);
1849    if (dp == 0) {
1850        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1851    }
1852
1853    SyncRef _s(sync);
1854    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1855    egl_sync_t* syncObject = get_sync(sync);
1856
1857    EGLContext ctx = syncObject->context;
1858    ContextRef _c(ctx);
1859    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1860    if (!validate_display_context(dpy, ctx))
1861        return EGL_FALSE;
1862
1863    egl_context_t * const c = get_context(ctx);
1864
1865    if (c->cnx->egl.eglDestroySyncKHR) {
1866        return c->cnx->egl.eglDestroySyncKHR(
1867                dp->disp[c->impl].dpy, syncObject->sync);
1868    }
1869
1870    return EGL_FALSE;
1871}
1872
1873EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1874{
1875    egl_display_t const * const dp = get_display(dpy);
1876    if (dp == 0) {
1877        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1878    }
1879
1880    SyncRef _s(sync);
1881    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1882    egl_sync_t* syncObject = get_sync(sync);
1883
1884    EGLContext ctx = syncObject->context;
1885    ContextRef _c(ctx);
1886    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1887    if (!validate_display_context(dpy, ctx))
1888        return EGL_FALSE;
1889
1890    egl_context_t * const c = get_context(ctx);
1891
1892    if (c->cnx->egl.eglClientWaitSyncKHR) {
1893        return c->cnx->egl.eglClientWaitSyncKHR(
1894                dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
1895    }
1896
1897    return EGL_FALSE;
1898}
1899
1900EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1901{
1902    egl_display_t const * const dp = get_display(dpy);
1903    if (dp == 0) {
1904        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1905    }
1906
1907    SyncRef _s(sync);
1908    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1909    egl_sync_t* syncObject = get_sync(sync);
1910
1911    EGLContext ctx = syncObject->context;
1912    ContextRef _c(ctx);
1913    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1914    if (!validate_display_context(dpy, ctx))
1915        return EGL_FALSE;
1916
1917    egl_context_t * const c = get_context(ctx);
1918
1919    if (c->cnx->egl.eglGetSyncAttribKHR) {
1920        return c->cnx->egl.eglGetSyncAttribKHR(
1921                dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
1922    }
1923
1924    return EGL_FALSE;
1925}
1926
1927// ----------------------------------------------------------------------------
1928// ANDROID extensions
1929// ----------------------------------------------------------------------------
1930
1931EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1932        EGLint left, EGLint top, EGLint width, EGLint height)
1933{
1934    SurfaceRef _s(draw);
1935    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1936
1937    if (!validate_display_surface(dpy, draw))
1938        return EGL_FALSE;
1939    egl_display_t const * const dp = get_display(dpy);
1940    egl_surface_t const * const s = get_surface(draw);
1941    if (s->cnx->egl.eglSetSwapRectangleANDROID) {
1942        return s->cnx->egl.eglSetSwapRectangleANDROID(
1943                dp->disp[s->impl].dpy, s->surface, left, top, width, height);
1944    }
1945    return setError(EGL_BAD_DISPLAY, NULL);
1946}
1947