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