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