OSDN Git Service

merge in klp-release history after reset to master
[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
504 // ----------------------------------------------------------------------------
505 // Contexts
506 // ----------------------------------------------------------------------------
507
508 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
509                             EGLContext share_list, const EGLint *attrib_list)
510 {
511     clearError();
512
513     egl_connection_t* cnx = NULL;
514     const egl_display_ptr dp = validate_display_connection(dpy, cnx);
515     if (dp) {
516         if (share_list != EGL_NO_CONTEXT) {
517             if (!ContextRef(dp.get(), share_list).get()) {
518                 return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
519             }
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
559 EGLBoolean 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
579 EGLBoolean 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 setError(EGL_BAD_CONTEXT, 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 (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
625             // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
626             return setError(EGL_BAD_MATCH, EGL_FALSE);
627         }
628         if (cur_c == NULL) {
629             // no current context
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         if (!_d.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
638         d = get_surface(draw);
639         impl_draw = d->surface;
640     }
641
642     // retrieve the underlying implementation's read EGLSurface
643     if (read != EGL_NO_SURFACE) {
644         if (!_r.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
645         r = get_surface(read);
646         impl_read = r->surface;
647     }
648
649
650     EGLBoolean result = dp->makeCurrent(c, cur_c,
651             draw, read, ctx,
652             impl_draw, impl_read, impl_ctx);
653
654     if (result == EGL_TRUE) {
655         if (c) {
656             setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
657             egl_tls_t::setContext(ctx);
658 #if EGL_TRACE
659             if (getEGLDebugLevel() > 0)
660                 GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
661 #endif
662             _c.acquire();
663             _r.acquire();
664             _d.acquire();
665         } else {
666             setGLHooksThreadSpecific(&gHooksNoContext);
667             egl_tls_t::setContext(EGL_NO_CONTEXT);
668         }
669     } else {
670         // this will ALOGE the error
671         result = setError(c->cnx->egl.eglGetError(), EGL_FALSE);
672     }
673     return result;
674 }
675
676
677 EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
678                             EGLint attribute, EGLint *value)
679 {
680     clearError();
681
682     const egl_display_ptr dp = validate_display(dpy);
683     if (!dp) return EGL_FALSE;
684
685     ContextRef _c(dp.get(), ctx);
686     if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
687
688     egl_context_t * const c = get_context(ctx);
689     return c->cnx->egl.eglQueryContext(
690             dp->disp.dpy, c->context, attribute, value);
691
692 }
693
694 EGLContext eglGetCurrentContext(void)
695 {
696     // could be called before eglInitialize(), but we wouldn't have a context
697     // then, and this function would correctly return EGL_NO_CONTEXT.
698
699     clearError();
700
701     EGLContext ctx = getContext();
702     return ctx;
703 }
704
705 EGLSurface eglGetCurrentSurface(EGLint readdraw)
706 {
707     // could be called before eglInitialize(), but we wouldn't have a context
708     // then, and this function would correctly return EGL_NO_SURFACE.
709
710     clearError();
711
712     EGLContext ctx = getContext();
713     if (ctx) {
714         egl_context_t const * const c = get_context(ctx);
715         if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
716         switch (readdraw) {
717             case EGL_READ: return c->read;
718             case EGL_DRAW: return c->draw;
719             default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
720         }
721     }
722     return EGL_NO_SURFACE;
723 }
724
725 EGLDisplay eglGetCurrentDisplay(void)
726 {
727     // could be called before eglInitialize(), but we wouldn't have a context
728     // then, and this function would correctly return EGL_NO_DISPLAY.
729
730     clearError();
731
732     EGLContext ctx = getContext();
733     if (ctx) {
734         egl_context_t const * const c = get_context(ctx);
735         if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
736         return c->dpy;
737     }
738     return EGL_NO_DISPLAY;
739 }
740
741 EGLBoolean eglWaitGL(void)
742 {
743     clearError();
744
745     egl_connection_t* const cnx = &gEGLImpl;
746     if (!cnx->dso)
747         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
748
749     return cnx->egl.eglWaitGL();
750 }
751
752 EGLBoolean eglWaitNative(EGLint engine)
753 {
754     clearError();
755
756     egl_connection_t* const cnx = &gEGLImpl;
757     if (!cnx->dso)
758         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
759
760     return cnx->egl.eglWaitNative(engine);
761 }
762
763 EGLint eglGetError(void)
764 {
765     EGLint err = EGL_SUCCESS;
766     egl_connection_t* const cnx = &gEGLImpl;
767     if (cnx->dso) {
768         err = cnx->egl.eglGetError();
769     }
770     if (err == EGL_SUCCESS) {
771         err = egl_tls_t::getError();
772     }
773     return err;
774 }
775
776 static __eglMustCastToProperFunctionPointerType findBuiltinGLWrapper(
777         const char* procname) {
778     const egl_connection_t* cnx = &gEGLImpl;
779     void* proc = NULL;
780
781     proc = dlsym(cnx->libGles2, procname);
782     if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
783
784     proc = dlsym(cnx->libGles1, procname);
785     if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
786
787     return NULL;
788 }
789
790 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
791 {
792     // eglGetProcAddress() could be the very first function called
793     // in which case we must make sure we've initialized ourselves, this
794     // happens the first time egl_get_display() is called.
795
796     clearError();
797
798     if (egl_init_drivers() == EGL_FALSE) {
799         setError(EGL_BAD_PARAMETER, NULL);
800         return  NULL;
801     }
802
803     if (FILTER_EXTENSIONS(procname)) {
804         return NULL;
805     }
806
807     __eglMustCastToProperFunctionPointerType addr;
808     addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap));
809     if (addr) return addr;
810
811     addr = findBuiltinGLWrapper(procname);
812     if (addr) return addr;
813
814     // this protects accesses to sGLExtentionMap and sGLExtentionSlot
815     pthread_mutex_lock(&sExtensionMapMutex);
816
817         /*
818          * Since eglGetProcAddress() is not associated to anything, it needs
819          * to return a function pointer that "works" regardless of what
820          * the current context is.
821          *
822          * For this reason, we return a "forwarder", a small stub that takes
823          * care of calling the function associated with the context
824          * currently bound.
825          *
826          * We first look for extensions we've already resolved, if we're seeing
827          * this extension for the first time, we go through all our
828          * implementations and call eglGetProcAddress() and record the
829          * result in the appropriate implementation hooks and return the
830          * address of the forwarder corresponding to that hook set.
831          *
832          */
833
834         const String8 name(procname);
835         addr = sGLExtentionMap.valueFor(name);
836         const int slot = sGLExtentionSlot;
837
838         ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
839                 "no more slots for eglGetProcAddress(\"%s\")",
840                 procname);
841
842 #if EGL_TRACE
843         gl_hooks_t *debugHooks = GLTrace_getGLHooks();
844 #endif
845
846         if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
847             bool found = false;
848
849             egl_connection_t* const cnx = &gEGLImpl;
850             if (cnx->dso && cnx->egl.eglGetProcAddress) {
851                 // Extensions are independent of the bound context
852                 addr =
853                 cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
854                 cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
855 #if EGL_TRACE
856                 debugHooks->ext.extensions[slot] =
857                 gHooksTrace.ext.extensions[slot] =
858 #endif
859                         cnx->egl.eglGetProcAddress(procname);
860                 if (addr) found = true;
861             }
862
863             if (found) {
864                 addr = gExtensionForwarders[slot];
865                 sGLExtentionMap.add(name, addr);
866                 sGLExtentionSlot++;
867             }
868         }
869
870     pthread_mutex_unlock(&sExtensionMapMutex);
871     return addr;
872 }
873
874 class FrameCompletionThread : public Thread {
875 public:
876
877     static void queueSync(EGLSyncKHR sync) {
878         static sp<FrameCompletionThread> thread(new FrameCompletionThread);
879         static bool running = false;
880         if (!running) {
881             thread->run("GPUFrameCompletion");
882             running = true;
883         }
884         {
885             Mutex::Autolock lock(thread->mMutex);
886             ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d",
887                     thread->mFramesQueued).string());
888             thread->mQueue.push_back(sync);
889             thread->mCondition.signal();
890             thread->mFramesQueued++;
891             ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size());
892         }
893     }
894
895 private:
896     FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {}
897
898     virtual bool threadLoop() {
899         EGLSyncKHR sync;
900         uint32_t frameNum;
901         {
902             Mutex::Autolock lock(mMutex);
903             while (mQueue.isEmpty()) {
904                 mCondition.wait(mMutex);
905             }
906             sync = mQueue[0];
907             frameNum = mFramesCompleted;
908         }
909         EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
910         {
911             ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d",
912                     frameNum).string());
913             EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
914             if (result == EGL_FALSE) {
915                 ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError());
916             } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
917                 ALOGE("FrameCompletion: timeout waiting for fence");
918             }
919             eglDestroySyncKHR(dpy, sync);
920         }
921         {
922             Mutex::Autolock lock(mMutex);
923             mQueue.removeAt(0);
924             mFramesCompleted++;
925             ATRACE_INT("GPU Frames Outstanding", mQueue.size());
926         }
927         return true;
928     }
929
930     uint32_t mFramesQueued;
931     uint32_t mFramesCompleted;
932     Vector<EGLSyncKHR> mQueue;
933     Condition mCondition;
934     Mutex mMutex;
935 };
936
937 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
938 {
939     ATRACE_CALL();
940     clearError();
941
942     const egl_display_ptr dp = validate_display(dpy);
943     if (!dp) return EGL_FALSE;
944
945     SurfaceRef _s(dp.get(), draw);
946     if (!_s.get())
947         return setError(EGL_BAD_SURFACE, EGL_FALSE);
948
949 #if EGL_TRACE
950     gl_hooks_t const *trace_hooks = getGLTraceThreadSpecific();
951     if (getEGLDebugLevel() > 0) {
952         if (trace_hooks == NULL) {
953             if (GLTrace_start() < 0) {
954                 ALOGE("Disabling Tracer for OpenGL ES");
955                 setEGLDebugLevel(0);
956             } else {
957                 // switch over to the trace version of hooks
958                 EGLContext ctx = egl_tls_t::getContext();
959                 egl_context_t * const c = get_context(ctx);
960                 if (c) {
961                     setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
962                     GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
963                 }
964             }
965         }
966
967         GLTrace_eglSwapBuffers(dpy, draw);
968     } else if (trace_hooks != NULL) {
969         // tracing is now disabled, so switch back to the non trace version
970         EGLContext ctx = egl_tls_t::getContext();
971         egl_context_t * const c = get_context(ctx);
972         if (c) setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
973         GLTrace_stop();
974     }
975 #endif
976
977     egl_surface_t const * const s = get_surface(draw);
978
979     if (CC_UNLIKELY(dp->traceGpuCompletion)) {
980         EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
981         if (sync != EGL_NO_SYNC_KHR) {
982             FrameCompletionThread::queueSync(sync);
983         }
984     }
985
986     if (CC_UNLIKELY(dp->finishOnSwap)) {
987         uint32_t pixel;
988         egl_context_t * const c = get_context( egl_tls_t::getContext() );
989         if (c) {
990             // glReadPixels() ensures that the frame is complete
991             s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1,
992                     GL_RGBA,GL_UNSIGNED_BYTE,&pixel);
993         }
994     }
995
996     return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
997 }
998
999 EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
1000                             NativePixmapType target)
1001 {
1002     clearError();
1003
1004     const egl_display_ptr dp = validate_display(dpy);
1005     if (!dp) return EGL_FALSE;
1006
1007     SurfaceRef _s(dp.get(), surface);
1008     if (!_s.get())
1009         return setError(EGL_BAD_SURFACE, EGL_FALSE);
1010
1011     egl_surface_t const * const s = get_surface(surface);
1012     return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
1013 }
1014
1015 const char* eglQueryString(EGLDisplay dpy, EGLint name)
1016 {
1017     clearError();
1018
1019     const egl_display_ptr dp = validate_display(dpy);
1020     if (!dp) return (const char *) NULL;
1021
1022     switch (name) {
1023         case EGL_VENDOR:
1024             return dp->getVendorString();
1025         case EGL_VERSION:
1026             return dp->getVersionString();
1027         case EGL_EXTENSIONS:
1028             return dp->getExtensionString();
1029         case EGL_CLIENT_APIS:
1030             return dp->getClientApiString();
1031     }
1032     return setError(EGL_BAD_PARAMETER, (const char *)0);
1033 }
1034
1035 EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
1036 {
1037     clearError();
1038
1039     const egl_display_ptr dp = validate_display(dpy);
1040     if (!dp) return (const char *) NULL;
1041
1042     switch (name) {
1043         case EGL_VENDOR:
1044             return dp->disp.queryString.vendor;
1045         case EGL_VERSION:
1046             return dp->disp.queryString.version;
1047         case EGL_EXTENSIONS:
1048             return dp->disp.queryString.extensions;
1049         case EGL_CLIENT_APIS:
1050             return dp->disp.queryString.clientApi;
1051     }
1052     return setError(EGL_BAD_PARAMETER, (const char *)0);
1053 }
1054
1055 // ----------------------------------------------------------------------------
1056 // EGL 1.1
1057 // ----------------------------------------------------------------------------
1058
1059 EGLBoolean eglSurfaceAttrib(
1060         EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1061 {
1062     clearError();
1063
1064     const egl_display_ptr dp = validate_display(dpy);
1065     if (!dp) return EGL_FALSE;
1066
1067     SurfaceRef _s(dp.get(), surface);
1068     if (!_s.get())
1069         return setError(EGL_BAD_SURFACE, EGL_FALSE);
1070
1071     egl_surface_t const * const s = get_surface(surface);
1072     if (s->cnx->egl.eglSurfaceAttrib) {
1073         return s->cnx->egl.eglSurfaceAttrib(
1074                 dp->disp.dpy, s->surface, attribute, value);
1075     }
1076     return setError(EGL_BAD_SURFACE, EGL_FALSE);
1077 }
1078
1079 EGLBoolean eglBindTexImage(
1080         EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1081 {
1082     clearError();
1083
1084     const egl_display_ptr dp = validate_display(dpy);
1085     if (!dp) return EGL_FALSE;
1086
1087     SurfaceRef _s(dp.get(), surface);
1088     if (!_s.get())
1089         return setError(EGL_BAD_SURFACE, EGL_FALSE);
1090
1091     egl_surface_t const * const s = get_surface(surface);
1092     if (s->cnx->egl.eglBindTexImage) {
1093         return s->cnx->egl.eglBindTexImage(
1094                 dp->disp.dpy, s->surface, buffer);
1095     }
1096     return setError(EGL_BAD_SURFACE, EGL_FALSE);
1097 }
1098
1099 EGLBoolean eglReleaseTexImage(
1100         EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1101 {
1102     clearError();
1103
1104     const egl_display_ptr dp = validate_display(dpy);
1105     if (!dp) return EGL_FALSE;
1106
1107     SurfaceRef _s(dp.get(), surface);
1108     if (!_s.get())
1109         return setError(EGL_BAD_SURFACE, EGL_FALSE);
1110
1111     egl_surface_t const * const s = get_surface(surface);
1112     if (s->cnx->egl.eglReleaseTexImage) {
1113         return s->cnx->egl.eglReleaseTexImage(
1114                 dp->disp.dpy, s->surface, buffer);
1115     }
1116     return setError(EGL_BAD_SURFACE, EGL_FALSE);
1117 }
1118
1119 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1120 {
1121     clearError();
1122
1123     const egl_display_ptr dp = validate_display(dpy);
1124     if (!dp) return EGL_FALSE;
1125
1126     EGLBoolean res = EGL_TRUE;
1127     egl_connection_t* const cnx = &gEGLImpl;
1128     if (cnx->dso && cnx->egl.eglSwapInterval) {
1129         res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
1130     }
1131
1132     return res;
1133 }
1134
1135
1136 // ----------------------------------------------------------------------------
1137 // EGL 1.2
1138 // ----------------------------------------------------------------------------
1139
1140 EGLBoolean eglWaitClient(void)
1141 {
1142     clearError();
1143
1144     egl_connection_t* const cnx = &gEGLImpl;
1145     if (!cnx->dso)
1146         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1147
1148     EGLBoolean res;
1149     if (cnx->egl.eglWaitClient) {
1150         res = cnx->egl.eglWaitClient();
1151     } else {
1152         res = cnx->egl.eglWaitGL();
1153     }
1154     return res;
1155 }
1156
1157 EGLBoolean eglBindAPI(EGLenum api)
1158 {
1159     clearError();
1160
1161     if (egl_init_drivers() == EGL_FALSE) {
1162         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1163     }
1164
1165     // bind this API on all EGLs
1166     EGLBoolean res = EGL_TRUE;
1167     egl_connection_t* const cnx = &gEGLImpl;
1168     if (cnx->dso && cnx->egl.eglBindAPI) {
1169         res = cnx->egl.eglBindAPI(api);
1170     }
1171     return res;
1172 }
1173
1174 EGLenum eglQueryAPI(void)
1175 {
1176     clearError();
1177
1178     if (egl_init_drivers() == EGL_FALSE) {
1179         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1180     }
1181
1182     egl_connection_t* const cnx = &gEGLImpl;
1183     if (cnx->dso && cnx->egl.eglQueryAPI) {
1184         return cnx->egl.eglQueryAPI();
1185     }
1186
1187     // or, it can only be OpenGL ES
1188     return EGL_OPENGL_ES_API;
1189 }
1190
1191 EGLBoolean eglReleaseThread(void)
1192 {
1193     clearError();
1194
1195 #if EGL_TRACE
1196     if (getEGLDebugLevel() > 0)
1197         GLTrace_eglReleaseThread();
1198 #endif
1199
1200     // If there is context bound to the thread, release it
1201     egl_display_t::loseCurrent(get_context(getContext()));
1202
1203     egl_connection_t* const cnx = &gEGLImpl;
1204     if (cnx->dso && cnx->egl.eglReleaseThread) {
1205         cnx->egl.eglReleaseThread();
1206     }
1207     egl_tls_t::clearTLS();
1208     return EGL_TRUE;
1209 }
1210
1211 EGLSurface eglCreatePbufferFromClientBuffer(
1212           EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1213           EGLConfig config, const EGLint *attrib_list)
1214 {
1215     clearError();
1216
1217     egl_connection_t* cnx = NULL;
1218     const egl_display_ptr dp = validate_display_connection(dpy, cnx);
1219     if (!dp) return EGL_FALSE;
1220     if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1221         return cnx->egl.eglCreatePbufferFromClientBuffer(
1222                 dp->disp.dpy, buftype, buffer, config, attrib_list);
1223     }
1224     return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1225 }
1226
1227 // ----------------------------------------------------------------------------
1228 // EGL_EGLEXT_VERSION 3
1229 // ----------------------------------------------------------------------------
1230
1231 EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1232         const EGLint *attrib_list)
1233 {
1234     clearError();
1235
1236     const egl_display_ptr dp = validate_display(dpy);
1237     if (!dp) return EGL_FALSE;
1238
1239     SurfaceRef _s(dp.get(), surface);
1240     if (!_s.get())
1241         return setError(EGL_BAD_SURFACE, EGL_FALSE);
1242
1243     egl_surface_t const * const s = get_surface(surface);
1244     if (s->cnx->egl.eglLockSurfaceKHR) {
1245         return s->cnx->egl.eglLockSurfaceKHR(
1246                 dp->disp.dpy, s->surface, attrib_list);
1247     }
1248     return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1249 }
1250
1251 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1252 {
1253     clearError();
1254
1255     const egl_display_ptr dp = validate_display(dpy);
1256     if (!dp) return EGL_FALSE;
1257
1258     SurfaceRef _s(dp.get(), surface);
1259     if (!_s.get())
1260         return setError(EGL_BAD_SURFACE, EGL_FALSE);
1261
1262     egl_surface_t const * const s = get_surface(surface);
1263     if (s->cnx->egl.eglUnlockSurfaceKHR) {
1264         return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
1265     }
1266     return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1267 }
1268
1269 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1270         EGLClientBuffer buffer, const EGLint *attrib_list)
1271 {
1272     clearError();
1273
1274     const egl_display_ptr dp = validate_display(dpy);
1275     if (!dp) return EGL_NO_IMAGE_KHR;
1276
1277     ContextRef _c(dp.get(), ctx);
1278     egl_context_t * const c = _c.get();
1279
1280     EGLImageKHR result = EGL_NO_IMAGE_KHR;
1281     egl_connection_t* const cnx = &gEGLImpl;
1282     if (cnx->dso && cnx->egl.eglCreateImageKHR) {
1283         result = cnx->egl.eglCreateImageKHR(
1284                 dp->disp.dpy,
1285                 c ? c->context : EGL_NO_CONTEXT,
1286                 target, buffer, attrib_list);
1287     }
1288     return result;
1289 }
1290
1291 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1292 {
1293     clearError();
1294
1295     const egl_display_ptr dp = validate_display(dpy);
1296     if (!dp) return EGL_FALSE;
1297
1298     EGLBoolean result = EGL_FALSE;
1299     egl_connection_t* const cnx = &gEGLImpl;
1300     if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
1301         result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
1302     }
1303     return result;
1304 }
1305
1306 // ----------------------------------------------------------------------------
1307 // EGL_EGLEXT_VERSION 5
1308 // ----------------------------------------------------------------------------
1309
1310
1311 EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1312 {
1313     clearError();
1314
1315     const egl_display_ptr dp = validate_display(dpy);
1316     if (!dp) return EGL_NO_SYNC_KHR;
1317
1318     EGLSyncKHR result = EGL_NO_SYNC_KHR;
1319     egl_connection_t* const cnx = &gEGLImpl;
1320     if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
1321         result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
1322     }
1323     return result;
1324 }
1325
1326 EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1327 {
1328     clearError();
1329
1330     const egl_display_ptr dp = validate_display(dpy);
1331     if (!dp) return EGL_FALSE;
1332
1333     EGLBoolean result = EGL_FALSE;
1334     egl_connection_t* const cnx = &gEGLImpl;
1335     if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
1336         result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
1337     }
1338     return result;
1339 }
1340
1341 EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
1342     clearError();
1343
1344     const egl_display_ptr dp = validate_display(dpy);
1345     if (!dp) return EGL_FALSE;
1346
1347     EGLBoolean result = EGL_FALSE;
1348     egl_connection_t* const cnx = &gEGLImpl;
1349     if (cnx->dso && cnx->egl.eglSignalSyncKHR) {
1350         result = cnx->egl.eglSignalSyncKHR(
1351                 dp->disp.dpy, sync, mode);
1352     }
1353     return result;
1354 }
1355
1356 EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
1357         EGLint flags, EGLTimeKHR timeout)
1358 {
1359     clearError();
1360
1361     const egl_display_ptr dp = validate_display(dpy);
1362     if (!dp) return EGL_FALSE;
1363
1364     EGLBoolean result = EGL_FALSE;
1365     egl_connection_t* const cnx = &gEGLImpl;
1366     if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
1367         result = cnx->egl.eglClientWaitSyncKHR(
1368                 dp->disp.dpy, sync, flags, timeout);
1369     }
1370     return result;
1371 }
1372
1373 EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
1374         EGLint attribute, EGLint *value)
1375 {
1376     clearError();
1377
1378     const egl_display_ptr dp = validate_display(dpy);
1379     if (!dp) return EGL_FALSE;
1380
1381     EGLBoolean result = EGL_FALSE;
1382     egl_connection_t* const cnx = &gEGLImpl;
1383     if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
1384         result = cnx->egl.eglGetSyncAttribKHR(
1385                 dp->disp.dpy, sync, attribute, value);
1386     }
1387     return result;
1388 }
1389
1390 // ----------------------------------------------------------------------------
1391 // EGL_EGLEXT_VERSION 15
1392 // ----------------------------------------------------------------------------
1393
1394 EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) {
1395     clearError();
1396     const egl_display_ptr dp = validate_display(dpy);
1397     if (!dp) return EGL_FALSE;
1398     EGLint result = EGL_FALSE;
1399     egl_connection_t* const cnx = &gEGLImpl;
1400     if (cnx->dso && cnx->egl.eglWaitSyncKHR) {
1401         result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags);
1402     }
1403     return result;
1404 }
1405
1406 // ----------------------------------------------------------------------------
1407 // ANDROID extensions
1408 // ----------------------------------------------------------------------------
1409
1410 EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync)
1411 {
1412     clearError();
1413
1414     const egl_display_ptr dp = validate_display(dpy);
1415     if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
1416
1417     EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
1418     egl_connection_t* const cnx = &gEGLImpl;
1419     if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) {
1420         result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync);
1421     }
1422     return result;
1423 }
1424
1425 EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface,
1426         EGLnsecsANDROID time)
1427 {
1428     clearError();
1429
1430     const egl_display_ptr dp = validate_display(dpy);
1431     if (!dp) {
1432         return EGL_FALSE;
1433     }
1434
1435     SurfaceRef _s(dp.get(), surface);
1436     if (!_s.get()) {
1437         setError(EGL_BAD_SURFACE, EGL_FALSE);
1438         return EGL_FALSE;
1439     }
1440
1441     egl_surface_t const * const s = get_surface(surface);
1442     native_window_set_buffers_timestamp(s->win.get(), time);
1443
1444     return EGL_TRUE;
1445 }
1446
1447 // ----------------------------------------------------------------------------
1448 // NVIDIA extensions
1449 // ----------------------------------------------------------------------------
1450 EGLuint64NV eglGetSystemTimeFrequencyNV()
1451 {
1452     clearError();
1453
1454     if (egl_init_drivers() == EGL_FALSE) {
1455         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1456     }
1457
1458     EGLuint64NV ret = 0;
1459     egl_connection_t* const cnx = &gEGLImpl;
1460
1461     if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
1462         return cnx->egl.eglGetSystemTimeFrequencyNV();
1463     }
1464
1465     return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1466 }
1467
1468 EGLuint64NV eglGetSystemTimeNV()
1469 {
1470     clearError();
1471
1472     if (egl_init_drivers() == EGL_FALSE) {
1473         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1474     }
1475
1476     EGLuint64NV ret = 0;
1477     egl_connection_t* const cnx = &gEGLImpl;
1478
1479     if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
1480         return cnx->egl.eglGetSystemTimeNV();
1481     }
1482
1483     return setErrorQuiet(EGL_BAD_DISPLAY, 0);
1484 }