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