eglApi.cpp revision bee205fd58a27c10a0895de5339e76025d429d2b
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
21#include <hardware/gralloc.h>
22#include <system/window.h>
23
24#include <EGL/egl.h>
25#include <EGL/eglext.h>
26#include <GLES/gl.h>
27#include <GLES/glext.h>
28
29#include <cutils/log.h>
30#include <cutils/atomic.h>
31#include <cutils/properties.h>
32#include <cutils/memory.h>
33
34#include <utils/KeyedVector.h>
35#include <utils/SortedVector.h>
36#include <utils/String8.h>
37
38#include "egl_impl.h"
39#include "egl_tls.h"
40#include "glesv2dbg.h"
41#include "hooks.h"
42
43#include "egl_display.h"
44#include "egl_impl.h"
45#include "egl_object.h"
46#include "egl_tls.h"
47
48using namespace android;
49
50// ----------------------------------------------------------------------------
51
52static char const * const sVendorString     = "Android";
53static char const * const sVersionString    = "1.4 Android META-EGL";
54static char const * const sClientApiString  = "OpenGL ES";
55static char const * const sExtensionString  =
56        "EGL_KHR_image "
57        "EGL_KHR_image_base "
58        "EGL_KHR_image_pixmap "
59        "EGL_KHR_gl_texture_2D_image "
60        "EGL_KHR_gl_texture_cubemap_image "
61        "EGL_KHR_gl_renderbuffer_image "
62        "EGL_KHR_fence_sync "
63        "EGL_ANDROID_image_native_buffer "
64        "EGL_ANDROID_swap_rectangle "
65        ;
66
67struct extention_map_t {
68    const char* name;
69    __eglMustCastToProperFunctionPointerType address;
70};
71
72static const extention_map_t sExtentionMap[] = {
73    { "eglLockSurfaceKHR",
74            (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
75    { "eglUnlockSurfaceKHR",
76            (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
77    { "eglCreateImageKHR",
78            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
79    { "eglDestroyImageKHR",
80            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
81    { "eglSetSwapRectangleANDROID",
82            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
83};
84
85// accesses protected by sExtensionMapMutex
86static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
87static int sGLExtentionSlot = 0;
88static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
89
90static void(*findProcAddress(const char* name,
91        const extention_map_t* map, size_t n))() {
92    for (uint32_t i=0 ; i<n ; i++) {
93        if (!strcmp(name, map[i].name)) {
94            return map[i].address;
95        }
96    }
97    return NULL;
98}
99
100// ----------------------------------------------------------------------------
101
102template<typename T>
103static __attribute__((noinline))
104int binarySearch(T const sortedArray[], int first, int last, T key) {
105    while (first <= last) {
106        int mid = (first + last) / 2;
107        if (sortedArray[mid] < key) {
108            first = mid + 1;
109        } else if (key < sortedArray[mid]) {
110            last = mid - 1;
111        } else {
112            return mid;
113        }
114    }
115    return -1;
116}
117
118// ----------------------------------------------------------------------------
119
120namespace android {
121extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
122extern EGLBoolean egl_init_drivers();
123extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
124extern int gEGLDebugLevel;
125extern gl_hooks_t gHooksTrace;
126extern gl_hooks_t gHooksDebug;
127} // namespace android;
128
129// ----------------------------------------------------------------------------
130
131static inline void clearError() { egl_tls_t::clearError(); }
132static inline EGLContext getContext() { return egl_tls_t::getContext(); }
133
134// ----------------------------------------------------------------------------
135
136EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
137{
138    clearError();
139
140    uint32_t index = uint32_t(display);
141    if (index >= NUM_DISPLAYS) {
142        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
143    }
144
145    if (egl_init_drivers() == EGL_FALSE) {
146        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
147    }
148
149    EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
150    return dpy;
151}
152
153// ----------------------------------------------------------------------------
154// Initialization
155// ----------------------------------------------------------------------------
156
157EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
158{
159    clearError();
160
161    egl_display_t * const dp = get_display(dpy);
162    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
163
164    EGLBoolean res = dp->initialize(major, minor);
165
166    return res;
167}
168
169EGLBoolean eglTerminate(EGLDisplay dpy)
170{
171    // NOTE: don't unload the drivers b/c some APIs can be called
172    // after eglTerminate() has been called. eglTerminate() only
173    // terminates an EGLDisplay, not a EGL itself.
174
175    clearError();
176
177    egl_display_t* const dp = get_display(dpy);
178    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
179
180    EGLBoolean res = dp->terminate();
181
182    return res;
183}
184
185// ----------------------------------------------------------------------------
186// configuration
187// ----------------------------------------------------------------------------
188
189EGLBoolean eglGetConfigs(   EGLDisplay dpy,
190                            EGLConfig *configs,
191                            EGLint config_size, EGLint *num_config)
192{
193    clearError();
194
195    egl_display_t const * const dp = validate_display(dpy);
196    if (!dp) return EGL_FALSE;
197
198    GLint numConfigs = dp->numTotalConfigs;
199    if (!configs) {
200        *num_config = numConfigs;
201        return EGL_TRUE;
202    }
203
204    GLint n = 0;
205    for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
206        *configs++ = EGLConfig(i);
207        config_size--;
208        n++;
209    }
210
211    *num_config = n;
212    return EGL_TRUE;
213}
214
215EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
216                            EGLConfig *configs, EGLint config_size,
217                            EGLint *num_config)
218{
219    clearError();
220
221    egl_display_t const * const dp = validate_display(dpy);
222    if (!dp) return EGL_FALSE;
223
224    if (num_config==0) {
225        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
226    }
227
228    EGLint n;
229    EGLBoolean res = EGL_FALSE;
230    *num_config = 0;
231
232
233    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
234    // to do this, we have to go through the attrib_list array once
235    // to figure out both its size and if it contains an EGL_CONFIG_ID
236    // key. If so, the full array is copied and patched.
237    // NOTE: we assume that there can be only one occurrence
238    // of EGL_CONFIG_ID.
239
240    EGLint patch_index = -1;
241    GLint attr;
242    size_t size = 0;
243    if (attrib_list) {
244        while ((attr=attrib_list[size]) != EGL_NONE) {
245            if (attr == EGL_CONFIG_ID)
246                patch_index = size;
247            size += 2;
248        }
249    }
250    if (patch_index >= 0) {
251        size += 2; // we need copy the sentinel as well
252        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
253        if (new_list == 0)
254            return setError(EGL_BAD_ALLOC, EGL_FALSE);
255        memcpy(new_list, attrib_list, size*sizeof(EGLint));
256
257        // patch the requested EGL_CONFIG_ID
258        bool found = false;
259        EGLConfig ourConfig(0);
260        EGLint& configId(new_list[patch_index+1]);
261        for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
262            if (dp->configs[i].configId == configId) {
263                ourConfig = EGLConfig(i);
264                configId = dp->configs[i].implConfigId;
265                found = true;
266                break;
267            }
268        }
269
270        egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
271        if (found && cnx->dso) {
272            // and switch to the new list
273            attrib_list = const_cast<const EGLint *>(new_list);
274
275            // At this point, the only configuration that can match is
276            // dp->configs[i][index], however, we don't know if it would be
277            // rejected because of the other attributes, so we do have to call
278            // cnx->egl.eglChooseConfig() -- but we don't have to loop
279            // through all the EGLimpl[].
280            // We also know we can only get a single config back, and we know
281            // which one.
282
283            res = cnx->egl.eglChooseConfig(
284                    dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
285                    attrib_list, configs, config_size, &n);
286            if (res && n>0) {
287                // n has to be 0 or 1, by construction, and we already know
288                // which config it will return (since there can be only one).
289                if (configs) {
290                    configs[0] = ourConfig;
291                }
292                *num_config = 1;
293            }
294        }
295
296        free(const_cast<EGLint *>(attrib_list));
297        return res;
298    }
299
300
301    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
302        egl_connection_t* const cnx = &gEGLImpl[i];
303        if (cnx->dso) {
304            if (cnx->egl.eglChooseConfig(
305                    dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
306                if (configs) {
307                    // now we need to convert these client EGLConfig to our
308                    // internal EGLConfig format.
309                    // This is done in O(n Log(n)) time.
310                    for (int j=0 ; j<n ; j++) {
311                        egl_config_t key(i, configs[j]);
312                        intptr_t index = binarySearch<egl_config_t>(
313                                dp->configs, 0, dp->numTotalConfigs, key);
314                        if (index >= 0) {
315                            configs[j] = EGLConfig(index);
316                        } else {
317                            return setError(EGL_BAD_CONFIG, EGL_FALSE);
318                        }
319                    }
320                    configs += n;
321                    config_size -= n;
322                }
323                *num_config += n;
324                res = EGL_TRUE;
325            }
326        }
327    }
328    return res;
329}
330
331EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
332        EGLint attribute, EGLint *value)
333{
334    clearError();
335
336    egl_display_t const* dp = 0;
337    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
338    if (!cnx) return EGL_FALSE;
339
340    if (attribute == EGL_CONFIG_ID) {
341        *value = dp->configs[intptr_t(config)].configId;
342        return EGL_TRUE;
343    }
344    return cnx->egl.eglGetConfigAttrib(
345            dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
346            dp->configs[intptr_t(config)].config, attribute, value);
347}
348
349// ----------------------------------------------------------------------------
350// surfaces
351// ----------------------------------------------------------------------------
352
353EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
354                                    NativeWindowType window,
355                                    const EGLint *attrib_list)
356{
357    clearError();
358
359    egl_display_t const* dp = 0;
360    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
361    if (cnx) {
362        EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy;
363        EGLConfig iConfig = dp->configs[intptr_t(config)].config;
364        EGLint format;
365
366        // set the native window's buffers format to match this config
367        if (cnx->egl.eglGetConfigAttrib(iDpy,
368                iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
369            if (format != 0) {
370                int err = native_window_set_buffers_format(window, format);
371                if (err != 0) {
372                    LOGE("error setting native window pixel format: %s (%d)",
373                            strerror(-err), err);
374                    return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
375                }
376            }
377        }
378
379        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
380                iDpy, iConfig, window, attrib_list);
381        if (surface != EGL_NO_SURFACE) {
382            egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
383                    dp->configs[intptr_t(config)].impl, cnx);
384            return s;
385        }
386    }
387    return EGL_NO_SURFACE;
388}
389
390EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
391                                    NativePixmapType pixmap,
392                                    const EGLint *attrib_list)
393{
394    clearError();
395
396    egl_display_t const* dp = 0;
397    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
398    if (cnx) {
399        EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
400                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
401                dp->configs[intptr_t(config)].config, pixmap, attrib_list);
402        if (surface != EGL_NO_SURFACE) {
403            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
404                    dp->configs[intptr_t(config)].impl, cnx);
405            return s;
406        }
407    }
408    return EGL_NO_SURFACE;
409}
410
411EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
412                                    const EGLint *attrib_list)
413{
414    clearError();
415
416    egl_display_t const* dp = 0;
417    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
418    if (cnx) {
419        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
420                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
421                dp->configs[intptr_t(config)].config, attrib_list);
422        if (surface != EGL_NO_SURFACE) {
423            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
424                    dp->configs[intptr_t(config)].impl, cnx);
425            return s;
426        }
427    }
428    return EGL_NO_SURFACE;
429}
430
431EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
432{
433    clearError();
434
435    egl_display_t const * const dp = validate_display(dpy);
436    if (!dp) return EGL_FALSE;
437
438    SurfaceRef _s(surface);
439    if (!_s.get())
440        return setError(EGL_BAD_SURFACE, EGL_FALSE);
441
442    egl_surface_t * const s = get_surface(surface);
443    EGLBoolean result = s->cnx->egl.eglDestroySurface(
444            dp->disp[s->impl].dpy, s->surface);
445    if (result == EGL_TRUE) {
446        if (s->win != NULL) {
447            native_window_set_buffers_geometry(s->win.get(), 0, 0, 0);
448        }
449        _s.terminate();
450    }
451    return result;
452}
453
454EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
455                            EGLint attribute, EGLint *value)
456{
457    clearError();
458
459    egl_display_t const * const dp = validate_display(dpy);
460    if (!dp) return EGL_FALSE;
461
462    SurfaceRef _s(surface);
463    if (!_s.get())
464        return setError(EGL_BAD_SURFACE, EGL_FALSE);
465
466    egl_surface_t const * const s = get_surface(surface);
467    EGLBoolean result(EGL_TRUE);
468    if (attribute == EGL_CONFIG_ID) {
469        // We need to remap EGL_CONFIG_IDs
470        *value = dp->configs[intptr_t(s->config)].configId;
471    } else {
472        result = s->cnx->egl.eglQuerySurface(
473                dp->disp[s->impl].dpy, s->surface, attribute, value);
474    }
475
476    return result;
477}
478
479// ----------------------------------------------------------------------------
480// Contexts
481// ----------------------------------------------------------------------------
482
483EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
484                            EGLContext share_list, const EGLint *attrib_list)
485{
486    clearError();
487
488    egl_display_t const* dp = 0;
489    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
490    if (cnx) {
491        if (share_list != EGL_NO_CONTEXT) {
492            egl_context_t* const c = get_context(share_list);
493            share_list = c->context;
494        }
495        EGLContext context = cnx->egl.eglCreateContext(
496                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
497                dp->configs[intptr_t(config)].config,
498                share_list, attrib_list);
499        if (context != EGL_NO_CONTEXT) {
500            // figure out if it's a GLESv1 or GLESv2
501            int version = 0;
502            if (attrib_list) {
503                while (*attrib_list != EGL_NONE) {
504                    GLint attr = *attrib_list++;
505                    GLint value = *attrib_list++;
506                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
507                        if (value == 1) {
508                            version = GLESv1_INDEX;
509                        } else if (value == 2) {
510                            version = GLESv2_INDEX;
511                        }
512                    }
513                };
514            }
515            egl_context_t* c = new egl_context_t(dpy, context, config,
516                    dp->configs[intptr_t(config)].impl, cnx, version);
517            return c;
518        }
519    }
520    return EGL_NO_CONTEXT;
521}
522
523EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
524{
525    clearError();
526
527    egl_display_t const * const dp = validate_display(dpy);
528    if (!dp)
529        return EGL_FALSE;
530
531    ContextRef _c(ctx);
532    if (!_c.get())
533        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
534
535    egl_context_t * const c = get_context(ctx);
536    EGLBoolean result = c->cnx->egl.eglDestroyContext(
537            dp->disp[c->impl].dpy, c->context);
538    if (result == EGL_TRUE) {
539        _c.terminate();
540    }
541    return result;
542}
543
544static void loseCurrent(egl_context_t * cur_c)
545{
546    if (cur_c) {
547        egl_surface_t * cur_r = get_surface(cur_c->read);
548        egl_surface_t * cur_d = get_surface(cur_c->draw);
549
550        // by construction, these are either 0 or valid (possibly terminated)
551        // it should be impossible for these to be invalid
552        ContextRef _cur_c(cur_c);
553        SurfaceRef _cur_r(cur_r);
554        SurfaceRef _cur_d(cur_d);
555
556        cur_c->read = NULL;
557        cur_c->draw = NULL;
558
559        _cur_c.release();
560        _cur_r.release();
561        _cur_d.release();
562    }
563}
564
565EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
566                            EGLSurface read, EGLContext ctx)
567{
568    clearError();
569
570    egl_display_t const * const dp = get_display(dpy);
571    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
572
573    // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
574    // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
575    // a valid but uninitialized display.
576    if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
577         (draw != EGL_NO_SURFACE) ) {
578        if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
579    }
580
581    // get a reference to the object passed in
582    ContextRef _c(ctx);
583    SurfaceRef _d(draw);
584    SurfaceRef _r(read);
585
586    // validate the context (if not EGL_NO_CONTEXT)
587    if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
588        // EGL_NO_CONTEXT is valid
589        return EGL_FALSE;
590    }
591
592    // these are the underlying implementation's object
593    EGLContext impl_ctx  = EGL_NO_CONTEXT;
594    EGLSurface impl_draw = EGL_NO_SURFACE;
595    EGLSurface impl_read = EGL_NO_SURFACE;
596
597    // these are our objects structs passed in
598    egl_context_t       * c = NULL;
599    egl_surface_t const * d = NULL;
600    egl_surface_t const * r = NULL;
601
602    // these are the current objects structs
603    egl_context_t * cur_c = get_context(getContext());
604
605    if (ctx != EGL_NO_CONTEXT) {
606        c = get_context(ctx);
607        impl_ctx = c->context;
608    } else {
609        // no context given, use the implementation of the current context
610        if (cur_c == NULL) {
611            // no current context
612            if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
613                // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
614                return setError(EGL_BAD_MATCH, EGL_FALSE);
615            }
616            // not an error, there is just no current context.
617            return EGL_TRUE;
618        }
619    }
620
621    // retrieve the underlying implementation's draw EGLSurface
622    if (draw != EGL_NO_SURFACE) {
623        d = get_surface(draw);
624        // make sure the EGLContext and EGLSurface passed in are for
625        // the same driver
626        if (c && d->impl != c->impl)
627            return setError(EGL_BAD_MATCH, EGL_FALSE);
628        impl_draw = d->surface;
629    }
630
631    // retrieve the underlying implementation's read EGLSurface
632    if (read != EGL_NO_SURFACE) {
633        r = get_surface(read);
634        // make sure the EGLContext and EGLSurface passed in are for
635        // the same driver
636        if (c && r->impl != c->impl)
637            return setError(EGL_BAD_MATCH, EGL_FALSE);
638        impl_read = r->surface;
639    }
640
641    EGLBoolean result;
642
643    if (c) {
644        result = c->cnx->egl.eglMakeCurrent(
645                dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
646    } else {
647        result = cur_c->cnx->egl.eglMakeCurrent(
648                dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
649    }
650
651    if (result == EGL_TRUE) {
652
653        loseCurrent(cur_c);
654
655        if (ctx != EGL_NO_CONTEXT) {
656            setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
657            egl_tls_t::setContext(ctx);
658            if (gEGLDebugLevel > 0) {
659                CreateDbgContext(c->version, c->cnx->hooks[c->version]);
660            }
661            _c.acquire();
662            _r.acquire();
663            _d.acquire();
664            c->read = read;
665            c->draw = draw;
666        } else {
667            setGLHooksThreadSpecific(&gHooksNoContext);
668            egl_tls_t::setContext(EGL_NO_CONTEXT);
669        }
670    }
671    return result;
672}
673
674
675EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
676                            EGLint attribute, EGLint *value)
677{
678    clearError();
679
680    egl_display_t const * const dp = validate_display(dpy);
681    if (!dp) return EGL_FALSE;
682
683    ContextRef _c(ctx);
684    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
685
686    egl_context_t * const c = get_context(ctx);
687
688    EGLBoolean result(EGL_TRUE);
689    if (attribute == EGL_CONFIG_ID) {
690        *value = dp->configs[intptr_t(c->config)].configId;
691    } else {
692        // We need to remap EGL_CONFIG_IDs
693        result = c->cnx->egl.eglQueryContext(
694                dp->disp[c->impl].dpy, c->context, attribute, value);
695    }
696
697    return result;
698}
699
700EGLContext eglGetCurrentContext(void)
701{
702    // could be called before eglInitialize(), but we wouldn't have a context
703    // then, and this function would correctly return EGL_NO_CONTEXT.
704
705    clearError();
706
707    EGLContext ctx = getContext();
708    return ctx;
709}
710
711EGLSurface eglGetCurrentSurface(EGLint readdraw)
712{
713    // could be called before eglInitialize(), but we wouldn't have a context
714    // then, and this function would correctly return EGL_NO_SURFACE.
715
716    clearError();
717
718    EGLContext ctx = getContext();
719    if (ctx) {
720        egl_context_t const * const c = get_context(ctx);
721        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
722        switch (readdraw) {
723            case EGL_READ: return c->read;
724            case EGL_DRAW: return c->draw;
725            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
726        }
727    }
728    return EGL_NO_SURFACE;
729}
730
731EGLDisplay eglGetCurrentDisplay(void)
732{
733    // could be called before eglInitialize(), but we wouldn't have a context
734    // then, and this function would correctly return EGL_NO_DISPLAY.
735
736    clearError();
737
738    EGLContext ctx = getContext();
739    if (ctx) {
740        egl_context_t const * const c = get_context(ctx);
741        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
742        return c->dpy;
743    }
744    return EGL_NO_DISPLAY;
745}
746
747EGLBoolean eglWaitGL(void)
748{
749    // could be called before eglInitialize(), but we wouldn't have a context
750    // then, and this function would return GL_TRUE, which isn't wrong.
751
752    clearError();
753
754    EGLBoolean res = EGL_TRUE;
755    EGLContext ctx = getContext();
756    if (ctx) {
757        egl_context_t const * const c = get_context(ctx);
758        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
759        if (uint32_t(c->impl)>=2)
760            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
761        egl_connection_t* const cnx = &gEGLImpl[c->impl];
762        if (!cnx->dso)
763            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
764        res = cnx->egl.eglWaitGL();
765    }
766    return res;
767}
768
769EGLBoolean eglWaitNative(EGLint engine)
770{
771    // could be called before eglInitialize(), but we wouldn't have a context
772    // then, and this function would return GL_TRUE, which isn't wrong.
773
774    clearError();
775
776    EGLBoolean res = EGL_TRUE;
777    EGLContext ctx = getContext();
778    if (ctx) {
779        egl_context_t const * const c = get_context(ctx);
780        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
781        if (uint32_t(c->impl)>=2)
782            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
783        egl_connection_t* const cnx = &gEGLImpl[c->impl];
784        if (!cnx->dso)
785            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
786        res = cnx->egl.eglWaitNative(engine);
787    }
788    return res;
789}
790
791EGLint eglGetError(void)
792{
793    EGLint result = EGL_SUCCESS;
794    EGLint err;
795    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
796        err = EGL_SUCCESS;
797        egl_connection_t* const cnx = &gEGLImpl[i];
798        if (cnx->dso)
799            err = cnx->egl.eglGetError();
800        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
801            result = err;
802    }
803    err = egl_tls_t::getError();
804    if (result == EGL_SUCCESS)
805        result = err;
806    return result;
807}
808
809// Note: Similar implementations of these functions also exist in
810// gl2.cpp and gl.cpp, and are used by applications that call the
811// exported entry points directly.
812typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
813typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
814
815static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
816static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
817
818static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
819{
820    GLeglImageOES implImage =
821        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
822    glEGLImageTargetTexture2DOES_impl(target, implImage);
823}
824
825static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
826{
827    GLeglImageOES implImage =
828        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
829    glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
830}
831
832__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
833{
834    // eglGetProcAddress() could be the very first function called
835    // in which case we must make sure we've initialized ourselves, this
836    // happens the first time egl_get_display() is called.
837
838    clearError();
839
840    if (egl_init_drivers() == EGL_FALSE) {
841        setError(EGL_BAD_PARAMETER, NULL);
842        return  NULL;
843    }
844
845    __eglMustCastToProperFunctionPointerType addr;
846    addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
847    if (addr) return addr;
848
849    // this protects accesses to sGLExtentionMap and sGLExtentionSlot
850    pthread_mutex_lock(&sExtensionMapMutex);
851
852        /*
853         * Since eglGetProcAddress() is not associated to anything, it needs
854         * to return a function pointer that "works" regardless of what
855         * the current context is.
856         *
857         * For this reason, we return a "forwarder", a small stub that takes
858         * care of calling the function associated with the context
859         * currently bound.
860         *
861         * We first look for extensions we've already resolved, if we're seeing
862         * this extension for the first time, we go through all our
863         * implementations and call eglGetProcAddress() and record the
864         * result in the appropriate implementation hooks and return the
865         * address of the forwarder corresponding to that hook set.
866         *
867         */
868
869        const String8 name(procname);
870        addr = sGLExtentionMap.valueFor(name);
871        const int slot = sGLExtentionSlot;
872
873        LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
874                "no more slots for eglGetProcAddress(\"%s\")",
875                procname);
876
877        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
878            bool found = false;
879            for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
880                egl_connection_t* const cnx = &gEGLImpl[i];
881                if (cnx->dso && cnx->egl.eglGetProcAddress) {
882                    found = true;
883                    // Extensions are independent of the bound context
884                    cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
885                    cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
886#if EGL_TRACE
887                    gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
888#endif
889                            cnx->egl.eglGetProcAddress(procname);
890                }
891            }
892            if (found) {
893                addr = gExtensionForwarders[slot];
894
895                if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
896                    glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
897                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
898                }
899                if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
900                    glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
901                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
902                }
903
904                sGLExtentionMap.add(name, addr);
905                sGLExtentionSlot++;
906            }
907        }
908
909    pthread_mutex_unlock(&sExtensionMapMutex);
910    return addr;
911}
912
913EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
914{
915    EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
916    if (gEGLDebugLevel > 0)
917        Debug_eglSwapBuffers(dpy, draw);
918
919    clearError();
920
921    egl_display_t const * const dp = validate_display(dpy);
922    if (!dp) return EGL_FALSE;
923
924    SurfaceRef _s(draw);
925    if (!_s.get())
926        return setError(EGL_BAD_SURFACE, EGL_FALSE);
927
928    egl_surface_t const * const s = get_surface(draw);
929    return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
930}
931
932EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
933                            NativePixmapType target)
934{
935    clearError();
936
937    egl_display_t const * const dp = validate_display(dpy);
938    if (!dp) return EGL_FALSE;
939
940    SurfaceRef _s(surface);
941    if (!_s.get())
942        return setError(EGL_BAD_SURFACE, EGL_FALSE);
943
944    egl_surface_t const * const s = get_surface(surface);
945    return s->cnx->egl.eglCopyBuffers(
946            dp->disp[s->impl].dpy, s->surface, target);
947}
948
949const char* eglQueryString(EGLDisplay dpy, EGLint name)
950{
951    clearError();
952
953    egl_display_t const * const dp = validate_display(dpy);
954    if (!dp) return (const char *) NULL;
955
956    switch (name) {
957        case EGL_VENDOR:
958            return sVendorString;
959        case EGL_VERSION:
960            return sVersionString;
961        case EGL_EXTENSIONS:
962            return sExtensionString;
963        case EGL_CLIENT_APIS:
964            return sClientApiString;
965    }
966    return setError(EGL_BAD_PARAMETER, (const char *)0);
967}
968
969
970// ----------------------------------------------------------------------------
971// EGL 1.1
972// ----------------------------------------------------------------------------
973
974EGLBoolean eglSurfaceAttrib(
975        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
976{
977    clearError();
978
979    egl_display_t const * const dp = validate_display(dpy);
980    if (!dp) return EGL_FALSE;
981
982    SurfaceRef _s(surface);
983    if (!_s.get())
984        return setError(EGL_BAD_SURFACE, EGL_FALSE);
985
986    egl_surface_t const * const s = get_surface(surface);
987    if (s->cnx->egl.eglSurfaceAttrib) {
988        return s->cnx->egl.eglSurfaceAttrib(
989                dp->disp[s->impl].dpy, s->surface, attribute, value);
990    }
991    return setError(EGL_BAD_SURFACE, EGL_FALSE);
992}
993
994EGLBoolean eglBindTexImage(
995        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
996{
997    clearError();
998
999    egl_display_t const * const dp = validate_display(dpy);
1000    if (!dp) return EGL_FALSE;
1001
1002    SurfaceRef _s(surface);
1003    if (!_s.get())
1004        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1005
1006    egl_surface_t const * const s = get_surface(surface);
1007    if (s->cnx->egl.eglBindTexImage) {
1008        return s->cnx->egl.eglBindTexImage(
1009                dp->disp[s->impl].dpy, s->surface, buffer);
1010    }
1011    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1012}
1013
1014EGLBoolean eglReleaseTexImage(
1015        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1016{
1017    clearError();
1018
1019    egl_display_t const * const dp = validate_display(dpy);
1020    if (!dp) return EGL_FALSE;
1021
1022    SurfaceRef _s(surface);
1023    if (!_s.get())
1024        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1025
1026    egl_surface_t const * const s = get_surface(surface);
1027    if (s->cnx->egl.eglReleaseTexImage) {
1028        return s->cnx->egl.eglReleaseTexImage(
1029                dp->disp[s->impl].dpy, s->surface, buffer);
1030    }
1031    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1032}
1033
1034EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1035{
1036    clearError();
1037
1038    egl_display_t const * const dp = validate_display(dpy);
1039    if (!dp) return EGL_FALSE;
1040
1041    EGLBoolean res = EGL_TRUE;
1042    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1043        egl_connection_t* const cnx = &gEGLImpl[i];
1044        if (cnx->dso) {
1045            if (cnx->egl.eglSwapInterval) {
1046                if (cnx->egl.eglSwapInterval(
1047                        dp->disp[i].dpy, interval) == EGL_FALSE) {
1048                    res = EGL_FALSE;
1049                }
1050            }
1051        }
1052    }
1053    return res;
1054}
1055
1056
1057// ----------------------------------------------------------------------------
1058// EGL 1.2
1059// ----------------------------------------------------------------------------
1060
1061EGLBoolean eglWaitClient(void)
1062{
1063    clearError();
1064
1065    // could be called before eglInitialize(), but we wouldn't have a context
1066    // then, and this function would return GL_TRUE, which isn't wrong.
1067    EGLBoolean res = EGL_TRUE;
1068    EGLContext ctx = getContext();
1069    if (ctx) {
1070        egl_context_t const * const c = get_context(ctx);
1071        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1072        if (uint32_t(c->impl)>=2)
1073            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1074        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1075        if (!cnx->dso)
1076            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1077        if (cnx->egl.eglWaitClient) {
1078            res = cnx->egl.eglWaitClient();
1079        } else {
1080            res = cnx->egl.eglWaitGL();
1081        }
1082    }
1083    return res;
1084}
1085
1086EGLBoolean eglBindAPI(EGLenum api)
1087{
1088    clearError();
1089
1090    if (egl_init_drivers() == EGL_FALSE) {
1091        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1092    }
1093
1094    // bind this API on all EGLs
1095    EGLBoolean res = EGL_TRUE;
1096    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1097        egl_connection_t* const cnx = &gEGLImpl[i];
1098        if (cnx->dso) {
1099            if (cnx->egl.eglBindAPI) {
1100                if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
1101                    res = EGL_FALSE;
1102                }
1103            }
1104        }
1105    }
1106    return res;
1107}
1108
1109EGLenum eglQueryAPI(void)
1110{
1111    clearError();
1112
1113    if (egl_init_drivers() == EGL_FALSE) {
1114        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1115    }
1116
1117    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1118        egl_connection_t* const cnx = &gEGLImpl[i];
1119        if (cnx->dso) {
1120            if (cnx->egl.eglQueryAPI) {
1121                // the first one we find is okay, because they all
1122                // should be the same
1123                return cnx->egl.eglQueryAPI();
1124            }
1125        }
1126    }
1127    // or, it can only be OpenGL ES
1128    return EGL_OPENGL_ES_API;
1129}
1130
1131EGLBoolean eglReleaseThread(void)
1132{
1133    clearError();
1134
1135    // If there is context bound to the thread, release it
1136    loseCurrent(get_context(getContext()));
1137
1138    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1139        egl_connection_t* const cnx = &gEGLImpl[i];
1140        if (cnx->dso) {
1141            if (cnx->egl.eglReleaseThread) {
1142                cnx->egl.eglReleaseThread();
1143            }
1144        }
1145    }
1146    egl_tls_t::clearTLS();
1147    dbgReleaseThread();
1148    return EGL_TRUE;
1149}
1150
1151EGLSurface eglCreatePbufferFromClientBuffer(
1152          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1153          EGLConfig config, const EGLint *attrib_list)
1154{
1155    clearError();
1156
1157    egl_display_t const* dp = 0;
1158    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1159    if (!cnx) return EGL_FALSE;
1160    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1161        return cnx->egl.eglCreatePbufferFromClientBuffer(
1162                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1163                buftype, buffer,
1164                dp->configs[intptr_t(config)].config, attrib_list);
1165    }
1166    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1167}
1168
1169// ----------------------------------------------------------------------------
1170// EGL_EGLEXT_VERSION 3
1171// ----------------------------------------------------------------------------
1172
1173EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1174        const EGLint *attrib_list)
1175{
1176    clearError();
1177
1178    egl_display_t const * const dp = validate_display(dpy);
1179    if (!dp) return EGL_FALSE;
1180
1181    SurfaceRef _s(surface);
1182    if (!_s.get())
1183        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1184
1185    egl_surface_t const * const s = get_surface(surface);
1186    if (s->cnx->egl.eglLockSurfaceKHR) {
1187        return s->cnx->egl.eglLockSurfaceKHR(
1188                dp->disp[s->impl].dpy, s->surface, attrib_list);
1189    }
1190    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1191}
1192
1193EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1194{
1195    clearError();
1196
1197    egl_display_t const * const dp = validate_display(dpy);
1198    if (!dp) return EGL_FALSE;
1199
1200    SurfaceRef _s(surface);
1201    if (!_s.get())
1202        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1203
1204    egl_surface_t const * const s = get_surface(surface);
1205    if (s->cnx->egl.eglUnlockSurfaceKHR) {
1206        return s->cnx->egl.eglUnlockSurfaceKHR(
1207                dp->disp[s->impl].dpy, s->surface);
1208    }
1209    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1210}
1211
1212EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1213        EGLClientBuffer buffer, const EGLint *attrib_list)
1214{
1215    clearError();
1216
1217    egl_display_t const * const dp = validate_display(dpy);
1218    if (!dp) return EGL_NO_IMAGE_KHR;
1219
1220    if (ctx != EGL_NO_CONTEXT) {
1221        ContextRef _c(ctx);
1222        if (!_c.get())
1223            return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1224        egl_context_t * const c = get_context(ctx);
1225        // since we have an EGLContext, we know which implementation to use
1226        EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
1227                dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
1228        if (image == EGL_NO_IMAGE_KHR)
1229            return image;
1230
1231        egl_image_t* result = new egl_image_t(dpy, ctx);
1232        result->images[c->impl] = image;
1233        return (EGLImageKHR)result;
1234    } else {
1235        // EGL_NO_CONTEXT is a valid parameter
1236
1237        /* Since we don't have a way to know which implementation to call,
1238         * we're calling all of them. If at least one of the implementation
1239         * succeeded, this is a success.
1240         */
1241
1242        EGLint currentError = eglGetError();
1243
1244        EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
1245        bool success = false;
1246        for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1247            egl_connection_t* const cnx = &gEGLImpl[i];
1248            implImages[i] = EGL_NO_IMAGE_KHR;
1249            if (cnx->dso) {
1250                if (cnx->egl.eglCreateImageKHR) {
1251                    implImages[i] = cnx->egl.eglCreateImageKHR(
1252                            dp->disp[i].dpy, ctx, target, buffer, attrib_list);
1253                    if (implImages[i] != EGL_NO_IMAGE_KHR) {
1254                        success = true;
1255                    }
1256                }
1257            }
1258        }
1259
1260        if (!success) {
1261            // failure, if there was an error when we entered this function,
1262            // the error flag must not be updated.
1263            // Otherwise, the error is whatever happened in the implementation
1264            // that faulted.
1265            if (currentError != EGL_SUCCESS) {
1266                setError(currentError, EGL_NO_IMAGE_KHR);
1267            }
1268            return EGL_NO_IMAGE_KHR;
1269        } else {
1270            // In case of success, we need to clear all error flags
1271            // (especially those caused by the implementation that didn't
1272            // succeed). TODO: we could avoid this if we knew this was
1273            // a "full" success (all implementation succeeded).
1274            eglGetError();
1275        }
1276
1277        egl_image_t* result = new egl_image_t(dpy, ctx);
1278        memcpy(result->images, implImages, sizeof(implImages));
1279        return (EGLImageKHR)result;
1280    }
1281}
1282
1283EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1284{
1285    clearError();
1286
1287    egl_display_t const * const dp = validate_display(dpy);
1288    if (!dp) return EGL_FALSE;
1289
1290    ImageRef _i(img);
1291    if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1292
1293    egl_image_t* image = get_image(img);
1294    bool success = false;
1295    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1296        egl_connection_t* const cnx = &gEGLImpl[i];
1297        if (image->images[i] != EGL_NO_IMAGE_KHR) {
1298            if (cnx->dso) {
1299                if (cnx->egl.eglDestroyImageKHR) {
1300                    if (cnx->egl.eglDestroyImageKHR(
1301                            dp->disp[i].dpy, image->images[i])) {
1302                        success = true;
1303                    }
1304                }
1305            }
1306        }
1307    }
1308    if (!success)
1309        return EGL_FALSE;
1310
1311    _i.terminate();
1312
1313    return EGL_TRUE;
1314}
1315
1316// ----------------------------------------------------------------------------
1317// EGL_EGLEXT_VERSION 5
1318// ----------------------------------------------------------------------------
1319
1320
1321EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1322{
1323    clearError();
1324
1325    egl_display_t const * const dp = validate_display(dpy);
1326    if (!dp) return EGL_NO_SYNC_KHR;
1327
1328    EGLContext ctx = eglGetCurrentContext();
1329    ContextRef _c(ctx);
1330    if (!_c.get())
1331        return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
1332
1333    egl_context_t * const c = get_context(ctx);
1334    EGLSyncKHR result = EGL_NO_SYNC_KHR;
1335    if (c->cnx->egl.eglCreateSyncKHR) {
1336        EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
1337                dp->disp[c->impl].dpy, type, attrib_list);
1338        if (sync == EGL_NO_SYNC_KHR)
1339            return sync;
1340        result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
1341    }
1342    return (EGLSyncKHR)result;
1343}
1344
1345EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1346{
1347    clearError();
1348
1349    egl_display_t const * const dp = validate_display(dpy);
1350    if (!dp) return EGL_FALSE;
1351
1352    SyncRef _s(sync);
1353    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1354    egl_sync_t* syncObject = get_sync(sync);
1355
1356    EGLContext ctx = syncObject->context;
1357    ContextRef _c(ctx);
1358    if (!_c.get())
1359        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1360
1361    EGLBoolean result = EGL_FALSE;
1362    egl_context_t * const c = get_context(ctx);
1363    if (c->cnx->egl.eglDestroySyncKHR) {
1364        result = c->cnx->egl.eglDestroySyncKHR(
1365                dp->disp[c->impl].dpy, syncObject->sync);
1366        if (result)
1367            _s.terminate();
1368    }
1369    return result;
1370}
1371
1372EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1373{
1374    clearError();
1375
1376    egl_display_t const * const dp = validate_display(dpy);
1377    if (!dp) return EGL_FALSE;
1378
1379    SyncRef _s(sync);
1380    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1381    egl_sync_t* syncObject = get_sync(sync);
1382
1383    EGLContext ctx = syncObject->context;
1384    ContextRef _c(ctx);
1385    if (!_c.get())
1386        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1387
1388    egl_context_t * const c = get_context(ctx);
1389    if (c->cnx->egl.eglClientWaitSyncKHR) {
1390        return c->cnx->egl.eglClientWaitSyncKHR(
1391                dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
1392    }
1393
1394    return EGL_FALSE;
1395}
1396
1397EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1398{
1399    clearError();
1400
1401    egl_display_t const * const dp = validate_display(dpy);
1402    if (!dp) return EGL_FALSE;
1403
1404    SyncRef _s(sync);
1405    if (!_s.get())
1406        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1407
1408    egl_sync_t* syncObject = get_sync(sync);
1409    EGLContext ctx = syncObject->context;
1410    ContextRef _c(ctx);
1411    if (!_c.get())
1412        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1413
1414    egl_context_t * const c = get_context(ctx);
1415    if (c->cnx->egl.eglGetSyncAttribKHR) {
1416        return c->cnx->egl.eglGetSyncAttribKHR(
1417                dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
1418    }
1419
1420    return EGL_FALSE;
1421}
1422
1423// ----------------------------------------------------------------------------
1424// ANDROID extensions
1425// ----------------------------------------------------------------------------
1426
1427EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1428        EGLint left, EGLint top, EGLint width, EGLint height)
1429{
1430    clearError();
1431
1432    egl_display_t const * const dp = validate_display(dpy);
1433    if (!dp) return EGL_FALSE;
1434
1435    SurfaceRef _s(draw);
1436    if (!_s.get())
1437        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1438
1439    egl_surface_t const * const s = get_surface(draw);
1440    if (s->cnx->egl.eglSetSwapRectangleANDROID) {
1441        return s->cnx->egl.eglSetSwapRectangleANDROID(
1442                dp->disp[s->impl].dpy, s->surface, left, top, width, height);
1443    }
1444    return setError(EGL_BAD_DISPLAY, NULL);
1445}
1446