1e2e45665eb3e98f1762f1515da869dadba0902a
[iec.git] / src / type3_AndroidCloud / anbox-master / android / opengl / tests / gles_android_wrapper / egl.cpp
1 /*
2 * Copyright (C) 2011 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 //
18 // WARNING -------------------------- WARNING
19 // This code meant to be used for testing purposes only. It is not production
20 // level quality.
21 // Use on your own risk !!
22 //
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <dlfcn.h>
28 #include "egl_dispatch.h"
29 #include "egl_ftable.h"
30 #include <cutils/process_name.h>
31 #include <cutils/log.h>
32 #include "ServerConnection.h"
33 #include "ThreadInfo.h"
34 #include <pthread.h>
35 #include "gl_wrapper_context.h"
36 #include "gl2_wrapper_context.h"
37
38 #define GLES_EMUL_TARGETS_FILE "/system/etc/gles_emul.cfg"
39 // implementation libraries;
40 #define GLESv1_enc_LIB "/system/lib/libGLESv1_enc.so"
41 #define GLESv2_enc_LIB "/system/lib/libGLESv2_enc.so"
42 #define GLES_android_LIB "/system/lib/egl/libGLES_android.so"
43 // driver libraries;
44 #define GLESv1_DRIVER "/system/lib/egl/libGLESv1_CM_emul.so"
45 #define GLESv2_DRIVER "/system/lib/egl/libGLESv2_emul.so"
46
47
48 static struct egl_dispatch *s_dispatch = NULL;
49 pthread_once_t dispatchTablesInitialized = PTHREAD_ONCE_INIT;
50
51 static bool s_needEncode = false;
52
53 static gl_wrapper_context_t *g_gl_dispatch = NULL;
54 static gl2_wrapper_context_t *g_gl2_dispatch = NULL;
55
56 template <class T>
57 int initApi(const char *driverLibName, const char *implLibName, T **dispatchTable, T *(*accessor)())
58 {
59     void *driverLib = dlopen(driverLibName, RTLD_NOW | RTLD_LOCAL);
60     if (driverLib == NULL) {
61         ALOGE("failed to load %s : %s\n", driverLibName, dlerror());
62         return -1;
63     }
64
65     typedef T *(*createFcn_t)(void *, T *(*accessor)());
66     createFcn_t createFcn;
67     createFcn = (createFcn_t) dlsym(driverLib, "createFromLib");
68     if (createFcn == NULL) {
69         ALOGE("failed to load createFromLib constructor function\n");
70         return -1;
71     }
72
73     void *implLib = dlopen(implLibName, RTLD_NOW | RTLD_LOCAL);
74     if (implLib == NULL) {
75         ALOGE("couldn't open %s", implLibName);
76         return -2;
77     }
78     *dispatchTable = createFcn(implLib, accessor);
79     if (*dispatchTable == NULL) {
80         return -3;
81     }
82
83     // XXX - we do close the impl library since it doesn't have data, as far as we concern.
84     dlclose(implLib);
85
86     // XXX - we do not dlclose the driver library, so its not initialized when
87     // later loaded by android - is this required?
88     ALOGD("loading %s into %s complete\n", implLibName, driverLibName);
89     return 0;
90
91 }
92
93 static gl_wrapper_context_t *getGLContext()
94 {
95     return g_gl_dispatch;
96 }
97
98 static gl2_wrapper_context_t *getGL2Context()
99 {
100     return g_gl2_dispatch;
101 }
102
103 const char *getProcName()
104 {
105     static const char *procname = NULL;
106
107     if (procname == NULL) {
108         const char *str = get_process_name();
109         if (strcmp(str, "unknown") != 0) {
110             procname = str;
111         } else {
112             // we need to obtain our process name from the command line;
113             FILE *fp = fopen("/proc/self/cmdline", "rt");
114             if (fp == NULL) {
115                 ALOGE("couldn't open /proc/self/cmdline\n");
116                 return NULL;
117             }
118
119             char line[1000];
120             if (fgets(line, sizeof(line), fp) == NULL) {
121                 ALOGE("couldn't read the self cmdline from \n");
122                 fclose(fp);
123                 return NULL;
124             }
125             fclose(fp);
126
127             if (line[0] == '\0') {
128                 ALOGE("cmdline is empty\n");
129                 return NULL;
130             }
131
132             //obtain the basename;
133             line[sizeof(line) - 1] = '\0';
134             char *p = line;
135             while (*p != '\0' &&
136                    *p != '\t' &&
137                    *p != ' ' &&
138                    *p != '\n') {
139                 p++;
140             }
141
142             *p = '\0'; p--;
143             while (p > line && *p != '/') p--;
144             if (*p == '/') p++;
145             procname = strdup(p);
146         }
147     }
148
149     return procname;
150 }
151
152
153
154 bool isNeedEncode()
155 {
156     const char *procname = getProcName();
157     if (procname == NULL) return false;
158     ALOGD("isNeedEncode? for %s\n", procname);
159     // check on our whitelist
160     FILE *fp = fopen(GLES_EMUL_TARGETS_FILE, "rt");
161     if (fp == NULL) {
162         ALOGE("couldn't open %s\n", GLES_EMUL_TARGETS_FILE);
163         return false;
164     }
165
166     char line[100];
167     bool found = false;
168     size_t  procnameLen = strlen(procname);
169
170     while (fgets(line, sizeof(line), fp) != NULL) {
171         if (strlen(line) >= procnameLen &&
172             !strncmp(procname, line, procnameLen)) {
173             char c = line[procnameLen];
174             if (c == '\0' || c == ' ' || c == '\t' || c == '\n') {
175                 found = true;
176                 ALOGD("should use encoder for %s\n", procname);
177                 break;
178             }
179         }
180     }
181     fclose(fp);
182     return found;
183 }
184
185 void initDispatchTables()
186 {
187     //
188     // Load our back-end implementation of EGL/GLES
189     //
190     ALOGD("Loading egl dispatch for %s\n", getProcName());
191
192     void *gles_android = dlopen("/system/lib/egl/libGLES_android.so", RTLD_NOW | RTLD_LOCAL);
193     if (!gles_android) {
194         fprintf(stderr,"FATAL ERROR: Could not load libGLES_android lib\n");
195         exit(-1);
196     }
197
198     //
199     // Load back-end EGL implementation library
200     //
201     s_dispatch = create_egl_dispatch( gles_android );
202     if (!s_dispatch) {
203         fprintf(stderr,"FATAL ERROR: Could not create egl dispatch\n");
204         exit(-1);
205     }
206
207     //
208     // initialize gles
209     //
210     s_needEncode = isNeedEncode();
211     void *gles_encoder = NULL;
212     if (s_needEncode) {
213         // initialize a connection to the server, and the GLESv1/v2 encoders;
214         ServerConnection * connection = ServerConnection::s_getServerConnection();
215         if (connection == NULL) {
216             ALOGE("couldn't create server connection\n");
217             s_needEncode = false;
218         }
219     }
220
221     // init dispatch tabels for GLESv1 & GLESv2
222     if (s_needEncode) {
223         // XXX - we do not check the retrun value because there isn't much we can do here on failure.
224
225         if (initApi<gl_wrapper_context_t>(GLESv1_DRIVER, GLESv1_enc_LIB, &g_gl_dispatch, getGLContext) < 0) {
226             // fallback to android on faluire
227             s_needEncode = false;
228         } else {
229             initApi<gl2_wrapper_context_t>(GLESv2_DRIVER, GLESv2_enc_LIB, &g_gl2_dispatch, getGL2Context);
230         }
231     }
232
233     if (!s_needEncode) {
234         ALOGD("Initializing native opengl for %s\n", getProcName());
235         initApi<gl_wrapper_context_t>(GLESv1_DRIVER, GLES_android_LIB, &g_gl_dispatch, getGLContext);
236         // try to initialize gl2 from GLES, though its probably going to fail
237         initApi<gl2_wrapper_context_t>(GLESv2_DRIVER, GLES_android_LIB, &g_gl2_dispatch, getGL2Context);
238     }
239 }
240
241 static struct egl_dispatch *getDispatch()
242 {
243     pthread_once(&dispatchTablesInitialized, initDispatchTables);
244     return s_dispatch;
245 }
246
247 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
248 {
249
250     // search in EGL function table
251     for (int i=0; i<egl_num_funcs; i++) {
252         if (!strcmp(egl_funcs_by_name[i].name, procname)) {
253             return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc;
254         }
255     }
256
257     // we do not support eglGetProcAddress for GLESv1 & GLESv2. The loader
258     // should be able to find this function through dynamic loading.
259     return NULL;
260 }
261
262 ////////////////  Path through functions //////////
263
264 EGLint eglGetError()
265 {
266     return getDispatch()->eglGetError();
267 }
268
269 EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
270 {
271     return getDispatch()->eglGetDisplay(display_id);
272 }
273
274 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
275 {
276     return getDispatch()->eglInitialize(dpy, major, minor);
277 }
278
279 EGLBoolean eglTerminate(EGLDisplay dpy)
280 {
281     return getDispatch()->eglTerminate(dpy);
282 }
283
284 const char* eglQueryString(EGLDisplay dpy, EGLint name)
285 {
286     return getDispatch()->eglQueryString(dpy, name);
287 }
288
289 EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
290 {
291     return getDispatch()->eglGetConfigs(dpy, configs, config_size, num_config);
292 }
293
294 static EGLint * filter_es2_bit(const EGLint *attrib_list, bool *isES2)
295 {
296     if (attrib_list == NULL) {
297         if (isES2 != NULL) *isES2 = false;
298         return NULL;
299     }
300
301     EGLint *attribs = NULL;
302     int nAttribs = 0;
303     while(attrib_list[nAttribs] != EGL_NONE) nAttribs++;
304     nAttribs++;
305
306     attribs = new EGLint[nAttribs];
307     memcpy(attribs, attrib_list, nAttribs * sizeof(EGLint));
308     if (isES2 != NULL) *isES2 = false;
309
310     // scan the attribute list for ES2 request and replace with ES1.
311     for (int i = 0; i < nAttribs; i++) {
312         if (attribs[i] == EGL_RENDERABLE_TYPE) {
313             if (attribs[i + 1] & EGL_OPENGL_ES2_BIT) {
314                 attribs[i + 1] &= ~EGL_OPENGL_ES2_BIT;
315                 attribs[i + 1] |= EGL_OPENGL_ES_BIT;
316                 ALOGD("removing ES2 bit 0x%x\n", attribs[i + 1]);
317                 if (isES2 != NULL) *isES2 = true;
318             }
319         }
320     }
321     return attribs;
322 }
323
324 EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
325 {
326     EGLBoolean res;
327     if (s_needEncode) {
328         EGLint *attribs = filter_es2_bit(attrib_list, NULL);
329         res =  getDispatch()->eglChooseConfig(dpy,
330                                               attribs,
331                                               configs,
332                                               config_size,
333                                               num_config);
334         ALOGD("eglChooseConfig: %d configs found\n", *num_config);
335         if (*num_config == 0 && attribs != NULL) {
336             ALOGD("requested attributes:\n");
337             for (int i = 0; attribs[i] != EGL_NONE; i++) {
338                 ALOGD("%d: 0x%x\n", i, attribs[i]);
339             }
340         }
341
342         delete attribs;
343     } else {
344         res = getDispatch()->eglChooseConfig(dpy, attrib_list, configs, config_size, num_config);
345     }
346     return res;
347 }
348
349 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
350 {
351     if (s_needEncode && attribute == EGL_RENDERABLE_TYPE) {
352         *value = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT;
353         return EGL_TRUE;
354     } else {
355         return getDispatch()->eglGetConfigAttrib(dpy, config, attribute, value);
356     }
357 }
358
359 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
360 {
361     EGLSurface surface =  getDispatch()->eglCreateWindowSurface(dpy, config, win, attrib_list);
362     if (surface != EGL_NO_SURFACE) {
363         ServerConnection *server;
364         if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
365             server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface);
366         }
367     }
368     return surface;
369 }
370
371 EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
372 {
373     EGLSurface surface =  getDispatch()->eglCreatePbufferSurface(dpy, config, attrib_list);
374     if (surface != EGL_NO_SURFACE) {
375         ServerConnection *server;
376         if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
377             server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface);
378         }
379     }
380     return surface;
381 }
382
383 EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
384 {
385     EGLSurface surface =  getDispatch()->eglCreatePixmapSurface(dpy, config, pixmap, attrib_list);
386     if (surface != EGL_NO_SURFACE) {
387         ServerConnection *server;
388         if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
389             server->utEnc()->createSurface(server->utEnc(), getpid(), (uint32_t)surface);
390         }
391     }
392     return surface;
393 }
394
395 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
396 {
397     EGLBoolean res =  getDispatch()->eglDestroySurface(dpy, surface);
398     if (res && surface != EGL_NO_SURFACE) {
399         ServerConnection *server;
400         if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
401             server->utEnc()->destroySurface(server->utEnc(), getpid(), (uint32_t)surface);
402         }
403     }
404     return res;
405 }
406
407 EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
408 {
409     EGLBoolean res = getDispatch()->eglQuerySurface(dpy, surface, attribute, value);
410     if (res && attribute == EGL_RENDERABLE_TYPE) {
411         *value |= EGL_OPENGL_ES2_BIT;
412     }
413     return res;
414 }
415
416 EGLBoolean eglBindAPI(EGLenum api)
417 {
418     return getDispatch()->eglBindAPI(api);
419 }
420
421 EGLenum eglQueryAPI()
422 {
423     return getDispatch()->eglQueryAPI();
424 }
425
426 EGLBoolean eglWaitClient()
427 {
428     return getDispatch()->eglWaitClient();
429 }
430
431 EGLBoolean eglReleaseThread()
432 {
433     return getDispatch()->eglReleaseThread();
434 }
435
436 EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
437 {
438     return getDispatch()->eglCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list);
439 }
440
441 EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
442 {
443     return getDispatch()->eglSurfaceAttrib(dpy, surface, attribute, value);
444 }
445
446 EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
447 {
448     return getDispatch()->eglBindTexImage(dpy, surface, buffer);
449 }
450
451 EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
452 {
453     return getDispatch()->eglReleaseTexImage(dpy, surface, buffer);
454 }
455
456 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
457 {
458     return getDispatch()->eglSwapInterval(dpy, interval);
459 }
460
461 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
462 {
463
464     EGLContext share = share_context;
465     if (share) share = ((EGLWrapperContext *)share_context)->aglContext;
466
467     // check if are ES2, and convert it to ES1.
468     int nAttribs = 0;
469     if (attrib_list != NULL) {
470         while(attrib_list[nAttribs] != EGL_NONE) {
471             nAttribs++;
472         }
473         nAttribs++;
474     }
475
476     EGLint *attrib = NULL;
477     if (nAttribs > 0) {
478         attrib = new EGLint[nAttribs];
479         memcpy(attrib, attrib_list, nAttribs * sizeof(EGLint));
480     }
481
482     int  version  = 1;
483     for (int i = 0; i < nAttribs; i++) {
484         if (attrib[i] == EGL_CONTEXT_CLIENT_VERSION &&
485             attrib[i + 1] == 2) {
486             version = 2;
487             attrib[i + 1] = 1; // replace to version 1
488         }
489     }
490
491     EGLContext ctx =  getDispatch()->eglCreateContext(dpy, config, share, attrib);
492     delete attrib;
493     EGLWrapperContext *wctx = new EGLWrapperContext(ctx, version);
494     if (ctx != EGL_NO_CONTEXT) {
495         ServerConnection *server;
496         if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
497             wctx->clientState = new GLClientState();
498             server->utEnc()->createContext(server->utEnc(), getpid(),
499                                            (uint32_t)wctx,
500                                            (uint32_t)(share_context == EGL_NO_CONTEXT ? 0 : share_context), wctx->version);
501         }
502     }
503     return (EGLContext)wctx;
504 }
505
506 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
507 {
508     EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
509     EGLBoolean res = EGL_FALSE;
510
511     if (ctx && ctx != EGL_NO_CONTEXT) {
512         res = getDispatch()->eglDestroyContext(dpy, wctx->aglContext);
513         if (res) {
514             EGLThreadInfo *ti = getEGLThreadInfo();
515             ServerConnection *server;
516             if (s_needEncode && (server = ServerConnection::s_getServerConnection())) {
517                 server->utEnc()->destroyContext(ti->serverConn->utEnc(), getpid(), (uint32_t)ctx);
518             }
519             if (ti->currentContext == wctx) ti->currentContext = NULL;
520             delete wctx;
521         }
522     }
523
524     return res;
525 }
526
527 EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
528 {
529     EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
530     EGLContext aglContext = (ctx == EGL_NO_CONTEXT ? EGL_NO_CONTEXT : wctx->aglContext);
531     EGLThreadInfo *ti = getEGLThreadInfo();
532     EGLBoolean res = getDispatch()->eglMakeCurrent(dpy, draw, read, aglContext);
533     if (res ) {
534         // NOTE - we do get a pointer to the server connection, (rather then using ti->serverConn)
535         // for cases that this is the first egl call of the current thread.
536
537         ServerConnection *server;
538         if (s_needEncode && (server = ServerConnection::s_getServerConnection())) {
539             server->utEnc()->makeCurrentContext(server->utEnc(), getpid(),
540                                                 (uint32_t) (draw == EGL_NO_SURFACE ? 0 : draw),
541                                                 (uint32_t) (read == EGL_NO_SURFACE ? 0 : read),
542                                                 (uint32_t) (ctx == EGL_NO_CONTEXT ? 0 : ctx));
543             server->glEncoder()->setClientState( wctx ? wctx->clientState : NULL );
544             server->gl2Encoder()->setClientState( wctx ? wctx->clientState : NULL );
545         }
546
547         // set current context in our thread info
548         ti->currentContext = wctx;
549     }
550     return res;
551
552 }
553
554 EGLContext eglGetCurrentContext()
555 {
556     EGLThreadInfo *ti = getEGLThreadInfo();
557     return (ti->currentContext ? ti->currentContext : EGL_NO_CONTEXT);
558 }
559
560 EGLSurface eglGetCurrentSurface(EGLint readdraw)
561 {
562     return getDispatch()->eglGetCurrentSurface(readdraw);
563 }
564
565 EGLDisplay eglGetCurrentDisplay()
566 {
567     return getDispatch()->eglGetCurrentDisplay();
568 }
569
570 EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
571 {
572     EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
573     if (wctx) {
574         if (attribute == EGL_CONTEXT_CLIENT_VERSION) {
575             *value = wctx->version;
576             return EGL_TRUE;
577         } else {
578             return getDispatch()->eglQueryContext(dpy, wctx->aglContext, attribute, value);
579         }
580     }
581     else {
582         return EGL_BAD_CONTEXT;
583     }
584 }
585
586 EGLBoolean eglWaitGL()
587 {
588     return getDispatch()->eglWaitGL();
589 }
590
591 EGLBoolean eglWaitNative(EGLint engine)
592 {
593     return getDispatch()->eglWaitNative(engine);
594 }
595
596 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
597 {
598     ServerConnection *server;
599     if (s_needEncode && (server = ServerConnection::s_getServerConnection()) != NULL) {
600         server->utEnc()->swapBuffers(server->utEnc(), getpid(), (uint32_t)surface);
601         server->glEncoder()->flush();
602         server->gl2Encoder()->flush();
603         return 1;
604     }
605     return getDispatch()->eglSwapBuffers(dpy, surface);
606 }
607
608 EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
609 {
610     return getDispatch()->eglCopyBuffers(dpy, surface, target);
611 }
612
613 EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list)
614 {
615     return getDispatch()->eglLockSurfaceKHR(display, surface, attrib_list);
616 }
617
618 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface)
619 {
620     return getDispatch()->eglUnlockSurfaceKHR(display, surface);
621 }
622
623 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
624 {
625     EGLWrapperContext *wctx = (EGLWrapperContext *)ctx;
626     EGLContext aglContext = (wctx ? wctx->aglContext : EGL_NO_CONTEXT);
627     return getDispatch()->eglCreateImageKHR(dpy, aglContext, target, buffer, attrib_list);
628 }
629
630 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
631 {
632     return getDispatch()->eglDestroyImageKHR(dpy, image);
633 }
634
635 EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
636 {
637     return getDispatch()->eglCreateSyncKHR(dpy, type, attrib_list);
638 }
639
640 EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
641 {
642     return getDispatch()->eglDestroySyncKHR(dpy, sync);
643 }
644
645 EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
646 {
647     return getDispatch()->eglClientWaitSyncKHR(dpy, sync, flags, timeout);
648 }
649
650 EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode)
651 {
652     return getDispatch()->eglSignalSyncKHR(dpy, sync, mode);
653 }
654
655 EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
656 {
657     return getDispatch()->eglGetSyncAttribKHR(dpy, sync, attribute, value);
658 }
659
660 EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height)
661 {
662     return getDispatch()->eglSetSwapRectangleANDROID(dpy, draw, left, top, width, height);
663 }