OSDN Git Service

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