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