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