eglApi.cpp revision 81a63350527cafce6929309533c58586878f10b5
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        if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
367            LOGE("EGLNativeWindowType %p already connected to another API",
368                    window);
369            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
370        }
371
372        // set the native window's buffers format to match this config
373        if (cnx->egl.eglGetConfigAttrib(iDpy,
374                iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
375            if (format != 0) {
376                int err = native_window_set_buffers_format(window, format);
377                if (err != 0) {
378                    LOGE("error setting native window pixel format: %s (%d)",
379                            strerror(-err), err);
380                    native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
381                    return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
382                }
383            }
384        }
385
386        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
387                iDpy, iConfig, window, attrib_list);
388        if (surface != EGL_NO_SURFACE) {
389            egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
390                    dp->configs[intptr_t(config)].impl, cnx);
391            return s;
392        }
393
394        // EGLSurface creation failed
395        native_window_set_buffers_format(window, 0);
396        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
397    }
398    return EGL_NO_SURFACE;
399}
400
401EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
402                                    NativePixmapType pixmap,
403                                    const EGLint *attrib_list)
404{
405    clearError();
406
407    egl_display_t const* dp = 0;
408    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
409    if (cnx) {
410        EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
411                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
412                dp->configs[intptr_t(config)].config, pixmap, attrib_list);
413        if (surface != EGL_NO_SURFACE) {
414            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
415                    dp->configs[intptr_t(config)].impl, cnx);
416            return s;
417        }
418    }
419    return EGL_NO_SURFACE;
420}
421
422EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
423                                    const EGLint *attrib_list)
424{
425    clearError();
426
427    egl_display_t const* dp = 0;
428    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
429    if (cnx) {
430        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
431                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
432                dp->configs[intptr_t(config)].config, attrib_list);
433        if (surface != EGL_NO_SURFACE) {
434            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
435                    dp->configs[intptr_t(config)].impl, cnx);
436            return s;
437        }
438    }
439    return EGL_NO_SURFACE;
440}
441
442EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
443{
444    clearError();
445
446    egl_display_t const * const dp = validate_display(dpy);
447    if (!dp) return EGL_FALSE;
448
449    SurfaceRef _s(surface);
450    if (!_s.get())
451        return setError(EGL_BAD_SURFACE, EGL_FALSE);
452
453    egl_surface_t * const s = get_surface(surface);
454    EGLBoolean result = s->cnx->egl.eglDestroySurface(
455            dp->disp[s->impl].dpy, s->surface);
456    if (result == EGL_TRUE) {
457        ANativeWindow* const window = s->win.get();
458        if (window != NULL) {
459            native_window_set_buffers_format(window, 0);
460            if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) {
461                LOGE("EGLNativeWindowType %p disconnected failed", window);
462            }
463        }
464        _s.terminate();
465    }
466    return result;
467}
468
469EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
470                            EGLint attribute, EGLint *value)
471{
472    clearError();
473
474    egl_display_t const * const dp = validate_display(dpy);
475    if (!dp) return EGL_FALSE;
476
477    SurfaceRef _s(surface);
478    if (!_s.get())
479        return setError(EGL_BAD_SURFACE, EGL_FALSE);
480
481    egl_surface_t const * const s = get_surface(surface);
482    EGLBoolean result(EGL_TRUE);
483    if (attribute == EGL_CONFIG_ID) {
484        // We need to remap EGL_CONFIG_IDs
485        *value = dp->configs[intptr_t(s->config)].configId;
486    } else {
487        result = s->cnx->egl.eglQuerySurface(
488                dp->disp[s->impl].dpy, s->surface, attribute, value);
489    }
490
491    return result;
492}
493
494// ----------------------------------------------------------------------------
495// Contexts
496// ----------------------------------------------------------------------------
497
498EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
499                            EGLContext share_list, const EGLint *attrib_list)
500{
501    clearError();
502
503    egl_display_t const* dp = 0;
504    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
505    if (cnx) {
506        if (share_list != EGL_NO_CONTEXT) {
507            egl_context_t* const c = get_context(share_list);
508            share_list = c->context;
509        }
510        EGLContext context = cnx->egl.eglCreateContext(
511                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
512                dp->configs[intptr_t(config)].config,
513                share_list, attrib_list);
514        if (context != EGL_NO_CONTEXT) {
515            // figure out if it's a GLESv1 or GLESv2
516            int version = 0;
517            if (attrib_list) {
518                while (*attrib_list != EGL_NONE) {
519                    GLint attr = *attrib_list++;
520                    GLint value = *attrib_list++;
521                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
522                        if (value == 1) {
523                            version = GLESv1_INDEX;
524                        } else if (value == 2) {
525                            version = GLESv2_INDEX;
526                        }
527                    }
528                };
529            }
530            egl_context_t* c = new egl_context_t(dpy, context, config,
531                    dp->configs[intptr_t(config)].impl, cnx, version);
532            return c;
533        }
534    }
535    return EGL_NO_CONTEXT;
536}
537
538EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
539{
540    clearError();
541
542    egl_display_t const * const dp = validate_display(dpy);
543    if (!dp)
544        return EGL_FALSE;
545
546    ContextRef _c(ctx);
547    if (!_c.get())
548        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
549
550    egl_context_t * const c = get_context(ctx);
551    EGLBoolean result = c->cnx->egl.eglDestroyContext(
552            dp->disp[c->impl].dpy, c->context);
553    if (result == EGL_TRUE) {
554        _c.terminate();
555    }
556    return result;
557}
558
559static void loseCurrent(egl_context_t * cur_c)
560{
561    if (cur_c) {
562        egl_surface_t * cur_r = get_surface(cur_c->read);
563        egl_surface_t * cur_d = get_surface(cur_c->draw);
564
565        // by construction, these are either 0 or valid (possibly terminated)
566        // it should be impossible for these to be invalid
567        ContextRef _cur_c(cur_c);
568        SurfaceRef _cur_r(cur_r);
569        SurfaceRef _cur_d(cur_d);
570
571        cur_c->read = NULL;
572        cur_c->draw = NULL;
573
574        _cur_c.release();
575        _cur_r.release();
576        _cur_d.release();
577    }
578}
579
580EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
581                            EGLSurface read, EGLContext ctx)
582{
583    clearError();
584
585    egl_display_t const * const dp = get_display(dpy);
586    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
587
588    // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
589    // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
590    // a valid but uninitialized display.
591    if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
592         (draw != EGL_NO_SURFACE) ) {
593        if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
594    }
595
596    // get a reference to the object passed in
597    ContextRef _c(ctx);
598    SurfaceRef _d(draw);
599    SurfaceRef _r(read);
600
601    // validate the context (if not EGL_NO_CONTEXT)
602    if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
603        // EGL_NO_CONTEXT is valid
604        return EGL_FALSE;
605    }
606
607    // these are the underlying implementation's object
608    EGLContext impl_ctx  = EGL_NO_CONTEXT;
609    EGLSurface impl_draw = EGL_NO_SURFACE;
610    EGLSurface impl_read = EGL_NO_SURFACE;
611
612    // these are our objects structs passed in
613    egl_context_t       * c = NULL;
614    egl_surface_t const * d = NULL;
615    egl_surface_t const * r = NULL;
616
617    // these are the current objects structs
618    egl_context_t * cur_c = get_context(getContext());
619
620    if (ctx != EGL_NO_CONTEXT) {
621        c = get_context(ctx);
622        impl_ctx = c->context;
623    } else {
624        // no context given, use the implementation of the current context
625        if (cur_c == NULL) {
626            // no current context
627            if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
628                // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
629                return setError(EGL_BAD_MATCH, EGL_FALSE);
630            }
631            // not an error, there is just no current context.
632            return EGL_TRUE;
633        }
634    }
635
636    // retrieve the underlying implementation's draw EGLSurface
637    if (draw != EGL_NO_SURFACE) {
638        d = get_surface(draw);
639        // make sure the EGLContext and EGLSurface passed in are for
640        // the same driver
641        if (c && d->impl != c->impl)
642            return setError(EGL_BAD_MATCH, EGL_FALSE);
643        impl_draw = d->surface;
644    }
645
646    // retrieve the underlying implementation's read EGLSurface
647    if (read != EGL_NO_SURFACE) {
648        r = get_surface(read);
649        // make sure the EGLContext and EGLSurface passed in are for
650        // the same driver
651        if (c && r->impl != c->impl)
652            return setError(EGL_BAD_MATCH, EGL_FALSE);
653        impl_read = r->surface;
654    }
655
656    EGLBoolean result;
657
658    if (c) {
659        result = c->cnx->egl.eglMakeCurrent(
660                dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
661    } else {
662        result = cur_c->cnx->egl.eglMakeCurrent(
663                dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
664    }
665
666    if (result == EGL_TRUE) {
667
668        loseCurrent(cur_c);
669
670        if (ctx != EGL_NO_CONTEXT) {
671            setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
672            egl_tls_t::setContext(ctx);
673            if (gEGLDebugLevel > 0) {
674                CreateDbgContext(c->version, c->cnx->hooks[c->version]);
675            }
676            _c.acquire();
677            _r.acquire();
678            _d.acquire();
679            c->read = read;
680            c->draw = draw;
681        } else {
682            setGLHooksThreadSpecific(&gHooksNoContext);
683            egl_tls_t::setContext(EGL_NO_CONTEXT);
684        }
685    }
686    return result;
687}
688
689
690EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
691                            EGLint attribute, EGLint *value)
692{
693    clearError();
694
695    egl_display_t const * const dp = validate_display(dpy);
696    if (!dp) return EGL_FALSE;
697
698    ContextRef _c(ctx);
699    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
700
701    egl_context_t * const c = get_context(ctx);
702
703    EGLBoolean result(EGL_TRUE);
704    if (attribute == EGL_CONFIG_ID) {
705        *value = dp->configs[intptr_t(c->config)].configId;
706    } else {
707        // We need to remap EGL_CONFIG_IDs
708        result = c->cnx->egl.eglQueryContext(
709                dp->disp[c->impl].dpy, c->context, attribute, value);
710    }
711
712    return result;
713}
714
715EGLContext eglGetCurrentContext(void)
716{
717    // could be called before eglInitialize(), but we wouldn't have a context
718    // then, and this function would correctly return EGL_NO_CONTEXT.
719
720    clearError();
721
722    EGLContext ctx = getContext();
723    return ctx;
724}
725
726EGLSurface eglGetCurrentSurface(EGLint readdraw)
727{
728    // could be called before eglInitialize(), but we wouldn't have a context
729    // then, and this function would correctly return EGL_NO_SURFACE.
730
731    clearError();
732
733    EGLContext ctx = getContext();
734    if (ctx) {
735        egl_context_t const * const c = get_context(ctx);
736        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
737        switch (readdraw) {
738            case EGL_READ: return c->read;
739            case EGL_DRAW: return c->draw;
740            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
741        }
742    }
743    return EGL_NO_SURFACE;
744}
745
746EGLDisplay eglGetCurrentDisplay(void)
747{
748    // could be called before eglInitialize(), but we wouldn't have a context
749    // then, and this function would correctly return EGL_NO_DISPLAY.
750
751    clearError();
752
753    EGLContext ctx = getContext();
754    if (ctx) {
755        egl_context_t const * const c = get_context(ctx);
756        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
757        return c->dpy;
758    }
759    return EGL_NO_DISPLAY;
760}
761
762EGLBoolean eglWaitGL(void)
763{
764    // could be called before eglInitialize(), but we wouldn't have a context
765    // then, and this function would return GL_TRUE, which isn't wrong.
766
767    clearError();
768
769    EGLBoolean res = EGL_TRUE;
770    EGLContext ctx = getContext();
771    if (ctx) {
772        egl_context_t const * const c = get_context(ctx);
773        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
774        if (uint32_t(c->impl)>=2)
775            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
776        egl_connection_t* const cnx = &gEGLImpl[c->impl];
777        if (!cnx->dso)
778            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
779        res = cnx->egl.eglWaitGL();
780    }
781    return res;
782}
783
784EGLBoolean eglWaitNative(EGLint engine)
785{
786    // could be called before eglInitialize(), but we wouldn't have a context
787    // then, and this function would return GL_TRUE, which isn't wrong.
788
789    clearError();
790
791    EGLBoolean res = EGL_TRUE;
792    EGLContext ctx = getContext();
793    if (ctx) {
794        egl_context_t const * const c = get_context(ctx);
795        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
796        if (uint32_t(c->impl)>=2)
797            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
798        egl_connection_t* const cnx = &gEGLImpl[c->impl];
799        if (!cnx->dso)
800            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
801        res = cnx->egl.eglWaitNative(engine);
802    }
803    return res;
804}
805
806EGLint eglGetError(void)
807{
808    EGLint result = EGL_SUCCESS;
809    EGLint err;
810    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
811        err = EGL_SUCCESS;
812        egl_connection_t* const cnx = &gEGLImpl[i];
813        if (cnx->dso)
814            err = cnx->egl.eglGetError();
815        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
816            result = err;
817    }
818    err = egl_tls_t::getError();
819    if (result == EGL_SUCCESS)
820        result = err;
821    return result;
822}
823
824// Note: Similar implementations of these functions also exist in
825// gl2.cpp and gl.cpp, and are used by applications that call the
826// exported entry points directly.
827typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
828typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
829
830static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
831static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
832
833static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
834{
835    GLeglImageOES implImage =
836        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
837    glEGLImageTargetTexture2DOES_impl(target, implImage);
838}
839
840static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
841{
842    GLeglImageOES implImage =
843        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
844    glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
845}
846
847__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
848{
849    // eglGetProcAddress() could be the very first function called
850    // in which case we must make sure we've initialized ourselves, this
851    // happens the first time egl_get_display() is called.
852
853    clearError();
854
855    if (egl_init_drivers() == EGL_FALSE) {
856        setError(EGL_BAD_PARAMETER, NULL);
857        return  NULL;
858    }
859
860    __eglMustCastToProperFunctionPointerType addr;
861    addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
862    if (addr) return addr;
863
864    // this protects accesses to sGLExtentionMap and sGLExtentionSlot
865    pthread_mutex_lock(&sExtensionMapMutex);
866
867        /*
868         * Since eglGetProcAddress() is not associated to anything, it needs
869         * to return a function pointer that "works" regardless of what
870         * the current context is.
871         *
872         * For this reason, we return a "forwarder", a small stub that takes
873         * care of calling the function associated with the context
874         * currently bound.
875         *
876         * We first look for extensions we've already resolved, if we're seeing
877         * this extension for the first time, we go through all our
878         * implementations and call eglGetProcAddress() and record the
879         * result in the appropriate implementation hooks and return the
880         * address of the forwarder corresponding to that hook set.
881         *
882         */
883
884        const String8 name(procname);
885        addr = sGLExtentionMap.valueFor(name);
886        const int slot = sGLExtentionSlot;
887
888        LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
889                "no more slots for eglGetProcAddress(\"%s\")",
890                procname);
891
892        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
893            bool found = false;
894            for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
895                egl_connection_t* const cnx = &gEGLImpl[i];
896                if (cnx->dso && cnx->egl.eglGetProcAddress) {
897                    found = true;
898                    // Extensions are independent of the bound context
899                    cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
900                    cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
901#if EGL_TRACE
902                    gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
903#endif
904                            cnx->egl.eglGetProcAddress(procname);
905                }
906            }
907            if (found) {
908                addr = gExtensionForwarders[slot];
909
910                if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
911                    glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
912                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
913                }
914                if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
915                    glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
916                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
917                }
918
919                sGLExtentionMap.add(name, addr);
920                sGLExtentionSlot++;
921            }
922        }
923
924    pthread_mutex_unlock(&sExtensionMapMutex);
925    return addr;
926}
927
928EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
929{
930    EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
931    if (gEGLDebugLevel > 0)
932        Debug_eglSwapBuffers(dpy, draw);
933
934    clearError();
935
936    egl_display_t const * const dp = validate_display(dpy);
937    if (!dp) return EGL_FALSE;
938
939    SurfaceRef _s(draw);
940    if (!_s.get())
941        return setError(EGL_BAD_SURFACE, EGL_FALSE);
942
943    egl_surface_t const * const s = get_surface(draw);
944    return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
945}
946
947EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
948                            NativePixmapType target)
949{
950    clearError();
951
952    egl_display_t const * const dp = validate_display(dpy);
953    if (!dp) return EGL_FALSE;
954
955    SurfaceRef _s(surface);
956    if (!_s.get())
957        return setError(EGL_BAD_SURFACE, EGL_FALSE);
958
959    egl_surface_t const * const s = get_surface(surface);
960    return s->cnx->egl.eglCopyBuffers(
961            dp->disp[s->impl].dpy, s->surface, target);
962}
963
964const char* eglQueryString(EGLDisplay dpy, EGLint name)
965{
966    clearError();
967
968    egl_display_t const * const dp = validate_display(dpy);
969    if (!dp) return (const char *) NULL;
970
971    switch (name) {
972        case EGL_VENDOR:
973            return sVendorString;
974        case EGL_VERSION:
975            return sVersionString;
976        case EGL_EXTENSIONS:
977            return sExtensionString;
978        case EGL_CLIENT_APIS:
979            return sClientApiString;
980    }
981    return setError(EGL_BAD_PARAMETER, (const char *)0);
982}
983
984
985// ----------------------------------------------------------------------------
986// EGL 1.1
987// ----------------------------------------------------------------------------
988
989EGLBoolean eglSurfaceAttrib(
990        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
991{
992    clearError();
993
994    egl_display_t const * const dp = validate_display(dpy);
995    if (!dp) return EGL_FALSE;
996
997    SurfaceRef _s(surface);
998    if (!_s.get())
999        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1000
1001    egl_surface_t const * const s = get_surface(surface);
1002    if (s->cnx->egl.eglSurfaceAttrib) {
1003        return s->cnx->egl.eglSurfaceAttrib(
1004                dp->disp[s->impl].dpy, s->surface, attribute, value);
1005    }
1006    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1007}
1008
1009EGLBoolean eglBindTexImage(
1010        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1011{
1012    clearError();
1013
1014    egl_display_t const * const dp = validate_display(dpy);
1015    if (!dp) return EGL_FALSE;
1016
1017    SurfaceRef _s(surface);
1018    if (!_s.get())
1019        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1020
1021    egl_surface_t const * const s = get_surface(surface);
1022    if (s->cnx->egl.eglBindTexImage) {
1023        return s->cnx->egl.eglBindTexImage(
1024                dp->disp[s->impl].dpy, s->surface, buffer);
1025    }
1026    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1027}
1028
1029EGLBoolean eglReleaseTexImage(
1030        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1031{
1032    clearError();
1033
1034    egl_display_t const * const dp = validate_display(dpy);
1035    if (!dp) return EGL_FALSE;
1036
1037    SurfaceRef _s(surface);
1038    if (!_s.get())
1039        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1040
1041    egl_surface_t const * const s = get_surface(surface);
1042    if (s->cnx->egl.eglReleaseTexImage) {
1043        return s->cnx->egl.eglReleaseTexImage(
1044                dp->disp[s->impl].dpy, s->surface, buffer);
1045    }
1046    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1047}
1048
1049EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1050{
1051    clearError();
1052
1053    egl_display_t const * const dp = validate_display(dpy);
1054    if (!dp) return EGL_FALSE;
1055
1056    EGLBoolean res = EGL_TRUE;
1057    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1058        egl_connection_t* const cnx = &gEGLImpl[i];
1059        if (cnx->dso) {
1060            if (cnx->egl.eglSwapInterval) {
1061                if (cnx->egl.eglSwapInterval(
1062                        dp->disp[i].dpy, interval) == EGL_FALSE) {
1063                    res = EGL_FALSE;
1064                }
1065            }
1066        }
1067    }
1068    return res;
1069}
1070
1071
1072// ----------------------------------------------------------------------------
1073// EGL 1.2
1074// ----------------------------------------------------------------------------
1075
1076EGLBoolean eglWaitClient(void)
1077{
1078    clearError();
1079
1080    // could be called before eglInitialize(), but we wouldn't have a context
1081    // then, and this function would return GL_TRUE, which isn't wrong.
1082    EGLBoolean res = EGL_TRUE;
1083    EGLContext ctx = getContext();
1084    if (ctx) {
1085        egl_context_t const * const c = get_context(ctx);
1086        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1087        if (uint32_t(c->impl)>=2)
1088            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1089        egl_connection_t* const cnx = &gEGLImpl[c->impl];
1090        if (!cnx->dso)
1091            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1092        if (cnx->egl.eglWaitClient) {
1093            res = cnx->egl.eglWaitClient();
1094        } else {
1095            res = cnx->egl.eglWaitGL();
1096        }
1097    }
1098    return res;
1099}
1100
1101EGLBoolean eglBindAPI(EGLenum api)
1102{
1103    clearError();
1104
1105    if (egl_init_drivers() == EGL_FALSE) {
1106        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1107    }
1108
1109    // bind this API on all EGLs
1110    EGLBoolean res = EGL_TRUE;
1111    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1112        egl_connection_t* const cnx = &gEGLImpl[i];
1113        if (cnx->dso) {
1114            if (cnx->egl.eglBindAPI) {
1115                if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
1116                    res = EGL_FALSE;
1117                }
1118            }
1119        }
1120    }
1121    return res;
1122}
1123
1124EGLenum eglQueryAPI(void)
1125{
1126    clearError();
1127
1128    if (egl_init_drivers() == EGL_FALSE) {
1129        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1130    }
1131
1132    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1133        egl_connection_t* const cnx = &gEGLImpl[i];
1134        if (cnx->dso) {
1135            if (cnx->egl.eglQueryAPI) {
1136                // the first one we find is okay, because they all
1137                // should be the same
1138                return cnx->egl.eglQueryAPI();
1139            }
1140        }
1141    }
1142    // or, it can only be OpenGL ES
1143    return EGL_OPENGL_ES_API;
1144}
1145
1146EGLBoolean eglReleaseThread(void)
1147{
1148    clearError();
1149
1150    // If there is context bound to the thread, release it
1151    loseCurrent(get_context(getContext()));
1152
1153    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1154        egl_connection_t* const cnx = &gEGLImpl[i];
1155        if (cnx->dso) {
1156            if (cnx->egl.eglReleaseThread) {
1157                cnx->egl.eglReleaseThread();
1158            }
1159        }
1160    }
1161    egl_tls_t::clearTLS();
1162    dbgReleaseThread();
1163    return EGL_TRUE;
1164}
1165
1166EGLSurface eglCreatePbufferFromClientBuffer(
1167          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1168          EGLConfig config, const EGLint *attrib_list)
1169{
1170    clearError();
1171
1172    egl_display_t const* dp = 0;
1173    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1174    if (!cnx) return EGL_FALSE;
1175    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1176        return cnx->egl.eglCreatePbufferFromClientBuffer(
1177                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1178                buftype, buffer,
1179                dp->configs[intptr_t(config)].config, attrib_list);
1180    }
1181    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1182}
1183
1184// ----------------------------------------------------------------------------
1185// EGL_EGLEXT_VERSION 3
1186// ----------------------------------------------------------------------------
1187
1188EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1189        const EGLint *attrib_list)
1190{
1191    clearError();
1192
1193    egl_display_t const * const dp = validate_display(dpy);
1194    if (!dp) return EGL_FALSE;
1195
1196    SurfaceRef _s(surface);
1197    if (!_s.get())
1198        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1199
1200    egl_surface_t const * const s = get_surface(surface);
1201    if (s->cnx->egl.eglLockSurfaceKHR) {
1202        return s->cnx->egl.eglLockSurfaceKHR(
1203                dp->disp[s->impl].dpy, s->surface, attrib_list);
1204    }
1205    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1206}
1207
1208EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1209{
1210    clearError();
1211
1212    egl_display_t const * const dp = validate_display(dpy);
1213    if (!dp) return EGL_FALSE;
1214
1215    SurfaceRef _s(surface);
1216    if (!_s.get())
1217        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1218
1219    egl_surface_t const * const s = get_surface(surface);
1220    if (s->cnx->egl.eglUnlockSurfaceKHR) {
1221        return s->cnx->egl.eglUnlockSurfaceKHR(
1222                dp->disp[s->impl].dpy, s->surface);
1223    }
1224    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1225}
1226
1227EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1228        EGLClientBuffer buffer, const EGLint *attrib_list)
1229{
1230    clearError();
1231
1232    egl_display_t const * const dp = validate_display(dpy);
1233    if (!dp) return EGL_NO_IMAGE_KHR;
1234
1235    if (ctx != EGL_NO_CONTEXT) {
1236        ContextRef _c(ctx);
1237        if (!_c.get())
1238            return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1239        egl_context_t * const c = get_context(ctx);
1240        // since we have an EGLContext, we know which implementation to use
1241        EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
1242                dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
1243        if (image == EGL_NO_IMAGE_KHR)
1244            return image;
1245
1246        egl_image_t* result = new egl_image_t(dpy, ctx);
1247        result->images[c->impl] = image;
1248        return (EGLImageKHR)result;
1249    } else {
1250        // EGL_NO_CONTEXT is a valid parameter
1251
1252        /* Since we don't have a way to know which implementation to call,
1253         * we're calling all of them. If at least one of the implementation
1254         * succeeded, this is a success.
1255         */
1256
1257        EGLint currentError = eglGetError();
1258
1259        EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
1260        bool success = false;
1261        for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1262            egl_connection_t* const cnx = &gEGLImpl[i];
1263            implImages[i] = EGL_NO_IMAGE_KHR;
1264            if (cnx->dso) {
1265                if (cnx->egl.eglCreateImageKHR) {
1266                    implImages[i] = cnx->egl.eglCreateImageKHR(
1267                            dp->disp[i].dpy, ctx, target, buffer, attrib_list);
1268                    if (implImages[i] != EGL_NO_IMAGE_KHR) {
1269                        success = true;
1270                    }
1271                }
1272            }
1273        }
1274
1275        if (!success) {
1276            // failure, if there was an error when we entered this function,
1277            // the error flag must not be updated.
1278            // Otherwise, the error is whatever happened in the implementation
1279            // that faulted.
1280            if (currentError != EGL_SUCCESS) {
1281                setError(currentError, EGL_NO_IMAGE_KHR);
1282            }
1283            return EGL_NO_IMAGE_KHR;
1284        } else {
1285            // In case of success, we need to clear all error flags
1286            // (especially those caused by the implementation that didn't
1287            // succeed). TODO: we could avoid this if we knew this was
1288            // a "full" success (all implementation succeeded).
1289            eglGetError();
1290        }
1291
1292        egl_image_t* result = new egl_image_t(dpy, ctx);
1293        memcpy(result->images, implImages, sizeof(implImages));
1294        return (EGLImageKHR)result;
1295    }
1296}
1297
1298EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1299{
1300    clearError();
1301
1302    egl_display_t const * const dp = validate_display(dpy);
1303    if (!dp) return EGL_FALSE;
1304
1305    ImageRef _i(img);
1306    if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1307
1308    egl_image_t* image = get_image(img);
1309    bool success = false;
1310    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1311        egl_connection_t* const cnx = &gEGLImpl[i];
1312        if (image->images[i] != EGL_NO_IMAGE_KHR) {
1313            if (cnx->dso) {
1314                if (cnx->egl.eglDestroyImageKHR) {
1315                    if (cnx->egl.eglDestroyImageKHR(
1316                            dp->disp[i].dpy, image->images[i])) {
1317                        success = true;
1318                    }
1319                }
1320            }
1321        }
1322    }
1323    if (!success)
1324        return EGL_FALSE;
1325
1326    _i.terminate();
1327
1328    return EGL_TRUE;
1329}
1330
1331// ----------------------------------------------------------------------------
1332// EGL_EGLEXT_VERSION 5
1333// ----------------------------------------------------------------------------
1334
1335
1336EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1337{
1338    clearError();
1339
1340    egl_display_t const * const dp = validate_display(dpy);
1341    if (!dp) return EGL_NO_SYNC_KHR;
1342
1343    EGLContext ctx = eglGetCurrentContext();
1344    ContextRef _c(ctx);
1345    if (!_c.get())
1346        return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
1347
1348    egl_context_t * const c = get_context(ctx);
1349    EGLSyncKHR result = EGL_NO_SYNC_KHR;
1350    if (c->cnx->egl.eglCreateSyncKHR) {
1351        EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
1352                dp->disp[c->impl].dpy, type, attrib_list);
1353        if (sync == EGL_NO_SYNC_KHR)
1354            return sync;
1355        result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
1356    }
1357    return (EGLSyncKHR)result;
1358}
1359
1360EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1361{
1362    clearError();
1363
1364    egl_display_t const * const dp = validate_display(dpy);
1365    if (!dp) return EGL_FALSE;
1366
1367    SyncRef _s(sync);
1368    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1369    egl_sync_t* syncObject = get_sync(sync);
1370
1371    EGLContext ctx = syncObject->context;
1372    ContextRef _c(ctx);
1373    if (!_c.get())
1374        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1375
1376    EGLBoolean result = EGL_FALSE;
1377    egl_context_t * const c = get_context(ctx);
1378    if (c->cnx->egl.eglDestroySyncKHR) {
1379        result = c->cnx->egl.eglDestroySyncKHR(
1380                dp->disp[c->impl].dpy, syncObject->sync);
1381        if (result)
1382            _s.terminate();
1383    }
1384    return result;
1385}
1386
1387EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1388{
1389    clearError();
1390
1391    egl_display_t const * const dp = validate_display(dpy);
1392    if (!dp) return EGL_FALSE;
1393
1394    SyncRef _s(sync);
1395    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1396    egl_sync_t* syncObject = get_sync(sync);
1397
1398    EGLContext ctx = syncObject->context;
1399    ContextRef _c(ctx);
1400    if (!_c.get())
1401        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1402
1403    egl_context_t * const c = get_context(ctx);
1404    if (c->cnx->egl.eglClientWaitSyncKHR) {
1405        return c->cnx->egl.eglClientWaitSyncKHR(
1406                dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
1407    }
1408
1409    return EGL_FALSE;
1410}
1411
1412EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1413{
1414    clearError();
1415
1416    egl_display_t const * const dp = validate_display(dpy);
1417    if (!dp) return EGL_FALSE;
1418
1419    SyncRef _s(sync);
1420    if (!_s.get())
1421        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1422
1423    egl_sync_t* syncObject = get_sync(sync);
1424    EGLContext ctx = syncObject->context;
1425    ContextRef _c(ctx);
1426    if (!_c.get())
1427        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1428
1429    egl_context_t * const c = get_context(ctx);
1430    if (c->cnx->egl.eglGetSyncAttribKHR) {
1431        return c->cnx->egl.eglGetSyncAttribKHR(
1432                dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
1433    }
1434
1435    return EGL_FALSE;
1436}
1437
1438// ----------------------------------------------------------------------------
1439// ANDROID extensions
1440// ----------------------------------------------------------------------------
1441
1442EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1443        EGLint left, EGLint top, EGLint width, EGLint height)
1444{
1445    clearError();
1446
1447    egl_display_t const * const dp = validate_display(dpy);
1448    if (!dp) return EGL_FALSE;
1449
1450    SurfaceRef _s(draw);
1451    if (!_s.get())
1452        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1453
1454    egl_surface_t const * const s = get_surface(draw);
1455    if (s->cnx->egl.eglSetSwapRectangleANDROID) {
1456        return s->cnx->egl.eglSetSwapRectangleANDROID(
1457                dp->disp[s->impl].dpy, s->surface, left, top, width, height);
1458    }
1459    return setError(EGL_BAD_DISPLAY, NULL);
1460}
1461