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