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