eglApi.cpp revision ed6d08b70d775852f4827471814c83eba3606aaa
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->traceGpuCompletion)) {
964        EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
965        if (sync != EGL_NO_SYNC_KHR) {
966            FrameCompletionThread::queueSync(sync);
967        }
968    }
969
970    if (CC_UNLIKELY(dp->finishOnSwap)) {
971        uint32_t pixel;
972        egl_context_t * const c = get_context( egl_tls_t::getContext() );
973        if (c) {
974            // glReadPixels() ensures that the frame is complete
975            s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1,
976                    GL_RGBA,GL_UNSIGNED_BYTE,&pixel);
977        }
978    }
979
980    return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
981}
982
983EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
984                            NativePixmapType target)
985{
986    clearError();
987
988    const egl_display_ptr dp = validate_display(dpy);
989    if (!dp) return EGL_FALSE;
990
991    SurfaceRef _s(dp.get(), surface);
992    if (!_s.get())
993        return setError(EGL_BAD_SURFACE, EGL_FALSE);
994
995    egl_surface_t const * const s = get_surface(surface);
996    return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
997}
998
999const char* eglQueryString(EGLDisplay dpy, EGLint name)
1000{
1001    clearError();
1002
1003    const egl_display_ptr dp = validate_display(dpy);
1004    if (!dp) return (const char *) NULL;
1005
1006    switch (name) {
1007        case EGL_VENDOR:
1008            return dp->getVendorString();
1009        case EGL_VERSION:
1010            return dp->getVersionString();
1011        case EGL_EXTENSIONS:
1012            return dp->getExtensionString();
1013        case EGL_CLIENT_APIS:
1014            return dp->getClientApiString();
1015    }
1016    return setError(EGL_BAD_PARAMETER, (const char *)0);
1017}
1018
1019EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
1020{
1021    clearError();
1022
1023    const egl_display_ptr dp = validate_display(dpy);
1024    if (!dp) return (const char *) NULL;
1025
1026    switch (name) {
1027        case EGL_VENDOR:
1028            return dp->disp.queryString.vendor;
1029        case EGL_VERSION:
1030            return dp->disp.queryString.version;
1031        case EGL_EXTENSIONS:
1032            return dp->disp.queryString.extensions;
1033        case EGL_CLIENT_APIS:
1034            return dp->disp.queryString.clientApi;
1035    }
1036    return setError(EGL_BAD_PARAMETER, (const char *)0);
1037}
1038
1039// ----------------------------------------------------------------------------
1040// EGL 1.1
1041// ----------------------------------------------------------------------------
1042
1043EGLBoolean eglSurfaceAttrib(
1044        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1045{
1046    clearError();
1047
1048    const egl_display_ptr dp = validate_display(dpy);
1049    if (!dp) return EGL_FALSE;
1050
1051    SurfaceRef _s(dp.get(), surface);
1052    if (!_s.get())
1053        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1054
1055    egl_surface_t const * const s = get_surface(surface);
1056    if (s->cnx->egl.eglSurfaceAttrib) {
1057        return s->cnx->egl.eglSurfaceAttrib(
1058                dp->disp.dpy, s->surface, attribute, value);
1059    }
1060    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1061}
1062
1063EGLBoolean eglBindTexImage(
1064        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1065{
1066    clearError();
1067
1068    const egl_display_ptr dp = validate_display(dpy);
1069    if (!dp) return EGL_FALSE;
1070
1071    SurfaceRef _s(dp.get(), surface);
1072    if (!_s.get())
1073        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1074
1075    egl_surface_t const * const s = get_surface(surface);
1076    if (s->cnx->egl.eglBindTexImage) {
1077        return s->cnx->egl.eglBindTexImage(
1078                dp->disp.dpy, s->surface, buffer);
1079    }
1080    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1081}
1082
1083EGLBoolean eglReleaseTexImage(
1084        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1085{
1086    clearError();
1087
1088    const egl_display_ptr dp = validate_display(dpy);
1089    if (!dp) return EGL_FALSE;
1090
1091    SurfaceRef _s(dp.get(), surface);
1092    if (!_s.get())
1093        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1094
1095    egl_surface_t const * const s = get_surface(surface);
1096    if (s->cnx->egl.eglReleaseTexImage) {
1097        return s->cnx->egl.eglReleaseTexImage(
1098                dp->disp.dpy, s->surface, buffer);
1099    }
1100    return setError(EGL_BAD_SURFACE, EGL_FALSE);
1101}
1102
1103EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1104{
1105    clearError();
1106
1107    const egl_display_ptr dp = validate_display(dpy);
1108    if (!dp) return EGL_FALSE;
1109
1110    EGLBoolean res = EGL_TRUE;
1111    egl_connection_t* const cnx = &gEGLImpl;
1112    if (cnx->dso && cnx->egl.eglSwapInterval) {
1113        res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
1114    }
1115
1116    return res;
1117}
1118
1119
1120// ----------------------------------------------------------------------------
1121// EGL 1.2
1122// ----------------------------------------------------------------------------
1123
1124EGLBoolean eglWaitClient(void)
1125{
1126    clearError();
1127
1128    egl_connection_t* const cnx = &gEGLImpl;
1129    if (!cnx->dso)
1130        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1131
1132    EGLBoolean res;
1133    if (cnx->egl.eglWaitClient) {
1134        res = cnx->egl.eglWaitClient();
1135    } else {
1136        res = cnx->egl.eglWaitGL();
1137    }
1138    return res;
1139}
1140
1141EGLBoolean eglBindAPI(EGLenum api)
1142{
1143    clearError();
1144
1145    if (egl_init_drivers() == EGL_FALSE) {
1146        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1147    }
1148
1149    // bind this API on all EGLs
1150    EGLBoolean res = EGL_TRUE;
1151    egl_connection_t* const cnx = &gEGLImpl;
1152    if (cnx->dso && cnx->egl.eglBindAPI) {
1153        res = cnx->egl.eglBindAPI(api);
1154    }
1155    return res;
1156}
1157
1158EGLenum eglQueryAPI(void)
1159{
1160    clearError();
1161
1162    if (egl_init_drivers() == EGL_FALSE) {
1163        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1164    }
1165
1166    egl_connection_t* const cnx = &gEGLImpl;
1167    if (cnx->dso && cnx->egl.eglQueryAPI) {
1168        return cnx->egl.eglQueryAPI();
1169    }
1170
1171    // or, it can only be OpenGL ES
1172    return EGL_OPENGL_ES_API;
1173}
1174
1175EGLBoolean eglReleaseThread(void)
1176{
1177    clearError();
1178
1179    // If there is context bound to the thread, release it
1180    egl_display_t::loseCurrent(get_context(getContext()));
1181
1182    egl_connection_t* const cnx = &gEGLImpl;
1183    if (cnx->dso && cnx->egl.eglReleaseThread) {
1184        cnx->egl.eglReleaseThread();
1185    }
1186
1187    egl_tls_t::clearTLS();
1188#if EGL_TRACE
1189    if (getEGLDebugLevel() > 0)
1190        GLTrace_eglReleaseThread();
1191#endif
1192    return EGL_TRUE;
1193}
1194
1195EGLSurface eglCreatePbufferFromClientBuffer(
1196          EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1197          EGLConfig config, const EGLint *attrib_list)
1198{
1199    clearError();
1200
1201    egl_connection_t* cnx = NULL;
1202    const egl_display_ptr dp = validate_display_connection(dpy, cnx);
1203    if (!dp) return EGL_FALSE;
1204    if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1205        return cnx->egl.eglCreatePbufferFromClientBuffer(
1206                dp->disp.dpy, buftype, buffer, config, attrib_list);
1207    }
1208    return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1209}
1210
1211// ----------------------------------------------------------------------------
1212// EGL_EGLEXT_VERSION 3
1213// ----------------------------------------------------------------------------
1214
1215EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1216        const EGLint *attrib_list)
1217{
1218    clearError();
1219
1220    const egl_display_ptr dp = validate_display(dpy);
1221    if (!dp) return EGL_FALSE;
1222
1223    SurfaceRef _s(dp.get(), surface);
1224    if (!_s.get())
1225        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1226
1227    egl_surface_t const * const s = get_surface(surface);
1228    if (s->cnx->egl.eglLockSurfaceKHR) {
1229        return s->cnx->egl.eglLockSurfaceKHR(
1230                dp->disp.dpy, s->surface, attrib_list);
1231    }
1232    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1233}
1234
1235EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1236{
1237    clearError();
1238
1239    const egl_display_ptr dp = validate_display(dpy);
1240    if (!dp) return EGL_FALSE;
1241
1242    SurfaceRef _s(dp.get(), surface);
1243    if (!_s.get())
1244        return setError(EGL_BAD_SURFACE, EGL_FALSE);
1245
1246    egl_surface_t const * const s = get_surface(surface);
1247    if (s->cnx->egl.eglUnlockSurfaceKHR) {
1248        return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
1249    }
1250    return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1251}
1252
1253EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1254        EGLClientBuffer buffer, const EGLint *attrib_list)
1255{
1256    clearError();
1257
1258    const egl_display_ptr dp = validate_display(dpy);
1259    if (!dp) return EGL_NO_IMAGE_KHR;
1260
1261    ContextRef _c(dp.get(), ctx);
1262    egl_context_t * const c = _c.get();
1263
1264    EGLImageKHR result = EGL_NO_IMAGE_KHR;
1265    egl_connection_t* const cnx = &gEGLImpl;
1266    if (cnx->dso && cnx->egl.eglCreateImageKHR) {
1267        result = cnx->egl.eglCreateImageKHR(
1268                dp->disp.dpy,
1269                c ? c->context : EGL_NO_CONTEXT,
1270                target, buffer, attrib_list);
1271    }
1272    return result;
1273}
1274
1275EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1276{
1277    clearError();
1278
1279    const egl_display_ptr dp = validate_display(dpy);
1280    if (!dp) return EGL_FALSE;
1281
1282    EGLBoolean result = EGL_FALSE;
1283    egl_connection_t* const cnx = &gEGLImpl;
1284    if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
1285        result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
1286    }
1287    return result;
1288}
1289
1290// ----------------------------------------------------------------------------
1291// EGL_EGLEXT_VERSION 5
1292// ----------------------------------------------------------------------------
1293
1294
1295EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1296{
1297    clearError();
1298
1299    const egl_display_ptr dp = validate_display(dpy);
1300    if (!dp) return EGL_NO_SYNC_KHR;
1301
1302    EGLSyncKHR result = EGL_NO_SYNC_KHR;
1303    egl_connection_t* const cnx = &gEGLImpl;
1304    if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
1305        result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
1306    }
1307    return result;
1308}
1309
1310EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1311{
1312    clearError();
1313
1314    const egl_display_ptr dp = validate_display(dpy);
1315    if (!dp) return EGL_FALSE;
1316
1317    EGLBoolean result = EGL_FALSE;
1318    egl_connection_t* const cnx = &gEGLImpl;
1319    if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
1320        result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
1321    }
1322    return result;
1323}
1324
1325EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
1326    clearError();
1327
1328    const egl_display_ptr dp = validate_display(dpy);
1329    if (!dp) return EGL_FALSE;
1330
1331    EGLBoolean result = EGL_FALSE;
1332    egl_connection_t* const cnx = &gEGLImpl;
1333    if (cnx->dso && cnx->egl.eglSignalSyncKHR) {
1334        result = cnx->egl.eglSignalSyncKHR(
1335                dp->disp.dpy, sync, mode);
1336    }
1337    return result;
1338}
1339
1340EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
1341        EGLint flags, EGLTimeKHR timeout)
1342{
1343    clearError();
1344
1345    const egl_display_ptr dp = validate_display(dpy);
1346    if (!dp) return EGL_FALSE;
1347
1348    EGLBoolean result = EGL_FALSE;
1349    egl_connection_t* const cnx = &gEGLImpl;
1350    if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
1351        result = cnx->egl.eglClientWaitSyncKHR(
1352                dp->disp.dpy, sync, flags, timeout);
1353    }
1354    return result;
1355}
1356
1357EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
1358        EGLint attribute, EGLint *value)
1359{
1360    clearError();
1361
1362    const egl_display_ptr dp = validate_display(dpy);
1363    if (!dp) return EGL_FALSE;
1364
1365    EGLBoolean result = EGL_FALSE;
1366    egl_connection_t* const cnx = &gEGLImpl;
1367    if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
1368        result = cnx->egl.eglGetSyncAttribKHR(
1369                dp->disp.dpy, sync, attribute, value);
1370    }
1371    return result;
1372}
1373
1374// ----------------------------------------------------------------------------
1375// EGL_EGLEXT_VERSION 15
1376// ----------------------------------------------------------------------------
1377
1378EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) {
1379    clearError();
1380    const egl_display_ptr dp = validate_display(dpy);
1381    if (!dp) return EGL_FALSE;
1382    EGLint result = EGL_FALSE;
1383    egl_connection_t* const cnx = &gEGLImpl;
1384    if (cnx->dso && cnx->egl.eglWaitSyncKHR) {
1385        result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags);
1386    }
1387    return result;
1388}
1389
1390// ----------------------------------------------------------------------------
1391// ANDROID extensions
1392// ----------------------------------------------------------------------------
1393
1394EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync)
1395{
1396    clearError();
1397
1398    const egl_display_ptr dp = validate_display(dpy);
1399    if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
1400
1401    EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
1402    egl_connection_t* const cnx = &gEGLImpl;
1403    if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) {
1404        result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync);
1405    }
1406    return result;
1407}
1408
1409EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface,
1410        EGLnsecsANDROID time)
1411{
1412    clearError();
1413
1414    const egl_display_ptr dp = validate_display(dpy);
1415    if (!dp) {
1416        return EGL_FALSE;
1417    }
1418
1419    SurfaceRef _s(dp.get(), surface);
1420    if (!_s.get()) {
1421        setError(EGL_BAD_SURFACE, EGL_FALSE);
1422        return EGL_FALSE;
1423    }
1424
1425    egl_surface_t const * const s = get_surface(surface);
1426    native_window_set_buffers_timestamp(s->win.get(), time);
1427
1428    return EGL_TRUE;
1429}
1430
1431// ----------------------------------------------------------------------------
1432// NVIDIA extensions
1433// ----------------------------------------------------------------------------
1434EGLuint64NV eglGetSystemTimeFrequencyNV()
1435{
1436    clearError();
1437
1438    if (egl_init_drivers() == EGL_FALSE) {
1439        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1440    }
1441
1442    EGLuint64NV ret = 0;
1443    egl_connection_t* const cnx = &gEGLImpl;
1444
1445    if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
1446        return cnx->egl.eglGetSystemTimeFrequencyNV();
1447    }
1448
1449    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1450}
1451
1452EGLuint64NV eglGetSystemTimeNV()
1453{
1454    clearError();
1455
1456    if (egl_init_drivers() == EGL_FALSE) {
1457        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1458    }
1459
1460    EGLuint64NV ret = 0;
1461    egl_connection_t* const cnx = &gEGLImpl;
1462
1463    if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
1464        return cnx->egl.eglGetSystemTimeNV();
1465    }
1466
1467    return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1468}
1469