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