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