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