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
do_on_unload(void)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 
eglDisplay()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 
~eglDisplay()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 
initialize(EGLClient_eglInterface * eglIface)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         uint32_t configCount = nInts - m_numConfigAttribs;
175 
176         m_configs = new EGLint[nInts-m_numConfigAttribs];
177 
178         if (!m_configs) {
179             pthread_mutex_unlock(&m_lock);
180             return false;
181         }
182 
183         EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), (GLuint*)tmp_buf);
184         if (n != m_numConfigs) {
185             pthread_mutex_unlock(&m_lock);
186             return false;
187         }
188 
189         // Fill the attributes vector.
190         // The first m_numConfigAttribs values of tmp_buf are the actual attributes enums.
191         for (int i=0; i<m_numConfigAttribs; i++) {
192             m_attribs[tmp_buf[i]] = i;
193         }
194 
195         memcpy(m_configs, tmp_buf + m_numConfigAttribs,
196                m_numConfigs*m_numConfigAttribs*sizeof(EGLint));
197 
198         m_initialized = true;
199     }
200     pthread_mutex_unlock(&m_lock);
201 
202     processConfigs();
203 
204     return true;
205 }
206 
processConfigs()207 void eglDisplay::processConfigs()
208 {
209     for (intptr_t i=0; i<m_numConfigs; i++) {
210         EGLConfig config = getConfigAtIndex(i);
211         PixelFormat format;
212         if (getConfigNativePixelFormat(config, &format)) {
213             setConfigAttrib(config, EGL_NATIVE_VISUAL_ID, format);
214         }
215     }
216 }
217 
terminate()218 void eglDisplay::terminate()
219 {
220     pthread_mutex_lock(&m_lock);
221     if (m_initialized) {
222         // Cannot use the for loop in the following code because
223         // eglDestroyContext may erase elements.
224         EGLContextSet::iterator ctxIte = m_contexts.begin();
225         while (ctxIte != m_contexts.end()) {
226             EGLContextSet::iterator ctxToDelete = ctxIte;
227             ctxIte ++;
228             eglDestroyContext(static_cast<EGLDisplay>(this), *ctxToDelete);
229         }
230         EGLSurfaceSet::iterator surfaceIte = m_surfaces.begin();
231         while (surfaceIte != m_surfaces.end()) {
232             EGLSurfaceSet::iterator surfaceToDelete = surfaceIte;
233             surfaceIte ++;
234             eglDestroySurface(static_cast<EGLDisplay>(this), *surfaceToDelete);
235         }
236         m_initialized = false;
237         delete [] m_configs;
238         m_configs = NULL;
239 
240         if (m_versionString) {
241             free(m_versionString);
242             m_versionString = NULL;
243         }
244         if (m_vendorString) {
245             free(m_vendorString);
246             m_vendorString = NULL;
247         }
248         if (m_extensionString) {
249             free(m_extensionString);
250             m_extensionString = NULL;
251         }
252     }
253     pthread_mutex_unlock(&m_lock);
254 }
255 
256 #ifdef __APPLE__
257 #define LIBSUFFIX ".dylib"
258 #else
259 #ifdef _WIN32
260 #define LIBSUFFIX ".dll"
261 #else
262 #define LIBSUFFIX ".so"
263 #endif // !_WIN32 (linux)
264 #endif // !__APPLE__
265 
266 #ifndef HOST_BUILD
267 #if PLATFORM_SDK_VERSION >= 26
268 #define PARTITION "/vendor"
269 #else
270 #define PARTITION "/system"
271 #endif // !PLATFORM_SDK_VERSION >= 26
272 #if __LP64__
273 #define LIBDIR "/lib64/egl/"
274 #else
275 #define LIBDIR "/lib/egl/"
276 #endif // !__LP64__
277 #endif // !HOST_BUILD
278 
loadGLESClientAPI(const char * basename,EGLClient_eglInterface * eglIface,void ** libHandle)279 EGLClient_glesInterface *eglDisplay::loadGLESClientAPI(const char *basename,
280                                                        EGLClient_eglInterface *eglIface,
281                                                        void **libHandle)
282 {
283 #ifdef HOST_BUILD
284     std::string baseDir =
285         android::base::System::get()->getProgramDirectory();
286     std::string path =
287         android::base::pj(
288             baseDir, "lib64", std::string(basename) + LIBSUFFIX);
289     void *lib = dlopen(path.c_str(), RTLD_NOW);
290 #else
291     std::string path(PARTITION);
292     path += LIBDIR;
293     path += basename;
294     path += LIBSUFFIX;
295     void *lib = dlopen(path.c_str(), RTLD_NOW);
296 #endif
297 
298     if (!lib) {
299         ALOGE("Failed to dlopen %s", basename);
300         return NULL;
301     }
302 
303     init_emul_gles_t init_gles_func = (init_emul_gles_t)dlsym(lib,"init_emul_gles");
304     if (!init_gles_func) {
305         ALOGE("Failed to find init_emul_gles");
306         dlclose((void*)lib);
307         return NULL;
308     }
309 
310     *libHandle = lib;
311     return (*init_gles_func)(eglIface);
312 }
313 
queryHostEGLString(EGLint name)314 static char *queryHostEGLString(EGLint name)
315 {
316     HostConnection *hcon = HostConnection::get();
317     if (hcon) {
318         renderControl_encoder_context_t *rcEnc = hcon->rcEncoder();
319         if (rcEnc) {
320             int n = rcEnc->rcQueryEGLString(rcEnc, name, NULL, 0);
321             if (n < 0) {
322                 // allocate space for the string.
323                 char *str = (char *)malloc(-n);
324                 n = rcEnc->rcQueryEGLString(rcEnc, name, str, -n);
325                 if (n > 0) {
326                     return str;
327                 }
328 
329                 free(str);
330             }
331         }
332     }
333 
334     return NULL;
335 }
336 
buildExtensionString()337 static char *buildExtensionString()
338 {
339     //Query host extension string
340     char *hostExt = queryHostEGLString(EGL_EXTENSIONS);
341     if (!hostExt || (hostExt[1] == '\0')) {
342         // no extensions on host - only static extension list supported
343         return strdup(systemStaticEGLExtensions);
344     }
345 
346     int n = strlen(hostExt);
347     if (n > 0) {
348         char *initialEGLExts;
349         char *finalEGLExts;
350 
351         HostConnection *hcon = HostConnection::get();
352         // If we got here, we must have succeeded in queryHostEGLString
353         // and we thus should have a valid connection
354         assert(hcon);
355 
356         asprintf(&initialEGLExts,"%s%s", systemStaticEGLExtensions, hostExt);
357 
358         std::string dynamicEGLExtensions;
359 
360         if ((hcon->rcEncoder()->hasVirtioGpuNativeSync() || hcon->rcEncoder()->hasNativeSync()) &&
361             !strstr(initialEGLExts, kDynamicEGLExtNativeSync)) {
362             dynamicEGLExtensions += kDynamicEGLExtNativeSync;
363 
364             if (hcon->rcEncoder()->hasVirtioGpuNativeSync() || hcon->rcEncoder()->hasNativeSyncV3()) {
365                 dynamicEGLExtensions += kDynamicEGLExtWaitSync;
366             }
367         }
368 
369         asprintf(&finalEGLExts, "%s%s", initialEGLExts, dynamicEGLExtensions.c_str());
370 
371         free((char*)hostExt);
372         return finalEGLExts;
373     }
374     else {
375         free((char*)hostExt);
376         return strdup(systemStaticEGLExtensions);
377     }
378 }
379 
queryString(EGLint name)380 const char *eglDisplay::queryString(EGLint name)
381 {
382     if (name == EGL_CLIENT_APIS) {
383         return "OpenGL_ES";
384     }
385     else if (name == EGL_VERSION) {
386         pthread_mutex_lock(&m_lock);
387         if (m_versionString) {
388             pthread_mutex_unlock(&m_lock);
389             return m_versionString;
390         }
391 
392         // build version string
393         asprintf(&m_versionString, "%d.%d", m_major, m_minor);
394         pthread_mutex_unlock(&m_lock);
395 
396         return m_versionString;
397     }
398     else if (name == EGL_VENDOR) {
399         pthread_mutex_lock(&m_lock);
400         if (m_vendorString) {
401             pthread_mutex_unlock(&m_lock);
402             return m_vendorString;
403         }
404 
405         // build vendor string
406         const char *hostVendor = queryHostEGLString(EGL_VENDOR);
407 
408         if (hostVendor) {
409             asprintf(&m_vendorString, "%s Host: %s",
410                                      systemEGLVendor, hostVendor);
411             free((char*)hostVendor);
412         }
413         else {
414             m_vendorString = (char *)systemEGLVendor;
415         }
416         pthread_mutex_unlock(&m_lock);
417 
418         return m_vendorString;
419     }
420     else if (name == EGL_EXTENSIONS) {
421         pthread_mutex_lock(&m_lock);
422         if (m_extensionString) {
423             pthread_mutex_unlock(&m_lock);
424             return m_extensionString;
425         }
426 
427         // build extension string
428         m_extensionString = buildExtensionString();
429         pthread_mutex_unlock(&m_lock);
430 
431         return m_extensionString;
432     }
433     else {
434         ALOGE("[%s] Unknown name %d\n", __FUNCTION__, name);
435         return NULL;
436     }
437 }
438 
439 /* To get the value of attribute <a> of config <c> use the following formula:
440  * value = *(m_configs + (int)c*m_numConfigAttribs + a);
441  */
getAttribValue(EGLConfig config,EGLint attribIdx,EGLint * value)442 EGLBoolean eglDisplay::getAttribValue(EGLConfig config, EGLint attribIdx, EGLint * value)
443 {
444     if (attribIdx == ATTRIBUTE_NONE)
445     {
446         ALOGE("[%s] Bad attribute idx\n", __FUNCTION__);
447         return EGL_FALSE;
448     }
449     *value = *(m_configs + (intptr_t)(getIndexOfConfig(config))*m_numConfigAttribs + attribIdx);
450     return EGL_TRUE;
451 }
452 
453 #define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339
454 #define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A
455 
getConfigAtIndex(uint32_t index) const456 EGLConfig eglDisplay::getConfigAtIndex(uint32_t index) const {
457     uintptr_t asPtr = (uintptr_t)index;
458     return (EGLConfig)(asPtr + 1);
459 }
460 
getIndexOfConfig(EGLConfig config) const461 uint32_t eglDisplay::getIndexOfConfig(EGLConfig config) const {
462     uintptr_t asInteger = (uintptr_t)config;
463     return (uint32_t)(asInteger - 1);
464 }
465 
isValidConfig(EGLConfig cfg) const466 bool eglDisplay::isValidConfig(EGLConfig cfg) const {
467     uint32_t index = getIndexOfConfig(cfg);
468     intptr_t asInt = (intptr_t)index;
469     return !(asInt < 0 || asInt > m_numConfigs);
470 }
471 
getConfigAttrib(EGLConfig config,EGLint attrib,EGLint * value)472 EGLBoolean eglDisplay::getConfigAttrib(EGLConfig config, EGLint attrib, EGLint * value)
473 {
474     if (attrib == EGL_FRAMEBUFFER_TARGET_ANDROID) {
475         *value = EGL_TRUE;
476         return EGL_TRUE;
477     }
478     if (attrib == EGL_COVERAGE_SAMPLES_NV ||
479         attrib == EGL_COVERAGE_BUFFERS_NV) {
480         *value = 0;
481         return EGL_TRUE;
482     }
483     if (attrib == EGL_DEPTH_ENCODING_NV) {
484         *value = EGL_DEPTH_ENCODING_NONE_NV;
485         return EGL_TRUE;
486     }
487     if  (attrib == EGL_COLOR_COMPONENT_TYPE_EXT) {
488         *value = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
489         return EGL_TRUE;
490     }
491     //Though it seems that valueFor() is thread-safe, we don't take chanses
492     pthread_mutex_lock(&m_lock);
493     EGLBoolean ret =
494         getAttribValue(
495             config,
496             findObjectOrDefault(
497                 m_attribs, attrib, EGL_DONT_CARE),
498             value);
499     pthread_mutex_unlock(&m_lock);
500     return ret;
501 }
502 
dumpConfig(EGLConfig config)503 void eglDisplay::dumpConfig(EGLConfig config)
504 {
505     EGLint value = 0;
506     DBG("^^^^^^^^^^ dumpConfig %p ^^^^^^^^^^^^^^^^^^", config);
507     for (int i=0; i<m_numConfigAttribs; i++) {
508         getAttribValue(config, i, &value);
509         DBG("Config %p: {%u}[%d] %d\n", config, getIndexOfConfig(config), i, value);
510     }
511 }
512 
513 /* To set the value of attribute <a> of config <c> use the following formula:
514  * *(m_configs + (int)c*m_numConfigAttribs + a) = value;
515  */
setAttribValue(EGLConfig config,EGLint attribIdx,EGLint value)516 EGLBoolean eglDisplay::setAttribValue(EGLConfig config, EGLint attribIdx, EGLint value)
517 {
518     if (attribIdx == ATTRIBUTE_NONE)
519     {
520         ALOGE("[%s] Bad attribute idx\n", __FUNCTION__);
521         return EGL_FALSE;
522     }
523     *(m_configs + (intptr_t)(getIndexOfConfig(config))*m_numConfigAttribs + attribIdx) = value;
524     return EGL_TRUE;
525 }
526 
setConfigAttrib(EGLConfig config,EGLint attrib,EGLint value)527 EGLBoolean eglDisplay::setConfigAttrib(EGLConfig config, EGLint attrib, EGLint value)
528 {
529     //Though it seems that valueFor() is thread-safe, we don't take chanses
530     pthread_mutex_lock(&m_lock);
531     EGLBoolean ret =
532         setAttribValue(
533             config,
534             findObjectOrDefault(
535                 m_attribs,
536                 attrib,
537                 EGL_DONT_CARE),
538             value);
539     pthread_mutex_unlock(&m_lock);
540     return ret;
541 }
542 
543 
getConfigNativePixelFormat(EGLConfig config,PixelFormat * format)544 EGLBoolean eglDisplay::getConfigNativePixelFormat(EGLConfig config, PixelFormat * format)
545 {
546     EGLint redSize, blueSize, greenSize, alphaSize;
547 
548     if (!(
549             getAttribValue(
550                 config,
551                 findObjectOrDefault(m_attribs, EGL_RED_SIZE, EGL_DONT_CARE),
552                 &redSize) &&
553             getAttribValue(
554                 config,
555                 findObjectOrDefault(m_attribs, EGL_BLUE_SIZE, EGL_DONT_CARE),
556                 &blueSize) &&
557             getAttribValue(
558                 config,
559                 findObjectOrDefault(m_attribs, EGL_GREEN_SIZE, EGL_DONT_CARE),
560                 &greenSize) &&
561             getAttribValue(
562                 config,
563                 findObjectOrDefault(m_attribs, EGL_ALPHA_SIZE, EGL_DONT_CARE),
564                 &alphaSize))) {
565         ALOGE("Couldn't find value for one of the pixel format attributes");
566         return EGL_FALSE;
567     }
568 
569     //calculate the GL internal format
570     if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==8)) *format = PIXEL_FORMAT_RGBA_8888; //XXX: BGR?
571     else if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGBX_8888; //XXX or PIXEL_FORMAT_RGB_888
572     else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGB_565;
573     else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = PIXEL_FORMAT_RGBA_5551;
574     else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = PIXEL_FORMAT_RGBA_4444;
575     else {
576         return EGL_FALSE;
577     }
578     return EGL_TRUE;
579 }
getConfigGLPixelFormat(EGLConfig config,GLenum * format)580 EGLBoolean eglDisplay::getConfigGLPixelFormat(EGLConfig config, GLenum * format)
581 {
582     EGLint redSize, blueSize, greenSize, alphaSize;
583 
584     if (!(
585             getAttribValue(
586                 config,
587                 findObjectOrDefault(m_attribs, EGL_RED_SIZE, EGL_DONT_CARE),
588                 &redSize) &&
589             getAttribValue(
590                 config,
591                 findObjectOrDefault(m_attribs, EGL_BLUE_SIZE, EGL_DONT_CARE),
592                 &blueSize) &&
593             getAttribValue(
594                 config,
595                 findObjectOrDefault(m_attribs, EGL_GREEN_SIZE, EGL_DONT_CARE),
596                 &greenSize) &&
597             getAttribValue(
598                 config,
599                 findObjectOrDefault(m_attribs, EGL_ALPHA_SIZE, EGL_DONT_CARE),
600                 &alphaSize))) {
601         ALOGE("Couldn't find value for one of the pixel format attributes");
602         return EGL_FALSE;
603     }
604 
605     //calculate the GL internal format
606     if ((redSize == greenSize) && (redSize == blueSize) &&
607         ((redSize == 8) || (redSize == 16) || (redSize == 32)))
608     {
609         if (alphaSize == 0) *format = GL_RGB;
610         else *format = GL_RGBA;
611     }
612     else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = GL_RGB565_OES;
613     else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = GL_RGB5_A1_OES;
614     else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = GL_RGBA4_OES;
615     else return EGL_FALSE;
616 
617     return EGL_TRUE;
618 }
619 
onCreateContext(EGLContext ctx)620 void eglDisplay::onCreateContext(EGLContext ctx) {
621     pthread_mutex_lock(&m_ctxLock);
622     m_contexts.insert(ctx);
623     pthread_mutex_unlock(&m_ctxLock);
624 }
625 
onCreateSurface(EGLSurface surface)626 void eglDisplay::onCreateSurface(EGLSurface surface) {
627     pthread_mutex_lock(&m_surfaceLock);
628     m_surfaces.insert(surface);
629     pthread_mutex_unlock(&m_surfaceLock);
630 }
631 
onDestroyContext(EGLContext ctx)632 void eglDisplay::onDestroyContext(EGLContext ctx) {
633     pthread_mutex_lock(&m_ctxLock);
634     m_contexts.erase(ctx);
635     pthread_mutex_unlock(&m_ctxLock);
636 }
637 
onDestroySurface(EGLSurface surface)638 void eglDisplay::onDestroySurface(EGLSurface surface) {
639     pthread_mutex_lock(&m_surfaceLock);
640     m_surfaces.erase(surface);
641     pthread_mutex_unlock(&m_surfaceLock);
642 }
643 
isContext(EGLContext ctx)644 bool eglDisplay::isContext(EGLContext ctx) {
645     pthread_mutex_lock(&m_ctxLock);
646     bool res = m_contexts.find(ctx) != m_contexts.end();
647     pthread_mutex_unlock(&m_ctxLock);
648     return res;
649 }
650 
isSurface(EGLSurface surface)651 bool eglDisplay::isSurface(EGLSurface surface) {
652     pthread_mutex_lock(&m_surfaceLock);
653     bool res = m_surfaces.find(surface) != m_surfaces.end();
654     pthread_mutex_unlock(&m_surfaceLock);
655     return res;
656 }
657