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