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