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