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