Home | History | Annotate | Download | only in egl
      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 #include "eglDisplay.h"
     17 #include "HostConnection.h"
     18 #include "KeyedVectorUtils.h"
     19 
     20 #ifdef HOST_BUILD
     21 #include "android/base/files/PathUtils.cpp"
     22 #include "android/base/system/System.cpp"
     23 #endif
     24 
     25 #include <string>
     26 
     27 #include <dlfcn.h>
     28 
     29 static const int systemEGLVersionMajor = 1;
     30 static const int systemEGLVersionMinor = 4;
     31 static const char systemEGLVendor[] = "Google Android emulator";
     32 
     33 // list of extensions supported by this EGL implementation
     34 //  NOTE that each extension name should be suffixed with space
     35 static const char systemStaticEGLExtensions[] =
     36             "EGL_ANDROID_image_native_buffer "
     37             "EGL_KHR_fence_sync "
     38             "EGL_KHR_image_base "
     39             "EGL_KHR_gl_texture_2d_image ";
     40 
     41 // extensions to add dynamically depending on host-side support
     42 static const char kDynamicEGLExtNativeSync[] = "EGL_ANDROID_native_fence_sync ";
     43 static const char kDynamicEGLExtWaitSync[] = "EGL_KHR_wait_sync ";
     44 
     45 static void *s_gles_lib = NULL;
     46 static void *s_gles2_lib = NULL;
     47 
     48 // The following function will be called when we (libEGL)
     49 // gets unloaded
     50 // At this point we want to unload the gles libraries we
     51 // might have loaded during initialization
     52 static void __attribute__ ((destructor)) do_on_unload(void)
     53 {
     54     if (s_gles_lib) {
     55         dlclose(s_gles_lib);
     56     }
     57 
     58     if (s_gles2_lib) {
     59         dlclose(s_gles2_lib);
     60     }
     61 }
     62 
     63 eglDisplay::eglDisplay() :
     64     m_initialized(false),
     65     m_major(0),
     66     m_minor(0),
     67     m_hostRendererVersion(0),
     68     m_numConfigs(0),
     69     m_numConfigAttribs(0),
     70     m_attribs(),
     71     m_configs(NULL),
     72     m_gles_iface(NULL),
     73     m_gles2_iface(NULL),
     74     m_versionString(NULL),
     75     m_vendorString(NULL),
     76     m_extensionString(NULL)
     77 {
     78     pthread_mutex_init(&m_lock, NULL);
     79     pthread_mutex_init(&m_ctxLock, NULL);
     80     pthread_mutex_init(&m_surfaceLock, NULL);
     81 }
     82 
     83 eglDisplay::~eglDisplay()
     84 {
     85     terminate();
     86     pthread_mutex_destroy(&m_lock);
     87     pthread_mutex_destroy(&m_ctxLock);
     88     pthread_mutex_destroy(&m_surfaceLock);
     89 }
     90 
     91 
     92 
     93 bool eglDisplay::initialize(EGLClient_eglInterface *eglIface)
     94 {
     95     pthread_mutex_lock(&m_lock);
     96     if (!m_initialized) {
     97 
     98         //
     99         // load GLES client API
    100         //
    101         m_gles_iface = loadGLESClientAPI("libGLESv1_CM_emulation",
    102                                          eglIface,
    103                                          &s_gles_lib);
    104         if (!m_gles_iface) {
    105             pthread_mutex_unlock(&m_lock);
    106             ALOGE("Failed to load gles1 iface");
    107             return false;
    108         }
    109 
    110 #ifdef WITH_GLES2
    111         m_gles2_iface = loadGLESClientAPI("libGLESv2_emulation",
    112                                           eglIface,
    113                                           &s_gles2_lib);
    114         // Note that if loading gles2 failed, we can still run with no
    115         // GLES2 support, having GLES2 is not mandatory.
    116 #endif
    117 
    118         //
    119         // establish connection with the host
    120         //
    121         HostConnection *hcon = HostConnection::get();
    122         if (!hcon) {
    123             pthread_mutex_unlock(&m_lock);
    124             ALOGE("Failed to establish connection with the host\n");
    125             return false;
    126         }
    127         hcon->setGrallocOnly(false);
    128 
    129         //
    130         // get renderControl encoder instance
    131         //
    132         renderControl_encoder_context_t *rcEnc = hcon->rcEncoder();
    133         if (!rcEnc) {
    134             pthread_mutex_unlock(&m_lock);
    135             ALOGE("Failed to get renderControl encoder instance");
    136             return false;
    137         }
    138 
    139         //
    140         // Query host reneder and EGL version
    141         //
    142         m_hostRendererVersion = rcEnc->rcGetRendererVersion(rcEnc);
    143         EGLint status = rcEnc->rcGetEGLVersion(rcEnc, &m_major, &m_minor);
    144         if (status != EGL_TRUE) {
    145             // host EGL initialization failed !!
    146             pthread_mutex_unlock(&m_lock);
    147             return false;
    148         }
    149 
    150         //
    151         // Take minimum version beween what we support and what the host support
    152         //
    153         if (m_major > systemEGLVersionMajor) {
    154             m_major = systemEGLVersionMajor;
    155             m_minor = systemEGLVersionMinor;
    156         }
    157         else if (m_major == systemEGLVersionMajor &&
    158                  m_minor > systemEGLVersionMinor) {
    159             m_minor = systemEGLVersionMinor;
    160         }
    161 
    162         //
    163         // Query the host for the set of configs
    164         //
    165         m_numConfigs = rcEnc->rcGetNumConfigs(rcEnc, (uint32_t*)&m_numConfigAttribs);
    166         if (m_numConfigs <= 0 || m_numConfigAttribs <= 0) {
    167             // just sanity check - should never happen
    168             pthread_mutex_unlock(&m_lock);
    169             return false;
    170         }
    171 
    172         uint32_t nInts = m_numConfigAttribs * (m_numConfigs + 1);
    173         EGLint tmp_buf[nInts];
    174         m_configs = new EGLint[nInts-m_numConfigAttribs];
    175         if (!m_configs) {
    176             pthread_mutex_unlock(&m_lock);
    177             return false;
    178         }
    179 
    180         EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), (GLuint*)tmp_buf);
    181         if (n != m_numConfigs) {
    182             pthread_mutex_unlock(&m_lock);
    183             return false;
    184         }
    185 
    186         // Fill the attributes vector.
    187         // The first m_numConfigAttribs values of tmp_buf are the actual attributes enums.
    188         for (int i=0; i<m_numConfigAttribs; i++) {
    189             m_attribs[tmp_buf[i]] = i;
    190         }
    191 
    192         memcpy(m_configs, tmp_buf + m_numConfigAttribs,
    193                m_numConfigs*m_numConfigAttribs*sizeof(EGLint));
    194 
    195         m_initialized = true;
    196     }
    197     pthread_mutex_unlock(&m_lock);
    198 
    199     processConfigs();
    200 
    201     return true;
    202 }
    203 
    204 void eglDisplay::processConfigs()
    205 {
    206     for (intptr_t i=0; i<m_numConfigs; i++) {
    207         EGLConfig config = (EGLConfig)i;
    208         PixelFormat format;
    209         if (getConfigNativePixelFormat(config, &format)) {
    210             setConfigAttrib(config, EGL_NATIVE_VISUAL_ID, format);
    211         }
    212     }
    213 }
    214 
    215 void eglDisplay::terminate()
    216 {
    217     pthread_mutex_lock(&m_lock);
    218     if (m_initialized) {
    219         // Cannot use the for loop in the following code because
    220         // eglDestroyContext may erase elements.
    221         EGLContextSet::iterator ctxIte = m_contexts.begin();
    222         while (ctxIte != m_contexts.end()) {
    223             EGLContextSet::iterator ctxToDelete = ctxIte;
    224             ctxIte ++;
    225             eglDestroyContext(static_cast<EGLDisplay>(this), *ctxToDelete);
    226         }
    227         EGLSurfaceSet::iterator surfaceIte = m_surfaces.begin();
    228         while (surfaceIte != m_surfaces.end()) {
    229             EGLSurfaceSet::iterator surfaceToDelete = surfaceIte;
    230             surfaceIte ++;
    231             eglDestroySurface(static_cast<EGLDisplay>(this), *surfaceToDelete);
    232         }
    233         m_initialized = false;
    234         delete [] m_configs;
    235         m_configs = NULL;
    236 
    237         if (m_versionString) {
    238             free(m_versionString);
    239             m_versionString = NULL;
    240         }
    241         if (m_vendorString) {
    242             free(m_vendorString);
    243             m_vendorString = NULL;
    244         }
    245         if (m_extensionString) {
    246             free(m_extensionString);
    247             m_extensionString = NULL;
    248         }
    249     }
    250     pthread_mutex_unlock(&m_lock);
    251 }
    252 
    253 #ifdef __APPLE__
    254 #define LIBSUFFIX ".dylib"
    255 #else
    256 #ifdef _WIN32
    257 #define LIBSUFFIX ".dll"
    258 #else
    259 #define LIBSUFFIX ".so"
    260 #endif // !_WIN32 (linux)
    261 #endif // !__APPLE__
    262 
    263 #ifndef HOST_BUILD
    264 #if PLATFORM_SDK_VERSION >= 26
    265 #define PARTITION "/vendor"
    266 #else
    267 #define PARTITION "/system"
    268 #endif // !PLATFORM_SDK_VERSION >= 26
    269 #if __LP64__
    270 #define LIBDIR "/lib64/egl/"
    271 #else
    272 #define LIBDIR "/lib/egl/"
    273 #endif // !__LP64__
    274 #endif // !HOST_BUILD
    275 
    276 EGLClient_glesInterface *eglDisplay::loadGLESClientAPI(const char *basename,
    277                                                        EGLClient_eglInterface *eglIface,
    278                                                        void **libHandle)
    279 {
    280 #ifdef HOST_BUILD
    281     std::string baseDir =
    282         android::base::System::get()->getProgramDirectory();
    283     std::string path =
    284         android::base::pj(
    285             baseDir, "lib64", std::string(basename) + LIBSUFFIX);
    286     void *lib = dlopen(path.c_str(), RTLD_NOW);
    287 #else
    288     std::string path(PARTITION);
    289     path += LIBDIR;
    290     path += basename;
    291     path += LIBSUFFIX;
    292     void *lib = dlopen(path.c_str(), RTLD_NOW);
    293 #endif
    294 
    295     if (!lib) {
    296         ALOGE("Failed to dlopen %s", basename);
    297         return NULL;
    298     }
    299 
    300     init_emul_gles_t init_gles_func = (init_emul_gles_t)dlsym(lib,"init_emul_gles");
    301     if (!init_gles_func) {
    302         ALOGE("Failed to find init_emul_gles");
    303         dlclose((void*)lib);
    304         return NULL;
    305     }
    306 
    307     *libHandle = lib;
    308     return (*init_gles_func)(eglIface);
    309 }
    310 
    311 static char *queryHostEGLString(EGLint name)
    312 {
    313     HostConnection *hcon = HostConnection::get();
    314     if (hcon) {
    315         renderControl_encoder_context_t *rcEnc = hcon->rcEncoder();
    316         if (rcEnc) {
    317             int n = rcEnc->rcQueryEGLString(rcEnc, name, NULL, 0);
    318             if (n < 0) {
    319                 // allocate space for the string.
    320                 char *str = (char *)malloc(-n);
    321                 n = rcEnc->rcQueryEGLString(rcEnc, name, str, -n);
    322                 if (n > 0) {
    323                     return str;
    324                 }
    325 
    326                 free(str);
    327             }
    328         }
    329     }
    330 
    331     return NULL;
    332 }
    333 
    334 static bool findExtInList(const char* token, int tokenlen, const char* list)
    335 {
    336     const char* p = list;
    337     while (*p != '\0') {
    338         const char* q = strchr(p, ' ');
    339         if (q == NULL) {
    340             /* should not happen, list must be space-terminated */
    341             break;
    342         }
    343         if (tokenlen == (q - p) && !memcmp(token, p, tokenlen)) {
    344             return true;  /* found it */
    345         }
    346         p = q+1;
    347     }
    348     return false;  /* not found */
    349 }
    350 
    351 static char *buildExtensionString()
    352 {
    353     //Query host extension string
    354     char *hostExt = queryHostEGLString(EGL_EXTENSIONS);
    355     if (!hostExt || (hostExt[1] == '\0')) {
    356         // no extensions on host - only static extension list supported
    357         return strdup(systemStaticEGLExtensions);
    358     }
    359 
    360     int n = strlen(hostExt);
    361     if (n > 0) {
    362         char *initialEGLExts;
    363         char *finalEGLExts;
    364 
    365         HostConnection *hcon = HostConnection::get();
    366         // If we got here, we must have succeeded in queryHostEGLString
    367         // and we thus should have a valid connection
    368         assert(hcon);
    369 
    370         asprintf(&initialEGLExts,"%s%s", systemStaticEGLExtensions, hostExt);
    371 
    372         std::string dynamicEGLExtensions;
    373 
    374         if (hcon->rcEncoder()->hasNativeSync() &&
    375             !strstr(initialEGLExts, kDynamicEGLExtNativeSync)) {
    376             dynamicEGLExtensions += kDynamicEGLExtNativeSync;
    377 
    378             if (hcon->rcEncoder()->hasNativeSyncV3()) {
    379                 dynamicEGLExtensions += kDynamicEGLExtWaitSync;
    380             }
    381         }
    382 
    383         asprintf(&finalEGLExts, "%s%s", initialEGLExts, dynamicEGLExtensions.c_str());
    384 
    385         free((char*)hostExt);
    386         return finalEGLExts;
    387     }
    388     else {
    389         free((char*)hostExt);
    390         return strdup(systemStaticEGLExtensions);
    391     }
    392 }
    393 
    394 const char *eglDisplay::queryString(EGLint name)
    395 {
    396     if (name == EGL_CLIENT_APIS) {
    397         return "OpenGL_ES";
    398     }
    399     else if (name == EGL_VERSION) {
    400         pthread_mutex_lock(&m_lock);
    401         if (m_versionString) {
    402             pthread_mutex_unlock(&m_lock);
    403             return m_versionString;
    404         }
    405 
    406         // build version string
    407         asprintf(&m_versionString, "%d.%d", m_major, m_minor);
    408         pthread_mutex_unlock(&m_lock);
    409 
    410         return m_versionString;
    411     }
    412     else if (name == EGL_VENDOR) {
    413         pthread_mutex_lock(&m_lock);
    414         if (m_vendorString) {
    415             pthread_mutex_unlock(&m_lock);
    416             return m_vendorString;
    417         }
    418 
    419         // build vendor string
    420         const char *hostVendor = queryHostEGLString(EGL_VENDOR);
    421 
    422         if (hostVendor) {
    423             asprintf(&m_vendorString, "%s Host: %s",
    424                                      systemEGLVendor, hostVendor);
    425             free((char*)hostVendor);
    426         }
    427         else {
    428             m_vendorString = (char *)systemEGLVendor;
    429         }
    430         pthread_mutex_unlock(&m_lock);
    431 
    432         return m_vendorString;
    433     }
    434     else if (name == EGL_EXTENSIONS) {
    435         pthread_mutex_lock(&m_lock);
    436         if (m_extensionString) {
    437             pthread_mutex_unlock(&m_lock);
    438             return m_extensionString;
    439         }
    440 
    441         // build extension string
    442         m_extensionString = buildExtensionString();
    443         pthread_mutex_unlock(&m_lock);
    444 
    445         return m_extensionString;
    446     }
    447     else {
    448         ALOGE("[%s] Unknown name %d\n", __FUNCTION__, name);
    449         return NULL;
    450     }
    451 }
    452 
    453 /* To get the value of attribute <a> of config <c> use the following formula:
    454  * value = *(m_configs + (int)c*m_numConfigAttribs + a);
    455  */
    456 EGLBoolean eglDisplay::getAttribValue(EGLConfig config, EGLint attribIdx, EGLint * value)
    457 {
    458     if (attribIdx == ATTRIBUTE_NONE)
    459     {
    460         ALOGE("[%s] Bad attribute idx\n", __FUNCTION__);
    461         return EGL_FALSE;
    462     }
    463     *value = *(m_configs + (intptr_t)config*m_numConfigAttribs + attribIdx);
    464     return EGL_TRUE;
    465 }
    466 
    467 #define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339
    468 #define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A
    469 
    470 EGLBoolean eglDisplay::getConfigAttrib(EGLConfig config, EGLint attrib, EGLint * value)
    471 {
    472     if (attrib == EGL_FRAMEBUFFER_TARGET_ANDROID) {
    473         *value = EGL_TRUE;
    474         return EGL_TRUE;
    475     }
    476     if (attrib == EGL_COVERAGE_SAMPLES_NV ||
    477         attrib == EGL_COVERAGE_BUFFERS_NV) {
    478         *value = 0;
    479         return EGL_TRUE;
    480     }
    481     if (attrib == EGL_DEPTH_ENCODING_NV) {
    482         *value = EGL_DEPTH_ENCODING_NONE_NV;
    483         return EGL_TRUE;
    484     }
    485     if  (attrib == EGL_COLOR_COMPONENT_TYPE_EXT) {
    486         *value = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
    487         return EGL_TRUE;
    488     }
    489     //Though it seems that valueFor() is thread-safe, we don't take chanses
    490     pthread_mutex_lock(&m_lock);
    491     EGLBoolean ret =
    492         getAttribValue(
    493             config,
    494             findObjectOrDefault(
    495                 m_attribs, attrib, EGL_DONT_CARE),
    496             value);
    497     pthread_mutex_unlock(&m_lock);
    498     return ret;
    499 }
    500 
    501 void eglDisplay::dumpConfig(EGLConfig config)
    502 {
    503     EGLint value = 0;
    504     DBG("^^^^^^^^^^ dumpConfig %d ^^^^^^^^^^^^^^^^^^", (int)config);
    505     for (int i=0; i<m_numConfigAttribs; i++) {
    506         getAttribValue(config, i, &value);
    507         DBG("{%d}[%d] %d\n", (int)config, i, value);
    508     }
    509 }
    510 
    511 /* To set the value of attribute <a> of config <c> use the following formula:
    512  * *(m_configs + (int)c*m_numConfigAttribs + a) = value;
    513  */
    514 EGLBoolean eglDisplay::setAttribValue(EGLConfig config, EGLint attribIdx, EGLint value)
    515 {
    516     if (attribIdx == ATTRIBUTE_NONE)
    517     {
    518         ALOGE("[%s] Bad attribute idx\n", __FUNCTION__);
    519         return EGL_FALSE;
    520     }
    521     *(m_configs + (intptr_t)config*m_numConfigAttribs + attribIdx) = value;
    522     return EGL_TRUE;
    523 }
    524 
    525 EGLBoolean eglDisplay::setConfigAttrib(EGLConfig config, EGLint attrib, EGLint value)
    526 {
    527     //Though it seems that valueFor() is thread-safe, we don't take chanses
    528     pthread_mutex_lock(&m_lock);
    529     EGLBoolean ret =
    530         setAttribValue(
    531             config,
    532             findObjectOrDefault(
    533                 m_attribs,
    534                 attrib,
    535                 EGL_DONT_CARE),
    536             value);
    537     pthread_mutex_unlock(&m_lock);
    538     return ret;
    539 }
    540 
    541 
    542 EGLBoolean eglDisplay::getConfigNativePixelFormat(EGLConfig config, PixelFormat * format)
    543 {
    544     EGLint redSize, blueSize, greenSize, alphaSize;
    545 
    546     if (!(
    547             getAttribValue(
    548                 config,
    549                 findObjectOrDefault(m_attribs, EGL_RED_SIZE, EGL_DONT_CARE),
    550                 &redSize) &&
    551             getAttribValue(
    552                 config,
    553                 findObjectOrDefault(m_attribs, EGL_BLUE_SIZE, EGL_DONT_CARE),
    554                 &blueSize) &&
    555             getAttribValue(
    556                 config,
    557                 findObjectOrDefault(m_attribs, EGL_GREEN_SIZE, EGL_DONT_CARE),
    558                 &greenSize) &&
    559             getAttribValue(
    560                 config,
    561                 findObjectOrDefault(m_attribs, EGL_ALPHA_SIZE, EGL_DONT_CARE),
    562                 &alphaSize))) {
    563         ALOGE("Couldn't find value for one of the pixel format attributes");
    564         return EGL_FALSE;
    565     }
    566 
    567     //calculate the GL internal format
    568     if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==8)) *format = PIXEL_FORMAT_RGBA_8888; //XXX: BGR?
    569     else if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGBX_8888; //XXX or PIXEL_FORMAT_RGB_888
    570     else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGB_565;
    571     else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = PIXEL_FORMAT_RGBA_5551;
    572     else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = PIXEL_FORMAT_RGBA_4444;
    573     else {
    574         return EGL_FALSE;
    575     }
    576     return EGL_TRUE;
    577 }
    578 EGLBoolean eglDisplay::getConfigGLPixelFormat(EGLConfig config, GLenum * format)
    579 {
    580     EGLint redSize, blueSize, greenSize, alphaSize;
    581 
    582     if (!(
    583             getAttribValue(
    584                 config,
    585                 findObjectOrDefault(m_attribs, EGL_RED_SIZE, EGL_DONT_CARE),
    586                 &redSize) &&
    587             getAttribValue(
    588                 config,
    589                 findObjectOrDefault(m_attribs, EGL_BLUE_SIZE, EGL_DONT_CARE),
    590                 &blueSize) &&
    591             getAttribValue(
    592                 config,
    593                 findObjectOrDefault(m_attribs, EGL_GREEN_SIZE, EGL_DONT_CARE),
    594                 &greenSize) &&
    595             getAttribValue(
    596                 config,
    597                 findObjectOrDefault(m_attribs, EGL_ALPHA_SIZE, EGL_DONT_CARE),
    598                 &alphaSize))) {
    599         ALOGE("Couldn't find value for one of the pixel format attributes");
    600         return EGL_FALSE;
    601     }
    602 
    603     //calculate the GL internal format
    604     if ((redSize == greenSize) && (redSize == blueSize) &&
    605         ((redSize == 8) || (redSize == 16) || (redSize == 32)))
    606     {
    607         if (alphaSize == 0) *format = GL_RGB;
    608         else *format = GL_RGBA;
    609     }
    610     else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = GL_RGB565_OES;
    611     else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = GL_RGB5_A1_OES;
    612     else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = GL_RGBA4_OES;
    613     else return EGL_FALSE;
    614 
    615     return EGL_TRUE;
    616 }
    617 
    618 void eglDisplay::onCreateContext(EGLContext ctx) {
    619     pthread_mutex_lock(&m_ctxLock);
    620     m_contexts.insert(ctx);
    621     pthread_mutex_unlock(&m_ctxLock);
    622 }
    623 
    624 void eglDisplay::onCreateSurface(EGLSurface surface) {
    625     pthread_mutex_lock(&m_surfaceLock);
    626     m_surfaces.insert(surface);
    627     pthread_mutex_unlock(&m_surfaceLock);
    628 }
    629 
    630 void eglDisplay::onDestroyContext(EGLContext ctx) {
    631     pthread_mutex_lock(&m_ctxLock);
    632     m_contexts.erase(ctx);
    633     pthread_mutex_unlock(&m_ctxLock);
    634 }
    635 
    636 void eglDisplay::onDestroySurface(EGLSurface surface) {
    637     pthread_mutex_lock(&m_surfaceLock);
    638     m_surfaces.erase(surface);
    639     pthread_mutex_unlock(&m_surfaceLock);
    640 }
    641 
    642 bool eglDisplay::isContext(EGLContext ctx) {
    643     pthread_mutex_lock(&m_ctxLock);
    644     bool res = m_contexts.find(ctx) != m_contexts.end();
    645     pthread_mutex_unlock(&m_ctxLock);
    646     return res;
    647 }
    648 
    649 bool eglDisplay::isSurface(EGLSurface surface) {
    650     pthread_mutex_lock(&m_surfaceLock);
    651     bool res = m_surfaces.find(surface) != m_surfaces.end();
    652     pthread_mutex_unlock(&m_surfaceLock);
    653     return res;
    654 }
    655