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