eglApi.cpp revision 7c0441ac271f4e00a2d63eb3048c037ebffa90b9
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#include "egldefs.h"
48
49using namespace android;
50
51// ----------------------------------------------------------------------------
52
53#define EGL_VERSION_HW_ANDROID  0x3143
54
55struct extention_map_t {
56    const char* name;
57    __eglMustCastToProperFunctionPointerType address;
58};
59
60static const extention_map_t sExtentionMap[] = {
61    { "eglLockSurfaceKHR",
62            (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
63    { "eglUnlockSurfaceKHR",
64            (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
65    { "eglCreateImageKHR",
66            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
67    { "eglDestroyImageKHR",
68            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
69    { "eglGetSystemTimeFrequencyNV",
70            (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
71    { "eglGetSystemTimeNV",
72            (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV },
73};
74
75// accesses protected by sExtensionMapMutex
76static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
77static int sGLExtentionSlot = 0;
78static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
79
80static void(*findProcAddress(const char* name,
81        const extention_map_t* map, size_t n))() {
82    for (uint32_t i=0 ; i<n ; i++) {
83        if (!strcmp(name, map[i].name)) {
84            return map[i].address;
85        }
86    }
87    return NULL;
88}
89
90// ----------------------------------------------------------------------------
91
92namespace android {
93extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
94extern EGLBoolean egl_init_drivers();
95extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
96extern int gEGLDebugLevel;
97extern gl_hooks_t gHooksTrace;
98} // namespace android;
99
100// ----------------------------------------------------------------------------
101
102static inline void clearError() { egl_tls_t::clearError(); }
103static inline EGLContext getContext() { return egl_tls_t::getContext(); }
104
105// ----------------------------------------------------------------------------
106
107EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
108{
109    clearError();
110
111    uint32_t index = uint32_t(display);
112    if (index >= NUM_DISPLAYS) {
113        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
114    }
115
116    if (egl_init_drivers() == EGL_FALSE) {
117        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
118    }
119
120    EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
121    return dpy;
122}
123
124// ----------------------------------------------------------------------------
125// Initialization
126// ----------------------------------------------------------------------------
127
128EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
129{
130    clearError();
131
132    egl_display_t * const dp = get_display(dpy);
133    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
134
135    EGLBoolean res = dp->initialize(major, minor);
136
137    return res;
138}
139
140EGLBoolean eglTerminate(EGLDisplay dpy)
141{
142    // NOTE: don't unload the drivers b/c some APIs can be called
143    // after eglTerminate() has been called. eglTerminate() only
144    // terminates an EGLDisplay, not a EGL itself.
145
146    clearError();
147
148    egl_display_t* const dp = get_display(dpy);
149    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
150
151    EGLBoolean res = dp->terminate();
152
153    return res;
154}
155
156// ----------------------------------------------------------------------------
157// configuration
158// ----------------------------------------------------------------------------
159
160EGLBoolean eglGetConfigs(   EGLDisplay dpy,
161                            EGLConfig *configs,
162                            EGLint config_size, EGLint *num_config)
163{
164    clearError();
165
166    egl_display_t const * const dp = validate_display(dpy);
167    if (!dp) return EGL_FALSE;
168
169    if (num_config==0) {
170        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
171    }
172
173    EGLBoolean res = EGL_FALSE;
174    *num_config = 0;
175
176    egl_connection_t* const cnx = &gEGLImpl;
177    if (cnx->dso) {
178        res = cnx->egl.eglGetConfigs(
179                dp->disp.dpy, configs, config_size, num_config);
180    }
181
182    return res;
183}
184
185EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
186                            EGLConfig *configs, EGLint config_size,
187                            EGLint *num_config)
188{
189    clearError();
190
191    egl_display_t const * const dp = validate_display(dpy);
192    if (!dp) return EGL_FALSE;
193
194    if (num_config==0) {
195        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
196    }
197
198    EGLBoolean res = EGL_FALSE;
199    *num_config = 0;
200
201    egl_connection_t* const cnx = &gEGLImpl;
202    if (cnx->dso) {
203        res = cnx->egl.eglChooseConfig(
204                dp->disp.dpy, attrib_list, configs, config_size, num_config);
205    }
206    return res;
207}
208
209EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
210        EGLint attribute, EGLint *value)
211{
212    clearError();
213
214    egl_display_t const* dp = 0;
215    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
216    if (!cnx) return EGL_FALSE;
217
218    return cnx->egl.eglGetConfigAttrib(
219            dp->disp.dpy, config, attribute, value);
220}
221
222// ----------------------------------------------------------------------------
223// surfaces
224// ----------------------------------------------------------------------------
225
226EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
227                                    NativeWindowType window,
228                                    const EGLint *attrib_list)
229{
230    clearError();
231
232    egl_display_t const* dp = 0;
233    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
234    if (cnx) {
235        EGLDisplay iDpy = dp->disp.dpy;
236        EGLint format;
237
238        if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
239            ALOGE("EGLNativeWindowType %p already connected to another API",
240                    window);
241            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
242        }
243
244        // set the native window's buffers format to match this config
245        if (cnx->egl.eglGetConfigAttrib(iDpy,
246                config, EGL_NATIVE_VISUAL_ID, &format)) {
247            if (format != 0) {
248                int err = native_window_set_buffers_format(window, format);
249                if (err != 0) {
250                    ALOGE("error setting native window pixel format: %s (%d)",
251                            strerror(-err), err);
252                    native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
253                    return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
254                }
255            }
256        }
257
258        // the EGL spec requires that a new EGLSurface default to swap interval
259        // 1, so explicitly set that on the window here.
260        ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
261        anw->setSwapInterval(anw, 1);
262
263        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
264                iDpy, config, window, attrib_list);
265        if (surface != EGL_NO_SURFACE) {
266            egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, cnx);
267            return s;
268        }
269
270        // EGLSurface creation failed
271        native_window_set_buffers_format(window, 0);
272        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
273    }
274    return EGL_NO_SURFACE;
275}
276
277EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
278                                    NativePixmapType pixmap,
279                                    const EGLint *attrib_list)
280{
281    clearError();
282
283    egl_display_t const* dp = 0;
284    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
285    if (cnx) {
286        EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
287                dp->disp.dpy, config, pixmap, attrib_list);
288        if (surface != EGL_NO_SURFACE) {
289            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
290            return s;
291        }
292    }
293    return EGL_NO_SURFACE;
294}
295
296EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
297                                    const EGLint *attrib_list)
298{
299    clearError();
300
301    egl_display_t const* dp = 0;
302    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
303    if (cnx) {
304        EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
305                dp->disp.dpy, config, attrib_list);
306        if (surface != EGL_NO_SURFACE) {
307            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
308            return s;
309        }
310    }
311    return EGL_NO_SURFACE;
312}
313
314EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
315{
316    clearError();
317
318    egl_display_t const * const dp = validate_display(dpy);
319    if (!dp) return EGL_FALSE;
320
321    SurfaceRef _s(dp, surface);
322    if (!_s.get())
323        return setError(EGL_BAD_SURFACE, EGL_FALSE);
324
325    egl_surface_t * const s = get_surface(surface);
326    EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
327    if (result == EGL_TRUE) {
328        _s.terminate();
329    }
330    return result;
331}
332
333EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
334                            EGLint attribute, EGLint *value)
335{
336    clearError();
337
338    egl_display_t const * const dp = validate_display(dpy);
339    if (!dp) return EGL_FALSE;
340
341    SurfaceRef _s(dp, surface);
342    if (!_s.get())
343        return setError(EGL_BAD_SURFACE, EGL_FALSE);
344
345    egl_surface_t const * const s = get_surface(surface);
346    return s->cnx->egl.eglQuerySurface(
347            dp->disp.dpy, s->surface, attribute, value);
348}
349
350void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
351    clearError();
352
353    egl_display_t const * const dp = validate_display(dpy);
354    if (!dp) {
355        return;
356    }
357
358    SurfaceRef _s(dp, surface);
359    if (!_s.get()) {
360        setError(EGL_BAD_SURFACE, EGL_FALSE);
361        return;
362    }
363
364    int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
365
366    egl_surface_t const * const s = get_surface(surface);
367    native_window_set_buffers_timestamp(s->win.get(), timestamp);
368}
369
370// ----------------------------------------------------------------------------
371// Contexts
372// ----------------------------------------------------------------------------
373
374EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
375                            EGLContext share_list, const EGLint *attrib_list)
376{
377    clearError();
378
379    egl_display_t const* dp = 0;
380    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
381    if (cnx) {
382        if (share_list != EGL_NO_CONTEXT) {
383            egl_context_t* const c = get_context(share_list);
384            share_list = c->context;
385        }
386        EGLContext context = cnx->egl.eglCreateContext(
387                dp->disp.dpy, config, share_list, attrib_list);
388        if (context != EGL_NO_CONTEXT) {
389            // figure out if it's a GLESv1 or GLESv2
390            int version = 0;
391            if (attrib_list) {
392                while (*attrib_list != EGL_NONE) {
393                    GLint attr = *attrib_list++;
394                    GLint value = *attrib_list++;
395                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
396                        if (value == 1) {
397                            version = egl_connection_t::GLESv1_INDEX;
398                        } else if (value == 2) {
399                            version = egl_connection_t::GLESv2_INDEX;
400                        }
401                    }
402                };
403            }
404            egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version);
405#if EGL_TRACE
406            if (gEGLDebugLevel > 0)
407                GLTrace_eglCreateContext(version, c);
408#endif
409            return c;
410        }
411    }
412    return EGL_NO_CONTEXT;
413}
414
415EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
416{
417    clearError();
418
419    egl_display_t const * const dp = validate_display(dpy);
420    if (!dp)
421        return EGL_FALSE;
422
423    ContextRef _c(dp, ctx);
424    if (!_c.get())
425        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
426
427    egl_context_t * const c = get_context(ctx);
428    EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
429    if (result == EGL_TRUE) {
430        _c.terminate();
431    }
432    return result;
433}
434
435EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
436                            EGLSurface read, EGLContext ctx)
437{
438    clearError();
439
440    egl_display_t const * const dp = get_display(dpy);
441    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
442
443    // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
444    // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
445    // a valid but uninitialized display.
446    if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
447         (draw != EGL_NO_SURFACE) ) {
448        if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
449    }
450
451    // get a reference to the object passed in
452    ContextRef _c(dp, ctx);
453    SurfaceRef _d(dp, draw);
454    SurfaceRef _r(dp, read);
455
456    // validate the context (if not EGL_NO_CONTEXT)
457    if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
458        // EGL_NO_CONTEXT is valid
459        return EGL_FALSE;
460    }
461
462    // these are the underlying implementation's object
463    EGLContext impl_ctx  = EGL_NO_CONTEXT;
464    EGLSurface impl_draw = EGL_NO_SURFACE;
465    EGLSurface impl_read = EGL_NO_SURFACE;
466
467    // these are our objects structs passed in
468    egl_context_t       * c = NULL;
469    egl_surface_t const * d = NULL;
470    egl_surface_t const * r = NULL;
471
472    // these are the current objects structs
473    egl_context_t * cur_c = get_context(getContext());
474
475    if (ctx != EGL_NO_CONTEXT) {
476        c = get_context(ctx);
477        impl_ctx = c->context;
478    } else {
479        // no context given, use the implementation of the current context
480        if (cur_c == NULL) {
481            // no current context
482            if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
483                // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
484                return setError(EGL_BAD_MATCH, EGL_FALSE);
485            }
486            // not an error, there is just no current context.
487            return EGL_TRUE;
488        }
489    }
490
491    // retrieve the underlying implementation's draw EGLSurface
492    if (draw != EGL_NO_SURFACE) {
493        d = get_surface(draw);
494        impl_draw = d->surface;
495    }
496
497    // retrieve the underlying implementation's read EGLSurface
498    if (read != EGL_NO_SURFACE) {
499        r = get_surface(read);
500        impl_read = r->surface;
501    }
502
503
504    EGLBoolean result = const_cast<egl_display_t*>(dp)->makeCurrent(c, cur_c,
505            draw, read, ctx,
506            impl_draw, impl_read, impl_ctx);
507
508    if (result == EGL_TRUE) {
509        if (c) {
510            setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
511            egl_tls_t::setContext(ctx);
512#if EGL_TRACE
513            if (gEGLDebugLevel > 0)
514                GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
515#endif
516            _c.acquire();
517            _r.acquire();
518            _d.acquire();
519        } else {
520            setGLHooksThreadSpecific(&gHooksNoContext);
521            egl_tls_t::setContext(EGL_NO_CONTEXT);
522        }
523    } else {
524        // this will ALOGE the error
525        result = setError(c->cnx->egl.eglGetError(), EGL_FALSE);
526    }
527    return result;
528}
529
530
531EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
532                            EGLint attribute, EGLint *value)
533{
534    clearError();
535
536    egl_display_t const * const dp = validate_display(dpy);
537    if (!dp) return EGL_FALSE;
538
539    ContextRef _c(dp, ctx);
540    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
541
542    egl_context_t * const c = get_context(ctx);
543    return c->cnx->egl.eglQueryContext(
544            dp->disp.dpy, c->context, attribute, value);
545
546}
547
548EGLContext eglGetCurrentContext(void)
549{
550    // could be called before eglInitialize(), but we wouldn't have a context
551    // then, and this function would correctly return EGL_NO_CONTEXT.
552
553    clearError();
554
555    EGLContext ctx = getContext();
556    return ctx;
557}
558
559EGLSurface eglGetCurrentSurface(EGLint readdraw)
560{
561    // could be called before eglInitialize(), but we wouldn't have a context
562    // then, and this function would correctly return EGL_NO_SURFACE.
563
564    clearError();
565
566    EGLContext ctx = getContext();
567    if (ctx) {
568        egl_context_t const * const c = get_context(ctx);
569        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
570        switch (readdraw) {
571            case EGL_READ: return c->read;
572            case EGL_DRAW: return c->draw;
573            default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
574        }
575    }
576    return EGL_NO_SURFACE;
577}
578
579EGLDisplay eglGetCurrentDisplay(void)
580{
581    // could be called before eglInitialize(), but we wouldn't have a context
582    // then, and this function would correctly return EGL_NO_DISPLAY.
583
584    clearError();
585
586    EGLContext ctx = getContext();
587    if (ctx) {
588        egl_context_t const * const c = get_context(ctx);
589        if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
590        return c->dpy;
591    }
592    return EGL_NO_DISPLAY;
593}
594
595EGLBoolean eglWaitGL(void)
596{
597    clearError();
598
599    egl_connection_t* const cnx = &gEGLImpl;
600    if (!cnx->dso)
601        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
602
603    return cnx->egl.eglWaitGL();
604}
605
606EGLBoolean eglWaitNative(EGLint engine)
607{
608    clearError();
609
610    egl_connection_t* const cnx = &gEGLImpl;
611    if (!cnx->dso)
612        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
613
614    return cnx->egl.eglWaitNative(engine);
615}
616
617EGLint eglGetError(void)
618{
619    EGLint err = EGL_SUCCESS;
620    egl_connection_t* const cnx = &gEGLImpl;
621    if (cnx->dso) {
622        err = cnx->egl.eglGetError();
623    }
624    if (err == EGL_SUCCESS) {
625        err = egl_tls_t::getError();
626    }
627    return err;
628}
629
630__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
631{
632    // eglGetProcAddress() could be the very first function called
633    // in which case we must make sure we've initialized ourselves, this
634    // happens the first time egl_get_display() is called.
635
636    clearError();
637
638    if (egl_init_drivers() == EGL_FALSE) {
639        setError(EGL_BAD_PARAMETER, NULL);
640        return  NULL;
641    }
642
643    // The EGL_ANDROID_blob_cache extension should not be exposed to
644    // applications.  It is used internally by the Android EGL layer.
645    if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID")) {
646        return NULL;
647    }
648
649    __eglMustCastToProperFunctionPointerType addr;
650    addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
651    if (addr) return addr;
652
653
654    // this protects accesses to sGLExtentionMap and sGLExtentionSlot
655    pthread_mutex_lock(&sExtensionMapMutex);
656
657        /*
658         * Since eglGetProcAddress() is not associated to anything, it needs
659         * to return a function pointer that "works" regardless of what
660         * the current context is.
661         *
662         * For this reason, we return a "forwarder", a small stub that takes
663         * care of calling the function associated with the context
664         * currently bound.
665         *
666         * We first look for extensions we've already resolved, if we're seeing
667         * this extension for the first time, we go through all our
668         * implementations and call eglGetProcAddress() and record the
669         * result in the appropriate implementation hooks and return the
670         * address of the forwarder corresponding to that hook set.
671         *
672         */
673
674        const String8 name(procname);
675        addr = sGLExtentionMap.valueFor(name);
676        const int slot = sGLExtentionSlot;
677
678        ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
679                "no more slots for eglGetProcAddress(\"%s\")",
680                procname);
681
682#if EGL_TRACE
683        gl_hooks_t *debugHooks = GLTrace_getGLHooks();
684#endif
685
686        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
687            bool found = false;
688
689            egl_connection_t* const cnx = &gEGLImpl;
690            if (cnx->dso && cnx->egl.eglGetProcAddress) {
691                found = true;
692                // Extensions are independent of the bound context
693                cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
694                cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
695#if EGL_TRACE
696                debugHooks->ext.extensions[slot] =
697                gHooksTrace.ext.extensions[slot] =
698#endif
699                        cnx->egl.eglGetProcAddress(procname);
700            }
701
702            if (found) {
703                addr = gExtensionForwarders[slot];
704                sGLExtentionMap.add(name, addr);
705                sGLExtentionSlot++;
706            }
707        }
708
709    pthread_mutex_unlock(&sExtensionMapMutex);
710    return addr;
711}
712
713EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
714{
715    clearError();
716
717    egl_display_t const * const dp = validate_display(dpy);
718    if (!dp) return EGL_FALSE;
719
720    SurfaceRef _s(dp, draw);
721    if (!_s.get())
722        return setError(EGL_BAD_SURFACE, EGL_FALSE);
723
724#if EGL_TRACE
725    if (gEGLDebugLevel > 0)
726        GLTrace_eglSwapBuffers(dpy, draw);
727#endif
728
729    egl_surface_t const * const s = get_surface(draw);
730    return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
731}
732
733EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
734                            NativePixmapType target)
735{
736    clearError();
737
738    egl_display_t const * const dp = validate_display(dpy);
739    if (!dp) return EGL_FALSE;
740
741    SurfaceRef _s(dp, surface);
742    if (!_s.get())
743        return setError(EGL_BAD_SURFACE, EGL_FALSE);
744
745    egl_surface_t const * const s = get_surface(surface);
746    return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
747}
748
749const char* eglQueryString(EGLDisplay dpy, EGLint name)
750{
751    clearError();
752
753    egl_display_t const * const dp = validate_display(dpy);
754    if (!dp) return (const char *) NULL;
755
756    switch (name) {
757        case EGL_VENDOR:
758            return dp->getVendorString();
759        case EGL_VERSION:
760            return dp->getVersionString();
761        case EGL_EXTENSIONS:
762            return dp->getExtensionString();
763        case EGL_CLIENT_APIS:
764            return dp->getClientApiString();
765        case EGL_VERSION_HW_ANDROID:
766            return dp->disp.queryString.version;
767    }
768    return setError(EGL_BAD_PARAMETER, (const char *)0);
769}
770
771
772// ----------------------------------------------------------------------------
773// EGL 1.1
774// ----------------------------------------------------------------------------
775
776EGLBoolean eglSurfaceAttrib(
777        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
778{
779    clearError();
780
781    egl_display_t const * const dp = validate_display(dpy);
782    if (!dp) return EGL_FALSE;
783
784    SurfaceRef _s(dp, surface);
785    if (!_s.get())
786        return setError(EGL_BAD_SURFACE, EGL_FALSE);
787
788    egl_surface_t const * const s = get_surface(surface);
789    if (s->cnx->egl.eglSurfaceAttrib) {
790        return s->cnx->egl.eglSurfaceAttrib(
791                dp->disp.dpy, s->surface, attribute, value);
792    }
793    return setError(EGL_BAD_SURFACE, EGL_FALSE);
794}
795
796EGLBoolean eglBindTexImage(
797        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
798{
799    clearError();
800
801    egl_display_t const * const dp = validate_display(dpy);
802    if (!dp) return EGL_FALSE;
803
804    SurfaceRef _s(dp, surface);
805    if (!_s.get())
806        return setError(EGL_BAD_SURFACE, EGL_FALSE);
807
808    egl_surface_t const * const s = get_surface(surface);
809    if (s->cnx->egl.eglBindTexImage) {
810        return s->cnx->egl.eglBindTexImage(
811                dp->disp.dpy, s->surface, buffer);
812    }
813    return setError(EGL_BAD_SURFACE, EGL_FALSE);
814}
815
816EGLBoolean eglReleaseTexImage(
817        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
818{
819    clearError();
820
821    egl_display_t const * const dp = validate_display(dpy);
822    if (!dp) return EGL_FALSE;
823
824    SurfaceRef _s(dp, surface);
825    if (!_s.get())
826        return setError(EGL_BAD_SURFACE, EGL_FALSE);
827
828    egl_surface_t const * const s = get_surface(surface);
829    if (s->cnx->egl.eglReleaseTexImage) {
830        return s->cnx->egl.eglReleaseTexImage(
831                dp->disp.dpy, s->surface, buffer);
832    }
833    return setError(EGL_BAD_SURFACE, EGL_FALSE);
834}
835
836EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
837{
838    clearError();
839
840    egl_display_t const * const dp = validate_display(dpy);
841    if (!dp) return EGL_FALSE;
842
843    EGLBoolean res = EGL_TRUE;
844    egl_connection_t* const cnx = &gEGLImpl;
845    if (cnx->dso && cnx->egl.eglSwapInterval) {
846        res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
847    }
848
849    return res;
850}
851
852
853// ----------------------------------------------------------------------------
854// EGL 1.2
855// ----------------------------------------------------------------------------
856
857EGLBoolean eglWaitClient(void)
858{
859    clearError();
860
861    egl_connection_t* const cnx = &gEGLImpl;
862    if (!cnx->dso)
863        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
864
865    EGLBoolean res;
866    if (cnx->egl.eglWaitClient) {
867        res = cnx->egl.eglWaitClient();
868    } else {
869        res = cnx->egl.eglWaitGL();
870    }
871    return res;
872}
873
874EGLBoolean eglBindAPI(EGLenum api)
875{
876    clearError();
877
878    if (egl_init_drivers() == EGL_FALSE) {
879        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
880    }
881
882    // bind this API on all EGLs
883    EGLBoolean res = EGL_TRUE;
884    egl_connection_t* const cnx = &gEGLImpl;
885    if (cnx->dso && cnx->egl.eglBindAPI) {
886        res = cnx->egl.eglBindAPI(api);
887    }
888    return res;
889}
890
891EGLenum eglQueryAPI(void)
892{
893    clearError();
894
895    if (egl_init_drivers() == EGL_FALSE) {
896        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
897    }
898
899    egl_connection_t* const cnx = &gEGLImpl;
900    if (cnx->dso && cnx->egl.eglQueryAPI) {
901        return cnx->egl.eglQueryAPI();
902    }
903
904    // or, it can only be OpenGL ES
905    return EGL_OPENGL_ES_API;
906}
907
908EGLBoolean eglReleaseThread(void)
909{
910    clearError();
911
912    // If there is context bound to the thread, release it
913    egl_display_t::loseCurrent(get_context(getContext()));
914
915    egl_connection_t* const cnx = &gEGLImpl;
916    if (cnx->dso && cnx->egl.eglReleaseThread) {
917        cnx->egl.eglReleaseThread();
918    }
919
920    egl_tls_t::clearTLS();
921#if EGL_TRACE
922    if (gEGLDebugLevel > 0)
923        GLTrace_eglReleaseThread();
924#endif
925    return EGL_TRUE;
926}
927
928EGLSurface eglCreatePbufferFromClientBuffer(
929          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
930          EGLConfig config, const EGLint *attrib_list)
931{
932    clearError();
933
934    egl_display_t const* dp = 0;
935    egl_connection_t* cnx = validate_display_config(dpy, config, dp);
936    if (!cnx) return EGL_FALSE;
937    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
938        return cnx->egl.eglCreatePbufferFromClientBuffer(
939                dp->disp.dpy, buftype, buffer, config, attrib_list);
940    }
941    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
942}
943
944// ----------------------------------------------------------------------------
945// EGL_EGLEXT_VERSION 3
946// ----------------------------------------------------------------------------
947
948EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
949        const EGLint *attrib_list)
950{
951    clearError();
952
953    egl_display_t const * const dp = validate_display(dpy);
954    if (!dp) return EGL_FALSE;
955
956    SurfaceRef _s(dp, surface);
957    if (!_s.get())
958        return setError(EGL_BAD_SURFACE, EGL_FALSE);
959
960    egl_surface_t const * const s = get_surface(surface);
961    if (s->cnx->egl.eglLockSurfaceKHR) {
962        return s->cnx->egl.eglLockSurfaceKHR(
963                dp->disp.dpy, s->surface, attrib_list);
964    }
965    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
966}
967
968EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
969{
970    clearError();
971
972    egl_display_t const * const dp = validate_display(dpy);
973    if (!dp) return EGL_FALSE;
974
975    SurfaceRef _s(dp, surface);
976    if (!_s.get())
977        return setError(EGL_BAD_SURFACE, EGL_FALSE);
978
979    egl_surface_t const * const s = get_surface(surface);
980    if (s->cnx->egl.eglUnlockSurfaceKHR) {
981        return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
982    }
983    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
984}
985
986EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
987        EGLClientBuffer buffer, const EGLint *attrib_list)
988{
989    clearError();
990
991    egl_display_t const * const dp = validate_display(dpy);
992    if (!dp) return EGL_NO_IMAGE_KHR;
993
994    ContextRef _c(dp, ctx);
995    egl_context_t * const c = _c.get();
996
997    EGLImageKHR result = EGL_NO_IMAGE_KHR;
998    egl_connection_t* const cnx = &gEGLImpl;
999    if (cnx->dso && cnx->egl.eglCreateImageKHR) {
1000        result = cnx->egl.eglCreateImageKHR(
1001                dp->disp.dpy,
1002                c ? c->context : EGL_NO_CONTEXT,
1003                target, buffer, attrib_list);
1004    }
1005    return result;
1006}
1007
1008EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1009{
1010    clearError();
1011
1012    egl_display_t const * const dp = validate_display(dpy);
1013    if (!dp) return EGL_FALSE;
1014
1015    egl_connection_t* const cnx = &gEGLImpl;
1016    if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
1017        cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
1018    }
1019    return EGL_TRUE;
1020}
1021
1022// ----------------------------------------------------------------------------
1023// EGL_EGLEXT_VERSION 5
1024// ----------------------------------------------------------------------------
1025
1026
1027EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1028{
1029    clearError();
1030
1031    egl_display_t const * const dp = validate_display(dpy);
1032    if (!dp) return EGL_NO_SYNC_KHR;
1033
1034    EGLSyncKHR result = EGL_NO_SYNC_KHR;
1035    egl_connection_t* const cnx = &gEGLImpl;
1036    if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
1037        result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
1038    }
1039    return result;
1040}
1041
1042EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1043{
1044    clearError();
1045
1046    egl_display_t const * const dp = validate_display(dpy);
1047    if (!dp) return EGL_FALSE;
1048
1049    EGLBoolean result = EGL_FALSE;
1050    egl_connection_t* const cnx = &gEGLImpl;
1051    if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
1052        result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
1053    }
1054    return result;
1055}
1056
1057EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
1058        EGLint flags, EGLTimeKHR timeout)
1059{
1060    clearError();
1061
1062    egl_display_t const * const dp = validate_display(dpy);
1063    if (!dp) return EGL_FALSE;
1064
1065    EGLBoolean result = EGL_FALSE;
1066    egl_connection_t* const cnx = &gEGLImpl;
1067    if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
1068        result = cnx->egl.eglClientWaitSyncKHR(
1069                dp->disp.dpy, sync, flags, timeout);
1070    }
1071    return result;
1072}
1073
1074EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
1075        EGLint attribute, EGLint *value)
1076{
1077    clearError();
1078
1079    egl_display_t const * const dp = validate_display(dpy);
1080    if (!dp) return EGL_FALSE;
1081
1082    EGLBoolean result = EGL_FALSE;
1083    egl_connection_t* const cnx = &gEGLImpl;
1084    if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
1085        result = cnx->egl.eglGetSyncAttribKHR(
1086                dp->disp.dpy, sync, attribute, value);
1087    }
1088    return result;
1089}
1090
1091// ----------------------------------------------------------------------------
1092// ANDROID extensions
1093// ----------------------------------------------------------------------------
1094
1095/* ANDROID extensions entry-point go here */
1096
1097// ----------------------------------------------------------------------------
1098// NVIDIA extensions
1099// ----------------------------------------------------------------------------
1100EGLuint64NV eglGetSystemTimeFrequencyNV()
1101{
1102    clearError();
1103
1104    if (egl_init_drivers() == EGL_FALSE) {
1105        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1106    }
1107
1108    EGLuint64NV ret = 0;
1109    egl_connection_t* const cnx = &gEGLImpl;
1110
1111    if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
1112        return cnx->egl.eglGetSystemTimeFrequencyNV();
1113    }
1114
1115    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1116}
1117
1118EGLuint64NV eglGetSystemTimeNV()
1119{
1120    clearError();
1121
1122    if (egl_init_drivers() == EGL_FALSE) {
1123        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1124    }
1125
1126    EGLuint64NV ret = 0;
1127    egl_connection_t* const cnx = &gEGLImpl;
1128
1129    if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
1130        return cnx->egl.eglGetSystemTimeNV();
1131    }
1132
1133    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1134}
1135