OSDN Git Service

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