OSDN Git Service

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