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