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