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