• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <string>
21 #include <vector>
22 
23 #include <dlfcn.h>
24 #include <GLES3/gl31.h>
25 
26 #include <aemu/base/Path.h>
27 #include <system/graphics.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     m_hostDriverCaps_knownMajorVersion(0),
78     m_hostDriverCaps_knownMinorVersion(0)
79 {
80     pthread_mutex_init(&m_lock, NULL);
81     pthread_mutex_init(&m_ctxLock, NULL);
82     pthread_mutex_init(&m_surfaceLock, NULL);
83 }
84 
~eglDisplay()85 eglDisplay::~eglDisplay()
86 {
87     terminate();
88     pthread_mutex_destroy(&m_lock);
89     pthread_mutex_destroy(&m_ctxLock);
90     pthread_mutex_destroy(&m_surfaceLock);
91 }
92 
93 
94 
initialize(EGLClient_eglInterface * eglIface)95 bool eglDisplay::initialize(EGLClient_eglInterface *eglIface)
96 {
97     pthread_mutex_lock(&m_lock);
98     if (!m_initialized) {
99 
100         //
101         // load GLES client API
102         //
103         m_gles_iface = loadGLESClientAPI("libGLESv1_CM_emulation",
104                                          eglIface,
105                                          &s_gles_lib);
106         if (!m_gles_iface) {
107             pthread_mutex_unlock(&m_lock);
108             ALOGE("Failed to load gles1 iface");
109             return false;
110         }
111 
112         m_gles2_iface = loadGLESClientAPI("libGLESv2_emulation",
113                                           eglIface,
114                                           &s_gles2_lib);
115 
116         //
117         // establish connection with the host
118         //
119         HostConnection *hcon = HostConnection::get();
120         if (!hcon) {
121             pthread_mutex_unlock(&m_lock);
122             ALOGE("Failed to establish connection with the host\n");
123             return false;
124         }
125 
126         //
127         // get renderControl encoder instance
128         //
129         renderControl_encoder_context_t *rcEnc = hcon->rcEncoder();
130         if (!rcEnc) {
131             pthread_mutex_unlock(&m_lock);
132             ALOGE("Failed to get renderControl encoder instance");
133             return false;
134         }
135 
136         //
137         // Query host reneder and EGL version
138         //
139         m_hostRendererVersion = rcEnc->rcGetRendererVersion(rcEnc);
140         EGLint status = rcEnc->rcGetEGLVersion(rcEnc, &m_major, &m_minor);
141         if (status != EGL_TRUE) {
142             // host EGL initialization failed !!
143             pthread_mutex_unlock(&m_lock);
144             return false;
145         }
146 
147         //
148         // Take minimum version beween what we support and what the host support
149         //
150         if (m_major > systemEGLVersionMajor) {
151             m_major = systemEGLVersionMajor;
152             m_minor = systemEGLVersionMinor;
153         }
154         else if (m_major == systemEGLVersionMajor &&
155                  m_minor > systemEGLVersionMinor) {
156             m_minor = systemEGLVersionMinor;
157         }
158 
159         //
160         // Query the host for the set of configs
161         //
162         m_numConfigs = rcEnc->rcGetNumConfigs(rcEnc, (uint32_t*)&m_numConfigAttribs);
163         if (m_numConfigs <= 0 || m_numConfigAttribs <= 0) {
164             // just sanity check - should never happen
165             pthread_mutex_unlock(&m_lock);
166             return false;
167         }
168 
169         uint32_t nInts = m_numConfigAttribs * (m_numConfigs + 1);
170         EGLint tmp_buf[nInts];
171 
172         m_configs = new EGLint[nInts-m_numConfigAttribs];
173 
174         if (!m_configs) {
175             pthread_mutex_unlock(&m_lock);
176             return false;
177         }
178 
179         EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), (GLuint*)tmp_buf);
180         if (n != m_numConfigs) {
181             pthread_mutex_unlock(&m_lock);
182             return false;
183         }
184 
185         // Fill the attributes vector.
186         // The first m_numConfigAttribs values of tmp_buf are the actual attributes enums.
187         for (int i=0; i<m_numConfigAttribs; i++) {
188             m_attribs[tmp_buf[i]] = i;
189         }
190 
191         memcpy(m_configs, tmp_buf + m_numConfigAttribs,
192                m_numConfigs*m_numConfigAttribs*sizeof(EGLint));
193 
194         m_initialized = true;
195     }
196     pthread_mutex_unlock(&m_lock);
197 
198     processConfigs();
199 
200     return true;
201 }
202 
processConfigs()203 void eglDisplay::processConfigs()
204 {
205     for (intptr_t i=0; i<m_numConfigs; i++) {
206         EGLConfig config = getConfigAtIndex(i);
207         uint32_t format;
208         if (getConfigNativePixelFormat(config, &format)) {
209             setConfigAttrib(config, EGL_NATIVE_VISUAL_ID, format);
210         }
211     }
212 }
213 
terminate()214 void eglDisplay::terminate()
215 {
216     pthread_mutex_lock(&m_lock);
217     if (m_initialized) {
218         // Cannot use the for loop in the following code because
219         // eglDestroyContext may erase elements.
220         EGLContextSet::iterator ctxIte = m_contexts.begin();
221         while (ctxIte != m_contexts.end()) {
222             EGLContextSet::iterator ctxToDelete = ctxIte;
223             ctxIte ++;
224             eglDestroyContext(static_cast<EGLDisplay>(this), *ctxToDelete);
225         }
226         EGLSurfaceSet::iterator surfaceIte = m_surfaces.begin();
227         while (surfaceIte != m_surfaces.end()) {
228             EGLSurfaceSet::iterator surfaceToDelete = surfaceIte;
229             surfaceIte ++;
230             eglDestroySurface(static_cast<EGLDisplay>(this), *surfaceToDelete);
231         }
232         m_initialized = false;
233         delete [] m_configs;
234         m_configs = NULL;
235 
236         if (m_versionString) {
237             free(m_versionString);
238             m_versionString = NULL;
239         }
240         if (m_vendorString) {
241             free(m_vendorString);
242             m_vendorString = NULL;
243         }
244         if (m_extensionString) {
245             free(m_extensionString);
246             m_extensionString = NULL;
247         }
248     }
249     pthread_mutex_unlock(&m_lock);
250 }
251 
252 #ifdef __APPLE__
253 #define LIBSUFFIX ".dylib"
254 #else
255 #ifdef _WIN32
256 #define LIBSUFFIX ".dll"
257 #else
258 #define LIBSUFFIX ".so"
259 #endif // !_WIN32 (linux)
260 #endif // !__APPLE__
261 
262 #define PARTITION "/system"
263 #if __LP64__
264 #define LIBDIR "/lib64/egl/"
265 #else
266 #define LIBDIR "/lib/egl/"
267 #endif // !__LP64__
268 
loadGLESClientAPI(const char * basename,EGLClient_eglInterface * eglIface,void ** libHandle)269 EGLClient_glesInterface *eglDisplay::loadGLESClientAPI(const char *basename,
270                                                        EGLClient_eglInterface *eglIface,
271                                                        void **libHandle)
272 {
273     std::vector<std::string> paths;
274 #if defined(__ANDROID__)
275     // Try to load from the current linker namespace first.
276     paths.push_back(basename + std::string(LIBSUFFIX));
277     // And then look into the known location.
278     paths.push_back(std::string(PARTITION) +
279                     std::string(LIBDIR) +
280                     basename +
281                     std::string(LIBSUFFIX));
282 #else
283     const std::string directory = gfxstream::guest::getProgramDirectory();
284     paths.push_back(directory + "/" + basename + LIBSUFFIX);
285     paths.push_back(directory + "/" + basename + "_with_host" + LIBSUFFIX);
286     paths.push_back(directory + "/lib64/" + basename + LIBSUFFIX);
287     paths.push_back(directory + "/lib64/" + basename + "_with_host" + LIBSUFFIX);
288 #endif
289 
290     void* lib = nullptr;
291     for (const std::string& path : paths) {
292         ALOGI("Opening %s", path.c_str());
293         lib = dlopen(path.c_str(), RTLD_NOW);
294         if (lib) {
295             break;
296         }
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(initialEGLExts);
372         free((char*)hostExt);
373         return finalEGLExts;
374     }
375     else {
376         free((char*)hostExt);
377         return strdup(systemStaticEGLExtensions);
378     }
379 }
380 
queryString(EGLint name)381 const char *eglDisplay::queryString(EGLint name)
382 {
383     if (name == EGL_CLIENT_APIS) {
384         return "OpenGL_ES";
385     }
386     else if (name == EGL_VERSION) {
387         pthread_mutex_lock(&m_lock);
388         if (m_versionString) {
389             pthread_mutex_unlock(&m_lock);
390             return m_versionString;
391         }
392 
393         // build version string
394         asprintf(&m_versionString, "%d.%d", m_major, m_minor);
395         pthread_mutex_unlock(&m_lock);
396 
397         return m_versionString;
398     }
399     else if (name == EGL_VENDOR) {
400         pthread_mutex_lock(&m_lock);
401         if (m_vendorString) {
402             pthread_mutex_unlock(&m_lock);
403             return m_vendorString;
404         }
405 
406         // build vendor string
407         const char *hostVendor = queryHostEGLString(EGL_VENDOR);
408 
409         if (hostVendor) {
410             asprintf(&m_vendorString, "%s Host: %s",
411                                      systemEGLVendor, hostVendor);
412             free((char*)hostVendor);
413         }
414         else {
415             m_vendorString = (char *)systemEGLVendor;
416         }
417         pthread_mutex_unlock(&m_lock);
418 
419         return m_vendorString;
420     }
421     else if (name == EGL_EXTENSIONS) {
422         pthread_mutex_lock(&m_lock);
423         if (m_extensionString) {
424             pthread_mutex_unlock(&m_lock);
425             return m_extensionString;
426         }
427 
428         // build extension string
429         m_extensionString = buildExtensionString();
430         pthread_mutex_unlock(&m_lock);
431 
432         return m_extensionString;
433     }
434     else {
435         ALOGE("[%s] Unknown name %d\n", __FUNCTION__, name);
436         return NULL;
437     }
438 }
439 
440 /* To get the value of attribute <a> of config <c> use the following formula:
441  * value = *(m_configs + (int)c*m_numConfigAttribs + a);
442  */
getAttribValue(EGLConfig config,EGLint attribIdx,EGLint * value)443 EGLBoolean eglDisplay::getAttribValue(EGLConfig config, EGLint attribIdx, EGLint * value)
444 {
445     if (attribIdx == ATTRIBUTE_NONE)
446     {
447         ALOGE("[%s] Bad attribute idx\n", __FUNCTION__);
448         return EGL_FALSE;
449     }
450     *value = *(m_configs + (intptr_t)(getIndexOfConfig(config))*m_numConfigAttribs + attribIdx);
451     return EGL_TRUE;
452 }
453 
454 #define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339
455 #define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A
456 
getConfigAtIndex(uint32_t index) const457 EGLConfig eglDisplay::getConfigAtIndex(uint32_t index) const {
458     uintptr_t asPtr = (uintptr_t)index;
459     return (EGLConfig)(asPtr + 1);
460 }
461 
getIndexOfConfig(EGLConfig config) const462 uint32_t eglDisplay::getIndexOfConfig(EGLConfig config) const {
463     uintptr_t asInteger = (uintptr_t)config;
464     return (uint32_t)(asInteger - 1);
465 }
466 
isValidConfig(EGLConfig cfg) const467 bool eglDisplay::isValidConfig(EGLConfig cfg) const {
468     uint32_t index = getIndexOfConfig(cfg);
469     intptr_t asInt = (intptr_t)index;
470     return !(asInt < 0 || asInt > m_numConfigs);
471 }
472 
getConfigAttrib(EGLConfig config,EGLint attrib,EGLint * value)473 EGLBoolean eglDisplay::getConfigAttrib(EGLConfig config, EGLint attrib, EGLint * value)
474 {
475     if (attrib == EGL_FRAMEBUFFER_TARGET_ANDROID) {
476         *value = EGL_TRUE;
477         return EGL_TRUE;
478     }
479     if (attrib == EGL_COVERAGE_SAMPLES_NV ||
480         attrib == EGL_COVERAGE_BUFFERS_NV) {
481         *value = 0;
482         return EGL_TRUE;
483     }
484     if (attrib == EGL_DEPTH_ENCODING_NV) {
485         *value = EGL_DEPTH_ENCODING_NONE_NV;
486         return EGL_TRUE;
487     }
488     if  (attrib == EGL_COLOR_COMPONENT_TYPE_EXT) {
489         *value = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
490         return EGL_TRUE;
491     }
492     //Though it seems that valueFor() is thread-safe, we don't take chanses
493     pthread_mutex_lock(&m_lock);
494     EGLBoolean ret =
495         getAttribValue(
496             config,
497             findObjectOrDefault(
498                 m_attribs, attrib, EGL_DONT_CARE),
499             value);
500     pthread_mutex_unlock(&m_lock);
501     return ret;
502 }
503 
dumpConfig(EGLConfig config)504 void eglDisplay::dumpConfig(EGLConfig config)
505 {
506     EGLint value = 0;
507     DBG("^^^^^^^^^^ dumpConfig %p ^^^^^^^^^^^^^^^^^^", config);
508     for (int i=0; i<m_numConfigAttribs; i++) {
509         getAttribValue(config, i, &value);
510         DBG("Config %p: {%u}[%d] %d\n", config, getIndexOfConfig(config), i, value);
511     }
512 }
513 
514 /* To set the value of attribute <a> of config <c> use the following formula:
515  * *(m_configs + (int)c*m_numConfigAttribs + a) = value;
516  */
setAttribValue(EGLConfig config,EGLint attribIdx,EGLint value)517 EGLBoolean eglDisplay::setAttribValue(EGLConfig config, EGLint attribIdx, EGLint value)
518 {
519     if (attribIdx == ATTRIBUTE_NONE)
520     {
521         ALOGE("[%s] Bad attribute idx\n", __FUNCTION__);
522         return EGL_FALSE;
523     }
524     *(m_configs + (intptr_t)(getIndexOfConfig(config))*m_numConfigAttribs + attribIdx) = value;
525     return EGL_TRUE;
526 }
527 
setConfigAttrib(EGLConfig config,EGLint attrib,EGLint value)528 EGLBoolean eglDisplay::setConfigAttrib(EGLConfig config, EGLint attrib, EGLint value)
529 {
530     //Though it seems that valueFor() is thread-safe, we don't take chanses
531     pthread_mutex_lock(&m_lock);
532     EGLBoolean ret =
533         setAttribValue(
534             config,
535             findObjectOrDefault(
536                 m_attribs,
537                 attrib,
538                 EGL_DONT_CARE),
539             value);
540     pthread_mutex_unlock(&m_lock);
541     return ret;
542 }
543 
544 
getConfigNativePixelFormat(EGLConfig config,uint32_t * format)545 EGLBoolean eglDisplay::getConfigNativePixelFormat(EGLConfig config, uint32_t * format)
546 {
547     EGLint redSize, blueSize, greenSize, alphaSize;
548 
549     if (!(
550             getAttribValue(
551                 config,
552                 findObjectOrDefault(m_attribs, EGL_RED_SIZE, EGL_DONT_CARE),
553                 &redSize) &&
554             getAttribValue(
555                 config,
556                 findObjectOrDefault(m_attribs, EGL_BLUE_SIZE, EGL_DONT_CARE),
557                 &blueSize) &&
558             getAttribValue(
559                 config,
560                 findObjectOrDefault(m_attribs, EGL_GREEN_SIZE, EGL_DONT_CARE),
561                 &greenSize) &&
562             getAttribValue(
563                 config,
564                 findObjectOrDefault(m_attribs, EGL_ALPHA_SIZE, EGL_DONT_CARE),
565                 &alphaSize))) {
566         ALOGE("Couldn't find value for one of the pixel format attributes");
567         return EGL_FALSE;
568     }
569 
570     //calculate the GL internal format
571     if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==8)) *format = HAL_PIXEL_FORMAT_RGBA_8888; //XXX: BGR?
572     else if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==0)) *format = HAL_PIXEL_FORMAT_RGBX_8888; //XXX or HAL_PIXEL_FORMAT_RGB_888
573     else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = HAL_PIXEL_FORMAT_RGB_565;
574     else {
575         return EGL_FALSE;
576     }
577     return EGL_TRUE;
578 }
getConfigGLPixelFormat(EGLConfig config,GLenum * format)579 EGLBoolean eglDisplay::getConfigGLPixelFormat(EGLConfig config, GLenum * format)
580 {
581     EGLint redSize, blueSize, greenSize, alphaSize;
582 
583     if (!(
584             getAttribValue(
585                 config,
586                 findObjectOrDefault(m_attribs, EGL_RED_SIZE, EGL_DONT_CARE),
587                 &redSize) &&
588             getAttribValue(
589                 config,
590                 findObjectOrDefault(m_attribs, EGL_BLUE_SIZE, EGL_DONT_CARE),
591                 &blueSize) &&
592             getAttribValue(
593                 config,
594                 findObjectOrDefault(m_attribs, EGL_GREEN_SIZE, EGL_DONT_CARE),
595                 &greenSize) &&
596             getAttribValue(
597                 config,
598                 findObjectOrDefault(m_attribs, EGL_ALPHA_SIZE, EGL_DONT_CARE),
599                 &alphaSize))) {
600         ALOGE("Couldn't find value for one of the pixel format attributes");
601         return EGL_FALSE;
602     }
603 
604     //calculate the GL internal format
605     if ((redSize == greenSize) && (redSize == blueSize) &&
606         ((redSize == 8) || (redSize == 16) || (redSize == 32)))
607     {
608         if (alphaSize == 0) *format = GL_RGB;
609         else *format = GL_RGBA;
610     }
611     else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = GL_RGB565_OES;
612     else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = GL_RGB5_A1_OES;
613     else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = GL_RGBA4_OES;
614     else return EGL_FALSE;
615 
616     return EGL_TRUE;
617 }
618 
onCreateContext(EGLContext ctx)619 void eglDisplay::onCreateContext(EGLContext ctx) {
620     pthread_mutex_lock(&m_ctxLock);
621     m_contexts.insert(ctx);
622     pthread_mutex_unlock(&m_ctxLock);
623 }
624 
onCreateSurface(EGLSurface surface)625 void eglDisplay::onCreateSurface(EGLSurface surface) {
626     pthread_mutex_lock(&m_surfaceLock);
627     m_surfaces.insert(surface);
628     pthread_mutex_unlock(&m_surfaceLock);
629 }
630 
onDestroyContext(EGLContext ctx)631 void eglDisplay::onDestroyContext(EGLContext ctx) {
632     pthread_mutex_lock(&m_ctxLock);
633     m_contexts.erase(ctx);
634     pthread_mutex_unlock(&m_ctxLock);
635 }
636 
onDestroySurface(EGLSurface surface)637 void eglDisplay::onDestroySurface(EGLSurface surface) {
638     pthread_mutex_lock(&m_surfaceLock);
639     m_surfaces.erase(surface);
640     pthread_mutex_unlock(&m_surfaceLock);
641 }
642 
isContext(EGLContext ctx)643 bool eglDisplay::isContext(EGLContext ctx) {
644     pthread_mutex_lock(&m_ctxLock);
645     bool res = m_contexts.find(ctx) != m_contexts.end();
646     pthread_mutex_unlock(&m_ctxLock);
647     return res;
648 }
649 
isSurface(EGLSurface surface)650 bool eglDisplay::isSurface(EGLSurface surface) {
651     pthread_mutex_lock(&m_surfaceLock);
652     bool res = m_surfaces.find(surface) != m_surfaces.end();
653     pthread_mutex_unlock(&m_surfaceLock);
654     return res;
655 }
656 
getHostDriverCaps(int majorVersion,int minorVersion)657 HostDriverCaps eglDisplay::getHostDriverCaps(int majorVersion, int minorVersion) {
658     pthread_mutex_lock(&m_lock);
659     if (majorVersion <= m_hostDriverCaps_knownMajorVersion &&
660         minorVersion <= m_hostDriverCaps_knownMinorVersion) {
661         pthread_mutex_unlock(&m_lock);
662         return m_hostDriverCaps;
663     }
664 
665     memset(&m_hostDriverCaps, 0x0, sizeof(m_hostDriverCaps));
666 
667     m_hostDriverCaps.max_color_attachments = 8;
668 
669     // Can we query gles2?
670     if (majorVersion >= 1) {
671         m_gles2_iface->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &m_hostDriverCaps.max_vertex_attribs);
672         m_gles2_iface->getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &m_hostDriverCaps.max_combined_texture_image_units);
673 
674         m_gles2_iface->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_hostDriverCaps.max_texture_size);
675         m_gles2_iface->getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &m_hostDriverCaps.max_texture_size_cube_map);
676         m_gles2_iface->getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_hostDriverCaps.max_renderbuffer_size);
677         m_hostDriverCaps_knownMajorVersion = 2;
678     }
679 
680     // Can we query gles3.0?
681     if (majorVersion >= 3) {
682         m_gles2_iface->getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &m_hostDriverCaps.max_color_attachments);
683         m_gles2_iface->getIntegerv(GL_MAX_DRAW_BUFFERS, &m_hostDriverCaps.max_draw_buffers);
684         m_gles2_iface->getIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_hostDriverCaps.ubo_offset_alignment);
685         m_gles2_iface->getIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &m_hostDriverCaps.max_uniform_buffer_bindings);
686         m_gles2_iface->getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &m_hostDriverCaps.max_transform_feedback_separate_attribs);
687         m_gles2_iface->getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &m_hostDriverCaps.max_texture_size_3d);
688         m_gles2_iface->getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &m_hostDriverCaps.max_array_texture_layers);
689 
690         m_hostDriverCaps_knownMajorVersion = 3;
691 
692         // Can we query gles3.1?
693         if (minorVersion >= 1) {
694             m_gles2_iface->getIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &m_hostDriverCaps.max_atomic_counter_buffer_bindings);
695             m_gles2_iface->getIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &m_hostDriverCaps.max_shader_storage_buffer_bindings);
696             m_gles2_iface->getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &m_hostDriverCaps.max_vertex_attrib_bindings);
697             m_gles2_iface->getIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &m_hostDriverCaps.max_vertex_attrib_stride);
698             m_gles2_iface->getIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &m_hostDriverCaps.ssbo_offset_alignment);
699             m_hostDriverCaps_knownMinorVersion = 1;
700         }
701     }
702 
703     pthread_mutex_unlock(&m_lock);
704 
705     return m_hostDriverCaps;
706 }
707 
708