OSDN Git Service

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