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 #include <dlfcn.h>
27 #include <GLES3/gl31.h>
28
29 #include <system/graphics.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 m_gles2_iface = loadGLESClientAPI("libGLESv2_emulation",
115 eglIface,
116 &s_gles2_lib);
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
175 m_configs = new EGLint[nInts-m_numConfigAttribs];
176
177 if (!m_configs) {
178 pthread_mutex_unlock(&m_lock);
179 return false;
180 }
181
182 EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), (GLuint*)tmp_buf);
183 if (n != m_numConfigs) {
184 pthread_mutex_unlock(&m_lock);
185 return false;
186 }
187
188 // Fill the attributes vector.
189 // The first m_numConfigAttribs values of tmp_buf are the actual attributes enums.
190 for (int i=0; i<m_numConfigAttribs; i++) {
191 m_attribs[tmp_buf[i]] = i;
192 }
193
194 memcpy(m_configs, tmp_buf + m_numConfigAttribs,
195 m_numConfigs*m_numConfigAttribs*sizeof(EGLint));
196
197 m_initialized = true;
198 }
199 pthread_mutex_unlock(&m_lock);
200
201 processConfigs();
202
203 return true;
204 }
205
processConfigs()206 void eglDisplay::processConfigs()
207 {
208 for (intptr_t i=0; i<m_numConfigs; i++) {
209 EGLConfig config = getConfigAtIndex(i);
210 uint32_t format;
211 if (getConfigNativePixelFormat(config, &format)) {
212 setConfigAttrib(config, EGL_NATIVE_VISUAL_ID, format);
213 }
214 }
215 }
216
terminate()217 void eglDisplay::terminate()
218 {
219 pthread_mutex_lock(&m_lock);
220 if (m_initialized) {
221 // Cannot use the for loop in the following code because
222 // eglDestroyContext may erase elements.
223 EGLContextSet::iterator ctxIte = m_contexts.begin();
224 while (ctxIte != m_contexts.end()) {
225 EGLContextSet::iterator ctxToDelete = ctxIte;
226 ctxIte ++;
227 eglDestroyContext(static_cast<EGLDisplay>(this), *ctxToDelete);
228 }
229 EGLSurfaceSet::iterator surfaceIte = m_surfaces.begin();
230 while (surfaceIte != m_surfaces.end()) {
231 EGLSurfaceSet::iterator surfaceToDelete = surfaceIte;
232 surfaceIte ++;
233 eglDestroySurface(static_cast<EGLDisplay>(this), *surfaceToDelete);
234 }
235 m_initialized = false;
236 delete [] m_configs;
237 m_configs = NULL;
238
239 if (m_versionString) {
240 free(m_versionString);
241 m_versionString = NULL;
242 }
243 if (m_vendorString) {
244 free(m_vendorString);
245 m_vendorString = NULL;
246 }
247 if (m_extensionString) {
248 free(m_extensionString);
249 m_extensionString = NULL;
250 }
251 }
252 pthread_mutex_unlock(&m_lock);
253 }
254
255 #ifdef __APPLE__
256 #define LIBSUFFIX ".dylib"
257 #else
258 #ifdef _WIN32
259 #define LIBSUFFIX ".dll"
260 #else
261 #define LIBSUFFIX ".so"
262 #endif // !_WIN32 (linux)
263 #endif // !__APPLE__
264
265 #ifndef HOST_BUILD
266 #if PLATFORM_SDK_VERSION >= 26
267 #define PARTITION "/vendor"
268 #else
269 #define PARTITION "/system"
270 #endif // !PLATFORM_SDK_VERSION >= 26
271 #if __LP64__
272 #define LIBDIR "/lib64/egl/"
273 #else
274 #define LIBDIR "/lib/egl/"
275 #endif // !__LP64__
276 #endif // !HOST_BUILD
277
loadGLESClientAPI(const char * basename,EGLClient_eglInterface * eglIface,void ** libHandle)278 EGLClient_glesInterface *eglDisplay::loadGLESClientAPI(const char *basename,
279 EGLClient_eglInterface *eglIface,
280 void **libHandle)
281 {
282 #ifdef HOST_BUILD
283 std::string baseDir =
284 android::base::System::get()->getProgramDirectory();
285 std::string path =
286 android::base::pj({
287 baseDir, "lib64", std::string(basename) + LIBSUFFIX});
288 void *lib = dlopen(path.c_str(), RTLD_NOW);
289 #else
290 std::string path(PARTITION);
291 path += LIBDIR;
292 path += basename;
293 path += LIBSUFFIX;
294 void *lib = dlopen(path.c_str(), RTLD_NOW);
295 #endif
296
297 if (!lib) {
298 ALOGE("Failed to dlopen %s", basename);
299 return NULL;
300 }
301
302 init_emul_gles_t init_gles_func = (init_emul_gles_t)dlsym(lib,"init_emul_gles");
303 if (!init_gles_func) {
304 ALOGE("Failed to find init_emul_gles");
305 dlclose((void*)lib);
306 return NULL;
307 }
308
309 *libHandle = lib;
310 return (*init_gles_func)(eglIface);
311 }
312
queryHostEGLString(EGLint name)313 static char *queryHostEGLString(EGLint name)
314 {
315 HostConnection *hcon = HostConnection::get();
316 if (hcon) {
317 renderControl_encoder_context_t *rcEnc = hcon->rcEncoder();
318 if (rcEnc) {
319 int n = rcEnc->rcQueryEGLString(rcEnc, name, NULL, 0);
320 if (n < 0) {
321 // allocate space for the string.
322 char *str = (char *)malloc(-n);
323 n = rcEnc->rcQueryEGLString(rcEnc, name, str, -n);
324 if (n > 0) {
325 return str;
326 }
327
328 free(str);
329 }
330 }
331 }
332
333 return NULL;
334 }
335
buildExtensionString()336 static char *buildExtensionString()
337 {
338 //Query host extension string
339 char *hostExt = queryHostEGLString(EGL_EXTENSIONS);
340 if (!hostExt || (hostExt[1] == '\0')) {
341 // no extensions on host - only static extension list supported
342 return strdup(systemStaticEGLExtensions);
343 }
344
345 int n = strlen(hostExt);
346 if (n > 0) {
347 char *initialEGLExts;
348 char *finalEGLExts;
349
350 HostConnection *hcon = HostConnection::get();
351 // If we got here, we must have succeeded in queryHostEGLString
352 // and we thus should have a valid connection
353 assert(hcon);
354
355 asprintf(&initialEGLExts,"%s%s", systemStaticEGLExtensions, hostExt);
356
357 std::string dynamicEGLExtensions;
358
359 if ((hcon->rcEncoder()->hasVirtioGpuNativeSync() || hcon->rcEncoder()->hasNativeSync()) &&
360 !strstr(initialEGLExts, kDynamicEGLExtNativeSync)) {
361 dynamicEGLExtensions += kDynamicEGLExtNativeSync;
362
363 if (hcon->rcEncoder()->hasVirtioGpuNativeSync() || hcon->rcEncoder()->hasNativeSyncV3()) {
364 dynamicEGLExtensions += kDynamicEGLExtWaitSync;
365 }
366 }
367
368 asprintf(&finalEGLExts, "%s%s", initialEGLExts, dynamicEGLExtensions.c_str());
369
370 free(initialEGLExts);
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,uint32_t * format)544 EGLBoolean eglDisplay::getConfigNativePixelFormat(EGLConfig config, uint32_t * 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 = HAL_PIXEL_FORMAT_RGBA_8888; //XXX: BGR?
571 else if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==0)) *format = HAL_PIXEL_FORMAT_RGBX_8888; //XXX or HAL_PIXEL_FORMAT_RGB_888
572 else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = HAL_PIXEL_FORMAT_RGB_565;
573 else {
574 return EGL_FALSE;
575 }
576 return EGL_TRUE;
577 }
getConfigGLPixelFormat(EGLConfig config,GLenum * format)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
onCreateContext(EGLContext ctx)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
onCreateSurface(EGLSurface surface)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
onDestroyContext(EGLContext ctx)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
onDestroySurface(EGLSurface surface)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
isContext(EGLContext ctx)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
isSurface(EGLSurface surface)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
getHostDriverCaps(int majorVersion,int minorVersion)656 HostDriverCaps eglDisplay::getHostDriverCaps(int majorVersion, int minorVersion) {
657 pthread_mutex_lock(&m_lock);
658 if (majorVersion <= m_hostDriverCaps_knownMajorVersion &&
659 minorVersion <= m_hostDriverCaps_knownMinorVersion) {
660 pthread_mutex_unlock(&m_lock);
661 return m_hostDriverCaps;
662 }
663
664 memset(&m_hostDriverCaps, 0x0, sizeof(m_hostDriverCaps));
665
666 m_hostDriverCaps.max_color_attachments = 8;
667
668 // Can we query gles2?
669 if (majorVersion >= 1) {
670 m_gles2_iface->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &m_hostDriverCaps.max_vertex_attribs);
671 m_gles2_iface->getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &m_hostDriverCaps.max_combined_texture_image_units);
672
673 m_gles2_iface->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_hostDriverCaps.max_texture_size);
674 m_gles2_iface->getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &m_hostDriverCaps.max_texture_size_cube_map);
675 m_gles2_iface->getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_hostDriverCaps.max_renderbuffer_size);
676 m_hostDriverCaps_knownMajorVersion = 2;
677 }
678
679 // Can we query gles3.0?
680 if (majorVersion >= 3) {
681 m_gles2_iface->getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &m_hostDriverCaps.max_color_attachments);
682 m_gles2_iface->getIntegerv(GL_MAX_DRAW_BUFFERS, &m_hostDriverCaps.max_draw_buffers);
683 m_gles2_iface->getIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_hostDriverCaps.ubo_offset_alignment);
684 m_gles2_iface->getIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &m_hostDriverCaps.max_uniform_buffer_bindings);
685 m_gles2_iface->getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &m_hostDriverCaps.max_transform_feedback_separate_attribs);
686 m_gles2_iface->getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &m_hostDriverCaps.max_texture_size_3d);
687 m_gles2_iface->getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &m_hostDriverCaps.max_array_texture_layers);
688
689 m_hostDriverCaps_knownMajorVersion = 3;
690
691 // Can we query gles3.1?
692 if (minorVersion >= 1) {
693 m_gles2_iface->getIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &m_hostDriverCaps.max_atomic_counter_buffer_bindings);
694 m_gles2_iface->getIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &m_hostDriverCaps.max_shader_storage_buffer_bindings);
695 m_gles2_iface->getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &m_hostDriverCaps.max_vertex_attrib_bindings);
696 m_gles2_iface->getIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &m_hostDriverCaps.max_vertex_attrib_stride);
697 m_gles2_iface->getIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &m_hostDriverCaps.ssbo_offset_alignment);
698 m_hostDriverCaps_knownMinorVersion = 1;
699 }
700 }
701
702 pthread_mutex_unlock(&m_lock);
703
704 return m_hostDriverCaps;
705 }
706
707